Skip to main content

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.

Policy inference runs across two machines on the same network, exactly like data collection:
  • Main host (the upper computer) — runs the policy server and the autonomous control loop.
  • ZED box (the Jetson sender) — streams the three ZED-X One cameras.
Both machines must agree on the time (via PTP) so the camera observations fed to the policy are aligned with the joint state. Each machine runs two long-lived processes, each in its own terminal, that stay up for the entire rollout session.
Start the clock-sync daemon on both machines before launching run-policy. If PTP isn’t running, the receiver’s capture/decode skew check in ZedCamera.connect() warns and the observations sent to the policy will not be time-aligned with joint state. See zed.sync-clocks.

Network setup

The two machines must be able to reach each other over the network. Pick the topology that matches your wiring — it determines whether you let axol assign static IPs or you point it at an existing address. This is the same setup as the Data Collection quickstart.
A single cable between the two NICs, no router in between. Neither machine gets a DHCP address on that link, so axol assigns static IPs for you: the ZED box takes 192.168.10.1 (via --setup-ip) and the main host takes 192.168.10.2 (via --zed_iface). The receiver’s default zed_host is already 192.168.10.1, so no IP flag is needed on run-policy.
Interface names vary by machine — the link might be eth0, enp3s0, eno1, and so on. Run ip link (or ip addr) on each machine to find the interface carrying the link, and substitute it for <iface> in the commands below. In both cases PTP runs over whichever interface carries the link (zed.sync-clocks --iface). If the two machines are not on the same L2 segment (e.g. separated by a router rather than a switch), add --transport udpv4 to the clock-sync commands.

Prerequisites

  • The lerobot extra installed on the main host. For GPU inference also add the cuda extra: uv sync --extra lerobot --extra cuda (see Installation).
  • A trained checkpoint (local path or HuggingFace repo) and its policy type (act, smolvla, pi0, …).
  • CAN set up on the main host (can.setup) and motors verified (motor.info).
  • pyzed installed on the ZED box (zed.install) and the three camera serial numbers on hand.
  • A network link between the two machines — either a direct ethernet cable or a shared router/switch (see Network setup).

ZED box (Jetson)

Open two terminals on the ZED box.
1

Start clock sync (slave)

axol zed.sync-clocks --role slave --iface <iface>
Replace <iface> with the ZED box’s link interface (find it with ip link). Leave this running for the whole session.
2

Stream the cameras

axol zed.stream \
    --overhead 12345678 \
    --left-arm 23456789 \
    --right-arm 34567890 \
    --setup-ip <iface>
--setup-ip <iface> assigns the sender IP 192.168.10.1/24 to that interface before streaming.
Use the same --resolution and --fps the policy was trained on so the ZedCamera validation on the main host passes. See zed.stream.

Main host (upper computer)

Open two terminals on the main host.
1

Start clock sync (master)

axol zed.sync-clocks --role master --iface <iface>
Replace <iface> with the main host’s link interface (find it with ip link). Leave it running for the whole session.
2

Run the policy

axol run-policy \
    --policy_path myorg/pick-place-policy \
    --policy_type act \
    --task "Pick the red cube" \
    --zed_iface <iface>
--zed_iface <iface> assigns the receiver IP 192.168.10.2/24 to that interface; the cameras are reached at the default zed_host 192.168.10.1.
A PolicyServer child process is launched on localhost; the parent streams observations to it and applies the returned action chunks. --fps must match the rate the policy was trained on. For CPU inference add --device cpu. See run-policy for aggregation, chunking, and dataset-saving fields, and Command configuration for the draccus override syntax.

Controlling a rollout

While run-policy runs, control the episode from stdin in the run-policy terminal:
KeyAction
sSave the rollout and end the episode
rDiscard and re-record
qDiscard and quit
--episode_time_s is a safety cap (default 120 s) that falls back to the same [Enter]=save / r / q prompt if no key is pressed. If --repo_id is supplied, each saved episode is appended to a LeRobot-format dataset. Between episodes the arms return to the rest pose via a collision-aware IK trajectory.

Next steps

Data Collection

Record more episodes to improve the policy.

run-policy reference

Every flag, aggregation strategy, and threading detail.