前言:机器人能不能从经验中学会行动?

过去学习机器人时,我接触更多的是怎样让机器人按照要求准确运动。AI 的发展让我开始追问另一个问题:机器人能不能通过观察人类示范,学会完成任务?

以“把桌上的杯子拿起来”为例,传统方案可能包含目标检测、位姿估计、运动规划、逆运动学、轨迹规划和底层控制。模仿学习的常见路径则是:人类示范、记录同步数据、训练策略、让策略根据观测输出动作,再在机器人上评估。

两者不是互斥关系:学习策略产生的动作最终仍需由机器人驱动和控制系统执行。

TEXT
示范与传感器数据 → 数据集 → 策略训练 → 策略推理 → 机器人执行
       ↑                                           ↓
       └──────────── 评估、分析、补充数据 ─────────┘

这就是我学习 LeRobot 的原因:理解机器人怎样从数据中学会行动,以及软件框架怎样把数据、模型和硬件串在一起。

LeRobot 是什么?

LeRobot 是 Hugging Face 用 Python 和 PyTorch 构建的机器人学习开源项目,目标是降低真实机器人学习的门槛。仓库本身提供硬件接口、遥操作、数据集、策略模型、训练与推理工具;Hub 上的机器人数据集和模型权重则属于更大的社区生态,并不等同于 GitHub 代码仓库本身。

把它简单理解成“机器人学习的端到端工具箱”比较合适,但它并不是完整的机器人操作系统,也不保证一个训练好的模型可以不经适配就控制任意机器人。硬件配置、特征维度、相机视角、动作定义和策略输入输出必须匹配。

Hugging Face LeRobot 官方文档

同济子豪兄中文文档

我认为 LeRobot 值得学习,不只是因为它是一个开源项目。更重要的是,它把传统机器人和 AI 连接起来了,这里的文档已经是很详细的教程了,按照子豪兄的文档能顺利地部署运行。

当前仓库仅列出理解“硬件接入 → 数据采集 → 训练 → 策略运行”主链路所需的核心目录和代表性文件。

TEXT
lerobot/                         # 机器人学习框架核心 Python 包
├── cameras/                     # 相机接口与驱动
│   ├── camera.py                # 相机抽象接口
│   ├── opencv/                  # USB/OpenCV 相机
│   └── realsense/               # Intel RealSense 相机
├── configs/                     # 机器人、数据集、策略和训练配置
│   ├── train.py                 # 训练配置入口
│   └── …
├── datasets/                    # 数据集读写、元数据与视频处理
│   ├── lerobot_dataset.py       # LeRobotDataset 主接口
│   ├── dataset_writer.py        # 帧和 episode 写入
│   ├── dataset_reader.py        # 数据读取接口
│   ├── dataset_metadata.py      # 特征、统计量和 episode 元数据
│   ├── video_utils.py           # 视频编码、解码和帧对齐
│   └── …
├── envs/                        # 仿真环境适配
│   └── …
├── motors/                      # 电机总线协议和驱动
│   ├── feetech/                 # Feetech 电机
│   ├── dynamixel/               # Dynamixel 电机
│   └── …
├── policies/                    # 策略模型及配置
│   ├── pretrained.py            # 策略通用基类与加载接口
│   ├── factory.py               # 根据配置创建策略
│   ├── act/                      # ACT 动作分块策略
│   │   ├── modeling_act.py      # ACT 模型、训练损失和动作选择
│   │   └── configuration_act.py  # ACT 参数配置
│   ├── diffusion/               # Diffusion Policy
│   ├── smolvla/                 # SmolVLA
│   └── …
├── processor/                   # 观测和动作处理流水线
│   ├── pipeline.py              # Processor pipeline 接口与组合逻辑
│   ├── factory.py               # 默认处理器构造
│   └── …
├── robots/                      # 机器人接口和硬件实现
│   ├── robot.py                 # Robot 抽象基类
│   ├── so_follower/             # SO 系列从动机械臂
│   ├── …
│   └── …
├── teleoperators/               # 遥操作设备接口和实现
│   ├── teleoperator.py          # Teleoperator 抽象接口
│   ├── so_leader/               # SO 系列主臂遥操作
│   └── …
├── scripts/                     # 命令行工作流入口
│   ├── lerobot_record.py        # 遥操作录制数据
│   ├── lerobot_train.py         # 训练策略
│   ├── lerobot_rollout.py       # 在机器人上运行策略
│   ├── lerobot_replay.py        # 回放数据集动作
│   └── …
├── rollout/                     # 策略 rollout 的运行逻辑和策略
├── async_inference/             # 机器人客户端与策略服务端异步推理
├── transport/                   # 网络传输与消息序列化
├── optim/                       # 优化器和学习率调度器
├── rl/                          # 强化学习流程
├── rewards/                     # 奖励模型
├── transforms/                  # 图像及观测变换
├── streaming/                   # 数据流式处理
├── data_processing/             # 数据清理、转换与标注
├── distributed/                 # 分布式训练组件
├── common/                      # 多个命令共享的控制逻辑
└── utils/                       # 通用工具函数

