LeRobot documentation

策略部署(lerobot-rollout)

Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

策略部署(lerobot-rollout)

lerobot-rollout 是用于在真实机器人上部署已训练策略的统一命令行工具。它支持多种执行策略和推理后端,涵盖从快速评估到持续录制以及人在回路数据采集的多种场景。

快速入门

除了机器人和策略的额外依赖项之外,无需其他额外依赖项。

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

这会在不录制任何内容的情况下运行策略 30 秒。

选择设备

在目标主机上,如果该设备可用,请传入 --device=cpu 或 --device=cuda 以覆盖检查点设备。 解析后的设备会在加载策略并构建其处理器之前,应用于策略配置。 例如,如果策略支持 CPU 执行,可以在上述命令中添加 --device=cpu,以便在仅配备 CPU 的主机上运行使用 CUDA 训练的检查点。 在部署到机器人之前,请确认 CPU 推理能够满足所需的控制频率。

如果省略 --device,rollout 会使用策略配置中指定的设备(如果已设置),否则会自动选择一个可用设备。 RolloutConfig(device=...) 与 build_rollout_context 的行为与此相同。


策略

使用 --strategy.type=<name> 选择一种策略。每种策略都定义了不同的控制循环,并拥有各自的录制和交互语义。

基础(--strategy.type=base)

自主策略执行,不记录数据。适用于快速评估、演示或仅需观察机器人的场景。

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
标志描述默认
--duration运行时间(秒)(0 = 无限)0
--task传递给策略的任务描述—
--display_data将观察/操作流式传输到 Rerun 以进行可视化false

Sentry ( --strategy.type=sentry )

持续自主录制,并定期上传至 Hugging Face Hub。剧集边界会根据相机分辨率和 FPS 自动计算,确保每个保存的剧集都能生成完整的视频文件,从而保持上传的高效性。

策略状态(隐藏状态、RTC 队列)在 episode 边界之间持续存在:机器人在 episode 之间不会重置。

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
标志描述默认
--strategy.upload_every_n_episodes每 N 个回合推送到 Hub5
--strategy.target_video_file_size_mb用于剧集轮换的目标视频文件大小auto
--dataset.repo_id必填。 用于记录数据集的 Hub 仓库—
--dataset.push_to_hub是否在拆卸时推送到 Hubtrue

高亮(--strategy.type=highlight)

通过内存受限的环形缓冲区实现自主展开与按需录制。该缓冲区会捕获最近 N 秒的遥测数据。按下保存键以刷新缓冲区并开始实时录制;再次按下以保存该回合。在使用异步后端时,每次切换都会暂停推理,使已排队或插值的运动失效,并在阻塞式排空或保存之前请求受支持的本地保持。运行正常时,随后将从新的捕获中恢复。

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"

键盘控制:

密钥操作
s(可配置)开始录制(刷新缓冲区)/ 停止并保存剧集
h(可配置)将数据集推送到 Hub
ESC停止会话
标志描述
--strategy.ring_buffer_seconds缓冲遥测的持续时间(默认值:10)
--strategy.ring_buffer_max_memory_mb环形缓冲区的内存上限(默认值:1024)
--strategy.save_key切换录制的按键(默认:s)
--strategy.push_key用于推送到 Hub 的按键(默认:h)

DAgger(--strategy.type=dagger)

Human-in-the-loop 数据收集。在自主策略执行与通过遥操作器进行的人工干预之间交替进行。干预帧会被标记为 intervention=True。需要配置遥操作器(--teleop.type)。

有关详细操作指南,请参阅人机协同数据收集。

仅修正模式(默认):仅记录人工修正窗口。每次修正构成一个 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"

