> ## 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.

# Teleoperation Config Parameters

> Every setting for axol teleop — what it does and its default.

export const prefix_4 = "jelly."

export const prefix_3 = "vr_server."

export const prefix_2 = "kinematics."

export const prefix_1 = "teleop."

export const F = ({children}) => <code style={{
  whiteSpace: "nowrap"
}}>{children}</code>;

export const prefix_0 = "axol."

Every setting for `axol teleop`. Add any flag below to the command, or set it once in the control panel — see [Command configuration](/cli/configuration) for config files and syntax details.

In the [shared settings file](/guides/control-panel-settings) (`~/.almond/settings.json`, read by default) the `axol`, `teleop`, `kinematics`, `vr_server` and `jelly` sections below appear under exactly those names — the file is a partial teleop config — while `--left_channel` / `--right_channel` live under `robot` and `--log_level` under `system`.

```bash theme={null}
axol teleop --axol.left_stiffness 0.8 --teleop.position_multiplier 1.5
```

## General

| Flag | Default | Description |
| - | - | - |
| `--sim` | `false` | Drive the browser visualiser instead of the robot. Robot gains and CAN channels are ignored. |
| `--mantis` | `false` | Drive the Mantis rigs' grippers from their triggers instead of the robot. |
| `--arms` | `true` | Drive the Axol arms. `false` drives only Jelly; the arms are never touched. Also skipped automatically when the arm CAN interfaces are absent while Jelly's are present. |
| `--left_channel` | `can_alm_axol_l` | CAN interface for the left arm. `null` disables the arm. |
| `--right_channel` | `can_alm_axol_r` | CAN interface for the right arm. `null` disables the arm. |
| `--cameras` | `{}` | Cameras to stream to the headset, as slot → serial: `"{overhead: 41234567, left_arm: 41234568}"`. Empty means no video. |
| `--camera_eyes` | `{}` | Which eye(s) of each stereo camera to stream: `"{overhead: both, left_arm: left}"`. Default is overhead both, wrists left. |
| `--resolution` | `null` | Capture resolution for all cameras: `SVGA`, `HD1080`, or `HD1200`. `null` keeps the camera default. |
| `--log_level` | `INFO` | `DEBUG`, `INFO`, `WARNING`, or `ERROR`. |
| `--config_path` | — | Load a JSON/YAML config file. Flags override it. |
| `--settings_path` / `--no_settings` | `~/.almond/settings.json` | Read another [shared settings file](/cli/configuration#the-shared-settings-file) / ignore it. Applies beneath `--config_path` and the flags. |

<h2 id="robot">
  Robot
</h2>

Arm stiffness, gripper limits, and per-joint gains. Ignored with `--sim`.

| Flag | Default | Description | | |
| - | - | - | - | - |
| <F>--{prefix_0}left\_stiffness</F> | `1.0` | How stiff the left arm is, from `0` (soft, hand-guidable) to `1` (the tuned gains). Lower values only add compliance — the arm tracks a little less tightly but yields more to obstacles. One number applies to every joint; a 7-element list sets each joint in the order `shoulder_1, shoulder_2, shoulder_3, elbow, wrist_1, wrist_2, wrist_3`. | | |
| <F>--{prefix_0}right\_stiffness</F> | `1.0` | Same, for the right arm. | | |
| <F>--{prefix_0}has\_gripper</F> | `true` | Set `false` on the gripperless model. The gripper motors are never enabled and datasets record 7 channels per arm instead of 8. | | |
| <F>--{prefix_0}gripper</F> | `parallel` | Which gripper is fitted: `parallel` (the stock two-finger gripper) or `parcel` (the hinged-plate parcel gripper). Sets which way each jaw closes for the bring-up calibration, which refuses a gripper whose measured stroke is the other type's. Box mode exists only with `parcel`. | | |
| <F>--{prefix_0}max\_step\_rad</F> | `0.5` | Largest joint move (rad) allowed between two consecutive commands. Bigger moves are dropped with a warning. `inf` disables. | | |
| <F>--{prefix_0}controller</F> | `impedance` | Which control law the realtime core runs the arms on. `impedance` is the production MIT frame at **240 Hz**: host gravity / friction / inertia feed-forward and host damping around the firmware PD, compliant. `position` hands every joint to its motor's own position loop at **400 Hz** — 0xA4 on the MyActuator joints, position-velocity on the Damiao wrists, the `firmware.*` gains below (written to ROM at enable) — where the position loop's target staircase (audible at 200 Hz) is gone. It is stiff: no compliance, no host feed-forward, and the contact watchdog is blind on the MyActuator joints (their torque telemetry reads NaN). At 400 Hz the bus cannot carry every motor every tick, so the core thins its schedule: every MyActuator command still goes out every tick, the two wrists are commanded on alternate ticks (200 Hz each), and one 0.01° a4 position read per tick rotates through the a4 joints and the gripper (\~67 Hz each; between reads a joint's position is carried on the speed its command echo reports every tick). The choice is baked into each joint's `wire_mode` when the robot is constructed; under `impedance` a per-joint `wire_mode` set explicitly is kept. Impedance joints are commanded at **240 Hz only**: an arm that mixes them with firmware-loop joints (a per-joint `wire_mode a4` under `impedance`, or `tune.motion --a4`) runs its core at **480 Hz**, the firmware-loop joints every tick and each impedance joint on alternate ticks — exactly 240 Hz, with its host feed-forward and damping stepped at that rate — and any other rate with an impedance joint on the arm is refused. Recorded-motion replays take `--controller` ([`tune.motion`](/cli/tune-motion)); teleop takes `--axol.controller position`. | | |
| <F>--{prefix_0}impedance\_hz</F> | `240.0` | Command rate of the MyActuator impedance joints: `240.0` (the verified rate) or `480.0` — every tick of a **480 Hz** core loop, their host feed-forward, damping and tracker stepped at 480, while the Damiao wrists stay at 240 Hz on alternate ticks (the gripper and any a4 position reads take one tick in eight). An experiment, never the default: the impedance gains, host damping and feed-forward were tuned at 240. With it set, any arm with an impedance joint runs its core at 480 Hz only. `tune.motion --impedance-hz 480` sets it for a run. | | |
| <F>--{prefix_0}left.gripper.torque\_limit</F> | `0.5` | Grip force — peak gripper torque (Nm). | | |
| <F>--{prefix_0}left.gripper.max\_speed</F> | `10.0` | Maximum gripper speed (rad/s). | | |
| <F>--{prefix_0}left.elbow\.kp</F> | per joint | Position stiffness of one joint, in `[0, 500]`. This is the stiffness-`1` value. | | |
| <F>--{prefix_0}left.elbow\.kd</F> | per joint | Velocity damping in the motor firmware, in `[0, 5]`. | | |
| <F>--{prefix_0}left.elbow\.kd\_host</F> | per joint | Extra damping (Nm·s/rad) applied by the host, for the slow shoulder resonance the firmware can't damp. Scaled down automatically in poses where the joint carries less inertia. `0` on joints whose firmware damping is enough. | | |
| <F>--{prefix_0}left.elbow\.kd\_host\_hz</F> | `null` | Centre frequency (Hz) of the band the host damping acts in. `null` tracks the arm's pose automatically. | | |
| <F>--{prefix_0}left.elbow\.kd\_host\_q</F> | `null` | Width of that band (bandwidth = centre ÷ q). `null` uses `0.8`. | | |
| <F>--{prefix_0}left.elbow\.j\_eff</F> | per joint | Effective inertia (kg·m²) used for acceleration feed-forward. | | |
| <F>--{prefix_0}left.elbow\.stiction\_gain</F> | `0.0` | Error-sign Coulomb compensation as a fraction of `friction.fc`: pushes up to `gain × fc` toward the target while the joint is stuck and the velocity feed-forward is off, fading out once the joint slides. The lever for slow-motion stick-slip stairs on the high-ratio X8 shoulders; keep it below the breakaway/`fc` ratio [`tune.breakaway`](/cli/tune-breakaway) measures. `0` is the production law. | | |
| <F>--{prefix_0}left.elbow\.stiction\_load\_gain</F> | `0.0` | Load-proportional part of that push, in Nm per Nm of the joint's gravity feed-forward (peak push = \`stiction\_gain × fc + stiction\_load\_gain × | gravity | \`). Gear friction follows the transmitted torque — right shoulder\_1 breaks away at 0.66 Nm at rest but at 2–3 Nm with the arm extended — so a constant push either hunts at rest or does nothing under load. |
| <F>--{prefix_0}left.elbow\.stiction\_err\_deg</F> | `0.1` | Position error (degrees) at which that term saturates. The push fades on *measured* velocity (gone above \~0.05 rad/s), so it never drives the slip. | | |
| <F>--{prefix_0}left.elbow\.dither\_nm</F> | `0.0` | Peak amplitude (Nm) of a sinusoidal torque dither on the feed-forward, `0` off. Keeps a geared joint's meshes sliding so its velocity-weakening friction (the X8-P20 shoulders: 2.1 Nm sliding at 0.05 rad/s, 0.7 Nm at 0.2 rad/s) cannot re-stick between cycles. Start at 1–2 Nm on a shoulder; it is audible. | | |
| <F>--{prefix_0}left.elbow\.dither\_hz</F> | `60.0` | Dither frequency: above the arm's structural modes (\~35 Hz), below the core's 120 Hz Nyquist. | | |
| <F>--{prefix_0}left.elbow\.stribeck\_gain</F> | `0.0` | Friction cancellation on **measured** velocity, as a fraction of the measured static-minus-sliding excess: \`gain × (stribeck\_dfs + stribeck\_load\_gain × | gravity | ) × exp(−(v/stribeck\_vs)²) × tanh(v/0.02)\`. The one feed-forward that acts on the velocity-weakening slope behind the X8 shoulders' 2 Hz stick-slip (a command-driven term cannot). Zero at rest. Sweep 0.5 → 0.9 and stop when the arm's 3 Hz mode grows. |
| <F>--{prefix_0}left.elbow\.stribeck\_dfs</F> | `0.3` | Static-minus-sliding friction excess (Nm) at zero gravity load. | | |
| <F>--{prefix_0}left.elbow\.stribeck\_load\_gain</F> | `0.1` | Growth of that excess per Nm of gravity feed-forward (right shoulder\_1: \~1.5 Nm under 12 Nm). | | |
| <F>--{prefix_0}left.elbow\.stribeck\_vs</F> | `0.1` | Speed (rad/s) at which the excess has fallen to 1/e. | | |
| <F>--{prefix_0}left.elbow\.stribeck\_pole</F> | `20.0` | Low-pass pole (rad/s) of the measured velocity the term follows. 20 is smooth but \~40° behind a 2.6 Hz surge; 40–80 follows it at the cost of encoder-step noise in the torque. | | |
| <F>--{prefix_0}left.elbow\.wire\_mode</F> | `mit` | Frame the realtime core commands the joint with while tracking. `mit` is the impedance frame (production). `a4` hands a **MyActuator** joint to the firmware's own position loop (0xA4, speed-capped at the tracker limit) with a paired 0x92 read for 0.01° position — the candidate for creeping through X8-P20 stick-slip. The joint is on 0xA4 from its first frame, holds included: the X6-P20's 2025-07 firmware ignores 0xA4 after an MIT frame until the motor is reset (the 2026 X8-P20 firmware switches freely). `pv` is the same for a **Damiao** wrist: its position-velocity mode (0x100+ID; the core sets control-mode register 2 at bring-up and switches it back to MIT for limp / gravity comp), gains in the KP\_APR/KP\_ASR registers, ramps in ACC/DEC. Costs of either: no compliance, no host feed-forward, and on a4 NaN torque telemetry (the contact watchdog is blind on that joint; a pv wrist keeps its torque channel). The gripper, gravity comp and the limp fallback always use MIT — so on the older firmware an a4 joint that has been hand-guided needs a re-enable before it tracks again. An a4 joint's stored planner acceleration must be 0 or 60000 (see [`tune.a4`](/cli/tune-a4)); loop gains come from `firmware.*` below. `controller` `position` (above) sets every joint's position wire mode at once; this field is the per-joint override. | | |
| <F>--{prefix_0}left.elbow\.mass</F> | per joint | Mass (kg) of the link, used for gravity compensation. Tune if an arm sags or pushes back in [gravity comp](/operations/gravity-comp). | | |
| <F>--{prefix_0}left.elbow\.com</F> | per joint | Centre of mass `[x, y, z]` (m) of the link. | | |
| <F>--{prefix_0}left.elbow\.friction.fc</F> | per motor | Coulomb friction (Nm). Measured per motor with [`tune.friction`](/cli/tune-friction). | | |
| <F>--{prefix_0}left.elbow\.friction.k</F> | per motor | Friction curve sharpness. | | |
| <F>--{prefix_0}left.elbow\.friction.fv</F> | per motor | Viscous friction (Nm·s/rad). | | |
| <F>--{prefix_0}left.elbow\.friction.fo</F> | per motor | Constant torque offset (Nm). | | |
| <F>--{prefix_0}left.elbow\.friction.fl</F> | `0.0` | Load-proportional Coulomb friction, Nm per Nm of gravity feed-forward: the effective `fc` is \`fc + fl × | gravity | `. Planetary gear friction grows with the torque it carries (right shoulder_1: ~0.6 Nm sliding at rest, ~1.5 Nm under 12 Nm), so a constant `fc`over-compensates at rest and under-compensates at reach.`0\` keeps the constant model. |
| <F>--{prefix_0}left.elbow\.firmware.position\_kp</F> | `null` | Firmware position-loop proportional gain (MyActuator 0x30 index 0x07, Damiao register KP\_APR), written to the motor's ROM at enable when set (`null` leaves the motor's stored value). Every joint defaults to `null` on every `firmware.*` field: the arms run impedance, where these loops are inert, so bring-up leaves the motors' own loops as shipped. These five gains are the motor's own position PI → speed PI controller and only act under `wire_mode` `a4`; identify them with [`tune.a4`](/cli/tune-a4). Stock 0.008 on the X8-P20 shoulders stick-slips at creep speed; the stairs are gone by 0.2 and, with the 400 Hz stream the core runs, tracking keeps improving to 1.0 (0.17° / 12 ms at 12 deg/s) with 1.4 still clean. | | |
| <F>--{prefix_0}left.elbow\.firmware.position\_ki</F> | `null` | Firmware position-loop integral gain. Leave at the stock `0`: on top of the speed integrator it hunts around the target. | | |
| <F>--{prefix_0}left.elbow\.firmware.position\_kd</F> | `null` | Firmware position-loop derivative gain (protocol V4.2+). The motor stores it, but the 0xA4 loop on the X8-P20 measured inert to it. | | |
| <F>--{prefix_0}left.elbow\.firmware.speed\_kp</F> | `null` | Firmware speed-loop proportional gain. Not a damper in practice — it did nothing for the loop's 5 Hz reversal mode — but the knob on the speed loop's own resonance (\~100 Hz on the X8-P20, \~135 Hz on the X6-P20): the current tone grows with it until the loop goes unstable (0.2 on the shoulder, 0.1 at position\_kp 1.5 on the elbow). Lower is quieter at no tracking cost. | | |
| <F>--{prefix_0}left.elbow\.firmware.profile\_acc</F> | `null` | **Damiao wrists only:** the position-velocity profiler's ramp (rad/s²), written to ACC and, negated, DEC at enable. Every streamed target is approached along a trapezoid under this acceleration, so it caps how fast the wrist follows: the stock `2` (115 deg/s²) cannot keep up with the 200 Hz stream — the loop hunts at \~5 Hz — and would take half a second to reach teleop speed. `50` sits above the core tracker's 33 rad/s² limit while still rounding each 5 ms step; `50` and `200` scored alike in `tune.a4`. | | |
| <F>--{prefix_0}left.elbow\.firmware.speed\_ki</F> | `null` | Firmware speed-loop integral gain. Lower than the stock `1e-4` is smoother on a geared joint: the integrator winds up while the joint is stuck and dumps it at release. | | |
| <F>--{prefix_0}left.elbow\.firmware.planner\_accel</F> | `null` | **MyActuator only:** the 0xA4 position planner's acceleration and deceleration (dps/s), written at enable to a joint on `wire_mode` `a4`. Only `0` (direct PI tracking of each target) and `60000` (the planner finishing each step within the tick) follow a stream; anything between re-plans every target and the joint barely moves, and is refused. On the X6-P20 elbow `tune.a4` tracked a 3 deg/s triangle to 0.02° RMS with 4 ms lag at `60000`, against 0.23° / 74 ms direct. `60000` wants `cap_track`. | | |
| <F>--{prefix_0}left.elbow\.firmware.cap\_track</F> | `null` | **0xA4 joints with the planner on:** each tick's speed cap as this multiple of the commanded speed (floor 1 dps, ceiling the tracker limit) instead of the fixed tracker limit — at a fixed cap the planner bursts through each step and idles the rest of the tick (4× the current spread on the elbow); `1.1`–`1.2` moved it continuously. Leave unset under direct tracking, where the cap is a hard limit on the PI output. Carried to the realtime core, not written to the motor. | | |
| <F>--{prefix_0}left.elbow\.firmware.tf\_rated\_current\_a</F> | `null` | **MyActuator a4 joints:** the motor's rated current (A — datasheet, or [`tune.a4 --tf-probe`](/cli/tune-a4)). Set, the realtime core sends the joint's position command as **0x73** (protocol V4.4 position control with torque feed-forward) carrying gravity and inertia, scaled by the joint's torque constant into the firmware's int8 1%-of-rated-current unit and faded in over a second. Only on firmware that implements 0x73 (VersionDate 2026042402 or later — the X8-P20 shoulders, not the X6-P20 elbow's 2025070202; elsewhere the joint stays on plain 0xA4 and the core logs why), and only in direct tracking (`planner_accel` `0`). Not written to the motor. | | |
| <F>--{prefix_0}left.elbow\.impedance\_hz</F> | `null` | This joint's impedance command rate: `480.0` commands it every tick of a 480 Hz core loop (its host feed-forward, damping and tracker stepped at 480), `240.0` keeps it on the verified 240 Hz lane, `null` follows `impedance_hz` above. Any joint at 480 runs the core at 480 Hz, the other impedance joints on alternate ticks. `tune.motion --fast-impedance right.shoulder_1` sets it for a run. | | |

Per-arm and per-joint flags are shown for `left` / `elbow`. Swap in `right`, or any joint: `shoulder_1`, `shoulder_2`, `shoulder_3`, `elbow`, `wrist_1`, `wrist_2`, `wrist_3`.

<Note>
  A robot calibrated with [`tune.pid --save`](/cli/tune-pid), [`tune.friction --save`](/cli/tune-friction), or [`tune.gravity --save`](/cli/tune-gravity) uses its own measured values (from `~/.almond/calibration.json`) instead of the defaults below. Flags you pass still override both.
</Note>

<Accordion title="Per-joint defaults">
  Both arms share these. `kp`/`kd` are the stiffness-`1` values (the default); the **soft** columns are what stiffness `0` blends toward. `shoulder_1` pins its host damper at `kd_host_hz` 2.6 / `kd_host_q` 1.0 and the `elbow` at 1.6 / 1.5 (every other joint leaves both `null`: a pose-tracked centre, the shared Q); `shoulder_1`, `shoulder_2` and the `elbow` run the Stribeck cancellation (`stribeck_gain` 0.8, `stribeck_pole` 40). Those values come from slow-motion tuning on the jelly robot's right arm (2026-09, and shoulder\_1's damper and shoulder\_2 on 2026-10-06 — shoulder\_2's creep ripple −57% at 3°/s; with shoulder\_1's damper change slow\_osc's 1–3 Hz wrist sway about −10% over three interleaved rounds).

  | Joint | `kp` | `kd` | `kd_host` | `j_eff` | `mass` (kg) | soft `kp` | soft `kd` |
  | - | - | - | - | - | - | - | - |
  | `shoulder_1` | 450 | 5.0 | 110 | 1.27 | 1.80 | 40 | 1.4 |
  | `shoulder_2` | 500 | 5.0 | 70 | 1.1 | 1.00 | 50 | 1.57 |
  | `shoulder_3` | 180 | 5.0 | 0 | 0.25 | 3.75 | 45 | 1.0 |
  | `elbow` | 200 | 5.0 | 10 | 0.6 | 0.25 | 40 | 2.22 |
  | `wrist_1` | 180 | 1.7 | 0 | 0 | 0.25 | 30 | 0.69 |
  | `wrist_2` | 130 | 2.25 | 0 | 0 | 0.65 | 25 | 1.5 |
  | `wrist_3` | 130 | 2.0 | 0 | 0 | 0.75 | 25 | 0.9 |
</Accordion>

<Accordion title="Per-motor friction defaults">
  Fallback friction for each motor, `fc + fl·|g|` sliding (Nm, `k` 100 — the realtime core's cap) with offset `fo`, and the low-speed Stribeck excess `dfs + ls·|g|` over `vs` (rad/s). Measured on the jelly robot with [`tune.friction --profile slow`](/cli/tune-friction) (2026-09); only `shoulder_1` and `elbow` cancel the excess by default (`stribeck_gain` 0.8). Friction is per motor — calibrate each robot.

  | Joint | Left: `fc`, `fl`, `fo` / `dfs`, `ls`, `vs` | Right: `fc`, `fl`, `fo` / `dfs`, `ls`, `vs` |
  | - | - | - |
  | `shoulder_1` | `0.5903, 0.0491, 0.0733` / `0.9814, 0.0485, 0.1` | `0.4022, 0.0544, −0.3074` / `0.7326, 0.0335, 0.1` |
  | `shoulder_2` | `0.4702, 0.0401, −0.6108` / `0.6142, 0.0389, 0.0989` | `1.3210, 0.0768, 1.0389` / `1.1065, 0.066, 0.0937` |
  | `shoulder_3` | `0.3664, 0.0786, −0.0018` / `0.2214, 0.1685, 0.1` | `0.3674, 0.0550, 0.1217` / `0.4078, 0.1479, 0.1` |
  | `elbow` | `0.0382, 0.0858, −0.0113` / `0.2347, 0.1301, 0.1` | `0.2704, 0.0448, 0.0197` / `0.1558, 0.1405, 0.0754` |
  | `wrist_1` | `0.4791, 0, 0.0686` / `0.5188, 0, 0.1` | `0.4998, 0, 0.1562` / `0.3968, 0, 0.0852` |
  | `wrist_2` | `0.1228, 0, −0.0286` / `0.0828, 0, 0.1` | `0.1923, 0, −0.0657` / `0.1498, 0, 0.1` |
  | `wrist_3` | `0.2765, 0, 0.0267` / `0.2378, 0, 0.1` | `0.2790, 0, −0.0392` / `0.2439, 0, 0.0916` |
</Accordion>

<h2 id="teleop">
  Teleop session
</h2>

How VR controller motion becomes arm motion.

| Flag | Default | Description |
| - | - | - |
| <F>--{prefix_1}rest\_pose\_left</F> | `[−0.157, 0, 0, 0.314, 0, 0, −0.157]` | Left arm rest pose (rad, 7 joints). The arms start here and return here on reset. Edit it visually in the control panel's **Rest pose** tab. |
| <F>--{prefix_1}rest\_pose\_right</F> | `[0.157, 0, 0, −0.314, 0, 0, 0.157]` | Right arm rest pose. |
| <F>--{prefix_1}frequency</F> | `120` | Motor command rate (Hz). Data collection sets this from `teleop_hz`. |
| <F>--{prefix_1}ik\_frequency</F> | `120` | How often VR poses are sent to the IK solver (Hz). The control loop interpolates between solutions. |
| <F>--{prefix_1}position\_multiplier</F> | `1.0` | Scales hand movement. `2` moves the arm twice as far as your hand. Ignored in `absolute_mode`. |
| <F>--{prefix_1}rotation\_multiplier</F> | `1.0` | Scales hand rotation the same way. Ignored in `absolute_mode`. |
| <F>--{prefix_1}hold\_to\_engage</F> | `false` | `false`: click both grips to engage, then click a grip to freeze or unfreeze that arm. `true`: each arm tracks only while its grip is held. |
| <F>--{prefix_1}disengage\_timeout</F> | `0.5` | Seconds without a VR frame before tracking disengages and the arms hold position. `0` disables. |
| <F>--{prefix_1}record</F> | `null` | Record every stage of the teleop pipeline to `~/.almond/recordings/<name>_*.npz` for [`motion.build`](/cli/motion-build) and [`diag.offline`](/cli/diag-offline). A bare name like `rec1` goes in that folder; a path is used as-is. |
| <F>--{prefix_1}reset\_speed</F> | `0.628` | Speed (rad/s) of the return-to-rest move. |
| <F>--{prefix_1}reset\_min\_duration</F> | `1.5` | Minimum duration (s) of a return-to-rest move. |
| <F>--{prefix_1}reset\_rest\_weight</F> | `50.0` | IK weight toward the rest pose when planning a return. |
| <F>--{prefix_1}reset\_limit\_weight</F> | `100.0` | IK weight against joint limits when planning a return. |
| <F>--{prefix_1}reset\_collision\_margin</F> | `0.025` | Minimum self-collision clearance (m) when planning a return. |
| <F>--{prefix_1}reset\_collision\_weight</F> | `100.0` | IK weight on self-collision when planning a return. |
| <F>--{prefix_1}reset\_max\_iterations</F> | `10` | IK iterations per return waypoint. |
| <F>--{prefix_1}reset\_torque\_threshold</F> | `6.0` | **Contact stop during return-to-rest** (Nm of unexpected torque). If the arm hits something, the move stops and the arms go limp; press reset to retry. `0` disables. Hardware only. |
| <F>--{prefix_1}teleop\_torque\_threshold</F> | `0` (off) | **Contact stop while tracking.** Same behaviour; a running episode is discarded. The control panel arms it at `16`. Hardware only. |
| <F>--{prefix_1}reset\_gravity\_comp\_kd</F> | `0.25` | Damping (Nm·s/rad) of the limp hold after a contact stop. |
| <F>--{prefix_1}engage\_max\_vel</F> | `0.628` | Joint speed cap (rad/s) right after engaging, so the first move is gentle. |
| <F>--{prefix_1}engage\_duration</F> | `1.0` | Seconds to ramp from `engage_max_vel` up to `teleop_max_vel`. |
| <F>--{prefix_1}teleop\_max\_vel</F> | `6.283` | Maximum joint speed (rad/s) while tracking. |
| <F>--{prefix_1}teleop\_max\_accel</F> | `21.99` | Maximum joint acceleration (rad/s²) while tracking. |
| <F>--{prefix_1}ik\_alpha</F> | `0.3` | Smoothing on the IK output, `(0, 1]`. `1` is no smoothing; lower is smoother but adds lag. See [Latency tuning](/operations/teleop#latency-tuning). |
| <F>--{prefix_1}pose\_cutoff</F> | `2.5` | Low-pass cutoff (Hz) on raw controller poses before IK. Lower rejects more hand tremor but adds lag. |
| <F>--{prefix_1}absolute\_mode</F> | `false` | Mantis mapping: track controller poses 1:1 in a fixed world frame instead of relative to where you engaged. Forced `true` by `--mantis`. |
| <F>--{prefix_1}base\_height</F> | `null` | In `absolute_mode`, fix the robot base this many metres above the VR floor instead of inferring it. Keeps datasets consistent across operators. |
| <F>--{prefix_1}tcp\_transform\_left</F> | `null` | *Mantis data collection.* Tracker → gripper transform `[x, y, z, qx, qy, qz, qw]` for the left rig. Normally read from the saved calibration; set to override. See [`tracker`](/cli/tracker#transform-file). |
| <F>--{prefix_1}tcp\_transform\_right</F> | `null` | *Mantis data collection.* Same for the right rig. |
| <F>--{prefix_1}tracker\_key</F> | `null` | *Mantis data collection, Quest.* Which saved calibration to use, e.g. `quest:oculus-touch-v3:grip`. Set from **Mantis settings** in the panel. |
| <F>--{prefix_1}quest\_controller\_profile</F> | `null` | *Mantis data collection, Quest.* Expected controller profile. Filled from `tracker_key`. |
| <F>--{prefix_1}quest\_pose\_space</F> | `null` | *Mantis data collection, Quest.* Expected pose datum, `grip` or `target-ray`. Filled from `tracker_key`. |
| <F>--{prefix_1}urdf\_viewer\_world\_aligned</F> | `null` | *Mantis data collection.* Whether the pose source shares the viewer headset's floor. `null` means `true` for Quest, `false` for Lighthouse/Ultimate. |

<Note>
  **Mantis mode** (`--mantis`) forces `absolute_mode: true`, `hold_to_engage: false`, `ik_alpha: 1.0`, `pose_cutoff: 5.0`, and removes the speed and acceleration limits. Your values for these keys are ignored in Mantis mode.
</Note>

<h2 id="kinematics">
  Kinematics
</h2>

The IK solver that turns hand targets into joint angles. A higher weight means the solver cares more about that term.

| Flag | Default | Description |
| - | - | - |
| <F>--{prefix_2}pos\_weight</F> | `50.0` | Weight on end-effector position error. |
| <F>--{prefix_2}ori\_weight</F> | `10.0` | Weight on end-effector orientation error. |
| <F>--{prefix_2}elbow\_weight</F> | `0` (off) | Weight on the headset's elbow-position hint. Off by default because the hint is unreliable on hardware. |
| <F>--{prefix_2}rest\_weight</F> | `15.0` | Damping toward the current pose. Higher is steadier, lower tracks faster. |
| <F>--{prefix_2}posture\_weight</F> | `5.0` | Pull toward the home posture, preventing slow drift. |
| <F>--{prefix_2}manipulability\_weight</F> | `0.05` | Keeps the arm away from singular poses. Forced `0` in Mantis mode. |
| <F>--{prefix_2}limit\_weight</F> | `75.0` | Penalty on joint-limit violations. |
| <F>--{prefix_2}self\_collision\_margin</F> | `0.025` | Distance (m) at which self-collision avoidance starts. Keep below the arm–torso clearance of normal poses. |
| <F>--{prefix_2}self\_collision\_weight</F> | `150.0` | Weight on self-collision avoidance. |
| <F>--{prefix_2}max\_iterations</F> | `8` | Solver iterations per IK call. |
| <F>--{prefix_2}cost\_tolerance</F> | `1e-4` | Convergence tolerance. Keep small. |
| <F>--{prefix_2}lambda\_initial</F> | `1e-2` | Initial Levenberg–Marquardt damping. |
| <F>--{prefix_2}lambda\_factor</F> | `10.0` | Damping multiplier after a rejected solver step. |
| <F>--{prefix_2}max\_joint\_delta</F> | `0.0346` | Largest joint change (rad) per IK call. Raise for faster tracking, lower for gentler motion. |
| <F>--{prefix_2}max\_reach</F> | `0.82` | Maximum shoulder-to-target distance (m). Targets beyond it are pulled in. |
| <F>--{prefix_2}reach\_soft\_start</F> | `0.78` | Distance (m) at which the reach limit starts to act. |
| <F>--{prefix_2}manip\_damping\_threshold</F> | `0.015` | Below this manipulability, extra damping kicks in (near full extension). |
| <F>--{prefix_2}manip\_damping\_boost</F> | `60.0` | Extra damping at zero manipulability. `0` disables. |
| <F>--{prefix_2}limit\_damping\_margin</F> | `0.12` | Distance (rad) from a joint limit inside which the joint is damped while moving toward it. |
| <F>--{prefix_2}elbow\_fade\_band</F> | `0.15` | Height (m) above the shoulder over which the elbow hint fades out. |

<Note>
  **Mantis mode** replaces any of these still at their default with `pos_weight 200`, `ori_weight 120`, `manipulability_weight 0`, `self_collision_margin 0.02`, `max_joint_delta 0.05`, `max_iterations 12`. A value you set explicitly still wins.
</Note>

<h2 id="vr-server">
  VR server
</h2>

The connection the headset streams poses over.

| Flag | Default | Description |
| - | - | - |
| <F>--{prefix_3}port</F> | `8000` | Port the headset connects to. [Quest-over-USB](/guides/quest-over-usb) uses the same port. |
| <F>--{prefix_3}certfile</F> | `null` | TLS certificate. `null` uses the auto-generated one in `~/.almond/vr/certs/`. |
| <F>--{prefix_3}keyfile</F> | `null` | TLS private key. `null` as above. |
| <F>--{prefix_3}interp\_enabled</F> | `true` | Smooth out jittery or batched pose arrivals. `false` uses the latest raw frame. |
| <F>--{prefix_3}interp\_min\_delay\_s</F> | `0` | Minimum playout delay (s). |
| <F>--{prefix_3}interp\_max\_delay\_s</F> | `0.15` | Maximum playout delay (s) spent absorbing network jitter. |
| <F>--{prefix_3}interp\_smooth\_window\_s</F> | `0.12` | Smoothing window (s). Adds about half of it as latency. `0` disables. See [Latency tuning](/operations/teleop#latency-tuning). |
| <F>--{prefix_3}interp\_outlier\_k</F> | `4.0` | Glitch-rejection threshold. Lower is more aggressive; `≤ 0` disables. |
| <F>--{prefix_3}interp\_max\_lag\_s</F> | `0.5` | Pose frames arriving more than this (s) later than normal are skipped, so the arms hold through a network stall instead of replaying it late. `≤ 0` disables. |
| <F>--{prefix_3}pose\_source\_kind</F> | `null` | Which pose source may drive: `webxr` (Quest), `tracker` (Lighthouse/Ultimate), or `null` for whichever connects first. Set automatically for Mantis. |
| <F>--{prefix_3}expected\_pose\_source\_id</F> | `null` | *Mantis data collection.* Exact pose-source ID accepted. Set automatically. |

<h2 id="jelly">
  Jelly
</h2>

The optional powered cart (x-drive base and telescoping lift), driven from the headset thumbsticks.

| Flag | Default | Description |
| - | - | - |
| <F>--{prefix_4}wheels</F> | `true` | Drive the wheels when their CAN interface is attached (thumbsticks drive the base). `false` leaves attached wheels cold. Jelly itself is never enabled by hand — it is inferred from the CAN devices present. |
| <F>--{prefix_4}channel</F> | `can_alm_axol_b` | CAN interface of the wheel motors. `null` means lift only. |
| <F>--{prefix_4}max\_speed</F> | `20.0` | Peak wheel speed (rad/s) at full stick. |
| <F>--{prefix_4}turn\_scale</F> | `1.0` | Rotation speed relative to driving speed, `[0, 1]`. |
| <F>--{prefix_4}slew</F> | `0.5` | Acceleration ramp. The default takes 2 s from rest to full speed. |
| <F>--{prefix_4}axis\_snap\_deg</F> | `15.0` | Stick directions within this many degrees of straight or sideways snap to exact. `0` disables. |
| <F>--{prefix_4}deadzone</F> | `0.15` | Thumbstick deadzone, as a fraction of full deflection. |
| <F>--{prefix_4}imu</F> | `false` | Use the board IMU to hold a straight heading. |
| <F>--{prefix_4}yaw\_hold\_gain</F> | `2.0` | Heading-hold strength. `0` disables. |
| <F>--{prefix_4}yaw\_hold\_max</F> | `0.3` | Maximum heading-hold correction. |
| <F>--{prefix_4}yaw\_log</F> | `false` | Log heading-hold data at 10 Hz, for diagnosing drift. |
| <F>--{prefix_4}hold\_kp</F> | `60.0` | Stiffness (Nm/rad) holding the wheels when parked. `0` leaves them idle. |
| <F>--{prefix_4}hold\_kd</F> | `1.5` | Damping (Nm·s/rad) of the parked hold. |
| <F>--{prefix_4}frequency</F> | `50.0` | Wheel command rate (Hz). |
| <F>--{prefix_4}command\_timeout</F> | `0.2` | Seconds without a stick command before Jelly stops. |
| <F>--{prefix_4}can\_timeout\_ms</F> | `200.0` | Motor-side loss-of-comms timeout (ms). Stops the wheels even if the host hangs. |
| <F>--{prefix_4}lift</F> | `true` | Run the lift when its CAN bus is attached (stick clicks). `false` leaves an attached lift cold. |
| <F>--{prefix_4}lift\_channel</F> | `null` (auto) | CAN interface of the lift controller. `null` picks the chest bus `can_alm_axol_c` when that interface exists, otherwise the wheel bus `can_alm_axol_b` the lift shares with the motors. |
| <F>--{prefix_4}lift\_speed</F> | `650` | Lift speed (encoder counts/s). |


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