阅读主链路时的建议顺序

  1. robots/robot.py:先看机器人如何统一暴露观测和动作接口。
  2. scripts/lerobot_record.py:跟踪遥操作数据如何采集并写入数据集。
  3. datasets/lerobot_dataset.py:了解数据如何组织和读取。
  4. policies/act/modeling_act.py:看训练时损失如何计算、推理时动作块如何选择。
  5. scripts/lerobot_train.py 与 scripts/lerobot_rollout.py:串起训练和策略运行。
  6. processor/:理解设备数据、数据集格式和策略输入输出之间的变换。

说明:目录和文件名按上述提交的源码核对。仓库持续更新,后续版本的结构可能变化。

先建立一个准确的心智模型

LeRobot 的关键不是“AI 直接驱动电机”,而是不同模块围绕统一的数据结构协作:

TEXT
机器人/相机 ──观测──┐
                   ├─处理器与特征映射─→ Policy ─动作─→ 机器人
示教设备 ───动作───┘                         │
                   └──── Dataset 记录 ───────┘

下面用源码中的接口逐段说明。

1. Robot:统一硬件接口,不是统一控制算法

源码:robots/robot.py。Robot 是 abc.ABC 抽象基类,规定具体机器人驱动必须实现的接口。基类本身不负责控制电机,也没有替子类实现通用运动学或控制器。

主要接口可以分成三组:

接口在系统里的作用
observation_features / action_features描述观测、动作的键及数据类型/形状;键应分别对应 get_observation() 返回值和 send_action() 参数。
connect() / disconnect() / is_connected建立、释放硬件连接并报告连接状态。connect(calibrate=True) 可按硬件实现决定是否自动校准。
calibrate() / is_calibrated / configure()校准电机或传感器,并应用控制模式等运行配置。校准数据由基类辅助方法按机器人类型和 ID 保存/加载。
get_observation()返回符合 observation_features 描述的扁平字典 RobotObservation。
send_action(action)接收符合 action_features 的 RobotAction,返回实际发送的动作;实现可以裁剪或修改目标。

一个典型的上层调用因此可以统一写成:

PYTHON
robot.connect()
obs = robot.get_observation()       # 读取状态/图像等观测
sent = robot.send_action(action)    # 发送目标并返回实际发送值
robot.disconnect()

统一的是调用约定,不是动作的物理含义。action 可能表示关节目标位置,也可能是底盘速度或其他控制量;单位、坐标系、范围、频率、安全限制都要继续看具体机器人实现,例如 robots/so_follower/ 和它使用的 motor bus。observation_features 也不等于运行时自动校验所有语义,它首先是数据结构描述,供数据集、处理器和策略配置对齐使用。

2. Teleoperation:示范数据从哪里来

源码:teleoperators/teleoperator.py。Teleoperator 同样是抽象基类。它提供 action_features、feedback_features、连接与校准接口,并要求实现 get_action()、send_feedback() 和 disconnect()。get_action() 返回的是设备读出的 RobotAction 字典;主臂设备如何把关节位置映射成从臂目标,则由具体设备实现和 processor 决定。

以 leader/follower 示教为例,每个控制周期通常依次读取机器人当前观测、读取 leader 动作、处理动作、发送给 follower。要注意,teleoperator 提供的是“人的输入”,不是示教标签本身。录制脚本把这个动作和对应时刻的机器人观测组合后,才构成监督学习数据中的输入—目标配对。

所以数据质量受几个因素共同影响:人的演示是否覆盖任务变化、输入设备与 follower 是否经过正确校准、相机是否能看到关键状态、采样频率和设备延迟是否可接受。遥操作是重要的数据来源,但训练还可以使用 Hub/本地已有数据集,评估可以使用环境或真实机器人 rollout。

3. Record:记录循环里实际发生什么

