Skip to main content
Full-robot factory calibration: identifies friction (tune.friction) and gravity CoM (tune.gravity) for all 14 joints (both arms × 7) in one command. Also available from the diagnostics dashboard’s Tuning workbench (axol serve). One bidirectional multi-velocity sweep per joint yields both fits — the half-difference of forward/backward torque gives the friction model (Fc, k, Fv), the average gives the gravity curve the CoM is fit to, with the friction offset Fo refit against the corrected model. Each arm runs distal → proximal (wrist_3 → … → shoulder_1) and every joint’s fit is saved before the next joint sweeps, so proximal sweeps see already-corrected distal links — the ordering tune.gravity asks the operator to keep by hand happens automatically here. Sweep safety and the gravity-load poses (base-collision caps, elbow raised for wrist_2, camera clearance, and axis-vertical joints posed so gravity actually loads them — see tune.gravity) match the individual tools. Results are saved to ~/.almond/calibration.json (this machine uses them immediately) and uploaded to Supabase Storage keyed by the robot’s identity — the Axol hub adapter’s USB serial, which travels with the arms across compute-host swaps. The documents live in a public bucket (axol-calibrations/<hub_serial>.json), so fetching them needs no credentials at all — only uploading does. The upload only happens when the write key is configured; without it the run calibrates locally and says so:
One-time Supabase setup: create a Storage bucket named axol-calibrations and mark it public. No table or RLS policies are needed — write access comes from the service key. The upload merges over what the cloud already stores, so a one-arm re-run never wipes the other arm’s data. An interrupted run keeps (and uploads) every joint that completed.

calibration.pull

Fetches a robot’s factory calibration from the public bucket into the local cache (~/.almond/factory_calibration.json) — no credentials needed. It also runs automatically at the end of can.setup, so a fresh machine picks up its robot’s calibration during first-time setup without any extra step. Run it manually to refresh:
Every AxolConfig then overlays the fetched values between the coded defaults and the local calibration file:
so anything tuned locally afterwards (tune.friction --save, tune.pid --save, tune.gravity --save) still wins over the factory values, and the coded defaults remain the fallback for joints neither layer covers.