连续录制模式(--strategy.record_autonomous=true):自主帧和校正帧均会进行录制,并采用基于时间的 episode 轮换(与 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"

键盘控制(默认输入设备):

密钥操作
Space暂停 / 恢复策略执行
Tab开始 / 停止人工校正
Enter将数据集推送到 Hub(仅更正模式)
ESC停止会话

也支持通过 --strategy.input_device=pedal 使用脚踏板输入。使用 --strategy.pedal.* 标志配置踏板代码。

当机器人支持 rollout 位置保持时,暂停操作会刷新驱动程序实际应用的最后一个位置目标,包括其裁剪和夹爪目标。在第一条命令之前,经过验证的测量位姿将作为目标提供。这保留了命令位置误差,而不是将目标更改为测量位姿;在策略轨迹推进停止期间,机器人可以继续向该目标收敛。请在实际机器人上验证负载臂和夹爪的行为;此软件保持功能不保证保持抓握或物理静止。

标志描述
--strategy.num_episodes要记录的纠正回合数(默认值:--dataset.num_episodes)
--strategy.record_autonomous同时记录自主帧(默认:false)
--strategy.upload_every_n_episodes每 N 个回合推送到 Hub(默认值:5)
--strategy.input_device输入设备:keyboard 或 pedal(默认:keyboard)
--strategy.smooth_handover在暂停/校正开始时平滑地移交控制权(默认值:true)。对于在接合时以当前机器人位姿重新参考的离合器式遥操作,请禁用此功能
--teleop.type必填。 遥操作类型

情景式(--strategy.type=episodic)

采用以回合(episode)为导向的录制方式,其行为与 lerobot-record 保持一致。在每个回合中,策略驱动机器人;在回合之间的重置阶段,可选的遥操作者可以驱动机器人。

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}/rollout_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 是可选的——如果省略,机器人在重置阶段将保持当前位置。

键盘控制:

密钥操作
→(右)提前结束当前回合
←(左)丢弃该回合并重新录制
ESC停止录制会话
标志描述
--dataset.num_episodes要记录的剧集数量
--dataset.episode_time_s每个录制片段的持续时间(以秒为单位)。如果设置了--duration且未设置此项,则默认使用--duration的值。
--dataset.reset_time_s剧集之间重置阶段的持续时间(以秒为单位)
--teleop.type可选。在重置期间由遥操作员控制机器人
--strategy.reset_to_initial_position是否在回合之间将机器人重置到其初始位置
--strategy.smooth_leader_to_follower_handover是否开启或关闭领导者 -> 跟随者的平滑交接行为。
--strategy.smooth_handover在重置开始时平滑地将控制权移交给遥操作(默认值:true)。对于在接合时以当前机器人位姿重新参考的离合器式遥操作,请禁用此功能

自带策略

--strategy.type 接受环境中注册的任何策略,而不仅仅是上述内置策略。一个策略是 pip 可安装包中的两个类:一个注册在 RolloutStrategyConfig 上的配置,以及一个以其名称去掉 Config 后缀命名的 RolloutStrategy 子类——与 自定义硬件 相同的 SomethingConfig/Something 约定,从配置的模块或包中解析。

from dataclasses import dataclass
from typing import ClassVar

from lerobot.rollout import RolloutContext, RolloutStrategy, RolloutStrategyConfig


@RolloutStrategyConfig.register_subclass("patrol")
@dataclass
class PatrolStrategyConfig(RolloutStrategyConfig):
    dataset_mode: ClassVar[str] = "required"  # the engine creates the dataset for you
    legs: int = 2  # becomes --strategy.legs


class PatrolStrategy(RolloutStrategy):
    def run(self, ctx: RolloutContext) -> None:
        ...  # the paced control loop: see the contract on RolloutStrategy.run

    def teardown(self, ctx: RolloutContext) -> None:
        ctx.data.dataset.finalize()
        self._teardown_hardware(ctx.hardware, ctx.runtime.cfg.return_to_initial_position)

配置声明了引擎代表策略所安排的内容,因此 LeRobot 中的任何部分都无需了解其类型:

声明效果
dataset_mode"none"(默认值)会拒绝 --dataset.* 标志,"optional" 会在提供时记录它们,"required" 会使 --dataset.repo_id 成为必填项
requires_teleop使 --teleop.type 成为必填项
supports_interactive允许使用 --interactive=true;此时 run() 必须遵循 RolloutStrategy 中记录的可重启契约
supports_sim_robot允许使用 --robot.type=sim;此时 run() 必须在每个回合结束时启动一个新的回合(参见 lerobot.robots.sim_robot)
requires_streaming_encoding()当帧从控制循环内部写入时返回 True:--dataset.streaming_encoding 将被强制启用
extra_dataset_features()策略拥有的数据集列(例如 DAgger 的intervention);每个记录的帧都必须包含这些列

