基于LeRobot与SO-101机械臂的ACT模型训练全流程实战解析
1. 项目概述从开源硬件到智能体训练最近在具身智能和机器人领域LeRobot 这个开源项目热度很高尤其是它配套的 SO 101 机械臂成为了很多研究者和开发者入门实操的首选平台。如果你正在寻找一个从硬件拆解、环境搭建到模型训练都能跑通的完整项目那么“使用 LeRobot 训练 SO 101 机械臂的 ACT 模型”这个流程无疑是一条黄金学习路径。这不仅仅是跑通一个Demo而是理解如何将一个真实的、开源的机械臂硬件通过仿真与真实数据结合的方式训练出一个能执行具体任务比如抓取的端到端策略模型。ACTAction Chunking with Transformers模型是近年来在机器人模仿学习中表现非常出色的架构它能够处理高维的视觉和状态观测并输出平滑、连贯的动作序列。将 ACT 模型部署到 SO 101 这样一款低成本、全开源的机械臂上其意义在于降低了机器人学习的研究和开发门槛。你不需要动辄数十万的工业机械臂也能验证和迭代你的算法。这个过程涵盖了机器人学的多个核心环节硬件认知、仿真环境构建、数据采集、模型训练与部署。无论是学生、研究者还是对机器人感兴趣的开发者通过复现这个流程都能系统地掌握现代机器人学习流水线的关键技能。接下来我将以一个实践者的角度拆解从开箱 SO 101 到成功训练并运行 ACT 模型的全过程分享其中每一步的细节、踩过的坑和验证有效的技巧。2. 核心硬件SO-101机械臂深度拆解与准备在开始任何代码工作之前充分理解你手中的硬件是至关重要的。SO-101 机械臂作为 LeRobot 项目的官方配套硬件其设计充分考虑了教育、研究和快速原型开发的需求。2.1 机械臂本体与组件解析SO-101 是一款6自由度的桌面级机械臂。所谓6自由度通常指的是机械臂末端的空间位姿可以由六个独立的关节运动来确定三个旋转确定姿态三个平移确定位置这为其完成抓取、放置等复杂任务提供了基础的运动能力。开箱后你需要熟悉的组件包括关节模组这是机械臂的核心运动单元。SO-101 的每个关节都集成了直流电机、减速齿轮箱和磁性编码器。编码器用于反馈电机的实时旋转位置是实现闭环控制的关键。你需要检查每个关节转动是否顺滑有无异响。末端执行器夹爪通常配套一个二指平行夹爪。夹爪的开合由一个单独的舵机或小型电机控制。它的开合范围、夹持力以及能否安装其他工具如吸盘、笔头决定了机械臂能执行的任务类型。主控板负责与上位机通常是你的电脑或树莓派通信并驱动所有关节电机和末端执行器。它通过 USB 或 UART 接收运动指令并将其转换为电机驱动信号。确保你清楚其固件版本和通信协议如 Dynamixel 协议或自定义串口协议。电源桌面机械臂通常需要独立的 12V/5A 以上的直流电源。供电不足会导致电机堵转、控制板重启甚至损坏硬件。务必使用官方推荐或参数匹配的电源适配器。注意在首次上电前请手动将机械臂各关节移动到“零位”或一个舒展的中间位置避免上电瞬间因初始位置异常导致剧烈动作发生碰撞。2.2 传感器扩展与选型考量虽然机械臂本体集成了关节编码器但要训练像 ACT 这样的视觉-动作策略模型外部视觉传感器是必不可少的。常见的方案有USB 摄像头最经济快捷的方案。可以固定在桌面或机械臂基座上提供全局的第三人称视角。对于抓取固定位置物体的任务这种“眼在手外”的配置通常足够。RGB-D 摄像头如 Intel RealSense D435i, Orbbec Astra这是更理想的方案。除了彩色图像还能提供深度信息。深度图对于判断物体距离、避免碰撞以及进行更精确的 3D 操作至关重要。LeRobot 的许多高级示例都默认支持 RGB-D 数据流。臂载摄像头将小型摄像头如树莓派摄像头安装在机械臂末端或靠近末端的位置实现“眼在手上”。这种视角更接近人类操作时的第一人称视角对于需要精细对准或环境遮挡严重的任务更有优势。但这会增加末端的质量和线缆复杂度。实操心得对于入门和大多数抓取任务一个固定的 USB 摄像头或 RGB-D 摄像头就足以开始。优先确保摄像头帧率至少 30 FPS和分辨率720p 以上并做好相机标定后续会讲这是保证后续视觉数据质量的基础。如果使用 RGB-D 相机注意其有效测距范围是否覆盖你的工作空间。3. 软件基石仿真与真实环境搭建机器人开发中“仿真先行”是提高效率、降低风险的金科玉律。我们需要搭建一个既能模拟 SO-101又能无缝对接真实硬件的软件环境。3.1 仿真环境选型MuJoCo vs. Isaac Sim目前主流的选择有两个MuJoCo 和 NVIDIA Isaac Sim。MuJoCo物理引擎速度快配置相对轻量与机器学习框架如 PyTorch集成度极高。LeRobot 官方提供了 SO-101 的 MuJoCo 模型文件.xml。在仿真中训练策略速度快成本低非常适合算法验证和初期策略学习。安装自从 MuJoCo 开源后安装变得简单。通常通过pip install mujoco即可。同时需要安装mujoco_menagerie来获取机器人模型以及mujoco_viewer用于可视化。模型加载LeRobot 的代码库中通常会有lerobot/robots/so101/assets/这样的目录存放着so101.xml文件。你需要确保仿真环境能正确找到这个模型文件及其相关的网格mesh文件。NVIDIA Isaac Sim功能强大的机器人仿真平台图形渲染逼真传感器模型丰富支持大规模并行仿真。如果你想进行更复杂的多物体交互、光线变化敏感的视觉训练或者需要高保真的传感器数据如逼真的深度图Isaac Sim 是更好的选择。但它的硬件要求高需要不错的 NVIDIA GPU学习曲线也更陡峭。部署提示Isaac Sim 通常以 Docker 容器方式运行。你需要按照官方指南拉取镜像并启动容器并配置好容器与宿主机之间用于传输控制指令和传感器数据的通信接口如 ROS 2 话题或 gRPC。我的选择与理由对于 ACT 模型训练的全流程解析我建议从MuJoCo开始。原因有三第一环境搭建简单能让你快速聚焦于 ACT 模型本身第二LeRobot 社区对 MuJoCo 的支持通常更即时、例子更丰富第三训练迭代速度快便于调试。当你在 MuJoCo 中获得一个基本可用的策略后可以再考虑将其迁移到 Isaac Sim 中进行更高保真的测试或直接进行真机部署。3.2 真机控制接口搭建仿真策略最终要落到真机上。这就需要建立上位机运行策略的电脑与 SO-101 主控板之间的通信桥梁。通信协议确认首先查阅 SO-101 的文档确定其主控板使用的通信协议。常见的是基于串口UART的简易指令协议如发送角度值或 Dynamixel SDK。LeRobot 项目通常会提供一个lerobot/robots/so101/driver/目录里面包含so101_driver.py这样的驱动文件。驱动层封装这个驱动文件的核心功能是connect(): 打开指定的串口如/dev/ttyUSB0或COM3并配置波特率。send_joint_angles(q): 接收一个包含6个关节角度的列表q单位通常是弧度将其编码成主控板能识别的字节流并发送。get_joint_angles(): 从主控板读取当前编码器反馈的关节角度。send_gripper_command(width): 控制夹爪开合到指定宽度。统一接口抽象为了便于策略代码在仿真和真机间切换我们需要定义一个统一的机器人接口类。例如创建一个RobotInterface基类它包含set_joint_positions(q),get_joint_positions(),set_gripper(width)等方法。然后分别实现MuJoCoRobot和RealSO101Robot两个子类。这样你的 ACT 模型在推理时只需要调用robot.set_joint_positions(action)而不需要关心背后是仿真还是真机。提示真机控制务必加入软件限位和运动插值。在驱动代码中对输入的目标关节角度进行范围检查防止超出机械限位。同时不要直接将目标角度发送给电机而应在当前角度和目标角度之间进行线性或五次多项式插值生成一串平滑的中间点依次发送这样机械臂运动才会平稳减少冲击。4. 数据引擎采集、管理与处理数据是机器学习模型的燃料。对于模仿学习我们需要采集“专家演示”数据即记录在成功完成任务时机器人的观测图像、关节状态和采取的动作。4.1 数据采集策略设计采集方式主要分为两种人工遥操作采集这是最直接的方式。你可以通过一个游戏手柄、3D鼠标或者图形化界面手动控制机械臂仿真或真机完成一次成功的抓取同时录制整个过程的数据。LeRobot 通常提供record_demo.py之类的脚本。这种方式数据质量高但耗时耗力且采集者的技能会影响数据分布。脚本化自动采集对于一些结构化的简单任务如从固定位置A抓取物体放到固定位置B可以编写脚本让机械臂自动执行一系列预定义的点位运动并录制数据。这种方式可以批量产生大量数据但“智能”都体现在你的脚本里数据多样性可能不足。采集内容每一帧数据通常包含一个“数据字典”dict。observation: 观测字典。包含imageH, W, 3 的 numpy 数组depth如果有深度相机joint_pos6维关节角度向量joint_vel关节速度可选等。action: 动作字典。包含joint_pos下一时刻的目标关节角度6维gripper夹爪开合指令1维。注意这里记录的是“执行器指令”而不是底层电机的扭矩或电压。timestep: 时间戳用于确保数据序列的连续性。4.2 数据集格式与存储优化LeRobot 定义了一套清晰的数据集格式通常使用 Hugging Face Datasets 库来管理这非常有利于共享和版本控制。存储结构数据集被组织成episode_data.hdf5文件和metadata.json文件。每个演示episode是 HDF5 文件中的一个组group里面包含了这个 episode 所有时间步的观测和动作数据以数组形式存储。元数据metadata.json记录了数据集的全局信息如{ action_dim: 7, // 6个关节 1个夹爪 observation_dim: {image: [128, 128, 3], joint_pos: 6}, num_episodes: 100, episode_lengths: [45, 50, ...] // 每个episode的长度 }处理与增强原始采集的数据往往不能直接用于训练。图像预处理统一缩放到固定尺寸如 128x128 或 224x224进行归一化像素值从 [0, 255] 缩放到 [0, 1] 或 [-1, 1]。动作归一化计算训练数据集中动作的均值和标准差对动作进行标准化。这有助于模型训练更稳定。数据增强对于图像可以随机进行小幅度的裁剪、颜色抖动、高斯噪声等增加数据的多样性提升模型的泛化能力。注意对于机器人任务空间变换如水平翻转要谨慎使用因为它可能改变任务的物理含义。踩坑记录早期我曾忽略了对关节角度进行归一化。由于各关节的运动范围不同例如关节1转动范围是 ±180°关节6可能是 ±360°直接输入原始角度值会导致模型对数值大的关节关注过度。进行归一化后例如将所有关节角度映射到 [-1, 1] 区间训练收敛速度和最终性能都有显著提升。5. 模型核心ACT架构详解与实现ACT 模型是整个过程的大脑它的设计巧妙地结合了 Transformer 的序列建模能力和机器人动作生成的需求。5.1 模型输入输出与工作原理想象一下教机器人抓杯子你给它看一段你抓杯子的视频图像序列以及你的手臂在每个时刻的角度状态序列。ACT 模型的学习目标就是建立从“看到的”到“该做的”之间的映射。输入编码视觉编码每一帧的图像通过一个预训练的视觉编码器如 ResNet-18 的卷积部分提取特征得到一个特征向量。这个编码器通常在训练初期被冻结不更新权重只利用其强大的通用视觉特征提取能力。状态编码当前的关节角度、夹爪宽度等低维状态信息通过一个简单的多层感知机MLP进行编码。特征融合将视觉特征向量和状态特征向量拼接concatenate起来形成当前时间步的“观测嵌入”。历史上下文与动作块ChunkingACT 不是只根据当前观测预测下一个动作而是考虑过去一段时间例如最近10步的观测序列。更重要的是它一次性预测未来一个“动作块”例如未来4个时间步的所有动作。这是“Action Chunking”的由来。将历史观测序列和要预测的动作块长度信息一起输入给 Transformer 编码器。Transformer 解码Transformer 的核心是自注意力机制它能捕捉序列中不同时间步信息之间的依赖关系。在这里它学习到“当连续看到手靠近杯子、对准把手、然后合拢”这样的模式时应该输出“一系列逐渐闭合夹爪并抬起的关节动作”。模型输出的是未来一个动作块内每个时间步的动作7维6关节1夹爪。训练目标损失函数通常采用平滑L1损失Huber Loss或均方误差MSE计算模型预测的动作块与数据集中真实专家动作块之间的差异。通过反向传播优化 Transformer 和 MLP 的权重。5.2 关键超参数调优经验ACT 模型的性能对超参数比较敏感以下是一些调优经验动作块长度action_chunk_size这是最重要的参数之一。太短如2模型规划能力弱动作可能不连贯太长如10预测难度急剧增加训练不易收敛。对于桌面抓取这类中等速度的任务4到6是一个不错的起点。你可以观察真机运行时的流畅度来调整。历史上下文长度observation_history_size模型回顾过去多少步的观测。通常设置为动作块长度的2-3倍。例如动作块长度为5历史长度可以设为10或15。Transformer 层数与隐藏层维度对于 SO-101 这类任务一个较小的模型通常就够用。例如4层 Transformer隐藏维度为256。模型太大不仅训练慢还容易在小数据集上过拟合。学习率与优化器使用 AdamW 优化器并采用带热启动Warmup的学习率调度器。初始学习率可以设在3e-4到1e-4之间。Warmup 阶段例如前1000步让学习率从0线性增加到初始值有助于训练初期稳定。实操心得不要一上来就训练很长时间。先用一个很小的数据集比如5条演示和较少的训练步数如5000步快速验证你的数据流水线、模型前向传播和损失下降是否正常。这个过程叫做“过拟合一个小批次”。如果能在这个小数据集上让训练损失降到接近0说明你的代码基础是没问题的然后再用全量数据正式训练。6. 训练流水线构建与实验管理构建一个稳健、可复现的训练流水线是项目成功的关键。6.1 训练脚本结构与配置管理一个清晰的训练脚本应包含以下模块# 伪代码结构示意 def main(config): # 1. 加载配置使用Hydra或YAML文件管理所有超参数 cfg load_config(config_path) # 2. 初始化数据集和数据加载器 train_dataset load_hdf5_dataset(cfg.data_path, splittrain) train_loader DataLoader(train_dataset, batch_sizecfg.batch_size, shuffleTrue) # 3. 初始化模型、优化器、损失函数 model ACTModel(cfg.model).to(device) optimizer AdamW(model.parameters(), lrcfg.lr) criterion nn.SmoothL1Loss() # 4. 初始化日志记录器如Weights Biases, TensorBoard logger setup_logger(cfg) # 5. 训练循环 for epoch in range(cfg.num_epochs): for batch in train_loader: obs, actions batch # 获取批次数据 pred_actions model(obs) # 前向传播 loss criterion(pred_actions, actions) # 计算损失 optimizer.zero_grad() loss.backward() # 反向传播 optimizer.step() # 参数更新 # 记录损失、图像等 logger.log({train_loss: loss.item()}) # 6. 定期在验证集上评估并保存检查点 if epoch % cfg.eval_freq 0: eval_loss evaluate(model, val_loader) logger.log({val_loss: eval_loss}) save_checkpoint(model, optimizer, epoch, cfg.checkpoint_dir)配置管理强烈推荐使用 Hydra 或简单的 YAML 文件来管理所有配置模型结构、训练参数、数据集路径。这样每次实验的完整设置都被保存下来确保结果可复现。6.2 实验跟踪与模型评估训练过程中不能只盯着损失曲线下降。可视化是关键损失曲线观察训练损失和验证损失。理想情况是两者同步平稳下降。如果训练损失下降但验证损失上升可能是过拟合。动作预测对比定期从验证集中采样一些序列将模型预测的动作块与真实的专家动作绘制在同一张图上对比它们的轨迹形状。这能直观看出模型学到了什么。仿真回放在 MuJoCo 环境中用训练中的模型策略控制仿真机械臂录制视频。这是最直接的评估方式。可以计算成功率如10次尝试成功几次。评估指标成功率在仿真或真机上运行策略 N 次如50次计算成功完成任务的次数比例。这是终极指标。轨迹误差计算模型预测的末端执行器轨迹与专家轨迹之间的平均位置误差。动作平滑度计算预测动作的加速度二阶差分的均值值越小说明动作越平滑对硬件越友好。我的工作流我使用Weights Biases (WB)来跟踪所有实验。它不仅能记录超参数、损失曲线还能直接记录仿真测试的视频、图像对比图。通过 WB 的表格对比不同实验如改变动作块长度、学习率的结果能高效地找到最佳配置。7. 仿真到实物的迁移与部署策略在仿真中表现完美的策略直接部署到真机常常会失败。这被称为“仿真到实物的差距”。7.1 差距来源与缓解技巧差距主要来自动力学差异仿真中的摩擦、阻尼、电机响应模型与真实世界不符。技巧在仿真中引入“域随机化”。训练时随机化仿真环境中的物理参数如物体质量、摩擦系数、电机增益、关节零位偏移等。这样训练出的策略会对这些变化更鲁棒。视觉差异仿真渲染的图像与真实摄像头拍摄的图像在纹理、光照、噪声上不同。技巧使用领域随机化或领域自适应。在仿真中随机改变灯光颜色、强度、纹理添加随机噪声。更高级的做法是使用生成对抗网络GAN将仿真图像风格迁移到接近真实图像。更实用的技巧直接使用真实图像进行训练。这就是为什么之前强调数据采集的重要性。用真机采集的少量真实数据哪怕只有几十条对仿真预训练的模型进行微调fine-tuning能极大提升其在真机上的表现。延迟与通信仿真中假设指令瞬时执行而真机存在通信延迟和电机响应时间。技巧在仿真中加入一个小的、随机的动作延迟来模拟真实情况。在真机控制循环中确保你的推理和控制频率是匹配且稳定的。7.2 真机部署与安全监控将训练好的模型部署到真实的 SO-101 上需要谨慎。部署流水线加载训练好的模型检查点.pth文件。初始化真机驱动 (RealSO101Robot)。启动摄像头并初始化与训练时相同的图像预处理流程。进入主循环while task_not_done: # 1. 获取当前观测 image camera.get_image() joint_pos robot.get_joint_positions() # 2. 预处理观测缩放、归一化 obs preprocess(image, joint_pos) # 3. 模型推理得到动作块 with torch.no_grad(): action_chunk model(obs) # 4. 只取动作块的第一个动作执行模型预测的是未来多个动作 next_action action_chunk[0] # 5. 发送给机器人 robot.set_joint_positions(next_action[:6]) robot.set_gripper(next_action[6]) # 6. 等待一个控制周期如0.1秒 time.sleep(control_period)安全第一急停开关手边必须有一个物理急停开关并确保其功能正常。软件限位在驱动层和策略层都设置关节角度软限位绝对禁止超限运动。人机交互区域用明显的标记划出机械臂工作区域操作时人员不要进入。看门狗实现一个软件看门狗。如果主控制循环卡住或超过预定时间没有更新指令看门狗触发使机械臂停止所有电机。低速首次运行第一次运行新策略时将模型输出的动作幅度按比例缩小例如乘以0.3以慢速运行观察其行为是否符合预期。8. 常见问题排查与性能优化在实际操作中你一定会遇到各种问题。这里汇总了一些典型问题及其解决思路。8.1 训练阶段问题问题现象可能原因排查与解决思路训练损失不下降或震荡剧烈学习率过高或过低尝试使用学习率查找器LR Finder找到一个合适的范围或采用带Warmup的调度器。验证损失远高于训练损失模型过拟合1. 增加数据增强的强度。2. 在模型中添加Dropout层。3. 减少模型容量隐藏层维度、层数。4. 收集更多样化的演示数据。模型预测的动作值始终接近零动作归一化问题或最后一层激活函数不当1. 检查动作归一化的均值和标准差计算是否正确。2. 确保模型输出层没有使用会将值压缩到特定范围如Tanh的激活函数除非你做了对应的反归一化。通常回归任务输出层不使用激活函数。仿真中策略表现“抽搐”动作块长度太短或控制频率过高1. 增加action_chunk_size让模型有更长的规划视野。2. 适当降低控制频率如从50Hz降到20Hz给模型更长的反应时间。8.2 部署与真机运行问题问题现象可能原因排查与解决思路真机动作卡顿、不流畅控制循环周期不稳定或通信延迟大1. 使用高精度定时器如time.perf_counter()严格保证循环周期。2. 检查串口波特率是否设置正确尝试使用更高效的通信协议如Socket。3. 在真机端如树莓派本地运行轻量级策略减少网络传输。抓取位置总是有偏差相机标定不准或手眼标定误差这是最常见的问题1. 重新进行相机内参标定确保焦距、畸变参数准确。2. 重新进行手眼标定Eye-to-Hand精确计算相机坐标系与机械臂基座坐标系之间的变换关系。这是一个必须耐心做好的步骤。策略在仿真成功真机失败仿真到实物的差距1. 使用在真机上采集的少量数据对模型进行微调。2. 在仿真中增加域随机化并重新训练。3. 检查真机传感器的数据如图像亮度、对比度是否与仿真预处理后的数据分布一致。机械臂到达目标点附近后抖动控制器增益不合适或模型输出动作噪声大1. 调整真机底层驱动器的PID增益参数。2. 对模型输出的动作进行低通滤波平滑高频噪声。3. 在训练数据中可以对专家的动作轨迹也进行轻微的平滑处理。最后的建议机器人学习是一个高度系统性的工程成功来自于对每个环节细节的把握。从 SO-101 机械臂的硬件连接到 MuJoCo 仿真的一行配置再到数据采集时相机的一个角度任何疏忽都可能导致最终失败。保持耐心做好实验记录从小任务开始验证比如先让机械臂笔直地移动一段距离逐步增加复杂度你最终一定能让这个开源的机械臂灵活地动起来完成你设想的任务。这个从零到一的过程所获得的关于硬件、软件、算法联调的经验远比单纯调通一个模型更有价值。