> ## Documentation Index
> Fetch the complete documentation index at: https://docs.almond.bot/llms.txt
> Use this file to discover all available pages before exploring further.

# Calibrating Axol

> Calibrate each Axol's friction and gravity model for smooth slow motion. One command runs a motion sweep, uploads the results to the cloud, and every machine that drives that Axol picks it up.

Axol's impedance controllers cancel each joint's friction and gravity with a feedforward model. How smoothly an arm moves at slow speed depends on how well that model matches this Axol's gearboxes and links.

We recommend you calibrate Axol after setup.

## Without a calibration

An uncalibrated Axol runs on the coded defaults: the joint gains in [`AxolConfig`](https://docs.almond.bot/cli/configuration), and the friction measured on our in-house Axol as a fallback for every joint. That beats no friction model, but gearboxes differ from unit to unit. Calibrate before relying on slow, precise motion.

## Calibrate

With both arms clear of obstacles, the E-Stop in reach, and Axol otherwise idle, run:

```bash theme={null}
axol tune.factory
```

or press **Factory calibration (all joints)** in the [diagnostics dashboard](https://docs.almond.bot/guides/diagnostics-dashboard.md). It sweeps every joint of both arms, distal to proximal, at slow and moderate speeds. Each joint takes about 6 minutes, about 1.5 hours in all. Per joint it fits:

* **Friction**, in the realtime core's own law: sliding friction that grows with the gravity load, viscous drag, an offset, and the low-speed Stribeck excess (cancelled on `shoulder_1`, `shoulder_2`, and `elbow`).
* **Gravity**: the link's centre of mass.

See [`tune.factory`](https://docs.almond.bot/cli/tune-factory) for the flags: one arm, raw sweep capture, and the older quick profile.

The result applies on this machine at once (`~/.almond/calibration.json`). When the upload key is configured, it is also uploaded under Axol's serial number, which stays with the arms across compute-host swaps.

```bash theme={null}
# .env on the calibrating machine
AXOL_SUPABASE_KEY=<service key with storage write access>
```

Without the key the run still calibrates locally and says so. Upload later with [`calibration.push`](https://docs.almond.bot/cli/tune-factory#calibration-push). Pass `--dry-run` first to see what goes up.

## Every machine that drives Axol

A machine picks up its Axol's calibration automatically at the end of [`can.setup`](https://docs.almond.bot/cli/can-setup), or with `axol calibration.pull` at any time. No credentials are needed to pull.

Configuration values layer in this order: coded defaults, then the uploaded factory calibration, then this machine's local calibration file.

## Check the result

Replay the built-in slow-motion reference and read the wrist IMU's shake score. In `slow_osc` the arm is bent up in front while `shoulder_1` sweeps slowly back and forth. It is generated in code, so it is the same on every Axol.

```bash theme={null}
axol tune.motion --motion slow_osc --arms right --repeat 2
```

Each pass prints a `wrist IMU (right): … vertical X mm = 1-3 Hz … + 3-15 Hz …` line. Compare it against the same command run before calibrating, in the same session, since the score drifts 10 to 20% over a day. The numbers above were measured on an earlier recorded version of `slow_osc`, so treat them as an order of magnitude rather than a target. The wrist IMU only measures here. Nothing feeds back from it.

> [!NOTE]
>
> To calibrate one joint at a time: [`tune.friction --profile slow`](https://docs.almond.bot/cli/tune-friction) fits a single joint's friction (`--fit-csv` re-fits a saved sweep), and [`tune.gravity`](https://docs.almond.bot/cli/tune-gravity) fits its gravity. Push the result with `calibration.push`.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.