Part III: Running a trained policy · §32 of 43
32.1 The complete command for zeus
This is the full command for a bimanual policy with one camera, with nothing left to defaults that matters for safety. Every line is explained in §32.2.
lerobot-rollout \
--strategy.type=base \
--policy.path=$HOME/Documents/lerobot/outputs/train/act_openarm_pick_cube/checkpoints/last/pretrained_model \
--robot.type=bi_openarm_follower \
--robot.id=my_bimanual_follower \
--robot.left_arm_config.port=can0 \
--robot.left_arm_config.side=left \
--robot.left_arm_config.max_relative_target=10.0 \
--robot.right_arm_config.port=can1 \
--robot.right_arm_config.side=right \
--robot.right_arm_config.max_relative_target=10.0 \
--robot.cameras='{top: {type: opencv, index_or_path: /dev/video0, width: 640, height: 480, fps: 30}}' \
--task="Pick up the red cube and place it in the bowl" \
--fps=30 \
--duration=30 \
--device=cuda \
--display_data=false32.2 Every flag explained
| Flag | Value on zeus | What it does | If it’s wrong or missing |
|---|---|---|---|
--strategy.type | base | What the run does: base = run the policy, record nothing. Others in §37, §38. | Default is base. |
--policy.path | absolute path to …/pretrained_model, or a Hub id | Which trained policy to load (weights + settings + normalisation stats). | Missing: --policy.path is required for rollout. Wrong folder: Hub “not found” style error. |
--robot.type | bi_openarm_follower | The two-arm OpenArm follower. | Must match the policy’s 16-value state/action. |
--robot.id | my_bimanual_follower | Name of the follower’s calibration files (…/openarm_follower/my_bimanual_follower_left.json / _right.json). | Missing or different = no file = LeRobot asks you to put the arms “hanging straight down” and re-zeroes all 16 motors (§21). The default id for this robot type is bi_openarm_follower, which has no files on zeus. If you see that prompt, Ctrl+C. |
--robot.left_arm_config.port | can0 | CAN interface of the left arm (zeus cabling, §22). | Swapped with right: each arm gets the other arm’s commands. |
--robot.right_arm_config.port | can1 | CAN interface of the right arm. | As above. |
--robot.left_arm_config.side / right_…side | left / right | Selects the per-side joint limits every command is clipped to (§20). | Missing: ±5° limits, the arms barely move. Swapped: joint_2 may swing into the torso. |
--robot.*_arm_config.max_relative_target | 10.0 (degrees) | Each command may move a joint at most this far from where it is now. At 30 fps, 10° per tick ≈ 300°/s, so it’s a guard against a single wild jump, not a speed limit. Write it with a decimal point. | Missing: no step limit at all. Too small (≤ 5): low-stiffness wrist joints stall short of their target (§23.3). See §36.4. |
--robot.cameras | copied from the recording command | Cameras, by name. Becomes observation.images.<name>. | Name/resolution mismatch: start-up error. Swapped devices: silently wrong. |
--task | the training task sentence | Instruction text. Ignored by ACT/Diffusion, essential for SmolVLA/Pi0. | VLAs: wrong behaviour. |
--fps | the dataset’s fps (30) | Loop rate: one policy action per tick. | Mismatch: motions play too fast or too slow. |
--duration | 30 for first runs | Seconds of policy control, then the run ends by itself (§33.3). 0 = until Ctrl+C. | Default is 0 = forever. Always set it at first. |
--device | cuda | Run the network on the GPU. | Omitted: taken from the checkpoint’s config.json, else auto-picked. cpu works but is slow. |
--display_data | false | Live Rerun viewer of joints and images. | true costs loop time and once froze the loop for 12.8 s on zeus (§26 item 11). |
32.3 Flags you can usually leave alone
| Flag | Default | When to change it |
|---|---|---|
--interactive | false | true to load everything and wait for you to type /start before anything moves. Recommended for the first runs (§35). Only with base (or sentry). |
--return_to_initial_position | true | false leaves the arms where they are at the end; they then go limp there. Keep true. |
--interpolation_multiplier | 1 | 2–3 for smoother motor commands (§36.3). |
--policy.n_action_steps, --policy.temporal_ensemble_coeff | from the checkpoint | Change how often ACT re-plans (§36.1, §36.2). Any --policy.<setting> overrides the value in config.json for this run only. |
--robot.*_arm_config.position_kp / position_kd | [240,240,240,240,24,31,25,25] / [5,5,3,5,0.3,0.3,0.3,0.3] | Softer arms (§36.5). |
--inference.type | sync | rtc for slow VLA models (§40). |
--use_torch_compile | false | Faster inference after a warm-up; not needed for ACT. |
--rename_map | {} | When the camera names differ between training and today: --rename_map='{"observation.images.cam_a": "observation.images.top"}'. |
--play_sounds | true | LeRobot speaks events aloud through spd-say (“Recording episode 3”, “Reset the environment”). Useful when you’re watching the arms, not the terminal. false to silence. |
--display_mode, --display_ip, --display_port | rerun | Only with --display_data=true. foxglove is the alternative viewer. |
--robot.*_arm_config.use_velocity_and_torque | false | Must equal what was used for recording. |
--robot.*_arm_config.disable_torque_on_disconnect | true | Keep true (otherwise the motors stay energised after the program exits, holding the last command with nobody supervising). |
lerobot-rollout --help lists every flag the installed version accepts.
32.4 Shell pitfalls when typing long commands
- The backslash
\must be the very last character of the line. A space after it ends the command there. The rest of the lines are then run as separate (failing) commands, and the robot runs with defaults for everything after the break. - No comments between continued lines. A
# …line in the middle ends the command. - Quote the cameras dict in single quotes
'{…}', and the task in double quotes"…". Inside the dict, keep the spaces after:and,as shown. max_relative_target=10.0, not10: LeRobot checks for a decimal number when it applies the limit. ⚠ verify that an integer is accepted; the decimal form is certainly fine.- Paste long commands from a file, not retyped. The script in §32.5 removes this whole class of mistakes.
32.5 A reusable script (recommended)
Put the parts that never change in a script, and keep what changes (policy, task, cameras, duration) as variables at the top. Create ~/Documents/openarm_lerobot/run_policy.sh with:
#!/usr/bin/env bash
# Run a trained LeRobot policy on the zeus bimanual OpenArm.
# Usage: bash run_policy.sh [extra lerobot-rollout flags, e.g. --interactive=true --duration=10]
set -euo pipefail
# ---- edit these per policy -------------------------------------------------
POLICY="$HOME/Documents/lerobot/outputs/train/act_openarm_pick_cube/checkpoints/last/pretrained_model"
TASK="Pick up the red cube and place it in the bowl"
CAMERAS='{top: {type: opencv, index_or_path: /dev/video0, width: 640, height: 480, fps: 30}}'
FPS=30
DURATION=30
MAX_STEP=10.0
# ---------------------------------------------------------------------------
command -v lerobot-rollout >/dev/null || { echo "lerobot-rollout not found: run 'conda activate lerobot' first"; exit 1; }
[ -f "$POLICY/config.json" ] || { echo "No config.json in $POLICY"; exit 1; }
lerobot-rollout \
--strategy.type=base \
--policy.path="$POLICY" \
--robot.type=bi_openarm_follower \
--robot.id=my_bimanual_follower \
--robot.left_arm_config.port=can0 --robot.left_arm_config.side=left --robot.left_arm_config.max_relative_target="$MAX_STEP" \
--robot.right_arm_config.port=can1 --robot.right_arm_config.side=right --robot.right_arm_config.max_relative_target="$MAX_STEP" \
--robot.cameras="$CAMERAS" \
--task="$TASK" \
--fps="$FPS" \
--duration="$DURATION" \
--device=cuda \
--display_data=false \
"$@"Flags added on the command line come last and override the ones in the script (e.g. bash run_policy.sh --duration=10 --interactive=true). ⚠ verify that a repeated flag takes the last value; if it doesn’t, remove --duration from the script and always pass it.