scarajectory

Motion Trajectory Studio & Streamer


Project maintained by vroncevic Hosted on GitHub Pages — Theme by mattgraham

SCARA Motion Trajectory Studio & Streamer

scarajectory is a standalone CAD/CAM motion planning, kinematic validation, and real-time trajectory streaming software for SCARA robotic manipulators.

Developed in python code.

The README is used to introduce the modules and provide instructions on how to install the modules, any machine dependencies it may have and any other information that should be provided before the modules are installed.

scarajectory python checker scarajectory package checker scarajectory interface checker scarajectory isp checker scarajectory srp checker License: GPL v3 License Python 3.10+ GitHub issues open GitHub contributors

SCARA Trajectory Studio in Progress

Table of Contents

πŸš€ Installation

Used next development environment

debian linux os

scarajectory python3 build

Currently there are three ways to install package

Install using pip

scarajectory is located at pypi.org.

You can install by using pip

# python3
pip3 install scarajectory
Install using build

Navigate to release page download and extract release archive.

To install scarajectory type the following

tar xvzf scarajectory-x.y.z.tar.gz
cd scarajectory-x.y.z/
# python3
wget https://bootstrap.pypa.io/get-pip.py
python3 get-pip.py 
python3 -m pip install --upgrade setuptools
python3 -m pip install --upgrade pip
python3 -m pip install --upgrade build
pip3 install -r requirements.txt
python3 -m build --no-isolation --wheel
pip3 install ./dist/scarajectory-*-py3-none-any.whl
rm -f get-pip.py
chmod 755 /usr/local/lib/python3.10/dist-packages/usr/local/bin/scarajectory_run.py
ln -s /usr/local/lib/python3.10/dist-packages/usr/local/bin/scarajectory_run.py /usr/local/bin/scarajectory_run.py
Install using py setup

Navigate to release page download and extract release archive.

To install scarajectory locate and run setup.py with arguments

tar xvzf scarajectory-x.y.z.tar.gz
cd scarajectory-x.y.z
# python3
pip3 install -r requirements.txt
python3 setup.py install_lib
python3 setup.py install_egg_info
Install using docker

You can use Dockerfile to create image/container.

πŸ“¦ Dependencies

scarajectory requires next modules and libraries

Core Robotics & Language Engine Dependency (scaralang): scarajectory directly integrates scaralang as its foundational domain dependency. scaralang provides the SCARA Domain-Specific Language (DSL) lexer, parser, and AST compiler, the analytical forward and inverse kinematics engine (solve_fk, solve_ik), trajectory reachability and feedrate boundary validation, and the low-level binary wire framing protocol codecs.

πŸ“ Tool structure

scarajectory is based on OOP and Clean Architecture.

Tool structure

