Skip to main content
The arms’ impedance controllers cancel each joint’s friction and gravity with a feedforward model. How smooth the arm moves at slow speed depends on how well that model matches this robot’s gearboxes and links, so every robot should be calibrated once — at the factory, and again after a joint or gearbox is replaced. On the jelly robot’s right arm the slow-motion reference (slow_osc) went from 4.3–4.5 mm of vertical tool shake untuned to about 2.5 mm with the calibrated friction model and the current joint gains — the 1–3 Hz sway an operator feels during slow teleop.

What a robot runs without one

An uncalibrated robot uses the coded defaults: the joint gains in AxolConfig, and the jelly robot’s measured friction for every joint as a fallback. That is much better than no friction model, but each robot’s gearboxes differ — calibrate before relying on slow, precise motion.

Calibrate

With both arms clear of obstacles, the e-stop in reach and the robot otherwise idle:
or Factory calibration (all joints) in the diagnostics dashboard. It sweeps every joint of both arms (distal → proximal, about 6 minutes per joint, ~1.5 h in all) at slow and moderate speeds and fits, per joint:
  • friction in the realtime core’s own law — sliding friction growing with the gravity load, viscous drag, an offset, and the low-speed Stribeck excess (cancelled on shoulder_1, shoulder_2 and the elbow);
  • gravity: the link’s centre of mass.
See tune.factory for the flags (one arm, raw sweep capture, the older quick profile). The results apply on this machine at once (~/.almond/calibration.json) and, when the upload key is configured, are uploaded under the robot’s identity — the Axol hub adapter’s serial, which stays with the arms across compute-host swaps:
Without the key the run still calibrates locally and says so. Upload later with calibration.push (--dry-run first to see what goes up).

Every machine that drives the robot

A machine picks up its robot’s calibration automatically at the end of can.setup, and with axol calibration.pull at any time — no credentials needed. Values layer as: coded defaults, then the uploaded factory calibration, then this machine’s local calibration file.

Check the result

Replay the built-in slow-motion reference (slow_osc: the arm bent up in front while shoulder_1 sweeps slowly back and forth, generated in code and the same on every robot) and read the wrist IMU’s shake score:
Each pass prints a wrist IMU (right): … vertical X mm = 1-3 Hz … + 3-15 Hz … line. Compare against the same command before calibrating, in the same session (the score drifts 10–20% across a day). Jelly’s numbers above were measured on an earlier recorded version of slow_osc, so treat them as an order of magnitude, not a target. The wrist camera only measures here; nothing feeds back from it.
One joint at a time: tune.friction --profile slow calibrates a single joint’s friction (and --fit-csv re-fits a saved sweep), tune.gravity its gravity. Push the result with calibration.push.