Integration · Post 6 of 6
Streaming joint states to ROS 2
A dependency-free publisher that a ROS 2 node wraps as a subprocess.
Robotics courses often mean ROS 2, so we also wanted the SO-101's live joint positions available as a
sensor_msgs/JointState stream.
The constraint
On our machine LeRobot needs Python 3.13, while ROS 2 Jazzy is built for Python 3.12. That means rclpy cannot be imported
from LeRobot's environment, and LeRobot cannot easily be imported from ROS's.
The approach: a process boundary
examples/so101_ros/publish_joint_states.pyconnects to the follower withSO101Followerand prints newline-delimited JSON on stdout: joint positions in radians, keyed by the URDF's joint names. It has no ROS dependency at all.- A ROS 2 node in a separate workspace runs that script as a subprocess through
uv runand republishes each line as aJointState.
uv run python examples/so101_ros/publish_joint_states.py --port /dev/ttyACM0
Because the interface is plain JSON lines, either side can be tested on its own, and neither environment has to be
compatible with the other's Python version. Joint order follows the SO-101 convention
(shoulder_pan, shoulder_lift, elbow_flex, wrist_flex, wrist_roll, gripper), and the names match
assets/so101/so101_new_calib.urdf so tools such as RViz can display the arm directly.