将分发命名为 lerobot_strategy_<name>,lerobot-rollout 会在解析 CLI 之前导入该包——此时仅执行其 __init__.py,因此请在此处导入配置。任何其他名称的包(包括其子模块)都会通过 --strategy.discover_packages_path=<package> 加载。策略的数据类字段会成为 --strategy.* 标志:

lerobot-rollout \
    --strategy.type=patrol \
    --strategy.legs=3 \
    --policy.path=${HF_USER}/my_policy \
    --robot.type=so100_follower \
    --robot.port=/dev/ttyACM0 \
    --dataset.repo_id=${HF_USER}/rollout_patrol \
    --dataset.single_task="patrol the aisle"

SentryStrategy(支持录制,交互安全)和 BaseStrategy(不录制)是可供参考的实现;lerobot.rollout.strategies 中的 send_next_action、safe_push_to_hub 和 estimate_max_episode_seconds 是它们所依赖的辅助函数。

对于异步后端,分发契约是强制性的。使用 engine.notify_observation(obs_processed) 发布每个捕获的观测值,在 每个自主电机节拍(包括插值和保持节拍)上调用 send_next_action(...),然后调用 engine.pump_query(obs_processed)。仅调用 engine.get_action() 会绕过权限和保持握手:计划中的文本查询可能会无限期等待,且终端故障可能永远不会发出关闭信号。

第三方策略可以调用 self._tick(timer, new_cycle=interpolator.needs_new_action()) 来替代 timer.tick(...),以便在 _init_engine(ctx) 之后包含定期健康报告。

send_next_action 基于 lerobot.inference.dispatch_tick 及其组成部分(next_interpolated_action、commit_action、dispatch_permitted)构建,这些部分一次性编码了该顺序:在拉取动作之前和之后,以及在发送之前调用 dispatch_allowed();当被拒绝时,执行插值失效处理、支持的本地保持以及 acknowledge_hold();在发送之后调用 record_dispatch()。失败的保持操作永远不会被确认。请使用这些辅助函数,而不是重新实现该序列;send_next_action 仅添加了数据集帧、机器人端的动作处理器以及节奏核算。远程上下文中,ctx.policy.policy、preprocessor 和 postprocessor 均设置为 None;请使用 ctx.policy.inference 以及 ctx.processors 中的机器人端流水线。

将运行中已知的阻塞性录制工作包裹在 self._pause_for_recording(ctx) 中,包括环形缓冲区排空和回合结束处理。这会在录制停顿前使异步运动失效,并且仅在运行仍然健康且处于活动状态时才恢复。具有操作员控制阶段的策略必须将其当前的运动权限作为 resume_allowed 传入。下一个动作必须来自新的观测;已保存的工作不得使已暂停、已停止或已发生故障的运行恢复。


可视化策略预测

使用 --display_data 时,查看器还会显示策略除动作之外的预测内容:世界模型想象出的相机帧、预测的子任务,以及绘制在相机画面上的边界框。每个策略自行决定其预测内容,并通过各自的配置将其启用,例如对于 LingBot-VA,使用 --policy.return_predicted_video=true。预测项以其预测的对象命名:Rerun 将预测的 observation.images.top 显示为 prediction.images.top,将预测的子任务显示为 prediction.subtask,并将边界框显示在其所属相机下(<camera>/prediction);Foxglove 则通过 /prediction/... 主题以及 <camera topic>/prediction 图像注释来发布它们。在使用 RTC 时,预测内容每个 chunk 刷新一次。请参阅 Bring your own policy 以了解如何从策略返回预测结果。

推理后端

使用 --inference.type=<name> 选择后端。本地同步推理和 RTC 推理使用下方配置的策略。远程后端 从服务器获取其策略契约,并且不会在机器人计算机上加载权重。

同步(默认)

每个控制周期调用一次策略。主循环会阻塞,直到动作计算完成。

适用于所有策略。无需额外标志。

实时分块(--inference.type=rtc)

后台线程会异步生成动作块。主控制循环轮询下一个已就绪的动作,同时策略并行计算下一个块。

