Skip to main content
Records teleoperation episodes using VR controller inputs and three ZED cameras. Saves to a LeRobot-format dataset. Loops until Ctrl+C.
Data collection runs across two machines (main host + ZED box). For the end-to-end two-machine workflow, see the Data Collection quickstart.
This command is configured via draccus. The robot and teleop subsystems are exposed as the nested robot_config / teleop_config configs (camera streams, per-joint gains, IK, VR server) — nest into them with dots or pass a whole-config file. See Command configuration.
FlagDescription
--repo_id <user>/<dataset>HuggingFace dataset repo ID (required)
--task TEXTNatural language task description (required)
--fps INTDataset recording frame rate — camera frames captured at this rate (default: 60)
--teleop_hz INTMotor command rate in Hz; decoupled from --fps for smooth control (default: 120)
--root PATHLocal dataset root (default: $HF_LEROBOT_HOME)
--push_to_hub truePush to HuggingFace Hub when done
--robot_config.zed_host IPShared IP of the ZED streamer for all three cameras (cameras use ports 30000/30002/30004). Override a single camera with --robot_config.cameras.<name>.host IP (<name>overhead/left_arm/right_arm).
--robot_config.cameras.overhead.stereo trueThe overhead is a stereo ZED X (streamed with zed.stream --overhead-stereo). The dataset then records two observation keys, overhead_left and overhead_right, backed by a single decoded stream.
--robot_config.axol_config.<side>.gripper.torque_limit FLOATMax torque (Nm) for a gripper in POSITION_FORCE mode (default: 0.5); <side> is left/right
--robot_config.axol_config.left_stiffness SCompliance↔stiffness blend for the left arm in [0, 1]. Scalar or 7-element list (one per arm joint, in Joint enum order). 0 = fully compliant; 1 = pre-tuning industrial gains; 0.5 (default) is the geometric mean. Use right_stiffness for the right arm. See AxolConfig.left_stiffness.
--teleop_config.vr_teleop_config.position_multiplier FLOATScale factor on hand position (not orientation): the end-effector target moves this many times as far as your hand. 1.0 (default) is 1:1; 2.0 moves the arm twice as far, helping cover the robot’s full reach when the arm is longer than the operator’s.
--teleop_config.vr_teleop_config.rotation_multiplier FLOATScale factor on hand orientation (not position): the end-effector target rotates this many times as far as your wrist. 1.0 (default) is 1:1; 2.0 rotates the arm twice as far.
--rerun_ip IPIP of a Rerun viewer on your local machine for live visualization
--rerun_port INTRerun viewer port (default: 9876); only used when --rerun_ip is set
--log_level {DEBUG,INFO,WARNING,ERROR}Default: INFO
--config_path PATHLoad a whole-config JSON/YAML file; CLI overrides layer on top.
axol collect-data --repo_id myorg/pick-place --task "Pick the red cube and place it in the bin"
axol collect-data --repo_id myorg/pick-place --task "Pick the red cube" --fps 30 \
    --robot_config.zed_host 192.168.1.42
axol collect-data --repo_id myorg/pick-place --task "Pick the red cube" \
    --robot_config.axol_config.left_stiffness 1.0 --robot_config.axol_config.right_stiffness 1.0

Headset camera views

During collection the camera feeds are also relayed to the headset over WebRTC (requires the video extra), so the operator sees the overhead and wrist views while recording — switched with the right thumbstick, same as teleop. See the VR Interface guide.

VR controller controls

Episodes are driven from the Quest controllers. For the full controller layout and step-by-step flow, see the Data Collection quickstart.
ButtonAction
BToggle between Teleop and Data Collection mode (recording is only armed in Data Collection)
AStart a take (3-second countdown), or stop and save the current take. The headset enters Saving until the write completes
XDuring a recording, stop and discard the take (re-record); otherwise reset to the rest pose
After each episode the robot automatically returns to its rest pose before the next take begins. If an existing dataset is found at --root, collection resumes from where it left off; conversely, if no episodes were saved before exit the empty dataset directory is removed on shutdown so an aborted session does not leave a half-initialized dataset on disk.
Dataset frame capture runs on a dedicated thread decoupled from the teleop control loop. Teleop ticks at --teleop_hz and only ever touches joint state; the capture thread ticks at --fps, blocks on ZedCamera.read_at_or_after(T_n) per camera so every recorded frame is sender-clock-aligned with the joint sample taken at T_n, and writes the dataset row. This keeps camera reads, image conversion, and dataset.add_frame() off the hot control loop, and produces datasets whose camera/joint pairing matches the sender’s exposure timeline rather than the receiver’s decode timeline. Both clocks must agree — make sure zed.sync-clocks is running on both machines.