mix bb_so101.calibrate PORT writes a position offset to each servo so that
the joint's mechanical centre corresponds to 0 rad in the BB DSL. Run it
after assigning IDs, and any time you remount a servo horn or replace a servo.
Usage
mix bb_so101.calibrate /dev/ttyUSB0
mix bb_so101.calibrate /dev/ttyUSB0 --dry-run
mix bb_so101.calibrate /dev/ttyACM0 --baud-rate 500000
| Argument | Default | Description |
|---|---|---|
PORT | required | Serial port for the Feetech bus |
--dry-run / -n | off | Compute and display offsets without writing |
--baud-rate / -b | 1000000 | Servo bus baud rate |
How it works
- Torque is disabled on every servo so the arm can be moved freely.
- The task polls all six servos in a loop and updates a live display of the min/max raw position observed for each joint.
- You move every joint through its full mechanical range — both extremes for each revolute joint, all the way open and all the way closed for the gripper. Don't be subtle; push to the actual mechanical limits.
- Press Enter when you're done.
- For each joint, the task computes the midpoint of the observed range, converts it to the servo's signed-magnitude offset format, and writes it to EEPROM. The new offset takes effect immediately.
Why this is needed: STS3215 servos have a 4096-step rotation and a factory
default that puts step 2048 at the centre of rotation. But "the centre of
rotation" doesn't necessarily coincide with the joint's mechanical centre —
horns get pressed on at whatever angle they happened to be at. The offset
shifts the servo's reported position so the mechanical centre reads as 2048
(and therefore 0 rad after BB's mapping).
Common adjustments
Preview before writing
Pass --dry-run (or -n) to see the computed offsets without touching
EEPROM. Useful as a sanity check, or when troubleshooting unexpected joint
behaviour.
mix bb_so101.calibrate /dev/ttyUSB0 --dry-run
Re-calibrating one joint
The task always reads min/max for all six joints. There's no per-joint flag.
The simplest workaround is to manually drive only the joint you care about
through its range and leave the others stationary — the offsets for the
untouched joints will be ±0, which is a no-op.
Different baud rate
Match whatever's currently on the bus:
mix bb_so101.calibrate /dev/ttyUSB0 --baud-rate 500000
Troubleshooting
One joint reports a tiny range
You didn't move it far enough. The min/max readout is live — exercise that joint to both stops before pressing Enter.
Calibration "works" but the 3D model is still off
The offsets only correct mechanical misalignment. If the URDF in
bb_so101's topology doesn't match your specific arm (e.g. you swapped a
3D-printed bracket), no amount of calibration will reconcile that. Inspect
the generated lib/{App}/robot.ex and adjust link lengths or joint axes
manually.
The gripper feels backwards
The gripper actuator uses the joint's positive direction, which on a standard
SO-101 means "open". If your gripper closes when commanded to open, set
reverse?: true on the gripper actuator in the generated robot.ex:
actuator(
:gripper_servo,
{BB.Servo.Feetech.Actuator,
servo_id: 6, controller: :feetech_controller, reverse?: true}
)The other five joints have reverse?: true baked in already; the gripper
historically doesn't need it but kits vary.
When you don't need to recalibrate
- After a normal power cycle — offsets are stored in EEPROM and persist.
- After a
mix bb_so101.calibrateitself — only run it again if something changed mechanically. - After updating
bb_so101to a new version — the offsets are per-servo, not per-package version.