使用 RTC 与兼容的 VLA 模型(Pi0、Pi0.5、SmolVLA)以重叠推理和运动。持续执行仍需足够的可用动作播放来覆盖推理延迟及其波动。

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
标志描述
--inference.rtc.execution_horizon与上一个块进行混合的步骤(默认值:因策略而异)
--inference.rtc.modeguided(默认)或兼容 Pi05 检查点的训练前缀 trained
--inference.rtc.max_guidance_weight一致性强制强度(默认值:因策略而异)
--inference.rtc.prefix_attention_schedule混合计划:LINEAR、EXP、ONES、ZEROS
--inference.queue_threshold背压阈值;训练 RTC 至少需要其最大延迟
--inference.action_starvation_grace_s在支持的机器人上,等待饥饿状态后的新运动(默认值为 1.0;0 会立即触发故障)

有关调整 RTC 参数的详细信息,请参阅 Real-Time Chunking 指南。

本地 RTC 在 rollout 进程的后台线程中运行,无需传输层。同一台计算机上的服务器和客户端应改用 --inference.type=remote。有关块对齐/混合以及异步后端共有的等待行为,请参阅远程指南。

等待功能需要受支持的机器人。普通的本地 RTC 在没有该功能的情况下仍然可用,但计划中的文本/指令变更暂停以及可恢复的饥饿状态需要它。位置控制的 SO、OMX、Koch、HopeJr 和 Rebot 跟随器支持此功能;OpenArm、Reachy2 和双手包装器存在配置限制,详见机器人支持表。在受支持的情况下,空缓冲区可以保留最后应用的目标,持续时间为 action_starvation_grace_s(默认 1 秒),包括排空旧推理并从新捕获中进行预测所需的时间。在运动开始后,如果宽限期为零或机器人不受支持,耗尽时会立即发生故障;启动有其自身的截止时间。与以前的本地 RTC 路径不同,耗尽不再是一个无限期跳过的 tick。宽限期永远不会延长已过期的请求或新鲜度限制。

Local RTC 通过 --inference. 公开了这些额外的预算:

参数默认含义
max_observation_age_s5 s通过操作执行实现的最大源年龄
action_timeout_s10 s待处理的操作请求
startup_timeout_s120 s初始准备和新鲜操作启动
language_timeout_s120 s计划中的语言操作

这些是初始值,而非实测的硬件保证。RTC 必须保留足够的修剪后播放时间,以应对下一次推理及时间余量。如果推理通常会耗尽可用的预测时域,那么提高queue_threshold也无济于事;请降低延迟,或验证更长的时域/不同的动作频率。

终端故障绝不会自动恢复策略运动。在可用的观测获取和执行器控制下,关机操作会遵循 --return_to_initial_position(默认为 true)并断开连接。返回过程需要读取完整的观测,因此持续的相机故障可能会阻止该过程。命令应用失败会抑制所有后端(包括同步后端)的进一步关机运动。这不会改变同步预测,也不会引入针对相机的特定恢复机制。

Compilation and instruction changes

RTC 编译会预热初始调用和带前缀的调用(包括一个具有代表性的非零延迟),然后才执行运动。尽管 --compile_warmup_inferences 的默认值为 2,但启用 RTC 至少需要 3;启动日志会报告实际生效的数量。预热必须在 startup_timeout_s 内完成。后续更改张量形状的指令可能会触发重新编译,从而导致超出播放或操作截止时间。

推理期间的任务变更会丢弃过时的结果。受支持的机器人会暂停并请求新的动作;如果机器人不具备这种等待能力,剩余的动作可能会耗尽。建议在这些机器人上于运行之间更改任务。


交互式会话

添加 --interactive=true 以从终端驱动 rollout,而不是立即开始。硬件连接和策略加载照常进行,但 在您输入 /start 之前,机器人保持静止 — 当您想先布置场景、在多次尝试之间重新指示策略,或在不重复支付加载时间的情况下运行多次拍摄时,这非常有用。

lerobot-rollout \
    --strategy.type=base \
    --policy.path=${HF_USER}/my_smolvla_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" \
    --interactive=true
