One joint travels to a certain angle and refuses to go further. Nothing is touching it, it moves freely by hand with the power off, and the other joints reach their full range without complaint.
- SO-100
- SO-101
- LeKiwi
A joint that stops at the same angle every time with nothing in its way is a calibration artifact, not a limit switch, because these arms have none. If the stored zero point sits near the end of the servo’s position scale, part of the joint’s working range falls past the point where the encoder count wraps, and commands beyond it get clamped rather than allowed to jump across the discontinuity. The fix is to remount the horn so the home pose sits near the middle of the scale, then recalibrate.
A soft stop and a hard stop feel different
Before you touch anything, establish which of the two you have. A software clamp is silent, perfectly repeatable and lands on the same number every time. A mechanical obstruction is noisy, slightly different on each attempt, and the servo audibly works against it. Confusing them sends you to opposite ends of the workshop.
| Observation | Reading |
|---|---|
| Stops at the same commanded value every run, silently | Software clamp, so calibration |
| Stops a little differently each time, with a strained sound | Mechanical, something is in the way or binding |
| Free by hand with the power off, blocked under power | Software clamp |
| Resists by hand with the power off too | Mechanical |
| Blocked in one direction, full travel in the other | Zero point sits near one end of the scale |
| Blocked symmetrically in both directions | The recorded sweep range is narrower than the joint |
What the wrap point is
A bus servo reports its position as a number on a fixed circular scale. The scale runs from one end to the other and then rolls back to the beginning, because the shaft is a circle and the count has to close. That rollover is the wrap point, and it exists at one fixed physical orientation of the output shaft, decided by the servo, not by your build.
Calibration stores where your neutral pose sits on that scale. Every angle you command afterward is that stored zero plus an offset. If the zero landed comfortably in the middle, offsets in both directions stay inside the scale and everything behaves. If the zero landed near one end, part of the range you want falls past the rollover, where the reported number stops increasing and starts again from the other extreme. Software that let a joint cross that boundary would produce a full-speed unwind in the wrong direction, so it clamps instead. The clamp is the stop you are feeling, and it is the safe behavior rather than a bug.
This is also why the problem is arm-specific rather than model-specific. The horn can be seated on the output shaft at many different rotations, and where it goes decides where mechanical neutral falls on the electrical scale. Two arms built from the same kit by two people can differ by enough that one owner never encounters this and the other loses an afternoon to it.
Fix it
- 1Rule out mechanics first
With the servo supply off, move the joint by hand through the whole range you want. If it goes there freely, nothing physical is stopping it and you are chasing a stored number, not a screw.
- 2Write down where it stops, in both directions
Note the commanded value at the stop going each way. A block in one direction only is the signature of a zero point near one end of the scale. A symmetric block is a narrow recorded sweep instead, which the same recalibration also fixes.
- 3Remount the horn so neutral sits mid-scale
Bring the joint to the pose you consider home mechanically, loosen the horn, and reseat it so the servo sits near the middle of its travel in that pose. This is the step that actually solves the problem. Everything after it is bookkeeping.
- 4Recalibrate the arm
Guide every joint to the neutral pose, confirm, and let the client capture the reference. Calibration is a whole-arm operation, so the other five joints get a new zero at the same time whether they needed one or not.
bashay-robots calibrate - 5Sweep the joint to both limits and watch
Walk the joint slowly to each end of the range you need. Stop immediately if anything sounds strained. What you are confirming is that the range you actually use now sits inside what was recorded.
- 6Check that no joint landed near an edge
Do this after every recalibration, not only after this one. A home value sitting close to either end of the scale is the same bomb waiting for a different joint, and it costs one look to notice.
- 7Home the arm and drive it
Return to the home pose and drive the repaired joint from the client through its full intended travel. If it goes where you send it, you are finished.
bashay-robots home
# Confirm the arm is complete before recalibrating
ay-robots devices
# SERIAL PORTS
# /dev/ttyACM0 SO-100 (6 servos responding)
# Capture the zero point: guide each joint to neutral, then press Enter
ay-robots calibrate
# Return to home and drive the joint from the client
ay-robots homeLook at where each joint’s home value landed on its scale. Anything close to either end is a joint whose usable range is about to be clipped, even if it behaves today. Fixing it now is a horn remount; fixing it later is a horn remount plus the datasets you recorded in between.
Recorded joint values are relative to the zero point that was in force when you recorded them. After you move the zero, older episodes describe different physical poses than they did before, so do not mix recordings from either side of a recalibration into one dataset. If you already have data worth keeping, finish that dataset first. Recording practice is covered on /so-100/data-collection.
Why this often appears right after a repair
Replacing a servo, removing a horn to get at a screw, or rebuilding a joint after a collision all change where neutral sits on the electrical scale. The arm worked yesterday, you fixed something unrelated, and now one joint stops short. The two events are connected through the horn, not through whatever you were originally repairing, which is why the timing tends to send people looking in the wrong place. Full first-time assembly and calibration is on /learn/so-100-getting-started if you want the reference procedure.
What it is not
- A limit switch. These arms have none, so there is no switch to bypass or replace.
- A firmware restriction you can unlock. The clamp exists because crossing the wrap point would unwind the joint at speed.
- A policy problem. A trained policy commands positions like anything else and is clamped the same way.
- Something a longer training run improves. If the joint cannot reach, more steps teach the policy to stop there more confidently.
- A sign the servo is failing. A servo that answers, holds torque and tracks inside its allowed range is healthy.
The cost of leaving it alone
A clipped joint quietly shapes your data. During teleoperation your hand keeps moving while the joint stops, so the recorded action column flattens against the limit for the rest of that segment. The policy learns that the correct action at that point is to stop, and it reproduces that faithfully at inference, which then looks like a model that will not reach. You can spend a long time adjusting hyperparameters for a problem that lives in a horn. If you have already trained on such a dataset, the fix is the horn, then a fresh recording, then a new run: the model side of that loop is described on /train/act-on-so-100.
Frequently asked questions
Can I just work inside the smaller range?▾
You can, and your usable workspace shrinks accordingly. The bigger cost is invisible: every demonstration you record inherits the limit, so the policy inherits it too and will not reach past it even on an arm that could.
Which joints does this usually affect?▾
Any of them, but the ones people notice are rotational joints whose useful travel is a large fraction of a full turn, because those are the ones whose range is most likely to run into the rollover.
Do I have to recalibrate all six joints to fix one?▾
Yes. Calibration captures the whole arm in a single pass, so the other five receive a new zero at the same time. That is also why you should treat a recalibration as a boundary in your dataset history.
Is there a command that just shifts the zero for one joint?▾
No. The CLI exposes calibrate for the whole arm and home to return to the neutral pose. Fixing the underlying geometry with the horn and recalibrating is both the supported path and the one that survives the next rebuild.
The joint reaches further when I push it by hand than when I drive it. Why?▾
Because by hand you are moving the mechanism and by command you are moving through the calibration. That difference is the clearest confirmation you will get that the stop is stored rather than physical.
A symptom in one part of the chain is regularly produced by the part before it. These pages cover the neighboring areas.