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=false

32.2 Every flag explained

FlagValue on zeusWhat it doesIf it’s wrong or missing
--strategy.typebaseWhat the run does: base = run the policy, record nothing. Others in §37, §38.Default is base.
--policy.pathabsolute path to …/pretrained_model, or a Hub idWhich trained policy to load (weights + settings + normalisation stats).Missing: --policy.path is required for rollout. Wrong folder: Hub “not found” style error.
--robot.typebi_openarm_followerThe two-arm OpenArm follower.Must match the policy’s 16-value state/action.
--robot.idmy_bimanual_followerName 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.portcan0CAN interface of the left arm (zeus cabling, §22).Swapped with right: each arm gets the other arm’s commands.
--robot.right_arm_config.portcan1CAN interface of the right arm.As above.
--robot.left_arm_config.side / right_…sideleft / rightSelects 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_target10.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.camerascopied from the recording commandCameras, by name. Becomes observation.images.<name>.Name/resolution mismatch: start-up error. Swapped devices: silently wrong.
--taskthe training task sentenceInstruction text. Ignored by ACT/Diffusion, essential for SmolVLA/Pi0.VLAs: wrong behaviour.
--fpsthe dataset’s fps (30)Loop rate: one policy action per tick.Mismatch: motions play too fast or too slow.
--duration30 for first runsSeconds of policy control, then the run ends by itself (§33.3). 0 = until Ctrl+C.Default is 0 = forever. Always set it at first.
--devicecudaRun the network on the GPU.Omitted: taken from the checkpoint’s config.json, else auto-picked. cpu works but is slow.
--display_datafalseLive 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

FlagDefaultWhen to change it
--interactivefalsetrue 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_positiontruefalse leaves the arms where they are at the end; they then go limp there. Keep true.
--interpolation_multiplier12–3 for smoother motor commands (§36.3).
--policy.n_action_steps, --policy.temporal_ensemble_coefffrom the checkpointChange 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.typesyncrtc for slow VLA models (§40).
--use_torch_compilefalseFaster 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_soundstrueLeRobot 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_portrerunOnly with --display_data=true. foxglove is the alternative viewer.
--robot.*_arm_config.use_velocity_and_torquefalseMust equal what was used for recording.
--robot.*_arm_config.disable_torque_on_disconnecttrueKeep 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, not 10: 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.

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.