LeRobot documentation

Policy Deployment (lerobot-rollout)

Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

Policy Deployment (lerobot-rollout)

lerobot-rollout is the single CLI for deploying trained policies on real robots. It supports multiple execution strategies and inference backends, from quick evaluation to continuous recording and human-in-the-loop data collection.

Quick Start

No extra dependencies are needed beyond your robot and policy extras.

lerobot-rollout \
    --strategy.type=base \
    --policy.path=lerobot/act_koch_real \
    --robot.type=koch_follower \
    --robot.port=/dev/ttyACM0 \
    --task="pick up cube" \
    --duration=30

This runs the policy for 30 seconds with no recording.


Strategies

Select a strategy with --strategy.type=<name>. Each strategy defines a different control loop with its own recording and interaction semantics.

Base ( --strategy.type=base )

Autonomous policy execution with no data recording. Use this for quick evaluation, demos, or when you only need to observe the robot.

lerobot-rollout \
    --strategy.type=base \
    --policy.path=${HF_USER}/my_policy \
    --robot.type=so100_follower \
    --robot.port=/dev/ttyACM0 \
    --robot.cameras="{ front: {type: opencv, index_or_path: 0, width: 640, height: 480, fps: 30}}" \
    --task="Put lego brick into the box" \
    --duration=60
FlagDescription
--durationRun time in seconds (0 = infinite)
--taskTask description passed to the policy
--display_dataStream observations/actions to Rerun for visualization

Sentry ( --strategy.type=sentry )

Continuous autonomous recording with periodic upload to the Hugging Face Hub. Episode boundaries are auto-computed from camera resolution and FPS so each saved episode produces a complete video file, keeping uploads efficient.

Policy state (hidden state, RTC queue) persists across episode boundaries: the robot does not reset between episodes.

lerobot-rollout \
    --strategy.type=sentry \
    --strategy.upload_every_n_episodes=5 \
    --policy.path=${HF_USER}/my_policy \
    --robot.type=so100_follower \
    --robot.port=/dev/ttyACM0 \
    --robot.cameras="{ front: {type: opencv, index_or_path: 0, width: 640, height: 480, fps: 30}}" \
    --dataset.repo_id=${HF_USER}/rollout_eval_data \
    --dataset.single_task="Put lego brick into the box" \
    --duration=3600
FlagDescription
--strategy.upload_every_n_episodesPush to Hub every N episodes (default: 5)
--strategy.target_video_file_size_mbTarget video file size for episode rotation (default: auto)
--dataset.repo_idRequired. Hub repository for the recorded dataset
--dataset.push_to_hubWhether to push to Hub on teardown (default: true)

Highlight ( --strategy.type=highlight )

Autonomous rollout with on-demand recording via a memory-bounded ring buffer. The robot runs continuously while the buffer captures the last N seconds of telemetry. Press the save key to flush the buffer and start live recording; press it again to save the episode.

lerobot-rollout \
    --strategy.type=highlight \
    --strategy.ring_buffer_seconds=30 \
    --strategy.save_key=s \
    --strategy.push_key=h \
    --policy.path=${HF_USER}/my_policy \
    --robot.type=koch_follower \
    --robot.port=/dev/ttyACM0 \
    --dataset.repo_id=${HF_USER}/rollout_highlight_data \
    --dataset.single_task="Pick up the red cube"

Keyboard controls:

KeyAction
s (configurable)Start recording (flushes buffer) / stop and save episode
h (configurable)Push dataset to Hub
ESCStop the session
FlagDescription
--strategy.ring_buffer_secondsDuration of buffered telemetry (default: 30)
--strategy.ring_buffer_max_memory_mbMemory cap for the ring buffer (default: 2048)
--strategy.save_keyKey to toggle recording (default: s)
--strategy.push_keyKey to push to Hub (default: h)

DAgger ( --strategy.type=dagger )

Human-in-the-loop data collection. Alternates between autonomous policy execution and human intervention via a teleoperator. Intervention frames are tagged with intervention=True. Requires a teleoperator (--teleop.type).

See the Human-In-the-Loop Data Collection guide for a detailed walkthrough.

Corrections-only mode (default): Only human correction windows are recorded. Each correction becomes one episode.

lerobot-rollout \
    --strategy.type=dagger \
    --strategy.num_episodes=20 \
    --policy.path=outputs/pretrain/checkpoints/last/pretrained_model \
    --robot.type=bi_openarm_follower \
    --teleop.type=bi_openarm_mini \
    --dataset.repo_id=${HF_USER}/rollout_hil_data \
    --dataset.single_task="Fold the T-shirt"

Continuous recording mode (--strategy.record_autonomous=true): Both autonomous and correction frames are recorded with time-based episode rotation (same as Sentry).

lerobot-rollout \
    --strategy.type=dagger \
    --strategy.record_autonomous=true \
    --strategy.num_episodes=50 \
    --policy.path=${HF_USER}/my_policy \
    --robot.type=so100_follower \
    --robot.port=/dev/ttyACM0 \
    --teleop.type=so101_leader \
    --teleop.port=/dev/ttyACM1 \
    --dataset.repo_id=${HF_USER}/rollout_dagger_data \
    --dataset.single_task="Grasp the block"

Keyboard controls (default input device):

KeyAction
SpacePause / resume policy execution
TabStart / stop human correction
EnterPush dataset to Hub (corrections-only mode)
ESCStop the session

