Part I: The ROS 2 stack · §1 of 43
The ROS 2 stack on zeus. Orange boxes run inside one controller_manager (ros2_control_node, 750 Hz). Dotted arrows carry data.
flowchart TB clients["your code · ros2 CLI · rclpy<br/>MoveIt (via move_group)"] jtc["trajectory controllers<br/>left arm · right arm · 2 grippers"]:::cm lhw["left hardware interface"]:::cm rhw["right hardware interface"]:::cm jsb["joint_state_broadcaster"]:::cm rviz["robot_state_publisher<br/>→ /tf → RViz"] larm["left arm<br/>7 Damiao + gripper"]:::hw rarm["right arm<br/>7 Damiao + gripper"]:::hw clients -.->|FollowJointTrajectory| jtc jtc -.->|position| lhw jtc -.->|position| rhw lhw ==>|can0| larm rhw ==>|can1| rarm lhw -.->|state| jsb rhw -.->|state| jsb jsb -.->|/joint_states| rviz classDef cm fill:#c2410c1f,stroke:#c2410c classDef hw fill:#0f766e1f,stroke:#0f766e
The same diagram as text, as written in the guide
┌─────────────────────────── your code / CLI / RViz ───────────────────────────┐ │ ros2 action send_goal … rclpy node MoveIt "Plan & Execute" ros2 topic │ └──────────────┬───────────────────────────────┬───────────────────────────────┘ │ FollowJointTrajectory action │ MoveGroup action │ or JointTrajectory topic ▼ │ ┌────────────┐ │ │ move_group │ (plans with OMPL + KDL IK, │ └─────┬──────┘ then sends trajectories) ▼ ▼ ┌──────────────────────────── controller_manager (ros2_control_node) ──────────────────────────┐ │ left_joint_trajectory_controller right_joint_trajectory_controller │ │ left_gripper_controller right_gripper_controller joint_state_broadcaster │ │ │ position commands ▲ position/velocity/effort states │ │ ┌─────────────▼──────────────────────────────────────┴─────────────────────┐ │ │ │ hardware component "openarm_left_hardware_interface" (+ "…right…") │ │ │ │ sim: mock_components/GenericSystem (echoes commands back as state) │ │ │ │ real: openarm_hardware/OpenArmHW → openarm_can library → SocketCAN │ │ │ └──────────────────────────────────────────────────────────────────────────┘ │ └───────────────────────────────────────────────────────────────────────────────────────────────┘ │ CAN-FD 1 Mbit/s nominal / 5 Mbit/s data can1 ──► left arm: 7× Damiao motors (IDs 1–7) + gripper (ID 8) can0 ──► right arm: 7× Damiao motors (IDs 1–7) + gripper (ID 8) robot_state_publisher: /robot_description + /joint_states → /tf → RViz
Key facts:
- One controller manager runs both arms. Each arm is its own ros2_control hardware component on its own CAN bus.
- Everything is joint-space position control. The trajectory controllers write position commands. On real hardware these become Damiao MIT-mode commands (
kp,kd,q_des,dq_des,tau_ff), so the motor itself runs the PD loop. - Sim and real use the same controllers, topics and actions. Only the hardware plugin changes (
use_fake_hardware:=true/false). Anything you develop against the mock works unchanged on the robot. The real robot just has physics, gravity and the ability to hurt someone.