命令操作
/start启动(或重启)策略控制循环
/subtask <text>更改当前运行中的指令;异步推理可能会进入计划中的暂停状态。不带参数时,将打印当前任务。仅影响基于语言进行条件判断的策略(SmolVLA、π0/π0.5 及类似策略)。当使用 外部规划器 时,/subtask 还会将控制权从 autosteer 交还
/vqa <text>询问机器人当前看到的内容。仅在运行进行中,且使用策略文本头或外部规划器时可用。
/autosteer <goal>提供一个高层目标,让策略的文本头部或外部规划器选择子任务。/autosteer off将控制权交还;不带参数则报告当前目标
/reset停止移动,将机器人返回到启动位置,并恢复--task指令
/stop结束会话并运行正常的关机例程
/help列出命令
> /start
Rollout running — task 'pick up the cube'. /subtask <text> to change it, ...
> /subtask put the cube in the box
Task: 'pick up the cube' → 'put the cube in the box' (applies from the next policy inference)
> /vqa is the cube inside the box?
Asked: 'is the cube inside the box?' — answering from the next observation...
Q: is the cube inside the box?
A: No — the cube is on the table to the left of the box.
> /reset
Task restored to 'pick up the cube'
Resetting — returning the robot to its initial position...
Robot reset — holding at initial position. /start to run.
> /stop

以 > 开头的行是您输入的内容;该会话本身不会显示任何提示符。

Ctrl-C 仍会按常规方式关闭,而关闭标准输入(Ctrl-D,或管道脚本的末尾)会结束会话——因此,管道脚本必须保持标准输入在预期时长内处于打开状态:

(printf '/start\n'; sleep 60; printf '/stop\n') | lerobot-rollout ... --interactive=true

/subtask 用于更新后续推理的任务。在使用 --inference.type=sync 时,预计算的块动作会被丢弃。在本地 RTC 或远程推理中,如果在动作请求期间发生更改,过时的结果将被丢弃。对于支持本地保持(local hold)的机器人,引擎会使队列中/插值中的运动失效,等待控制循环确认保持状态,然后在新任务下请求新的运动。在此过渡期间预计会出现停止;这不保证是连续的混合。请求之间的更改可以保留已接受的动作以保持连续性。在不支持保持的机器人上使用本地 RTC 时,仍然会丢弃过时的结果,但可能会耗尽剩余的动作并终止。如果该机器人无法适当保持,请在运行之间更改指令。

在本地使用 --use_torch_compile=true 时,改变处理后张量形状的指令可能会触发重新编译。填充(Padding)可能使某些任务变更保持相同的形状,但后续的编译并不保证能适配剩余的播放或指令变更截止时间:这可能导致终端故障。除非已验证这些转换,否则在探索指令时应保持编译关闭。在初始编译预热期间的变更不会请求运动保持,因为策略运动尚未开始。

/vqa 和 /autosteer 需要一个声明了文本生成支持并实现了 PreTrainedPolicy.generate_text() 的策略,例如经过适当训练的 EO1 检查点,或一个 外部规划器。在接受查询之前会检查该能力;特定于检查点的行为仍需验证。

/vqa 会基于下一帧观测进行回答,并在就绪时打印结果,因此您可以在此期间继续输入;同一时间只有一个问题在处理中(autosteer 自身的查询也共享该槽位)。若使用外部规划器,问题将在工作线程上回答,而机器人继续执行动作,以下描述均不适用。异步后端首先进入已确认的本地保持状态,并使队列中/插值后的运动失效,然后将新的观测提交给文本路径。健康的活跃运行会在回答后从新的动作块恢复;暂停或停止的运行保持非活动状态。同步文本生成在控制线程上内联执行,并丢弃策略预计算的动作,因此下一个 tick 将从新的推理恢复。查询时间会计入 --duration。仅在运行进行中时才会接受问题——空闲引擎没有当前视图。如果指令或执行上下文使异步回答失效,问题将收到一条取消通知,而不是过时的回答。片段结束时也会报告未回答的问题,包括仍在生成中的问题;报告取消不会中断正在运行的模型调用,也不会提前释放其查询槽位。

/autosteer 向策略(policy)提供一个目标,并每隔 --autosteer_interval_s 秒(默认 10 秒)请求下一个子任务,通过与 /subtask 相同的路径应用每个子任务,并在聊天中宣布。每次查询都是一次完整的文本生成,因此该间隔是一个成本调节旋钮:更低的值会更快重新规划,但会花费更多循环时间用于生成文本而非执行动作。计划进度保存在策略中,而非 rollout 中,因此计划会随 segment 结束而终止;sequencer 也会在 /reset、/subtask、/autosteer off 以及首次规划失败时停止。