源码:scripts/lerobot_record.py。该脚本头部明确说明:lerobot-record 是通过遥操作录制数据的工具;部署训练好的策略应使用 lerobot-rollout。RecordConfig.__post_init__() 也会在未提供 teleop 时直接报错。

主循环 record_loop() 的关键步骤如下:

TEXT
robot.get_observation()
  → robot_observation_processor(obs)
  → teleop.get_action()
  → teleop_action_processor((action, obs))
  → robot_action_processor((processed_action, obs))
  → robot.send_action(robot_action_to_send)
  → dataset.add_frame(observation + action + task)

源码把三条处理管道分开传入:机器人观测管道、teleop 动作管道、发给机器人前的动作管道。当前默认实现由 processor/factory.py::make_default_processors() 创建,默认步骤主要是 identity;实际项目可以替换管道,完成键名映射、动作变换等操作。录制循环还用 CycleTimer 按目标 FPS 节拍运行,并检查 dataset FPS 与请求 FPS 是否一致。

有个值得从源码注意的细节:循环中 action_values 保存的是 teleop action processor 的输出;发给硬件的是再经过 robot_action_processor 的 robot_action_to_send。接着写 Dataset 时使用 action_values 构造 action 字段。机器人 send_action() 返回的 _sent_action 在此处没有被重新写入该字段。因此当 robot action processor 或硬件侧会裁剪/修改动作时,要检查记录动作与真实执行动作是否完全一致;LeRobot 源码注释也特别提到 max_relative_target 等裁剪可能造成差异。不要笼统地假设数据集 action 必然等于电机最终收到的数值。

一个 episode 的结束不只是循环停下来:外围 record() 负责创建/恢复数据集、连接硬件、处理重录或丢弃事件,并在确认保留时调用 dataset.save_episode();退出清理阶段会 finalize 数据集并断开设备。若重新录制,当前 episode buffer 会被清空,而不是作为有效训练样本保存。

4. LeRobotDataset:同步的时序数据

源码:datasets/lerobot_dataset.py、datasets/dataset_writer.py。LeRobotDataset 同时承担读数据的 PyTorch Dataset facade 和写入接口:读模式从本地或 Hub 构造,写模式通过 create() / resume() 创建 writer。其 metadata 包括 feature 结构、统计信息、FPS、任务和 episode 信息;数值帧数据由存储 reader/writer 管理,图像可以以 MP4 视频或图像数据存储。

录制时,add_frame(frame) 将单帧交给 writer 的 episode buffer;save_episode() 再完成当前片段的持久化、更新 metadata,并重置 buffer。episode 通常还会被划分成 chunk/file 存储;不要把“一个 episode 等于一个独立文件”当作固定格式假设。

读取时,dataset[idx] 不只是返回底层 Parquet 的原始行。__getitem__() 委托给 reader,可能展开 delta_timestamps 时间窗口、解码与表格时间同步的视频帧,并应用图像变换。要检查未展开的原始表格行,可看 get_raw_item();这与训练时拿到的样本可能不同。

TEXT
样本的主要信息:观测特征 + action + 时间/索引信息 + task
时间窗口样本:当前时刻及按 delta_timestamps 选取的前后时刻特征
episode:具有边界和元数据的一段帧序列
dataset:多 episode、特征定义、任务表、统计量和存储索引

因此,检查数据时要同时看画面与结构:dataset.features 中的键与 shape、FPS、episode/frame 数、动作数值范围、任务文本、数据统计量,以及视频帧和时间戳是否能对应。LeRobot 常用存储是 Parquet 数值/索引数据与 MP4 视觉数据的组合,但当前格式还有版本和 storage reader 的抽象,最好以数据集自身的 meta/info 和实际文件为准。

5. Processor:连接设备、数据集和策略的转换层

Processor 不只是“归一化模块”。processor/pipeline.py 提供 ProcessorStep、transition 和 pipeline 抽象,可按顺序把数据从一种结构转换到另一种结构,并支持配置保存/加载、重置和 feature 变换。真实系统会针对不同边界构造不同的管道:

管道典型输入 → 输出录制/运行中的位置
robot observation processor机器人原始观测 → 标准化后的机器人观测get_observation() 之后
teleop action processor遥操作输入与当前观测 → 示教动作teleop.get_action() 之后
robot action processor处理后的动作与当前观测 → 硬件动作robot.send_action() 之前
policy preprocessor数据集/机器人观测 batch → 模型期望的输入Policy 前
policy postprocessorPolicy 输出 → 机器人动作格式Policy 后

