ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

MicroDuck双足机器鸭拆解:50Hz神经控制闭环与陷波器设计

MicroDuck双足机器鸭拆解:50Hz神经控制闭环与陷波器设计 1. 一只机器鸭凭什么值得拆解第一次看到 MicroDuck 这个项目的时候我正蹲在工位上调试一台四足平台的步态参数屏幕上那条关节力矩曲线抖得像心电图。同事甩过来一个链接说“你看看这个一只鸭子50Hz 闭环跑得比你这稳”。我当时的第一反应是双足本来就比四足难还做成鸭子这种重心靠前、支撑面窄的形态50Hz 的控制频率在今天看来也不算高它到底是怎么站住的带着这个疑问我把 MicroDuck 的公开资料、拆解记录、仿真回放流程翻了个遍越看越觉得这东西有意思。它不是那种堆算力、堆传感器的高预算项目反而处处透着“用最朴素的工程手段解决最要命的问题”的思路。MicroDuck 是一只双足机器鸭核心是一套运行在 50Hz 频率下的神经控制闭环说白了就是感知—推理—执行这条链路每 20 毫秒跑一次用神经网络输出关节目标再靠底层控制器把姿态稳住。它解决的问题很具体——在算力有限、传感器不算豪华的前提下让一个双足平台实现稳定的动态平衡和步态切换。这篇文章适合谁看如果你正在做足式机器人、想入门强化学习控制、或者单纯好奇“一只机器鸭是怎么不摔倒的”都能从里面拿到能直接抄的东西。我会把它的整体设计思路、50Hz 这个数字背后的取舍、神经控制闭环的每一环、仿真回放与拆解资料怎么用全部摊开讲。MicroDuck、50Hz、神经控制闭环、双足机器鸭这几个关键词会贯穿始终因为它们是理解这个项目的四把钥匙。先说结论性的判断MicroDuck 的价值不在于它用了多前沿的算法而在于它把“神经控制”和“经典控制”缝合得恰到好处50Hz 这个频率就是缝合线。往下看你就明白为什么。2. 整体设计思路与方案选型拆解2.1 为什么是双足而不是四足或者轮式做机器人的人都知道一句话轮式最稳四足最实用双足最难。那 MicroDuck 为什么偏偏选双足我分析下来有三个层面的原因而且这三个原因互相咬合不是拍脑袋决定的。第一是形态表达的需求。鸭子这个形象天然是双足的你要做一个“机器鸭”用四足或者轮式就失去了辨识度。项目本身带有很强的展示和教学属性形态本身就是内容的一部分。这一点在做开源硬件的时候特别重要——一个好看、有记忆点的形态能让项目传播效率翻好几倍。第二是控制难度的“甜点区”。四足平台因为支撑点多静态稳定裕度大很多问题可以靠“慢慢挪”糊过去反而不容易逼出真正的动态控制能力。双足则相反它必须处理倒立摆式的本质不稳定每一步都是“主动摔倒再救回来”。对于想验证神经控制闭环的项目来说双足提供的挑战刚刚好——难到必须用闭环又不至于难到需要工业级算力。第三是成本与可复现性。双足意味着更少的关节、更少的电机、更少的驱动器。MicroDuck 的腿部自由度设计得很克制每条腿的关节数控制在个位数整机成本压到了个人开发者能承受的范围。这一点我在实际做项目时体会很深一个开源项目能不能火往往不取决于它多先进而取决于别人能不能照着做出来。提示如果你打算复现类似平台先想清楚你要的是“能站住”还是“能走好看”。前者可以砍自由度后者必须保留足够的髋、膝、踝关节否则步态会非常僵硬。2.2 50Hz 这个数字是怎么定下来的很多人看到 50Hz 会觉得“这也太低了”现在随便一个 IMU 都能跑到 1kHz电机驱动器动辄 20kHz 的 PWM。但控制频率不是越高越好它是一道综合了算力、延迟、噪声和稳定性的平衡题。我把 MicroDuck 选 50Hz 的逻辑拆成四块讲。第一块是神经网络推理的算力账。神经控制闭环里每一帧都要跑一次前向推理。假设网络不大参数量在几十万级别在嵌入式 CPU 或者低端 NPU 上跑一次推理大概需要几毫秒到十几毫秒。如果控制频率定到 200Hz留给推理的时间只有 5ms很多低成本平台直接跑不动。50Hz 给出 20ms 的预算推理占掉一半还剩一半给其他环节这个余量是合理的。第二块是传感器噪声的滤波账。这是最容易被忽略的一点。IMU 的原始数据里混着大量高频噪声尤其是电机振动带来的干扰。控制频率越高你越容易把噪声当成真实信号去响应结果就是机器人抖个不停。50Hz 天然是一个低通的效果——它把 25Hz 以上的成分基本排除在控制回路之外。这里就引出了热搜词里的“50Hz 陷波器”和“50Hz 双 T 型陷波滤波器设计”后面我会专门用一节讲。第三块是机械响应的时间账。双足机器人的腿部惯量不小从发出力矩指令到关节真正动起来本身就有几十毫秒的延迟。你控制频率再高机械也跟不上反而会造成指令堆积和相位滞后。50Hz 和中小型双足平台的机械带宽是匹配的。第四块是经典控制器的兼容账。神经网络的输出通常不是直接给电机的力矩而是给一个目标角度或者目标姿态底层还要跑一层 PID 或者阻抗控制器。这层底层控制器往往跑在更高的频率上比如 500Hz 到 1kHz。50Hz 的神经层和 1kHz 的底层形成一个分层结构各司其职。控制频率推理预算噪声敏感度机械匹配度适用场景20Hz充裕低偏慢慢速静态平衡50Hz适中较低好动态步态、教学平台200Hz紧张高一般高性能平台1kHz几乎不可能跑神经网络极高需高刚度机械纯经典控制这张表是我根据实际调试经验整理的不是绝对标准但能帮你快速判断自己的项目该往哪个区间靠。2.3 神经控制闭环的整体架构MicroDuck 的闭环可以画成一条链状态估计 → 神经网络策略 → 动作输出 → 底层控制 → 机械执行 → 传感器反馈然后回到状态估计。这条链每 20ms 转一圈。状态估计这一环输入主要是 IMU 的姿态角、角速度加上关节编码器的角度和速度可能还有足底接触开关。输出是一个低维的状态向量喂给神经网络。这里的关键是状态向量的维度和归一化维度太高网络难训太低信息不够归一化不做训练时梯度会炸。神经网络策略这一环输入状态向量输出目标关节角度或者目标关节力矩。MicroDuck 用的是相对轻量的全连接网络层数不深激活函数用 ReLU 或者 Tanh。为什么不用 LSTM 或者 Transformer因为 50Hz 的预算下循环网络和注意力机制的计算开销太大而且双足的平衡更多是“当前状态决定当前动作”历史信息的边际价值有限。动作输出之后底层控制器接手。如果网络输出的是目标角度底层跑位置 PID如果输出的是力矩底层跑力矩环或者阻抗控制。MicroDuck 更偏向位置目标加阻抗的组合这样对电机的要求低一些也更容易在仿真里迁移到真机。注意神经网络的输出一定要做限幅和速率限制。我踩过的坑是网络在训练分布外会输出离谱的角度如果没有限幅关节会直接撞机械限位轻则丢步重则烧驱动。3. 核心细节解析与实操要点3.1 50Hz 陷波器为什么偏偏盯上这个频率热搜里“50Hz 陷波器”和“50Hz 双 T 型陷波滤波器设计”出现得很频繁这不是巧合。在机器人控制里陷波器的核心作用是干掉某个特定频率的干扰同时尽量不影响其他频段。那为什么是 50Hz一方面50Hz 在很多地区是工频电源和某些电磁环境会引入这个频率的干扰。另一方面更关键的是机械共振。双足平台的腿部、躯干、电机支架都有各自的固有频率如果某个固有频率恰好落在控制带宽附近就会引起持续振荡。很多中小型双足平台的共振点就在几十赫兹这个区间50Hz 附近是重灾区。陷波器的设计目标很明确在 50Hz 处挖一个“深坑”让这个频率的增益趋近于零其他频率照常通过。双 T 型陷波滤波器Twin-T Notch Filter是实现这个目标的经典结构它由两个 T 型网络组成一个在反馈路径一个在前馈路径通过参数匹配在目标频率处形成传输零点。双 T 型陷波器的传递函数大致长这样H(s) (s^2 ω0^2) / (s^2 (ω0/Q)s ω0^2)其中 ω0 是陷波中心角频率对应 50Hz 就是 ω0 2π×50 ≈ 314.16 rad/sQ 是品质因数决定坑的宽窄。Q 越大坑越窄越深但对频率漂移越敏感Q 越小坑越宽但会误伤附近的信号。我在实际调这个滤波器的时候总结了几个参数选择的经验Q 值从 1 开始试不要一上来就设 10。Q 太高的话如果实际共振频率偏了 2Hz陷波器就完全失效。中心频率要实测不要照抄 50Hz。用扫频或者敲击实验测出你平台的真实共振点可能是在 47Hz 也可能是 53Hz。陷波器要放在信号链的正确位置。一般放在 IMU 姿态解算之后、控制输入之前不要放在原始数据上否则会引入额外相位滞后。参数含义推荐初值调整方向ω0陷波中心频率实测共振频率按实测值设Q品质因数1.0振荡未消则减小误伤信号则增大采样率滤波器运行频率≥ 500Hz至少是中心频率的 10 倍提示陷波器不是万能的。如果振荡来自控制增益过高正确做法是降增益而不是硬加陷波器。陷波器是治标降增益是治本两者要配合用。3.2 状态估计与传感器融合的细节状态估计这一环决定了神经网络“看到”的世界准不准。MicroDuck 的状态估计主要靠 IMU 和关节编码器可能还有足底接触。这里有几个实操要点。IMU 的姿态解算常见做法是互补滤波或者 Mahony 滤波。互补滤波简单把陀螺仪积分的高频响应和加速度计的低频响应加权融合。Mahony 滤波稍微复杂一点但姿态精度更好。对于 50Hz 的控制回路互补滤波其实够用了因为控制频率本身不高对姿态的瞬时精度要求没那么苛刻。关节编码器的数据处理要注意差分求速度时的噪声放大。编码器角度差分一次得到速度噪声会被放大差分两次得到加速度噪声基本没法看。所以速度一般用低通滤波后的角度差分或者直接用编码器自带的测速功能。足底接触检测用开关最简单但开关有抖动需要做去抖。用足底力传感器更好但成本高。MicroDuck 这种项目一般用开关加软件去抖去抖时间设在 5ms 到 10ms 之间。状态向量的组织方式也很讲究。我习惯把状态分成几组姿态组roll、pitch、yaw 及其角速度、关节组各关节角度和速度、接触组左右脚是否着地。每组内部做归一化组间用不同的权重。这样网络更容易学到“姿态优先、关节次之”的层次关系。3.3 神经网络策略的训练与部署训练这一环MicroDuck 走的是仿真到现实的路线。先在 MuJoCo 里建一个和真机参数接近的模型用强化学习训练策略再迁移到真机。这里有几个关键点。仿真模型的准确性直接决定迁移成功率。质量、惯量、摩擦、电机响应曲线这些参数要尽量测准。我见过太多项目仿真里跑得飞起真机一上就趴八成是仿真模型太理想化。域随机化Domain Randomization是提升迁移鲁棒性的核心手段。训练时随机扰动质量、摩擦、延迟、噪声让策略学会在参数不确定的情况下也能站住。随机化的范围要合理太小没用太大策略学不到东西。奖励函数的设计是强化学习里最玄学的部分。双足平衡的奖励一般包含存活奖励活着就给分、姿态惩罚偏离直立扣分、动作平滑惩罚动作变化太剧烈扣分、能耗惩罚省电加分。权重怎么配得反复试。部署时的推理优化网络训练完要转成推理格式比如 ONNX 或者直接量化成 int8。量化能大幅降低推理时间但会损失一点精度需要重新验证。# 一个简化的策略网络结构示例 import torch import torch.nn as nn class DuckPolicy(nn.Module): def __init__(self, state_dim18, action_dim8): super().__init__() self.net nn.Sequential( nn.Linear(state_dim, 128), nn.ReLU(), nn.Linear(128, 128), nn.ReLU(), nn.Linear(128, 64), nn.ReLU(), nn.Linear(64, action_dim), nn.Tanh() # 输出限制在 [-1, 1] ) def forward(self, state): return self.net(state)这个结构很朴素但够用。Tanh 输出天然限幅省去了额外的裁剪逻辑。实际部署时我会把 action_dim 的输出再乘一个缩放系数映射到真实的关节角度范围。4. 实操过程与核心环节实现4.1 从零搭建仿真环境第一步是装 MuJoCo 和相关的 Python 绑定。MuJoCo 现在是开源的pip 就能装。装完之后你需要一个机器鸭的 MJCF 模型文件描述连杆、关节、几何、质量、惯量这些。建模的时候有几个坑我提前说关节轴向要统一别一个关节绕 X 一个绕 Y后面写控制代码会疯。碰撞体要简化用胶囊体或者球体代替复杂网格否则仿真速度会慢到没法训练。执行器要配好MuJoCo 里的 actuator 可以设成位置、速度或者力矩模式要和你的底层控制器对应。模型建好后先做一件事让机器鸭自由落体看它会不会穿模、会不会爆炸。这一步能筛掉大部分建模错误。4.2 训练策略的完整流程训练流程我拆成六步环境封装把 MuJoCo 环境包装成 Gym 接口定义 reset() 和 step()。奖励设计按前面说的四类奖励组合先给一组保守权重。并行采样用多个环境实例并行跑加速数据收集。一般开 8 到 32 个。策略更新用 PPO 或者 SACPPO 更稳SAC 样本效率更高。定期评估每隔一段训练用确定性策略跑几轮看平均存活时间。域随机化训练后期逐步加大随机化范围提升鲁棒性。训练时长取决于平台单卡的话几个小时到一天不等。判断训练是否收敛不要只看奖励曲线要看存活时间和步态质量。奖励高但步态丑的情况很常见。4.3 仿真回放与 viewer 重新播放热搜里有个词是“microduck mujoco viewer 重新播放”这个点很实用。MuJoCo 的 viewer 支持录制和回放但很多人不知道怎么重新播放已经跑过的轨迹。我的做法是在 step 的时候把状态、动作、时间戳存到一个列表里训练结束后用 viewer 的mj_viewer逐帧回放。具体来说可以写一个回放脚本加载模型然后按时间戳把 qpos 和 qvel 设回去调用viewer.sync()刷新。import mujoco import mujoco.viewer import time model mujoco.MjModel.from_xml_path(microduck.xml) data mujoco.MjData(model) # 假设 trajectory 是存好的 (qpos, qvel) 列表 with mujoco.viewer.launch_passive(model, data) as viewer: for qpos, qvel in trajectory: data.qpos[:] qpos data.qvel[:] qvel mujoco.mj_forward(model, data) viewer.sync() time.sleep(0.02) # 对应 50Hz这个回放脚本的好处是你可以慢放、暂停、逐帧看对分析步态问题特别有用。我经常用它来找“到底是哪一步开始歪的”。注意回放时不要调用 mj_step否则物理会继续演化你看到的就不是录制的轨迹了。要用 mj_forward 只更新状态不推进时间。4.4 真机部署与 50Hz 闭环落地真机部署是整个项目最容易翻车的地方。仿真到现实的差距主要体现在四个方面延迟、摩擦、噪声、执行器非线性。延迟方面真机的传感器读取、通信、推理、执行加起来往往比仿真多出十几毫秒。如果你的控制周期是 20ms这十几毫秒就是致命的。解决办法是测量真实延迟然后在仿真里也加入同样的延迟让策略提前适应。摩擦方面真机的关节摩擦比仿真大尤其是减速器。可以在仿真里加库仑摩擦和粘滞摩擦模型。噪声方面前面讲的陷波器和低通滤波就是干这个的。执行器非线性方面电机在小信号下的响应和大信号下不一样需要实测电机曲线。真机上的 50Hz 闭环我建议用一个实时循环来保证周期稳定。不要用 sleep 来凑时间sleep 的精度不够。用高精度定时器或者干脆用 RTOS。周期抖动如果超过 2ms控制效果会明显变差。环节仿真耗时真机耗时优化手段传感器读取0.1ms1-3ms用 DMA、减少总线争用状态估计0.5ms1-2ms简化滤波、定点化神经网络推理2-5ms5-15ms量化、剪枝、NPU 加速底层控制0.5ms1-2ms提高底层频率、优化代码通信与执行0.5ms2-5ms用高速总线、减少协议开销这张表是我实测的典型值你的平台可能不同但量级可以参考。核心思路是把 20ms 的预算分配清楚每个环节都要留余量。5. 常见问题与排查技巧实录5.1 机器鸭站不住、一直抖这是最常见的问题原因通常有三类。第一类是控制增益过高。神经网络的输出如果直接当位置目标底层 PID 的 P 太大就会高频振荡。解决办法是降 P或者加 D。判断方法把 P 减半如果抖动减轻就是增益问题。第二类是陷波器没调好。如果抖动频率集中在 50Hz 附近说明共振没压住。检查陷波器中心频率是否对准实测共振点Q 值是否合适。第三类是状态估计噪声太大。IMU 数据没滤波或者编码器差分噪声大都会让网络“看到”一个抖动的世界。解决办法是加低通滤波但要注意滤波会引入相位滞后。5.2 仿真能跑真机一上就趴这是 sim-to-real 的经典问题。排查顺序我建议这样先查延迟真机延迟是不是比仿真大很多如果是在仿真里加延迟重训。再查摩擦关节是不是比仿真涩手动转一下关节感受阻力。再查质量分布真机重心是不是和模型不一致称重、测重心。最后查执行器电机响应是不是和模型不符单独测电机阶跃响应。我踩过最深的坑是电池电压下降导致电机力矩不足。仿真里电机力矩恒定真机上电池一掉压力矩就软了策略直接失效。后来我在仿真里加了电压随电量下降的模型问题才解决。5.3 神经网络输出离谱动作网络在训练分布外会输出奇怪的值这是正常现象。防护措施有三层输出层用 Tanh天然限制在 [-1, 1]。输出缩放后做限幅映射到关节角度范围时再裁一次。加速度限制相邻两帧的输出变化不能超过阈值。第三层最容易被忽略但最有效。我一般把单帧角度变化限制在 5 度以内这样即使网络抽风机械也不会瞬间撞限位。5.4 常见问题速查表现象可能原因排查方法解决手段高频抖动增益过高/共振降增益看是否缓解降 P、加陷波器低频摇摆状态估计漂移看姿态角是否漂改互补滤波参数单腿无力电机/驱动问题单独测该关节换驱动、查接线起步就倒初始状态不对检查 reset 逻辑对齐初始姿态走几步就歪累积误差看 yaw 是否漂加航向修正推理超时算力不足测单帧推理时间量化、剪枝提示排查问题时一次只改一个变量。同时改三个参数你永远不知道是哪个起了作用。这是我调试多年最深刻的教训。6. 拆解资料怎么用才不浪费6.1 拆解资料的价值不在“看”在“对”热搜里提到“microduck 拆解资料”很多人拿到拆解图就是看看结构、感叹一下做工然后就放一边了。这其实浪费了拆解资料最大的价值。拆解资料真正的用法是对照自己的设计做差异分析。具体怎么做拿一张拆解图逐个部件问自己三个问题这个部件为什么用这个材料这个关节为什么用这个传动方式这个位置为什么留这个间隙然后对照自己的方案看差异在哪里差异背后的原因是什么。比如 MicroDuck 的腿部结构如果它用了某种特定的连杆布局你要想它是为了减小惯量还是为了增大工作空间还是为了走线方便想清楚这些你才能把别人的设计转化成自己的知识。6.2 从拆解反推控制参数拆解资料还能帮你反推控制参数。比如你从拆解图里量出大腿长度、小腿长度、关节到质心的距离就能算出转动惯量进而估算需要的力矩和带宽。这些参数直接喂给仿真模型能大幅提升仿真准确性。我一般会从拆解资料里提取这几类信息几何尺寸连杆长度、关节位置、质心位置质量分布各部件质量、材料密度传动比减速器型号、传动比电气参数电机型号、额定电压电流这些信息凑齐了你的仿真模型就能建得八九不离十。6.3 复现时的取舍策略完全复刻一个项目往往不现实也没必要。我的建议是抓核心、放细节。核心是什么是控制架构和闭环逻辑。50Hz 的神经控制闭环、状态估计的方式、底层控制的分层这些是灵魂必须复现。细节是什么是具体的机械尺寸、外观造型、走线方式。这些可以根据你手头的材料和加工能力调整。我见过太多人卡在“找不到一模一样的电机”上其实换个参数接近的电机重新标定一下照样能跑。工程的核心是解决问题不是复刻零件。7. 我在这个项目里踩过的坑和真实体会做双足控制这几年MicroDuck 这类项目给我的最大启发是不要迷信高频要迷信匹配。50Hz 听起来不高但它和中小型双足平台的机械带宽、算力预算、噪声特性是匹配的。我早期做过一个 500Hz 的控制回路结果因为噪声和延迟效果还不如降到 100Hz。另一个体会是陷波器要慎用。陷波器能压住特定频率的振荡但它也会引入相位滞后如果中心频率没对准反而会制造新的问题。我现在更倾向于先降增益、优化机械结构实在不行才上陷波器。还有一点关于仿真回放回放不是看热闹是找问题。我习惯把每次失败的轨迹都录下来慢放逐帧看往往能发现一些实时运行时注意不到的细节比如某一步落地时脚掌角度偏了 3 度累积几步就倒了。最后分享一个小技巧训练策略的时候先训一个“站住”的策略再训“走”的策略。不要一上来就训走路那样收敛慢还容易陷入局部最优。站住的策略作为初始化能让走路训练快很多。这个技巧我在多个项目里验证过屡试不爽。
返回列表