会话运行期间,低于 ERROR 级别的日志会被静音,以避免常规输出与您正在输入的内容交错显示;错误和致命的推理失败仍会显示,会话结束后恢复正常日志记录。节奏摘要 会打印在聊天中,而不使用 --interactive 运行则会恢复实时日志。

会话通过 SSH 运行,也适用于无头机器——无需显示服务器。

交互过程中录制。 --strategy.type=sentry 还支持 --interactive=true,在您操控时持续录制:每个 /start…/reset 片段会保存完整的 episode 以及一个最终的 partial episode,并且数据集在关闭前保持打开状态。帧携带实际发送动作的任务来源信息,因此已在旧任务下排队或插值的动作仍保留旧标签。

运行中途的阻塞式 episode 保存会暂停异步推理,使已排队或插值的动作失效,并请求受支持的本地保持。仅当运行仍处于活跃且健康状态时,才会从新的捕获中恢复。相同的保护机制也适用于 DAgger 保存以及 Highlight 环形缓冲区的排空/保存。录制暂停和普通饥饿共享相同的物理等待行为,但它们的截止时间以及恢复原因保持独立。

lerobot-rollout \
    --strategy.type=sentry \
    --policy.path=${HF_USER}/my_smolvla_policy \
    --robot.type=so100_follower \
    --robot.port=/dev/ttyACM0 \
    --dataset.repo_id=${HF_USER}/rollout_cube_sessions \
    --task="pick up the cube" \
    --interactive=true

其他录制策略(episodic、DAgger、highlight)不受支持:它们会绑定自己的键盘控制,并在 run() 退出时完成数据集,因此无法按片段重启。

外部规划器

--planner.model_id=<name> 使 /vqa 和 /autosteer 通过注释管道的 VLM 客户端(annotations 附加组件)运行,而不是通过策略的文本头。调用在机器人持续行动期间于工作线程上执行,并且不会为它们请求语言保持,但有一个刻意的例外:当 /autosteer 启动时,推理后端会暂停,直到规划器给出第一个回复,因为目标是规划器的上下文,而不是策略的指令。异步后端(rtc、remote)会丢弃已排队或正在为上一条指令计算的动作;同步后端则会保持机器人。一旦第一个子任务被应用,后端将从新的观测中恢复。 /subtask 仍然直接应用您的指令并取消自动规划;规划器晚到的回复无法覆盖它。

规划器适用于所有推理后端。在本地推理中,如果已加载的处理器存在子任务配方,则复用该配方;否则,请求一条简短的指令;但这并不能证明检查点能够遵循该指令。--planner.instructions='["pick up the cup","open the drawer"]' 会限制规划器的输出:VLM 被要求从这些字符串中选择一个,而返回不在列表中的下一个子任务将被视为错误。大小写、多余的空格和末尾的句号会被忽略,而列表本身的措辞会发送给策略。如果不使用此标志,列表将从检查点训练数据集的任务标签中读取(通过其 train_config.json)。由于每个标签都会进入提示词,因此对于包含许多任务的数据集,请通过该标志传入更短的列表。如果无法读取数据集,则会记录一条警告,并且规划器的输出将保持自由格式。远程推理拥有策略,因此本地无法访问配方或训练词汇表:请显式传入 --planner.instructions,否则回答将保持自由格式。规划器仅在配备本地推理的硬件上经过测试。

外部规划器会接收最近 --planner.history 个观测/指令对(默认为 4 个),随后是当前图像。每个对包含用于请求指令的观测,以及引擎随后接受的指令;接受并不表示执行成功。重复的指令会保留在历史中,以便 VLM 评估是否缺乏进展。在手动接管、重置、停止、片段结束或新的 autosteer 目标时,历史会被清空。设置 --planner.history=0 可禁用此功能。/vqa 可以检查此历史,但不会添加条目。对于下一个子任务请求,VLM 必须先描述场景并说明上一条指令是已完成、进行中还是失败,然后才能给出下一条指令。done 的回复表示目标已完成:autosteer 停止,运行结束,机器人保持其姿态,直到执行 /reset 或 /start。在 /subtask、/reset 或新目标之前发出的迟到的 done 将被丢弃。每个应用的子任务都会打印出模型的场景评估和请求延迟。

