Skip to main content
LeRobot-compatible wrappers for the Axol hardware. Requires the lerobot extra. These classes implement the LeRobot Robot, Teleoperator, and Camera interfaces so the Axol works with any LeRobot training or data-collection pipeline without modification. The collect-data and run-policy CLI commands are built on top of this layer.
Treat policy checkpoints and existing LeRobot datasets as trusted input. The pinned upstream runtime parses dataset metadata and deserializes model files; it is not a sandbox for arbitrary Hub repositories or directories supplied by someone else. Only load artifacts you created or obtained from a source you trust, especially on a machine connected to robot hardware.

Use with the stock LeRobot CLIs

almond-axol is published to PyPI, and the companion lerobot_robot_axol plugin registers these wrappers through LeRobot’s plugin auto-discovery — so the stock LeRobot CLIs (lerobot-teleoperate, lerobot-record, lerobot-replay, …) drive the Axol with no changes to LeRobot itself. Installing the plugin pulls in almond-axol[lerobot]; then select the devices by type:
Teleoperation still uses the VR headset — open the VR app and connect to the robot machine. For the highest-rate data collection (out-of-process ZED capture, on-Jetson NVENC dataset encoding, headset video streaming), prefer the SDK’s own collect-data / run-policy, which are built on these same classes.
Requires the pinned LeRobot 0.6.1 release, Linux, and Python 3.12+ (the hosted installer bundles 3.13) on the robot machine; the zed camera additionally needs pyzed (zed.install). See the plugin README for adding it to an existing one-command-install axol environment.
When installed from PyPI into the hosted Axol environment, the plugin’s exact version is preserved automatically across installer/control-panel Axol updates. A direct, VCS, or otherwise customized plugin install instead blocks the hosted force update before mutation; update that deployment manually with an explicit plan for the same source.

AxolRobot

LeRobot Robot wrapping the async Axol hardware driver. A background thread runs a dedicated asyncio event loop so motor telemetry keeps streaming while the synchronous get_observation() and send_action() calls block on the calling thread.

AxolRobotConfig fields

Key methods

AxolVRTeleop

LeRobot Teleoperator wrapping VRTeleop. Runs the VR WebSocket server and IK subprocess on a background thread so get_action() is non-blocking and safe to call from any thread.

AxolVRTeleopConfig fields

Key methods

ZedCamera

LeRobot Camera for a locally attached ZED camera. Opens the camera by serial number via the ZED SDK and grabs frames in a background thread. Requires pyzed (zed.install).
Each grabbed frame carries two timestamps on the local perf_counter clock: capture_perf_ts (when the sensor exposed the frame, derived from TIME_REFERENCE.IMAGE) and receive_perf_ts (when this process retrieved it). Since capture is local, both live on the same clock — no cross-machine sync needed. The retrieve-vs-capture skew is sampled on connect() and a warning is logged if the mean falls outside the expected range.

ZedStereoCamera

Wrapper for a stereo ZED X. Opens one SDK connection and, on every grab, retrieves both eyes — so the camera is grabbed once. The eyes are exposed as left_view / right_view, which present the same read API as ZedCamera so the rest of the pipeline can treat them as ordinary cameras.
When an AxolRobot camera config has stereo=True, the observation keys depend on eyes (see AxolRobotConfig.observation_cameras()): "both" expands camera X into X_left / X_right (the head camera records both eyes in the dataset), while "left" / "right" exposes a single eye under the plain name X — indistinguishable downstream from a mono camera (the wrist convention). Stereo is auto-promoted from the serial by AxolRobotConfig.apply_detected_stereo()collect-data / run-policy call it so a stereo ZED X opens correctly without setting stereo by hand.

ZedCameraConfig fields