Click to expand framework structure</summary>

    scarajectory/
         β”œβ”€β”€ core/
         β”‚Β Β  β”œβ”€β”€ __init__.py
         β”‚Β Β  β”œβ”€β”€ model/
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ __init__.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ jog/
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ __init__.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ jog_axis.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ jog_command.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  └── jog_direction.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ preferences/
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ connection_preference.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  └── __init__.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ protocol/
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ __init__.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ protocol_mode.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  └── scara_response.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ state/
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ __init__.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ stream_session.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  └── stream_state.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ streaming/
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ __init__.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ stream_config.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  └── stream_pacing_config.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ telemetry/
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ diagnostics_bundle.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ diagnostics_snapshot.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ fault_event.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ __init__.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ move_event.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ scara_status.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ stream_progress.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  └── stream_summary.py
         β”‚Β Β  β”‚Β Β  └── trajectory/
         β”‚Β Β  β”‚Β Β      β”œβ”€β”€ plan_metrics.py
         β”‚Β Β  β”‚Β Β      β”œβ”€β”€ validation_report.py
         β”‚Β Β  β”‚Β Β      └── waypoint.py
         β”‚Β Β  └── service/
         β”‚Β Β      β”œβ”€β”€ barrier/
         β”‚Β Β      β”‚Β Β  β”œβ”€β”€ iflow_barrier.py
         β”‚Β Β      β”‚Β Β  β”œβ”€β”€ iflow_barrier_coordinator.py
         β”‚Β Β      β”‚Β Β  └── __init__.py
         β”‚Β Β      β”œβ”€β”€ classifier/
         β”‚Β Β      β”‚Β Β  β”œβ”€β”€ iflow_status_classifier.py
         β”‚Β Β      β”‚Β Β  β”œβ”€β”€ ihoming_status_classifier.py
         β”‚Β Β      β”‚Β Β  β”œβ”€β”€ imotion_status_classifier.py
         β”‚Β Β      β”‚Β Β  β”œβ”€β”€ __init__.py
         β”‚Β Β      β”‚Β Β  └── iresponse_parser.py
         β”‚Β Β      β”œβ”€β”€ connection/
         β”‚Β Β      β”‚Β Β  β”œβ”€β”€ ichannel_dispatcher.py
         β”‚Β Β      β”‚Β Β  β”œβ”€β”€ iconnection.py
         β”‚Β Β      β”‚Β Β  β”œβ”€β”€ __init__.py
         β”‚Β Β      β”‚Β Β  β”œβ”€β”€ iraw_channel.py
         β”‚Β Β      β”‚Β Β  └── istream_connection.py
         β”‚Β Β      β”œβ”€β”€ engine.py
         β”‚Β Β      β”œβ”€β”€ event/
         β”‚Β Β      β”‚Β Β  β”œβ”€β”€ ibinary_frame_dispatcher.py
         β”‚Β Β      β”‚Β Β  β”œβ”€β”€ ibinary_frame_handler.py
         β”‚Β Β      β”‚Β Β  └── __init__.py
         β”‚Β Β      β”œβ”€β”€ __init__.py
         β”‚Β Β      β”œβ”€β”€ iservice.py
         β”‚Β Β      β”œβ”€β”€ kinematics/
         β”‚Β Β      β”‚Β Β  β”œβ”€β”€ __init__.py
         β”‚Β Β      β”‚Β Β  β”œβ”€β”€ iscara_deadzone_calculator.py
         β”‚Β Β      β”‚Β Β  β”œβ”€β”€ scara_deadzone_calculator.py
         β”‚Β Β      β”‚Β Β  └── scara_deadzone_calculator_factory.py
         β”‚Β Β      β”œβ”€β”€ manipulator/
         β”‚Β Β      β”‚Β Β  β”œβ”€β”€ ijog_controller.py
         β”‚Β Β      β”‚Β Β  β”œβ”€β”€ imotion_controller.py
         β”‚Β Β      β”‚Β Β  β”œβ”€β”€ __init__.py
         β”‚Β Β      β”‚Β Β  └── iquery_controller.py
         β”‚Β Β      β”œβ”€β”€ pacing/
         β”‚Β Β      β”‚Β Β  β”œβ”€β”€ iflow_pacing_controller.py
         β”‚Β Β      β”‚Β Β  └── __init__.py
         β”‚Β Β      β”œβ”€β”€ packet/
         β”‚Β Β      β”‚Β Β  β”œβ”€β”€ __init__.py
         β”‚Β Β      β”‚Β Β  └── ipacket_strategy.py
         β”‚Β Β      β”œβ”€β”€ preferences/
         β”‚Β Β      β”‚Β Β  β”œβ”€β”€ connection_preference_factory.py
         β”‚Β Β      β”‚Β Β  β”œβ”€β”€ iconnection_repository.py
         β”‚Β Β      β”‚Β Β  └── __init__.py
         β”‚Β Β      β”œβ”€β”€ service_factory.py
         β”‚Β Β      β”œβ”€β”€ settings/
         β”‚Β Β      β”‚Β Β  β”œβ”€β”€ __init__.py
         β”‚Β Β      β”‚Β Β  β”œβ”€β”€ iscara_bounds_loader.py
         β”‚Β Β      β”‚Β Β  β”œβ”€β”€ iscara_bounds_parser.py
         β”‚Β Β      β”‚Β Β  β”œβ”€β”€ iscara_transmission_loader.py
         β”‚Β Β      β”‚Β Β  └── istream_config_loader.py
         β”‚Β Β      β”œβ”€β”€ state/
         β”‚Β Β      β”‚Β Β  β”œβ”€β”€ __init__.py
         β”‚Β Β      β”‚Β Β  β”œβ”€β”€ istream_state_controller.py
         β”‚Β Β      β”‚Β Β  β”œβ”€β”€ istream_state_machine.py
         β”‚Β Β      β”‚Β Β  └── session_factory.py
         β”‚Β Β      β”œβ”€β”€ storage/
         β”‚Β Β      β”‚Β Β  β”œβ”€β”€ __init__.py
         β”‚Β Β      β”‚Β Β  β”œβ”€β”€ iplan_loader.py
         β”‚Β Β      β”‚Β Β  β”œβ”€β”€ iplan_storage_service.py
         β”‚Β Β      β”‚Β Β  └── iplan_storer.py
         β”‚Β Β      β”œβ”€β”€ streaming/
         β”‚Β Β      β”‚Β Β  β”œβ”€β”€ config_factory.py
         β”‚Β Β      β”‚Β Β  β”œβ”€β”€ ibinary_program_streamer.py
         β”‚Β Β      β”‚Β Β  β”œβ”€β”€ imotion_streamer.py
         β”‚Β Β      β”‚Β Β  β”œβ”€β”€ __init__.py
         β”‚Β Β      β”‚Β Β  β”œβ”€β”€ istream_control_transmitter.py
         β”‚Β Β      β”‚Β Β  β”œβ”€β”€ istream_dispatcher.py
         β”‚Β Β      β”‚Β Β  β”œβ”€β”€ istream_playback_controller.py
         β”‚Β Β      β”‚Β Β  β”œβ”€β”€ observer/
         β”‚Β Β      β”‚Β Β  β”‚Β Β  β”œβ”€β”€ __init__.py
         β”‚Β Β      β”‚Β Β  β”‚Β Β  β”œβ”€β”€ iobservable.py
         β”‚Β Β      β”‚Β Β  β”‚Β Β  β”œβ”€β”€ iobserver.py
         β”‚Β Β      β”‚Β Β  β”‚Β Β  └── istream_observer_dispatcher.py
         β”‚Β Β      β”‚Β Β  └── stream_pacing_config_factory.py
         β”‚Β Β      β”œβ”€β”€ telemetry/
         β”‚Β Β      β”‚Β Β  β”œβ”€β”€ diagnostics_snapshot_factory.py
         β”‚Β Β      β”‚Β Β  β”œβ”€β”€ fault_event_factory.py
         β”‚Β Β      β”‚Β Β  β”œβ”€β”€ __init__.py
         β”‚Β Β      β”‚Β Β  └── move_event_factory.py
         β”‚Β Β      β”œβ”€β”€ tool/
         β”‚Β Β      β”‚Β Β  β”œβ”€β”€ __init__.py
         β”‚Β Β      β”‚Β Β  β”œβ”€β”€ ipurge_valve_actuator.py
         β”‚Β Β      β”‚Β Β  └── itool_controller.py
         β”‚Β Β      β”œβ”€β”€ trajectory/
         β”‚Β Β      β”‚Β Β  β”œβ”€β”€ contract/
         β”‚Β Β      β”‚Β Β  β”‚Β Β  β”œβ”€β”€ __init__.py
         β”‚Β Β      β”‚Β Β  β”‚Β Β  β”œβ”€β”€ iplan_command_service.py
         β”‚Β Β      β”‚Β Β  β”‚Β Β  β”œβ”€β”€ iplan_persistence_service.py
         β”‚Β Β      β”‚Β Β  β”‚Β Β  └── iplan_validation_service.py
         β”‚Β Β      β”‚Β Β  β”œβ”€β”€ history/
         β”‚Β Β      β”‚Β Β  β”‚Β Β  β”œβ”€β”€ __init__.py
         β”‚Β Β      β”‚Β Β  β”‚Β Β  β”œβ”€β”€ iplan_history.py
         β”‚Β Β      β”‚Β Β  β”‚Β Β  β”œβ”€β”€ iplan_history_saver.py
         β”‚Β Β      β”‚Β Β  β”‚Β Β  β”œβ”€β”€ plan_history.py
         β”‚Β Β      β”‚Β Β  β”‚Β Β  └── plan_history_factory.py
         β”‚Β Β      β”‚Β Β  β”œβ”€β”€ __init__.py
         β”‚Β Β      β”‚Β Β  └── plan/
         β”‚Β Β      β”‚Β Β      β”œβ”€β”€ history/
         β”‚Β Β      β”‚Β Β      β”‚Β Β  β”œβ”€β”€ __init__.py
         β”‚Β Β      β”‚Β Β      β”‚Β Β  β”œβ”€β”€ plan_history_service.py
         β”‚Β Β      β”‚Β Β      β”‚Β Β  └── plan_history_service_factory.py
         β”‚Β Β      β”‚Β Β      β”œβ”€β”€ __init__.py
         β”‚Β Β      β”‚Β Β      β”œβ”€β”€ itrajectory_history.py
         β”‚Β Β      β”‚Β Β      β”œβ”€β”€ itrajectory_mutable.py
         β”‚Β Β      β”‚Β Β      β”œβ”€β”€ itrajectory_read_only.py
         β”‚Β Β      β”‚Β Β      β”œβ”€β”€ mutation/
         β”‚Β Β      β”‚Β Β      β”‚Β Β  β”œβ”€β”€ __init__.py
         β”‚Β Β      β”‚Β Β      β”‚Β Β  β”œβ”€β”€ iplan_bulk_mutator.py
         β”‚Β Β      β”‚Β Β      β”‚Β Β  β”œβ”€β”€ iplan_mutation_service.py
         β”‚Β Β      β”‚Β Β      β”‚Β Β  β”œβ”€β”€ iplan_point_mutator.py
         β”‚Β Β      β”‚Β Β      β”‚Β Β  β”œβ”€β”€ plan_mutation_service.py
         β”‚Β Β      β”‚Β Β      β”‚Β Β  └── plan_mutation_service_factory.py
         β”‚Β Β      β”‚Β Β      β”œβ”€β”€ observer/
         β”‚Β Β      β”‚Β Β      β”‚Β Β  β”œβ”€β”€ __init__.py
         β”‚Β Β      β”‚Β Β      β”‚Β Β  β”œβ”€β”€ iplan_observer_dispatcher.py
         β”‚Β Β      β”‚Β Β      β”‚Β Β  β”œβ”€β”€ itrajectory_observer.py
         β”‚Β Β      β”‚Β Β      β”‚Β Β  β”œβ”€β”€ plan_observer_dispatcher.py
         β”‚Β Β      β”‚Β Β      β”‚Β Β  └── plan_observer_dispatcher_factory.py
         β”‚Β Β      β”‚Β Β      β”œβ”€β”€ selection/
         β”‚Β Β      β”‚Β Β      β”‚Β Β  β”œβ”€β”€ __init__.py
         β”‚Β Β      β”‚Β Β      β”‚Β Β  β”œβ”€β”€ iplan_selection_coordinator.py
         β”‚Β Β      β”‚Β Β      β”‚Β Β  β”œβ”€β”€ iplan_selection_manager.py
         β”‚Β Β      β”‚Β Β      β”‚Β Β  β”œβ”€β”€ iplan_selection_navigator.py
         β”‚Β Β      β”‚Β Β      β”‚Β Β  β”œβ”€β”€ iplan_selection_state.py
         β”‚Β Β      β”‚Β Β      β”‚Β Β  β”œβ”€β”€ plan_selection_coordinator.py
         β”‚Β Β      β”‚Β Β      β”‚Β Β  β”œβ”€β”€ plan_selection_coordinator_factory.py
         β”‚Β Β      β”‚Β Β      β”‚Β Β  β”œβ”€β”€ plan_selection_manager.py
         β”‚Β Β      β”‚Β Β      β”‚Β Β  β”œβ”€β”€ plan_selection_manager_factory.py
         β”‚Β Β      β”‚Β Β      β”‚Β Β  β”œβ”€β”€ plan_selection_navigator.py
         β”‚Β Β      β”‚Β Β      β”‚Β Β  β”œβ”€β”€ plan_selection_navigator_factory.py
         β”‚Β Β      β”‚Β Β      β”‚Β Β  └── plan_selection_state.py
         β”‚Β Β      β”‚Β Β      └── store/
         β”‚Β Β      β”‚Β Β          β”œβ”€β”€ __init__.py
         β”‚Β Β      β”‚Β Β          β”œβ”€β”€ iwaypoint_bulk_mutator.py
         β”‚Β Β      β”‚Β Β          β”œβ”€β”€ iwaypoint_mutator.py
         β”‚Β Β      β”‚Β Β          β”œβ”€β”€ iwaypoint_query.py
         β”‚Β Β      β”‚Β Β          β”œβ”€β”€ iwaypoint_store.py
         β”‚Β Β      β”‚Β Β          β”œβ”€β”€ waypoint_bulk_mutator.py
         β”‚Β Β      β”‚Β Β          β”œβ”€β”€ waypoint_mutator.py
         β”‚Β Β      β”‚Β Β          β”œβ”€β”€ waypoint_query.py
         β”‚Β Β      β”‚Β Β          β”œβ”€β”€ waypoint_store.py
         β”‚Β Β      β”‚Β Β          └── waypoint_store_factory.py
         β”‚Β Β      β”œβ”€β”€ transmission/
         β”‚Β Β      β”‚Β Β  β”œβ”€β”€ __init__.py
         β”‚Β Β      β”‚Β Β  └── itransmission_step_calculator.py
         β”‚Β Β      └── worker/
         β”‚Β Β          β”œβ”€β”€ ibyte_sender.py
         β”‚Β Β          β”œβ”€β”€ icommand_formatter.py
         β”‚Β Β          β”œβ”€β”€ icommand_sender.py
         β”‚Β Β          β”œβ”€β”€ iexecution_service.py
         β”‚Β Β          β”œβ”€β”€ iexecution_worker.py
         β”‚Β Β          β”œβ”€β”€ __init__.py
         β”‚Β Β          β”œβ”€β”€ istream_bytes_receiver.py
         β”‚Β Β          β”œβ”€β”€ istream_line_receiver.py
         β”‚Β Β          └── istream_loop_runner.py
         β”œβ”€β”€ engine.py
         β”œβ”€β”€ infrastructure/
         β”‚Β Β  β”œβ”€β”€ barrier/
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ flow_barrier.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ flow_barrier_factory.py
         β”‚Β Β  β”‚Β Β  └── __init__.py
         β”‚Β Β  β”œβ”€β”€ classifier/
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ __init__.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ iresponse_classification_rule.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ response_classification_registry.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ response_classification_registry_factory.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ response_classification_rule.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ response_parser.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ response_parser_factory.py
         β”‚Β Β  β”‚Β Β  └── status/
         β”‚Β Β  β”‚Β Β      β”œβ”€β”€ flow_status_classifier.py
         β”‚Β Β  β”‚Β Β      β”œβ”€β”€ flow_status_classifier_factory.py
         β”‚Β Β  β”‚Β Β      β”œβ”€β”€ homing_status_classifier.py
         β”‚Β Β  β”‚Β Β      β”œβ”€β”€ homing_status_classifier_factory.py
         β”‚Β Β  β”‚Β Β      β”œβ”€β”€ __init__.py
         β”‚Β Β  β”‚Β Β      β”œβ”€β”€ motion_status_classifier.py
         β”‚Β Β  β”‚Β Β      └── motion_status_classifier_factory.py
         β”‚Β Β  β”œβ”€β”€ cli/
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ engine.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ icli.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ __init__.py
         β”‚Β Β  β”‚Β Β  └── setup/
         β”‚Β Β  β”‚Β Β      β”œβ”€β”€ bundle.py
         β”‚Β Β  β”‚Β Β      β”œβ”€β”€ dep_validator.py
         β”‚Β Β  β”‚Β Β      β”œβ”€β”€ dependencies.py
         β”‚Β Β  β”‚Β Β      β”œβ”€β”€ factory.py
         β”‚Β Β  β”‚Β Β      β”œβ”€β”€ __init__.py
         β”‚Β Β  β”‚Β Β      β”œβ”€β”€ keys.py
         β”‚Β Β  β”‚Β Β      β”œβ”€β”€ opt_validator.py
         β”‚Β Β  β”‚Β Β      β”œβ”€β”€ options.py
         β”‚Β Β  β”‚Β Β      β”œβ”€β”€ registry.py
         β”‚Β Β  β”‚Β Β      └── validator.py
         β”‚Β Β  β”œβ”€β”€ command/
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ command_bundle.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ icommand_definition.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ icommand_executor.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ __init__.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ studio_command_definition.py
         β”‚Β Β  β”‚Β Β  └── studio_command_executor.py
         β”‚Β Β  β”œβ”€β”€ config/
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ scara_geometry.json
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ scarajectory.cfg
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ scarajectory.logo
         β”‚Β Β  β”‚Β Β  └── scheme.json
         β”‚Β Β  β”œβ”€β”€ connection/
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ channel_dispatcher.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ channel_dispatcher_factory.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ __init__.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ istream_raw_transceiver.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ stream_connection_manager.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ stream_connection_manager_factory.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ stream_raw_transceiver.py
         β”‚Β Β  β”‚Β Β  └── stream_raw_transceiver_factory.py
         β”‚Β Β  β”œβ”€β”€ event/
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ binary_frame_dispatcher.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ binary_frame_dispatcher_factory.py
         β”‚Β Β  β”‚Β Β  └── __init__.py
         β”‚Β Β  β”œβ”€β”€ formatter/
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ command/
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ config_command_formatter.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ __init__.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ jog_command_formatter.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ motion_command_formatter.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ query_command_formatter.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ system_command_formatter.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  └── tool_command_formatter.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ command_formatter.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ command_formatter_factory.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ command_templates.py
         β”‚Β Β  β”‚Β Β  └── __init__.py
         β”‚Β Β  β”œβ”€β”€ gui/
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ canvas/
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ bundle.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ canvas_event_binder.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ canvas_event_binder_factory.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ handler/
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ canvas_drag_handler.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ canvas_event_context.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ canvas_mouse_handler.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ canvas_mouse_handler_factory.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ canvas_shape_handler.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ canvas_tool_handler.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ icanvas_mouse_handler.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ __init__.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ mouse_handler_bundle.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ mouse_handler_init_bundle.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ pan/
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ canvas_viewport_pan_handler.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ canvas_viewport_pan_handler_factory.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ icanvas_viewport_pan_handler.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  └── __init__.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  └── selection/
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β      β”œβ”€β”€ canvas_selection_mouse_handler.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β      β”œβ”€β”€ canvas_selection_mouse_handler_factory.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β      β”œβ”€β”€ icanvas_selection_mouse_handler.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β      └── __init__.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ icanvas.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ __init__.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ navigation/
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ canvas_view_navigator.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ canvas_view_navigator_factory.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ icanvas_view_navigator.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ icanvas_view_target.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  └── __init__.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ observer/
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ canvas_plan_observer_bridge.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ canvas_plan_observer_bridge_factory.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ icanvas_plan_observer_bridge.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  └── __init__.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ render/
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ forbidden_zone_renderer.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ ilayer_renderer.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ __init__.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ polar_grid_renderer.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ preview_renderer.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ reach_boundary_renderer.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ renderer.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ trajectory_renderer.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ waypoint_node_renderer.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  └── waypoint_node_renderer_factory.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ status/
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ canvas_status_presenter.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ canvas_status_presenter_factory.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ icanvas_status_presenter.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  └── __init__.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ trajectory_canvas.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  └── trajectory_canvas_factory.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ connection/
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ __init__.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ iport_connection_delegate.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ null_port_connection_delegate.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  └── port_connection_panel.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ console/
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ __init__.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ serial_console.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ serial_console_builder.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  └── serial_console_builder_factory.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ controls/
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ bundle.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ controls_panel.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ controls_panel_factory.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ icontrols_panel.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ __init__.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ itabs_assembler.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ manipulator_controllers_bundle.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ manipulator_controllers_factory.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ tabs_assembler.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ tabs_assembler_factory.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  └── tabs_bundle.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ dsl/
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ bundle.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ code_editor.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ code_editor_factory.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ console_view.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ document/
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ document_manager.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ document_manager_factory.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ example_catalog.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ example_catalog_factory.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  └── __init__.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ dsl_editor_tab.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ dsl_editor_tab_factory.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ handler/
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ execution_handler.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ execution_handler_bundle.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ execution_handler_factory.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ file_handler.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ file_handler_bundle.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ file_handler_factory.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ iexecution_delegate.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ ifile_delegate.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  └── __init__.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ __init__.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ syntax/
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ highlighter.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ highlighter_factory.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ ihighlighter.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ __init__.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ itag_applier.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ itokenizer.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ tag_applier.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ tag_applier_factory.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ token.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ tokenizer.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  └── tokenizer_factory.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  └── toolbar.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ editor/
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ __init__.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ table/
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ bundle.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ __init__.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ itable.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ selection_handler.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ selection_handler_factory.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  └── trajectory_table.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ waypoint_coordinate_inputs.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ waypoint_edit_applier.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ waypoint_edit_applier_factory.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  └── waypoint_editor.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ emulator/
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ emulator_launcher.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ emulator_launcher_factory.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ iemulator_launcher.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  └── __init__.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ igui.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ __init__.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ layout/
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ canvas_pane_builder.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ canvas_pane_builder_factory.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ editor_pane_builder.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ editor_pane_builder_factory.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ icanvas_pane_builder.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ ieditor_pane_builder.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ __init__.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ itoolbar_layout_builder.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ main_content_builder.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ main_content_builder_factory.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ toolbar_layout_builder.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  └── toolbar_layout_builder_factory.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ manipulator/
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ imanipulator_action_delegate.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ __init__.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ jog/
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ axis_grid_panel.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ axis_grid_panel_factory.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ controllers_bundle.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ __init__.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ jog_tab.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ jog_tab_factory.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ panel_bundle.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ power_panel.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ power_panel_factory.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ raw_command_panel.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ raw_command_panel_factory.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ tool_panel.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  └── tool_panel_factory.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ manipulator_override_panel.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  └── null_manipulator_action_delegate.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ menu/
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ app_menu_bar.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ app_menu_bar_factory.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ builders_bundle.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ bundle.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ iapp_menu_bar.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ __init__.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ menu_hotkey_binder.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ menu_hotkey_binder_factory.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ menu_layout_builder.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  └── menu_layout_builder_factory.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ model/
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ canvas_interaction_state.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ canvas_settings.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ canvas_tool_mode.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ __init__.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  └── viewport_transform.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ preview/
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ __init__.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ preview_tab.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  └── preview_tab_factory.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ scarajectory_gui.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ scarajectory_gui_bundle.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ scarajectory_gui_factory.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ scarajectory_gui_init_bundle.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ streaming/
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ bundle.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ handler/
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ __init__.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ playback_handler_bundle.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ stream_playback_action_handler.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ stream_playback_action_handler_factory.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ stream_tool_action_handler.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  └── stream_tool_action_handler_factory.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ __init__.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ observer/
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ gui_stream_observer_bridge.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ gui_stream_observer_bridge_factory.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ igui_stream_observer_bridge.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  └── __init__.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ panel/
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ __init__.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ istream_control_delegate.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ stream_control_panel.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ stream_progress_adapter.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”‚Β Β  └── stream_status_bar.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ streamer_action_bundle.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ streamer_controllers_bundle.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ streamer_tab.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  └── streamer_tab_factory.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ theme/
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ __init__.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ theme_button_styler.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ theme_button_styler_factory.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ theme_manager.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ theme_notebook_styler.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  └── theme_notebook_styler_factory.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ toolbar/
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ bundle.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ __init__.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ itoolbar.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ navigation_controls.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ navigation_controls_factory.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ parameter_inputs.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ parameter_inputs_bundle.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ parameter_inputs_factory.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ tool_selector.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ tool_selector_factory.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ toolbar.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  └── toolbar_factory.py
         β”‚Β Β  β”‚Β Β  └── validation/
         β”‚Β Β  β”‚Β Β      β”œβ”€β”€ __init__.py
         β”‚Β Β  β”‚Β Β      β”œβ”€β”€ validation_tab.py
         β”‚Β Β  β”‚Β Β      └── validation_tab_factory.py
         β”‚Β Β  β”œβ”€β”€ __init__.py
         β”‚Β Β  β”œβ”€β”€ manipulator/
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ __init__.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ jog_controller.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ jog_controller_factory.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ motion_controller.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ motion_controller_factory.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ query_controller.py
         β”‚Β Β  β”‚Β Β  └── query_controller_factory.py
         β”‚Β Β  β”œβ”€β”€ pacing/
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ bundle.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ flow_barrier_coordinator.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ flow_barrier_coordinator_factory.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ flow_pacing_bundle_factory.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ flow_pacing_controller.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ flow_pacing_controller_factory.py
         β”‚Β Β  β”‚Β Β  └── __init__.py
         β”‚Β Β  β”œβ”€β”€ packet/
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ binary_packet_strategy.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ binary_packet_strategy_factory.py
         β”‚Β Β  β”‚Β Β  └── __init__.py
         β”‚Β Β  β”œβ”€β”€ preferences/
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ connection_repository.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ connection_repository_factory.py
         β”‚Β Β  β”‚Β Β  └── __init__.py
         β”‚Β Β  β”œβ”€β”€ settings/
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ bounds/
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ __init__.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ scara_bounds_loader.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ scara_bounds_loader_factory.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ scara_bounds_parser.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  └── scara_bounds_parser_factory.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ __init__.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ isettings_reader.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ settings_reader.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ settings_reader_factory.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ stream/
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ __init__.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ stream_config_loader.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  └── stream_config_loader_factory.py
         β”‚Β Β  β”‚Β Β  └── transmission/
         β”‚Β Β  β”‚Β Β      β”œβ”€β”€ __init__.py
         β”‚Β Β  β”‚Β Β      β”œβ”€β”€ scara_transmission_loader.py
         β”‚Β Β  β”‚Β Β      └── scara_transmission_loader_factory.py
         β”‚Β Β  β”œβ”€β”€ state/
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ __init__.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ stream_state_machine.py
         β”‚Β Β  β”‚Β Β  └── stream_state_machine_factory.py
         β”‚Β Β  β”œβ”€β”€ storage/
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ __init__.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ plan_loader.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ plan_storage_service.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ plan_storage_service_factory.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ plan_storer.py
         β”‚Β Β  β”‚Β Β  └── trajectory_serializer.py
         β”‚Β Β  β”œβ”€β”€ streaming/
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ assembly/
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ __init__.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ stream_pacing_assembler.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ stream_pipeline_assembler.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ stream_transport_assembler.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ stream_worker_assembler.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  └── worker_bundle.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ binary_program_streamer.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ binary_program_streamer_factory.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ bundle.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ __init__.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ observer/
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ __init__.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ istream_observer_registry.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ istream_telemetry_notifier.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ stream_observer_dispatcher.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ stream_observer_dispatcher_factory.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ stream_observer_registry.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ stream_observer_registry_factory.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ stream_telemetry_notifier.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  └── stream_telemetry_notifier_factory.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ stream_control_transmitter.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ stream_control_transmitter_factory.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ stream_playback_controller.py
         β”‚Β Β  β”‚Β Β  └── stream_playback_controller_factory.py
         β”‚Β Β  β”œβ”€β”€ tool/
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ __init__.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ tool_controller.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ tool_controller_factory.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ valve_pulse_worker.py
         β”‚Β Β  β”‚Β Β  └── valve_pulse_worker_factory.py
         β”‚Β Β  β”œβ”€β”€ transmission/
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ __init__.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ transmission_step_calculator.py
         β”‚Β Β  β”‚Β Β  └── transmission_step_calculator_factory.py
         β”‚Β Β  β”œβ”€β”€ transport/
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ bundle.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ driver/
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ ichannel.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ __init__.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ serial_channel.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ serial_channel_factory.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ serial_port_scanner.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ tcp_channel.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  └── tcp_channel_factory.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ __init__.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ istream_transport_connection.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ istream_transport_transceiver.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ listener/
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ __init__.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ itransport_listener.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ itransport_listener_holder.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ null_transport_listener.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ stream_ascii_transport_listener.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ stream_ascii_transport_listener_factory.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ stream_binary_transport_listener.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ stream_binary_transport_listener_factory.py
         β”‚Β Β  β”‚Β Β  β”‚Β Β  └── transport_listener_holder.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ stream_transport_connection.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ stream_transport_connection_factory.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ stream_transport_transceiver.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ stream_transport_transceiver_factory.py
         β”‚Β Β  β”‚Β Β  β”œβ”€β”€ transport_factory.py
         β”‚Β Β  β”‚Β Β  └── worker/
         β”‚Β Β  β”‚Β Β      β”œβ”€β”€ __init__.py
         β”‚Β Β  β”‚Β Β      β”œβ”€β”€ itransport_reader_worker.py
         β”‚Β Β  β”‚Β Β      β”œβ”€β”€ transport_reader_worker.py
         β”‚Β Β  β”‚Β Β      └── transport_reader_worker_factory.py
         β”‚Β Β  └── worker/
         β”‚Β Β      β”œβ”€β”€ binary/
         β”‚Β Β      β”‚Β Β  β”œβ”€β”€ binary_stream_execution_worker.py
         β”‚Β Β      β”‚Β Β  β”œβ”€β”€ binary_stream_execution_worker_factory.py
         β”‚Β Β      β”‚Β Β  β”œβ”€β”€ binary_stream_frame_handler.py
         β”‚Β Β      β”‚Β Β  β”œβ”€β”€ binary_stream_frame_handler_factory.py
         β”‚Β Β      β”‚Β Β  β”œβ”€β”€ binary_stream_loop_runner.py
         β”‚Β Β      β”‚Β Β  β”œβ”€β”€ binary_stream_loop_runner_factory.py
         β”‚Β Β      β”‚Β Β  β”œβ”€β”€ ibinary_stream_frame_handler.py
         β”‚Β Β      β”‚Β Β  β”œβ”€β”€ ibinary_stream_loop_runner.py
         β”‚Β Β      β”‚Β Β  └── __init__.py
         β”‚Β Β      β”œβ”€β”€ __init__.py
         β”‚Β Β      β”œβ”€β”€ istream_queue_drainer.py
         β”‚Β Β      β”œβ”€β”€ istream_step_dispatcher.py
         β”‚Β Β      β”œβ”€β”€ stream_execution_worker.py
         β”‚Β Β      β”œβ”€β”€ stream_execution_worker_factory.py
         β”‚Β Β      β”œβ”€β”€ stream_loop_runner.py
         β”‚Β Β      β”œβ”€β”€ stream_loop_runner_factory.py
         β”‚Β Β      β”œβ”€β”€ stream_queue_drainer.py
         β”‚Β Β      β”œβ”€β”€ stream_queue_drainer_factory.py
         β”‚Β Β      β”œβ”€β”€ stream_step_dispatcher.py
         β”‚Β Β      └── stream_step_dispatcher_factory.py
         β”œβ”€β”€ __init__.py
         β”œβ”€β”€ py.typed
         └── setup/
             β”œβ”€β”€ assembly/
             β”‚Β Β  β”œβ”€β”€ app_core_assembler.py
             β”‚Β Β  β”œβ”€β”€ app_core_bundle.py
             β”‚Β Β  β”œβ”€β”€ app_presentation_assembler.py
             β”‚Β Β  β”œβ”€β”€ app_runtime_assembler.py
             β”‚Β Β  β”œβ”€β”€ app_runtime_bundle.py
             β”‚Β Β  └── __init__.py
             β”œβ”€β”€ bundle.py
             β”œβ”€β”€ dep_validator.py
             β”œβ”€β”€ dependencies.py
             β”œβ”€β”€ factory.py
             β”œβ”€β”€ __init__.py
             β”œβ”€β”€ keys.py
             β”œβ”€β”€ opt_validator.py
             β”œβ”€β”€ options.py
             β”œβ”€β”€ pipeline/
             β”‚Β Β  β”œβ”€β”€ dsl_pipeline_builder.py
             β”‚Β Β  β”œβ”€β”€ __init__.py
             β”‚Β Β  β”œβ”€β”€ plan_pipeline_builder.py
             β”‚Β Β  β”œβ”€β”€ plan_pipeline_bundle.py
             β”‚Β Β  β”œβ”€β”€ stream_pipeline_builder.py
             β”‚Β Β  └── stream_pipeline_bundle.py
             β”œβ”€β”€ registry.py
             └── validator.py

     106 directories, 578 files

