资讯动态

强化学习四足机器人从仿真到RK3566实机部署全攻略

发布时间:2026/9/6 8:37:03 来源:尧图企业网站定制
老读者可能还记得我之前一直在聊强化学习在仿真环境里怎么跑、训练曲线怎么调、奖励函数怎么改但说实话仿真跑得再漂亮真机一上电、舵机一响很多东西都会打回原形。这次的项目是把手头一套 Microduck 25 厘米四足机器人从“在英伟达 GPU 上训练策略”推进到“在 RK3566 开发板上实机运行”整个过程踩了不少坑也摸清了一条比较靠谱的落地路径今天把这些经验整理出来希望能给正在折腾强化学习机器人落地的朋友一点参考。先交代一下这套东西是什么Microduck 是一台大约 25 厘米长的小型四足机器人结构上类似 MIT 的 mini cheetah 和 Stanford Pupper 那一系但成本友好得多用的是串行总线舵机加一块 RK3566 开发板做大脑。RK3566 是瑞芯微的一款四核 Cortex-A55 处理器主频 1.8GHz 左右带 0.8 TOPS 的 NPU放在边缘设备里属于够用但不宽裕的水平。整个项目的核心目标是让机器人在真实地面上走出稳定的步态而不是只在 MuJoCo 或者 Isaac Gym 里走两步就完事。本文适合手里已经有机器人和一点 PyTorch / Linux 基础、想把强化学习策略搬到真机上的朋友接下来讲的内容基本是踩坑实录不是教科书。1. 方案选型与整体架构1.1 为什么是 Microduck为什么是 RK3566刚开始我其实纠结过一段时间的平台选型。市面上四足机器人开发平台不算少尤其是树莓派加舵机的方案很常见资料也多。但 Microduck 这个尺寸级别有个很关键的优势结构件和舵机都是为低成本教育场景设计的整机重量轻25 厘米这个尺寸刚好适合在桌面上做实验即使摔倒也不至于把电机烧了。对比过 30 厘米以上的大型四足那些东西一套下来成本翻好几倍而且功率大、速度快真在室内调策略时风险也大。RK3566 之所以被选中有三点考虑。第一它跑 Linux 的生态比较成熟Ubuntu、Debian 镜像都有ROS2 也能顺利装上去第二接口丰富USB 3.0、千兆以太网、PCIe 都有后续扩展摄像头、激光雷达都比较方便第三NPU 虽然算力不高但实际用下来跑普通 CNN 模型是没问题的后面有需要可以做视觉感知。相比树莓派 4B 在缺货时期的价格RK3566 的板卡性价比也更高像泰山派这类开发板两三百块钱就能拿下。唯一需要注意的是RK3566 的 CPU 单核性能并不强跑一些复杂模型时延迟会比树莓派高一些后面会详细说。1.2 从仿真到实机的整体数据流整个系统的数据流可以分成训练侧和部署侧两条线。训练侧核心就是英伟达 GPU 平台用 PyTorch 写策略网络在 MuJoCo 物理引擎里做强化学习训练。这里没有选 Isaac Gym 主要是因为当时手头环境对 Unity 资产支持不太好MuJoCo 的 Python 接口更轻量直接 pip install 就能跑对自定义地形、模型加载也比较直观。训练完的策略网络会导出成 ONNX 格式。这一步很关键因为部署侧不可能直接跑 PyTorch 模型RK3566 上跑 ONNX Runtime 才是合理选择。ONNX 是一个中间表示格式相当于把 PyTorch 训练出来的网络结构固化成一个与框架无关的模型文件这样部署端的推理引擎就能直接读了。部署侧的数据流大概是这样的RK3566 通过串口或者 USB 转串口连接底层的舵机控制板控制板负责解析位置指令并驱动 Microduck 的 12 个关节。RK3566 上跑一个轻量的控制程序循环内部先读传感器数据主要是 IMU 的角速度和线加速度把这些数据拼成输入张量交给 ONNX Runtime 推理得到 12 个关节的目标位置再通过串行总线发给舵机。![数据流示意文字版]GPU 训练端MuJoCo 环境 PyTorch - 导出 ONNX - RK3566 部署端ONNX Runtime 推理 - 关节控制指令 - 舵机执行这个架构的优势在于分工明确训练侧不关心部署硬件部署侧不依赖训练框架。需要强调的是这里的策略网络输入不仅仅是关节角度还包括 IMU 数据和时间步的历史信息因为强化学习策略通常需要知道状态的时序变化才能做出稳定决策这就引出了后面要聊的 LSTM 网络部署问题。2. 训练阶段容易忽略的部署细节2.1 在仿真里训练一个“能上真机”的策略很多人跑强化学习训练时只盯着 reward 曲线觉得仿真里 reward 上去了就等于任务完成了。但实际从仿真到真机的迁移过程中最大的坑就是仿真环境和真实环境之间的差距学术上叫 sim-to-real gap。如果训练时完全没有考虑真机环境的差异策略在仿真里能跑得很好到了真机上因为摩擦力、惯量、延迟等因素的微小变化直接一个侧摔变成“路倒”。我在训练阶段采用的策略是领域随机化domain randomization。简单说就是在每一次训练 episode 开始的时候随机改变仿真环境里的物理参数比如地面摩擦力系数、舵机响应延迟、负载质量、IMU 噪声水平等。这样做的好处是让策略不再依赖某一个固定的物理参数而是学会一套在各种不确定条件下都能保持平衡的控制策略。实际设置的随机范围我建议先小后大比如地面摩擦系数在 0.4 到 1.2 之间随机舵机延迟在 0 到 20 毫秒之间随机逐步加大范围直到真机表现趋于稳定。另一个关键点是仿真步长和真机控制频率的匹配。MuJoCo 仿真步长我设的是 0.002 秒也就是 500Hz 的物理更新率但策略推理不可能在真机上跑这么高频。真机上强化学习策略的常用控制频率是 50Hz也就是每 20 毫秒推理一次。这两个频率之间需要通过动作平滑策略来衔接我的做法是把 500Hz 的物理仿真步长下、每隔 10 步取一次状态做推理剩下的 9 步把目标位置做线性插值。这样做的好处是策略看到的状态变化曲线跟真机上 50Hz 采样看到的基本一致避免策略过于依赖高频信息。2.2 导出 ONNX 时的算子与动态维度问题训练好策略网络后导出 ONNX 这一个环节真的能让人怀疑人生。我最初直接用 torch.onnx.export 导出一个包含 LSTM 层的策略网络结果在 RK3566 的 ONNX Runtime 上加载直接报错提示某些算子不支持。排查了半天发现问题是 PyTorch 导出的 LSTM 默认用了一堆动态循环节点ONNX Runtime 的 CPU 版本在 RK3566 上不支持这些动态图算子的高效执行。解决办法有两个方向。第一个是改用 ONNX Runtime 支持较好的静态图结构比如用固定循环次数的展开 LSTM 替代动态 LSTM第二个更激进直接把 LSTM 换成 GRU 或者甚至一维卷积层GRU 跟 LSTM 的表达能力接近但导出后的算子更简洁部署兼容性更好。我最终在 Microduck 上选择了 GRU因为四足步态控制需要记忆过去几个周期的状态GRU 在这方面完全够用而且推理速度比 LSTM 快不少。动态维度问题也值得单独说。torch.onnx.export 默认导出的模型输入维度是固定的比如 [1, 12]但在真机运行的时候IMU 数据的维度可能因为批次处理的原因变成 [1, 14] 或者 [2, 12]如果模型写死了输入形状推理就会报错。解决方案是在导出时把 dynamic_axes 参数配上把时间步和批次维度标记成动态但要注意动态维度在部分推理引擎里会降低算子融合效率尽可能保持部署时的输入形状和导出时一致更好。2.3 奖励函数设计的一些“后悔药”关于奖励函数网上文章已经很多了我只提一个跟真机落地强相关的心得。最初我按通用 bipedal 任务设计奖励函数比如前进速度奖励、身体朝向惩罚、能量消耗惩罚结果真机跑起来发现步态虽然对但关节角度变化过于剧烈舵机发热严重跑个几分钟主板就开始电压不稳。后来在奖励函数里加了关节角加速度的惩罚项同时把关节速度的惩罚系数调高了两倍效果立竿见影。这里背后逻辑是仿真里舵机是理想模型任意高加速度的运动都能执行但真机舵机有物理极限过高的加速度需求会被舵机直接裁掉造成策略期望和实际执行的偏差。如果奖励函数显式惩罚高加速度训练出的策略自然会更“平滑”真机执行的成功率就上来了。注意训练阶段一定要记录策略输入输出张量的范围。真机推理时如果输入状态和训练时的分布差异过大比如 IMU 噪声导致加速度数值飙到训练时没见过的高值策略输出可能完全乱掉。我的做法是训练时把每个状态维度的 min/max 记录下来部署后在推理前做裁剪。3. RK3566 实机适配性能、算子与通信3.1 实测推理性能50Hz 控制循环到底能不能撑住这是很多刚从 GPU 转到边缘设备的人最担心的一个问题。GPU 上一个前向传播可能只要几毫秒RK3566 上跑同样的网络可能直接慢一个数量级。但这里有个关键点GPU 擅长的是大规模并行计算的卷积操作而强化学习控制策略通常是小规模全连接网络加少量循环结构这种模型在 CPU 上跑反而没有想象中那么慢。我的策略网络结构大致是14 维输入12 个关节角 2 个 IMU 角速度经过两层 128 维的全连接和 ReLU 激活接一个 64 维的 GRU 层再经过一层 128 维全连接最终输出 12 个关节目标角速度。整个模型参数量在 7 万左右。在 RK3566 上用 ONNX Runtime 的 CPU 后端跑单次推理耗时大约 8 到 12 毫秒加上前后处理、串口通信整个 50Hz 控制循环的耗时能稳定控制在 20 毫秒以内也就是 CPU 占用率在 50% 左右。如果模型再大一点比如把 GRU 换成隐藏层 128 维的双层 LSTM单次推理会飙到 25 毫秒以上控制循环就要降到 30Hz 了。所以结论很明确在 RK3566 上做强化学习控制控制频率和模型大小是直接矛盾的优先保证 50Hz 以上的控制频率更重要模型精简后策略仍然可以通过训练阶段的调优来弥补表达能力的损失。实测我最终在 Microduck 上跑的数据是模型推理 9.4ms平均状态读取与预处理 2.1ms串口发送控制指令 1.8ms总循环时间 13.3ms满足 50Hz 预算3.2 RK3566 NPU 为什么没派上用场RK3566 宣传的 0.8 TOPS NPU 看起来很诱人但实际用在这一类强化学习控制策略上性价比并不高。原因有三点第一NPU 主要针对 CNN 类模型做了大量优化对全连接层和循环神经网络的支持很弱。我尝试过把训练好的模型用 RKNN-Toolkit2 转成 RKNN 格式结果 RKNN 对 GRU/LSTM 的支持非常有限部分算子直接需要退回 CPU 执行这样反而多了一层数据拷贝开销整体速度甚至比纯 CPU 推理更慢。第二量化精度损失对控制策略影响很大。NPU 要跑得快通常需要 INT8 量化但控制策略输出的关节角度精度要求很高量化到 8 bit 后角度误差会被放大真机上表现为每个控制周期都会出现小幅抖动合在一起就是步态的明显不平滑。第三渲染和调度复杂。NPU 推理是异步的需要自己管理输入输出缓冲区控制循环这种对延迟一致性要求很高的场景增加了不少调试成本。所以最终我选择在 CPU 上用 FP32 ONNX Runtime 推理模型小、延迟稳、精度无损这才是边缘控制的正道。3.3 通信链路RNDIS、串口和时序预算Microduck 的 RK3566 开发板与上位机之间一般通过 USB RNDIS 协议组建虚拟以太网也就是说插上 USB 线后在宿主机和开发板上分别配置 IP就能像局域网一样 SSH 登录和传输文件。这种方式比 HDMI 加键鼠方便太多也是我日常调试的主要入口。不过在实机运行时要特别注意RNDIS 的虚拟网卡走的是 USB 协议栈偶尔会有小幅延迟抖动所以我的做法是控制程序启动后把所有无关服务停掉保证 CPU 不被 USB 协议栈抢占太多。另一个值得强调的通信链路是 RK3566 与底层舵机控制板的连接。Microduck 的舵机控制板一般通过串口接收指令波特率通常设为 1Mbps 或者 500kbps。串口通信的时序非常敏感我之前踩过一个坑是在同一路串口上既给舵机发位置指令又去读舵机角度反馈结果读取的时候产生了几毫秒阻塞导致控制循环超过 20ms 预算。后来我改成发出指令后不等待反馈只在需要校准或紧急停止时才主动读取舵机状态时序就稳定了。如果你也遇到控制循环周期波动大的情况可以先在代码里打印每个环节的耗时分布看堵塞到底出在推理、串口还是系统调用上。大多数情况通过调整线程优先级就能解决实时的思路参考 RT Linux 的做法把控制线程绑定到特定 CPU 核并用 sched_setscheduler 设置 SCHED_FIFO 实时优先级。3.4 电源噪声与舵机抖动这个坑我一开始完全没有预料到。真机第一次站稳后走路总是发抖一开始我以为是策略网络输出的速度指令波动太大后来把推理输出直接打到日志里发现输出序列非常平滑问题其实是电源。Microduck 如果直接用 USB 或者普通稳压模块给舵机和 RK3566 同时供电舵机大电流瞬态变化会引起电源电压波动这个噪声会通过 ADC 传导到 IMU 的读数上最终导致控制策略收到错误的姿态信息。花了两天才定位到这个问题当时的排查办法是看 IMU 原始数据里是不是有跟舵机动作相关的周期性噪声发现确实是。解决方案分两步第一舵机电源和控制板电源分开舵机用电池高压直接供电控制板经过稳压模块隔离供电第二在 IMU 数据进入策略网络前用低通滤波器滤掉高频噪声。我这里用的是二阶 Butterworth 低通滤波器截止频率 30Hz对 50Hz 的控制循环来说足够了不会引入明显延迟。建议给 RK3566 和舵机分别供电至少也要在舵机电源上加大容量的电解电容。真机调试电源问题的优先级应该放在模型调优之前。4. 真机运行与调试从站不起来到稳定步态4.1 安全措施与开机逻辑真机调试第一步不是调策略而是写好安全逻辑。我在 Microduck 的控制程序里加了三层保护第一层是状态检查如果 IMU 检测到机身倾斜角度超过 45 度立即停止发送控制指令第二层是看门狗控制循环每一轮都会更新一个计数器如果主循环卡住超过 500ms舵机控制板自动把所有关节回到初始位置第三层是每次上电时所有舵机处于零力矩状态只有确认遥控指令后才进入工作模式。这个看起来简单的安全逻辑救了我无数次。刚开始调试策略网络的时候因为 IMU 数据方向没校准对机器人一站起来就往一边倒摔倒速度极快如果没有第一层保护和外壳缓冲舵机齿轮早摔断了。提醒所有做真机强化学习的朋友安全逻辑一定是最先写的代码没有协商余地。4.2 零点校准与关节方向统一Microduck 这类四足机器人采用的是串行总线舵机可以实现角度反馈和位置闭环但出厂时关节零点和方向并不统一。同一个关节两只脚可能一个默认在 20 度一个默认在 -20 度如果不校准就算策略网络输出完全正确的角度指令机器人也会走成螺旋步态。校准方法不复杂用一个水平平台把机身架起来让每条腿自然下垂读取所有关节的当前角度并记录为“零点偏移”部署时把策略输出减去这个偏移再下发。关节方向的处理更隐蔽需要确认每个舵机的旋转方向和策略训练中使用的正方向一致不一致的关节在部署代码里单独翻转角度符号。这个校准过程虽然无聊但直接影响最终步态质量。4.3 真机实测结果与 PPO 策略的调整方向经过上面的适配后我把训练好的 PPO 策略部署到 RK3566 上第一次尝试是让机器人在原地站定 10 秒再看姿态是否稳定。实测结果是机身倾斜角度能控制在 5 度以内但伴随大约 1.5Hz 的周期性低频晃动步态虽然没倒但看起来像是时刻在“微调”。这个问题的根源是策略网络在训练时没有见过真机的 IMU 高频噪声导致它对速度信号过于敏感。解决办法有三条路一是增大训练时 IMU 噪声的随机范围让策略学会过滤噪声二是在部署端滤波正如前文所说三是降低策略输出增益让每个控制周期的关节角度变化幅度变小。我最终采用了第二种加第三种组合实机表现明显改善低频晃动基本消失了。再说一个在参考关注里反复出现的关键词——“基于强化学习的 PID 控制”。很多人误以为强化学习替代了 PID实际上在 Microduck 上更合理的做法是让强化学习策略输出目标速度和姿态再由底层的 PD/PID 控制器去跟踪这些目标。也就是说强化学习负责“指挥”传统控制负责“执行”。这个分工让整个系统更容易调试哪一层出问题就修哪一层而不是把两个复杂的控制逻辑混在一个黑盒里。4.4 常见问题与排查速查表现象可能原因排查方法机器人在固频 1-2Hz 晃动IMU 噪声过大或输出增益过高检查 IMU 原始数据降低策略输出增益加强低通滤波电机发热严重策略输出加速度过大在奖励函数里加加速度惩罚检查舵机是否超限位控制循环超过 20ms模型推理过慢或串口阻塞打印各环节耗时换更小的网络调整串口读逻辑走起来往一侧偏零点偏移未校准 / 关节方向不一致重新校准零点检查关节方向符号机器人一上电就抖电源噪声干扰 IMU分开供电IMU 和舵机地线分离ONNX Runtime 加载失败算子不支持 / 动态维度问题换 GRU检查 dynamic_axes 是否合理舵机失去响应看门狗触发或串口错误查日志看是否触发安全逻辑重启控制程序5. 个人体会仿真到真机之间到底隔了什么整个项目从训练到实机跑通前后花了我大概三周业余时间真正花在训练和模型调优上的时间只占三分之一剩下三分之二全部耗在系统集成和调试上。这大概是强化学习机器人落地最真实的规律算法是引擎但真机落地是底盘、电源、通信、实时性、安全机制这些“脏活”共同堆出来的。如果让我重新做一遍我会在项目一开始就把部署目标平台、控制频率、模型大小上限、通信时序预算这些约束写进设计文档里然后带着这些约束去设计网络结构和训练超参而不是训练完了才开始考虑“怎么搬到 RK3566 上”。否则等待你的就是改网络结构重新训练、重新适配边缘算子的循环。另外要说的经验是不要迷信 GPU 时代的训练工具链。PyTorch 里写网络很惬意但 ONNX 导出、算子兼容、INT8 量化这些部署相关的能力一定要提前熟悉。尤其像 RK3566 这种边缘设备ONNX Runtime CPU 推理是最稳的路径NPU 能不用就不用至少在控制类任务上是这样。最后分享一个对 Microduck 这类小型四足很实用的小技巧真机部署前先在仿真环境里把策略加上输出限幅和变化率限幅再测试一遍在不同初始姿态下的表现。因为真机上舵机执行角度指令本身有延迟如果策略输出变化速度过快实际执行和仿真之间会出现滞后误差。加上变化率限幅之后这个误差会被显著压小步态也会平滑很多。这也是我这次工程里体会最深、回报最高的一个改动。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价