ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

从GPU训练到RK3566实机部署:强化学习四足机器人踩坑全记录

2026/9/6 8:58:20 拓冰建站 浏览量
从GPU训练到RK3566实机部署:强化学习四足机器人踩坑全记录 从英伟达 GPU 上把策略训出来再塞进一块巴掌大的 RK3566 板子里让 Microduck 这只 25 厘米的小机器人真正站起来走路——这个过程听起来不算复杂但真做下来坑比想象中多得多。我前前后后折腾了两周把训练、导出、部署、联调整条链路跑通之后最深的感受是强化学习机器人项目训练只占三分之一剩下三分之二的精力全在“迁移”和“实机”上。Microduck 这类项目最大的特点就是便宜、小巧、可复现主控用 RK3566 这种百元级 ARM 板卡关节用串行总线舵机机身 25 厘米左右非常适合做强化学习运动控制的实验平台。但正因为硬件成本压得低算力和执行器的余量都很紧张GPU 上跑得飞快的策略到了实机上可能连 100Hz 的控制频率都跑不满。这篇手记我就按自己的实操顺序把从训练环境搭建到 RK3566 实机部署的关键环节、参数选择和踩坑记录都写清楚给准备上手类似项目的朋友一份可以直接参考的路线图。这个内容适合谁如果你正在做足式机器人、强化学习 sim2real 迁移或者手头有一块 RK3566 想跑学习类控制策略这篇文章应该能帮你少走不少弯路。哪怕你只是好奇“训练用 GPU、部署用 ARM”这条链路到底怎么打通也可以从头到尾读一遍里面的思路是通用的。1. 先看全局这套系统到底在做什么在动手之前我建议先花十分钟把整条技术链路想清楚。很多人在 GPU 上把策略训练好了结果模型导出失败、部署延迟过高、真机行为完全不像仿真根本原因就是对这条链路缺乏全局认知。1.1 为什么是“GPU 训练 RK3566 实机”这个组合强化学习训练和实机推理是两种完全不同的计算负载。训练阶段需要在仿真环境里并行跑上千条轨迹反复计算策略梯度这必须依赖英伟达 GPU 的大规模并行能力而部署阶段只需要对单个策略网络做前向推理计算量很小对硬件的要求其实不高。RK3566 恰好是这块板子的一个甜点选择。它集成了四核 Cortex-A55 CPU主频 1.8GHz还有 0.8TOPs 的 NPU虽然跟英伟达 GPU 完全不是一个量级但跑一个几十万参数的 MLP 策略网络绰绰有余。更重要的是这块板子功耗低、价格便宜、接口齐全适合直接塞进 25 厘米级别的机器人机身里。我见过不少人纠结要不要上树莓派 5 或者 Jetson Nano其实对于纯运动控制策略RK3566 已经足够了没必要为了用不上的算力多花几倍的钱。这套组合的核心逻辑就是把重计算放在训练端把轻推理放在实机端。训练时用英伟达 GPU 大规模并行采集数据、更新策略部署时在 RK3566 上用 CPU 跑一个轻量前向网络两边各司其职链路清晰成本也可控。1.2 Microduck 这类 25 厘米机器人的硬件性格Microduck 是一只 25 厘米级别的小型四足机器人整机重量在一公斤左右关节采用串行总线舵机而非传统的伺服电机加减速箱方案。这意味着它的关节响应速度、力矩输出和位置精度都有上限策略输出频率太高或者关节目标位置变化太剧烈舵机其实是跟不上的。了解硬件性格对设计训练环境很重要。仿真里一个 500Hz 的控制指令舵机可能实际上要 20ms 才能响应到位如果训练时完全不考虑这个延迟特性策略就会学出一种“超前预测”的行为模式到了真机上必然崩溃。这也是为什么后来我在仿真里刻意加入动作延迟模拟目的就是让策略适应舵机的物理响应速度。另外一个容易忽略的点是供电。四足机器人行走时四条腿同时发力峰值电流会突然拉得很高如果电源设计余量不足电压跌落会直接导致主控板复位。我第一次实机测试时就遇到这个问题机器人刚迈两步就重启排查了很久才发现是供电问题而不是代码问题。1.3 整条部署链路的一眼看懂把整个流程拆开大致是六个环节仿真环境搭建、策略训练、模型导出、格式转换、板端适配、实机联调。仿真用 MuJoCo 物理引擎在英伟达 GPU 上用 PPO 算法训练训练好的 PyTorch 权重导出为 ONNX再在 RK3566 上通过 ONNX Runtime 做前向推理控制主循环读取惯性测量单元和关节反馈把观测拼成向量送进网络得到动作后下发到舵机执行。这六个环节里最容易出问题的不是训练本身而是模型导出和板端适配。PyTorch 模型里很多算子在 ONNX 导出时会有兼容性问题板端的内存带宽和 CPU 频率也会影响推理延迟。所以我强烈建议从一开始训练的时候就有意识地向最终部署目标靠拢比如避免使用动态维度、避免在模型里塞入不必要的高频计算模块这些细节会在后面省下大量排查时间。2. 训练端的核心细节把仿真跑出真机的脾气训练阶段直接决定了最终策略的性能上限。一个好的训练设置不仅能让你更快看到收敛更重要的是能让策略在迁移到真机时保持稳定。2.1 仿真器选型为什么用 MuJoCo 而不是 Gazebo选仿真器我几乎没有犹豫就用了 MuJoCo。原因很简单它够快、够准、接口友好。尤其是 MuJoCo 的 MJX 版本可以在英伟达 GPU 上并行跑数千个环境这对于强化学习训练来说是质的提升。一个 GPU 并行环境训练一天的效果可能相当于以前 CPU 串行环境跑半个月。Gazebo 虽然在 ROS 生态里很成熟物理精度也能调但它的单环境仿真速度太慢不太适合需要大量采样的强化学习场景。更重要的是 MuJoCo 对接触动力学模拟得比较稳定四足机器人这种依赖足底摩擦和接触的移动方式在 MuJoCo 里不容易出现数值爆炸。这里要说明一个常见误区物理引擎的“准确性”并不等于“真实”。哪怕是 MuJoCo仿真里计算出的接触力也不可能和真实世界完全一致。所以选仿真器的核心标准不是谁最准而是谁最快、最稳定能让我跑足够多的采样配合域随机化把差距补回来。2.2 观测、动作与 reward 设计的基本盘Microduck 的策略输入我用的是三部分拼接本体的姿态信息翻滚角、俯仰角、角速度、关节状态12 个关节的角度和角速度、上一时刻的动作输出。总共大约 50 维左右的输入向量。这个观测空间不算大但信息量足够策略判断当前的运动状态了。动作空间方面我选择输出 12 个关节的目标位置而不是关节力矩。原因在于 Microduck 的舵机本身是一个位置伺服系统你给它一个目标角度它内部会自己去闭环策略层只需要给出目标位置即可。这大大简化了控制问题也让采样和部署都更加稳定。如果输出力矩舵机内部的 PID 和策略层的力矩控制会形成一种未知的串联关系反而更难调。reward 设计可以说是训练阶段最玄学但也最重要的一环。我的核心 reward 由前进速度奖励、姿态稳定惩罚、能耗惩罚三部分组成。前进速度奖励是主线让机器人尽可能快地朝目标方向移动姿态稳定惩罚用一个二次项约束机身不要过度倾斜能耗惩罚则限制动作幅度避免策略学到高频抖动的“作弊”行为。三者的权重需要反复调如果速度奖励权重太高策略会学到一种剧烈甩动身体的步态如果稳定惩罚太高机器人又会变得过于保守速度上不来。2.3 domain randomization 到底随机什么Sim2real 迁移中最关键的一招就是域随机化。我在训练时对以下几类参数做了随机化处理地面摩擦系数0.3 到 1.2机身质量和质心位置±20%关节阻尼和电机增益±15%以及外部推力扰动。这样策略在仿真里见过的“世界”足够多变迁移到真机时就不会因为参数偏差而完全失效。还有一个容易被忽略的点是传感器噪声模拟。实机上惯性测量单元和关节编码器的读数都有噪声如果在训练时给观测向量叠加高斯噪声策略就会学得更加鲁棒不容易被传感器抖动干扰。动作延迟模拟是我认为最重要的一个随机项。我设置了 20ms 到 40ms 的动作延迟窗口模拟舵机从收到指令到实际运动到位的滞后。这个设计直接解决了“仿真里走得飞快、真机上一迈就摔”的经典问题。策略学会了在延迟情况下做预判到了真机上反而表现得更稳。3. 从模型到实机的关键一跳导出与量化策略训练完之后接下来的工作就是把 PyTorch 模型变成能在 RK3566 上高效运行的形式。这一步看起来简单实际上细节非常多稍不留神就会在这里消耗一两天时间。3.1 为什么不能直接拿 PyTorch 权重上机很多第一次接触部署的人会问RK3566 上装个 PyTorch 不就行了确实可以但问题很多。PyTorch 在 ARM 平台上的安装本身就比较折腾而且运行时内存占用高、推理速度慢最重要的是它的依赖体积动辄几百 MB对于嵌入式场景来说过于臃肿。更合理的做法是把模型导出成 ONNX 格式然后使用 ONNX Runtime 在板端推理。ONNX 是一个开放的模型交换格式PyTorch 模型可以通过 torch.onnx.export 直接导出ONNX Runtime 在 ARM Linux 上有轻量级的运行库推理速度很快内存占用也很低。对于 Microduck 这种只需要前向推理的场景ONNX Runtime 是性能和开发效率的平衡点。如果追求更极致的速度还可以把模型量化成 INT8 并转换到 RKNN 格式利用 RK3566 的 NPU 跑推理。但我会在后面的章节解释为什么不建议这么做——至少对于运动控制策略来说CPU 推理已经足够快了没有必要引入 NPU 带来的一系列兼容性麻烦。3.2 ONNX 导出时的算子与动态维度坑ONNX 导出不是每次都能一次成功的最常见的问题有三个动态维度、不支持的算子、BatchNorm 的状态。动态维度是第一个坑。PyTorch 模型默认输入可以有任意 batch size但导出的 ONNX 如果保留动态 batch在板端推理时就会因为维度不确定而降低效率甚至触发不必要的内存重分配。我的做法是导出时显式指定一个固定的 batch size并把输入张量的动态轴全部固定下来这样板端推理就变成一个完全静态的计算图速度快很多。第二个坑是算子兼容性。PyTorch 里很多高级 API 在 ONNX 导出时找不到对应的算子映射最常见的解决方案是尽量避免用过于新奇的层结构用基础卷积、线性层、激活函数堆叠出一个足够强大的网络即可。我用的三层 MLP 加 tanh 激活就完全没有导出问题。BatchNorm 是第三个需要注意的点。训练时 BatchNorm 依赖 batch 统计量但推理时必须使用累计的 running statistics。如果导出前没有把模型切换到 eval 模式BatchNorm 的统计量就会被错误编码进 ONNX导致实机推理结果异常。这是一个很隐蔽的坑排查起来非常头疼。经验是导出前必须调用 model.eval()并且用固定输入做一次预热推理确保计算图已经稳定。3.3 RK3566 上到底该用 CPU 还是 NPURK3566 自带 NPU很多人一上来就想着把模型塞进 NPU 跑展现出更强的性能。但对于 Microduck 这个场景我明确建议使用 CPU 推理。原因有三个。第一控制策略网络本身只有三层 MLP大约 50 维输入、12 维输出单次推理的浮点运算量只有几万次四核 A55 CPU 跑一次推理只需要零点几毫秒完全够用。第二NPU 推理需要把模型转换成 RKNN 格式这个转换过程对算子支持有严格限制稍微复杂一点的网络结构就可能转换失败或者精度下降。第三NPU 推理涉及内存拷贝和运行时初始化的额外开销在控制频率只有 200Hz 的场景下这个开销反而可能比纯 CPU 推理更高。当然如果后面要给 Microduck 加上视觉感知功能比如在 RK3566 的 NPU 上跑 YOLO 做目标检测那就是另一回事了。NPU 在那类任务上简直是降维打击比 CPU 快一个数量级。只是对于纯运动控制策略CPU 是更简单、更可靠的选择。4. RK3566 实机部署实操环境、驱动与实时性从模型到手接下来的工作就是让策略在 RK3566 上真正跑起来把机器人的关节驱动起来。这个阶段的核心矛盾是实时性和稳定性的平衡。4.1 系统镜像与基础环境准备我给 RK3566 刷的是 Ubuntu 22.04 的 ARM 版本。选这个系统的原因是软件生态成熟、工具链齐全ONNX Runtime 在 ARM Linux 下有官方发布的预编译包省去了自己交叉编译的麻烦。系统装好后第一件事是配好 CPU 性能模式。RK3566 默认的 CPU 调频策略是 ondemand空闲时 CPU 频率会降得很低这会对控制任务的实时性造成很大影响。我直接用 cpufreq-set 把 CPU governor 设置为 performance让四核 A55 始终跑在 1.8GHz 的高频上。对于一个 200Hz 的控制循环这一条改动带来的收益是最直接的。然后是安装 ONNX Runtime。直接用 pip 安装 onnxruntime 即可版本选择 1.16 或者更新的版本都行ARM Linux 的 wheel 包开箱即用。另外还需要安装串口通信库 pyserial 和一些实用的系统工具比如 htop 和 stress后面排查性能问题的时候用得上。4.2 舵机通讯与关节驱动初始化Microduck 使用的串行总线舵机通过 UART 进行半双工通信。我用的舵机是类似 Feetech SCS0009 这一类的串行总线舵机通信协议基于 115200 波特率的串口。上电后第一件事是扫描总线上的舵机 ID确认 12 个关节全部在线然后依次给每个舵机设置好位置限制、速度限制和扭矩开关。这里有一个非常关键的细节舵机通信本身是带延迟的。一个舵机的控制指令周期大约是 2ms如果串行逐个下发 12 个关节的指令一轮就要 24ms这个延迟对控制策略来说是不可接受的。所以我的做法是使用舵机的同步写指令一条命令同时下发所有 12 个关节的目标位置这样一轮通信只需要大约 10ms基本满足 200Hz 控制频率的需求。在初始化阶段还有一个坑舵机上电瞬间会有一个很小的角度突变如果此时策略尚未启动机器人可能会“抽搐”一下。我的处理是让主程序启动后先等待 500ms然后给舵机发送一个轻微的扭矩使能信号再开始主控制循环。这个“预热”过程能有效避免上电瞬间的异常动作。4.3 控制主循环的频率设计与线程绑定控制主循环我跑的是 200Hz也就是每 5ms 执行一次状态读取、推理、指令下发。这个频率对于 Microduck 的舵机响应速度来说是合理的选择既不会超出舵机的物理响应能力又能保证运动控制的平滑性。实时性方面我在 Linux 上做了两件事。第一是给控制线程设置为 SCHED_FIFO 实时调度策略优先级设为 90确保控制线程不会被普通用户态进程抢占。第二是使用 sched_setaffinity 把控制线程绑定到第三个 CPU 核心上这样控制线程独占一个核心其他核心处理系统任务和通信任务互不干扰。主循环的结构大致是读取惯性测量单元数据、读取关节反馈、拼接观测向量、调用 ONNX Runtime 推理、解析动作输出、通过同步写指令下发到舵机。整个循环里最耗时的其实是串口通信也就是等待舵机返回数据的过程而不是模型推理。所以我在设计时把传感读取和推理做了流水线化上一轮的数据在推理的同时下一轮的数据已经在采集进一步提升了有效频率。4.4 首次上电联调的三个原则首次上电是非常刺激的时刻。在按下电源开关之前我给自己定了三个原则第一机器人固定在测试支架上离地悬空避免直接摔机第二策略输出的幅度限制在正常范围的一半以内第三手里永远握着紧急停止的物理按钮一旦机器人出现异常抖动就立刻断电。第一次通电后如果机器人表现得像喝醉了酒一样乱抖不要慌这很正常。最可能的原因是策略输入的特征分布和训练时不一致比如传感器数据的缩放因子不对或者惯性测量单元的方向定义反了。我花了大概半小时定位到是加速度计的符号方向和训练时正好相反修正之后机器人就逐渐稳定了下来。从这里开始机器人正式进入了真机调试阶段。每次修改完代码我都会遵循一个原则只在仿真里先验证一遍同样的修改再回到实机上测试。这种双轨验证能帮你快速定位问题是出在策略本身还是出在部署环境而不是靠猜。5. 常见问题与排查速查整个项目做下来我遇到的技术问题可以分成三类训练期问题、迁移期问题和实机期问题。每类问题我都记录了一些典型症状和排查思路写成速查表供大家参考。5.1 训练期高频问题loss、reward 和策略退化训练期最常见的现象是 reward 不涨或者策略退化。reward 不涨先检查动作幅度是不是被惩罚项压制得太狠了我一开始把能耗惩罚权重设得太高机器人学了半天直接趴在地上不动因为“不动”反而是奖励最高的策略。这种局部最优是 reward 设计问题调低惩罚权重并加入正向的“前进奖励”就能解决。策略退化则表现为训练初期 reward 提升很快但跑了一段时间后突然崩盘性能大幅下降。这个是 PPO 算法的典型问题通常是学习率设置过高或者 entropy bonus 太小导致策略过早收敛到局部区域。我后来把学习率从 3e-4 降到 1e-4并适当提高 entropy 系数策略稳定性有了明显改善。还有一种情况是训练曲线看起来很好但 rollout 测试时策略完全不动。这往往是因为 reward 中存在某种“作弊”路径比如机器人通过大幅摆动身体获得了本不该有的前进速度。这时需要回看 rollout 视频用肉眼判断行为是否符合预期而不是只看曲线数字。5.2 迁移期高频问题sim2real 落差迁移期最典型的症状是仿真里走得飞快真机上完全走不了或者走两步就摔。这个问题百分之八十是动作延迟模拟没做够。我之前只设置了 10ms 延迟实机上舵机实际响应要 30ms 左右策略的“预判”完全失效了。把延迟加大到 30ms 重新训练之后真机表现立刻有了质的提升。第二个常见问题是物理参数偏差过大。真机的脚底摩擦系数可能跟仿真里的中位数差别很大机器人走起来要么打滑要么卡顿。解决方法是扩大摩擦系数的随机范围或者在仿真里增加多种地面材质的切换测试。第三个问题是观测噪声不匹配。实机上的惯性测量单元噪声比仿真里模拟的大不少策略对姿态反馈过于敏感导致高频颤抖。我的处理是在实机上对传感器数据做了低通滤波滤波截止频率设在 50Hz 左右既保留了运动信息又抑制了高频噪声。5.3 实机期高频问题延迟、偶发卡死与复位实机期最折磨人的三个问题是延迟抖动、主程序偶发卡死和系统复位。延迟抖动主要来自 Linux 系统的调度不确定性。即使设置了实时优先级某些系统中断仍然可能抢占控制线程。我的解决方案有两个一是把控制线程绑定到专用核心二是在非控制核心上运行繁重的日志任务时加上 nice 值限制避免它们争抢 CPU 资源。偶发卡死多半是串口通信的问题。总线舵机通信偶尔会出现帧错误或者超时如果代码里没有做超时保护程序就会一直阻塞等待表现为“卡死”。我的做法是给每次串口读写加上 2ms 的超时时间一旦超时就丢弃本轮数据并使用上一次的有效反馈保证控制循环始终不阻塞。系统复位大多数情况是供电问题。四足机器人启动瞬间的峰值电流很大电压跌落超过主控板的掉电阈值就会触发复位。我在电源输入端加了一个大容量电解电容并在代码里加了软启动逻辑先让舵机逐个使能而不是全部同时上电问题就解决了。5.4 问题排查小结表问题类型典型症状首要排查方向训练不收敛reward 长期不上升检查 reward 是否被某个惩罚项主导策略退化训练中期突然崩盘降低学习率、提高 entropy 系数奖励作弊曲线高但行为异常回看 rollout 视频确认行为合理性sim2real 翻转仿真好、实机差加大动作延迟模拟范围地面不适配打滑或卡顿扩大摩擦系数随机范围高频颤抖姿态抖动明显实机传感器加低通滤波实时性抖动控制频率不稳绑定核心、实时调度、隔离中断偶发卡死程序无响应串口读写加超时保护上电复位机器人重启检查供电余量、软启动舵机最后再分享一个小技巧我在整个调试过程中受益最大的一个设计是给控制程序加了一个“安全降级”模式。当策略推理连续失败或者传感器数据异常时系统会自动切换到一种预设的站姿保持程序让机器人原地蹲下而不是继续执行可疑的指令。这个机制在我后续调试中救过机器人好几次也让我敢在实机上更大胆地做实验。你如果有类似项目强烈建议在第一次上电前就把这个安全网做好它花不了多少时间但能避免大部分因小失大的意外。