ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

基于50Hz神经控制闭环的低成本双足机器鸭MicroDuck设计与实现

基于50Hz神经控制闭环的低成本双足机器鸭MicroDuck设计与实现 1. 项目缘起为什么我要做一只双足机器鸭1.1 从“能走”到“走得稳”的那道坎双足机器人这个方向做的人多做出来的东西少。原因不复杂轮式底盘和四足平台在静态稳定性上有天然优势而双足系统从站立那一刻起就在和重力做对抗。我最初做 MicroDuck 的动机很朴素——想验证一套轻量化的神经控制闭环能不能在低成本舵机平台上跑出接近生物步态的稳定性。选“鸭子”这个形态不是噱头鸭子的重心分布和步幅节奏在中小型双足平台里属于比较友好的参考模型髋关节摆幅不需要太大脚掌接触面积也够用。MicroDuck 的核心定位是一个50Hz 神经控制闭环的验证平台。50Hz 这个数字不是随便定的它对应 20ms 的控制周期是嵌入式实时控制里一个非常经典的折中点再快MCU 的算力和舵机响应跟不上再慢姿态修正就会滞后到无法挽回。整只鸭子的硬件成本控制在千元以内主控用的是一块常见的 Cortex-M4 开发板舵机是串行总线舵机IMU 是六轴模块。这套配置听起来平平无奇但把神经控制闭环跑通之后它的步态稳定性超出了我最初的预期。这篇文章适合三类人看一是想入门双足机器人但被“高门槛”劝退的爱好者二是已经在做舵机平台、想引入闭环控制但不知道从哪下手的人三是对 50Hz 控制频率、陷波器设计这些细节感兴趣的控制方向从业者。我会把设计思路、参数计算、实操步骤、踩过的坑全部摊开讲你照着做大概率能复现。1.2 神经控制闭环到底“闭”在哪里很多人听到“神经控制闭环”会觉得玄乎其实拆开看就三件事感知、决策、执行然后执行结果再反馈回感知。MicroDuck 的闭环链路是这样的——IMU 以 200Hz 采样姿态角和角速度主控在 50Hz 的控制周期里跑一次神经网络推理输出各关节的目标角度增量通过串行总线发给舵机舵机执行后再由 IMU 感知新的姿态进入下一轮。这个环里最关键的不是神经网络有多深而是时序必须严格对齐。我见过太多项目神经网络训练得漂漂亮亮一上真机就抖成筛子问题几乎都出在时序上采样、推理、执行三个环节的时间戳对不齐闭环就变成了开环加噪声。MicroDuck 的神经网络并不大输入是 IMU 的姿态角、角速度加上关节反馈角度输出是髋、膝、踝的目标角度修正量。网络结构是三层全连接参数量在几千级别跑在 MCU 上单次推理耗时约 3ms留足了余量给通信和执行。这里我要强调一个观点双足控制里控制频率的稳定性比网络复杂度重要得多。一个 50Hz 稳定运行的简单网络效果远好过一个 200Hz 但时快时慢的复杂网络。2. 硬件选型与机械结构把钱花在刀刃上2.1 主控与舵机的搭配逻辑主控我选的是带 FPU 的 Cortex-M4主频 168MHzFlash 1MBRAM 192KB。选它的理由很直接神经网络推理需要浮点运算没有 FPU 的 M0/M3 跑起来会非常吃力而 RAM 要同时容纳网络权重、IMU 缓冲区和舵机指令队列192KB 是个比较舒服的下限。舵机用的是串行总线舵机扭矩 15kg·cm 级别金属齿轮。这里有个选型心得双足平台的舵机扭矩要按静态站立时单腿承重的 2.5 倍以上来选。MicroDuck 整机重约 1.2kg单腿承重约 0.6kg考虑到步态中的动态冲击15kg·cm 是够用的再低就会在快速迈步时出现“软脚”。串行总线舵机相比 PWM 舵机的好处是接线简单、支持角度回读。角度回读这一点对闭环至关重要——没有关节反馈神经网络就不知道执行结果闭环就断了。总线舵机的通信协议通常是半双工的我用的是 1Mbps 波特率一帧指令包含 ID、目标角度、运行时间回读帧包含当前角度和负载。实测下来12 个关节轮询一遍回读大约 4ms加上推理 3ms50Hz 周期里还剩 13ms 余量比较从容。2.2 机械结构的几个关键尺寸机械部分我用的是 3D 打印件材料 PLA层高 0.2mm壁厚 1.6mm。这里不展开讲建模重点说三个影响控制效果的尺寸。第一是大腿长度和小腿长度的比例我取的是 1:1.1这个比例下膝关节的力矩需求比较均衡不会出现某一侧舵机长期过载。第二是脚掌的前后长度前掌比后掌长约 30%这样在重心前移时脚掌能提供足够的支撑面减少前倾翻倒的概率。第三是髋关节的横向间距我取的是肩宽的 0.8 倍太窄会左右晃太宽会增加舵机负担。装配的时候有个细节容易被忽略所有关节的初始零位必须在装配前统一标定。我的做法是给每个舵机写入中位值然后用直角尺逐个校准连杆的垂直度误差控制在 1 度以内。这一步偷懒的话后面神经网络要花大量精力去补偿机械偏差得不偿失。3. 50Hz 控制周期的实现细节3.1 定时器配置与任务调度50Hz 意味着 20ms 一个周期。我用的是硬件定时器中断优先级设为最高中断里只做一件事置位一个标志位。主循环检测到标志位后依次执行 IMU 读取、神经网络推理、舵机指令下发。为什么不直接在中断里跑完整流程因为神经网络推理耗时 3ms放在中断里会阻塞其他中断尤其是串口接收中断容易丢包。中断只做标记主循环做重活这是嵌入式实时控制的经典做法。定时器的配置要注意预分频和重装载值的计算。假设系统时钟 168MHz预分频设为 167则定时器时钟为 1MHz重装载值设为 19999溢出周期就是 20ms。这个计算过程我写出来是想说明50Hz 不是拍脑袋定的是定时器参数算出来的。如果你用的主频不同重装载值要重新算别直接抄。3.2 50Hz 陷波器的设计动机这里要专门讲一下 50Hz 陷波器因为这是热词里反复出现的点也是实际调试中绕不开的坑。舵机在运动时会产生周期性的机械振动这个振动的基频往往和舵机的控制频率、齿轮啮合频率相关。当振动频率接近控制频率的整数倍时会通过 IMU 反馈进入控制环形成正反馈振荡。我实测发现 MicroDuck 在站立时有一个约 50Hz 的抖动分量正好和控制频率重合导致姿态角读数一直在小幅震荡。解决办法就是在 IMU 数据处理环节加一个 50Hz 陷波器。陷波器的本质是一个带阻滤波器只衰减特定频率的信号其他频率正常通过。我用的双 T 型陷波滤波器它的传递函数是H(s) (s² ω₀²) / (s² (ω₀/Q)s ω₀²)其中 ω₀ 2π×50 rad/sQ 是品质因数我取 0.707。Q 值太小阻带太宽会滤掉有用的姿态信息Q 值太大阻带太窄又滤不干净。0.707 是巴特沃斯响应的经典值实测效果比较均衡。离散化的时候我用的是双线性变换采样率 200Hz算出来的差分方程直接写进代码里每个 IMU 采样点过一遍计算量很小。注意陷波器不是万能的。如果你的机械振动频率随负载变化而漂移固定频率的陷波器效果会打折。这时候要么做自适应陷波要么从机械上把振动源解决掉。我后来在舵机输出轴加了一圈硅胶减震垫50Hz 分量直接降了一半陷波器的压力小了很多。4. 神经网络控制器的训练与部署4.1 仿真环境搭建与数据采集神经网络不能直接在真机上试错摔几次舵机就废了。我的流程是先在 MuJoCo 里建 MicroDuck 的模型用 viewer 观察步态采集仿真数据训练网络再部署到真机。MuJoCo 的模型参数要和真机对齐尤其是质量、惯量、关节摩擦这几个差太多的话仿真里走得好好的网络上真机就废了。我用的方法是称重每个连杆用摆锤法测惯量摩擦系数靠试凑。数据采集的方式是让仿真里的鸭子在随机扰动下走记录每一时刻的 IMU 读数、关节角度和对应的“正确修正量”。正确修正量怎么来我用的是一个简化的 PD 控制器作为“教师”它的输出作为神经网络的标签。这就是行为克隆的思路先用传统控制器跑出数据再用神经网络去拟合最后用神经网络替代传统控制器。这样做的好处是训练数据有保障坏处是神经网络的上限受教师控制器限制。对于 MicroDuck 这个验证平台来说够用了。4.2 网络结构与推理优化网络结构我前面提过三层全连接输入 12 维姿态角 3 角速度 3 关节角 6隐藏层 32 维输出 6 维髋膝踝各 2。激活函数用 ReLU输出层用 tanh 把修正量限制在 ±0.3 弧度内防止输出过大导致舵机猛打。训练用 PyTorch损失函数是 MSE优化器 Adam学习率 1e-3训练 500 个 epoch 收敛。部署的时候要把 PyTorch 的权重导出成 C 数组推理代码手写矩阵乘法。这里有个优化技巧把权重按行主序存储循环展开用 FPU 的 SIMD 指令加速。我实测下来优化前单次推理 8ms优化后 3ms提升明显。另外输入数据要做归一化把姿态角除以 π角速度除以 10关节角除以 π这样网络输入的数值范围在 ±1 附近训练和推理都更稳定。5. 真机调试与问题排查实录5.1 首次上电的“死亡抖动”第一次给 MicroDuck 上电的时候它站起来不到两秒就开始剧烈抖动然后直接趴下。我当时的排查顺序是这样的先看 IMU 数据发现姿态角在 ±5 度范围内高频震荡再看舵机指令发现指令本身也在震荡。这说明闭环形成了正反馈。我把神经网络断开直接用固定角度指令抖动消失说明问题出在控制环里。然后我把控制频率从 50Hz 降到 20Hz抖动幅度减小但没消失说明不是单纯的频率问题。最后加上 50Hz 陷波器抖动基本消失。这个排查过程告诉我遇到抖动先断环再逐段排查不要一上来就改网络。5.2 常见问题速查表现象可能原因排查方法解决措施站立时高频抖动控制频率与机械振动耦合断开神经网络看是否消失加 50Hz 陷波器机械加减震迈步时前倾摔倒重心前移过快脚掌支撑不足观察 IMU 俯仰角变化率减小步幅加长前掌舵机发热严重扭矩余量不足或零位偏差摸舵机温度查关节角度换大扭矩舵机重新标定零位通信丢包波特率过高或线缆过长统计回读成功率降波特率缩短线缆网络输出饱和输入未归一化或训练不足打印网络输入输出归一化输入增加训练轮次5.3 几个独家避坑技巧第一个技巧IMU 要远离舵机电源线。我最初把 IMU 装在腹部离舵机电源线很近姿态角噪声特别大。后来移到背部噪声直接降了一个数量级。舵机换向时电源线上的电流尖峰会通过磁场耦合进 IMU这是硬件层面的干扰软件滤波只能缓解不能根治。第二个技巧舵机指令下发要加斜率限制。神经网络输出的修正量可能突变如果直接发给舵机舵机会猛打既伤齿轮又引起振动。我的做法是在指令和舵机之间加一个一阶低通时间常数 30ms让角度变化平滑一些。这个低通的时间常数不能太大否则响应滞后也不能太小否则起不到平滑作用30ms 是试出来的。第三个技巧调试时用 MuJoCo viewer 重新播放功能。真机调试成本高每次摔倒都要重新摆姿势。我后来养成习惯把真机的 IMU 和关节数据录下来导入 MuJoCo 用 viewer 重新播放在仿真里复现问题改好了再上真机。这个流程能省下大量时间尤其是排查偶发性摔倒的时候。6. 拆解资料与后续扩展方向6.1 拆解资料整理MicroDuck 的拆解资料我整理了一份包含机械图纸、电路原理图、固件源码和训练脚本。机械图纸是 STEP 格式方便你改尺寸电路原理图是 KiCad 格式主控和舵机的接线都标清楚了固件源码是 C 语言基于 HAL 库注释写得比较细训练脚本是 Python依赖 PyTorch 和 MuJoCo。这些资料我放在一个压缩包里结构是这样的/mechanical放图纸/electronics放原理图/firmware放固件/training放训练脚本/docs放调试记录。调试记录里我详细写了每个问题的现象、排查过程和最终解决比这篇文章更细适合想深入的人看。6.2 后续可以怎么玩MicroDuck 作为一个验证平台跑通闭环只是起点。后续我打算往三个方向扩展。第一是加入足底力传感器现在脚掌是刚性的落地冲击全靠舵机吸收加了力传感器之后可以做落地检测和柔顺控制步态会更自然。第二是把控制频率提到 100Hz这需要换更强的 MCU 或者把网络量化成 int8算力和时序都要重新调。第三是做多鸭协同两只鸭子互相推搡测试闭环的抗扰能力这个方向偏研究但挺有意思。我个人在实际操作中的体会是双足控制这件事硬件是基础时序是骨架算法是血肉。很多人一上来就钻算法结果硬件和时序的坑没填算法再好也跑不起来。MicroDuck 这个项目我最大的收获不是神经网络调得多好而是把 50Hz 这个控制周期里的每一个环节都摸透了——从定时器配置到陷波器设计从舵机通信到指令平滑每一处细节都值得反复打磨。如果你也在做类似的东西我的建议是先把 50Hz 的裸机控制跑稳再往上叠神经网络顺序反了会走很多弯路。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进