</details>

πŸ— Architecture & SOLID Principles

scarajectory is built on a strictly decoupled, Layered Clean Architecture where presentation, domain logic, AST compilation, and hardware communication are segregated through pure Python protocols:

                  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                  β”‚                     ScarajectoryGUI                     β”‚ (Presenter / Main Window)
                  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                               β”‚ Orchestrates UI Components via DTOs
         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
         β–Ό                         β–Ό                         β–Ό                          β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ TrajectoryCanvas β”‚      β”‚ TrajectoryTable β”‚      β”‚   DslEditorTab    β”‚      β”‚   StreamerTab    β”‚
β”‚   (Vector CAD)   β”‚      β”‚   (Data Grid)   β”‚      β”‚(Syntax Highlighterβ”‚      β”‚ (Live Feedrate & β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜      β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜      β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜      β”‚  Device Control) β”‚
         β”‚                         β”‚                         β”‚                β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚                         β”‚                         β”‚                         β”‚
         β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                         β”‚
                      β”‚ Observes / Modifies TrajectoryPlan                             β”‚
                      β–Ό                                                                β”‚
         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                                                  β”‚
         β”‚      TrajectoryPlan      β”‚ (Domain Model)                                   β”‚
         β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                                                  β”‚
                      β”‚                                                                β”‚
         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                          β”‚ Uses ITransport &
         β–Ό                         β–Ό                        β–Ό                          β”‚ Classifiers
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                 β–Ό
β”‚TrajectoryValidat.β”‚      β”‚  ScaraDslService β”‚     β”‚ ScaraPlanExport β”‚        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚(Workspace Bounds)β”‚      β”‚  (DSL Compiler)  β”‚     β”‚  (Plan to DSL)  β”‚        β”‚  SerialStreamer  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜      β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜        β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                   β”‚                                                   β”‚
              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                              β–Ό
              β–Ό                    β–Ό                    β–Ό                     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”            β”‚Response & FlowClsβ”‚
     β”‚   ScaraLexer    β”‚  β”‚   ScaraParser   β”‚  β”‚  ScaraCompiler  β”‚            β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
     β”‚  (Token Stream) β”‚  β”‚(ICommandParser) β”‚  β”‚(IMacroExpander) β”‚
     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
SOLID Principles Compliance
  • S β€” Single Responsibility Principle (SRP):
    • Every module and class has exactly one clearly bounded reason to change.
    • Parser and compiler logic is decomposed into dedicated handlers (MotionCommandParser, ArcCommandParser, JumpMacroExpander, etc.) rather than a monolithic interpreter.
    • Enforced by automated gate: strict limit of $\le 15$ methods per class across the entire codebase.
  • O β€” Open/Closed Principle (OCP):
    • The DSL parser and compiler are open for extension without modifying existing code.
    • New DSL keywords and high-level macros plug into ICommandParser and IMacroExpander registries dynamically.
  • L β€” Liskov Substitution Principle (LSP):
    • Pure structural subtyping via Python @runtime_checkable Protocol definitions. Concrete classes never inherit concrete logic, ensuring complete interchangeability.
  • I β€” Interface Segregation Principle (ISP):
    • Clients depend only on the minimal interfaces they require (ITrajectoryValidator, IScaraLexer, IScaraParser, IScaraCompiler, ISerialStreamer, ITransport).
  • D β€” Dependency Inversion Principle (DIP):
    • Core domain entities and compilers have zero dependencies on lower-level infrastructure (serial drivers, formatters, UI widgets). All dependencies are injected via protocols.
Automated Quality Gates (run_quality_gates.sh)

Every build is validated against 4 strict automated quality gates:

  1. Structural Protocols Gate: Verifies 100% compliance with @runtime_checkable Protocol structural typing.
  2. Interface Segregation Gate (ISP): Verifies that no bloated or unused interfaces exist.
  3. Module Limits Gate: Enforces file length and line length limits ($\le 100$ characters).
  4. Single Responsibility Gate (SRP): Strictly enforces $\le 15$ methods per class.
🌐 SCARA Ecosystem & Dual-Mode Motor Actuation

scarajectory is the desktop CAD/CAM studio and trajectory streaming hub within the unified SCARA robotics architecture:

  • scaralang Integration: scarajectory uses scaralang as the Single Source of Truth (SSoT) to parse, validate, and compile Cartesian trajectories and .scara DSL scripts into deterministic binary wire protocol frames (0xAA 0x55).
  • Hardware Streaming to scara_base: Wire frames stream over UART / USB-CDC to the Raspberry Pi Pico (RP2040) firmware, which executes real-time motion across dual motor drive modes:
    • Open-Loop Mode (TMC2209): Coordinated microstepping pulses generated by RP2040 PIO state machines driving silent TMC2209 stepper stages.
    • Closed-Loop Mode (MKS SERVO42D over CAN Bus): NEMA stepper motors equipped with MKS SERVO42D closed-loop modules communicating with the Raspberry Pi Pico over high-speed differential CAN bus (CAN_H / CAN_L) for stall-free closed-loop positioning with magnetic encoder feedback.
  • Digital Twin Synchronization with scaraemu: Real-time closed-loop TCP loopback streaming to scaraemu for visual motion animation and validation before physical execution.

✨ Features

  • Interactive Vector CAD Editor: Real-time vector drafting with dedicated Point, Line, Rectangle, Circle, and Freehand tools with live vertex dragging and viewport zoom/pan.
  • Integrated .scara DSL Editor & AST Compiler: Full-featured code editor with real-time syntax highlighting for industrial SCARA scripts (.scara), AST compilation, and instant bidirectional visual canvas synchronization.
  • Kinematic Reachability & Deadzone Enforcement: Annular geometric validation ensuring trajectories stay within reachable workspace boundaries ($R_{min} = L_1 - L_2 $, $R_{max} = L_1 + L_2$).
  • Undo / Redo Transaction Stack: Non-destructive history management for waypoint additions, modifications, insertions, and deletions (Ctrl+Z, Ctrl+Y).
  • ASCII Protocol Generation: Generates micro-command streaming packets for RP2040 firmware (<pt#X#Y#Z#PHI#SPEED#end>).
  • Sliding Window Hardware Streaming: Multi-threaded USB serial (/dev/ttyACM0) and TCP socket streaming with dynamic ACK tracking, auto-pause on buffer full, progress monitoring, and live Feedrate Override (10% - 200%).
  • Manual Jogging & Diagnostics: Interactive jog grid (X, Y, Z, Phi), vacuum pump and release valve toggles, homing, status queries, and raw serial command console.
  • Configurable Kinematics & Dimensions: Dynamic robot link lengths ($L_1, L_2$), stroke limits ($Z_{min}, Z_{max}$), and speed bounds configurable via CLI options and JSON schema.
  • Strict Quality & SOLID Standards: 100% protocol conformity, zero ISP/SRP violations, 81% test coverage, and 10.00 / 10.00 Pylint score.

πŸ“ SCARA Kinematic & Geometric Configuration

The robot dimensions and physical boundaries can be customized in scara_geometry.json or injected programmatically:

Parameter Default Value Description Β  Β 
l1 150.0 mm Primary arm link length (shoulder to elbow). Β  Β 
l2 120.0 mm Secondary arm link length (elbow to wrist). Β  Β 
r_min 30.0 mm Inner singular deadzone radius ($ L_1 - L_2 $).
r_max 270.0 mm Maximum horizontal reach boundary ($L_1 + L_2$). Β  Β 
z_min 0.0 mm Minimum vertical height limit (bed level). Β  Β 
z_max 100.0 mm Maximum vertical stroke limit. Β  Β 
min_speed 1.0 mm/s Minimum allowable feedrate speed. Β  Β 
max_speed 100.0 mm/s Maximum allowable safe feedrate speed. Β  Β 

πŸ“œ SCARA Domain-Specific Language (DSL) & .scara Programs

scarajectory includes a dedicated, industrial-grade Domain-Specific Language designed specifically for SCARA robotic manipulators. Programs are written in plain text files with the .scara extension and compiled into validated Cartesian trajectories via a clean AST pipeline:

                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                    β”‚     .scara Source       β”‚
                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                 β”‚ ScaraLexer
                                 β–Ό
                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                    β”‚      Token Stream       β”‚
                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                 β”‚ ScaraParser
                                 β–Ό
                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                    β”‚      Abstract AST       β”‚
                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                 β”‚ ScaraCompiler (Macros + Kinematics)
                                 β–Ό
                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                    β”‚     TrajectoryPlan      β”‚ (Waypoints & Protocols)
                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
SCARA DSL Instruction Reference
Category Instruction & Syntax Parameters Description
Motion MOVE_J X <x> Y <y> Z <z> [P <phi>] X, Y, Z (mm), P (deg) Rapid Cartesian point-to-point motion.
Β  MOVE_L X <x> Y <y> Z <z> [P <phi>] X, Y, Z (mm), P (deg) Linear interpolated Cartesian path.
Β  ARC_CW X <x> Y <y> I <i> J <j> [Z <z>] X, Y target, I, J center offset Clockwise circular arc interpolation.
Β  ARC_CCW X <x> Y <y> I <i> J <j> [Z <z>] X, Y target, I, J center offset Counter-clockwise circular arc interpolation.
Β  APPROACH DIST <d> DIST (mm) Vertical descent towards workpiece along Z.
Β  RETRACT DIST <d> DIST (mm) Vertical clearance ascent along Z.
Macros JUMP X <x> Y <y> Z <z> [ARCH <h>] X, Y, Z, ARCH apex clearance Smooth 3D parabolic pick-and-place arch motion.
Β  PALLET ROWS <r> COLS <c> DX <dx> DY <dy> Grid dimensions & spacing Generates structured 2D Cartesian pallet matrix.
Β  TANGENT_ARC RADIUS <r> ANGLE <a> RADIUS (mm), ANGLE (deg) Smooth tangential curve blending into path.
Actuators PUMP <ON\|OFF> ON or OFF Actuates end-effector vacuum pump.
Β  VALVE <ON\|OFF> ON or OFF Opens or closes pneumatic release blow-off valve.
Β  WAIT <ms> ms (milliseconds) Dwells execution for specified hardware duration.
Β  HOME None Triggers complete multi-axis homing routine.
Dynamics SPEED <RAPID\|WORK> <val> RAPID or WORK, feedrate (mm/s) Configures travel or working linear feedrate.
Β  ACCEL <val> val (mm/sΒ²) Configures linear path acceleration limit.
Β  OVERRIDE <percent> percent (10% - 200%) Scales path execution velocity dynamically.
Β  ZONE <OFF\|FINE\|Z1..Z50> Corner rounding tolerance Corner tolerance zone for trajectory smoothing.
Config CONFIG ELBOW <LEFT\|RIGHT> LEFT or RIGHT Sets arm kinematic inverse solution branch.
Β  FRAME X <x> Y <y> Z <z> [PHI <p>] Cartesian offset coordinates Defines user workpiece reference coordinate frame.
Β  PROBE AXIS <Z> FEED <f> Axis identifier, search feedrate Probes touch switch / surface sensor.
Example .scara Program: Industrial Pick & Place
# ----------------------------------------------------
# Industrial Pick-and-Place Cycle with Pneumatic Grip
# ----------------------------------------------------
CONFIG ELBOW LEFT
SPEED RAPID 180.0
SPEED WORK 60.0
ACCEL 400.0
OVERRIDE 100

# Home robot to reference position
HOME

# Rapid move above pick feeder station
MOVE_J X 140.0 Y -30.0 Z 35.0
APPROACH DIST 30.0

# Engage suction cup and pause for vacuum seal
PUMP ON
WAIT 200

# Retract with part
RETRACT DIST 30.0

# Smooth 3D parabolic arch transfer to drop location
JUMP X 180.0 Y 30.0 Z 5.0 ARCH 40.0

# Release part with air pulse
PUMP OFF
VALVE ON
WAIT 100
VALVE OFF

# Retract to safe transit altitude
RETRACT DIST 30.0
HOME

πŸ“‘ Unified Serial ASCII Communication Protocol

All communication between scarajectory, the physical scara_base firmware, and the scaraemu digital twin is governed by a packetized ASCII streaming protocol:

Command Packets (PC $\to$ Robot)
Command Packet Description Response Handshake
<pt#X#Y#Z#PHI#SPEED#end> Push Cartesian trajectory point to FIFO motion buffer <RESP:ACK#QUEUE=n> then <RESP:MOVE_DONE#...>
<CMD:JOG#axis#step> Incremental manual jog (X, Y, Z, P) by step mm/deg <RESP:ACK#JOG_QUEUED#QUEUE=n>
<CMD:OVERRIDE#percent> Real-time feedrate override scaling (10 to 200 %) <RESP:ACK#OVERRIDE=percent>
<CMD:WAIT#ms> Synchronous dwell delay pause on motion controller <RESP:ACK#WAIT_DONE#MS=ms>
<CMD:PUMP#1> / <CMD:PUMP#0> Energize / de-energize vacuum pump actuator <RESP:ACK#PUMP_ON> / <RESP:ACK#PUMP_OFF>
<CMD:VALVE#1> / <CMD:VALVE#0> Open / close pneumatic air release valve <RESP:ACK#VALVE_ON> / <RESP:ACK#VALVE_OFF>
<CMD:HOME> Execute multi-axis homing and calibrate zero <RESP:ACK#HOMING_STARTED> then <RESP:HOMED_SUCCESS#...>
<CMD:ENABLE> / <CMD:DISABLE> Energize / de-energize stepper driver stages <RESP:ACK#MOTORS_ENABLED> / <RESP:ACK#MOTORS_DISABLED>
<CMD:ESTOP> Instant emergency stop and motion queue abort <RESP:ACK#ESTOP_TRIGGERED>
<CMD:HOLD> / <CMD:RESUME> Decelerate to feed hold / resume paused trajectory <RESP:ACK#FEED_HOLD_ACTIVE> / <RESP:ACK#MOTION_RESUMED>
<CMD:STATUS> Query operational machine state and endstop flags <RESP:STATUS#STATE=...#ENDSTOPS=...>
<CMD:GETPOS> Read active Cartesian tool coordinates and orientation <RESP:POS#X=...#Y=...#Z=...#PHI=...>
<CMD:SET_ELBOW#LEFT\|RIGHT> Select inverse kinematic arm solution branch <RESP:ACK#ELBOW=LEFT\|RIGHT>
<CMD:GET_ELBOW> Query active elbow configuration branch <RESP:ELBOW#CONFIG=LEFT\|RIGHT>
<CMD:GET_CONFIG> Read persisted geometry, dynamics, and stroke bounds <RESP:CONFIG#L1=...#L2=...#MIN_SPD=...>
<CMD:SET_CONFIG#...> Update robot link lengths, stroke, and speed bounds <RESP:ACK#CONFIG_STORED...>
<CMD:SAVE_CONFIG> Commit active configuration to RP2040 Flash (CRC32) <RESP:ACK#CONFIG_SAVED>
<CMD:RESET_CONFIG> Restore factory default geometry and kinematic bounds <RESP:ACK#CONFIG_RESET>
Microcontroller Response Packets (Robot $\to$ PC)
Response Packet Category Streamer Meaning
<RESP:ACK#QUEUE=n> Acknowledgment Waypoint accepted into ring buffer; n slots remaining.
<RESP:MOVE_DONE#X=..#Y=..#Z=..#PHI=..> Move Complete Physical execution of waypoint completed. Advances done counter.
<RESP:ACK#WAIT_DONE#...> Action Complete Hardware dwell delay elapsed. Advances streamer progress.
<RESP:ACK#PUMP_ON\|OFF> Action Complete Tool actuation complete. Advances streamer progress.
<RESP:ACK#VALVE_ON\|OFF> Action Complete Valve actuation complete. Advances streamer progress.
<RESP:HOMED_SUCCESS#...> Homing Complete Machine homed and zero-reference established.
<RESP:NACK_BUFFER_FULL> Flow Control Microcontroller queue full; streamer enters auto-pause.
<RESP:NACK_ESTOP_ACTIVE> Error / Safety E-Stop asserted; all motions rejected until reset.
<RESP:NACK_OUT_OF_REACH> Kinematic Rejection Target coordinate outside reachable arm envelope ($R_{max}$).
<RESP:NACK_SINGULARITY_LIMIT> Kinematic Rejection Target inside inner deadzone ($R_{min} = |L_1 - L_2|$).

πŸ“Š Code coverage

Click to expand code coverage</summary>

Name Stmts Miss Cover
scarajectory/__init__.py 9 0 100%
scarajectory/core/__init__.py 9 0 100%
scarajectory/core/model/__init__.py 9 0 100%
scarajectory/core/model/jog/__init__.py 9 0 100%
scarajectory/core/model/jog/jog_axis.py 16 0 100%
scarajectory/core/model/jog/jog_command.py 18 0 100%
scarajectory/core/model/jog/jog_direction.py 14 0 100%
scarajectory/core/model/preferences/__init__.py 9 0 100%
scarajectory/core/model/preferences/connection_preference.py 14 0 100%
scarajectory/core/model/protocol/__init__.py 9 0 100%
scarajectory/core/model/protocol/protocol_mode.py 14 0 100%
scarajectory/core/model/protocol/scara_response.py 16 0 100%
scarajectory/core/model/state/__init__.py 9 0 100%
scarajectory/core/model/state/stream_session.py 19 0 100%
scarajectory/core/model/state/stream_state.py 17 0 100%
scarajectory/core/model/streaming/__init__.py 9 0 100%
scarajectory/core/model/streaming/stream_config.py 18 0 100%
scarajectory/core/model/streaming/stream_pacing_config.py 15 0 100%
scarajectory/core/model/telemetry/__init__.py 9 0 100%
scarajectory/core/model/telemetry/diagnostics_bundle.py 29 0 100%
scarajectory/core/model/telemetry/diagnostics_snapshot.py 29 0 100%
scarajectory/core/model/telemetry/fault_event.py 15 0 100%
scarajectory/core/model/telemetry/move_event.py 14 0 100%
scarajectory/core/model/telemetry/scara_status.py 19 0 100%
scarajectory/core/model/telemetry/stream_progress.py 22 0 100%
scarajectory/core/model/telemetry/stream_summary.py 18 0 100%
scarajectory/core/model/trajectory/waypoint.py 19 0 100%
scarajectory/core/service/__init__.py 9 0 100%
scarajectory/core/service/barrier/__init__.py 9 0 100%
scarajectory/core/service/barrier/iflow_barrier.py 16 0 100%
scarajectory/core/service/barrier/iflow_barrier_coordinator.py 16 0 100%
scarajectory/core/service/classifier/__init__.py 9 0 100%
scarajectory/core/service/classifier/iflow_status_classifier.py 15 0 100%
scarajectory/core/service/classifier/ihoming_status_classifier.py 14 0 100%
scarajectory/core/service/classifier/imotion_status_classifier.py 16 0 100%
scarajectory/core/service/classifier/iresponse_parser.py 16 0 100%
scarajectory/core/service/connection/__init__.py 9 0 100%
scarajectory/core/service/connection/ichannel_dispatcher.py 22 0 100%
scarajectory/core/service/connection/iconnection.py 16 0 100%
scarajectory/core/service/connection/iraw_channel.py 15 0 100%
scarajectory/core/service/connection/istream_connection.py 14 0 100%
scarajectory/core/service/engine.py 38 0 100%
scarajectory/core/service/event/__init__.py 9 0 100%
scarajectory/core/service/event/ibinary_frame_dispatcher.py 15 0 100%
scarajectory/core/service/event/ibinary_frame_handler.py 13 0 100%
scarajectory/core/service/iservice.py 19 0 100%
scarajectory/core/service/kinematics/__init__.py 9 0 100%
scarajectory/core/service/kinematics/iscara_deadzone_calculator.py 14 0 100%
scarajectory/core/service/kinematics/scara_deadzone_calculator.py 16 0 100%
scarajectory/core/service/kinematics/scara_deadzone_calculator_factory.py 17 0 100%
scarajectory/core/service/manipulator/__init__.py 9 0 100%
scarajectory/core/service/manipulator/ijog_controller.py 14 0 100%
scarajectory/core/service/manipulator/imotion_controller.py 16 0 100%
scarajectory/core/service/manipulator/iquery_controller.py 14 0 100%
scarajectory/core/service/pacing/__init__.py 9 0 100%
scarajectory/core/service/pacing/iflow_pacing_controller.py 18 0 100%
scarajectory/core/service/packet/__init__.py 9 0 100%
scarajectory/core/service/packet/ipacket_strategy.py 14 0 100%
scarajectory/core/service/preferences/__init__.py 9 0 100%
scarajectory/core/service/preferences/connection_preference_factory.py 23 0 100%
scarajectory/core/service/preferences/iconnection_repository.py 16 0 100%
scarajectory/core/service/service_factory.py 21 1 95%
scarajectory/core/service/settings/__init__.py 9 0 100%
scarajectory/core/service/settings/iscara_bounds_loader.py 16 0 100%
scarajectory/core/service/settings/iscara_bounds_parser.py 17 0 100%
scarajectory/core/service/settings/iscara_transmission_loader.py 16 0 100%
scarajectory/core/service/settings/istream_config_loader.py 16 0 100%
scarajectory/core/service/state/__init__.py 9 0 100%
scarajectory/core/service/state/istream_state_controller.py 16 0 100%
scarajectory/core/service/state/istream_state_machine.py 18 0 100%
scarajectory/core/service/state/session_factory.py 19 1 95%
scarajectory/core/service/storage/__init__.py 9 0 100%
scarajectory/core/service/storage/iplan_loader.py 16 0 100%
scarajectory/core/service/storage/iplan_storage_service.py 14 0 100%
scarajectory/core/service/storage/iplan_storer.py 17 0 100%
scarajectory/core/service/streaming/__init__.py 9 0 100%
scarajectory/core/service/streaming/config_factory.py 18 0 100%
scarajectory/core/service/streaming/ibinary_program_streamer.py 14 0 100%
scarajectory/core/service/streaming/imotion_streamer.py 14 0 100%
scarajectory/core/service/streaming/istream_control_transmitter.py 17 0 100%
scarajectory/core/service/streaming/istream_dispatcher.py 14 0 100%
scarajectory/core/service/streaming/istream_playback_controller.py 18 0 100%
scarajectory/core/service/streaming/observer/__init__.py 9 0 100%
scarajectory/core/service/streaming/observer/iobservable.py 14 0 100%
scarajectory/core/service/streaming/observer/iobserver.py 15 0 100%
scarajectory/core/service/streaming/observer/istream_observer_dispatcher.py 16 0 100%
scarajectory/core/service/streaming/stream_pacing_config_factory.py 23 0 100%
scarajectory/core/service/telemetry/__init__.py 9 0 100%
scarajectory/core/service/telemetry/diagnostics_snapshot_factory.py 18 0 100%
scarajectory/core/service/telemetry/fault_event_factory.py 17 0 100%
scarajectory/core/service/telemetry/move_event_factory.py 17 0 100%
scarajectory/core/service/tool/__init__.py 9 0 100%
scarajectory/core/service/tool/ipurge_valve_actuator.py 13 0 100%
scarajectory/core/service/tool/itool_controller.py 15 0 100%
scarajectory/core/service/trajectory/__init__.py 9 0 100%
scarajectory/core/service/trajectory/contract/__init__.py 9 0 100%
scarajectory/core/service/trajectory/contract/iplan_command_service.py 16 0 100%
scarajectory/core/service/trajectory/contract/iplan_persistence_service.py 14 0 100%
scarajectory/core/service/trajectory/contract/iplan_validation_service.py 13 0 100%
scarajectory/core/service/trajectory/history/__init__.py 9 0 100%
scarajectory/core/service/trajectory/history/iplan_history.py 17 0 100%
scarajectory/core/service/trajectory/history/iplan_history_saver.py 15 0 100%
scarajectory/core/service/trajectory/history/plan_history.py 38 1 97%
scarajectory/core/service/trajectory/history/plan_history_factory.py 17 1 94%
scarajectory/core/service/trajectory/plan/__init__.py 9 0 100%
scarajectory/core/service/trajectory/plan/history/__init__.py 9 0 100%
scarajectory/core/service/trajectory/plan/history/plan_history_service.py 40 0 100%
scarajectory/core/service/trajectory/plan/history/plan_history_service_factory.py 21 0 100%
scarajectory/core/service/trajectory/plan/itrajectory_history.py 14 0 100%
scarajectory/core/service/trajectory/plan/itrajectory_mutable.py 21 0 100%
scarajectory/core/service/trajectory/plan/itrajectory_read_only.py 18 0 100%
scarajectory/core/service/trajectory/plan/mutation/__init__.py 9 0 100%
scarajectory/core/service/trajectory/plan/mutation/iplan_bulk_mutator.py 16 0 100%
scarajectory/core/service/trajectory/plan/mutation/iplan_mutation_service.py 14 0 100%
scarajectory/core/service/trajectory/plan/mutation/iplan_point_mutator.py 17 0 100%
scarajectory/core/service/trajectory/plan/mutation/plan_mutation_service.py 63 0 100%
scarajectory/core/service/trajectory/plan/mutation/plan_mutation_service_factory.py 21 0 100%
scarajectory/core/service/trajectory/plan/observer/__init__.py 9 0 100%
scarajectory/core/service/trajectory/plan/observer/iplan_observer_dispatcher.py 18 0 100%
scarajectory/core/service/trajectory/plan/observer/itrajectory_observer.py 14 0 100%
scarajectory/core/service/trajectory/plan/observer/plan_observer_dispatcher.py 29 0 100%
scarajectory/core/service/trajectory/plan/observer/plan_observer_dispatcher_factory.py 17 1 94%
scarajectory/core/service/trajectory/plan/selection/__init__.py 9 0 100%
scarajectory/core/service/trajectory/plan/selection/iplan_selection_coordinator.py 15 0 100%
scarajectory/core/service/trajectory/plan/selection/iplan_selection_manager.py 14 0 100%
scarajectory/core/service/trajectory/plan/selection/iplan_selection_navigator.py 16 0 100%
scarajectory/core/service/trajectory/plan/selection/iplan_selection_state.py 17 0 100%
scarajectory/core/service/trajectory/plan/selection/plan_selection_coordinator.py 27 0 100%
scarajectory/core/service/trajectory/plan/selection/plan_selection_coordinator_factory.py 20 0 100%
scarajectory/core/service/trajectory/plan/selection/plan_selection_manager.py 35 1 97%
scarajectory/core/service/trajectory/plan/selection/plan_selection_manager_factory.py 26 1 96%
scarajectory/core/service/trajectory/plan/selection/plan_selection_navigator.py 23 0 100%
scarajectory/core/service/trajectory/plan/selection/plan_selection_navigator_factory.py 18 0 100%
scarajectory/core/service/trajectory/plan/selection/plan_selection_state.py 28 0 100%
scarajectory/core/service/trajectory/plan/store/__init__.py 9 0 100%
scarajectory/core/service/trajectory/plan/store/iwaypoint_bulk_mutator.py 16 0 100%
scarajectory/core/service/trajectory/plan/store/iwaypoint_mutator.py 17 0 100%
scarajectory/core/service/trajectory/plan/store/iwaypoint_query.py 18 0 100%
scarajectory/core/service/trajectory/plan/store/iwaypoint_store.py 15 0 100%
scarajectory/core/service/trajectory/plan/store/waypoint_bulk_mutator.py 21 0 100%
scarajectory/core/service/trajectory/plan/store/waypoint_mutator.py 29 0 100%
scarajectory/core/service/trajectory/plan/store/waypoint_query.py 22 0 100%
scarajectory/core/service/trajectory/plan/store/waypoint_store.py 41 0 100%
scarajectory/core/service/trajectory/plan/store/waypoint_store_factory.py 27 1 96%
scarajectory/core/service/transmission/__init__.py 9 0 100%
scarajectory/core/service/transmission/itransmission_step_calculator.py 15 0 100%
scarajectory/core/service/worker/__init__.py 9 0 100%
scarajectory/core/service/worker/ibyte_sender.py 13 0 100%
scarajectory/core/service/worker/icommand_formatter.py 14 0 100%
scarajectory/core/service/worker/icommand_sender.py 13 0 100%
scarajectory/core/service/worker/iexecution_service.py 16 0 100%
scarajectory/core/service/worker/iexecution_worker.py 18 0 100%
scarajectory/core/service/worker/istream_bytes_receiver.py 14 0 100%
scarajectory/core/service/worker/istream_line_receiver.py 14 0 100%
scarajectory/core/service/worker/istream_loop_runner.py 16 0 100%
scarajectory/engine.py 58 2 97%
scarajectory/infrastructure/__init__.py 9 0 100%
scarajectory/infrastructure/barrier/__init__.py 9 0 100%
scarajectory/infrastructure/barrier/flow_barrier.py 23 0 100%
scarajectory/infrastructure/barrier/flow_barrier_factory.py 17 0 100%
scarajectory/infrastructure/classifier/__init__.py 9 0 100%
scarajectory/infrastructure/classifier/iresponse_classification_rule.py 15 0 100%
scarajectory/infrastructure/classifier/response_classification_registry.py 23 0 100%
scarajectory/infrastructure/classifier/response_classification_registry_factory.py 22 0 100%
scarajectory/infrastructure/classifier/response_classification_rule.py 28 0 100%
scarajectory/infrastructure/classifier/response_parser.py 32 0 100%
scarajectory/infrastructure/classifier/response_parser_factory.py 23 0 100%
scarajectory/infrastructure/classifier/status/__init__.py 9 0 100%
scarajectory/infrastructure/classifier/status/flow_status_classifier.py 24 0 100%
scarajectory/infrastructure/classifier/status/flow_status_classifier_factory.py 22 0 100%
scarajectory/infrastructure/classifier/status/homing_status_classifier.py 17 0 100%
scarajectory/infrastructure/classifier/status/homing_status_classifier_factory.py 17 0 100%
scarajectory/infrastructure/classifier/status/motion_status_classifier.py 28 0 100%
scarajectory/infrastructure/classifier/status/motion_status_classifier_factory.py 22 0 100%
scarajectory/infrastructure/cli/__init__.py 9 0 100%
scarajectory/infrastructure/cli/engine.py 41 0 100%
scarajectory/infrastructure/cli/icli.py 15 0 100%
scarajectory/infrastructure/cli/setup/__init__.py 9 0 100%
scarajectory/infrastructure/cli/setup/bundle.py 22 1 95%
scarajectory/infrastructure/cli/setup/dep_validator.py 36 5 86%
scarajectory/infrastructure/cli/setup/dependencies.py 18 0 100%
scarajectory/infrastructure/cli/setup/factory.py 37 1 97%
scarajectory/infrastructure/cli/setup/keys.py 28 0 100%
scarajectory/infrastructure/cli/setup/opt_validator.py 36 5 86%
scarajectory/infrastructure/cli/setup/options.py 17 0 100%
scarajectory/infrastructure/cli/setup/registry.py 24 1 96%
scarajectory/infrastructure/cli/setup/validator.py 43 5 88%
scarajectory/infrastructure/command/__init__.py 9 0 100%
scarajectory/infrastructure/command/command_bundle.py 16 0 100%
scarajectory/infrastructure/command/icommand_definition.py 14 0 100%
scarajectory/infrastructure/command/icommand_executor.py 14 0 100%
scarajectory/infrastructure/command/studio_command_definition.py 24 0 100%
scarajectory/infrastructure/command/studio_command_executor.py 37 0 100%
scarajectory/infrastructure/connection/__init__.py 9 0 100%
scarajectory/infrastructure/connection/channel_dispatcher.py 46 0 100%
scarajectory/infrastructure/connection/channel_dispatcher_factory.py 20 0 100%
scarajectory/infrastructure/connection/istream_raw_transceiver.py 16 0 100%
scarajectory/infrastructure/connection/stream_connection_manager.py 30 0 100%
scarajectory/infrastructure/connection/stream_connection_manager_factory.py 19 0 100%
scarajectory/infrastructure/connection/stream_raw_transceiver.py 28 0 100%
scarajectory/infrastructure/connection/stream_raw_transceiver_factory.py 19 0 100%
scarajectory/infrastructure/event/__init__.py 9 0 100%
scarajectory/infrastructure/event/binary_frame_dispatcher.py 28 0 100%
scarajectory/infrastructure/event/binary_frame_dispatcher_factory.py 17 0 100%
scarajectory/infrastructure/formatter/__init__.py 9 0 100%
scarajectory/infrastructure/formatter/command/__init__.py 9 0 100%
scarajectory/infrastructure/formatter/command/config_command_formatter.py 22 0 100%
scarajectory/infrastructure/formatter/command/jog_command_formatter.py 15 0 100%
scarajectory/infrastructure/formatter/command/motion_command_formatter.py 38 0 100%
scarajectory/infrastructure/formatter/command/query_command_formatter.py 21 0 100%
scarajectory/infrastructure/formatter/command/system_command_formatter.py 29 0 100%
scarajectory/infrastructure/formatter/command/tool_command_formatter.py 25 0 100%
scarajectory/infrastructure/formatter/command_formatter.py 20 0 100%
scarajectory/infrastructure/formatter/command_formatter_factory.py 17 1 94%
scarajectory/infrastructure/formatter/command_templates.py 46 2 96%
scarajectory/infrastructure/gui/__init__.py 9 0 100%
scarajectory/infrastructure/gui/canvas/__init__.py 9 0 100%
scarajectory/infrastructure/gui/canvas/bundle.py 24 0 100%
scarajectory/infrastructure/gui/canvas/canvas_event_binder.py 59 0 100%
scarajectory/infrastructure/gui/canvas/canvas_event_binder_factory.py 21 0 100%
scarajectory/infrastructure/gui/canvas/handler/__init__.py 9 0 100%
scarajectory/infrastructure/gui/canvas/handler/canvas_drag_handler.py 40 0 100%
scarajectory/infrastructure/gui/canvas/handler/canvas_event_context.py 18 0 100%
scarajectory/infrastructure/gui/canvas/handler/canvas_mouse_handler.py 73 0 100%
scarajectory/infrastructure/gui/canvas/handler/canvas_mouse_handler_factory.py 36 0 100%
scarajectory/infrastructure/gui/canvas/handler/canvas_shape_handler.py 55 0 100%
scarajectory/infrastructure/gui/canvas/handler/canvas_tool_handler.py 45 0 100%
scarajectory/infrastructure/gui/canvas/handler/icanvas_mouse_handler.py 18 0 100%
scarajectory/infrastructure/gui/canvas/handler/mouse_handler_bundle.py 24 0 100%
scarajectory/infrastructure/gui/canvas/handler/mouse_handler_init_bundle.py 22 0 100%
scarajectory/infrastructure/gui/canvas/handler/pan/__init__.py 9 0 100%
scarajectory/infrastructure/gui/canvas/handler/pan/canvas_viewport_pan_handler.py 41 0 100%
scarajectory/infrastructure/gui/canvas/handler/pan/canvas_viewport_pan_handler_factory.py 19 1 95%
scarajectory/infrastructure/gui/canvas/handler/pan/icanvas_viewport_pan_handler.py 17 0 100%
scarajectory/infrastructure/gui/canvas/handler/selection/__init__.py 9 0 100%
scarajectory/infrastructure/gui/canvas/handler/selection/canvas_selection_mouse_handler.py 49 0 100%
scarajectory/infrastructure/gui/canvas/handler/selection/canvas_selection_mouse_handler_factory.py 22 1 95%
scarajectory/infrastructure/gui/canvas/handler/selection/icanvas_selection_mouse_handler.py 16 0 100%
scarajectory/infrastructure/gui/canvas/icanvas.py 16 0 100%
scarajectory/infrastructure/gui/canvas/navigation/__init__.py 9 0 100%
scarajectory/infrastructure/gui/canvas/navigation/canvas_view_navigator.py 34 0 100%
scarajectory/infrastructure/gui/canvas/navigation/canvas_view_navigator_factory.py 20 0 100%
scarajectory/infrastructure/gui/canvas/navigation/icanvas_view_navigator.py 16 0 100%
scarajectory/infrastructure/gui/canvas/navigation/icanvas_view_target.py 14 0 100%
scarajectory/infrastructure/gui/canvas/observer/__init__.py 9 0 100%
scarajectory/infrastructure/gui/canvas/observer/canvas_plan_observer_bridge.py 20 0 100%
scarajectory/infrastructure/gui/canvas/observer/canvas_plan_observer_bridge_factory.py 18 0 100%
scarajectory/infrastructure/gui/canvas/observer/icanvas_plan_observer_bridge.py 14 0 100%
scarajectory/infrastructure/gui/canvas/render/__init__.py 9 0 100%
scarajectory/infrastructure/gui/canvas/render/forbidden_zone_renderer.py 56 0 100%
scarajectory/infrastructure/gui/canvas/render/ilayer_renderer.py 17 0 100%
scarajectory/infrastructure/gui/canvas/render/polar_grid_renderer.py 36 0 100%
scarajectory/infrastructure/gui/canvas/render/preview_renderer.py 31 1 97%
scarajectory/infrastructure/gui/canvas/render/reach_boundary_renderer.py 31 0 100%
scarajectory/infrastructure/gui/canvas/render/renderer.py 34 0 100%
scarajectory/infrastructure/gui/canvas/render/trajectory_renderer.py 32 0 100%
scarajectory/infrastructure/gui/canvas/render/waypoint_node_renderer.py 25 0 100%
scarajectory/infrastructure/gui/canvas/render/waypoint_node_renderer_factory.py 17 1 94%
scarajectory/infrastructure/gui/canvas/status/__init__.py 9 0 100%
scarajectory/infrastructure/gui/canvas/status/canvas_status_presenter.py 21 0 100%
scarajectory/infrastructure/gui/canvas/status/canvas_status_presenter_factory.py 17 0 100%
scarajectory/infrastructure/gui/canvas/status/icanvas_status_presenter.py 16 0 100%
scarajectory/infrastructure/gui/canvas/trajectory_canvas.py 68 4 94%
scarajectory/infrastructure/gui/canvas/trajectory_canvas_factory.py 44 0 100%
scarajectory/infrastructure/gui/connection/__init__.py 9 0 100%
scarajectory/infrastructure/gui/connection/iport_connection_delegate.py 13 0 100%
scarajectory/infrastructure/gui/connection/null_port_connection_delegate.py 11 0 100%
scarajectory/infrastructure/gui/connection/port_connection_panel.py 76 2 97%
scarajectory/infrastructure/gui/console/__init__.py 9 0 100%
scarajectory/infrastructure/gui/console/serial_console.py 39 0 100%
scarajectory/infrastructure/gui/console/serial_console_builder.py 30 1 97%
scarajectory/infrastructure/gui/console/serial_console_builder_factory.py 17 1 94%
scarajectory/infrastructure/gui/controls/__init__.py 9 0 100%
scarajectory/infrastructure/gui/controls/bundle.py 29 0 100%
scarajectory/infrastructure/gui/controls/controls_panel.py 52 0 100%
scarajectory/infrastructure/gui/controls/controls_panel_factory.py 29 0 100%
scarajectory/infrastructure/gui/controls/icontrols_panel.py 16 0 100%
scarajectory/infrastructure/gui/controls/itabs_assembler.py 17 0 100%
scarajectory/infrastructure/gui/controls/manipulator_controllers_bundle.py 20 0 100%
scarajectory/infrastructure/gui/controls/manipulator_controllers_factory.py 34 0 100%
scarajectory/infrastructure/gui/controls/tabs_assembler.py 43 0 100%
scarajectory/infrastructure/gui/controls/tabs_assembler_factory.py 17 0 100%
scarajectory/infrastructure/gui/controls/tabs_bundle.py 22 0 100%
scarajectory/infrastructure/gui/dsl/__init__.py 9 0 100%
scarajectory/infrastructure/gui/dsl/bundle.py 20 0 100%
scarajectory/infrastructure/gui/dsl/code_editor.py 36 3 92%
scarajectory/infrastructure/gui/dsl/code_editor_factory.py 24 1 96%
scarajectory/infrastructure/gui/dsl/console_view.py 27 3 89%
scarajectory/infrastructure/gui/dsl/document/__init__.py 9 0 100%
scarajectory/infrastructure/gui/dsl/document/document_manager.py 42 0 100%
scarajectory/infrastructure/gui/dsl/document/document_manager_factory.py 22 1 95%
scarajectory/infrastructure/gui/dsl/document/example_catalog.py 35 4 89%
scarajectory/infrastructure/gui/dsl/document/example_catalog_factory.py 23 1 96%
scarajectory/infrastructure/gui/dsl/dsl_editor_tab.py 57 0 100%
scarajectory/infrastructure/gui/dsl/dsl_editor_tab_factory.py 52 0 100%
scarajectory/infrastructure/gui/dsl/handler/__init__.py 9 0 100%
scarajectory/infrastructure/gui/dsl/handler/execution_handler.py 61 0 100%
scarajectory/infrastructure/gui/dsl/handler/execution_handler_bundle.py 24 0 100%
scarajectory/infrastructure/gui/dsl/handler/execution_handler_factory.py 18 1 94%
scarajectory/infrastructure/gui/dsl/handler/file_handler.py 47 0 100%
scarajectory/infrastructure/gui/dsl/handler/file_handler_bundle.py 22 0 100%
scarajectory/infrastructure/gui/dsl/handler/file_handler_factory.py 18 1 94%
scarajectory/infrastructure/gui/dsl/handler/iexecution_delegate.py 16 0 100%
scarajectory/infrastructure/gui/dsl/handler/ifile_delegate.py 15 0 100%
scarajectory/infrastructure/gui/dsl/syntax/__init__.py 9 0 100%
scarajectory/infrastructure/gui/dsl/syntax/highlighter.py 29 0 100%
scarajectory/infrastructure/gui/dsl/syntax/highlighter_factory.py 24 0 100%
scarajectory/infrastructure/gui/dsl/syntax/ihighlighter.py 15 0 100%
scarajectory/infrastructure/gui/dsl/syntax/itag_applier.py 17 0 100%
scarajectory/infrastructure/gui/dsl/syntax/itokenizer.py 15 0 100%
scarajectory/infrastructure/gui/dsl/syntax/tag_applier.py 24 0 100%
scarajectory/infrastructure/gui/dsl/syntax/tag_applier_factory.py 17 1 94%
scarajectory/infrastructure/gui/dsl/syntax/token.py 15 0 100%
scarajectory/infrastructure/gui/dsl/syntax/tokenizer.py 42 0 100%
scarajectory/infrastructure/gui/dsl/syntax/tokenizer_factory.py 17 0 100%
scarajectory/infrastructure/gui/dsl/toolbar.py 50 2 96%
scarajectory/infrastructure/gui/editor/__init__.py 9 0 100%
scarajectory/infrastructure/gui/editor/table/__init__.py 9 0 100%
scarajectory/infrastructure/gui/editor/table/bundle.py 20 0 100%
scarajectory/infrastructure/gui/editor/table/itable.py 14 0 100%
scarajectory/infrastructure/gui/editor/table/selection_handler.py 28 3 89%
scarajectory/infrastructure/gui/editor/table/selection_handler_factory.py 17 1 94%
scarajectory/infrastructure/gui/editor/table/trajectory_table.py 87 2 98%
scarajectory/infrastructure/gui/editor/waypoint_coordinate_inputs.py 17 0 100%
scarajectory/infrastructure/gui/editor/waypoint_edit_applier.py 30 1 97%
scarajectory/infrastructure/gui/editor/waypoint_edit_applier_factory.py 17 0 100%
scarajectory/infrastructure/gui/editor/waypoint_editor.py 68 0 100%
scarajectory/infrastructure/gui/emulator/__init__.py 9 0 100%
scarajectory/infrastructure/gui/emulator/emulator_launcher.py 40 0 100%
scarajectory/infrastructure/gui/emulator/emulator_launcher_factory.py 17 0 100%
scarajectory/infrastructure/gui/emulator/iemulator_launcher.py 13 0 100%
scarajectory/infrastructure/gui/igui.py 17 0 100%
scarajectory/infrastructure/gui/layout/__init__.py 9 0 100%
scarajectory/infrastructure/gui/layout/canvas_pane_builder.py 30 0 100%
scarajectory/infrastructure/gui/layout/canvas_pane_builder_factory.py 18 0 100%
scarajectory/infrastructure/gui/layout/editor_pane_builder.py 38 0 100%
scarajectory/infrastructure/gui/layout/editor_pane_builder_factory.py 18 0 100%
scarajectory/infrastructure/gui/layout/icanvas_pane_builder.py 18 0 100%
scarajectory/infrastructure/gui/layout/ieditor_pane_builder.py 18 0 100%
scarajectory/infrastructure/gui/layout/itoolbar_layout_builder.py 19 0 100%
scarajectory/infrastructure/gui/layout/main_content_builder.py 39 0 100%
scarajectory/infrastructure/gui/layout/main_content_builder_factory.py 26 0 100%
scarajectory/infrastructure/gui/layout/toolbar_layout_builder.py 33 0 100%
scarajectory/infrastructure/gui/layout/toolbar_layout_builder_factory.py 18 0 100%
scarajectory/infrastructure/gui/manipulator/__init__.py 9 0 100%
scarajectory/infrastructure/gui/manipulator/imanipulator_action_delegate.py 16 0 100%
scarajectory/infrastructure/gui/manipulator/jog/__init__.py 9 0 100%
scarajectory/infrastructure/gui/manipulator/jog/axis_grid_panel.py 46 0 100%
scarajectory/infrastructure/gui/manipulator/jog/axis_grid_panel_factory.py 20 0 100%
scarajectory/infrastructure/gui/manipulator/jog/controllers_bundle.py 22 0 100%
scarajectory/infrastructure/gui/manipulator/jog/jog_tab.py 51 0 100%
scarajectory/infrastructure/gui/manipulator/jog/jog_tab_factory.py 35 0 100%
scarajectory/infrastructure/gui/manipulator/jog/panel_bundle.py 20 0 100%
scarajectory/infrastructure/gui/manipulator/jog/power_panel.py 27 0 100%
scarajectory/infrastructure/gui/manipulator/jog/power_panel_factory.py 19 0 100%
scarajectory/infrastructure/gui/manipulator/jog/raw_command_panel.py 36 0 100%
scarajectory/infrastructure/gui/manipulator/jog/raw_command_panel_factory.py 19 0 100%
scarajectory/infrastructure/gui/manipulator/jog/tool_panel.py 26 0 100%
scarajectory/infrastructure/gui/manipulator/jog/tool_panel_factory.py 19 0 100%
scarajectory/infrastructure/gui/manipulator/manipulator_override_panel.py 60 0 100%
scarajectory/infrastructure/gui/manipulator/null_manipulator_action_delegate.py 14 0 100%
scarajectory/infrastructure/gui/menu/__init__.py 9 0 100%
scarajectory/infrastructure/gui/menu/app_menu_bar.py 77 0 100%
scarajectory/infrastructure/gui/menu/app_menu_bar_factory.py 26 1 96%
scarajectory/infrastructure/gui/menu/builders_bundle.py 16 0 100%
scarajectory/infrastructure/gui/menu/bundle.py 26 0 100%
scarajectory/infrastructure/gui/menu/iapp_menu_bar.py 16 0 100%
scarajectory/infrastructure/gui/menu/menu_hotkey_binder.py 23 0 100%
scarajectory/infrastructure/gui/menu/menu_hotkey_binder_factory.py 17 1 94%
scarajectory/infrastructure/gui/menu/menu_layout_builder.py 40 0 100%
scarajectory/infrastructure/gui/menu/menu_layout_builder_factory.py 17 1 94%
scarajectory/infrastructure/gui/model/__init__.py 9 0 100%
scarajectory/infrastructure/gui/model/canvas_interaction_state.py 26 0 100%
scarajectory/infrastructure/gui/model/canvas_settings.py 15 0 100%
scarajectory/infrastructure/gui/model/canvas_tool_mode.py 17 0 100%
scarajectory/infrastructure/gui/model/viewport_transform.py 47 0 100%
scarajectory/infrastructure/gui/preview/__init__.py 9 0 100%
scarajectory/infrastructure/gui/preview/preview_tab.py 33 0 100%
scarajectory/infrastructure/gui/preview/preview_tab_factory.py 21 0 100%
scarajectory/infrastructure/gui/scarajectory_gui.py 65 2 97%
scarajectory/infrastructure/gui/scarajectory_gui_bundle.py 27 0 100%
scarajectory/infrastructure/gui/scarajectory_gui_factory.py 57 0 100%
scarajectory/infrastructure/gui/scarajectory_gui_init_bundle.py 28 0 100%
scarajectory/infrastructure/gui/streaming/__init__.py 9 0 100%
scarajectory/infrastructure/gui/streaming/bundle.py 24 0 100%
scarajectory/infrastructure/gui/streaming/handler/__init__.py 9 0 100%
scarajectory/infrastructure/gui/streaming/handler/playback_handler_bundle.py 24 0 100%
scarajectory/infrastructure/gui/streaming/handler/stream_playback_action_handler.py 61 0 100%
scarajectory/infrastructure/gui/streaming/handler/stream_playback_action_handler_factory.py 18 0 100%
scarajectory/infrastructure/gui/streaming/handler/stream_tool_action_handler.py 52 0 100%
scarajectory/infrastructure/gui/streaming/handler/stream_tool_action_handler_factory.py 20 0 100%
scarajectory/infrastructure/gui/streaming/observer/__init__.py 9 0 100%
scarajectory/infrastructure/gui/streaming/observer/gui_stream_observer_bridge.py 23 0 100%
scarajectory/infrastructure/gui/streaming/observer/gui_stream_observer_bridge_factory.py 19 0 100%
scarajectory/infrastructure/gui/streaming/observer/igui_stream_observer_bridge.py 15 0 100%
scarajectory/infrastructure/gui/streaming/panel/__init__.py 9 0 100%
scarajectory/infrastructure/gui/streaming/panel/istream_control_delegate.py 15 0 100%
scarajectory/infrastructure/gui/streaming/panel/stream_control_panel.py 21 0 100%
scarajectory/infrastructure/gui/streaming/panel/stream_progress_adapter.py 35 0 100%
scarajectory/infrastructure/gui/streaming/panel/stream_status_bar.py 30 0 100%
scarajectory/infrastructure/gui/streaming/streamer_action_bundle.py 16 0 100%
scarajectory/infrastructure/gui/streaming/streamer_controllers_bundle.py 18 0 100%
scarajectory/infrastructure/gui/streaming/streamer_tab.py 70 0 100%
scarajectory/infrastructure/gui/streaming/streamer_tab_factory.py 31 0 100%
scarajectory/infrastructure/gui/theme/__init__.py 9 0 100%
scarajectory/infrastructure/gui/theme/theme_button_styler.py 23 0 100%
scarajectory/infrastructure/gui/theme/theme_button_styler_factory.py 17 1 94%
scarajectory/infrastructure/gui/theme/theme_manager.py 43 0 100%
scarajectory/infrastructure/gui/theme/theme_notebook_styler.py 16 0 100%
scarajectory/infrastructure/gui/theme/theme_notebook_styler_factory.py 17 1 94%
scarajectory/infrastructure/gui/toolbar/__init__.py 9 0 100%
scarajectory/infrastructure/gui/toolbar/bundle.py 24 0 100%
scarajectory/infrastructure/gui/toolbar/itoolbar.py 15 0 100%
scarajectory/infrastructure/gui/toolbar/navigation_controls.py 32 0 100%
scarajectory/infrastructure/gui/toolbar/navigation_controls_factory.py 20 0 100%
scarajectory/infrastructure/gui/toolbar/parameter_inputs.py 56 1 98%
scarajectory/infrastructure/gui/toolbar/parameter_inputs_bundle.py 20 0 100%
scarajectory/infrastructure/gui/toolbar/parameter_inputs_factory.py 19 0 100%
scarajectory/infrastructure/gui/toolbar/tool_selector.py 33 0 100%
scarajectory/infrastructure/gui/toolbar/tool_selector_factory.py 19 0 100%
scarajectory/infrastructure/gui/toolbar/toolbar.py 33 0 100%
scarajectory/infrastructure/gui/toolbar/toolbar_factory.py 29 0 100%
scarajectory/infrastructure/gui/validation/__init__.py 9 0 100%
scarajectory/infrastructure/gui/validation/validation_tab.py 35 0 100%
scarajectory/infrastructure/gui/validation/validation_tab_factory.py 20 0 100%
scarajectory/infrastructure/manipulator/__init__.py 9 0 100%
scarajectory/infrastructure/manipulator/jog_controller.py 41 1 98%
scarajectory/infrastructure/manipulator/jog_controller_factory.py 23 1 96%
scarajectory/infrastructure/manipulator/motion_controller.py 46 0 100%
scarajectory/infrastructure/manipulator/motion_controller_factory.py 23 1 96%
scarajectory/infrastructure/manipulator/query_controller.py 36 1 97%
scarajectory/infrastructure/manipulator/query_controller_factory.py 23 1 96%
scarajectory/infrastructure/pacing/__init__.py 9 0 100%
scarajectory/infrastructure/pacing/bundle.py 16 0 100%
scarajectory/infrastructure/pacing/flow_barrier_coordinator.py 23 0 100%
scarajectory/infrastructure/pacing/flow_barrier_coordinator_factory.py 18 0 100%
scarajectory/infrastructure/pacing/flow_pacing_bundle_factory.py 26 0 100%
scarajectory/infrastructure/pacing/flow_pacing_controller.py 77 0 100%
scarajectory/infrastructure/pacing/flow_pacing_controller_factory.py 30 0 100%
scarajectory/infrastructure/packet/__init__.py 9 0 100%
scarajectory/infrastructure/packet/binary_packet_strategy.py 45 0 100%
scarajectory/infrastructure/packet/binary_packet_strategy_factory.py 28 0 100%
scarajectory/infrastructure/preferences/__init__.py 9 0 100%
scarajectory/infrastructure/preferences/connection_repository.py 57 0 100%
scarajectory/infrastructure/preferences/connection_repository_factory.py 22 0 100%
scarajectory/infrastructure/settings/__init__.py 9 0 100%
scarajectory/infrastructure/settings/bounds/__init__.py 9 0 100%
scarajectory/infrastructure/settings/bounds/scara_bounds_loader.py 35 1 97%
scarajectory/infrastructure/settings/bounds/scara_bounds_loader_factory.py 29 0 100%
scarajectory/infrastructure/settings/bounds/scara_bounds_parser.py 19 0 100%
scarajectory/infrastructure/settings/bounds/scara_bounds_parser_factory.py 18 0 100%
scarajectory/infrastructure/settings/isettings_reader.py 14 0 100%
scarajectory/infrastructure/settings/settings_reader.py 46 1 98%
scarajectory/infrastructure/settings/settings_reader_factory.py 25 0 100%
scarajectory/infrastructure/settings/stream/__init__.py 9 0 100%
scarajectory/infrastructure/settings/stream/stream_config_loader.py 27 0 100%
scarajectory/infrastructure/settings/stream/stream_config_loader_factory.py 22 0 100%
scarajectory/infrastructure/settings/transmission/__init__.py 9 0 100%
scarajectory/infrastructure/settings/transmission/scara_transmission_loader.py 21 0 100%
scarajectory/infrastructure/settings/transmission/scara_transmission_loader_factory.py 22 0 100%
scarajectory/infrastructure/state/__init__.py 9 0 100%
scarajectory/infrastructure/state/stream_state_machine.py 28 0 100%
scarajectory/infrastructure/state/stream_state_machine_factory.py 18 0 100%
scarajectory/infrastructure/storage/__init__.py 9 0 100%
scarajectory/infrastructure/storage/plan_loader.py 37 0 100%
scarajectory/infrastructure/storage/plan_storage_service.py 33 0 100%
scarajectory/infrastructure/storage/plan_storage_service_factory.py 26 0 100%
scarajectory/infrastructure/storage/plan_storer.py 40 0 100%
scarajectory/infrastructure/storage/trajectory_serializer.py 39 0 100%
scarajectory/infrastructure/streaming/__init__.py 9 0 100%
scarajectory/infrastructure/streaming/assembly/__init__.py 9 0 100%
scarajectory/infrastructure/streaming/assembly/stream_pacing_assembler.py 21 0 100%
scarajectory/infrastructure/streaming/assembly/stream_pipeline_assembler.py 52 1 98%
scarajectory/infrastructure/streaming/assembly/stream_transport_assembler.py 24 0 100%
scarajectory/infrastructure/streaming/assembly/stream_worker_assembler.py 57 0 100%
scarajectory/infrastructure/streaming/assembly/worker_bundle.py 20 0 100%
scarajectory/infrastructure/streaming/binary_program_streamer.py 50 0 100%
scarajectory/infrastructure/streaming/binary_program_streamer_factory.py 21 0 100%
scarajectory/infrastructure/streaming/bundle.py 22 0 100%
scarajectory/infrastructure/streaming/observer/__init__.py 9 0 100%
scarajectory/infrastructure/streaming/observer/istream_observer_registry.py 17 0 100%
scarajectory/infrastructure/streaming/observer/istream_telemetry_notifier.py 16 0 100%
scarajectory/infrastructure/streaming/observer/stream_observer_dispatcher.py 35 0 100%
scarajectory/infrastructure/streaming/observer/stream_observer_dispatcher_factory.py 29 0 100%
scarajectory/infrastructure/streaming/observer/stream_observer_registry.py 24 0 100%
scarajectory/infrastructure/streaming/observer/stream_observer_registry_factory.py 23 0 100%
scarajectory/infrastructure/streaming/observer/stream_telemetry_notifier.py 33 0 100%
scarajectory/infrastructure/streaming/observer/stream_telemetry_notifier_factory.py 18 0 100%
scarajectory/infrastructure/streaming/stream_control_transmitter.py 42 0 100%
scarajectory/infrastructure/streaming/stream_control_transmitter_factory.py 19 0 100%
scarajectory/infrastructure/streaming/stream_playback_controller.py 78 0 100%
scarajectory/infrastructure/streaming/stream_playback_controller_factory.py 25 0 100%
scarajectory/infrastructure/tool/__init__.py 9 0 100%
scarajectory/infrastructure/tool/tool_controller.py 50 0 100%
scarajectory/infrastructure/tool/tool_controller_factory.py 24 0 100%
scarajectory/infrastructure/tool/valve_pulse_worker.py 23 0 100%
scarajectory/infrastructure/tool/valve_pulse_worker_factory.py 18 0 100%
scarajectory/infrastructure/transmission/__init__.py 9 0 100%
scarajectory/infrastructure/transmission/transmission_step_calculator.py 24 0 100%
scarajectory/infrastructure/transmission/transmission_step_calculator_factory.py 18 1 94%
scarajectory/infrastructure/transport/__init__.py 9 0 100%
scarajectory/infrastructure/transport/bundle.py 16 0 100%
scarajectory/infrastructure/transport/driver/__init__.py 9 0 100%
scarajectory/infrastructure/transport/driver/ichannel.py 19 0 100%
scarajectory/infrastructure/transport/driver/serial_channel.py 37 0 100%
scarajectory/infrastructure/transport/driver/serial_channel_factory.py 17 0 100%
scarajectory/infrastructure/transport/driver/serial_port_scanner.py 36 0 100%
scarajectory/infrastructure/transport/driver/tcp_channel.py 66 0 100%
scarajectory/infrastructure/transport/driver/tcp_channel_factory.py 17 0 100%
scarajectory/infrastructure/transport/istream_transport_connection.py 18 0 100%
scarajectory/infrastructure/transport/istream_transport_transceiver.py 16 0 100%
scarajectory/infrastructure/transport/listener/__init__.py 9 0 100%
scarajectory/infrastructure/transport/listener/itransport_listener.py 15 0 100%
scarajectory/infrastructure/transport/listener/itransport_listener_holder.py 17 0 100%
scarajectory/infrastructure/transport/listener/null_transport_listener.py 13 0 100%
scarajectory/infrastructure/transport/listener/stream_ascii_transport_listener.py 23 0 100%
scarajectory/infrastructure/transport/listener/stream_ascii_transport_listener_factory.py 19 0 100%
scarajectory/infrastructure/transport/listener/stream_binary_transport_listener.py 23 0 100%
scarajectory/infrastructure/transport/listener/stream_binary_transport_listener_factory.py 19 0 100%
scarajectory/infrastructure/transport/listener/transport_listener_holder.py 22 0 100%
scarajectory/infrastructure/transport/stream_transport_connection.py 61 1 98%
scarajectory/infrastructure/transport/stream_transport_connection_factory.py 20 0 100%
scarajectory/infrastructure/transport/stream_transport_transceiver.py 54 0 100%
scarajectory/infrastructure/transport/stream_transport_transceiver_factory.py 20 0 100%
scarajectory/infrastructure/transport/transport_factory.py 35 1 97%
scarajectory/infrastructure/transport/worker/__init__.py 9 0 100%
scarajectory/infrastructure/transport/worker/itransport_reader_worker.py 14 0 100%
scarajectory/infrastructure/transport/worker/transport_reader_worker.py 54 0 100%
scarajectory/infrastructure/transport/worker/transport_reader_worker_factory.py 20 0 100%
scarajectory/infrastructure/worker/__init__.py 9 0 100%
scarajectory/infrastructure/worker/binary/__init__.py 9 0 100%
scarajectory/infrastructure/worker/binary/binary_stream_execution_worker.py 60 0 100%
scarajectory/infrastructure/worker/binary/binary_stream_execution_worker_factory.py 31 0 100%
scarajectory/infrastructure/worker/binary/binary_stream_frame_handler.py 55 0 100%
scarajectory/infrastructure/worker/binary/binary_stream_frame_handler_factory.py 20 0 100%
scarajectory/infrastructure/worker/binary/binary_stream_loop_runner.py 98 2 98%
scarajectory/infrastructure/worker/binary/binary_stream_loop_runner_factory.py 32 0 100%
scarajectory/infrastructure/worker/binary/ibinary_stream_frame_handler.py 16 0 100%
scarajectory/infrastructure/worker/binary/ibinary_stream_loop_runner.py 18 0 100%
scarajectory/infrastructure/worker/istream_queue_drainer.py 16 0 100%
scarajectory/infrastructure/worker/istream_step_dispatcher.py 15 0 100%
scarajectory/infrastructure/worker/stream_execution_worker.py 52 0 100%
scarajectory/infrastructure/worker/stream_execution_worker_factory.py 30 3 90%
scarajectory/infrastructure/worker/stream_loop_runner.py 57 3 95%
scarajectory/infrastructure/worker/stream_loop_runner_factory.py 38 1 97%
scarajectory/infrastructure/worker/stream_queue_drainer.py 40 1 98%
scarajectory/infrastructure/worker/stream_queue_drainer_factory.py 20 1 95%
scarajectory/infrastructure/worker/stream_step_dispatcher.py 49 0 100%
scarajectory/infrastructure/worker/stream_step_dispatcher_factory.py 22 1 95%
scarajectory/setup/__init__.py 9 0 100%
scarajectory/setup/assembly/__init__.py 9 0 100%
scarajectory/setup/assembly/app_core_assembler.py 33 0 100%
scarajectory/setup/assembly/app_core_bundle.py 20 0 100%
scarajectory/setup/assembly/app_presentation_assembler.py 40 0 100%
scarajectory/setup/assembly/app_runtime_assembler.py 33 0 100%
scarajectory/setup/assembly/app_runtime_bundle.py 24 0 100%
scarajectory/setup/bundle.py 25 1 96%
scarajectory/setup/dep_validator.py 36 5 86%
scarajectory/setup/dependencies.py 21 0 100%
scarajectory/setup/factory.py 72 4 94%
scarajectory/setup/keys.py 37 0 100%
scarajectory/setup/opt_validator.py 36 5 86%
scarajectory/setup/options.py 20 0 100%
scarajectory/setup/pipeline/__init__.py 9 0 100%
scarajectory/setup/pipeline/dsl_pipeline_builder.py 29 0 100%
scarajectory/setup/pipeline/plan_pipeline_builder.py 35 0 100%
scarajectory/setup/pipeline/plan_pipeline_bundle.py 22 0 100%
scarajectory/setup/pipeline/stream_pipeline_builder.py 58 0 100%
scarajectory/setup/pipeline/stream_pipeline_bundle.py 22 0 100%
scarajectory/setup/registry.py 34 1 97%
scarajectory/setup/validator.py 53 5 91%
Total 13316 120 99%

</details>

πŸ›  Usage

Install package

pip3 install scarajectory

Prepare main entry point by downloading main.py or create your own.

wget -O main.py https://raw.githubusercontent.com/vroncevic/scarajectory/main/main.py
CLI Command Options

Launch the graphical studio with default configuration:

python3 main.py studio

Launch with initial trajectory plan file, deadzone restriction, and verbose output:

python3 main.py studio --file ./trajectories/rectangle_demo.json --dead-zone --verbose
Option Type Choices Description
--file str File path Path to initial trajectory JSON plan file to load on startup.
--dead-zone bool Flag Enable kinematic dead zone enforcement ($R_{min}$).
--verbose bool Flag Enable verbose ATS operational logging.
Interactive Motion Planning Workflow

SCARA Trajectory Studio in Progress

  1. Design Trajectory & Geometry:
    • Use Point, Line, Rectangle, Circle, or Freehand tools directly on the interactive vector canvas.
    • Fine-tune Cartesian parameters ($X, Y, Z, \phi, \text{speed}$) using the Waypoint Data Table or interactive vertex drag.
  2. Kinematic Validation:
    • Open the Plan Validation tab and run validation against reachability limits ($L_1 = 150\text{ mm}, L_2 = 120\text{ mm}$).
    • Verify total path length and estimated execution time.
  3. ASCII Program Preview:
    • Inspect the formatted ASCII micro-command stream (<pt#...#end>) under the Program Preview tab.
  4. Hardware Streaming & Execution:
    • Connect to /dev/ttyACM0 (or TCP host) under the Hardware Streamer tab.
    • Trigger streaming to execute real-time motion on the physical SCARA robot.
  5. Manual Jogging & Diagnostics:
    • Use the Manual Jog tab for directional jog movements, vacuum pump activation, release valve triggers, and homing.
πŸ€– Digital Twin Integration with SCARAEmu

scarajectory seamlessly integrates with scaraemu as a software-in-the-loop (SITL) Digital Twin. This allows you to visually simulate, animate, and validate trajectories and .scara DSL programs in 2D/3D before deploying to physical hardware.

Mode 1: One-Click Simulation from DSL Editor
  1. In scarajectory, open the SCARA DSL Editor tab.
  2. Write or load any .scara program (or select from bundled examples in examples/).
  3. Click the πŸš€ Preview in SCARAEmu button located at the bottom toolbar.
  4. scarajectory automatically launches scaraemu in a background subprocess, passing the active trajectory file via --file.
  5. The 2D Planar and 3D Z-Tower canvases immediately render the robot arm executing the trajectory.
Mode 2: Real-Time Closed-Loop TCP Streaming
  1. Launch scaraemu:
    python3 main.py emulator
    
  2. Activate the Virtual Robot Server:
    • Click the 🌐 Virtual Server: OFF toggle button on the top status bar.
    • The button turns green and displays 🌐 Virtual Server: 8888, listening on 127.0.0.1:8888.
  3. Launch scarajectory:
    python3 main.py studio
    
  4. Compile DSL code to trajectory:
    • In the SCARA DSL Editor tab, load or write your .scara script.
    • Click ⚑ Compile to Plan. The AST compiler compiles Cartesian paths, macros, and action commands into the active trajectory plan.
  5. Navigate to the Hardware Streamer tab.
  6. In the Port dropdown, select 127.0.0.1:8888 (Digital Twin).
  7. Click Connect. The status bar updates to Streamer: Connected to 127.0.0.1:8888.
  8. Click Stream Trajectory (or use the Manual Jog controls):
    • Trajectory waypoints (<pt#X#Y#Z#PHI#SPEED#end>) stream live over the loopback TCP socket.
    • scaraemu smoothly animates the dual-link arm and carriage along the path.
    • Closed-loop protocol acknowledgments (<RESP:ACK#QUEUE=1>, <RESP:MOVE_DONE#...>) flow back to scarajectory, dynamically driving the streaming progress bar.
Mode 3: Direct File Loading in SCARAEmu
  • Open scaraemu and navigate to the Trajectories tab.
  • In the SCARA DSL Script dropdown, select any of the 12 bundled programs (e.g. pick_and_place.scara, engrave_spiral.scara, pallet_matrix.scara).
  • Or click πŸ“‚ Load to load any custom .scara script or exported plan.json file.

πŸ“š Docs

Documentation Status

More documentation and info at

πŸ‘₯ Contributing

Contributing to scarajectory

License: GPL v3 License

Copyright (C) 2026 by vroncevic.github.io/scarajectory

scarajectory is free software; you can redistribute it and/or modify it under the same terms as Python itself, either Python version 3.x or, at your option, any later version of Python 3 you may have available.

Special thanks to Google and the Google developer ecosystem for their tremendous support and innovative tools from the Google bundle that empowered the development and realization of this project. Google, you make this world a better place! 🌍✨

Lets help and support PSF.

Python Software Foundation

Donate