← reports index ← reports index
Field guide · 2026-09-09

Left Arm Calibration

The left arm's zero point has drifted. Every scripted motion today stopped short on shoulder_lift by 3–5°. This guide is what to do at the robot. Takes about 10 minutes.

⚠ Two mistakes that ruin the calibration
1. Press c — never ENTER. ENTER silently writes the old file back and exits in ~20 s. If you don't see Running calibration of …, nothing was calibrated.
2. At "move to the middle", shoulder_lift must really be at mid-travel. If it isn't, the encoder wraps and you get a full 0–4095 range. The arm is then commanded to positions it physically cannot reach — it stalls against the stop and overheats.

What is wrong right now

shoulder_lift travel mechanical calibrated now 1440 3866 where it should be missing ≈ 5°
The span (2426 ticks) is correct. The whole window is shifted, so the low end is out of reach.

The six joints

1 shoulder_pan left / right 2 shoulder_lift ★ THE BROKEN ONE ★ 3 elbow_flex 4 wrist_flex 5 wrist_roll 6 gripper
Joint 2 is the one that fights gravity — and the one that is mis-zeroed.

Steps

1 Back up the old calibration
cp -r ~/.cache/huggingface/lerobot/calibration ~/calib-backup-$(date +%Y%m%d)

Redoing a calibration is tedious. Always back up first.

2 Free the serial bus
systemctl --user stop leader-follower

Two programs on one bus crash each other. On 2026-08-17 this exact collision dropped both arms onto the table.

3 Put shoulder_lift at MID-TRAVEL by hand

Torque is off, so the arm moves freely. Swing joint 2 to each end to feel where the stops are, then leave it halfway between them.

lower stop upper stop put it HERE middle

Why this matters: the encoder is 12-bit and wraps at 0/4095. Starting away from the middle makes the sweep cross that wrap, and you get a bogus full-turn range.

4 Run the calibration
lerobot-calibrate --robot.type=so101_follower \
  --robot.port=/dev/ttyACM0 --robot.id=left_arm

--robot.id is not a label — it picks the file:
~/.cache/huggingface/lerobot/calibration/robots/so_follower/left_arm.json

When it asks, press c then ENTER. You must then see:

Running calibration of …
Move the arm to the middle of its range …

Then sweep every joint through its full range, slowly, and return to the middle.

5 Check the result

Spans should match the right arm within a few percent:

JointExpected spanRight arm
shoulder_pan27362727
shoulder_lift24262405
elbow_flex22512215
wrist_flex23802367
wrist_rollfull turn by designfull turn
gripper15581554
A span of 0–4095 on any joint except wrist_roll = redo it
That is the encoder-wrap failure. Do not use that calibration — the arm will be driven into its stop and cook.
When it's done, tell the remote operator. Two config values were temporarily loosened to work around the bad calibration and must be put back:

Why this is worth 10 minutes

Today, with the arm carrying a cup, every scripted move stopped short by 3–5° on shoulder_lift while every other joint landed within 0.6°. That is the signature of a shifted zero, not of a weak motor or a slow move — the servo reported it had reached its Min_Position_Limit while still 4.39° away from the commanded goal.

Reference: 03-software/SETUP.md §6 · calibration files in ~/.cache/huggingface/lerobot/calibration/robots/so_follower/
Measured on 2026-09-09: left shoulder_lift range 1440–3866 ticks (span 2426, correct), homing_offset 1617.