Conversation
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: aj0khi <81395597+aj0khi@users.noreply.github.com>
This PR adds the first physical hardware integration for the WayBionic arm. ## What's new - **waybionic_hardware package**: ROS 2 Arduino serial bridge using the confirmed Uno R4 protocol. Accepts RUN/HOME/STOP commands, publishes estimated joint state for RViz, and reports connection/command status on /diagnostics. - **Hardware mode support**: Launch parameter hardware_mode switches between simulation (default) and arduino mode. Prevents simulated publishers from running simultaneously with the physical bridge. - **Dry-run testing**: Arduino bridge supports --dry-run for development without hardware or USB connection. - **Architecture documentation**: Complete hardware path design, protocol details, and phased implementation plan in docs/arm_hardware_motion_architecture.md. ## Commands to test ### Dry-run (no Arduino needed): ```bash source install/setup.bash ros2 launch waybionic_bringup ground_station.launch.py \ hardware_mode:=arduino \ arduino_dry_run:=true ``` ### Physical hardware (Arduino connected): ```bash source install/setup.bash ros2 launch waybionic_bringup ground_station.launch.py \ hardware_mode:=arduino \ arduino_port:=/dev/ttyACM0 ``` ### Verify motion and state: ```bash ros2 topic echo /joint_states ros2 topic echo /diagnostics ``` ## Current limitations - No physical position feedback; RViz shows estimated commanded pose. - Joint sensors (encoders/potentiometers) not yet integrated. - MotionTestPanel remains on string topic; trajectory action interface planned for phase 2. ## Build and run ```bash colcon build --symlink-install source install/setup.bash ```
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Advanced Run ID: Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Co-authored-by: aj0khi <81395597+aj0khi@users.noreply.github.com>
There was a problem hiding this comment.
🟡 Changes recommended
Unresolved hardware safety, fault-handling, motion-limit, and launch issues block approval.
Get a fresh assessment by requesting another Copilot review.
Pull request overview
Adds a four-joint arm simulation, Arduino serial bridge, RViz motion and diagnostics tooling, launch configurations, packaging, and architecture documentation.
Changes:
- Adds simulation trajectories and estimated Arduino joint-state publishing.
- Extends RViz panels, diagnostics CLI, tests, and configuration.
- Adds URDF, bringup modes, package metadata, and hardware architecture docs.
File summaries
| File | Summary |
|---|---|
waybionic_rviz_plugins/test/test_ros_diagnostics_source.cpp |
Adds diagnostics regression coverage. |
waybionic_rviz_plugins/src/ros_diagnostics_source.cpp |
Handles diagnostic alert messages. |
waybionic_rviz_plugins/src/motion_test_panel.cpp |
Implements motion command controls. |
waybionic_rviz_plugins/src/diagnostics_panel.cpp |
Adds movement-test UI. |
waybionic_rviz_plugins/scripts/temporary_diagnostics_publisher.py |
Publishes diagnostic messages. |
waybionic_rviz_plugins/plugin_description.xml |
Registers the motion panel. |
waybionic_rviz_plugins/package.xml |
Adds package dependencies. |
waybionic_rviz_plugins/include/waybionic_rviz_plugins/motion_test_panel.hpp |
Declares the motion panel API. |
waybionic_rviz_plugins/include/waybionic_rviz_plugins/diagnostics_panel.hpp |
Declares diagnostics UI members. |
waybionic_rviz_plugins/config/engineer_monitoring_view.rviz |
Configures the engineer monitoring view. |
waybionic_rviz_plugins/CMakeLists.txt |
Builds and exports panel sources. |
waybionic_motion_test/waybionic_motion_test/motion_test.py |
Implements simulated arm trajectories. |
waybionic_motion_test/waybionic_motion_test/__init__.py |
Defines the Python package. |
waybionic_motion_test/setup.py |
Defines motion-test installation. |
waybionic_motion_test/setup.cfg |
Configures script installation. |
waybionic_motion_test/resource/waybionic_motion_test |
Adds the ament package marker. |
waybionic_motion_test/package.xml |
Defines motion-test metadata and dependencies. |
waybionic_hardware/waybionic_hardware/arduino_bridge.py |
Implements Arduino transport and estimated state. |
waybionic_hardware/waybionic_hardware/__init__.py |
Defines the hardware package. |
waybionic_hardware/setup.py |
Defines bridge installation. |
waybionic_hardware/setup.cfg |
Configures script installation. |
waybionic_hardware/resource/waybionic_hardware |
Adds the ament package marker. |
waybionic_hardware/package.xml |
Defines hardware dependencies. |
waybionic_diagnostics/waybionic_diagnostics/cli.py |
Implements the diagnostics CLI. |
waybionic_diagnostics/waybionic_diagnostics/__init__.py |
Defines the diagnostics package. |
waybionic_diagnostics/test/test_cli.py |
Tests CLI behavior. |
waybionic_diagnostics/setup.py |
Defines CLI installation. |
waybionic_diagnostics/setup.cfg |
Configures script installation. |
waybionic_diagnostics/resource/waybionic_diagnostics |
Adds the ament package marker. |
waybionic_diagnostics/package.xml |
Defines diagnostics metadata and dependencies. |
waybionic_description/urdf/old_arm_prototype.urdf |
Adds the four-joint arm model and limits. |
waybionic_bringup/rviz/waybionic.rviz |
Updates the RViz layout. |
waybionic_bringup/rviz/waybionic_unified.rviz |
Adds the unified motion-panel layout. |
waybionic_bringup/package.xml |
Adds bringup dependencies. |
waybionic_bringup/launch/ground_station.launch.py |
Selects simulation or Arduino mode. |
waybionic_bringup/launch/display.launch.py |
Configures standalone display bringup. |
docs/arm_hardware_motion_architecture.md |
Documents the hardware architecture and safety model. |
cpsc. |
No functional content shown. |
Review details
Suppressed comments (6)
waybionic_bringup/launch/ground_station.launch.py:54
- This argument accepts arbitrary strings, so a typo such as
hardware_mode:=arduinmakes both the simulation and Arduino conditions false and silently launches without a state source. Restrict it to the two supported values so invalid modes fail at launch.
hardware_mode_arg = DeclareLaunchArgument(
'hardware_mode', default_value='simulation',
description='Arm mode: simulation or arduino')
waybionic_hardware/waybionic_hardware/arduino_bridge.py:20
- These calibration and trajectory constants are duplicated in
waybionic_motion_test/motion_test.pyand this bridge. A future change to the home offsets, directions, or sequence can make simulation and physical mode command different poses, contrary to the documented single calibration source. Move the shared calibration/sequence into one package-level configuration consumed by both nodes.
HOME_PHYSICAL_DEGREES = [33.5, 112.5, 151.5, 27.5]
SERVO_DIRECTIONS = [1.0, -1.0, 1.0, 1.0]
PHYSICAL_LIMITS = [(0.0, 270.0), (0.0, 112.5), (90.0, 270.0), (0.0, 270.0)]
SEQUENCE = [
[60.0, 95.0, 125.0, 60.0],
[45.0, 75.0, 200.0, 100.0],
[15.0, 100.0, 130.0, 5.0],
HOME_PHYSICAL_DEGREES,
waybionic_hardware/waybionic_hardware/arduino_bridge.py:20
- The first physical
RUNsends waypoints for all four servos simultaneously. The architecture's safety rules require a low-speed, one-joint-at-a-time commissioning test before synchronized trajectories, so this default hardware path bypasses that guard. Gate the synchronized sequence behind explicit commissioning or use a one-joint sequence first.
SEQUENCE = [
[60.0, 95.0, 125.0, 60.0],
[45.0, 75.0, 200.0, 100.0],
[15.0, 100.0, 130.0, 5.0],
HOME_PHYSICAL_DEGREES,
waybionic_hardware/waybionic_hardware/arduino_bridge.py:199
- The estimator state is committed before
send_line()succeeds. If a HOME/RUN command is issued while another move is active and the serial write fails,motion_activecan remain true whiletargethas been changed to a command the Arduino never received;sequence_activecan likewise remain set after a failed RUN. Commit motion state only after a successful write and clear the sequence on failure.
self.start = list(self.current)
self.target = list(target)
self.motion_started = time.monotonic()
self.motion_duration = max(0.3, min(15.0, self.segment_duration))
command = 'MOVE,' + ','.join(f'{value:.2f}' for value in target)
waybionic_motion_test/waybionic_motion_test/motion_test.py:71
- When HOME interrupts an active sequence,
sequence_indexstill points at the interrupted segment. Once the HOME segment completes,update_trajectory()sees an index below the final element and starts the remaining RUN sequence instead of stopping at HOME. Reset the sequence state when handling HOME.
elif command == 'HOME':
self.start_segment(self.home)
waybionic_rviz_plugins/src/motion_test_panel.cpp:120
- The panel reports STOPPED immediately after publishing HOLD, without checking that a bridge received the command or that the Arduino acknowledged it. If the bridge is absent or the write fails, the physical arm may continue while the UI reports a successful stop; make stop completion/failure depend on hardware feedback.
- Files reviewed: 35/41 changed files
- Comments generated: 19
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| def read_serial(self): | ||
| while not self.serial_stop.is_set() and self.serial_port is not None: | ||
| try: | ||
| line = self.serial_port.readline().decode('ascii', errors='replace').strip() | ||
| if line: | ||
| self.process_serial_line(line) |
| except Exception as error: | ||
| self.connected = False | ||
| self.last_error = str(error) | ||
| self.last_status = 'serial-read-failed' | ||
| return |
There was a problem hiding this comment.
Confirmed on d77c284 with a fake serial read failure. connected becomes false, but both motion flags remain true, and the next state timer advances the published pose. Please freeze the estimate and cancel the sequence when the transport fails; the current three hardware tests do not exercise this path.
| def process_serial_line(self, line): | ||
| self.get_logger().debug(f'Arduino: {line}') | ||
| if line.startswith('READY,IK4,1'): |
| if line.startswith('ERROR,'): | ||
| self.motion_active = False | ||
| self.sequence_active = False | ||
| self.last_error = line[6:] | ||
| self.last_status = 'arduino-error' |
| status.level = DiagnosticStatus.OK if self.connected else DiagnosticStatus.ERROR | ||
| status.message = self.last_status |
| movement_test_button_ = new QPushButton("▶ Run Movement Test"); | ||
| movement_test_button_->setToolTip( | ||
| "Run the robot through its predefined movement test sequence."); |
| test_running_ = true; | ||
|
|
||
| result_label_->setText("Running motion sequence..."); | ||
| status_label_->setText("RUNNING: synchronized 4-DOF sequence"); | ||
|
|
||
| run_button_->setEnabled(false); | ||
| home_button_->setEnabled(false); | ||
| stop_button_->setEnabled(true); | ||
|
|
||
| publishCommand("RUN"); |
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
- Resolves colcon test failures due to missing test files - Both packages now have minimal unit tests that verify module imports - CI/CD pipeline will now pass the test phase
|
Updated todo list Connect Arduino to WSL In Windows PowerShell as Administrator: usbipd list
usbipd bind --busid <BUSID>
usbipd attach --wsl --busid <BUSID>Replace In WSL, verify the port: ls /dev/ttyACM* /dev/ttyUSB*Usually it will be sudo usermod -aG dialout "$USER"Restart WSL afterward if needed. Run the arm cd ~/waybionic_ground_station
source /opt/ros/jazzy/setup.bash
source install/setup.bash
ros2 launch waybionic_bringup ground_station.launch.py \
hardware_mode:=arduino \
arduino_port:=/dev/ttyACM0 \
launch_rviz:=trueVerify the Arduino connects: ros2 topic echo /diagnosticsBefore using the real arm, test without sending commands: ros2 launch waybionic_bringup ground_station.launch.py \
hardware_mode:=arduino \
arduino_dry_run:=true \
launch_rviz:=trueTo disconnect the USB device from WSL: usbipd detach --wsl --busid <BUSID> |
yassinsolim
left a comment
There was a problem hiding this comment.
Reviewed d77c284. The hardware and simulator packages each pass their three tests, but mocked behavior checks exposed the issues below. I also reproduced the existing disconnect finding. All checks were hardware-free; no serial device or motor was accessed. Please address these and the remaining safety threads before merge.
There was a problem hiding this comment.
[P1] Remove the Windows-invalid filename
This empty file has a trailing dot, which Windows cannot check out normally. On Windows, even exporting the selected packages with git archive fails with error: invalid path 'cpsc.'. Please remove the file or rename it without the trailing dot so contributors can check out this branch without weakening Git's path protections.
| self.serial_stop.set() | ||
| if self.serial_port is not None: | ||
| try: | ||
| self.serial_port.close() |
There was a problem hiding this comment.
[P1] Request a stop before closing an active bridge
I started a MOVE against a fake serial device and called destroy_node(). The port was closed with only the MOVE in the write log; no HOLD was sent. The firmware runs that trajectory independently, so closing the launch does not request a stop for the active move. Please cancel the sequence and request HOLD while the transport is still usable, serialize shutdown with the reader, and add a shutdown-during-motion regression.
|
|
||
| if progress >= 1.0: | ||
| self.current = list(self.target) | ||
| if self.sequence_index < len(self.sequence) - 1: |
There was a problem hiding this comment.
[P2] Keep HOME separate from sequence playback
HOME also reaches this sequence-advance branch. Starting from a fresh node, I sent HOME and advanced 151 timer ticks with the default duration: the node moved on to sequence index 1 with a non-home target, without receiving RUN. Please advance the sequence only while an explicit RUN is active. Cover HOME both before a run and while interrupting a run so it finishes at home and stays there.
| except Exception as error: | ||
| self.connected = False | ||
| self.last_error = str(error) | ||
| self.last_status = 'serial-read-failed' | ||
| return |
There was a problem hiding this comment.
Confirmed on d77c284 with a fake serial read failure. connected becomes false, but both motion flags remain true, and the next state timer advances the published pose. Please freeze the estimate and cancel the sequence when the transport fails; the current three hardware tests do not exercise this path.
Arm Hardware and Motion Architecture
Goal
Use the same four-joint arm model in RViz for both simulation and a connected
Arduino, while allowing the motion test to command the physical arm and report
failures instead of only animating a simulated pose.
The current model is
old_arm_prototype.urdfwith these joints:base_yawshoulderelbowwrist_rollCurrent State
The motion test currently publishes generated positions directly to
/joint_states. That is suitable for visualization, but it is not a hardwarecontrol path: it represents commanded positions as if they were measured
positions.
There is currently no Arduino transport, encoder feedback path,
ros2_controlhardware plugin, trajectory controller, or motion action in theworkspace.
The archived handoff provides a usable first transport contract:
base_yaw, D4shoulder, D5elbow, D6wrist_roll.INPUT_PULLUP.ID,MOVE,s1,s2,s3,s4,durationMs,JOG,servo,delta,durationMs,and
HOLD.READY,IK4,1,OK,MOVE,OK,JOG,OK,ARRIVED,OK,HOLD,OK,SWITCH HOLD, andERROR,....The firmware interpolates commands internally every 20 ms and has software
limits, but it does not stream measured servo angles. Its
OK,ARRIVEDresponsemeans the command timeline completed, not that the mechanism was measured at
the target.
Target Runtime Architecture
The current Arduino firmware has no encoder or potentiometer feedback. It
reports command acceptance and arrival, but not measured servo positions. In
the first physical integration, the host bridge can publish an estimated
/joint_statespose from the accepted command timeline. RViz will then showthe commanded pose, not verified mechanical position. When real feedback is
added, measured state should replace that estimate.
Runtime Modes
Simulation
This preserves the existing visual motion test. It must not run at the same
time as the physical hardware state publisher.
Physical Hardware
The launch file should select exactly one mode, for example with a
hardware_modeargument whose values aresimulationandarduino.ROS Interfaces
These are the proposed stable interfaces between packages:
/joint_states,sensor_msgs/msg/JointState/joint_trajectory_controller/follow_joint_trajectory,control_msgs/action/FollowJointTrajectory/joint_trajectory_controller/joint_trajectory,trajectory_msgs/msg/JointTrajectory/diagnostics,diagnostic_msgs/msg/DiagnosticArrayThe motion test should become an action client. Actions provide acceptance,
feedback, completion, cancellation, and failure results, which the current
RUN/HOME/STOPstring topic cannot provide.The existing string topic can remain temporarily as a simulation-only adapter
while the action path is introduced.
The first bridge implementation is available as
waybionic_hardwareandaccepts the existing
/old_arm_motion_test/commandtopic. It translatesRUN,HOME, andSTOPinto the firmware protocol, publishes the estimatedpose, and publishes connection/command status on
/diagnostics.Package Responsibilities
waybionic_descriptionros2_controlblock for the four actuated joints.New
waybionic_hardwareare added.
The first implementation can use a small serial bridge if a full
ros2_controlplugin is not yet ready. The public ROS interfaces should stillmatch the target design so the bridge can later be replaced without changing
RViz or the motion test.
waybionic_motion_testIt must not publish synthetic
/joint_statesin physical mode.waybionic_rviz_pluginsRobotModelvisualization.MotionTestPanelto use the action interface.waybionic_bringuprobot_state_publisherin both modes.Safety Rules
Arduino-reported fault.
merely stop publishing messages.
cannot move the arm accidentally.
running synchronized trajectories.
Incremental Implementation Plan
servo calibration, joint limits, and the Arduino packet format.
/joint_statespublisher from starting in physical mode.waybionic_hardwarewith connection state,heartbeat, command conversion, command-state estimation, and diagnostics.
ros2_controland load ajoint state broadcaster plus trajectory controller.
verify Arduino arrival status against each target. Add measured-feedback
verification when sensors become available.
only when the controller reports the arm is connected.
then RViz with recorded feedback, and only then the physical arm.
Current Bringup Commands
Simulation remains the default:
Arduino mode requires an explicit serial port:
The bridge can be exercised without an Arduino:
The first physical test should use the external servo-power switch, confirm
the arm is supported and clear, then use
HOMEbeforeRUN. The currentbridge intentionally does not claim measured position feedback.
Definition of Done
measured feedback once sensors are added.
panel and
/diagnostics.state.
/joint_states.Decisions Still Needed
measurement, or both. The current firmware provides command status only.
lower-level controller.