前言:
首先,完成后最大的感想是:行业之间的壁垒因为AI在逐渐缩小。
最重要的不是我简单通过SO-ARM101实现了ACT,而是我感受到了AI的力量,全程在Codex的帮助下完成了这个任务。有哪些看不懂和不会做,直接问Codex,他会给你答案,所有问题都可以问。
你不需要去完成复杂的python环境配置和代码编写调试,只需要专注于怎么完成这个事情,分解你的任务,一步步完成,遇到困难让AI协助你解决,这帮我节省了大量时间。
如果是原生靠自己手搓,配环境、调代码和慢慢去看官网说明文档,尤其是排查处理过程中的各种问题,我觉得很难坚持下去。
顺便说个题外话,或许物理AI出来后打螺丝都不用自己做了,群里有个人就说后悔自己没买电动螺丝刀,手麻了。
我们可能真的处在第四次工业革命!
完整流程:
SO-ARM101整个流程
黄仁勋近期G20上的一段采访:
我们人类的工作并不会因此消亡。一份工作的真谛,最终是由它的使命、业务情境与核心目的所定义的。AI 会将起草文案、解析数据、编写代码等具体的职能任务自动化,但这个岗位背后的核心使命将始终延续。
整个人类社会将迎来前所未有的超强赋能。在英伟达内部,我们在使用 OpenAI 和 Anthropic 的第三方模型以及像 Cursor 这样的专业编码工具的同时,也在大力研发我们自有的内部专有模型。
每一家企业、每一个国家都应当遵循这一框架:在适用的场景善用现成模型,但必须打造属于自己的主权智能。你绝不能将属于本机构的专属知识沉淀和战略判断,完完全全外包给第三方供应商。
那种认为自动化将导致就业全面覆灭的观点是完全错误的。相反,全人类的雄心壮志将被彻底放大。
比起历史上任何时期,今天的我们都怀有更宏大的抱负。我们如今习以为常推进的项目,若放在一百年前,都会被视作异想天开的科幻奇谈。
在未来的十年里,这种基准线将被再次彻底刷新。过去需要耗时十年的任务,未来一年即可完成;过去耗时一年的工作,未来一个月就能解决。
我们正在步入一个精干团队与普通个体都能切实撼动百万亿美元全球经济体量的时代。各国与无数创新者正在共同规划如何在全球范围内创造数十万亿美元的全新经济增量。这种规模的雄心壮志,在整个人类历史上都是前所未有的。
目录
[三、Le Robot 环境部署规划【借助Codex-把说明书链接和你的需求说清楚,让他给你安装环境】](#三、Le Robot 环境部署规划【借助Codex-把说明书链接和你的需求说清楚,让他给你安装环境】)
1.对舵机分类区分,完成舵机校准【这步按教程插好让Codex帮你软件校准】
7.真机推理测试:必须在连接机械臂和摄像头的那台电脑上安装本地LeRobot环境。
一、SO-ARM101实现ACT步骤【前置条件】
1.名词概念
SO-ARM101:整套机械臂
Feetech:机械臂里的关节舵机
LeRobot:控制舵机、采集数据、训练和部署模型的软件
ACT:根据图像和关节状态预测动作的策略模型
ROS/ROS2:机器人软硬链接框架,重点解决"机器人各个模块怎么协同工作",本次工作没用到
Sim2Real仿真到现实(类似于数字孪生):在虚拟机器人上把模型练会,再想办法让它在真实机器人上也能正常工作。现在做的SO-ARM101实现ACT,严格来说不是Sim2Real,而是Real-to-Real(真实数据训练 → 真实机器人部署)
2.完整流程
Windows + Miniforge Prompt(命令行终端工具)
↓
Feetech舵机ID写入(软件)和安装 LeRobot(硬件)
↓
主从臂显示为 COM3 / COM5(软件)
↓
校准(软件)
↓
遥操作(软件)
↓
接双 USB 相机(硬件)
↓
采集 Episode(硬件/软件)
↓
云端训练 ACT(软件)
↓
本地部署(软件)
3.前置了解
步骤0:用谷歌账号在huggingface网创建了一个新账号(huggingface网)
-创建token密钥用来跟ACT Colab Notebook绑定,上传训练后的模型到huggingface网
步骤1:安装开源pytorch环境
步骤2 :熟悉LeRobot指令(huggingface网-官方文档)
步骤3:熟悉SO-ARM101介绍(huggingface网-官方文档)
-实现代码让 Windows 能识别并控制 SO-ARM101,网上买的可能已经配好了
步骤4:LeLab【可以不用命令行了,面向 SO-ARM101 的完整操作,适合用于机械臂操作和数据采集】 (huggingface网-官方文档)
-是 LeRobot 的浏览器 GUI,可以完成机械臂配置、标定、遥操作、数据采集、云端训练和模型部署。
步骤5:看ACT说明(huggingface网-官方文档)
-ACT 模型怎么训练、怎么部署
步骤6:ACT Colab Notebook【只负责训练这一段,适合查看 Loss、修改训练步数、batch size、模型参数和排查问题。】(私有网址)
-功能:可以在浏览器中直接运行 ACT 训练代码,使用 Google 云端 Python 环境和 GPU 训练 ACT
-代码:!lerobot-train --dataset.repo_id=lerobot/aloha_sim_transfer_cube_human --policy.type=act --output_dir=outputs/train/act_test_upload --job_name=act_test --policy.device=cuda --policy.repo_id=zyzy7/act_test --policy.push_to_hub=true --wandb.enable=false --batch_size=4 --steps=100
步骤7:注册W&B【可以提供密钥作为插件集成到ACT Colab Notebook(步骤六)中,训练完在该平台看loss曲线】(W&B官网)
--代码需修改:wandb.enable=true
4.相关网址
①huggingface【个人账号】zyzy7 https://huggingface.co/zyzy7
②LeRobot 【说明文档】 https://huggingface.co/docs/lerobot
③visualize_dataset【可视数据集】 https://huggingface.co/spaces/lerobot/visualize_dataset
④Colab【云端训练ACT】
⑤Weights & Biases平台【看训练loss】 Weights & Biases
⑥视频教程:【新版Lerobot SO101机械臂教程一站通:1.序言-哔哩哔哩】 https://b23.tv/st3PGKV
⑦中文wiki教程【B站视频的文字版 + 命令合集 + FAQ + 更完整参数说明】:https://wiki.seeedstudio.com/cn/lerobot_so100m_new/
注:3和4的内容做个前置了解就好,不用特别深究,主要还是实践,哪里看不懂就去问codex
二、硬件采购筹备
可以,整理成更适合直接放到项目文档里的清单:
| 序号 | 设备/材料 | 预算 | 是否必须 | 数量 | 说明 |
|---|---|---|---|---|---|
| 1 | SO-ARM101 套件 | 1314 元 | ✅ 必须 | 1 套 | 淘宝购买 SO-ARM101,自己组装版本;组装成品大约贵 400 元 |
| 2 | 笔记本电脑 | 已有 | ✅ 必须 | 1 台 | 普通办公笔记本即可,主要负责数据采集、遥操作和部署;模型训练可放到云端 |
| 3 | 外置摄像头 | 约 200 元 | ✅ 必须 | 2 个 | 数据采集需要两个视角;已有摄像头可直接使用,则无需额外支出 |
| 4 | USB 扩展坞 | 约 40 元 | ✅ 必须 | 1 个 | 双机械臂 + 双摄像头至少占用 4 个 USB 接口,用于解决笔记本接口不足问题 |
| 5 | 便利贴 + 笔 | 约 3 元 | ⚪ 可选 | 1 套 | 用于标记舵机编号、机械臂部件,方便组装和后续维护 |
| 6 | 螺丝刀套件 | 20~169 元 | ✅ 必须 | 1 套 | 普通螺丝刀套件约 20 元即可;也可选择小米电动螺丝刀,约 169 元,更省力 |
| 7 | 摄像头支架 | 约 20 元 | ✅ 必须 | 2 个 | 用于固定数据采集视角;已有手机自拍支架可替代,摄像头自带合适支架时也可忽略 |
所以这个 SO-ARM101 项目,已有普通笔记本电脑的情况下,总共需要大概大约 1400-1700元
1.SO-ARM101套件【1350元-必须】:淘宝买的101 型号,需要自己组装版本,直接买组装好的好像要加400元
2.自己的笔记本电脑【必须】:普通办公笔记本电脑就可,训练可以放云端
3.摄像头方案【200元-必须】:项目需 2 个外置摄像头,手头原有上网课的摄像头,无需额外采购;固定支架利用现有手机自拍支架替代,省去购置摄像头支架成本。
4.接口扩容需求【40元-必须】:双摄像头搭配双机械臂共占用 4 个 USB 接口,笔记本电脑原生仅 3 个 USB 口,日常还需外接鼠标、键盘,接口数量不足,购入 40 元左右 USB 扩展坞解决接口短缺问题。
5.便利贴+笔【3元-可选】:主要用来标记舵机,方便自己后续区分。
6.螺丝刀【20元/169元-必须】:用来拧螺丝,自己后面买的是小米电动的版本【169元】,比较省力。家里有普通的螺丝刀套件,直接用就好。没有的买个普通的螺丝刀套件就可以【20元】。
7.摄像头支架【20元-必须】:用来后续固定两个摄像头采集数据,一个固定作为侧视角度,一个固定作为俯视角度。


三、Le Robot 环境部署规划【借助Codex-把说明书链接和你的需求说清楚,让他给你安装环境】
1.工具辅助安装:借助 Codex 自动化搭建 Le Robot 软件环境;可以让codex分析下本机性能,我的电脑 GPU 可支撑常规功能运行,仅大规模训练任务会存在性能局限,当前交由 GPT 辅助调试运行。
2.系统选型方案:项目支持两套运行系统,一是英伟达机器人专用 Jetson 平台,二是 Ubuntu Linux 系统;行业不推荐 Windows WSL2 部署,容易出现程序 bug,最优方案为电脑安装 Windows+Ubuntu 双系统,后续在 Ubuntu 内下载配套依赖包、Le Robot 工具包。
注:但是以上两个系统是训练所必须的,可以在云端训练,数据采集和模型的调试推理在windows系统上安装依赖包就可以
四、实操【硬件组装/软件校准环节】
1.对舵机分类区分,完成舵机校准【这步按教程插好让Codex帮你软件校准】
101版本,舵机校准的时候,主从舵机的电源不能接错!!!
101版本,舵机校准的时候,主从舵机的电源不能接错!!!
101版本,舵机校准的时候,主从舵机的电源不能接错!!!
**案例:**让Codex处理软件写入的例子,在校准过程中,自己多按了一下,将L6的ID写成5了,这种直接让codex帮你改,自己不用费心去怎么做,节省大量时间。
感觉有 AI 真好啊,当时刚工作在 Linux 上解决 Python包冲突的问题,被折腾的就不信了,硬要下决心,费了几天才把那个问题最终给搞定,虽然现在已经忘记具体细节了,但是很有成就感。而现在去装个环境,只要在 Codex 里面说一下, AI 就帮你装好了,不知道是好是坏。但是对人类来说确实轻松了很多。

2机械臂整体组装还比较麻烦,慢慢做吧【按照教程拧螺丝】
①打印件(机械臂各组件)尺寸会有太小的情况(普遍比较紧),刚开始还以为是自己螺丝没装准,按不下去,后面才知道是孔太小,可以在安装打印件之前,把螺丝先在各个孔试下卡进去,方便后续安装。如果螺丝卡不进去孔,可以用螺丝刀将孔翘大点 
②舵盘安装到舵机上:带螺纹的对黄色舵机部分,不带螺纹的对底部。安装带螺纹的托盘,一定要对好位置再卡进去。 
③安装舵盘螺丝技巧:可以先安装套件卡住舵盘,再拿套件旋转,来控制带螺母舵盘的位置。套件的孔对准舵盘的孔后,螺丝拧对角来卡主,后续好上其他螺丝。 
④安装主臂用了三天,安装从臂的用了一天,熟能生巧 
3.机械臂校准及遥操作
①【卡子使用技巧】:直接按橙色的小圆点,其他不要动,就会松开,然后用其卡住位置,扣动扳机,就会上紧。效果如图 

②【机械臂校准】:先把机械臂各个舵机关节放到居中位置,然后启动程序,开始转动每个关节到极限位 
③【遥操作】:要先将各个部件的误差<5,然后按enter,等待2s,从臂同步后,白色的爪子会稍微动下。然后开始操作主臂,观察从臂动作是否一致。
4.添加摄像头
①最少需要2个摄像头,一个侧拍,一个俯拍。侧拍可以用平的支架放桌面(我这里买的回来的迟了,懒得换了);俯拍用支架把摄像头架起来。
②最后两个视角的画面如图

5.场景搭建及数据采集
遇到的问题及解决办法
问题1:从臂的夹爪抓住东西后起不来?
解决办法:是因为腰部的舵机两边需要加小的尖头螺丝固定
问题2:从臂的夹爪舵机红色闪烁灯抓住物品后一直闪烁?
解决办法:是因为夹爪夹住胡萝卜后仍被命令继续闭合,舵机发生堵转,触发过载/过流报警,所以红灯闪烁。不要把黑色扳机一直握到底。白色夹爪刚夹稳胡萝卜后,稍微松一点扳机,让夹爪保持但不继续挤压。
①构建一个测试页面,先跑通一条抓取数据,测试硬件 
②准备开始采集,了解数据采集阶段的逻辑注意事项(我设计的是5 条质检采集模式)
现在硬件链路已经基本通过,可以进入数据采集阶段。建议采用:
5 条质检试录 → 检查合格 → 正式采集 50 条以上 → 数据审核 → 上传云端训练
先理解三个概念
Episode:一次完整示范,例如"从初始姿态出发 → 抓胡萝卜 → 放入纸盒 → 停稳"。
Reset:一条示范结束后,把胡萝卜和机械臂恢复到下一条的起始状态。
Dataset:所有 episode 的双摄像头视频、主臂动作、从臂状态、时间戳和任务文字的集合。
模型最终学习的是:
两路摄像头画面 + 当前关节状态 + 任务文字 → 下一步关节动作推荐采集参数
| 项目 | 当前建议 |
|---|---|
| 任务文字 |
Pick up the orange carrot by its middle and place it inside the box on the left.|| 摄像头 | 顶视 + 侧视,位置全程固定 |
| 采集频率 | 20 FPS |
| 单条时间 | 先用 25--30 秒 |
| Reset 时间 | 25--30 秒 |
| 质检批次 | 先录 5 条 |
| 正式数据 | 至少 50 条 |
| 位置分布 | 5 个胡萝卜起始位置,每个位置约 10 条 |
| 保存位置 | F 盘本地数据集目录 |
| 上传 | 采集、审核完成后再上传云端 |
官方也建议从不少于 50 个 episode 开始,例如"5 个位置 × 每个位置 10 条",并保持摄像头固定、抓取方式一致、物体始终可见。Seeed Studio 数据采集说明
一、正式采集前锁定环境
正式开始后,以下内容尽量不要改变:
机械臂底座和摄像头支架全部夹紧。
纸盒位置固定,可以用胶带标记四角。
在桌面标记胡萝卜的 5 个起始位置。
固定灯光,避免白天、晚上亮度差异太大。
不再移动桌子、摄像头、机械臂底座。
两个画面始终能看到:
胡萝卜起始位置;
白色从臂夹爪;
完整纸盒;
抓取和放置路径。
正式数据开始后不要临时调整相机角度;如果必须调整,应建立新的数据集版本。
二、每次开始一批采集前
黑色主臂接通 5V。
白色从臂接通 12V。
检查两块控制板和所有舵机供电。
清理从臂运动范围内的线缆和杂物。
将两臂摆到相近、非极限的起始姿态。
页面确认六个关节差值全部 ≤5°,并稳定 3 秒。
轻握测试夹爪,确认没有舵机闪红灯。
在摄像头预览中确认画面正常。
异常运动时,优先关闭白色从臂 12V。
三、一条合格 Episode 的动作流程
建议每次都按照相同顺序:
从统一的休息姿态开始。
平稳靠近胡萝卜。
将夹爪对准胡萝卜中部。
轻柔闭合夹爪。
夹稳后稍微松一点主臂扳机,避免持续堵转。
先垂直抬起一点,再向纸盒移动。
到达纸盒内部后再松开夹爪。
确认胡萝卜完全落入纸盒。
将机械臂停在统一的结束姿态。
保持不动,等待页面进入 Reset。
动作应平稳、直接,尽量减少试探、来回修正和长时间停顿。
四、Reset 阶段
只在页面显示"复位"之后操作环境:
把胡萝卜取回指定起始点。
清空纸盒。
检查夹爪是否正常。
将黑色主臂和白色从臂恢复到下一条的起始姿态。
不移动摄像头或纸盒。
等待下一条自动开始。
不要在仍处于录制阶段时伸手进入白色从臂工作区。
五、哪些数据必须作废
以下任意一种情况出现,这条 episode 都不应进入训练集:
胡萝卜没有夹住或中途掉落;
没有完全放入纸盒;
舵机闪红灯、嗡鸣、抖动或卡住;
夹爪长时间握到底;
从臂明显追不上主臂;
撞到桌面、纸盒或摄像头支架;
手、身体或其他杂物严重遮挡画面;
摄像头掉帧、黑屏或编号互换;
操作过程中长时间犹豫或反复尝试;
录制被意外停止;
任务成功,但完成方式与其他示范差异非常大。
模仿学习更看重"干净、稳定、可重复"的成功示范,而不是勉强凑数量。
六、建议的采集节奏
不要直接连续录完 50 条:
先录 5 条质检数据。
检查双路视频、帧数、动作跟随和舵机报警。
合格后录第一批 10 条。
休息几分钟,检查舵机温度和螺丝。
每完成 10 条审核一次。
最终保留至少 50 条合格数据。
位置变化建议循序渐进:
前 10 条:同一位置,先确保稳定成功;
后续 40 条:5 个小范围位置,每个位置约 8--10 条;
暂时不要同时改变纸盒、相机、光线和抓取方式。
七、采集完成后的处理
完成后还不能马上训练,需要:
确认 episode 数量和总帧数;
播放两路视频抽查;
检查动作与从臂状态是否同步;
删除或重录异常 episode;
生成数据统计信息;
备份原始数据;
再上传到云端或 Hugging Face;
在云端训练 ACT 或 SmolVLA;
用独立的 10 次测试评估成功率。
③重新构建一个采集页面,可视化实时跟踪你的采集进度(制定一个自己手动开始录制和复位启停的页面,不要写死时间) 
④一轮数据测试完成后,让Codex检查下是否合格,合格的存档上传到huggingfa ce
6.数据合并和训练模型
①第一次使用 SO-ARM101 真机数据训练 ACT,完整流程为:
发现 11 份原始数据 → 元数据检查 → 视觉质检 → 合并 55 条 → 上传并验证 → 100 步冒烟测试 → 20k 正式训练 → 下载模型并部署。
②本次已经确认的数据配置:
| 项目 | 实际值 |
|---|---|
| 原始数据仓库 | 11 个 |
| 每个仓库 | 5 episodes |
| 合计 | 55 episodes |
| 总帧数 | 46,079 |
| 采样频率 | 20 FPS |
| 相机 | side、top |
| 图像尺寸 | 3×720×1280 |
| 关节状态 | 6 维 |
| 动作 | 6 维 |
| LeRobot | 0.6.1 |
| 策略 | ACT |
| 正式训练 | batch_size=4、steps=20000 |
| 预计训练时间 | T4 约 5~6 小时 |
③最终数据与模型仓库【已在huggingface开源可获取】
数据集:zyzy7/so101-carrot-box-manual55-20260904
冒烟模型:zyzy7/act-so101-carrot-box-55ep-smoke100
正式模型:zyzy7/act-so101-carrot-box-55ep-20k
④训练配置说明
| 参数 | 含义 |
|---|---|
batch_size=4 |
已在 T4 上验证,显存约 8 GB |
num_workers=2 |
匹配当前 Colab CPU 建议,避免 worker 警告 |
steps=20000 |
第一版正式基线 |
log_freq=100 |
每 100 步向日志和 W&B 记录一次 |
save_freq=5000 |
每 5,000 步保存一次 |
save_checkpoint_to_hub=true |
将中间断点上传到 Hub,防止 Colab 中断后全部丢失 |
⑤训练过程
------------------------------------一Colab 环境和密钥---------------------------------------------
1.选择GPU:运行时 → 更改运行时类型 → T4 GPU
2.配置密钥
先在Colab左边加huggingface的token密钥,用来链接 huggingface获取数据集和上传模型【 HF_TOKEN**】**
再在Colab左边加WANDB的密钥,用来后续查看训练的loss曲线【WANDB_API_KEY】
3.安装完整训练依赖
%pip install -q -U "lerobottraining"
4.登录huggingface
from google.colab import userdata
from huggingface_hub import HfApi, login
HF_TOKEN = userdata.get("HF_TOKEN")
assert HF_TOKEN, "没有读取到HF_TOKEN"
login(token=HF_TOKEN, add_to_git_credential=False)
api = HfApi(token=HF_TOKEN)
print("当前账号:", api.whoami()"name")
--------------------------------------二数据获取与处理(我的是11份,每份5条数据)-------------------------------------------
1.查找11份数据并补版本标签
PREFIX = "zyzy7/so101-carrot-box-manual5-"
SOURCE_REPOS = sorted(
for dataset in api.list_datasets(author="zyzy7")
if dataset.id.startswith(PREFIX)
)
print("找到原始数据集数量:", len(SOURCE_REPOS))
for index, repo_id in enumerate(SOURCE_REPOS, start=1):
print(f"{index:02d}. {repo_id}")
assert len(SOURCE_REPOS) == 11, "原始数据集数量不是11,请先检查仓库列表"
2.检查每份数据的 episode 数、帧数、FPS、字段名称、字段形状和数据版本;同时给缺少标签的仓库补上 v3.0****标签。(给数据集加v3.0的标签,需要在huggingface新申请一个write权限的token)
import json
from huggingface_hub import hf_hub_download
total_episodes = 0
total_frames = 0
schema_signatures = set()
for repo_id in SOURCE_REPOS:
info_path = hf_hub_download(
repo_id=repo_id,
filename="meta/info.json",
repo_type="dataset",
token=HF_TOKEN,
)
print("\n汇总")
print("数据集数量:", len(SOURCE_REPOS))
print("episode总数:", total_episodes)
print("总帧数:", total_frames)
print("数据结构种类:", len(schema_signatures))
assert len(SOURCE_REPOS) == 11, "原始仓库数量不是11"
assert total_episodes == 55, "episode总数不是55"
assert total_frames == 46079, "总帧数与本次记录不一致"
assert len(schema_signatures) == 1, "不同批次的数据结构不一致"
print("\n自动检查通过,可以进入视觉质量检查")
3.合并为55条数据
from lerobot.datasets import LeRobotDataset
from lerobot.datasets.dataset_tools import merge_datasets
MERGED_REPO = "zyzy7/so101-carrot-box-manual55-20260904"
source_datasets = \[\]
for index, repo_id in enumerate(SOURCE_REPOS, start=1):
print(f"{index}/11 正在下载:{repo_id}")
print("\n11份数据下载完成,开始合并......")
merged_dataset = merge_datasets(
datasets=source_datasets,
output_repo_id=MERGED_REPO,
)
print("\n合并完成")
print("新数据集:", merged_dataset.repo_id)
print("episode数量:", merged_dataset.meta.total_episodes)
print("总帧数:", merged_dataset.meta.total_frames)
print("FPS:", merged_dataset.meta.fps)
print("相机:", merged_dataset.meta.camera_keys)
assert merged_dataset.meta.total_episodes == 55
assert merged_dataset.meta.total_frames == 46079
print("\n合并结果检查通过")
4**.上传55条合并数据到Hugging Face**
merged_dataset.push_to_hub(
private=True,
tags=[
"lerobot",
"so101",
"real-world",
"imitation-learning",
"act",
],
)
print("上传完成:") print("https://huggingface.co/datasets/" + MERGED_REPO)
5.检查 Hub 仓库
dataset_info = api.dataset_info(MERGED_REPO)
repo_files = api.list_repo_files(
repo_id=MERGED_REPO,
repo_type="dataset",
)
refs = api.list_repo_refs(
repo_id=MERGED_REPO,
repo_type="dataset",
)
info_path = hf_hub_download(
repo_id=MERGED_REPO,
filename="meta/info.json",
repo_type="dataset",
token=HF_TOKEN,
force_download=True,
)
with open(info_path, "r", encoding="utf-8") as file:
hub_info = json.load(file)
print("仓库:", dataset_info.id)
print("是否私有:", dataset_info.private)
print("episode数量:", hub_info"total_episodes")
print("总帧数:", hub_info"total_frames")
print("FPS:", hub_info"fps")
print("版本标签:", tag.name for tag in refs.tags)
print("存在meta:", any(path.startswith("meta/") for path in repo_files))
print("存在data:", any(path.startswith("data/") for path in repo_files))
print("存在videos:", any(path.startswith("videos/") for path in repo_files))
--------------------------------------三冒烟测试与正式训练-------------------------------------------
1.登录 W&B 并检查 GPU
import torch
import wandb
WANDB_API_KEY = userdata.get("WANDB_API_KEY")
assert WANDB_API_KEY, "没有读取到WANDB_API_KEY"
wandb.login(key=WANDB_API_KEY, relogin=True)
print("CUDA:", torch.cuda.is_available())
if torch.cuda.is_available():
print("GPU:", torch.cuda.get_device_name(0))
else:
raise RuntimeError("请将Colab运行时切换为T4 GPU")
2.设置训练名称
DATASET_REPO = "zyzy7/so101-carrot-box-manual55-20260904"
POLICY_REPO = "zyzy7/act-so101-carrot-box-55ep-smoke100"
OUTPUT_DIR = "outputs/train/act-so101-carrot-box-55ep-smoke100"
print("训练数据:", DATASET_REPO)
print("模型仓库:", POLICY_REPO)
print("本地输出:", OUTPUT_DIR)
3.冒烟100步训练测试-训练100步代码(在这里左侧把W&B的token密钥加进去,看loss曲线)
!lerobot-train
--dataset.repo_id={DATASET_REPO}
--policy.type=act
--output_dir={OUTPUT_DIR}
--job_name=act-so101-carrot-box-55ep-smoke100
--policy.device=cuda
--policy.repo_id={POLICY_REPO}
--policy.push_to_hub=true
--policy.private=true
--wandb.enable=true
--wandb.project=so101-act
--batch_size=4
--num_workers=2
--steps=100
--log_freq=10
--save_freq=100
4.冒烟100步训练测试-验证训完上传到huggingface的模型文件
from huggingface_hub import HfApi
api = HfApi(token=HF_TOKEN)
MODEL_REPO = "zyzy7/act-so101-carrot-box-15ep-wandb-test100"
model_files = api.list_repo_files(MODEL_REPO)
print("模型文件:")
for file in model_files:
print(file)
print("\n关键文件检查:")
print("存在模型权重:", "model.safetensors" in model_files)
print("存在模型配置:", "config.json" in model_files)
print("存在训练配置:", "train_config.json" in model_files)
5.20K正式训练-每5K一个断点保存
①设置实验名称
DATASET_REPO = "zyzy7/so101-carrot-box-manual55-20260904"
POLICY_REPO = "zyzy7/act-so101-carrot-box-55ep-20k"
OUTPUT_DIR = "outputs/train/act-so101-carrot-box-55ep-20k"
print("正式训练数据:", DATASET_REPO)
print("正式模型仓库:", POLICY_REPO)
②确认GPU和登录
import torch
import wandb
from google.colab import userdata
from huggingface_hub import login
HF_TOKEN = userdata.get("HF_TOKEN")
WANDB_API_KEY = userdata.get("WANDB_API_KEY")
login(token=HF_TOKEN, add_to_git_credential=False)
wandb.login(key=WANDB_API_KEY, relogin=True)
assert torch.cuda.is_available(), "当前没有GPU"
print("GPU:", torch.cuda.get_device_name(0))
③正式训练代码
!lerobot-train \
--dataset.repo_id={DATASET_REPO} \
--policy.type=act \
--output_dir={OUTPUT_DIR} \
--job_name=act-so101-carrot-box-55ep-20k \
--policy.device=cuda \
--policy.repo_id={POLICY_REPO} \
--policy.push_to_hub=true \
--policy.private=true \
--wandb.enable=true \
--wandb.project=so101-act \
--batch_size=4 \
--num_workers=2 \
--steps=20000 \
--log_freq=100 \
--save_freq=5000 \
--save_checkpoint_to_hub=true
④训练中的名词LOSS解释
-l1_loss:模型预测的机械臂动作,与真人遥操作采集的真实动作差多远。
-kld_loss:用来约束潜变量分布
-L1 Loss负责让动作预测准确,KLD Loss负责让 ACT 内部的"动作表示空间"不要乱掉。-loss:是nan/Inf ,代表某个计算数值已经大到溢出了
-CUDA OOM ,代表显存溢出不够了
-Traceback :Python 程序真的报异常退出了
⑤正式训练20K训练后的模型验证
MODEL_REPO = "zyzy7/act-so101-carrot-box-55ep-20k"
model_files = api.list_repo_files(MODEL_REPO)
print("模型文件:")
for path in model_files:
print(path)
print("\n关键文件检查:")
print("存在模型权重:", "model.safetensors" in model_files)
print("存在模型配置:", "config.json" in model_files)
print("存在训练配置:", "train_config.json" in model_files)
6.训到17000步的时候colab断开了,处理方式【等待,等待额度恢复,买他的GPU资源需要美国银行卡】
①确认15k断点已经上传
from google.colab import userdata
from huggingface_hub import HfApi, login
HF_TOKEN = userdata.get("HF_TOKEN")
login(token=HF_TOKEN)
MODEL_REPO = "zyzy7/act-so101-carrot-box-55ep-20k"
api = HfApi(token=HF_TOKEN)
files = api.list_repo_files(MODEL_REPO)
for path in files:
if "checkpoint" in path.lower() or "train_config" in path:
print(path)
②重新登录
import wandb
from google.colab import userdata
from huggingface_hub import login
HF_TOKEN = userdata.get("HF_TOKEN")
WANDB_API_KEY = userdata.get("WANDB_API_KEY")
login(
token=HF_TOKEN,
add_to_git_credential=False,
)
wandb.login(
key=WANDB_API_KEY,
relogin=True,
)
③下载环境
%pip install -q "lerobottraining==0.6.1"
④从Hub最新断点恢复
!lerobot-train \
--config_path=zyzy7/act-so101-carrot-box-55ep-20k \
--resume=true \
--save_freq=1000 \
--save_checkpoint_to_hub=true
--------------------------------------四离线推理测试【先用的训的15k模型】-------------------------------------------
1.导出独立的15k模型为一个新仓库,方便测试
from pathlib import Path
from huggingface_hub import snapshot_download
SOURCE_REPO = "zyzy7/act-so101-carrot-box-55ep-20k"
SOURCE_PREFIX = "checkpoints/015000/pretrained_model"
TARGET_REPO = "zyzy7/act-so101-carrot-box-55ep-15k"
download_root = snapshot_download(
repo_id=SOURCE_REPO,
repo_type="model",
token=HF_TOKEN,
allow_patterns=f"{SOURCE_PREFIX}/\*",
local_dir="/content/act-15k-export",
)
model_folder = Path(download_root) / SOURCE_PREFIX
print("15k模型目录:", model_folder)
print("目录是否存在:", model_folder.exists())
api.create_repo(
repo_id=TARGET_REPO,
repo_type="model",
private=True,
exist_ok=True,
)
api.upload_folder(
repo_id=TARGET_REPO,
repo_type="model",
folder_path=str(model_folder),
commit_message="Export ACT 15k checkpoint for evaluation",
)
print("15k独立模型上传完成:")
print("https://huggingface.co/" + TARGET_REPO)
2.检查独立仓库
target_files = api.list_repo_files(TARGET_REPO)
for path in target_files:
print(path)
assert "model.safetensors" in target_files
assert "config.json" in target_files
assert "train_config.json" in target_files
assert "policy_preprocessor.json" in target_files
assert "policy_postprocessor.json" in target_files
print("\n独立15k模型仓库检查通过")
3.离线推理-加载15K模型
import time
import torch
from lerobot.datasets import LeRobotDataset
from lerobot.policies import make_pre_post_processors
DATASET_REPO = "zyzy7/so101-carrot-box-manual55-20260904"
MODEL_REPO = "zyzy7/act-so101-carrot-box-55ep-15k"
加载真实数据集
dataset = LeRobotDataset(DATASET_REPO)
加载模型保存的归一化和反归一化处理器
preprocessor, postprocessor = make_pre_post_processors(
policy_cfg=policy.config,
pretrained_path=MODEL_REPO,
preprocessor_overrides={
"device_processor": {"device": "cpu"},
},
postprocessor_overrides={
"device_processor": {"device": "cpu"},
},
)
print("数据集帧数:", len(dataset))
print("预处理器和后处理器加载成功")
4离线推理-第0帧进行一次预测,查看误差,MAE结果在3.49
sample = dataset0
observation = {
name: samplename
for name in policy.config.input_features
}
policy.reset()
start_time = time.perf_counter()
with torch.inference_mode():
processed_observation = preprocessor(observation)
predicted_action = policy.select_action(processed_observation)
predicted_action = postprocessor(predicted_action)
elapsed = time.perf_counter() - start_time
print("离线推理成功")
print("预测结果类型:", type(predicted_action))
print("预测结果形状:", getattr(predicted_action, "shape", None))
print("预测动作:", predicted_action)
print("真实动作:", sample"action")
print("CPU单次推理耗时:", f"{elapsed:.3f}秒")
if torch.is_tensor(predicted_action):
prediction = predicted_action.detach().cpu().reshape(-1)
target = sample"action".detach().cpu().reshape(-1)
print("预测动作维度:", prediction.shape)
print("真实动作维度:", target.shape)
print("单帧动作MAE:", torch.mean(torch.abs(prediction - target)).item())
print("预测值全部有限:", torch.isfinite(prediction).all().item())
-训练LOSS图 
-训到17000的时候,跑出限额了,只能等待了 
-最终2W步的LOSS 
-最终55条训练数据和20K训练模型已开源,可自主获取 
7.真机推理测试:必须在连接机械臂和摄像头的那台电脑上安装本地LeRobot环境。
①构建推理前端页面 
②推理测试,记录结果,分析原因
-----------------------------实验一:10HZ,限幅3.0---------------------------------------
实验:
1成功:放进去了,但是会拖着盒子,放的有一点点偏差
2失败:爪子抓住萝卜后,去放盒子,抬起高度太低,托纸盒
3失败:爪子抓住萝卜后,去放盒子,抬起高度太低,托纸盒
4失败:也是放的时候,抬起高度太低,托纸盒
5失败:也是放的时候,抬起高度太低,托纸盒
6失败:也是放的时候,抬起高度太低,托纸盒
7失败:也是放的时候,抬起高度太低,托纸盒
分析:
1.采集数据时,主臂移动太快,导致从臂爪子抓到萝卜后,去盒子放时高度偏低,会把盒子顶走(这里刚开始认为是采集的数据不太好,后面才知道是限幅设置太小了),而且爪子的舵机很多次都闪红灯(过载)
2.数据样本太少,只有55条,而且自己采集时候,还用了两种盒子摆放顺序策略,而且盒子位置会有微小变化
3.有抖动是因为该电脑配置不好,用的CPU推理,所以只用了8Hz的输出
有个好处是,一次放不进去,会一直去放,抓住萝卜的概率成功率基本是100%
-----------------------------实验二:8HZ,限幅5.0---------------------------------------
实验:
1失败:抬起高度很高,但是夹得太紧,触发过载保护
分析:
1.采集时夹爪舵机一直闪红灯=过载,说明示范数据里"夹爪长期被夹到过载",模型就学到"要夹得很紧",于是推理时也夹过头、触发过载。
优化:
1.按"降低夹爪默认力、保留过载保护"来改的关键是只降了 Max_Torque_Limit 到 35%,让夹爪"用适中力度"就够,不会为了夹紧而一直顶到 50% 触发过载闪灯;过载保护没有关闭,所以安全网还在。
--------------------优化具体细节----------------------------
参数 原来 现在 说明
Max_Torque_Limit 500 (50%) 350(35%) 夹爪默认最多出 35% 力,夹胡萝卜时不会一直顶到最大
Protection_Current 250(50%) 200(40%) 电流保护阈值同步调低
Overload_Torque 25 25(不变) 保留 25% 过载判定,真夹到硬物仍会断电保护
①Max_Torque_Limit(最大扭矩限制)------ "最大出力上限":这是舵机最高能输出多大的力气的封顶值。无论你怎么按按钮,舵机用的力都不会超过这个百分比。
②Protection_Current(保护电流)------ "功耗警戒线":舵机用的力气越大,电机转动的电流就越大。这个参数是触发过载报警的电流门槛。一旦电流超过这个值,舵机立刻闪红灯报错并停止动作,防止烧坏电机。
③Overload_Torque(过载扭矩判定)------ "硬物碰撞急停判定":这是一个瞬时冲击判定。它不看你用了多大的稳态力气,而是看舵机转子是不是"突然转不动了"(硬卡死)。当舵机遇到物理硬限位(比如夹爪完全闭合卡住金属)时,扭矩会瞬间剧烈跳动,超过此阈值就直接断电保护。
-------------------------------实验三:8HZ,限幅4.0-----------------------------------
实验:
1.成功:
2.成功:
3.成功:
分析:
1.稍微放的时候有一丢丢偏,整体还是很精准的
限幅概念:"限幅"就是我代码里给每次控制周期设的一个保护上限,从臂每个关节,一次最多只能朝模型想要的方向挪一小段,不能一步到位。模型每次会给出"目标关节角",但真正下发给舵机的,被限制为从当前角度最多再移动 ±限幅值。限幅的单位跟随关节配置,这里大约是角度(°)。例如:
限幅 3.0:某关节当前在 0°,模型想一次到 -65°,实际这次只到 -3°,然后每个循环再逼近一点。
限幅 5.0:每次最多到 -5°,勉强多推进一点。
如果完全不限,就会一次直接跳到 -65°。
③一些AI分析的记录截图 


哲学思考
"机械臂学会抓取,人也在重新学习如何跨过门槛。"
------Codex修正舵机ID,让陌生的软件配置变成可以追问的问题;双摄像头记录55条示范,把手上的动作变成模型能够学习的经验;Colab断点保住训练进度,纸盒被顶走、夹爪过载,则让屏幕里的结果接受现实检验。当限幅与力度经过调整,胡萝卜终于落进盒子,跨行的门槛也被拆成一个个能够验证的步骤。AI让专业知识更容易调用,也让人的判断更直接地面对结果:提出问题、动手尝试、观察偏差、修正做法------机械臂学会抓取的过程,也是一个人把陌生领域逐步变成自身能力的过程。