策略的默认处理步骤可在 processor/factory.py::make_default_policy_processor_steps() 看到:按模型配置准备观测重命名、添加 batch 维、移动设备、基于数据统计量归一化输出/输入等步骤;具体策略工厂会按模型需求组合步骤,顺序是配置的一部分。lerobot_train.py 也会先把 uint8 图像转成浮点范围、应用 rename_map,再送入预处理器。

所以训练和部署时必须保持同一套兼容的预处理/后处理。模型要求的 observation.images.*、observation.state 和 action 特征要能与 Dataset/Robot features 对上;部署时的 action postprocessor 再将模型空间中的动作还原成机器人接受的动作。接口能拼接起来,不代表各个空间的语义自动一致。

6. Policy 与 ACT:从训练 loss 到动作块执行

源码:policies/act/configuration_act.py、policies/act/modeling_act.py。ACT 配置要求 action 输出特征;输入至少要有视觉图像特征或 observation.environment_state,机器人状态 observation.state 可以按任务需要提供。配置参数还包括 ResNet backbone、Transformer 维度/层数、VAE、chunk_size、n_action_steps 和可选 temporal ensembling。

训练时,ACTPolicy.forward(batch) 将相机键整理成模型使用的图像列表,模型预测形状大致为 (batch, chunk_size, action_dim) 的动作序列。随后源码对预测动作和标注动作计算逐元素 L1 error,并使用 action_is_pad 屏蔽 episode 尾部补齐的无效动作。如果启用 VAE,再计算 latent 分布相对标准正态分布的 KL 项,最终损失是 L1 + kl_weight × KL。这解释了为什么 batch 中除了 observation 和 action,还会有 padding mask。

推理时 select_action() 的逻辑不同于训练:

  1. 当动作队列为空时,调用 predict_action_chunk() 预测一整段动作。
  2. 默认模式把预测序列截取前 n_action_steps 个并放入队列,每次调用只弹出一个动作。
  3. 队列用完后再根据最新观测重新预测。
  4. 若设置 temporal_ensemble_coeff,每个时刻重新预测,并把多个时间点预测到当前时刻的动作按指数权重融合;此模式要求 n_action_steps == 1。

默认配置中 chunk_size=100、n_action_steps=100,但配置注释明确允许只执行 chunk 的一部分。chunk 过长会让策略较久才基于新观测更新,过短则增加推理频率;它与模型速度、控制频率和任务动态有关,不存在总是最优的固定长度。

7. Training:lerobot-train 实际做了哪些事

训练入口在 scripts/lerobot_train.py。README 的基本命令形式是:

BASH
lerobot-train \
  --policy.type=act \
  --dataset.repo_id=lerobot/aloha_mobile_cabinet

这个命令展示了 CLI 配置字段,不代表该数据集无须检查就必然匹配当前 ACT 配置。训练启动后,train(cfg) 首先校验配置、创建 Accelerate 分布式/混合精度运行器,然后用 make_train_eval_datasets(cfg) 准备训练/验证数据,用 make_policy(...) 根据 Policy 配置和数据集 metadata 创建策略,并构造 dataloader、优化器和 scheduler。默认处理器、图像增强、checkpoint 恢复、W&B、本地日志、可选仿真评估和 Hub 发布也由这条流程按配置组织。

每个 batch 的更新由 update_policy() 执行,核心次序是:

TEXT
图像 dtype/range 与键名预处理
  → policy(batch) 得到 loss 和模型输出
  → accelerator.backward(loss)
  → (同步梯度时)梯度裁剪
  → optimizer.step() / zero_grad()
  → scheduler.step()、统计指标

Accelerator 负责 mixed precision、gradient accumulation 和并行训练相关处理;源码还区分真正应用的 optimizer update 与 accumulation micro-batch,并据此更新 EMA 等状态。主训练循环按 steps 取 batch、调用 update_policy()、记录指标、按频率保存 checkpoint,并可在配置的环境中评估。这比“循环里直接 forward、backward、step”多了许多可复现性与训练状态管理。

离线 imitation loss 衡量的是模型在示范样本上的动作预测误差,并不直接等于机器人任务成功率。机器人执行时产生的新状态可能偏离示范数据分布,因此还需单独做仿真或真实环境 rollout,并定义清楚成功标准。

8. Rollout:训练好的策略如何运行

当前入口 scripts/lerobot_rollout.py 将 lerobot-rollout 实现为带可插拔 strategy 的策略部署引擎。rollout(cfg) 初始化日志/可视化,调用 build_rollout_context() 组装运行上下文,再创建 strategy 并依次调用 setup(ctx)、run(ctx)、teardown(ctx);交互模式下会由 InteractiveSession 接管会话。

