{"id":26921651,"url":"https://github.com/aqc-github/jiggyjoystick","last_synced_at":"2025-08-01T21:08:45.603Z","repository":{"id":285626647,"uuid":"957649207","full_name":"aqc-github/JiggyJoystick","owner":"aqc-github","description":"ROS core nodes and controllers for the Be.Neuro Dynamic Mouse Joystick project. (Powered by RPi5 running Ubuntu 24.04 Server edition)","archived":false,"fork":false,"pushed_at":"2025-07-25T18:37:59.000Z","size":5853,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-07-26T00:03:54.467Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/aqc-github.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-03-30T21:34:32.000Z","updated_at":"2025-07-25T18:38:04.000Z","dependencies_parsed_at":"2025-06-07T02:34:49.144Z","dependency_job_id":"2487fd2b-e640-4a78-96bd-6e32acb1b584","html_url":"https://github.com/aqc-github/JiggyJoystick","commit_stats":null,"previous_names":["aqc-github/jiggyjoystick"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/aqc-github/JiggyJoystick","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aqc-github%2FJiggyJoystick","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aqc-github%2FJiggyJoystick/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aqc-github%2FJiggyJoystick/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aqc-github%2FJiggyJoystick/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/aqc-github","download_url":"https://codeload.github.com/aqc-github/JiggyJoystick/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aqc-github%2FJiggyJoystick/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":268297333,"owners_count":24228123,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-01T02:00:08.611Z","response_time":67,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-04-01T23:35:56.130Z","updated_at":"2025-08-01T21:08:45.593Z","avatar_url":"https://github.com/aqc-github.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# JiggyJoystick: Robotic Arm Experiment Controller\n\n## Overview\n\nJiggyJoystick is a user-friendly system for running experiments on a 2-degrees-of-freedom (2-DOF) robotic arm. It simplifies robotic arm control using Docker containers and micro-ROS for communication with microcontrollers, designed to support beginners and non-experts.\n\n## Key Features\n\n- **Dynamic Force Fields**: Leverage isotropic, anisotropic, oriented, and time-dependent viscous force fields for comprehensive experimentation\n- **Containerization**: Easy to set up and manage experiments using Docker\n- **Automated Control and Logging**: Control the robotic arm and log data automatically\n- **Dynamic Configuration**: Adjust experiment settings on the fly with ROS 2\n- **Micro-ROS Support**: Communicate with microcontrollers (like Teensy 4.1)\n- **CSV Data Logging**: Automatic data collection for analysis\n\n## Lessons Learned\n\n- Extensive testing is vital for dynamic systems to prevent unexpected behavior.\n- Improvements in automated startup processes enhance reliability.\n\n## Quick Start\n\n### Docker-First Approach\n\n**JiggyJoystick runs entirely in Docker containers for platform-agnostic deployment.** This ensures consistent behavior across all operating systems (Linux, macOS, Windows) and eliminates dependency management issues.\n\n```bash\n# Start the entire system with automatic Teensy detection and reset\n./scripts/start_system.sh\n```\n\nThis script will:\n\n- Automatically detect the Teensy device port\n- Start the micro-ROS agent container\n- Start the ROS2 workspace container, which automatically launches the robot orchestrator\n- Reset the Teensy to establish proper communication\n- Verify that all topics are available\n- **Prompt for manual connection if automatic reset fails**\n\n### Why Docker?\n\n- **Platform Independence**: Works on any system with Docker installed\n- **No Local ROS2 Installation**: All ROS2 dependencies are contained within Docker\n- **Reproducible Environment**: Consistent behavior across different machines\n- **Easy Deployment**: Single command startup with automatic dependency resolution\n- **Isolation**: No conflicts with existing software on the host system\n\n### Recent Improvements\n\nWe've made several important improvements to the JiggyJoystick system:\n\n- **Fully Automated Startup**: The entire system, including the ROS 2 agent, can now be launched with a single command (`./scripts/start_system.sh`).\n- **Enhanced Firmware Robustness**: Updated the Teensy firmware to handle connection failures gracefully. The firmware now includes retry logic that attempts to reconnect every 5 seconds, ensuring robust communication even if the initial connection doesn't succeed.\n- **Automatic Teensy Reset**: Integrated an automatic reset feature into the startup script. This triggers a hardware reset of the Teensy after the micro-ROS agent is fully initialized, resolving timing issues and ensuring the XRCE-DDS session is established correctly.\n- **Visibility of ROS2 Topics**: Successfully established communication between the Teensy and micro-ROS agent, allowing all expected topics to appear correctly in the ROS2 network.\n- **Plug-and-Play Experience**: With the automatic reset and improved connection logic, the system now offers a plug-and-play experience.\n\n## Micro-ROS Integration\n\nThe JiggyJoystick system integrates with micro-ROS to communicate with the Teensy 4.1 microcontroller that controls the robotic arm. This integration provides:\n\n### Hardware Communication\n\n- **Teensy 4.1 Node**: `/micro_ros_simulator` publishes joint states and subscribes to control commands\n- **Automatic Port Detection**: The system automatically detects the Teensy USB port\n- **Robust Connection**: Enhanced firmware with retry logic ensures reliable communication\n\n### Available Topics\n\nOnce the system is running, the following topics are available:\n\n| Topic                        | Type                     | Description                              |\n| ---------------------------- | ------------------------ | ---------------------------------------- |\n| `/joint_states`              | `sensor_msgs/JointState` | Joint positions, velocities, and efforts |\n| `/microcontroller_handshake` | `std_msgs/Bool`          | Handshake initiation from Teensy         |\n| `/ros2_handshake`            | `std_msgs/Bool`          | Handshake response to Teensy             |\n| `/start_trial`               | `std_msgs/Bool`          | Start trial command to Teensy            |\n| `/abort_trial`               | `std_msgs/Bool`          | Abort trial command to Teensy            |\n| `/trial_success`             | `std_msgs/Bool`          | Trial success notification to Teensy     |\n\n### Monitoring the Connection\n\nTo verify the micro-ROS connection is working:\n\n```bash\n# Check if the Teensy node is visible\nsudo docker exec -it jiggy-joystick-ros2 bash -c \"source /opt/ros/jazzy/setup.bash \u0026\u0026 source /ros2_ws/install/setup.bash \u0026\u0026 ros2 node list\"\n\n# Monitor joint states\nsudo docker exec -it jiggy-joystick-ros2 bash -c \"source /opt/ros/jazzy/setup.bash \u0026\u0026 source /ros2_ws/install/setup.bash \u0026\u0026 ros2 topic echo /joint_states\"\n\n# Check handshake messages\nsudo docker exec -it jiggy-joystick-ros2 bash -c \"source /opt/ros/jazzy/setup.bash \u0026\u0026 source /ros2_ws/install/setup.bash \u0026\u0026 ros2 topic echo /microcontroller_handshake\"\n```\n\n### Firmware Features\n\nThe Teensy firmware includes several robust features:\n\n- **Connection Retry Logic**: Automatically retries connection every 5 seconds if initial connection fails\n- **Graceful Error Handling**: No longer gets stuck in infinite error loops\n- **Handshake Protocol**: Implements a proper handshake sequence before starting trials\n- **Trial State Management**: Manages setup, active, and completion states\n- **Dynamic Force Field Control**: Applies configurable viscous force fields during trials\n  - Isotropic viscous damping\n  - Anisotropic viscous damping\n  - Oriented viscous damping\n  - Time-dependent viscous damping\n  - Static force fields (original behavior)\n\n## Experiment Description\n\nThe experiment involves running a series of **assays**, each consisting of multiple **trials**, on a 2-DOF robotic arm. Each trial applies specific control parameters (e.g., force fields) for a defined duration, and the system logs joint positions, velocities, torques, and other metadata. The experiment is configured via a YAML file (`assays.yaml`), which specifies:\n\n- The number of assays and trials per assay.\n- Trial durations.\n- **Dynamic force field settings** with multiple types:\n  - Static force fields (original 2x2 matrix)\n  - Viscous isotropic (uniform damping)\n  - Viscous anisotropic (different X/Y damping)\n  - Viscous oriented (rotated damping matrix)\n  - Viscous time-dependent (damping changes over time)\n\nThe system is designed to:\n\n- Load experiment configurations dynamically.\n- Control the robot by applying torques based on joint states and force fields.\n- Log data for post-experiment analysis.\n- Support dynamic reconfiguration via a ROS 2 service.\n\n### Node Details\n\n1. **ExperimentManagerNode**\n   - **Role**: Orchestrates the experiment by iterating through assays and trials defined in `assays.yaml`.\n   - **Functionality**:\n     - Loads the configuration file using `ament_index_python` to locate `assays.yaml`.\n     - Sends trial goals to the `ControlNode` via an action client (`/trial_action`, type `custom_interfaces.action.TrialAction`).\n     - Provides a service (`/load_config`, type `custom_interfaces.srv.LoadConfig`) to reload configurations dynamically.\n     - Logs trial progress and status.\n   - **Key Interactions**:\n     - Sends goals to the `ControlNode`’s action server.\n     - Receives results (success/aborted) from trials.\n     - Handles configuration updates via the service.\n\n2. **ControlNode**\n   - **Role**: Executes trials by controlling the robotic arm and computing torques.\n   - **Functionality**:\n     - Hosts an action server (`/trial_action`) to receive trial goals.\n     - Subscribes to `/joint_states` (type `sensor_msgs.msg.JointState`) for joint positions and velocities.\n     - Publishes torque commands to `/torque_commands` (type `std_msgs.msg.Float64MultiArray`) at 100 Hz.\n     - Publishes trial metadata (e.g., assay/trial numbers, force field status) to topics like `/assay_number`, `/trial_number`, `/ff_enabled`, and `/ff_value`.\n     - Computes torques based on joint states and an optional force field matrix.\n     - Supports trial cancellation and abort signals.\n   - **Key Interactions**:\n     - Receives goals from `ExperimentManagerNode`.\n     - Publishes data consumed by `LoggerNode`.\n     - Requires a hardware interface publishing `/joint_states`.\n\n3. **LoggerNode**\n   - **Role**: Logs experiment data to CSV files for analysis.\n   - **Functionality**:\n     - Subscribes to multiple topics: `/joint_states`, `/torque_commands`, `/assay_number`, `/trial_number`, `/trial_status`, `/ff_enabled`, and `/ff_value`.\n     - Creates a new CSV file for each trial, named `log_assayX_trialY_TIMESTAMP.csv`, in the `logs` directory.\n     - Logs timestamped data including joint positions, velocities, torques, force field settings, and trial status.\n   - **Key Interactions**:\n     - Consumes data published by `ControlNode`.\n     - Writes to CSV files in the current working directory’s `logs` folder.\n\n## Prerequisites\n\n**JiggyJoystick runs entirely in Docker containers - no local ROS2 installation required!**\n\n### System Requirements\n\n- **Docker**: Installed on your system. See the [official Docker installation guide](https://docs.docker.com/get-docker/).\n- **User Groups**: Your user must be in the `docker` and `dialout` groups.\n  ```bash\n  sudo usermod -aG docker $USER\n  sudo usermod -aG dialout $USER\n  ```\n  (Log out and back in to apply changes).\n- **Hardware**: Teensy 4.1 microcontroller with USB connection\n- **Operating System**: Any system that supports Docker (Linux, macOS, Windows)\n\n### What's Included in Docker\n\nThe Docker containers provide everything needed:\n\n- **ROS 2 Jazzy Jalisco**: Complete ROS2 installation\n- **Dependencies**: All ROS 2 packages (`rclpy`, `sensor_msgs`, `std_msgs`, `ament_python`)\n- **Python Libraries**: `numpy`, `pyyaml`, and other required packages\n- **Custom Interfaces**: `custom_interfaces` package with `TrialAction` and `LoadConfig`\n- **Robot Orchestrator**: Complete `robot_orchestrator` package\n- **Micro-ROS Agent**: For communication with Teensy microcontroller\n\n## Getting Started\n\n**No installation required!** Simply clone the repository and run the startup script.\n\n### 1. Clone the Repository\n\n```bash\ngit clone https://github.com/your-username/JiggyJoystick.git\ncd JiggyJoystick\n```\n\n### 2. Connect Your Teensy\n\n- Connect your Teensy 4.1 to your computer via USB\n- Ensure the Teensy has the correct firmware loaded (see firmware documentation)\n\n### 3. Start the System\n\n```bash\n./scripts/start_system.sh\n```\n\nThat's it! The Docker containers will be built automatically and the system will start.\n\n## Standard Operating Procedure (Verified)\n\nBased on extensive testing, the following procedure ensures reliable system operation:\n\n### Quick Start (Recommended)\n\n1. **Connect Teensy**: Ensure Teensy 4.1 is connected via USB\n2. **Run startup script**: `./scripts/start_system.sh`\n3. **Manual reconnection**: If prompted, physically disconnect and reconnect the Teensy USB cable\n4. **Verify connection**: Check that handshake completes successfully\n\n### Manual Docker Control\n\nFor advanced users who prefer manual control:\n\n1. **Build containers**:\n\n   ```bash\n   sudo docker-compose build --no-cache\n   ```\n\n2. **Start services**:\n\n   ```bash\n   sudo docker-compose up -d\n   ```\n\n3. **Reset Teensy** (if handshake fails):\n\n   ```bash\n   python3 -c \"\n   import serial\n   import time\n   try:\n       ser = serial.Serial('/dev/ttyACM0', 115200, timeout=1)\n       ser.dtr = False  # Reset\n       time.sleep(0.1)\n       ser.dtr = True   # Release reset\n       time.sleep(0.5)\n       ser.close()\n       print('✅ Teensy reset successful')\n   except Exception as e:\n       print(f'⚠️  Teensy reset failed: {e}')\n   \"\n   ```\n\n4. **Verify handshake**:\n\n   ```bash\n   sudo docker-compose logs jiggy-joystick-ros2 --tail 10\n   ```\n\n   Look for \"Handshake: ✅ Complete\"\n\n5. **Run experiment**:\n   ```bash\n   sudo docker exec -it jiggy-joystick-ros2 bash -c \"source /opt/ros/jazzy/setup.bash \u0026\u0026 source /ros2_ws/install/setup.bash \u0026\u0026 ros2 run robot_orchestrator experiment_manager_node\"\n   ```\n\n### Expected Behavior\n\n- **Initial startup**: System may show \"Handshake: ❌ Waiting\" for 30-60 seconds\n- **After Teensy reset**: Handshake should complete within 5-10 seconds\n- **Successful operation**: All trials should be accepted and complete successfully\n- **Data flow**: Joint positions and velocities should update in real-time\n\n### Troubleshooting Connection Issues\n\n**If handshake fails:**\n\n1. Check Teensy connection: `ls -la /dev/ttyACM*`\n2. Verify micro-ROS node: `sudo docker exec micro-ros-agent bash -c \"source /opt/ros/jazzy/setup.bash \u0026\u0026 ros2 node list\"`\n3. Look for `/micro_ros_simulator` in the node list\n4. Try physical disconnection/reconnection of USB cable\n5. Check container logs: `sudo docker-compose logs micro-ros-agent`\n\n**System Status Indicators:**\n\n- ✅ **Handshake Complete**: Ready for experiments\n- ✅ **Joint States Receiving**: Real-time data flowing\n- ✅ **Action Server Ready**: Can accept trial commands\n- ❌ **Handshake Waiting**: Teensy connection needed\n\n## Launch Instructions\n\nTo run the `robot_orchestrator` package, simply run the main startup script:\n\n```bash\n./scripts/start_system.sh\n```\n\nThis script handles the entire startup process, including:\n\n- Detecting the Teensy port.\n- Launching the `micro-ros-agent` and `jiggy-joystick-ros2` Docker containers.\n- Automatically running the `robot_orchestrator_launch.py` file within the `jiggy-joystick-ros2` container.\n\n### Monitoring the System\n\nOnce the system is running, you can monitor it in several ways:\n\n- **View Container Logs**:\n\n  ```bash\n  sudo docker-compose logs -f\n  ```\n\n- **Connect to the ROS 2 Container**:\n\n  ```bash\n  sudo docker exec -it jiggy-joystick-ros2 bash\n  ```\n\n- **List ROS 2 Topics**:\n  ```bash\n  ros2 topic list\n  ```\n\n## Configuration\n\nThe experiment is configured via `assays.yaml` in `~/ros2_ws/src/robot_orchestrator/config/`.\n\n### Dynamic Force Field Configuration\n\nThe system now supports multiple types of force fields configured using a new format:\n\n```yaml\nassays:\n  # Baseline - No force field\n  - name: \"baseline\"\n    n_trials: 3\n    trial_duration: 10.0\n    force_field:\n      enabled: false\n      matrix: [0.0, 0.0, 0.0, 0.0]\n\n  # Isotropic viscous field\n  - name: \"viscous_isotropic\"\n    n_trials: 3\n    trial_duration: 10.0\n    force_field:\n      enabled: true\n      matrix: [1, 10.0] # [type_id, damping]\n\n  # Anisotropic viscous field\n  - name: \"viscous_anisotropic\"\n    n_trials: 3\n    trial_duration: 10.0\n    force_field:\n      enabled: true\n      matrix: [2, 15.0, 5.0] # [type_id, damping_x, damping_y]\n\n  # Time-dependent viscous field\n  - name: \"viscous_time_dependent\"\n    n_trials: 3\n    trial_duration: 15.0\n    force_field:\n      enabled: true\n      matrix: [4, 0.0, 25.0, 10.0] # [type_id, damping_initial, damping_final, transition_time]\n```\n\n### Force Field Types\n\n- **Type 0**: Static force field (original behavior)\n- **Type 1**: Viscous isotropic (uniform damping)\n- **Type 2**: Viscous anisotropic (different X/Y damping)\n- **Type 3**: Viscous oriented (rotated damping matrix)\n- **Type 4**: Viscous time-dependent (damping changes over time)\n\n**See `docs/DYNAMIC_FORCE_FIELDS.md` for detailed documentation.**\n\n### Configuration Fields\n\n- **Fields**:\n  - `name`: Assay identifier (informational).\n  - `n_trials`: Number of trials per assay.\n  - `trial_duration`: Duration of each trial in seconds.\n  - `force_field.enabled`: Whether to apply a force field.\n  - `force_field.matrix`: Force field parameters `[type_id, param1, param2, ...]`.\n\nTo reload a new configuration during runtime:\n\n```bash\nros2 service call /load_config custom_interfaces/srv/LoadConfig \"{config_file_path: 'new_assays.yaml'}\"\n```\n\n## Troubleshooting\n\n### General Issues\n\n- **Package Not Found**:\n  - Ensure the workspace is built and sourced.\n  - Verify `package.xml` and `setup.py` are correct.\n- **Action Server Not Available**:\n  - Check that `ControlNode` is running (it hosts `/trial_action`).\n  - Increase the timeout in `ExperimentManagerNode.run_experiment` (e.g., from 5.0 to 10.0 seconds).\n- **No `/joint_states`**:\n  - Ensure the robot hardware or a dummy publisher is running.\n- **Logging Issues**:\n  - Verify `~/ros2_ws/logs` is writable.\n  - Check for CSV files after trials complete.\n- **Build Errors**:\n  - Install missing dependencies: `rosdep install --from-paths src --ignore-src -r -y`.\n  - Check logs in `~/ros2_ws/log/latest_build`.\n\n### Teensy Connection Issues\n\n**Problem**: Micro-ROS agent cannot establish connection with Teensy\n\n**Symptoms**:\n\n- `/micro_ros_simulator` node not visible in `ros2 node list`\n- No `/joint_states` topic data\n- Micro-ROS agent logs show \"Serial port not found\" or connection errors\n\n**Solution**: **Manual Teensy Connection Procedure**\n\n1. **Check Teensy Detection**:\n\n   ```bash\n   # Verify Teensy is detected by the system\n   lsusb | grep -i teensy\n   ls -la /dev/ttyACM*\n   ```\n\n2. **Manual Reset Process**:\n   When the startup script prompts for manual connection:\n   - **Physically disconnect** the Teensy USB cable\n   - **Wait 2-3 seconds** for the system to detect disconnection\n   - **Reconnect** the Teensy USB cable\n   - **Wait for bootup** - look for the Teensy LED to blink indicating it's ready\n   - **Press ENTER** in the terminal to continue\n\n3. **Verify Connection**:\n\n   ```bash\n   # Check if micro-ROS node is now visible\n   sudo docker exec jiggy-joystick-ros2 bash -c \"source /opt/ros/jazzy/setup.bash \u0026\u0026 ros2 node list\"\n\n   # Check topics are available\n   sudo docker exec jiggy-joystick-ros2 bash -c \"source /opt/ros/jazzy/setup.bash \u0026\u0026 ros2 topic list\"\n   ```\n\n4. **If Still Not Working**:\n   - Check micro-ROS agent logs: `sudo docker logs micro-ros-agent`\n   - Verify Teensy has correct firmware loaded\n   - Check USB cable and port functionality\n   - Try a different USB port\n   - Ensure user has permission to access serial ports (dialout group)\n\n**Note**: This manual connection step is required because the automatic reset mechanism in the startup script doesn't work reliably with all Teensy configurations. The manual disconnect/reconnect ensures the Teensy firmware initializes properly and establishes the micro-ROS connection.\n\n## Example Workflow\n\n1. Launch the system: `./scripts/start_system.sh`.\n2. The `ExperimentManagerNode` loads `assays.yaml` (e.g., 3 assays, 2 trials each).\n3. For each trial:\n   - Sends a goal to `ControlNode` (e.g., assay 1, trial 1, duration 10s, force field enabled).\n   - `ControlNode` publishes torques to `/torque_commands` and trial metadata.\n   - `LoggerNode` writes data to `logs/log_assay1_trial1_TIMESTAMP.csv`.\n4. `ControlNode` completes the trial and sends the result.\n5. `ExperimentManagerNode` proceeds to the next trial or assay.\n6. After all trials, the experiment completes, and logs are saved.\n\n## Contributing\n\nTo contribute:\n\n1. Fork the repository and make your changes\n2. Update source files in `ros2_ws/src/robot_orchestrator/` or `ros2_ws/src/custom_interfaces/`\n3. Test your changes: `./scripts/start_system.sh` (Docker will automatically rebuild)\n4. Submit changes via pull requests\n\n### Development Workflow\n\n- **Code changes**: Edit files in `ros2_ws/src/` - Docker will rebuild automatically\n- **Configuration changes**: Modify `ros2_ws/src/robot_orchestrator/config/assays.yaml`\n- **Testing**: Use `./scripts/start_system.sh` to test changes\n- **Debugging**: Access the container with `sudo docker exec -it jiggy-joystick-ros2 bash`\n\n## License\n\nThis package is licensed under the Apache-2.0 License.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faqc-github%2Fjiggyjoystick","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faqc-github%2Fjiggyjoystick","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faqc-github%2Fjiggyjoystick/lists"}