Foot pedal input is also supported via --strategy.input_device=pedal. Configure pedal codes with --strategy.pedal.* flags.

FlagDescription
--strategy.num_episodesNumber of correction episodes to record (default: 10)
--strategy.record_autonomousRecord autonomous frames too (default: false)
--strategy.upload_every_n_episodesPush to Hub every N episodes (default: 5)
--strategy.input_deviceInput device: keyboard or pedal (default: keyboard)
--teleop.typeRequired. Teleoperator type

Episodic ( --strategy.type=episodic )

Episode-oriented recording that mirrors the behavior of lerobot-record. The policy drives the robot for each episode; an optional teleoperator can drive the robot during the reset phase between episodes.

lerobot-rollout \
    --strategy.type=episodic \
    --policy.path=${HF_USER}/my_policy \
    --robot.type=so100_follower \
    --robot.port=/dev/ttyACM0 \
    --teleop.type=so100_leader \
    --teleop.port=/dev/ttyACM1 \
    --dataset.repo_id=${HF_USER}/my_eval_data \
    --dataset.num_episodes=20 \
    --dataset.episode_time_s=30 \
    --dataset.reset_time_s=10 \
    --dataset.single_task="Pick up the red cube"

Teleop is optional — if omitted the robot holds its position during the reset phase.

Keyboard controls:

KeyAction
(right)End the current episode early
(left)Discard episode and re-record it
ESCStop the recording session
FlagDescription
--dataset.num_episodesNumber of episodes to record
--dataset.episode_time_sDuration of each recording episode in seconds
--dataset.reset_time_sDuration of the reset phase between episodes in seconds
--teleop.typeOptional. Teleoperator to drive the robot during resets
--strategy.reset_to_initial_positionWhether to reset the robot to its initial position between episodes
--strategy.smooth_leader_to_follower_handoverWhether to turn on or off the leader -> follower smooth handover behavior.

Inference Backends

Select a backend with --inference.type=<name>. All strategies work with both backends.

Sync (default)

One policy call per control tick. The main loop blocks until the action is computed.

Works with all policies. No extra flags needed.

Real-Time Chunking ( --inference.type=rtc )

A background thread produces action chunks asynchronously. The main control loop polls for the next ready action while the policy computes the next chunk in parallel.

Use RTC with large, slow VLA models (Pi0, Pi0.5, SmolVLA) for smooth, continuous motion despite high inference latency.

lerobot-rollout \
    --strategy.type=base \
    --inference.type=rtc \
    --inference.rtc.execution_horizon=10 \
    --inference.rtc.max_guidance_weight=10.0 \
    --policy.path=${HF_USER}/pi0_policy \
    --robot.type=so100_follower \
    --robot.port=/dev/ttyACM0 \
    --robot.cameras="{ front: {type: opencv, index_or_path: 0, width: 640, height: 480, fps: 30}}" \
    --task="Pick up the cube" \
    --duration=60 \
    --device=cuda
FlagDescription
--inference.rtc.execution_horizonSteps to blend with previous chunk (default: varies by policy)
--inference.rtc.max_guidance_weightConsistency enforcement strength (default: varies by policy)
--inference.rtc.prefix_attention_scheduleBlend schedule: LINEAR, EXP, ONES, ZEROS
--inference.queue_thresholdMax queue size before backpressure (default: 30)

See the Real-Time Chunking guide for details on tuning RTC parameters.


Common Flags

FlagDescriptionDefault
--policy.pathRequired. HF Hub model ID or local checkpoint path
--robot.typeRequired. Robot type (e.g. so100_follower, koch_follower)
--robot.portSerial port for the robot
--robot.camerasCamera configuration (JSON dict)
--fpsControl loop frequency30
--durationRun time in seconds (0 = infinite)0
--deviceTorch device (cpu, cuda, mps)auto
--taskTask description (used when no dataset is provided)
--display_dataStream telemetry to Rerun visualizationfalse
--display_ip / --display_portRemote Rerun server address
--interpolation_multiplierAction interpolation factor1
--use_torch_compileEnable torch.compile for inferencefalse
--resumeResume a previous recording sessionfalse
--play_soundsVocal synthesis for eventstrue

Programmatic Usage

For custom deployments (e.g. with kinematics processors), use the rollout module API directly:

from lerobot.rollout import BaseStrategyConfig, RolloutConfig, build_rollout_context
from lerobot.rollout.inference import SyncInferenceConfig
from lerobot.rollout.strategies import BaseStrategy
from lerobot.utils.process import ProcessSignalHandler

cfg = RolloutConfig(
    robot=my_robot_config,
    policy=my_policy_config,
    strategy=BaseStrategyConfig(),
    inference=SyncInferenceConfig(),
    fps=30,
    duration=60,
    task="my task",
)

signal_handler = ProcessSignalHandler(use_threads=True)
ctx = build_rollout_context(
    cfg,
    signal_handler.shutdown_event,
    robot_action_processor=my_custom_action_processor,       # optional
    robot_observation_processor=my_custom_obs_processor,     # optional
)

strategy = BaseStrategy(cfg.strategy)
try:
    strategy.setup(ctx)
    strategy.run(ctx)
finally:
    strategy.teardown(ctx)

See examples/so100_to_so100_EE/rollout.py and examples/phone_to_so100/rollout.py for full examples with kinematics processors.

Update on GitHub