Part II: Teleoperation and data collection · §21 of 43

Read this before running any LeRobot command on the follower arms.

What LeRobot’s calibration does (source: robots/openarm_follower/openarm_follower.py, motors/damiao/damiao.py):

DeviceWhen calibration runsWhat it does to the hardware
Follower (openarm_follower)lerobot-calibrate, or automatically on connect() if no calibration file exists for that --robot.id (e.g. the first lerobot-teleoperate)Torque off → asks you to put the arm hanging straight down, gripper closed → sends the Damiao set-zero command (0xFE) to all 8 motors. This rewrites the motors’ zero, which persists. It then saves a JSON file with dummy ranges.
Damiao leader (openarm_leader)Same as follower, and additionally on every connect() once calibrated (if self.is_calibrated: self.bus.set_zero_position())Re-zeroes the leader motors every time you start teleop. The leader must be hanging/gripper-closed at every start.
OpenArm Mini (openarm_mini)Every connect() asks “ENTER to use existing calibration or c to recalibrate”Writes Feetech homing offsets to the Mini’s own servos (half-turn homing) and records the gripper open/closed range. Only the Mini is affected.

Why this matters for the ROS stack: the follower’s motor zero is the same zero ROS 2 uses (§11). LeRobot’s zero is a hand-placed “hanging straight down” pose, and that matches the URDF zero (in RViz with all joints at 0 the arms hang straight down). So the convention is compatible, but:

  • a hand-placed zero is less precise than Enactic’s mechanical-stop calibration (openarm-can-zero-position-calibration);
  • every time someone runs LeRobot calibration on the follower, the ROS zero moves too;
  • running it with the arm not properly hanging (e.g. resting on the table) corrupts the zero for both stacks, and the next ROS activation will “return to zero” into the wrong pose.

Recommended procedure (do the zero once, with Enactic’s tool, and stop LeRobot from re-zeroing the followers):

  1. Zero each follower arm once with the mechanical-stop script (§11, Option A), or verify the existing zero with openarm-can-cli -i canX monitor while the arm hangs straight down.

  2. Pre-create LeRobot’s follower calibration files so LeRobot never runs its own zeroing:

    conda activate lerobot
    python ~/Documents/openarm_lerobot/make_follower_calibration.py my_follower                   # single arm, --robot.id=my_follower
    python ~/Documents/openarm_lerobot/make_follower_calibration.py my_bimanual_follower --bimanual  # --robot.id=my_bimanual_follower

    Files go to ~/.cache/huggingface/lerobot/calibration/robots/openarm_follower/<id>.json (bimanual: <id>_left.json, <id>_right.json). They only need to exist: the Damiao bus keeps nothing else from them, and clipping uses the side limits.

  3. Always use the same --robot.id afterwards. A new id means no file, which means LeRobot re-zeroes the motors.

  4. If lerobot-calibrate asks “Press ENTER to use provided calibration file … or type ‘c’”, press ENTER. Typing c re-zeroes the motors.

  5. Leaders are separate hardware, so let LeRobot calibrate them normally. For the Damiao leader, remember it re-zeroes at every start: start it hanging, gripper closed.