LeRobot 手册
从一台机械臂到具身智能
一个 200 美元的机械臂、一份 Parquet 文件、三十条人类演示, 能训出一个会抓东西的模型。这本书讲清这条链路是怎么搭起来的, 以及你可以在哪一段插手。
为什么写这本书
「让每个人都能贡献并受益于共享的数据集与预训练模型。」
——LeRobot 的一句话目标
过去两年,具身智能的论文数量涨得比数据快。几乎每周都有新的 VLA 模型刷榜,几乎每家都宣称自己在「真实机器人上验证过」。但如果你真的拆开其中一篇的代码仓库,会发现复现它需要三样很贵的东西:一台特定型号的机械臂、一套特定布置的相机、以及作者没说清楚的数据处理脚本。
LeRobot 想解决的正是这三样。它做的事情听起来很朴素——把机器人硬件抽象成统一的接口,把数据统一成一种格式,把主流策略用纯 PyTorch 重写一遍,然后全部放到 Hugging Face 上。但就是这三件事,让「复现一个机器人策略」的成本从几周降到了几个小时。
这本书不打算写成 API 文档的翻译。文档告诉你每个参数是什么意思,但不会告诉你为什么要有这个参数、什么时候它会咬你一口。所以本书的组织方式是:先讲这个项目由哪些零件组成,再讲这些零件背后的科学原理,然后带你装一遍,最后告诉你从哪里可以改它。
四章的分工
- 第一章拆仓库。把
src/lerobot下的二十多个子包按职责分层,讲清每个模块解决什么问题、彼此怎么调用。读完你应该能在脑子里画出这个项目的架构图。 - 第二章讲原理。从「为什么机器人学习比图像分类难」讲到动作表示、VLA 架构、以及 2026 年正在收敛的几个技术方向。这一章不依赖 LeRobot,但读完你会明白 LeRobot 为什么长成现在这样。
- 第三章动手。硬件清单、接线、环境、五条命令跑通全流程、数据集结构、训练与部署、故障排查。这一章是可以照着做的。
- 第四章参与。从「上传一个数据集」到「给核心加一个新策略」,按投入从轻到重排开,附代码落点与评审预期。
你需要会写 Python(能读懂 dataclass 和类型注解),用过一次命令行,知道什么是 GPU 显存。不需要学过机器人学,不需要有硬件——第三章最后一节给了完全无硬件的路径。
本书基于 2026 年 11 月 1 日的 main 分支与 PyPI 上的 v0.6.1。这个仓库的迭代速度快得反常——当天还有新的 commit 推上来,开放 issue 数接近九百。文中所有文件路径与命令都以该时间点为准;如果你读到的是半年后的版本,请以仓库为准,但架构层面的判断大概率仍然成立。
认识 LeRobot
What LeRobot Actually Is
大多数人对它的第一印象是「机器人版的 transformers」。这个类比有一半对,而错的那一半,恰好是最关键的部分。
1.1它是什么,不是什么
官方的定义只有一句话:LeRobot 用 PyTorch 为真实世界的机器人提供模型、数据集和工具。这句话里三个名词都是重点——模型、数据集、工具,缺一个都不成立。
更具体地说,它提供四样东西:
- 一个硬件无关的控制接口。不管是 200 美元的 SO-101 舵机臂、几万块的 OpenArm,还是 Unitree G1 人形,在代码里都实现同一个
Robot类:connect()、get_observation()、send_action()。上层逻辑不需要知道你插的是什么。 - 一种数据格式。
LeRobotDataset:视觉存 MP4(或图片),状态与动作存 Parquet,两者按时间戳逐帧对齐,附一份meta/info.json描述所有字段。托管在 Hugging Face Hub 上,可以流式读取、可以合并、可以切分。 - 一批纯 PyTorch 的策略实现。从最经典的 ACT、Diffusion Policy,到 π0、GR00T N1.7、SmolVLA 这些 VLA,再到世界模型与奖励模型,全部用原生 PyTorch 写,不依赖任何闭源推理栈。
- 一套 CLI。校准、遥操、录制、训练、评测、部署,各自对应一个
lerobot-*命令。这些命令不只是脚本,它们是把配置系统、数据管线、硬件接口串起来的入口。
它不是什么
这部分比上面更重要,因为误解通常从这里开始。
- 它不是 ROS。ROS 解决的是进程间通信、消息定义、分布式节点的编排;LeRobot 解决的是「怎么把一段人类演示变成一个能跑的神经网络」。两者可以共存(社区有 ROS 2 桥接插件),但设计目标不同。LeRobot 没有节点、没有 topic、没有 launch 文件,它是一个 Python 库加一组脚本。
- 它不是仿真器。仓库里确实有
envs模块,支持 LIBERO、MetaWorld 这类基准,但物理引擎不在它里面——它只是把这些环境包装成统一接口,方便做评测。 - 它不是模型 zoo。虽然内置了三十个策略,但它的定位不是「给你一堆权重下载」,而是「给你一套能训、能评、能部署的流水线」。权重在 Hub 上,训练代码在你本地。
- 它不是「开箱即用的机器人」。你需要自己买舵机、打印结构件、接线、校准。软件层把门槛降到了很低,但物理世界那一半的门槛还在。
LeRobot 的本质是一条流水线,而不是一堆模型。它的四个环节是「采 → 存 → 训 → 跑」,每个环节都可以单独拿出来用,也可以整条用。
1.2为什么会有这个项目
2024 年之前,机器人学习领域有一个很尴尬的现象:论文越来越多,能复现的越来越少。原因不复杂,但每一层都在叠加成本。
| 障碍 | 具体表现 | LeRobot 的解法 |
|---|---|---|
| 数据碎片化 | 每个实验室用自己的 HDF5 结构,字段名、坐标系、采样率都不同。A 组的数据在 B 组的代码里读不出来。 | 统一的 LeRobotDataset 格式 + Hub 托管 |
| 硬件绑定 | 策略代码里写死了关节数量、相机数量、控制频率。换一台机器人就要重写一遍 I/O。 | Robot 抽象类 + 配置驱动 |
| 实现不可读 | 论文附带的代码经常是研究原型,硬编码路径、缺依赖、没有测试。 | 纯 PyTorch 重写 + CI + 文档化的 API |
| 硬件太贵 | 主流的 ALOHA 双臂系统成本在数万美元,个人和小实验室进不来。 | 主推 SO-100 / SO-101 这类几百美元的舵机臂 |
| 评测不统一 | 每家在自己的任务集上报成功率,数字无法横向比较。 | 统一接 LIBERO / MetaWorld,并提供 EnvHub 机制 |
把这五条放在一起,你会看到 LeRobot 不是在做某一个技术突破,而是在修基础设施。这也解释了为什么它的价值随着时间越来越高:基础设施的回报是复利式的,用的人越多,数据越多,格式越稳,后来者越没有理由另起一套。
2026 年,这套基础设施得到了学术界的正式确认——团队在 ICLR 2026 发表了论文《LeRobot: An Open-Source Library for End-to-End Robot Learning》。从「一个开源仓库」变成「一个有引用格式的学术成果」,这个转变本身说明了问题:在具身智能这个领域,基础设施已经成了需要被研究、被引用的对象。
1.3现状与版本
几个数字,帮你建立体量感(截至 2026 年 11 月 1 日):
| 指标 | 数值 | 说明 |
|---|---|---|
| 最新版本 | 0.6.1 | PyPI 可直装,pip install lerobot |
| Python 要求 | >= 3.12 | 注意:比很多教程里写的 3.10 要高 |
| Star | 28,617 | 机器人学习类开源项目里第一梯队 |
| Fork | 5,991 | 插件生态的基础 |
| 开放 issue | 877 | 侧面说明迭代强度 |
| 许可 | Apache 2.0 | 可商用,可闭源衍生 |
877 个开放 issue 不是坏消息,而是这个阶段的正常状态。它意味着有大量真实用户在用、在报问题,也意味着你遇到的问题大概率已经有人踩过——搜索 issue 是使用 LeRobot 的第一技能。
安装的两种方式
第一种,直接装 PyPI 包。适合只想跑策略、读数据集的人:
pip install lerobot
lerobot-info # 打印版本、已装 extras、检测到的设备
基础安装很轻。功能按需加载,每种能力对应一个 extra:lerobot[dataset] 读数据,lerobot[training] 训模型,lerobot[core_scripts,feetech] 用 SO-101 录数据。这个设计的好处是:只读数据集的人不需要装 CUDA 相关的几百兆依赖。
第二种,从源码装。适合要改代码、要提 PR 的人(第四章会详细讲)。
网上大量教程写的是 pip install -e ".[aloha,pusht]" 这类旧写法。v0.6 起 extras 已经重组为按能力分组(dataset / training / hardware / viz / core_scripts / evaluation),旧的按硬件分组的部分写法已经失效。装之前先看 pyproject.toml 里的 [project.optional-dependencies],那是最权威的清单。
1.4仓库地图:目录结构就是架构图
读一个陌生的开源项目,最有效的方式不是从 README 开始,而是先看 src/ 下的目录名。目录划分往往暴露了作者心里的抽象边界,而 README 只会告诉你它有多好。
LeRobot 的 src/lerobot/ 下有三十二个条目(二十七个包 + 几个单文件)。初看很碎,但按职责归一下,会发现它严格分成五层:
↑ 五层栈。上层只依赖下层,反向依赖只通过抽象(Robot、Policy、Processor)发生。这意味着你可以只替换其中一层——比如保留数据与训练,换掉硬件层去接自己的机械臂。
这种分层不是学院式的洁癖,它有非常实际的好处:你可以在没有硬件的情况下训练和评测,也可以在没有 GPU 的情况下采数据。因为「硬件层」和「策略层」之间没有直接引用,中间隔了一个 processor 和一个 Robot 接口。
1.5逐模块详解
下面按从下往上的顺序讲。这个顺序不是随意的——它对应你将来读源码时最省力的路径:先看懂最底层的约定,再看上层怎么用它。
1.5.1硬件层:robots / teleoperators / motors / cameras
四个包,解决一件事:把物理世界翻译成 Python 字典。
robots/ 里最重要但不是最显眼的文件是 robot.py——它定义了抽象的 Robot 基类。所有具体机器人都是它的子类,都只承诺四件事:
class Robot: def connect(self) # 打开串口/CAN,上电,读初始状态 def get_observation(self) -> dict[str, Tensor] def send_action(self, action: dict[str, Tensor]) def disconnect(self)
约定的细节在于字典的键名。不是随意的字符串,而是一套命名规则:shoulder_pan.pos、gripper.pos、wrist(相机名)等等。策略层不认识任何具体硬件,它只认识这些键。所以键名就是硬件与算法之间的契约——这也是为什么接一台新机器人时,最容易出错的地方不是驱动,而是键名对不上。
| 包 | 已内置实现(部分) | 说明 |
|---|---|---|
| robots/ | so_follower · bi_so_follower koch_follower · lekiwi openarm_follower · rebot_b601_follower unitree_g1 · reachy2 · hope_jr omx_follower · earthrover_mini_plus | 从几百美元的舵机臂到人形与移动底盘。bi_* 前缀表示双臂。 |
| teleoperators/ | so_leader · bi_so_leader · koch_leader openarm_leader · rebot_102_leader gamepad · keyboard · phone · homunculus reachy2_teleoperator · unitree_g1 | 主从臂、手柄、键盘、手机、VR 手部追踪。遥操器本身也是一种「机器人」的对称物。 |
| motors/ | Feetech · Dynamixel · CAN 设备 | 伺服总线的读写、ID 分配、限位与使能。对应 extras:feetech、rustypot、can。 |
| cameras/ | OpenCV(USB 相机)· RealSense | 统一成「打开 / 读帧 / 关闭」,支持第三方相机插件。 |
这里有一个容易被忽略的设计:遥操作臂和从动臂用同一套代码路径。so_leader 和 so_follower 都是 Robot 的子类,区别只是前者被读取、后者被写入。这带来的好处是校准逻辑、端口扫描、限位保护全部复用;代价是你会看到一些看起来多余的接口——比如给主臂也实现了 send_action。这是刻意的冗余,为了让主从对称。
1.5.2数据层:datasets——全项目最核心的包
如果这本书只能讲一个模块,我会选 datasets/。原因很简单:LeRobot 对行业最大的贡献不是那三十个策略,而是这个数据格式。策略会过时,格式不会——一旦几百个数据集都按同一种结构存在 Hub 上,它就变成了沉没成本最低的公共资产。
这个包有二十多个文件,按职责可以分成四组:
| 职责 | 关键文件 | 做什么 |
|---|---|---|
| 读写核心 | lerobot_dataset.py dataset_writer.py dataset_reader.py | LeRobotDataset 类本身。__getitem__ 返回一个字典,自动处理视频解码、时间戳对齐、字段重命名。 |
| 流式与大规模 | streaming_dataset.py streaming_sidecar.py lance_backend.py multi_dataset.py | 不下载全量也能训练;多数据集混合采样;列式后端(Lance)用于超大数据集。 |
| 编辑与合并 | aggregate.py dataset_tools.py compute_stats.py | 删 episode、按比例切分、增删特征、合并多个数据集、统计归一化参数。 |
| 媒体与元信息 | image_writer.py video_utils.py / pyav_utils.py feature_utils.py card_template.md | 写 MP4、编解码、特征 schema 校验、自动生成数据集卡片。 |
几个值得单独说的设计:
- 媒体外置。视频不塞进 Parquet,而是单独存 MP4,Parquet 里只记
episode_index与frame_index。这样做的直接好处是:训练时按帧随机采样,只需要解码对应的一小段视频,而不是把几百 GB 全读进内存。 - 统计量预计算。
compute_stats.py把每个特征的均值、方差、分位数提前算好写进 meta。训练时的归一化不再需要扫一遍数据集,这对「边下边训」是必需的。 - 多数据集混合(
multi_dataset+recipe+sampler)。这是协同训练的基础设施:你可以按权重混合「自己的 50 条真机数据」和「十万条仿真数据」,而不需要先物理上合并成一个巨大文件。策略层看到的是一个普通 Dataset。 - 版本迁移脚本。
convert_dataset_v21_to_v30.py单独放在 scripts 里——格式演进是常态,提供官方迁移路径比追求「一开始就设计对」更务实。
建议顺序:lerobot_dataset.py 的 __init__ 与 __getitem__ → dataset_metadata.py(看清 meta 结构)→ dataset_writer.py(理解写盘时序)→ 再看 aggregate.py。前三步读完,你对「一条数据到底存在哪」就没有疑问了。
1.5.3策略层之一:processor——被低估的中间件
如果 datasets 是骨架,processor 就是血管。它负责在「原始字典」和「模型张量」之间来回搬运,并在搬运过程中做所有必要的变换。
这个包有近二十个 processor,名字都很直白,但每一个对应一个真实存在的工程问题:
| Processor | 解决的问题 |
|---|---|
| normalize_processor | 用预计算的均值方差做归一化;推理时必须用训练时的同一份统计量,否则输出会静默偏移。 |
| relative_action_processor delta_action_processor | 把绝对关节角转成相对末端增量。这是跨本体迁移的关键,第二章会展开。 |
| rename_processor | 不同数据集字段名不同(observation.images.top vs cam_high),靠它对齐后再混训。 |
| tokenizer_processor | 把语言指令切成 token,供 VLA 的文本塔使用。 |
| device_processor | 把张量搬到 GPU,并统一 dtype(bf16 / fp32)。 |
| image_augmentation_processor | 训练期增强:颜色抖动、随机裁剪。只在训练时启用。 |
| policy_robot_bridge | 把策略输出接到 Robot.send_action,处理频率不匹配与缓冲。 |
| hil_processor | Human-in-the-loop:人在环干预时切换控制源,用于 HIL-SERL 这类方法。 |
理解 processor 的关键是理解 pipeline.py:它把若干 processor 串成一条链,训练时正向走一遍,推理时反向还原。这是一个很干净的对称设计——模型只看到归一化后的相对动作,机器人只收到反归一化后的绝对指令,中间的转换全部由这条链负责。
为什么这个设计重要?因为机器人学习里最常见的 bug 不是模型不收敛,而是训练和推理的预处理不一致。少做一次反归一化,机械臂就会以一种看起来很「合理」但完全错误的方式运动,而且日志里不会有任何报错。把变换显式建模成 pipeline,并在 checkpoint 里保存这份配置,是这个 bug 的工程解法。
1.5.4策略层之二:policies——三十个实现,五类范式
policies/ 是外人最感兴趣、也最容易误读的包。它不是一个「模型集合」,而是一个带统一接口的注册表。核心是两个文件:factory.py(按名字造模型)和 pretrained.py(按名字加载权重)。每个策略是一个子目录,内部通常包含 configuration_*.py(超参 dataclass)与 modeling_*.py(网络与损失)。
按 README 的分类,三十个实现分布在五个范式里:
| 范式 | 代表 | 一句话 |
|---|---|---|
| 模仿学习 IL | ACT · Diffusion · VQ-BeT Multi-Task DiT | 从演示直接学策略。轻、快、稳,单任务首选。 |
| 强化学习 RL | HIL-SERL · TDMPC | 用奖励信号在真机上继续优化,通常需要人在环干预。 |
| 视觉语言动作 VLA | π0 / π0-FAST / π0.5 · GR00T N1.7 SmolVLA · X-VLA · MolmoAct2 EO-1 · EVO1 · DM05 · FineART-VLA LingBot-VLA 2.0 · WALL-OSS 系列 | 用预训练视觉语言模型做主干,接一个动作专家头。泛化强,显存贵。 |
| 世界模型 | VLA-JEPA · LingBot-VA · FastWAM Long-WAM · LaWAM · FLUX 3 Action | 不直接输出动作,而是学习「动作会让世界变成什么样」,可用于规划或合成数据。 |
| 奖励模型 | SARM · TOPReward · Robometer | 给轨迹打分,替代人工设计奖励函数。 |
这个分类本身就是一份领域地图:IL 是基线,RL 是后训练,VLA 是泛化,世界模型是想象,奖励模型是评价。一个完整的现代流水线往往同时用到其中三四个——比如「ACT 冷启动 → VLA 泛化 → 奖励模型打分 → HIL-SERL 精调」。
另外几个单文件值得一提:chunk.py(动作块的时间维度处理,几乎所有现代策略都用到)、rtc.py(real-time chunking,实时分块执行)、pi_gemma.py(π 系列共用的主干封装)。这些是把「论文里的公式」变成「能跑在 30 Hz 控制循环里的代码」的地方。
1.5.5入口层:configs + scripts——配置即 API
LeRobot 有一个很强烈的设计选择:不用 YAML,用 Python dataclass 当配置。configs/ 下的 train.py、eval.py、dataset.py、policies.py 都是一层套一层的 dataclass,parser.py 负责把命令行参数解析进这些 dataclass。
lerobot-train --policy.type=act --dataset.repo_id=lerobot/aloha_mobile_cabinet --policy.push_to_hub=false
这行命令里,policy.type 决定实例化哪个 dataclass,dataset.repo_id 落到 DatasetConfig 上。好处是三层:类型检查在启动前就能发现拼写错误;IDE 能补全所有参数;配置对象可以直接序列化进 checkpoint,于是「用哪个参数训的」这件事被永久记录在模型里。
scripts/ 下有二十三个入口,是用户唯一需要记住的「表面」。完整的表在附录 A,这里只按功能分组给你一个印象:
- 硬件准备:
lerobot_find_port(找串口)、lerobot_setup_motors(分配 ID)、lerobot_calibrate(校准)、lerobot_find_joint_limits、lerobot_setup_can。 - 采集与回放:
lerobot_teleoperate、lerobot_record、lerobot_replay、lerobot_annotate。 - 训练与评测:
lerobot_train、lerobot_train_tokenizer、lerobot_eval、lerobot_rollout。 - 数据工具:
lerobot_dataset_viz、lerobot_edit_dataset、lerobot_imgtransform_viz、lerobot_build_mp4_sidecar、convert_dataset_v21_to_v30、augment_dataset_quantile_stats。 - 服务化:
lerobot_policy_server(把策略跑成一个服务端,机器人端做客户端)。
1.5.6运行时层:inference / rollout / transport
这一层是 v0.5 之后新长出来的,也是最容易被老教程忽略的部分。它回答一个具体问题:模型前向一次要 200 毫秒,但控制循环要求 30 Hz,怎么办?
inference/ 里的文件名几乎就是答案:chunk_settings.py(一次预测多少个动作)、prediction.py(预测)、execution.py(执行)、sync.py(同步模式)、rtc.py(实时分块)、latency.py(延迟估计)、policy_runner.py(跑策略的进程/线程)、dispatch.py、contracts.py(输入输出契约)。
核心思路是预测与执行解耦:策略一次吐出未来 K 步的动作块,执行端按控制频率逐步消费;与此同时策略已经在算下一块。当新块到达时,用一个插值或重叠平均把接缝抹平(rollout/ 里的 ring_buffer.py 与 strategies/ 就是干这个的)。
rollout/ 则是「把策略接到真机器人上」的编排层:robot_wrapper.py(包装硬件)、controller.py(控制循环)、planner.py(任务规划)、interactive.py(人工干预)、status.py(状态机)。transport/ 与 remote_inference/ 负责跨进程/跨机器通信——把大模型放在带显卡的服务器上,机器人端只跑一个轻客户端。
绝大多数「模型在离线评测里 90%,上真机只有 40%」的案例,问题不在模型,而在这里:动作块接缝不平滑、延迟没补偿、控制频率抖动。读一遍 inference/ 比调三天超参有用。
1.5.7其余模块
envs/:把 LIBERO、MetaWorld 等基准包装成统一接口,供lerobot-eval调用。也支持通过 EnvHub 发布自定义环境。rl/与rewards/:强化学习算法与奖励模型的实现,配合hil_processor做人在环训练。annotations/:数据标注(语言分段、技能标签),对应lerobot_annotate。data_processing/与transforms/:更底层的图像/张量变换,被 processor 调用。distributed/与optim/:多卡训练、优化器与学习率调度。jobs/:把任务提交到 HF Jobs(云端跑训练),hf.py是 Hub 相关封装。common/:control_utils.py(控制循环工具)、train_utils.py(训练工具)、trackio_utils.py(实验记录)。templates/:新机器人/新策略的脚手架模板——第四章会用到。
1.6一次训练的数据流
把模块串起来看,整条链路只有四个阶段。每个阶段之间传递的不是「代码」,而是落在磁盘上的产物——这一点很重要,因为产物可以被检查、被替换、被单独复现。
值得说明的是第二阶段内部发生了什么。一个 batch 的组装是这样的:
LeRobotDataset按frame_index取出该帧的 Parquet 行(状态、动作、任务索引)与对应的视频帧(解码后是 HWC 张量)。- 根据
meta/stats.json里的统计量做归一化,把状态和动作压到零均值附近。 - 把绝对动作按配置转成相对增量(如果策略需要)。
- 语言指令经 tokenizer 变成 token id,补齐到固定长度。
- 所有张量搬到 GPU,统一 dtype,reshape 成
[B, T, ...]。 - 策略前向、算损失、反向、更新。
第 2 到第 5 步全部由 processor 完成,而不是写在策略内部。这是 LeRobot 与「论文仓库」最大的结构性差异:论文仓库把这些变换写死在 model.py 里,换个数据集就要改代码;LeRobot 把它抽出来变成可配置的链条,换个数据集只改配置。
1.7四条设计哲学
读到这儿,你已经见过全部零件。最后用四条原则把它们收拢——这四条不只解释 LeRobot,也解释了过去两年所有活得好的机器人开源项目。
01配置即 API,而不是装饰
用 dataclass 而不是 YAML,用 --policy.type 而不是 --config my.yaml。表面上是语法选择,实质上是把「可配置的东西」和「代码结构」对齐:每个可调项都必须对应一个明确归属的类。副作用是配置能随 checkpoint 一起保存,于是复现性变成了默认属性而不是额外工作。
02一切皆 dict[str, Tensor]
观测是字典,动作是字典。这个决定让「换机器人」从改代码变成改配置:只要新机器人的键名和老机器人一致,上层完全不用动。代价是失去了静态类型带来的安全感——键名拼错要到运行时才报错。这是 LeRobot 里最常见的一类 bug,也是为什么它提供了 rename_processor 和特征校验。
03纯 PyTorch,不绑框架
三十个策略全部用原生 PyTorch 写,不依赖某个训练框架的抽象。这让代码更啰嗦(你要自己写训练循环),但换来两件事:调试时 stack trace 是直的;任何人读 modeling_*.py 都能对上论文公式。对基础设施项目来说,可读性比简洁性重要。
04格式优先于模型
这是最重要的一条。团队把最多的工程投入放在了 datasets 而不是 policies:格式、流式、合并、统计、卡片、迁移脚本。因为模型会被超越,格式会沉淀。两年后 π0 可能没人用了,但那时候的数据集大概率还叫 LeRobotDataset。
判断一个基础设施项目能不能活下来,看它把工程量花在哪:花在「接入更多模型」上的,会随模型一起过时;花在「让别人更容易贡献数据」上的,会随数据一起增值。
具身智能的原理与趋势
Why Robots Are Hard to Teach
监督学习假设数据是独立同分布的。机器人不满足这个假设——它的每一个动作都会改变下一个输入,所以错误会累积,而不是被平均掉。
2.1为什么机器人学习比图像分类难
如果你做过视觉模型,第一次接触机器人策略训练会有一种强烈的不适感:所有指标看起来都很好,真机上一塌糊涂。训练 loss 降到了 0.01,验证集上动作的 L2 误差只有几毫米,但机械臂在空中画出诡异的弧线,然后撞到桌子。
这不是调参问题,是问题结构本身不同。四个根本差异:
1分布会移动,而且是被你自己推动的
图像分类里,测试集的分布和训练集不同,但至少是固定的。机器人不一样:策略在状态 s 采取动作 a,环境转移到 s',而 s' 的分布取决于策略本身。你在训练时看到的状态分布,和部署时遇到的状态分布,是同一个策略的两副面孔。一旦策略在某个状态下出错,它就会进入训练数据里从未出现过的区域,然后错得更离谱。这个现象叫协变量偏移(covariate shift),在机器人里它有一个更狠的名字:复合误差。
2错误会累积,不会被平均
分类错一帧,下一帧还有机会;控制错一步,后面全歪。一条 10 秒、30 Hz 的轨迹有 300 步,每步 99% 的正确率,整条轨迹完全成功的概率是 0.99³⁰⁰ ≈ 5%。这就是为什么论文里 90% 的单步精度毫无意义,而「任务成功率」才是唯一指标。
3同一个状态有多个正确答案
从左边绕还是右边绕,先抓把手还是先扶杯身——都行。传统回归损失(MSE)面对这种多模态分布,会输出两个答案的平均,而平均值往往既不是左也不是右,是撞在中间。这是 Diffusion Policy 出现的直接原因,也是为什么现代策略几乎不再直接用 MSE 回归动作。
4数据贵得离谱
ImageNet 有 1400 万张图,采集成本约等于零(网上本来就有)。机器人没有「互联网规模的动作数据」:每一条示范都要一个人、一台机器、一段时间。行业公认的量级是:要达到 GPT-3.5 那种通用性,需要一亿小时的真实交互;而目前全球有效数据只有几十万小时。
2.2形式化:其实就是一个闭环
把上面这些说清楚,只需要一张图。机器人控制是一个部分可观测马尔可夫决策过程(POMDP),但在模仿学习的语境下,它可以简化成最朴素的形式:
用公式写就是最小化负对数似然:
L(θ) = − E(o,a)~D [ log πθ(a | o) ]
看起来和图像分类的交叉熵一模一样。区别在于:分类的 a 是一个离散标签,机器人这里的 a 是一个连续的、多维的、有时序结构的向量——一台六轴臂加一个夹爪就是 7 维,双臂就是 14 维,人形可能是 40 维以上。「怎么表示这个 a」是整个领域最核心的工程问题之一,下一节专门讲。
2.3模仿学习三代:从回归到生成
过去八年,机器人模仿学习只发生了两次范式转移。理解这两次,你就理解了 LeRobot 里为什么会有这么多策略实现。
第一代行为克隆(BC):直接回归
最简单的方法:一个 CNN 提图像特征,拼上本体状态,MLP 输出动作。损失用 MSE。
它的问题是上一节第 2、3 条的直接后果:MSE 面对多模态动作会输出平均解,且复合误差无人处理。业界的补救办法是DAgger:让策略自己去跑,跑偏了由人类接管纠正,把纠正后的 (o, a) 加回数据集重训。理论上正确,实践上很贵——每个人类纠正都要实时介入。
第二代动作块 + 生成模型:ACT 与 Diffusion Policy
2023 年两个工作几乎同时给出了两个方向的解法,它们构成了今天所有策略的底座。
ACT(Action Chunking with Transformers) 的思路是「少做决定」:不预测下一步动作,而是一次预测未来 100 步(一个 chunk)。这样复合误差的累积次数从 300 次降到 3 次。为了处理多模态,它引入了一个 CVAE 结构——训练时用一个编码器从完整动作序列推断隐变量 z,推理时把 z 置为零(取分布的均值)。执行时用 temporal ensembling 把相邻 chunk 的重叠部分加权平均,抹平接缝。
Diffusion Policy 的思路是「把动作生成当成图像生成」:把动作序列看作一条一维的「轨迹图像」,用 DDPM 从噪声逐步去噪出动作。多模态问题被天然解决——不同的噪声种子会收敛到不同的有效解,而不是平均。代价是推理需要多步去噪,慢。
在单任务、中等精度、几百条数据的场景下,ACT 训练快(单卡几小时)、推理快(一次前向)、调参少。它不是最强的,但它是性价比最高的基线。任何新方法如果打不过一个认真调过的 ACT,就还没有到值得部署的程度。
第三代流匹配(Flow Matching):一步到位的生成
扩散模型要迭代几十步,太慢。流匹配学的是一个速度场:从噪声到动作的直线路径上,每一步该往哪走。训练目标更简单(回归速度场而不是噪声),推理可以用很少的步数(4 到 10 步)就得到高质量样本。π0 系列用的就是这套。
工程上还有一个更激进的变体:π0-FAST 把动作离散化成 token,用自回归的方式逐 token 生成。这让动作生成可以直接复用语言模型的解码器与 KV cache,但牺牲了连续性。LeRobot 里 pi0_fast 就是这一类。
| 代际 | 代表 | 处理多模态 | 推理开销 | 适用 |
|---|---|---|---|---|
| BC | MLP / ResNet 策略 | 不能,会平均 | 极低 | 单一解、高精度、数据量大 |
| ACT | ACT · VQ-BeT | CVAE 隐变量 | 低(一次前向) | 单任务、几百条演示 |
| 扩散 | Diffusion Policy | 天然支持 | 高(多步去噪) | 多解任务、精度要求高 |
| 流匹配 | π0 · π0.5 · SmolVLA | 天然支持 | 中(4—10 步) | 通用操作、跨本体 |
2.4动作表示之战:一个被低估的关键设计
同一份演示数据,用不同的动作表示喂给模型,学出来的东西完全不同。这个问题在论文里常常藏在附录,但在工程上是第一决策。
| 表示 | 形式 | 优点 | 代价 | LeRobot 中的对应 |
|---|---|---|---|---|
| 绝对关节角 | 7 维(6 关节 + 夹爪) | 简单、无歧义、可直接下发 | 绑定本体;换个臂就废;对校准误差敏感 | 原始数据集默认 |
| 绝对末端位姿 | 位置 3 + 旋转 6D | 与关节结构无关 | 依赖逆运动学求解,可能无解 | 需自行配置 |
| 相对末端增量 | Δ位置 + Δ旋转 | 跨本体能力最强;数值小、易归一化 | 误差会累积;需要本体状态作为基准 | relative_action_processor |
| 增量动作块 | [K, 7] 的相对序列 | 兼顾时序平滑与跨本体 | 需要处理 chunk 接缝 | delta_action_processor + inference |
为什么「相对增量」会成为主流?因为它是目前唯一能同时满足三个约束的表示:可跨本体(不依赖关节数量)、可混训(不同机器人的数据可以放在同一个 batch 里)、可增量部署(每次只走一小步,出错也小)。
但它有代价,而且这个代价经常被忽略:相对动作的误差会累积。每步偏 0.5 毫米,走 100 步就偏 5 厘米,而且没有任何机制把它拉回来。解法通常有两层:一是执行端有绝对位置的下位控制(舵机自身闭环),二是策略的观测里必须包含当前末端状态,让它「知道自己偏了」。
一个实用的判断:如果你只打算用一台机器人,绝对关节角最简单;如果你打算用别人的数据、或者把模型迁移到第二台机器人,从第一天就该用相对末端增量。
2.5VLA:把语言模型接进控制回路
2024 年之后,机器人策略的主线变成了「拿一个预训练的视觉语言模型(VLM)当主干,再接一个动作输出头」。这个范式叫 VLA(Vision-Language-Action)。
动机很直接:VLM 已经在互联网规模的图像-文本对上学会了「杯子是什么」「把手在哪」「这句话指哪个物体」。这些是语义先验,而机器人数据的瓶颈恰恰是样本量。用 VLM 初始化,等于把几十亿张图的知识免费搬进了策略里。
三种「接头」方式
- 离散 token 头:把每个动作维度离散成 256 个 bin,当成词表里的 token,用自回归解码。代表是 RT-2、π0-FAST。优点是复用语言模型全套设施;缺点是量化误差,精细任务上会抖。
- 扩散头:VLM 出特征,后面接一个扩散模型生成连续动作。代表是 Diffusion Policy 的 VLM 版本、GR00T 早期版本。优点是连续、平滑;缺点是慢。
- 流匹配头:VLM 出特征,接一个小的「动作专家」网络,用流匹配生成动作块。代表是 π0、π0.5、SmolVLA。目前是主流。
为什么要「双塔解耦」
π0 之后几乎所有人都采用了一个结构:视觉语言塔(大、预训练、冻结或低秩微调)与动作专家塔(小、从零训练、全参更新)分离,中间用共享注意力交换信息。
原因有两个。第一是防止灾难性遗忘:如果让整个 VLM 全参微调去学「怎么拧瓶盖」,它会把「什么是瓶盖」这部分语义知识覆盖掉。第二是参数效率:动作专家通常只有几亿参数,而主干有几十亿,冻结主干能让训练显存降一个档。
LeRobot 里的体现是:smolvla(450M,能在消费级显卡上跑)、pi05(3.6B)、groot(3B,Cosmos-Reason 主干 + DiT 头)走的是同一条路,只是主干与头的规模不同。
被低估的敌人:延迟
一个 3B 的 VLA,在单张消费级显卡上前向一次要 100 到 300 毫秒。而机械臂的控制频率是 30 到 100 Hz,也就是每 10 到 33 毫秒要一个新指令。模型比控制器慢一个数量级。
解法不是「让模型变快」,而是改架构:一次预测未来 K 步(动作块),执行端按控制频率逐步消费,模型在后台算下一块。这就是第一章提到的 inference/ 层的全部意义,也是 rtc.py(real-time chunking)存在的原因。新块到达时,旧块还没走完,两者的重叠部分要做加权融合——这个融合策略的细节,直接决定了真机上动作是否平滑。
「参数量越大效果越好」在 VLA 上不成立。SmolVLA 用 450M 参数在多个基准上追平 3B 级模型,原因是它的训练数据经过了精心的筛选与配比。在具身智能里,数据质量对性能的边际贡献远大于参数规模——这也是为什么 LeRobot 把工程量押在数据集上。
2.6数据的三个难题
前面所有方法论的讨论,最后都撞在同一堵墙上:数据。而「数据不够」这个说法太笼统,它实际是三个不同的问题。
难题一规模:差两到三个数量级
语言模型靠互联网文本,视觉模型靠互联网图片,两者都是「本来就有」的副产品。机器人动作数据没有这样的来源——每一条都要人花时间。目前全球有效的高质量具身数据在几十万小时量级,而行业估算需要一亿小时。这个缺口不可能靠「多建几个数采中心」补上,因为那是一条线性增长的路。
难题二本体:数据是绑在硬件上的
一台 Franka 采的数据,换一台 SO-101 就不能直接用:关节数不同、连杆长度不同、相机位置不同。解法有两条——一是用相对动作表示降低绑定程度(见 2.4),二是用重定向(retargeting)把动作映射到新本体。两条都不完美,而且都需要额外工作。
难题三长尾:真实世界的多样性在别人手里
实验室能复刻的场景是「样板间」:一张桌子、几个固定物体、稳定光照。而真实世界分布在酒店客房、冷链仓库、理发店、汽修厂里。这些场景你租不到,也搭不出来。这就解释了过去一年为什么会出现「手持采集设备」和「众包数据平台」——把采集权从机构手里放出去,是唯一能触达长尾的方式。
| 路线 | 代表 | 单位成本 | 真实度 | 能解决哪个难题 |
|---|---|---|---|---|
| 真机遥操作 | ALOHA · DROID · SO-101 | 高 | 最高(真实动力学) | 精度、接触丰富任务 |
| 手持无本体 | UMI · Grabette | 低 | 中(缺力反馈) | 规模、长尾 |
| 人类第一视角 | EgoDex(Vision Pro) | 极低(被动) | 低(人手≠机器人手) | 规模、语义先验 |
| 仿真合成 | RoboTwin · Genie Sim | 极低(算力) | 低(物理近似) | 规模、可控评测 |
2.72026 年的六个趋势
把近一年的论文与开源发布放在一起看,有六条线正在收敛。它们也是你判断「下一个值得学的技术」的依据。
趋势一架构已经收敛:VLM 主干 + 独立动作专家
从 π0 到 GR00T 到 SmolVLA 到 X-VLA,结构惊人地一致:一个大主干负责理解,一个小子网负责出动作,中间用注意力交换信息。差异只剩在动作头类型(流匹配 / 扩散 / 离散 token)和数据配比上。这意味着「设计一个新架构」的边际回报正在下降,而「准备一份别人没有的数据」的回报在上升。
趋势二推理与执行彻底解耦
动作块 + 异步推理 + 实时分块(RTC)从「优化技巧」变成了「默认架构」。LeRobot 专门为此建了 inference/ 与 remote_inference/ 两个包,说明这已经是基础设施问题,不是模型问题。
趋势三世界模型从「生成视频」转向「预测后果」
早期的世界模型目标是把视频生成得像;现在的目标是用它做动作条件预测——给定动作,未来状态会怎么变。这带来两个用途:一是作为策略的辅助损失(学到物理直觉),二是合成训练数据。LeRobot 里 World Models 这一整类(VLA-JEPA、LingBot-VA、FastWAM、Long-WAM 等)就是这条线。
趋势四奖励模型成为独立组件
强化学习在真机上最大的障碍是「没有奖励函数」。人工设计奖励脆弱,学一个判别器又容易奖励黑客。把奖励模型单独做成一类可复用的组件(SARM、TOPReward、Robometer),让「评价」和「优化」解耦,是近一年很务实的进展。
趋势五失败数据进入一等公民
过去的数据集只收成功示范。2026 年几个大版本都改了:有的把「抓空、滑落、碰撞」单独做成一期主题,有的用「人工干预 + 回滚」把失败轨迹转成成对的偏好样本做后训练。只训成功态的模型,学不会世界怎么拒绝它。
趋势六评测正在标准化,但还没统一
LIBERO、MetaWorld、RoboTwin 成了事实上的公共基准,LeRobot 用 envs/ 把它们包成统一接口,还用 EnvHub 允许社区发布新环境。但「仿真分数能不能预测真机成功率」仍然没有公论——目前最诚实的做法是同时报仿真与真机,并说明真机的测法。
具身智能的算法层已经收敛到「够用」的程度:一套 VLM + 动作专家的架构,配上动作块与异步推理,就能覆盖大部分操作任务。真正没有收敛的是数据——规模、本体、长尾三个问题都还开着。所以在 2026 年,把时间投在「怎么采到别人没有的数据」上,比投在「再设计一个动作头」上回报更高。
动手搭建
From Screws to a Trained Policy
这一章可以照着做。但请先读完 3.1,因为它决定了你要买什么——买错硬件的成本,远高于配错环境的成本。
3.1三条路线,先选一条
很多人一上来就问「买哪台机器人」。这个问题问早了。先确定你要做的是哪件事:
| 你的目标 | 该走的路 | 投入 | 多久看到结果 |
|---|---|---|---|
| 只想看看这东西是什么 | 3.9 无硬件路线:读公开数据集 + 跑仿真评测 | 0 元 | 一个周末 |
| 要训一个能抓东西的策略 | SO-101 主从臂 + 两个相机 | 1,600—3,000 元 | 一周 |
| 要做研究、跑基准、发论文 | 先用仿真(LIBERO / RoboTwin),再考虑真机 | 一块 GPU | 两周 |
| 要把自己的设备接进来 | 写一个 Robot 子类(第四章 4.3) | 0 元 + 你的硬件 | 三到五天 |
本章主线走第二条:SO-101。选它的理由不是性能好,是它把「标准」这件事做到了极致——结构件开源、舵机型号固定、社区里有几千人用同一套东西采数据,出问题能搜到答案。
3.2硬件清单
SO-101 是一套主从结构:你用一只手带动「主臂」,另一只手(严格说是另一台同构的臂)作为「从臂」跟随。主臂不需要电机驱动,只读角度;从臂才出力。所以两臂的舵机数量相同,但主臂的舵机工作在「读取」模式。
| 物料 | 数量 | 说明 |
|---|---|---|
| 结构件(3D 打印) | 1 套 | PLA 或 PETG。打印精度直接影响回差,建议 0.2 mm 层高、40% 填充。 |
| Feetech STS3215 舵机 | 12 个 | 主臂 6 + 从臂 6。带磁编码器,可读绝对位置——这是它能断电续位的前提。 |
| 舵机控制板(USB 转总线) | 2 块 | 每臂一块。板上有电平转换与电源输入。 |
| 电源 | 1—2 个 | 5V / 5A 以上。电压不足会表现为「舵机抖动」或「中途掉线」,很容易误判成软件问题。 |
| USB-C 数据线 | 2 条 | 必须是数据线,不能是充电线。这是新手第一大坑。 |
| USB 摄像头 | 2 个 | 一个装腕部(看夹爪),一个装全局(看桌面)。建议 640×480 / 30 fps 起步。 |
| 桌面夹具 / 配重 | 1 套 | 不打夹具的臂会在快速动作时整体位移,数据全废。 |
| 螺丝与轴承包 | 1 套 | 通常随结构件一起买。 |
成本区间:整套约 1,600 元(自行采购舵机 + 打印)到 3,000 元(含打印服务的成品套件)。第三方套件从 199 到 500 美元不等,差异主要在舵机版本与结构件质量。价格波动大,下单前先看仓库的硬件文档。
结构件可以自己打印,能省几百块。但舵机不要买便宜替代型号:总线协议、编码器分辨率、堵转扭矩任何一项不同,都会导致校准漂移或夹爪夹不住东西,而这些问题在软件层完全看不出来。电源也不要省,供电不足造成的间歇性掉线极难排查。
3.3组装与接线:三个必须做对的细节
机械装配按官方图纸走即可。这里只讲三件图纸上不会强调、但会决定你后面两周是否顺利的事。
01总线是菊花链,不是星型
六个舵机串在同一条总线上:控制板 → 舵机1 → 舵机2 → … → 舵机6。每个舵机有两个接口,进和出。接反了不会烧,但不通。上电前先用手拨一下每个关节,确认机械上能自由转动(主臂必须能,从臂在断电时也能)。
02舵机 ID 必须一条一条设
出厂 ID 都是 1,六个串在一起会冲突。正确做法是每次只接一个舵机,用 lerobot-setup-motors 把它改成目标 ID,断电,再接下一条。这一步枯燥但不可跳过——ID 错了的表现是「某个关节乱转」,而不是报错。
lerobot-setup-motors --robot.type=so101_follower --robot.port=/dev/ttyACM0
03主臂的舵机要设成「只读」
主臂不输出力矩,否则你会感觉像在推一堵墙,而且反向电流可能损伤控制板。配置里通过 --teleop.type 选择 so101_leader 就自动处理了——这也是为什么主从必须用不同的 type,即使它们是同一套硬件。
3.4软件环境
先确认 Python 版本。v0.6.1 要求 Python ≥ 3.12,这一点和大量旧教程(写着 3.10)不同。用 3.10 会直接装不上。
python --version # 需要 3.12 或更高 pip install "lerobot[core_scripts,feetech]" lerobot-info # 打印版本、extras、检测到的设备
extras 是按能力分的,不是按硬件分的。选错会导致「命令存在但导入失败」:
| extra | 给你的东西 | 什么时候需要 |
|---|---|---|
| dataset | 读数据集、视频解码、Hub 下载 | 几乎所有场景都要 |
| training | 训练循环、加速、实验记录(trackio) | 要训模型 |
| hardware | 串口、键盘监听、配置比对 | 接真机 |
| viz | Rerun / Foxglove 可视化 | 调试数据流 |
| core_scripts | record / replay / calibrate / teleoperate 全套 | 做采集 |
| evaluation | 评测框架(还需环境与策略各自的 extra) | 跑基准 |
| feetech / rustypot / can | 对应总线的驱动 | 按你的舵机型号 |
如果要跑 VLA,还要额外装对应策略的 extra(比如 lerobot[pi] 之于 π0 系列),并注意 transformers 的版本被钉在一个较窄的区间里——这是经常导致「昨天还能跑,今天 import 失败」的原因。
3.5五步跑通全流程
这五步是 LeRobot 的「主路径」。每一步都产出可检查的东西,不要跳步。
STEP 1找端口
lerobot-find-port
# 拔掉设备再插上,观察新出现的是哪个,通常是 /dev/ttyACM0、/dev/ttyACM1
# macOS 是 /dev/tty.usbmodemXXXX
sudo usermod -aG dialout $USER # Linux:把当前用户加入串口组,重新登录生效
权限问题占新手报错的一半。表现是 Permission denied: '/dev/ttyACM0',看起来像硬件坏了,其实只是没进组。
STEP 2校准
lerobot-calibrate --robot.type=so101_follower --robot.port=/dev/ttyACM0 --robot.id=my_arm lerobot-calibrate --teleop.type=so101_leader --teleop.port=/dev/ttyACM1 --teleop.id=my_leader
校准做的事:让每个关节走到两个极限位置,记录编码器读数与机械限位的映射,写进 ~/.cache/lerobot/calibration/。--robot.id 就是这条校准记录的键,之后所有命令都必须带同一个 id,否则会读到别的机器的校准文件,表现为「动作幅度不对」。
STEP 3遥操
lerobot-teleoperate \ --robot.type=so101_follower --robot.port=/dev/ttyACM0 --robot.id=my_arm \ --teleop.type=so101_leader --teleop.port=/dev/ttyACM1 --teleop.id=my_leader \ --display_data=true
先别录数据,先练。目标是能连续十次拿起同一个物体而不碰倒旁边的东西。手不稳的时候采的数据,是在给模型喂噪声——而且你事后无法从 loss 上看出来。
STEP 4录制
lerobot-record \ --robot.type=so101_follower --robot.port=/dev/ttyACM0 --robot.id=my_arm \ --robot.cameras='{top:{type:opencv,index_or_path:1,width:640,height:480,fps:30}, wrist:{type:opencv,index_or_path:0,width:640,height:480,fps:30}}' \ --teleop.type=so101_leader --teleop.port=/dev/ttyACM1 --teleop.id=my_leader \ --dataset.repo_id=${HF_USER}/so101_pick_cube \ --dataset.num_episodes=30 \ --dataset.single_task="pick the red cube and put it in the bowl" \ --dataset.streaming_encoding=true \ --display_data=true
录制过程中键盘就是编辑器:→ 保存这一条并进入下一条,← 作废重录,ESC 结束并编码上传。这条交互设计比大多数标注工具都好用——它把「筛选」放进了采集过程,而不是留到事后。
关于数量:一个简单的抓放任务,30 到 50 条通常够训出一个能用的 ACT。但关键不是条数,是变化:每次换物体位置、换一点光照、换一点相机角度。三十条一模一样的演示,等于一条数据重复三十遍。
STEP 5训练
lerobot-train \ --dataset.repo_id=${HF_USER}/so101_pick_cube \ --policy.type=act \ --output_dir=outputs/train/act_pick_cube \ --job_name=act_pick_cube \ --policy.device=cuda \ --steps=20000
单卡 RTX 4090 上,ACT 训 2 万步大约几十分钟到两小时(取决于分辨率与 batch size)。换策略只改 --policy.type——这是 LeRobot 最舒服的一点:数据管线完全不变。lerobot-train 会把配置一起存进 checkpoint,所以「这个模型是用什么参数训的」不需要你另外记。
3.6数据集长什么样
录完之后,~/.cache/huggingface/lerobot/${HF_USER}/so101_pick_cube/ 下会是这样的结构:
四个设计点值得注意:
- 视频与表格分离。Parquet 里只有数值,图像在 MP4 里,两边靠
episode_index+frame_index对齐。这样随机采样一帧只需解码几百毫秒的视频片段。 - chunk 分片。数据量大时按 chunk 组织,避免单文件上千兆导致读取变慢。
- stats.json 预计算。归一化参数在录制时就统计好。这是「边下边训」能成立的前提,也让训练与推理的行为一致。
- features 是 schema。
info.json里的features定义了所有字段的名字、类型、维度。合并两个数据集前必须先对齐 features,否则会得到一个静默错误的混合体。
想看一眼数据长什么样,不必写代码:
lerobot-dataset-viz --repo-id=${HF_USER}/so101_pick_cube --episode-index=0
3.7评测与部署
仿真评测
先把模型放到标准基准上跑一轮,得到一个可与他人比较的数字:
lerobot-eval \ --policy.path=${HF_USER}/act_pick_cube \ --env.type=libero --env.task=libero_object \ --eval.n_episodes=10
注意:LIBERO 上的分数和你自己的任务没有直接关系,它的价值是确认模型没有训坏,以及给你一个横向参照。
真机部署
两种方式,取决于模型大小:
# 方式一:模型就在本机,直接跑 lerobot-rollout --policy.path=${HF_USER}/act_pick_cube \ --robot.type=so101_follower --robot.port=/dev/ttyACM0 # 方式二:模型在带显卡的服务器上,机器人端做客户端 lerobot-policy-server --policy.path=${HF_USER}/pi05_finetuned --port=8000
第二种就是第一章说的「推理与执行解耦」。当模型前向要 200 毫秒、控制周期只有 33 毫秒时,你必须把推理放到另一个进程甚至另一台机器上,让执行端靠动作块缓冲顶住。
相机配置必须和训练时完全一致——分辨率、帧率、哪个 index 对应哪个视角。模型不认识「顶视图」这个概念,它只认识张量里的第几个通道。顺序一换,动作就全乱,而且不会报错。
3.8故障排查
下面这张表覆盖了社区里出现频率最高的十二类问题。建议先按「现象」查,不要按「怀疑」查。
| 现象 | 最可能的原因 | 处理 |
|---|---|---|
| Permission denied /dev/ttyACM* | 用户不在串口组 | sudo usermod -aG dialout $USER,重新登录 |
| 找不到端口 | 用的是充电线 | 换一条确认能传数据的 USB-C 线 |
| 某个关节乱转 | 舵机 ID 冲突 | 单独接该舵机重设 ID |
| 动作幅度不对 / 方向反了 | 校准文件不匹配(id 不一致) | 检查 --robot.id,重新校准 |
| 舵机间歇性掉线 | 供电不足 | 换 5V/5A 以上电源,缩短总线 |
| 录的视频全黑 | 相机 index 选错 / 被占用 | lerobot-find-cameras 确认 index |
| 训练 loss 不降 | stats 缺失或动作维度不匹配 | 检查 info.json 的 features 与 stats |
| 真机上动作乱飞 | 相机顺序与训练时不一致 | 逐项对齐 cameras 配置 |
| 显存不足 | 模型太大或 batch 太大 | 减 batch、开梯度检查点、LoRA 微调主干 |
| 视频解码报错 | ffmpeg / torchcodec 平台 wheel 缺失 | 按 pyproject 注释选对应版本,或回退到 PyAV 解码 |
| 推理频率跟不上 | 同步推理 | 改用 rollout + policy server,配动作块 |
| 合并数据集后字段错位 | features 不一致 | 先用 rename_processor 对齐再 merge |
3.9零硬件路线
如果你现在一分钱都不想花,仍然可以完整走一遍除了「真机部署」之外的所有环节。
pip install "lerobot[dataset,training,evaluation]" # 1. 拿一份公开数据集的调试子集(100 条,约 2 GB) huggingface-cli download lerobot/droid_100 --repo-type dataset --local-dir ./droid_100 # 2. 看一眼它长什么样 lerobot-dataset-viz --repo-id=lerobot/droid_100 --episode-index=0 # 3. 训一个基线 lerobot-train --dataset.repo_id=lerobot/droid_100 --policy.type=act --steps=5000 # 4. 在仿真基准上评测一个公开权重 lerobot-eval --policy.path=lerobot/pi0_libero_finetuned \ --env.type=libero --env.task=libero_object --eval.n_episodes=10
这套流程跑完,你会得到三样东西:一个能复现的 checkpoint、对数据格式的肌肉记忆、以及对「仿真分数有多不可靠」的直观感受。第三样最值钱——它会让你在将来看到任何「某模型在某基准上 95%」的宣称时,先问一句「真机怎么测的」。
如何参与 LeRobot
From User to Contributor
开源项目的贡献不是从「提 PR」开始的,是从「你遇到的问题别人也会遇到」这个判断开始的。
4.1五种角色,五种进入方式
「参与」这个词很容易让人想到写代码。实际上这个项目的贡献面比代码宽得多,而且最稀缺的那部分恰好不是代码。
| 角色 | 你做的事 | 门槛 | 稀缺程度 |
|---|---|---|---|
| 用户 | 用、报 issue、在 Discord 回答别人的问题 | 会用 | 不稀缺,但有用 |
| 数据贡献者 | 采自己的场景,按格式上传到 Hub | 有设备 | 最稀缺 |
| 硬件适配者 | 把自己那台机器人接进来(核心或插件) | 会写 Python | 高 |
| 策略作者 | 复现一篇论文,加成 policies/ | 懂论文 + 工程 | 中 |
| 维护者 | 审 PR、定接口、修 CI | 长期投入 | 极稀缺 |
注意到一个反直觉的地方:数据贡献比代码贡献更稀缺。因为代码谁都能写,但「别人没有的场景」只有你有。这也是第三章反复强调「先想清楚你要采什么」的原因——它同时是你做研究和使用开源的最优策略。
4.2最小贡献:上传一个数据集
这是投入产出比最高的一件事:不需要改一行代码,但会永久留在公共资产里。
第一步把数据采到「能复现」的程度
- 相机配置写清楚:几个、装在哪、分辨率、帧率。
- 任务描述唯一可判:「把红方块放进左边的碗」,而不是「整理一下」。
- 每条 episode 之间有变化:物体位置、光照、背景至少各变三档。
- 保留失败样本。可以单独放一个子集,但不要全删——它的价值正在被重新认识。
第二步命名与结构
仓库里 datasets/card_template.md 是官方卡片模板,datasets 包还会自动生成基础字段。命名建议遵循社区的默认习惯:{机器人}_{任务}_{场景},全小写、连字符分隔。不要在名字里塞版本号和日期,版本靠 git tag 与 Hub 的 revision 管理。
第三步写卡片,这是真正的贡献
一张好的数据集卡片应该让陌生人不问你任何问题就能用起来。必须包含:
- 硬件:机器人型号、舵机型号、相机型号与安装位置。
- 任务定义与成功判据(怎么算成功,这一条 90% 的数据集都没写)。
- 规模:episode 数、总帧数、平均时长。
- 采集方式:遥操作 / 手持 / 仿真;谁采的、采了多久。
- 已知问题:哪些场景没覆盖、哪些 episode 质量差。
- 许可:能否商用、能否再分发、要不要署名。
如果你的数据集卡片里没有「已知问题」这一节,那它大概不是一份诚实的数据集。所有真实采集都有缺陷,写出来比藏起来对使用者更有价值。
4.3接入一台新机器人
LeRobot 内置了十余种机器人,但真实世界里的机械臂远不止这些。接入一台新机器人是整个项目里最受欢迎的一类贡献——每多一种硬件,生态的覆盖面就宽一圈。
目录结构
必须实现的四件事
抽象基类在 robots/robot.py。子类至少要给出 connect、get_observation、send_action、disconnect,另外还有一个常被漏掉的 observation_features / action_features——它告诉数据层「这台机器人的观测有哪些字段、什么形状」。漏了它,录制时会直接失败。
from lerobot.robots.robot import Robot class MyRobot(Robot): config_class = MyRobotConfig name = "my_robot" def connect(self): ... # 打开总线,使能舵机,读初始位姿 def get_observation(self): # → {"shoulder_pan.pos": tensor, "top": image, ...} ... def send_action(self, action): # 写入目标位置,处理限位与超时 ...
三个容易踩的坑
- 键名要和现有约定一致。
<关节名>.pos、相机直接用名字。键名不一致的数据集无法和别人混训,这条比代码风格重要得多。 - 单位统一。舵机常用「刻度值」,策略期望「弧度或米」。换算放在机器人层,不要放到 processor 里——processor 是共享的。
send_action要幂等且非阻塞。控制循环在 30 Hz 上跑,任何阻塞调用都会拖垮频率,进而让动作块接缝变大。
接完之后,别忘了同步做三件事:在 robots/__init__.py 注册、在 docs/ 补一页硬件说明、在 tests/ 加一个不依赖硬件的接口测试(用 mock 总线)。没有测试的硬件 PR 基本不会被合,因为维护者无法验证。
4.4加一个新策略
如果你复现了一篇论文,把它加进 policies/ 是最有价值的落点。结构比机器人复杂一些:
接口契约
策略类需要提供两样东西:训练时能吃到 batch 并返回 loss(或可直接反传的 dict),推理时能接受单帧观测并返回动作块。policies/factory.py 负责按 --policy.type 实例化,pretrained.py 负责按 Hub 名加载。
最容易出问题的是动作块的时间维度。LeRobot 统一用 [B, K, A](batch、chunk 长度、动作维度)的约定,所有涉及 chunk 的工具(chunk.py、rtc.py、rollout 的环形缓冲)都依赖这个形状。如果你的模型内部用的是别的排布,必须在 forward 出口处转回来。
还需要做的
- 在
policies/__init__.py与 factory 里注册类型名。 - 声明它需要的 processor 链(归一化?相对动作?tokenizer?)。这一步决定它能否直接吃标准数据集。
- 写
docs/source/policy_my_policy_README.md:论文链接、显存需求、训练时长、已知失效场景。 - 加测试:至少一个前向 shape 测试,一个在极小数据集上的过拟合测试(loss 应该能降到接近零——降不下去说明实现有 bug)。
不是你的模型刷了多高的分,而是它能不能在别人的机器上跑起来。判断标准很朴素:别人 pip install 之后,照着你的 README 复制三条命令,能不能得到一个 checkpoint。做不到的话,分数再高也不会被合。
4.5更轻的路:插件机制
如果你不想改核心仓库,或者你的硬件太小众不适合进主库,LeRobot 提供了一套插件发现机制:任何已安装的、以特定前缀开头的 Python 包,都会被自动导入。
lerobot_robot_<name> # 自定义机器人 lerobot_teleoperator_<name> # 自定义遥操设备 lerobot_camera_<name> # 自定义相机/传感器
装好之后,插件注册的 type 就能直接在 CLI 里用,不需要改 LeRobot 一行代码:
pip install lerobot_robot_myarm lerobot-record --robot.type=myarm --teleop.type=so101_leader \ --dataset.repo_id=${HF_USER}/my-dataset
这条路的价值在于把「贡献」和「审核」解耦了:项目维护者不需要为每一种小众硬件负责,硬件作者也不需要等 PR 合并。社区已经用这种方式接上了 xArm、UR5e、Franka、Piper、WidowX、ARX5、GELLO、SpaceMouse、Meta Quest、ROS 2 桥接,以及各类触觉与深度相机。
对个人来说,这也是最现实的路径:先做成插件跑通,用的人多了,再考虑提请并入核心。反过来做,你会在 review 里耗掉三个月。
4.6开发流程与评审预期
环境准备
git clone https://github.com/<your-handle>/lerobot.git
cd lerobot
git remote add upstream https://github.com/huggingface/lerobot.git
git lfs install && git lfs pull # 测试需要的素材在 LFS 里
pre-commit install
提 PR 前的四项检查
pre-commit run --all-files通过(格式、lint、import 排序)。pytest -sv ./tests通过。测试按 extra 分 tier:需要dataset/hardware/viz的测试必须打上对应 mark,否则会在 base tier 里被跳过或失败。本地可以只跑一层:pytest -sv tests -m dataset。- 涉及 CUDA 的测试打
@pytest.mark.gpu,它只在 GPU CI 里跑。 - 如果你改了公开 API,docstring 要符合规范——API 文档是从 docstring 生成的,格式错误会在 CI 里被卡。
分支与提交
不要在 main 上开发,用描述性分支名;提交前 rebase 到 upstream/main(不是 merge,保持历史线性)。PR 描述按模板填:改了什么、为什么、怎么验证的。「怎么验证的」这一栏是评审的第一眼,写「已本地测试」等于没写。
现实预期
这个仓库有近九百个开放 issue,维护团队不大。这意味着:小改动(文档、bugfix、测试)通常几天内会有回应;涉及接口的大改动可能几周没人看。一个务实的策略是先在 issue 里把设计讨论清楚,再写代码——直接提一个大 PR 而被搁置,是这个项目里最常见的挫败感来源。
4.7不写代码的贡献
最后说几件被严重低估的事。
- 把错误报清楚。一个附了版本号、
lerobot-info输出、完整 traceback、最小复现步骤的 issue,价值等同于一个修复。反之,「record 命令报错了」这样的 issue 只会被关掉。 - 补文档里的空缺。官方文档覆盖了主路径,但「在 Windows 上装 torchcodec」「用 WSL 接 USB 设备」「不同批次的舵机固件差异」这类边角,全靠社区补。
- 翻译与教程。README 里专门列了一篇中文教程(同济子豪兄的 SO-ARM101 全流程文档),说明维护团队认可这类贡献的价值。一个有截图、有踩坑记录的中文教程,对中文使用者的帮助超过十个 PR。
- 写「失败报告」。「我按论文复现了但我这里不 work,我的配置是 X,现象是 Y」——这种帖子在 Discord 里极受欢迎,因为它省下了后面十个人的时间。
开源项目的健康度不看 star 数,看「新手能不能在一天内跑通」。而决定这一点的,往往不是核心代码,是那些把坑标出来的人。
CLI 速查
Twenty-Three Entry Points
命令名由 src/lerobot/scripts/ 下的脚本文件名转写而来,具体参数以 <命令> --help 为准。
| 分组 | 命令 | 用途 |
|---|---|---|
| 硬件 | lerobot-info | 打印版本、extras、检测到的设备 |
| lerobot-find-port | 扫描串口,找出机械臂对应的那个 | |
| lerobot-find-cameras | 列出可用相机与 index | |
| lerobot-setup-motors | 逐个设置舵机 ID 与波特率 | |
| lerobot-calibrate | 记录关节极限,写校准文件 | |
| lerobot-find-joint-limits / setup-can | 探测关节范围 / 配置 CAN 总线 | |
| 采集 | lerobot-teleoperate | 主从遥操,用于练习与调试 |
| lerobot-record | 录制数据集,自动编码并上传 Hub | |
| lerobot-replay | 回放已录 episode,验证数据可用性 | |
| lerobot-annotate | 给数据加语言分段与技能标签 | |
| 训练 | lerobot-train | 训练策略,配置随 checkpoint 保存 |
| lerobot-train-tokenizer | 为离散动作策略训练 tokenizer | |
| 评测与部署 | lerobot-eval | 在 LIBERO / MetaWorld 等基准上评测 |
| lerobot-rollout | 在真机上跑策略,处理动作块流式执行 | |
| lerobot-policy-server | 把策略跑成服务端,机器人端做客户端 | |
| 数据工具 | lerobot-dataset-viz | 可视化数据集(视频 + 曲线) |
| lerobot-edit-dataset | 删 episode、切分、增删特征、合并 | |
| lerobot-imgtransform-viz | 预览图像增强效果 | |
| lerobot-build-mp4-sidecar | 为旧数据集补建视频附属文件 | |
| convert-dataset-v21-to-v30 | 从 v2.1 格式迁移到 v3.0 | |
| augment-dataset-quantile-stats | 补算分位数统计 |
术语表
Glossary
| 术语 | 英文 | 一句话解释 |
|---|---|---|
| 策略 | Policy | 从观测到动作的映射函数,通常是神经网络。π(a|o)。 |
| 动作块 | Action Chunk | 一次预测未来 K 步动作,而不是只预测下一步。降低复合误差、缓解推理延迟。 |
| 动作专家 | Action Expert | VLA 里专门负责生成连续动作的小网络,与视觉语言主干解耦。 |
| 本体 | Embodiment | 机器人的物理形态(关节数、连杆、传感器)。「跨本体」指策略能迁移到不同形态。 |
| 遥操作 | Teleoperation | 人通过主臂/手柄/VR 实时控制机器人,同时记录数据。 |
| 协变量偏移 | Covariate Shift | 策略自己把状态分布推离训练分布的现象,是复合误差的根源。 |
| 行为克隆 | Behavior Cloning | 最朴素的模仿学习:监督学习 (o, a) 对。 |
| DAgger | Dataset Aggregation | 让策略自己跑、人纠正、把纠正数据加回训练集,迭代。 |
| 流匹配 | Flow Matching | 学生成动作的速度场,几步就能出高质量样本,比扩散快。 |
| VLA | Vision-Language-Action | 用预训练视觉语言模型做主干、接动作头的策略范式。 |
| 重定向 | Retargeting | 把一种本体的动作映射到另一种本体(如人手→二指夹爪)。 |
| Episode | — | 一次完整的任务尝试,从复位到结束。数据集的基本单位。 |
| features | — | 数据集的字段 schema:名字、dtype、shape。合并数据集前必须对齐。 |
| stats | — | 预计算的归一化统计量,存在 meta/stats.json。 |
| RTC | Real-Time Chunking | 在新动作块到达时与旧块平滑衔接的技术,解决推理慢于控制的问题。 |
三十天路径
A Month, Four Weeks
如果你打算系统学一遍,这份日程是按「每周 6—8 小时」排的。它的原则是:每一周都要产出一个可以被别人看到的东西,而不是攒到最后。
第一周 · 读懂
- 读 README 与文档的 Installation / LeRobotDataset / Bring your own policies 三页。
- 按 3.9 跑通零硬件路线,训一个 ACT,哪怕它什么都不会。
- 打开
lerobot_dataset.py,把__getitem__逐行读懂。产出:一篇笔记,画出数据从磁盘到张量的路径。
第二周 · 训练与评测
- 换三种策略(ACT / Diffusion / SmolVLA)在同一份数据上训,记录显存、时长、成功率。
- 在 LIBERO 上跑一次
lerobot-eval,理解「基准分数」的含义与局限。 - 读
processor/下的 normalize 与 relative_action,搞清训练/推理的一致性怎么保证。产出:一张对比表,三种策略的代价与效果。
第三周 · 上手硬件
- 组装、校准、遥操熟练(目标是连续十次成功)。
- 采 30—50 条,训出第一个真机能用的策略。
- 记录失败模式,针对性补采 20 条,重训。产出:一个能跑的策略 + 一份失败分析。
第四周 · 发布与参与
- 把数据集与策略卡一起发到 Hub(4.2 的六项检查全过一遍)。
- 给仓库提一个真正的小 PR:文档修正、测试补充、或一个插件。
- 在 Discord 回答一个别人的问题。产出:一次公开提交 + 一次公开回答。
这本书讲的所有东西,都可以浓缩成一句话:具身智能的瓶颈不在算法,在「有没有人愿意把手怎么干活这件事录下来」。LeRobot 把录、存、训、跑这四件事的门槛降到了一个人可以独立完成的水平。剩下的部分,取决于你手上有什么别人没有的场景。