单独启动一个 OpenAI 兼容的 VLM 服务器,然后进行连接:

transformers serve Qwen/Qwen3-VL-8B-Instruct --port 8000
# Alternatively: vllm serve Qwen/Qwen3-VL-8B-Instruct --port 8000
lerobot-rollout ... --task="pick up the cup" --interactive=true \
    --planner.model_id=Qwen/Qwen3-VL-8B-Instruct \
    --planner.api_base=http://localhost:8000/v1
> /start
> /vqa What is the next short instruction to clear the table?
> /subtask put the cup in the sink
> /autosteer clear the table

托管模型的工作方式相同。此示例使用 Hugging Face Inference Providers,并使用具有“Make calls to Inference Providers”权限的令牌:

export HF_TOKEN=hf_...
lerobot-rollout ... --task="put all colored cubes in the green bin" --interactive=true \
    --planner.model_id=Qwen/Qwen3.8-27B:novita \
    --planner.api_base=https://router.huggingface.co/v1 \
    --planner.api_key_env=HF_TOKEN

/vqa 仅报告答案;/autosteer 应用指令。使用 --planner.api_base 配置端点,使用 --planner.api_key_env=<variable>(推荐,密钥不会出现在命令和日志中)或 --planner.api_key 配置密钥。--planner.request_timeout_s(默认 600)和 --planner.request_max_retries(默认 2)限制每个请求;--planner.camera_key 选择一个摄像头;--planner.log_path 将每次交互追加为一行 JSON。模型服务依赖项应位于服务器环境中。--autosteer_interval_s 在应用回复后测量机器人运动时间,此外还包括请求延迟。多级转向和自动场景清单不在该适配器的范围内。

编程控制

RolloutController 暴露了与库 API 相同的操作——线程安全的 start() / reset() / stop() / set_task() 以及一个 RolloutEvent 回调,且不附带任何标准输入、打印或日志静默功能:

from threading import Event, Thread

from lerobot.rollout import (
    LinkedEvent,
    RolloutController,
    RolloutEvent,
    build_rollout_context,
    create_strategy,
)

parent = Event()  # your application's shutdown signal
ctx = build_rollout_context(cfg, LinkedEvent(parent))  # loads policy, connects robot
strategy = create_strategy(cfg.strategy)
strategy.setup(ctx)

controller = RolloutController(strategy, ctx, on_event=print)  # or your own observer
serve_thread = Thread(target=controller.serve)  # serve() blocks; run it where you like
serve_thread.start()

controller.start()                        # robot starts executing the policy
controller.set_task("grab the red cube")  # re-instruct mid-run
controller.reset()                        # stop movement, return home, stay warm
controller.stop()                         # end serve()

serve_thread.join()
strategy.teardown(ctx)  # teardown stays with the caller

RolloutController 要求上下文的关闭事件是一个 LinkedEvent,构建方式如上所述:控制器通过其本地标志结束运行段,而您的 parent 事件仍会强制完全关闭。除非您希望听到语音播报,否则请设置 play_sounds=False。


常用标志

标志描述默认
--policy.path必填。HF Hub 模型 ID 或本地检查点路径—
--robot.type必填。 机器人类型(例如 so100_follower、koch_follower)—
--robot.port机器人的串行端口—
--robot.cameras相机配置(JSON 字典)—
--fps策略推理和数据集记录频率30
--status_interval_s健康日志之间的秒数(0 表示禁用;仅限非交互模式)5
--duration运行时间(秒)(0 = 无限;交互模式下按段计算)0
--deviceTorch 设备(cpu、cuda、mps)auto
--task任务描述(在未提供数据集时使用)—
--display_data将遥测数据流式传输到 Rerun 可视化false
--display_ip / --display_port远程 Rerun 服务器地址—
--interpolation_multiplier每个策略动作对应的机器人指令(以 fps × N Hz 的频率进行控制)1
--interactive在 stdin 上进行聊天会话;机器人在收到 /start 之前保持空闲(base, sentry)false
--use_torch_compile为推理启用 torch.compilefalse
--resume恢复之前的录制会话false
--play_sounds活动语音合成true

Cadence 报告

非交互式 rollout 会每五秒记录一次其状态。使用 --status_interval_s=10 可更改该间隔,或使用 --status_interval_s=0 将其禁用。