源码注释列出的运行策略包括 base(自主运行)、sentry(持续录制/上传)、highlight(环形缓存后选择保存)、dagger(人机协作纠正)和 episodic(episode 流程);推理后端包括每个控制 tick 同步调用策略的 sync,以及面向较慢 VLA 的 RTC。不同 strategy 会决定是否录制、何时保存数据和如何与人交互,所以 lerobot-rollout 不只是一个固定的“相机读一帧、模型推一步”循环。

从功能上看,底层仍是下面这条闭环:

TEXT
采集机器人观测 → observation preprocessor → policy 推理
  → action postprocessor → robot.send_action() → 进入下一控制周期

策略加载、特征兼容性、processor、相机和机器人配置由 rollout context/相关 factory 负责准备,strategy 再按其运行方式消费上下文。执行前需核对机器人 calibration、动作范围和速度限制、工作空间、急停,以及 policy 的输入输出特征;尤其应先以低风险方式验证动作方向和尺度。

9. 仿真、评估与 Sim2Real

LeRobot 代码中“训练时评估”和“真实机器人部署”有不同入口。lerobot_train.py 可以按配置创建 eval dataset 或 eval environments;独立的 scripts/lerobot_eval.py 提供策略评估流程;真实设备上运行策略则由 lerobot-rollout 负责。三者的数据接口有共通之处,但执行环境、终止条件和成功指标不同。

仿真评估通常按 episode 重置环境,经过环境 observation processor 调整输入,调用策略选择动作、经 action processor 转换后 env.step(action),累积奖励/终止状态并汇总结果。真实机器人则面对相机视角、标定、摩擦、机械间隙、控制延迟和安全约束等因素。仿真成功率不能直接当作真实成功率;Sim2Real 需要在目标硬件上逐步验证。

建议把评估作为可复现实验记录:固定任务定义和初始条件,报告尝试次数、成功标准、成功率与失败类型,并关联 policy checkpoint、训练配置、数据集版本和硬件配置。这样失败才能反馈到具体环节:补充示范、修正相机/标定、调整 processor,还是更换训练配置。

10. LeRobot 与 ROS 2:互补而非二选一

ROS 2 面向通用机器人软件系统,提供节点通信、驱动集成和生态工具;LeRobot 更聚焦于机器人学习中的数据、模型训练和策略运行。它们解决的问题不同,可以在同一系统中共存。不能简单说 LeRobot “取代 ROS 2”,也不应把 LeRobot 描述成一个具有 ROS 2 同等职责的机器人操作系统。是否需要 ROS 2,取决于项目的驱动、导航、通信和部署需求。

同样,LeRobot 的 Python 接口和数据格式不意味着硬实时保证。对于高频、强实时或安全关键控制,应由适当的底层控制与安全系统承担,策略放在符合系统约束的层级。

初学者建议的学习顺序

  1. 先跑通一条最小链路:安装当前版本,确认相机和机器人可连接,理解遥操作和校准。
  2. 看一条示范数据:检查 episode、图像、状态、动作、任务和元数据。
  3. 读 Record 主循环:追踪 get_observation → processor → get_action → send_action → add_frame/save_episode。
  4. 从 ACT 看策略:读配置、forward() 的训练损失和 select_action() 的推理行为。
  5. 跑训练与评估:先确认数据特征兼容,再比较 loss 和 rollout 指标。
  6. 看 Rollout 与安全边界:弄清设备接口、处理器、策略和动作执行的关系,再上实体机器人。

不建议一开始通读全部源码、追逐最新 VLA 名称,或只看训练曲线就判断机器人学会了。先理解一条端到端数据流,再深入模型和底层通信会更有效。

我目前最大的体会:数据和接口同样重要

机器人学习的数据不只是图像,而是视觉、状态、动作、时间、任务和 episode 结构之间的对应关系。采集质量、标定、相机位姿、动作定义和同步方式都会影响训练。模型也很重要,但模型不能自动弥补输入输出接口不一致或数据覆盖不足。

LeRobot 值得研究的地方,在于它努力把硬件抽象、示教采集、标准数据集、策略训练和 rollout 串起来。真正理解它,不是记住几个命令,而是能回答:观测从哪里来?中途如何变换?动作代表什么?数据怎样保存?训练目标是什么?策略怎样安全地回到机器人?

代码与文档索引