.local) and local IP address are printed — enter either of these in the VR app at axol.almond.bot to connect.
Runs on the real robot by default; pass --sim for the browser visualizer. The full robot config is exposed via draccus, so every gain, stiffness, and gripper limit is reachable from the CLI or a config file — see Command configuration.
Network tip: If VR tracking feels jittery or packets arrive in bursts, configure the following on your router/access point:
- DTIM interval →
1 - Beacon interval →
100ms - WMM APSD (U-APSD) → disabled
Camera streaming to the headset
With--cameras set, teleop opens the locally attached ZED cameras by serial number and relays them to the headset over WebRTC, so the operator sees the robot’s cameras instead of (or alongside) passthrough. All streamed feeds show at once and can be moved and resized with the controllers — see the VR Interface guide for the layout and controls. Requires pyzed (zed.install) and the GStreamer NVENC stack (gst.install — the hosted installer runs it).
Teleop and collect-data share one GPU-resident video path (almond_axol.video.gst_zed): the zed-gstreamer source elements (zedxonesrc mono / zedsrc stereo) grab and NVENC-encode (nvvidconv → nvv4l2h264enc) entirely on the GPU, and Python only ever sees the encoded H.264 access units — which aiortc forwards as pre-encoded packets (RTP/SRTP/ICE + SDP signaling), with no Python encode step. Teleop asks the cameras for 60 fps capture (falling back to the camera default when unsupported). Stereo ZED X cameras are auto-detected from their serial: a stereo overhead grabs both eyes on one pass and is relayed as a single side-by-side source, overhead_sbs (both eyes packed into one track — one decoder session on the headset), rendered per-lens, while a stereo wrist is relayed as a single source under its slot name (one feed, like a mono camera). When the gst stack is unavailable the path falls back to the ZED SDK grab (ZedCamera) plus in-Python NVENC (almond_axol.video.hw_video), which streams the overhead as the two per-eye sources overhead_left / overhead_right instead.
The whole relay — camera grab/encode plus WebRTC sending — runs in a dedicated subprocess (almond_axol.video.video_proc), the same isolation pattern used for the IK solver: it keeps the camera pump off the teleop process so the control loops stay at full rate. Only SDP signaling crosses the process boundary.
For low-latency encode the NVENC/VIC engine clocks must be pinned to their maximum (the default Jetson devfreq governor scales them for throughput, not latency, which roughly triples per-frame encode time). This is handled by axol jetson.setup, run at boot by the installer’s systemd unit — not at teleop startup. If no GStreamer hardware encoder is present at all, aiortc falls back to software H.264 — SVGA is then the recommended resolution.
This command takes its config via draccus, not fixed
argparse flags. Field names use underscores, nested fields are dot-separated, None is null, and lists use [a,b,c] — see Command configuration for the full model.