Part II: Teleoperation and data collection · §24 of 43
24.1 Record a dataset
lerobot-record \
--robot.type=bi_openarm_follower \
--robot.left_arm_config.port=can0 --robot.left_arm_config.side=left --robot.left_arm_config.max_relative_target=5.0 \
--robot.right_arm_config.port=can1 --robot.right_arm_config.side=right --robot.right_arm_config.max_relative_target=5.0 \
--robot.id=my_bimanual_follower \
--robot.cameras='{top: {type: opencv, index_or_path: /dev/video0, width: 640, height: 480, fps: 30}}' \
--teleop.type=bi_openarm_mini \
--teleop.left_arm_config.port=/dev/serial/by-id/usb-1a86_USB_Single_Serial_5876043720-if00 --teleop.left_arm_config.side=left \
--teleop.right_arm_config.port=/dev/serial/by-id/usb-1a86_USB_Single_Serial_5876043592-if00 --teleop.right_arm_config.side=right \
--teleop.id=my_mini \
--dataset.repo_id=<hf_user>/openarm_pick_cube \
--dataset.single_task="Pick up the red cube and place it in the bowl" \
--dataset.num_episodes=20 \
--dataset.episode_time_s=60 --dataset.reset_time_s=20 \
--dataset.fps=30 \
--dataset.no_stamp=true \
--dataset.push_to_hub=false \
--display_data=falseDataset names (new in V3)
- Without
--dataset.no_stamp=true,lerobot-recordappends a date-time tag to the name:<hf_user>/openarm_pick_cubebecomes<hf_user>/openarm_pick_cube_20261010_143000. Every later command (lerobot-train,lerobot-dataset-viz,--resume) then needs that full name.ls ~/.cache/huggingface/lerobot/<hf_user>/shows the real names. Withno_stamp, the name stays as typed. To add episodes to it later, add--resume=true.- Names starting with
eval_are refused bylerobot-record(“reserved for policy evaluation”). Policy evaluation is done withlerobot-rolloutand needs names starting withrollout_(§37).
Recording uses stock LeRobot, so it has the start-up snap behaviour described in §23.3 (
safe_teleop.pydoesn’t record). Before everylerobot-record: runcompare_mini_follower.py, put the Minis in the followers’ pose (all diffs ≈ 0), keepmax_relative_target, and keep--display_data=false. A recording mode forsafe_teleop.py(gate first, then hand over to LeRobot’s dataset writer) is the obvious next improvement.
The docs page you pasted uses short flags (--repo-id, --num-episodes, --fps). The v0.6.2 CLI expects the --dataset.* names above.
- Data goes to
~/.cache/huggingface/lerobot/<repo_id>/(override with--dataset.root=…): parquet for joint data, mp4 per camera. - Keyboard during recording (needs an X session;
pynput): → ends the episode early, ← re-records it, Esc stops. --resume=trueappends to an existing dataset.--dataset.push_to_hub=trueuploads (needshf auth login).- Recorded observation = follower joint positions in degrees (+ images). Action = the (clipped) command sent to the follower, i.e. the leader’s pose.
24.2 Inspect / replay
lerobot-dataset-viz --repo-id <hf_user>/openarm_pick_cube --episode-index 0 # Rerun viewer
lerobot-replay --robot.type=bi_openarm_follower … --dataset.repo_id=<hf_user>/openarm_pick_cube --dataset.episode=0lerobot-replay drives the real follower through the recorded actions. Same safety rules as teleop: start pose matched, max_relative_target set.
24.3 Train a policy (on the RTX 5050 or a bigger machine)
lerobot-train \
--dataset.repo_id=<hf_user>/openarm_pick_cube \
--policy.type=act \
--output_dir=outputs/train/act_openarm_pick_cube \
--job_name=act_openarm_pick_cube \
--policy.device=cuda \
--policy.push_to_hub=falseACT is a good first policy for ~20–50 demos. Diffusion, SmolVLA and Pi0 need their extras and much more GPU memory. An 8 GB laptop GPU is tight for anything beyond ACT/Diffusion with small batch sizes.
The trained model ends up in outputs/train/act_openarm_pick_cube/checkpoints/last/pretrained_model/ (relative to
where you ran lerobot-train). That directory is what --policy.path points to in Part III (§31.2). It contains the
weights, the policy config (which inputs it expects) and the normalisation statistics of the training dataset.
--policy.push_to_hub=true --policy.repo_id=<hf_user>/act_openarm_pick_cube uploads it so you can use --policy.path=<hf_user>/act_openarm_pick_cube instead.
24.4 Which policy to train
| Policy | --policy.type | Extra to install | Inference on zeus (RTX 5050, 8 GB) | Notes |
|---|---|---|---|---|
| ACT | act | none | ✅ fast, --inference.type=sync | Best first choice: 20–50 demos of one task |
| Diffusion | diffusion | pip install -e ".[diffusion]" | ✅ slower per call | Smoother, multimodal behaviour; needs more demos |
| SmolVLA | smolvla | pip install -e ".[smolvla]" | ⚠ probably fits; use RTC | Language-conditioned (--task matters); fine-tune from lerobot/smolvla_base |
| Pi0 / Pi0.5 | pi0 / pi05 | pip install -e ".[pi]" | ❌ too big for 8 GB, use a bigger GPU + async inference (§40) | Strongest generalist VLAs |
Install extras inside the lerobot env, in ~/Documents/lerobot. The training command (§24.3) is the same apart from
--policy.type (VLAs: --policy.path=lerobot/smolvla_base to fine-tune instead of --policy.type).
24.5 Running the trained policy
Running a policy on the arms has its own part, written for a first-time user: Part III.
| You want to… | Go to |
|---|---|
| Understand what running a policy means, and the vocabulary | §30 |
| Find the trained model, check what it expects, find the training start pose | §31 |
Understand every flag of lerobot-rollout (+ a ready-made script) | §32 |
| Know what happens, and when the arms move | §33 |
| Run it the first time, safely | §34, §35 |
| Make it smoother or more reactive | §36 |
| Measure the success rate | §37 |
| Correct it with the Minis (DAgger) | §38 |
| Fix an error | §41 |