机械臂这摊子事,说简单也简单,说坑多那是真的多。我前后折腾过五六款不同价位的桌面级机械臂,从总线舵机方案到谐波减速器方案都摸过一遍,最后在 LeRobot 这套生态上停留的时间最长。原因不复杂:它把"数据采集—训练—部署"这条链路打通了,不用自己从零写一套遥操作采集框架,也不用为了跑一个模仿学习算法去啃半个月的论文。SO-ARM100 这个臂体本身结构不复杂,3D 打印件加几个总线舵机,成本压得很低,但真正让它有价值的是配套的 ACT 模型——Action Chunking Transformer,动作分块 Transformer。这篇就把我从零搭环境、标定、采数据、训 ACT、调参、部署的完整过程摊开讲,重点放在那些文档里不会写、但你不注意就会卡一整天的细节上。
1. 先搞清楚 SO-ARM100 这套东西到底适合谁
1.1 它不是工业臂,别拿工业标准要求它
SO-ARM100 的定位非常明确:低成本、可复现、面向学习与研究的桌面级机械臂。它的结构件基本靠 3D 打印,关节驱动用的是总线舵机(常见的是 STS 系列),重复定位精度大概在毫米级,负载能力也就几百克。你要是想拿它做精密装配、力控打磨,那方向就错了。但如果你要做的是抓取放置、简单分拣、模仿学习的数据采集与策略验证,它完全够用,而且成本只有工业臂的零头。
我一开始也犯过这个毛病,总想着让它去干一些"精细活",结果发现舵机回程间隙和打印件的形变叠加起来,末端重复定位误差能到两三毫米。后来调整心态,把它当成一个"算法验证平台"而不是"生产工具",整个项目的推进就顺了。这个认知转变很关键,因为它直接决定了你后面采数据时对精度的预期,以及 ACT 模型需要多强的泛化能力来补偿硬件误差。
1.2 为什么选 ACT 而不是别的模仿学习方案
模仿学习这块,常见的选择有行为克隆(BC)、扩散策略(Diffusion Policy)、ACT 等。BC 最简单,但它在长时序任务上容易累积误差,因为它是逐帧预测,每一步的小偏差会滚雪球。Diffusion Policy 效果好,但推理速度慢,对算力要求高,桌面级部署不太友好。ACT 的核心思路是"动作分块"——一次预测未来一段时间的动作序列(比如 100 步),而不是只预测下一步。这样做的好处是动作在时间上更连贯,抖动少,而且推理时可以用时间集成(temporal ensemble)来平滑输出。
对于 SO-ARM100 这种舵机臂,ACT 的优势特别明显。舵机本身响应有延迟,逐帧控制容易出现"追不上"或者"过冲"的情况,而 ACT 一次给出一段动作,舵机可以平滑地跟踪,实际跑下来轨迹明显更稳。这也是为什么 LeRobot 官方把 ACT 作为默认推荐方案的原因。
1.3 你需要准备的东西清单
在动手之前,先把物料盘清楚,免得做到一半发现缺东西。硬件方面:SO-ARM100 的打印件一套(主臂和从臂各一套,如果你要做遥操作采集的话)、总线舵机若干(具体数量看你的自由度配置,常见是 6 个)、舵机驱动板、电源(舵机供电要独立,别指望 USB 供电)、USB 转串口模块、以及一台能跑训练的机器(有独立显卡最好,没有的话 CPU 也能训但慢)。
软件方面:Ubuntu 系统(我用的是 22.04,20.04 也行)、Python 环境、LeRobot 库、以及相机(做视觉模仿学习必须要有,常见的是 RealSense 或者普通 USB 摄像头)。这里要特别提醒一句:舵机供电一定要独立,我见过太多人用 USB 给舵机供电,结果一动就掉电重启,排查半天以为是代码问题,其实是供电不足。
2. 环境搭建:那些让你卡半天的依赖问题
2.1 系统与 Python 版本的选择
LeRobot 对 Python 版本有要求,太新太旧都可能出问题。我实测下来 Python 3.10 是最稳的,3.11 也能跑但偶尔有些包编译会报错。系统层面,Ubuntu 22.04 是首选,因为很多依赖(比如 PyTorch 的 CUDA 版本)在这个系统上兼容性最好。
创建虚拟环境这一步别偷懒,直接用 conda 或者 venv 隔离。我习惯用 conda,因为后面装 PyTorch 的时候版本管理方便一些:
conda create -n lerobot python=3.10 conda activate lerobot装完之后先别急着装 LeRobot,先把 PyTorch 装好。这里有个坑:PyTorch 的 CUDA 版本要和你显卡驱动匹配。你先用nvidia-smi看一下驱动支持的 CUDA 版本,然后去 PyTorch 官网找对应的安装命令。别直接pip install torch,那样装的是 CPU 版本,训练的时候你会发现 GPU 根本用不上。
2.2 LeRobot 安装过程中的依赖冲突
LeRobot 的安装本身不复杂,从源码装:
git clone https://github.com/huggingface/lerobot.git cd lerobot pip install -e .但这里经常出问题的是依赖冲突。最常见的是numpy版本、opencv版本和torch版本之间的打架。我的经验是,先装 LeRobot 的基础依赖,然后再单独处理相机相关的包。如果你用的是 RealSense,pyrealsense2这个包有时候会和系统里的 libusb 版本冲突,解决办法是先装系统级的 libusb:
sudo apt install libusb-1.0-0-dev然后再 pip 装 pyrealsense2。如果还是不行,就去看 RealSense 官方的 SDK 安装文档,先把底层驱动装好再装 Python 包。
还有一个坑是ffmpeg相关的。LeRobot 在录视频的时候会用到 ffmpeg,如果系统里没有或者版本太老,录出来的视频会花屏或者直接失败。装一下:
sudo apt install ffmpeg2.3 舵机驱动与串口权限
总线舵机通过串口和电脑通信,Linux 下串口设备默认是需要 root 权限的。你每次都要 sudo 跑脚本很麻烦,解决办法是把当前用户加到 dialout 组:
sudo usermod -a -G dialout $USER然后注销重新登录生效。这一步做完之后,插上舵机驱动板,用ls /dev/ttyUSB*或者ls /dev/ttyACM*看一下设备名。注意,设备名可能会变,今天插上是 ttyUSB0,明天可能就是 ttyUSB1。稳妥的做法是用 udev 规则固定设备名,或者每次跑之前先确认一下。
我踩过的一个坑是:舵机驱动板的波特率设置和代码里不一致。总线舵机常见的波特率是 1000000(1M),但有些驱动板默认是 115200。如果你发现舵机没反应,先检查波特率。这个在 LeRobot 的配置文件里可以改,但很多人不知道去哪改,就在那干着急。
3. 机械臂组装与标定:精度从这里开始丢
3.1 组装时的机械零位对齐
组装这一步看起来是体力活,但其实决定了后面标定的难度。SO-ARM100 的每个关节在组装时都有一个"机械零位",也就是舵机在特定角度时,机械结构处于一个标准姿态。如果你组装的时候零位没对齐,后面软件标定就要花大力气去补偿,甚至补偿不回来。
我的做法是:在拧螺丝之前,先用舵机调试软件把每个舵机转到中位(通常是 2048,对应 180 度舵机的 90 度位置),然后再把机械臂的连杆装上去,让机械结构在这个中位时处于一个合理的姿态(比如所有关节都大致垂直或水平)。这样软件里的零位和机械零位基本对齐,后面标定就轻松很多。
3.2 舵机 ID 与方向配置
每个总线舵机都有一个 ID,多个舵机挂在同一条总线上,靠 ID 区分。组装前一定要先把 ID 设好,并且记下来哪个 ID 对应哪个关节。我建议按关节顺序设 ID,比如底座旋转是 1,肩部是 2,肘部是 3,以此类推。这样代码里配置的时候不容易搞混。
方向配置也是个容易出错的地方。同样的舵机,装在不同的关节上,正转对应的机械运动方向可能相反。LeRobot 的配置里有一个motor direction的参数,你需要根据实际情况设置。判断方法很简单:手动给一个正角度指令,看关节往哪个方向动,如果和预期相反,就把方向参数取反。
3.3 标定流程与常见偏差处理
标定是让软件知道"舵机角度"和"末端位姿"之间的对应关系。LeRobot 有一套标定脚本,流程大致是:把机械臂摆到几个已知姿态,记录每个姿态下的舵机读数,然后拟合出一个映射。这个过程听起来简单,但实际操作中有几个坑。
第一个坑是舵机回程间隙。你正转到位和反转到位,舵机读数可能差几十个计数。解决办法是标定时始终从同一个方向接近目标位置,比如始终从负方向往正方向转到位,这样间隙的影响是一致的,可以被拟合吸收掉。
第二个坑是打印件的形变。3D 打印件在受力时会轻微形变,尤其是长连杆。如果你发现标定完精度还是不行,检查一下是不是某个关节的打印件太软。解决办法是增加填充率或者换更硬的材料,比如 PETG 或者加碳纤的 PLA。
第三个坑是相机外参标定。如果你做视觉模仿学习,相机和机械臂基座的相对位置必须固定,而且要知道这个变换关系。最简单的做法是把相机固定在机械臂基座附近,然后用眼在手外(eye-to-hand)的方式标定。LeRobot 里有辅助工具,但精度要求不高的时候,手动量一下相机相对基座的位移和角度也能凑合用。
4. 数据采集:质量比数量重要得多
4.1 遥操作采集的两种模式
LeRobot 支持两种数据采集模式:一种是主从臂遥操作,就是你手动拖动主臂,从臂跟随运动,同时记录从臂的关节角度和相机画面;另一种是直接用键盘或者手柄控制。主从臂的方式更直观,采集的数据也更自然,但需要你有两套臂体。如果只有一套臂,那就只能用键盘控制,效率低一些,但也能用。
我强烈建议用主从臂方式,因为模仿学习的核心是"人类演示",主从臂能让你像教小孩一样去教机械臂,动作的连贯性和自然度是键盘控制比不了的。而且主从臂采集的数据,动作分布更接近真实任务,训练出来的策略泛化性更好。
4.2 采集时的几个关键细节
采集数据的时候,有几个细节直接决定训练效果。第一,每个 episode 的起始状态要尽量一致。比如你做抓取任务,每次开始的时候物体位置可以略有不同,但机械臂的初始姿态要基本一致。这样模型学起来容易收敛。第二,动作要平滑,不要有突然的抖动。舵机臂本身响应就慢,如果你手动拖的时候一顿一顿的,采出来的数据噪声很大,训练出来的策略也会抖。第三,相机画面要稳定。相机不能有晃动,光照也要尽量一致,否则模型会把光照变化当成任务相关的特征去学,换个环境就废了。
还有一个容易被忽略的点:采集频率。LeRobot 默认的采集频率是 30Hz 左右,但舵机的实际响应可能跟不上。如果你发现采出来的动作序列有明显的阶梯感,可以适当降低采集频率,比如降到 15Hz 或者 10Hz。频率低了,每个动作之间的间隔大了,但动作本身更干净,训练效果反而可能更好。
4.3 数据集的划分与增强
采集完之后,数据要划分成训练集和验证集。我的习惯是留出 10% 到 20% 的 episode 做验证,用来监控过拟合。如果任务比较简单,数据量不大,也可以做交叉验证,但那样训练时间会成倍增加。
数据增强这块,视觉模仿学习常用的有随机裁剪、颜色抖动、随机擦除等。但要注意,不是所有增强都适合机械臂任务。比如颜色抖动,如果你的任务依赖颜色信息(比如抓红色方块),那颜色抖动就会破坏任务相关性。随机裁剪也要小心,如果裁剪掉了物体,模型就学不到东西了。我的经验是,先用最少的增强(比如只做轻微的随机裁剪),看效果,不够再加。
5. ACT 模型训练:参数背后的逻辑
5.1 ACT 的网络结构与关键参数
ACT 的核心是一个 Transformer 编码器-解码器结构。编码器把当前观测(图像 + 关节角度)编码成特征,解码器根据这个特征和一组可学习的"动作查询"(action queries)生成未来一段时间的动作序列。关键参数有几个:chunk_size(动作分块大小)、hidden_dim(隐藏层维度)、n_heads(注意力头数)、n_encoder_layers和n_decoder_layers(编码器和解码器层数)。
chunk_size是最重要的参数之一。它决定了模型一次预测多少步动作。太小了,动作连贯性不够,退化成逐帧预测;太大了,模型要预测太远的未来,难度增加,而且推理延迟也大。对于 SO-ARM100 这种舵机臂,我实测下来chunk_size在 50 到 100 之间比较合适。任务动作快、周期短的,用 50;动作慢、周期长的,用 100。
5.2 训练过程中的 loss 曲线解读
训练 ACT 的时候,loss 曲线是你判断训练状态的主要依据。ACT 的 loss 通常由两部分组成:动作预测的 L1 loss 和 KL 散度(如果用了 VAE 结构)。正常情况下,loss 会先快速下降,然后进入一个缓慢下降的平台期。如果你看到 loss 震荡很厉害,可能是学习率太大了;如果 loss 下降很慢或者不下降,可能是学习率太小,或者数据有问题。
我遇到过一个情况:loss 一直降不下去,排查了半天发现是数据里的动作范围没有归一化。ACT 对输入的尺度比较敏感,关节角度和图像像素值都要归一化到合理范围。LeRobot 的数据处理流程里默认会做归一化,但如果你自己处理数据,一定要检查这一步。
5.3 过拟合的识别与应对
桌面级机械臂的数据量通常不大,几十到几百个 episode,很容易过拟合。过拟合的表现是:训练 loss 持续下降,但验证 loss 开始上升,或者验证集上的成功率明显低于训练集。应对方法有几个:增加数据量(最有效但最费时间)、加 dropout、减小模型规模、早停(early stopping)。
我的经验是,对于 SO-ARM100 这种任务,模型规模不用太大。hidden_dim设 256 或者 512 就够了,再大容易过拟合,而且推理也慢。层数也不用太深,编码器和解码器各 4 层左右就能work。关键还是数据质量,数据好了,小模型也能跑出好效果。
6. 调参实战:从能跑到跑好的那些调整
6.1 学习率与 batch size 的配合
学习率和 batch size 是绑在一起调的。一般来说,batch size 增大,学习率也可以相应增大。但 ACT 的训练对 batch size 比较敏感,太小了梯度噪声大,太大了显存不够。我的建议是,如果你的显存允许,batch size 设 8 到 16,学习率从 1e-5 开始试。如果 loss 下降太慢,加到 3e-5 或者 5e-5;如果震荡,降到 1e-5 以下。
这里有个小技巧:用学习率预热(warmup)。训练初期用很小的学习率,然后逐渐增加到设定值。这样可以让模型在初期稳定地适应数据分布,避免一开始就震荡。LeRobot 的训练脚本里通常有 warmup 的配置,把 warmup 步数设成总步数的 5% 到 10% 就行。
6.2 chunk size 与推理频率的权衡
前面说了chunk_size影响动作连贯性,但它还影响推理频率。ACT 推理的时候,一次生成chunk_size步动作,然后可以有两种执行方式:一种是全部执行完再推理下一次,另一种是执行一部分就重新推理(时间集成)。全部执行完的方式推理频率低,计算量小,但动作的实时性差;时间集成的方式推理频率高,动作更平滑,但计算量大。
对于 SO-ARM100,我推荐用时间集成,但集成窗口不用太大。具体做法是:每次推理生成chunk_size步动作,但只执行前k步(比如 k=10),然后重新推理。这样既有动作分块的连贯性,又有较高的推理频率来保证实时性。k的大小可以根据你的控制频率来定,控制频率高就小一点,低就大一点。
6.3 视觉编码器的选择与冻结策略
ACT 的视觉编码器通常用 ResNet 或者 ViT。ResNet 轻量,推理快,适合桌面级部署;ViT 表达能力强,但计算量大。对于 SO-ARM100 这种任务,ResNet18 或者 ResNet34 就够用了。如果你用的是预训练的 ResNet,可以考虑冻结前面的层,只训练后面的层,这样可以加快训练速度,也能减少过拟合。
冻结策略要看你的数据量。数据量少(比如几十个 episode),冻结大部分层,只微调最后几层;数据量多(几百个 episode),可以解冻更多层,甚至全部训练。我一般是从冻结开始,看验证集效果,如果欠拟合再逐步解冻。
6.4 动作平滑与时间集成
时间集成是 ACT 的一个关键技巧。它的核心思想是:每次推理生成的动作序列,不是只执行第一步,而是把多次推理的结果在时间上做加权平均。这样可以让动作更平滑,减少抖动。LeRobot 里默认实现了时间集成,但权重函数可以调。常用的权重是指数衰减,越近的推理结果权重越高。
我实测下来,对于舵机臂,时间集成能明显减少抖动,尤其是快速运动的时候。但权重函数不能太激进,否则动作会变得"迟钝",跟不上任务节奏。我的经验是,指数衰减的系数设在 0.1 到 0.5 之间比较合适,具体值要根据任务调整。
7. 部署与实测:从仿真到真机的落差
7.1 模型导出与推理优化
训练完之后,模型要导出成推理格式。LeRobot 支持直接加载训练好的 checkpoint 做推理,但如果你要部署到边缘设备(比如 Jetson),可能需要做模型转换和优化。常见的优化手段有:量化(把 FP32 转成 FP16 或 INT8)、剪枝、算子融合等。
对于桌面级部署,如果用的是带显卡的 PC,其实不用太激进的优化,直接跑 FP32 也能到实时。但如果用 Jetson 或者树莓派,那量化就很有必要了。量化的时候要注意,视觉编码器对量化比较敏感,量化后精度可能下降明显。我的做法是只量化后面的 Transformer 部分,视觉编码器保持 FP16。
7.2 真机部署时的延迟与抖动处理
真机部署最大的问题是延迟。从相机采集图像,到模型推理,再到舵机执行,这一整条链路的延迟如果太大,机械臂就会"反应迟钝",甚至出现振荡。延迟的来源主要有:相机采集延迟、模型推理延迟、通信延迟、舵机响应延迟。
降低延迟的办法:用高帧率相机(至少 30fps)、用 GPU 推理、用高速串口(波特率拉到 1M 以上)、选响应快的舵机。另外,控制频率不要设太高,舵机跟不上反而会抖。我一般把控制频率设在 20Hz 到 30Hz,这个频率下舵机响应跟得上,动作也够流畅。
7.3 实际抓取任务中的偏差修正
真机跑起来之后,你会发现模型预测的动作和实际执行的有偏差。偏差的来源有几个:标定误差、舵机回程间隙、机械形变、以及模型本身的预测误差。修正偏差的办法,一是提高标定精度,二是加闭环反馈(比如用视觉伺服),三是在训练数据里加入更多的状态变化,让模型学会补偿。
我做过一个简单的抓取任务,模型在训练集上的成功率能到 90% 以上,但真机上只有 60% 左右。后来发现主要是标定误差和舵机间隙导致的。重新标定,并且在标定时考虑了回程间隙,成功率提到了 80% 左右。剩下的差距,靠增加数据量和调整时间集成参数又补了一些。
8. 那些文档里不会写的避坑经验
8.1 舵机过热与保护
总线舵机在堵转或者频繁启停的时候会发热,温度过高会触发保护,舵机直接罢工。我遇到过好几次,跑着跑着机械臂突然不动了,一摸舵机烫手。解决办法:一是限制舵机的输出力矩,别让它长时间堵转;二是加散热片或者风扇;三是在代码里加温度监控,温度过高就暂停任务。
LeRobot 本身没有温度监控功能,需要自己加。总线舵机通常支持读取温度,你可以在控制循环里定期读一下,超过阈值就报警或者暂停。这个功能在长时间运行的任务里特别重要。
8.2 电源噪声导致的通信错误
总线舵机和电脑通过串口通信,如果电源噪声大,串口通信会出错,表现为舵机偶尔不响应或者返回错误数据。这个问题的根源通常是舵机电源和逻辑电源没有隔离。解决办法是用独立的电源给舵机供电,并且加滤波电容。如果条件允许,用带隔离的 USB 转串口模块。
我踩过这个坑,排查了很久。现象是机械臂跑一段时间就随机出现某个关节不动,重启又好了。后来用示波器看电源,发现舵机启动瞬间电压跌落很大,导致串口芯片复位。换了独立电源加电容之后,问题消失。
8.3 数据采集时的相机同步问题
如果你用多个相机(比如一个全局相机加一个腕部相机),相机之间的同步很重要。如果不同步,采出来的数据里,不同视角的画面时间戳对不上,训练的时候模型会学到错误的对应关系。LeRobot 支持多相机采集,但同步需要自己保证。最简单的办法是用硬件触发,或者用软件时间戳对齐。
我用的是软件时间戳对齐,采集的时候记录每个相机帧的时间戳,然后在训练前把时间戳对齐到最近的控制周期。这样做精度差一些,但对于桌面级任务够用了。如果任务对同步要求高,还是建议上硬件触发。
8.4 模型在不同光照下的泛化
视觉模仿学习最怕的就是光照变化。训练的时候光照好,部署的时候光照变了,模型就懵了。解决办法:一是在采集数据的时候故意变化光照,让模型见过各种光照条件;二是在训练时做颜色增强;三是用对光照不敏感的特征,比如边缘特征或者深度图。
我试过用深度相机(RealSense D435i),深度图对光照变化不敏感,泛化性明显好于 RGB。但深度图也有问题,比如反光表面测不准,透明物体测不到。所以如果任务里有这些物体,还是得靠 RGB,那就得在数据增强和光照变化上下功夫。
8.5 训练中断后的恢复
训练大模型的时候,中途可能会因为各种原因中断(断电、显存溢出、系统更新等)。如果没有 checkpoint,之前的训练就白费了。LeRobot 默认会定期保存 checkpoint,但保存频率可以调。我的建议是,每训练一定的步数就保存一次,比如每 1000 步或者每 10 分钟。这样即使中断,也能从最近的 checkpoint 恢复。
恢复训练的时候要注意,优化器的状态也要保存和加载,否则学习率调度和动量会重置,影响训练效果。LeRobot 的 checkpoint 里通常包含优化器状态,但如果你自己写训练脚本,记得把优化器状态也存下来。
9. 从这套流程里我真正学到的东西
折腾完这一整套,我最大的感受是:硬件精度决定了模型效果的上限,而数据质量决定了你能不能摸到这个上限。SO-ARM100 的硬件精度有限,所以你不能指望它做出工业级的精细操作,但在这个限制下,把数据采好、把标定做准、把参数调对,它依然能完成很多有意思的任务。
另一个体会是,调参不是玄学,而是有逻辑的。每个参数背后都有它的物理意义或者数学意义,理解了这些,调参就有方向,而不是盲目试。比如chunk_size对应的是动作的时间相关性,学习率对应的是优化过程的稳定性,时间集成对应的是动作的平滑性。想清楚这些,调参就变成了一个有据可循的过程。
最后说一个我个人的小习惯:每次做新任务,我都会先用很少的数据(比如 10 个 episode)快速训一个模型,看看能不能跑通整个流程。如果能跑通,再增加数据量去提升效果;如果跑不通,说明流程里有问题,先排查流程,别急着堆数据。这个习惯帮我省了很多时间,也避免了很多无效劳动。