Skip to main content
This guide sets up two SO-101 arms with a ready-made example. You move the leader arm by hand on the operator machine, and the follower arm on the robot machine copies it. You don’t need to write any code.

Example project

Launch files, configs, and shortcut commands for two SO-101 arms.

Prerequisites

  • Two SO-101 arms, calibrated with LeRobot. lerobot-calibrate comes from a separate LeRobot install. The id you give each arm there goes in .env.
  • Ubuntu 24.04 and ROS 2 Jazzy on each machine. On other 64-bit Linux (Raspberry Pi OS, Debian, Ubuntu 22.04, Jetson), run this example in Docker instead: see the example’s Docker section.
  • An access token. You create a room id in step 4.
You can run one arm per machine, or both arms on one machine. Do the first four steps on each machine.

Install the ROS packages

Install the SDK

Check the install: which zrt-teleops-ros2-leader should print a path.

Get and build the example

Fill in .env

Add your token, the room id, and the port and calibration id of the arm on this machine. If both arms are on one machine, fill in both.No room id yet? Create one on either machine, and use the same id on both:
.env
  • Ports: find them with ls /dev/serial/by-id/. Don’t use /dev/ttyACM0: those names can change after a replug or reboot.
  • Ids: the names you gave the arms when you calibrated them. The calibration files must be on the machine that runs that arm, under ~/.cache/huggingface/lerobot/calibration/ (robots/so_follower/ for the follower, teleoperators/so_leader/ for the leader). If you calibrated on another machine, copy them there.

Start the follower

Plug in the follower arm and its power supply first. Then, on the robot machine:
The follower arm becomes stiff and holds its position. This is the follower’s launch terminal: keep it open.

Start the leader

On the operator machine, the same way:
The leader arm stays loose, so you can move it by hand. Before going on, wait until both launch terminals show the bridge’s topics: ... line.

Take control

Open a command terminal on each machine and load the shortcut commands. env.sh loads ROS and .env for you.
Optional first-run check, on the operator machine: hold the leader arm in its middle pose (the pose you used during calibration) and run:
Every joint should read close to 0 rad. A value near 3.14 means that joint’s offset (2048 in the URDF) is missing, or the arm wasn’t calibrated with LeRobot. Fix that before take_control: the example sets max_misalignment: 0.0, so nothing stops the follower from moving to a wrong pose.Then, on the operator machine:
The reply should say armed, lease …. The follower moves to match the leader, then follows it. Keep the space around the follower clear.If the reply says no grant within 5.0s, see Troubleshooting.

Stopping

  • release_control on the operator machine stops the follower. It holds its position.
  • Ctrl-C in the leader’s launch terminal is safe. The leader is loose anyway.
  • follower_leave on the robot machine disconnects the follower while the arm keeps holding.
Ctrl-C in the follower’s launch terminal stops the servo driver, which turns the servos’ torque off. The arm is then held only by its gears: it often stays where it is, but a stretched-out pose can sag or drop. Hold the arm first. To leave the room with the arm actively holding, use follower_leave instead. Ctrl-C in the command terminal, or on the leader, is harmless.

Commands

Run these in the command terminal, after source env.sh. Leader commands go on the operator machine, follower commands on the robot machine; run one on the wrong machine and it tells you where to run it. To keep both sides running after you close the terminal, see the example’s README. In background mode, follower_up and leader_up refuse to start while a ros2 launch of the same arm is running.

Troubleshooting

What’s next

Reference

Recording, cameras, and all settings.

SO-101 on LeRobot

The same arms without ROS.