HIL-SERL 这个词玩 Lerobot 的朋友应该不陌生。简单说它是加州大学那个 SERL 项目在 lerobot 框架上适配的一套强化学习训练流程。但真正的痛点从来不是训练本身而是数据从哪来。你总不能指望每次都抓几个现成的数据集就跑机械臂的安装角度、相机位置一变模型基本就废了。所以我这次把这套“用键盘给 Lerobot 机械臂采集 HIL-SERL 训练数据”的完整流程捋了一遍从环境搭建到配置文件每一步都记了下来。这篇文章适合已经装好 Lerobot、但对数据采集流程还不熟或者在采集时遇到各种奇怪报错的朋友。我会尽量把容易踩的坑都指出来尤其是那些官方文档里写得含糊、实际运行起来却特别影响效率的细节。1. 项目整体思路与数据采集方案选型1.1 为什么 HIL-SERL 需要专门的数据采集流程SERL 这类强化学习项目核心是“从视觉输入直接映射到关节动作”这意味着训练数据里每一帧都必须是“图像 机械臂关节状态”的同步组合。这和传统模仿学习只需要录轨迹不一样HIL-SERL 对数据的时序一致性要求极高。你录数据的时候如果相机帧率和机械臂状态采样频率不一致训练出来的 policy 就会莫名其妙地抖动。而 Lerobot 本身的数据采集逻辑走的是“每个 episode 存成一个独立文件”的路子。官方默认支持遥控器、动捕手套这类高成本设备但对于大多数人来说手里只有一台普通电脑和一个 USB 相机。我自己试过用鼠标在仿真环境里拖拽效果很糟糕——鼠标位移和真实关节运动之间有个天然的滤波延迟采集出来的轨迹不平滑训练效果直接受影响。键盘就不一样。Lerobot 里键盘控制走的是 teleop 模块按键按下去就是固定步长的关节增量松开就立刻停住没有任何额外的平滑处理。这个特性对强化学习数据采集反而是优点因为数据里会天然包含“停顿-启动-再停顿”这种阶段性的动作模式让模型更容易学到“何时该动、何时该停”的决策边界。1.2 键盘控制 vs 其他遥操作方案的利弊先做一个直观对比方便你判断自己该用哪种方式。说实话键盘不是最优解但它是性价比最高的方案。方案成本数据平滑度操作自然度学习曲线键盘零成本偏低动作有阶梯感一般适合点位式任务几分钟上手游戏手柄几十到两百元中等摇杆有连续量较好适合速度控制十几分钟上手3D 鼠标SpaceMouse几百元较高六维力感高适合空间操作需要一周适应动捕手套/外骨骼数万元以上极高极高专业级需校准键盘最大的问题在于你一次只能控制一个或几个关节而真实任务往往需要多关节协同运动。我的做法是在配置文件里把几个常用关节的增量步长调小一点然后用组合键来切换控制模式。比如按住 Shift 的时候控制末端 XYZ 平移松开时控制单个关节角度。这样虽然不够优雅但至少能完成最基本的抓取-放置任务的数据采集。1.3 整套流程的数据流路径先弄清楚数据在哪流动后面踩坑时才知道该查哪里。整个采集链路是键盘输入 → teleop 键盘节点 → lerobot 的 Policy 接口 → 机器人驱动节点 ↓ HDF5/MCAP 数据文件相机图 关节状态 动作标签Lerobot 的数据采集和训练是解耦的。采集时你只需要让机器人动起来同时让 recorder 进程把相机图像、关节状态、时间戳一起写进磁盘。等到训练时再读这些文件去算 loss。这个设计意味着你完全可以在不装训练环境的情况下先搞定数据采集流程。2. Ubuntu 环境准备与 Lerobot 基础配置2.1 系统版本与依赖版本选型先说结论我实测下来最稳的组合是 Ubuntu 22.04 LTS Python 3.10 PyTorch 2.1.x。20.04 也能跑但有些依赖编译会出问题尤其是和实时控制相关的库。24.04 太新部分二进制包还没跟上容易在编译环节卡住。有个容易忽略的点Lerobot 默认依赖的h5py版本和系统自带的 HDF5 库版本可能不匹配导致写入数据时报错。你在装依赖之前先手动更新一下系统基础库sudo apt update sudo apt install libhdf5-dev libhdf5-serial-dev这两个包装不装决定了你后续会不会在与 hdf5 存储相关的报错上浪费大量时间。2.2 创建虚拟环境并安装 Lerobot我不建议直接用全局 Python 环境装 Lerobot因为它依赖的包版本比较敏感比如 einops、hydra-core 这些库版本新了旧了都可能出兼容问题。推荐用 conda 或 venv 隔离环境。# 创建虚拟环境 python3 -m venv lerobot_env source lerobot_env/bin/activate # 安装核心依赖 pip install --upgrade pip pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 pip install lerobot[all]如果你用的是 ARM 架构的设备比如 Jetson上面的 PyTorch 安装命令要换成对应平台的 wheel否则会静默装成 CPU 版后续跑起来慢到怀疑人生。2.3 配置文件目录结构说明Lerobot 的配置遵循 Hydra 的配置覆盖机制简单说就是所有默认参数集中在一个 YAML 文件里你可以在命令行里用keyvalue的方式临时覆盖也可以直接改 YAML 文件。我建议在项目根目录单独建一个configs/my_robot/文件夹把你自己的配置都放进去这样不会污染官方配置。首次跑通时你不需要理解每一个配置项。核心就三个env机器人类型、teleop控制方式、dataset数据保存路径。先把这三个搞清楚其余参数保持默认即可。3. 键盘控制方案的核心原理与配置文件解读3.1 HIL-SERL 的交互逻辑与键盘映射设计读源码的时候你会发现Lerobot 的键盘遥操作其实是基于pynput库监听全局键盘事件再把按键映射成action向量。这个向量会直接叠加到当前关节位置上形成目标位置指令。HIL-SERL 在数据采集上有一层自己的封装它对动作向量的格式有要求——不是简单地记录最终关节位置而是记录每一步的“增量动作”。这意味着你在键盘映射里必须把按键的“按下-释放”状态实时转换成动作增量# teleop_keyboard_action 的核心逻辑简化版 if key w: action[0] 0.02 # 关节1正方向增量 elif key s: action[0] -0.02 # 关节1反方向增量这个动作增量会同时写进训练数据集里作为模型的监督信号。所以按键按下多久、每步增量多大直接决定了模型学到的动作力度和粒度。这是我后来才真正意识到的重要一环——一开始我图省事把增量设得很大结果采集到的数据里动作全是“突跳”训练出来的模型一运行就疯狂抖动。3.2 完整配置文件逐行解读下面这份配置文件是我在多次实践后稳定下来的键盘遥操作配置可以直接抄作业# configs/my_robot/teleop_keyboard.yaml env: lerobot policy: type: keypoint teleop: type: keyboard keyboard: action_speed: 0.05 # 每个按键事件的关节增量弧度 action_speed_turbo: 0.15 # 按住 Shift 时的高速增量 joint_indices: [0, 1, 2, 3, 4, 5] # 控制的关节索引列表 keys_mapping: # 关节0基座旋转控制键 q: [0, 0, 0, 0, 0, 0] # 预留 a: [0.02, 0, 0, 0, 0, 0] # 关节0正转 d: [-0.02, 0, 0, 0, 0, 0] # 关节0反转 # 关节1肩部控制键 w: [0, 0.02, 0, 0, 0, 0] s: [0, -0.02, 0, 0, 0, 0] # 关节2肘部控制键 e: [0, 0, 0.02, 0, 0, 0] f: [0, 0, -0.02, 0, 0, 0] # 末端夹爪开合 r: [0, 0, 0, 0, 0, 0.01] t: [0, 0, 0, 0, 0, -0.01] hz: 30 # 控制频率30Hz 足够平滑 dataset: path: data/my_hil_serl_dataset repo_id: my_hil_serl/keyboard_demo use_videos: true fps: 30这里重点解释两个参数action_speed和hz。前者是每个按键事件产生的关节增量说白了就是“按一下动多大角度”。对于 UR 这类关节范围较大的机械臂0.05 弧度比较合适对于小型桌面机械臂比如 SO-100建议调到 0.02否则速度太快容易撞到限位。后者是控制频率我实测 30Hz 足够太高会增加 CPU 负载而且没有必要太低会显得动作一顿一顿的。3.3 关节索引与机械臂型号的对应关系不同的 Lerobot 支持的机械臂型号关节顺序定义不同。这点非常关键因为如果你在配置文件里把关节索引搞错按下按键后动起来的就不是你想控制的那个关节。以常见的 SO-100 为例Lerobot 源码中定义的关节顺序是joint0: 底座旋转 joint1: 肩部俯仰 joint2: 肘部俯仰 joint3: 腕部俯仰 joint4: 腕部旋转 joint5: 夹爪开合但如果你用的是 ARX 或其他型号顺序很可能不一样。我的建议是拿到机器人后第一步先用命令行把每个关节的实时角度打印出来手动掰动各个关节确认索引顺序再写配置python -m lerobot.robot.observe这一步能帮你节省大量的试错时间。要是跳过这一步直接配好就开始采集等到训练完部署到真机上才发现关节对应错误那时候想哭都来不及。4. 实操过程从启动到完成第一批 HIL-SERL 数据采集4.1 启动相机与机器人控制节点的正确顺序顺序很重要。我踩过一次坑先启动了机器人控制节点再启动相机节点结果前几秒的图像是黑的。虽然不影响最终数据但会白白多出几个废 episode。推荐顺序是# 终端1启动机器人控制节点 python lerobot/scripts/control_robot.py \ --robot.typeso100 \ --robot.calibration_pathcalibration/so100.json # 终端2启动相机节点 python lerobot/scripts/control_camera.py \ --camera.typeusb \ --camera.id0先确认相机正常出图再控制机器人这样能保证录制的第一帧就是有效的。4.2 键盘控制的启动与校准测试启动键盘遥操作模块的命令是python lerobot/scripts/teleoperate.py \ --teleop.typekeyboard \ --teleop.keyboard.action_speed0.05 \ --robot.typeso100 \ --robot.calibration_pathcalibration/so100.json启动后你会看到终端出现Press key to move joint, q to quit之类的提示。这时不要急着录数据先按每个键观察机械臂运动方向是否符合预期同时确认关节限位保护生效。一个细节按键w和s通常映射到同一根轴的正反两个方向但很多国产机械臂的控制板对反向运动有死区。如果你按反方向键时发现机械臂没有立即响应先确认一下是不是控制板固件的问题而不是键盘映射的问题。我就是在这上面浪费了很多时间最后换了个固件版本就好了。4.3 录制 HIL-SERL 格式数据的完整流程启动所有节点后进入数据采集主流程。注意不同的阶段应该在独立的终端里执行方便出错时快速定位# 终端3启动数据录制HIL-SERL 模式 python lerobot/scripts/record_data.py \ --dataset.pathdata/my_hil_serl_dataset \ --dataset.repo_idmy_hil_serl/keyboard_demo \ --dataset.fps30 \ --dataset.use_videostrue \ --env.taskreach_and_grasp \ --episode.time_limit120录制过程中每按一次键盘组合键record_data.py会创建一条新的 episode并以episode_000001这样的格式递增。我当时实际用的是 Teleop 节点自带的回车键来标记 episode 边界效果一样。完整采集一个 episode 大约需要 1 到 2 分钟取决于任务复杂度。HIL-SERL 建议每个 task 至少采集 50 个以上 episode 才能有比较稳定的训练效果。这个数据量听起来很多但实际操作起来熟悉后一小时采 30 个没压力。4.4 数据文件结构与 HDF5 格式说明采集完成后你会看到data/my_hil_serl_dataset/下生成了一堆文件my_hil_serl_dataset/ ├── meta/ │ └── episodes_000001.json ├── data/ │ ├── episode_000001.hdf5 │ └── episode_000001.mp4 └── info.json我是强烈建议直接把meta/episodes_000001.json这个文件打开看一眼的。它里面不仅记录了每个 episode 的帧数、开始时间、动作维度还保存了每个时间步的关节位置和动作增量。如果发现动作增量全是 0说明你的键盘映射没有正确写入动作信息即使图像数据是好的这集数据对训练也没有意义。HDF5 文件内部的组织方式很简洁/episode_000001/action /episode_000001/observation/state /episode_000001/observation/images/cam_0 /episode_000001/observation/images/cam_1HIL-SERL 训练时主要会读取action和observation/state这两部分。你不需要手动去操作 HDF5但需要理解它的存储逻辑这样在遇到“数据读不进来”的问题时才知道是时间戳对不上还是 key 名称不匹配。5. 常见问题与排查技巧实录5.1 关节不动或响应延迟这个是最常见的。网络上的教程往往只讲配置不讲排查。根据我的实操关节响应异常基本逃不出这几种原因现象可能原因解决方案按键无任何反应键盘监听模块未启动成功检查终端是否显示了pynput的启动日志按下键后 1 秒才动控制频率设置过低将teleop.keyboard.hz调到 30 以上只有部分关节能动关节索引配置错误运行observe命令核对关节顺序能动但方向反了机械臂校准文件搞反了方向重新执行校准流程注意正负方向我的经验是遇到任何“键盘控制异常”的问题先用最简单的测试排除硬件问题直接运行 Lerobot 自带的脚本手动给关节发一个指定的位置指令如果这样能动说明问题出在键盘映射层如果连这样都不能动那就是底层驱动的问题了。5.2 相机无法打开或图像全黑USB 相机在 Ubuntu 上有个典型的坑设备节点权限不足。第一次插上相机后你会看到/dev/video0存在但程序打开时报Permission denied。解决方式是把当前用户加进video组sudo usermod -aG video $USER然后重新登录。这个问题大概率在重新登录后消失。图像全黑的原因又是另一个方向相机的自动曝光没有就绪。Lerobot 的相机控制代码默认不启用自动曝光如果环境光线突然变化比如你打开了头顶的灯相机可能还停留在之前的曝光参数上。解决办法是在control_camera.py启动后等 10 秒再开始采数据给自动白平衡和自动曝光一个收敛的时间。5.3 HDF5 文件损坏或写入中断录制过程中如果直接关闭终端没按 CtrlC 让进程安全退出很容易导致当下的 episode 的 HDF5 文件只写了一半。下次读这个文件时可能报Unable to synchronously open file (unable to lock file)之类的错误。解决办法有两层养成习惯结束录制时按CtrlC等待进程清理完再关终端。如果已经坏了用 h5py 尝试以r模式打开并修补或者直接删掉那个 episode 重新采。5.4 数据采集频率与训练频率不匹配还有一个容易被忽视的问题采集时的dataset.fps是 30训练时配置的帧率却是 20那么模型训练时会对时间轴做重采样。如果你的任务动作速度较快这种重采样会丢失细节动作。我觉得最保险的做法是采集和训练都用同一个 fps 值不要自己随意调。除非是抓取这类慢速任务可以适当降到 15不然我不建议在帧率上做过度优化。6. 一段实操心得与后续动作最后分享几点我自己的体会。这套键盘采集 HIL-SERL 数据的流程真正难的不是技术而是耐着性子把几十个 episode 一段段采集完。中间你会遇到各种干扰手酸了、按键按错导致动作突变、相机画面里突然出现了不该出现的东西……这些都是正常的不要指望一次就能采出完美的数据集。我能给的最靠谱的建议是在正式采集前先完整跑通一次“空采”——不控制机器人只启动录制流程录几个空 episode然后读一下生成的文件确认格式完整、图像非黑、动作矩阵有数值。这一步只要花十几分钟但能避免你白白采一个小时的废数据。等数据采集稳定了下一步我打算尝试在这个键盘数据上跑一遍 HIL-SERL 的训练流程看看键盘采集的数据和真实手柄采集的数据在训练效果上的差异到底有多大。到时候再来更新一篇对比文章。