Skip to main content
The one-command install is the right path for running Axol on the robot machine. This page is for working on Axol itself — installing from a clone, picking optional dependency extras, and building the web UI locally. If you just want to use the robot, you don’t need any of this.

Install from a clone

Install the package from a checkout using uv — every dependency resolves from PyPI (kinematics comes through our published forks, almond-pyroki and almond-jaxls):
Then activate the virtual environment so the axol CLI is on your path:
You need to activate the environment in every new shell session. Alternatively, prefix every command with uv run (e.g. uv run axol can.setup) to skip activation.

Optional extras

Install optional dependency groups as needed (the install script includes lerobot, sim, and tracker):
PyPI’s torch==2.10.0 wheel is CPU-only on aarch64. On a Jetson, an exact uv sync also replaces an out-of-band Torch build with that locked CPU wheel. If local policy inference needs CUDA, manage a JetPack-compatible Torch + Torchvision build explicitly after dependency sync, and do not exact-sync that deployed environment again without a restoration plan. Remote inference and --device cpu work with the hosted dependency set.
Streaming the ZED camera feeds to the headset (teleop --cameras, collect-data) isn’t a dependency extra — it needs the system GStreamer + camera stack, installed via axol provision (see Headset-video stack below).

ZED Python bindings

The ZED Python bindings (pyzed) are not on PyPI and must be installed separately, after the ZED SDK is installed:
See zed.install for details.

Headset-video stack

Relaying the ZED cameras to the headset grabs and NVENC-encodes frames on the GPU via the zed-gstreamer pipeline (zedxonesrc / zedsrc) and sends them over WebRTC with aiortc (a normal Python dependency). The encode path needs the system GStreamer + GObject-introspection packages, PyGObject, and the patched ZED source elements — none of which are PyPI extras. axol provision installs all of them idempotently in one step (the same command the install script and the axol serve self-updater run):
This runs the Quest-over-USB adb setup, the zed.driver GMSL camera-driver upgrade (ZED Box Duo / Mini, ZED Link Duo on an AGX Orin), the board-IMU group access (gyro.install, Jelly’s heading-hold yaw source), zed.install, gst.install, and gst.build-zed in order; each self-gates and no-ops off the target hardware (no ZED SDK / apt / Stereolabs camera driver / board IMU). You can also run them individually. Its last step applies the host’s real-time tuning: on a Jetson (Orin NX, AGX Orin, Thor) it selects the max power mode, pins the NVENC/VIC/GPU and CPU clocks, steers the CAN adapters’ interrupt onto a CAN core, and schedules the Argus camera daemon real-time — see jetson.setup for each. It’s a no-op on other hosts. The tuning resets at reboot; the install script’s systemd unit re-applies it at every boot with axol provision --boot, and on a dev checkout without that unit you can run the same command after a reboot.

First-run hardware setup

Before using any motor or robot commands, initialize the CAN hardware once:
sudo is invoked automatically where required. See can.setup for what it configures — including the hotplug service that brings the interfaces back up on its own after a mid-session replug — and can.enable for re-running the bring-up manually.

Build the web UI

axol serve looks for the built web bundle at web/app/dist. To serve the control panel and VR interface from your own machine, build it once:
Then start the server and open the printed URL:
axol serve works without this step (the API is still available) — the hosted UI at axol.almond.bot connects to it directly. See serve and the Web Control Panel guide.

Next steps

CLI Reference

Every axol command, flag, and the draccus config model.

Python API

Axol, the kinematics solver, VR teleop, and the LeRobot wrappers.