Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Servo sysid: the 56× kp question answered — replay error 3.31° → 1.76°

2026-08-11 19:2x–2x:xxZ work session. Closes sim-servo-sysid, the last physics item ahead of the sim-policy-eval-100seeds protocol pre-reg. Follows the sim-as-eval lit page (SIMPLER: controller gains are the FIRST-order eval-fidelity lever) and the sim fixes batch 1 contact work.

Plain words. Our simulator and the robot’s own manufacturer disagree by a factor of 56 about how stiff the arm’s servo motors are, and nobody had measured which value is right. We settled it with data we already own: take real recorded episodes, feed the same motor commands into the simulated arm, and check how closely the simulated joints retrace what the real joints actually did. The vendored stiffness turns out to be badly wrong — it makes a motor that slams to its force limit at the slightest error, then can’t hold a raised arm posture where the real arm holds steady. Fitting six physical parameters against the recordings cut the retrace error roughly in half on episodes the fit never saw, and the fitted values are now the simulator’s defaults. Every safety check from the last batch of sim fixes was re-run and still passes — one number even improved: a gripped boat now twists only 0.1° in the jaws instead of 0.4°.

The question

The vendored menagerie model drives every STS3215 with kp 998.22, kv 2.731, forcerange ±2.94; TheRobotStudio’s own MJCF for the same servo says kp 17.8, kv 0, ±3.35. At kp 998 with a ±2.94 N·m force clamp, the actuator saturates at 0.17° of position error — a bang-bang force-clamped servo, not a proportional controller. The sim review measured exactly that signature on the rig-median home pose (joints pinned at ±2.94). SIMPLER’s ablation says this is the parameter class that moves sim-vs-real eval fidelity most (control loss 0.131→0.432 moved MMRV 0.031→0.100), so it had to be answered before the 100-seed protocol pins “v0 physics”.

Method (SIMPLER’s recipe, our data)

Open-loop replay, sim/sysid_servo.py: reset the sim arm to a recorded episode’s first observation.state, then feed the episode’s recorded action stream (absolute joint targets, degrees, 30 Hz) tick-for-tick into the position actuators and score the sim joint trajectory against the recorded observation.state stream — mean absolute error in degrees over the 5 arm joints (the gripper is contact-coupled: real episodes close it onto a boat the arm-only replay doesn’t carry; reported record-only).

  • Fit set (train-side): clean ep 0; v2 eps 0, 7, 20, 30, 47.
  • Validation set: the er-60k deterministic episode holdout (fraction 0.1, split-seed 0) — clean ep 2; v2 eps 1, 4, 10, 36, 44. Same split the policy evals use; every headline number below is validation.
  • Fitted params (shared by all six servos, log₁₀ space, 6-D): kp, kv, forcerange, joint damping, frictionloss, armature. Optimizer is a dependency-free coordinate descent (golden-section per coordinate, 4 shrinking sweeps, ~240 objective evals), two starts.
  • Scale to read errors against: the real servo itself trails its own commands by 2.19° mean (|action[t] − state[t+1]| on val) — a sim that teleported to each command would score ≈ that. Beating it requires actually modeling the lag.

Results (validation = held-out episodes, arm-joint MAE)

candidatekpkvforcedampingfrictionarmaturefit MAEval MAE
menagerie (vendored)998.222.7312.940.600.0520.0282.74°3.31°
upstream (TheRobotStudio)17.803.350.600.0520.0282.40°2.80°
fitted, start=menagerie → pinned108.213.383.480.720.0180.2041.47°1.76°
fitted, start=upstream8.800.521.970.600.0430.0361.32°1.90°

Reads:

  • The vendored gains are the worst candidate measured — worse than a servo that teleports to its target (3.31° vs the 2.19° lag scale). The failure mode is visible in the overlay: holding a raised shoulder posture (t≈13–18 s), the bang-bang servo sags ~19° below the commanded plateau while the real arm holds it.
  • Upstream’s published gains are closer to the truth than menagerie’s — the 56× question resolves in upstream’s favor directionally, but neither is right.
  • The fit halves the error: 3.31° → 1.76° (−47%) on episodes it never saw, and beats the teleport scale — the lag dynamics are genuinely modeled. Per-joint: shoulder_pan 1.02→0.56, shoulder_lift 3.83→2.18, wrist_flex 3.93→1.13, wrist_roll 3.06→1.03.
  • Two very different solutions score close (kp 108/kv 13.4 vs kp 8.8/kv 0.52): at 30 Hz observability there’s a stiffness/damping ridge. The kp-108 fit wins validation and is the pin. Its large armature (0.204 vs 0.028) reads as the servo’s reflected gear-train inertia, which the vendored model essentially omits.
  • Elbow_flex barely improves (4.72→3.89) — the residual is dominated by the un-modeled boat payload and the settled-home geometry (jaw-on-table projection), not by servo gains.

What’s pinned

sim/so101_sim.py now applies SERVO_SYSID (kp 108.18, kv 13.377, forcerange ±3.478, damping 0.722, frictionloss 0.0183, armature 0.2045) to all twelve STS3215 actuators (both arms) at model load — same runtime-override convention as the widened joint ranges; the vendored XML is untouched. Full numbers + per-candidate scores banked in analysis__sim_servo_sysid.json (local: outputs/sim/sysid_servo.json).

All sim-fixes gates re-verified under the new params (probe suite re-run): reset strikes 0/100, settled start state bit-identical across seeds (spread 0.0000°), rest drift 0.001 mm / spin 0.004° per 10 s, pinch → lift held with in-grip spin 0.1° (was 0.4°), upright 0.91, penetration 2.6 mm, qpos + render bit-determinism green, 28.0 ms/control-tick (+5%; 100-seed eval still ~21 min sim-side). The settled home elbow residual grows 6.6° → 7.1° (softer, truer servo sags slightly more; the pre-reg pins the settled state either way).

Limitations (stated, not hidden)

  • The replay carries no payload — grasp-phase arm loading (~40 g boat) is unmodeled; elbow_flex’s residual is the visible cost.
  • The sim tick is 35 ms vs the rig’s 33.3 ms; fitting tick-for-tick absorbs the ~5% timebase skew into the gains — the right choice for eval use, but these are effective sim parameters, not bench-true servo constants (BAM-style rig measurement would be the upgrade).
  • One shared parameter set for six differently-loaded joints; per-joint gains are the obvious next rung if elbow fidelity ever gates.

What this feeds

The sim-policy-eval-100seeds pre-reg pins v0 physics = widened joint ranges + solver caps 50/50 + the 340-hull asset build + this SERVO_SYSID set, with the replay-MAE table above as the measured justification. The SIMPLER-recommended sysid-before-freeze is done; the protocol pre-reg is next in the queue with nothing blocking it.