Part II: Teleoperation and data collection · §25 of 43
Never run both stacks on the same follower bus. There is no lock between them. Both would send MIT commands to motors 1–8 and the arm would follow whichever frame arrived last.
| Going from → to | Do this |
|---|---|
| ROS 2 → LeRobot | 1. Move the arms to the hanging pose (home / all zeros) with ROS. 2. Support the arms. 3. bash /root/scripts/openarm_stop.sh (motors off, then ROS stopped; a plain Ctrl+C can crash before the motors are switched off, §12.4). 4. Check ps aux | grep ros2_control_node in the container shows nothing. 5. Start LeRobot. |
| LeRobot → ROS 2 | 1. Lower the leader so the follower hangs. 2. Ctrl+C LeRobot (torque off → arms limp; support them). 3. Both arms powered, then bash /root/scripts/openarm_launch.sh real (zeus cabling built in, §22). On activation the arms go to zero in 10 s (patched driver, §4); from hanging, that’s a tiny move. 4. Identification wiggle (§12.2). |
Handing a follower bus from one stack to the other. Never run both at once.
flowchart TB subgraph a["ROS 2 → LeRobot"] direction TB a1["Move arms to the hanging pose<br/>(home / all zeros) with ROS"] --> a2["Support the arms"] --> a3["Ctrl+C the ROS launch"] --> a4["Check no ros2_control_node<br/>is left in the container"] --> a5["Start LeRobot"] end subgraph b["LeRobot → ROS 2"] direction TB b1["Lower the leader so<br/>the follower hangs"] --> b2["Ctrl+C LeRobot<br/>(torque off: support the arms)"] --> b3["Launch ROS, real hardware,<br/>zeus CAN arguments"] --> b4["Activation moves the arms<br/>to zero in ~2 s"] end
A quick “is the bus free?” check from the host:
candump -n 20 -T 500 can0 # no output within 0.5 s means no one is commanding the left arm (zeus: can0 = left)Ways to combine them (not built yet)
- Replay LeRobot demos in RViz/MoveIt: load a dataset (
LeRobotDataset) in thelerobotenv, convert each frame withlerobot_to_ros()(§20), and send it as aJointTrajectoryto the ROS mock’s/left|right_joint_trajectory_controller/joint_trajectorytopic. The two Python envs differ (conda vs ROS Jazzy), so use a file in between (e.g. export to CSV/NumPy) or runrclpyfrom the ROS container on an exported file. - Live view of LeRobot teleop in RViz: a small bridge that publishes the follower observation as
sensor_msgs/JointState(radians/metres) to arobot_state_publisherrunning without ros2_control. Read-only, so it doesn’t conflict on the bus as long as the bridge gets its data from LeRobot, not from CAN. - LeRobot policy through ROS: write a custom LeRobot
Robotclass whosesend_action()publishes to the ROS trajectory controllers andget_observation()subscribes to/joint_states. Then ROS owns the bus, and LeRobot benefits from ROS-side safety (limits, MoveIt collision checks). This is the cleanest long-term integration, but it’s real work.