Rollout: loop 29.7/30 Hz · over budget 2/149 · starved 0 · infer 18.7 ms (worst 40.1) · process 2.41 GiB · GPU 5.12/79.6 GiB

延迟为区间内的中位数/最差值(RTC/远程为turnaround)。不可用的字段将被省略;GPU 内存为设备级,远程内存为本地。当循环阻塞时,报告将暂停。

每种策略都会报告其控制循环实际达成的结果,lerobot-record、lerobot-teleoperate 和 lerobot-replay 也是如此——它们都按照同一个计时器推进。每个保存的 episode 都会生成一行摘要,当循环结束时——包括在按下 Ctrl-C 时——会输出一个涵盖整个运行过程的代码块:

Cadence (episode 1): 29.84 Hz policy vs 30 Hz target · 1200 ticks, 20.1 s measured · 6/598 cycles over the 33.3 ms budget (work mean 18.7 ms, worst 48.1 ms)
Cadence (episode 2): 29.84 Hz policy vs 30 Hz target · 1200 ticks, 20.1 s measured · 6/599 cycles over the 33.3 ms budget (work mean 18.7 ms, worst 48.1 ms)
Cadence summary — whole run, 2 episodes · target 30 Hz × 2 (16.7 ms tick slot, 33.3 ms cycle budget): 2400 ticks, 1197 cycles judged
  effective cadence: 29.84 Hz policy / 59.67 Hz commands over 40.2 s measured
  cycles over the 33.3 ms work budget: 12/1197 (1.0%) — work mean 18.7 ms, worst 48.1 ms
  ticks over their 16.7 ms slot: 40/2400 (costs interpolation smoothness only)
  loop-body steps (share of measured work):
    observe      mean   3.13 ms · worst   9.00 ms ·  31.7% of work · 2400 calls
    process_obs  mean   0.50 ms · worst   1.00 ms ·   5.1% of work · 2400 calls
    infer        mean   5.18 ms · worst  40.00 ms ·  52.4% of work · 2400 calls
    send         mean   0.40 ms · worst   0.40 ms ·   4.1% of work · 2400 calls
    record       mean   0.67 ms · worst 620.00 ms ·   6.8% of work · 2402 calls
  pacing headroom: 7.4 ms slept per tick on average (max 13.0 ms) — near zero means the loop is saturated

自上而下阅读:有效节奏 是相对于 --fps 的实际达成值,超出预算的周期数 表示循环未能维持该节奏的频率,步骤分解 说明了时间消耗在哪里,而接近零的 节奏余量 意味着没有剩余空间来吸收缓慢的节拍。较高的 infer 占比指向策略或设备;较高的 observe 占比指向相机。某一步骤的 worst 远高于其 mean 属于一次性事件——在上文中,record 为每帧 0.67 毫秒,而 620 毫秒的异常值是关闭剧集时阻塞的 save_episode。

此处的cycle指一个策略动作所对应的 tick 数量(即 --interpolation_multiplier 个)。只有当完整的 cycle 超出 1/fps 的预算时,才会导致掉帧;单个 tick 超出其时间槽只会使插值后的运动不够平滑,因此这两者被分开统计。在没有插值的情况下,一个 cycle 就是一个 tick,因此报告会取消这种区分,并始终按 tick 进行统计。

在 交互式会话中,每个 /start 片段都拥有自己的计时器,因此报告会在每个片段(/reset、/stop 或 --duration)结束时发送到聊天中,而不是在每个进程结束时发送。


编程式用法

对于扩展功能,lerobot.inference 是用于后端配置、本地引擎和共享调度契约的公共包。lerobot.remote_inference 负责远程引擎、协议、部署和会话的实现;lerobot.rollout 负责机器人循环、策略、插值和记录。请从各自的包中导入公共符号,而不是从实现文件中导入。仅在使用远程后端或服务器时,才需要可选的远程依赖项。

对于自定义部署(例如使用运动学处理器),请直接使用 rollout 模块 API:

from lerobot.rollout import BaseStrategyConfig, RolloutConfig, build_rollout_context
from lerobot.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)

请参阅 examples/so100_to_so100_EE/rollout.py 和 examples/phone_to_so100/rollout.py 以获取包含运动学处理器的完整示例。

Update on GitHub