Skip to main content
Replays a reference motion through the production Rust-core motion_control path — impedance gains, gravity/friction/inertia feedforward, and host-side damping all come from the same AxolConfig production uses (the panel settings over the calibration, as teleop and the SDK load them: per-joint gains, link mass / CoM, stiffness, has_gripper) — and scores tracking accuracy and smoothness per joint. Because the motion is identical from run to run, this is the deterministic A/B loop that ad-hoc teleop testing can’t give you: override one gain with --gain, replay, and compare the numbers (and graphs, in the diagnostics dashboard). Every run persists a tuning-run artifact (full per-joint time series + metrics) under ~/.almond/diagnostics/tuning/ for charting and side-by-side comparison. The arm moves to the motion’s start and back to rest on collision-aware planned trajectories; a contact watchdog aborts playback if a sustained torque residual says the arm is pushing on something that isn’t in the plan. Arrival at the start pose is checked before playback: a joint more than ~3° off is named and playback is skipped (the arm returns to rest). A --a4 joint that fails this almost always has a stored planner acceleration that is neither 0 nor 60000 — read it with scripts/fw_gains.py --id <id>; anything in between re-plans every streamed target and the joint barely moves (see tune.a4).
The live wrist-IMU damping flags below (--imu-damp*, --gyro-damp*, --torque-probe) are research diagnostics. Damping from the wrist camera’s IMU was evaluated on jelly and rejected: it adds high-frequency oscillation, and its effect depended on how the camera sat on the wrist. Encoder-only damping (--imu-damp-source encoder) made the 1–3 Hz sway worse.
With --noise, --filter, and/or --ik the run is still scored against the clean reference, and the artifact stores the stream actually sent alongside it — the dashboard charts overlay commanded (clean), sent, and actual per joint, so the filters’ cleanup (and their lag) — or the IK solver’s reconstruction of the Cartesian path — is directly visible on hardware. --ik re-solves the whole chain (warm-started, like teleop) before playback starts, so a slow solve can’t stretch the command pacing; solve-time stats land on the run artifact instead.

Reading the scorecard

Each pass also prints — and stores as metrics.imu with the raw samples as imu_{side}_t/acc/gyro — the wrist IMU shake: the gripper camera’s acceleration band-passed to 1–15 Hz (above the motion, below the buzz), integrated to displacement and scored as the median (and p90) 2 s peak-to-peak excursion in mm, overall and along gravity (vertical, split into low_mm 1–3 Hz — the impedance sway — and high_mm 3–15 Hz), plus the band’s acceleration and angular-rate RMS and its peak frequency. Unlike the joint columns it sees what the motor-side encoders cannot — gear backlash, link flex, the gripper itself — so it is the number that matches a tool tip you can see shaking. Joints the motion never exercises (under 1° of commanded travel) show - in the tracking columns — a parked joint tracks meaninglessly well — but keep their row and are still scored for buzz and torque chatter, which is exactly where a hold-pose limit cycle shows up.