MicroDuck四足机器人装配与步态调试:舵机、MuJoCo与电流预算
三年里我前后装过六只 MicroDuck头两只的残骸现在还躺在零件盒里当备用件。这只机器鸭说白了就是个四足仿生小平台四条腿十二个自由度全靠舵机驱动主控跑逆运动学解算电池塞在腹部夹层。它能干的事不多——站起来、原地转圈、沿直线走、被轻推一下能自己找回平衡——但恰好是练步态控制最合适的体量比六足简单比两足不容易摔成残废坏了也好修。这篇东西是写给已经下单了套件、正对着一堆散件发愁的人看的也适合想搞明白仿真里走得挺好实物为什么一上电就抖的朋友。我会从结构件清点一路讲到 MuJoCo 里回放轨迹把舵机归中、电流预算、相位分配这些真正卡人的环节掰开揉碎说清楚。1. MicroDuck 的整体设计与选型思路1.1 这只机器鸭的骨架长什么样先把结构说清楚不然后面所有调试都是瞎猜。MicroDuck 的机身是一块主承力底板前后各延伸出一段支架四条腿对称分布在四角。每条腿三个关节髋部外展负责左右张开、髋部俯仰负责前后摆、膝关节负责抬落。三个舵机首尾串联成一条链最上面那个装在机身侧板上最下面那个直接驱动小腿。十二个舵机听起来多实际布置有个规律外展关节只在大幅度转向或者侧向抗扰时才动日常直线行走基本锁死在一个固定角度。真正高频工作的是髋俯仰和膝关节这八个。理解这一点很关键——后面算电流预算、选驱动板通道数、甚至判断为什么左边第二条腿总是最烫都要回到这个工作负载分布上。机身底板我用的是 3mm 厚 PETG 打印件关节处加密到 100% 填充主板仓位留了 25% 就够了因为那里不受力。层高 0.2mm、壁厚三圈、喷嘴 0.4mm这是打了三次才定下来的参数。第一次用 PLA 打夏天在阳台跑了一下午髋部支架直接软了变形舵机开始互相较劲最后烧了一个。PETG 耐温高一些韧性也好代价是表面拉丝多关节孔要拿 3mm 钻头手动通一遍。1.2 为什么用舵机而不是无刷电机新手最容易问的就是这个都什么年代了还用舵机我自己的答案是三点。第一舵机自带减速箱、驱动电路和位置反馈一个几十块的东西把电机编码器驱动减速全打包了对原型验证来说省掉的是整条调试链路。第二MicroDuck 这种小体量四足关节需要的峰值力矩大概在 15 到 20 kg·cm 之间速度要求不高舵机的特性曲线正好卡在这个区间。第三也是最现实的一点舵机坏了直接换一个无刷关节一旦烧驱动你得回炉重焊。具体型号我用的是 20 kg·cm 级别的金属齿数字舵机工作电压标称 4.8 到 7.2V。选金属齿是因为塑料齿在四足落地冲击下基本撑不过两百次起落我这个已经换过两轮了现在全换成金属齿之后再没断过。数字舵机比模拟舵机贵一点但死区小、响应快走起来姿态明显更干净。如果你手上有模拟舵机也能跑只是 PWM 频率得压到 50Hz不然会嗡嗡响。1.3 先仿真后实物这条路为什么更省钱我第一只鸭子是硬啃实物的结果一周烧了两个舵机、摔断三根打印腿。第二只开始改路线先在 MuJoCo 里把模型建出来把步态参数调通再照着仿真里的角度值去写实物的控制代码。这个顺序的价值在于——仿真里摔一万次不花钱实物上摔一次可能就是一小时的重装。MuJoCo 的好处是对接触和关节约束的处理比较稳算得也快普通笔记本上跑实时完全没压力。而且它有个 viewer可视化做得干净改一个参数立刻能看到腿怎么动。工作流大概是这样MJCF 里描述机身质量和惯量、关节范围和驱动方式写个简单的正弦控制器让鸭子原地踏步确认关节方向没搞反再上步态。等仿真里能走直线了把录制下来的关节角序列存成 npy 文件实物固件直接读这个序列做前馈成功率会高一大截。2. 装配前的物料清点与结构件处理2.1 BOM 清点缺件和错件最耽误时间套件到手第一件事不是拆袋是把所有东西摊开对着清单数一遍。我自己遇到过三次问题一次是舵盘少给了两个一次是 M3 螺丝长度发错给了 8mm实际需要 6mm 和 12mm 两种还有一次是电源线插头规格跟电池不匹配。这些事在装配中间才发现最要命因为那时候你已经在拧第十七颗螺丝了。清点的时候我会分四堆结构件、紧固件、电气件、线材。紧固件按长度分格放别混在一起不然拧到一半要在一堆螺丝里找 6mm 的那种烦躁感会直接摧毁你的耐心。线材这一堆要特别注意舵机延长线的数量和长度——十二条腿里靠后的几条需要更长的线短了就得接接了就有压降和接触不良的风险。物料类别关键检查项常见坑结构件关节孔是否堵料、螺孔是否滑牙打印件孔位公差漂移需要用钻头通孔紧固件M3 各长度数量、是否带垫片6mm 与 12mm 混装长度错了会顶穿舵机外壳舵机型号是否一致、齿形是否统一混批舵机中位偏差大同一条腿会互相拉扯电气件主控、驱动板、稳压模块、电池电压规格不匹配2S 电池直连舵机会超压线材延长线长度、插头规格后排舵机线不够长硬拉会拽松插头2.2 舵机归中装配前必须做完的一步这是我在第一只鸭子上栽的最大跟头。当时急着装直接把舵机按在结构件上通电才发现四个髋关节的初始角度全不一样有的腿往前撇有的往后撇软件里怎么补都补不齐最后不得不把整机拆开重来。正确做法是装配之前先用舵机测试仪或者主控输出 1500μs 脉宽让每个舵机转到中位然后在舵机还在通电保持中位的状态下把舵盘按与舵机外壳长边垂直的方向装上去。这样机械中位和电气中位就对齐了软件里的零位就是真的零位关节行程能用满。如果反过来先装后调等于把行程的余量提前吃掉十几度抬腿高度和站立高度都会被压缩。另外提醒一句归中操作最好一次性把十二个舵机全做完并且按安装位置编号贴标签。同批次舵机的中位偏差一般在 3 到 5 度以内混批的可能到 10 度以上所以尽量买同一批次的货。2.3 装配顺序和锁紧力度顺序上我的建议是先做腿再做身最后接线。每条腿单独装配完成后立刻通电测试三个关节的方向和行程确认没问题再上机身。整机装完再发现有腿装反拆解成本是单腿测试的十倍。锁紧力度这块有个具体经验值M3 自攻螺丝拧进 PETG 打印件扭矩控制在 0.3 到 0.4 N·m 之间就够了手感上大概是拧到明显受阻后再拧四分之一圈。拧过头会直接滑牙滑牙之后只能换大一号螺丝或者灌胶非常麻烦。我现在的做法是先用手拧到贴合再用小扭矩电动螺丝刀点一下最后用手指晃一晃关节座能感觉到轻微刚性但又不晃就是对的。舵盘的螺丝也要留意一定要上螺纹胶。四足行走时的持续振动会让舵盘螺丝慢慢退出来我有一只鸭子在跑了大概半小时后左前腿突然失控拆开一看舵盘螺丝已经掉了。3. 电气系统与控制链路落地3.1 电源方案与电流预算怎么算电气这块是新手翻车率最高的地方核心就一个问题电压对不上电流不够用。先看舵机的标称工作电压是 4.8 到 7.2V而 2S 锂电满电是 8.4V直接接上去属于超压运行短时间可能没事长时间会加速碳刷磨损甚至烧驱动。所以必须加一级降压。方案上我推荐 2S 锂电配 6V/5A 的 UBEC 给舵机供电主控单独走一路 5V 输出。为什么不把舵机和主控共用一路 5V因为舵机启停时电流突变很剧烈会把 5V 拉出明显跌落主控一旦跌到复位阈值以下就重启了表现出来就是走着走着自己复位站住很容易误判成程序 bug。电流预算我算过一遍贴出来供参考。单个舵机空载保持电流约 100mA正常行走时 400 到 700mA堵转可以到 2.5A。按对角步态估算任一时刻六条腿承重发力、六条腿摆动轻载承重腿按 600mA、摆动腿按 200mA 计总电流约为 6×0.6 6×0.2 4.8A再留 30% 余量就是 6.2A。所以 UBEC 选 5A 是底线能上 8A 更稳。电池方面2S 1300mAh 30C 的放电能力是 39A远远够用不用为了电流去堆大容量。续航折算一下平均工作电流按 4A 算1300mAh 理论能撑约 0.32 小时也就是 19 分钟。实际因为行走是断续的、间歇还有静止姿态实测能到 25 分钟左右。线材记得用 20AWG 以上接头用 XT30普通杜邦线走 5A 会发热发软。3.2 驱动板、主控与接线要点十二个舵机不可能全挂主控的 GPIO一是引脚不够二是主控定时器资源会被吃光。常规做法是主控加一块 16 路 PWM 驱动板走 I2C 通信主控只负责算角度、发目标值脉宽生成交给驱动板。接线有三条纪律。第一条驱动板的供电和主控的供电必须分开走线只在一点共地不要在主控板上把两路电源直接并起来。第二条舵机插头方向不要凭感觉驱动板一排是信号、一排是正、一排是负插反了通电就是一瞬间的事我烧过一块现在插之前一定对着丝印再看一遍。第三条线束要扎带固定留出关节活动余量但不要让线在关节处反复弯折那种地方的线两个月内必断芯。PWM 频率这块有个细节值得说数字舵机可以吃 300Hz 以上的刷新率抖动会明显变小模拟舵机只能 50Hz。如果你发现静止时腿在轻微高频抖动先把频率调高试试很多时候不是机械问题。3.3 固件烧录与第一次上电第一次上电我强烈建议不要接腿把十二个舵机全部脱开只留电气连接先验证三件事主控能被识别、驱动板 I2C 能扫到地址、角度指令能让舵机动。固件结构上我会把代码分成三层最底层是舵机角度转脉宽的输出层中间是逆运动学解算层最上面是步态生成层。这样分层的好处是调试的时候可以把步态层停掉直接手动给单腿发目标点看着它抬起来落下去确认正负号和角度范围。# 逆运动学单腿解算示意参数需按你的连杆长度替换 import math L1 0.045 # 大腿长度 m L2 0.075 # 小腿长度 m def leg_ik(x, y, z, hip_offset0.02): # 髋外展角 theta_abd math.atan2(y, z) r math.hypot(y, z) # 髋俯仰 膝关节余弦定理 d math.hypot(x, r - hip_offset) d min(d, L1 L2 - 1e-6) cos_knee (L1**2 L2**2 - d**2) / (2 * L1 * L2) theta_knee math.pi - math.acos(cos_knee) cos_hip (L1**2 d**2 - L2**2) / (2 * L1 * d) theta_hip math.atan2(x, r - hip_offset) math.acos(cos_hip) return theta_abd, theta_hip, theta_knee这段代码是骨架实际用之前一定要先验证符号方向给一个正的 x看腿是不是往前迈。方向搞反是新手最常犯的错而且很难从现象上判断——因为鸭子在原地抽搐的样子看起来像是力矩不够其实完全是符号问题。4. 步态调试从站不稳到走得直4.1 站立姿态与重心标定步态之前先要站稳。站立姿态的确定有个流程先把足端目标点设为在机身正下方、离地高度刚好让小腿垂直的位置四条腿对称设置通电看看是不是平站。如果某条腿悬空或者顶地说明那条腿的机械中位偏了要么在软件里给一个补偿角要么回去重新归中——我建议后者软件补偿会吃掉行程。重心标定我用的方法比较土但好用让鸭子站住用手指从侧面轻轻推机身看它往哪边倒得更快。重心投影应该落在四个足端构成的支撑多边形中心附近偏了就调整电池位置。MicroDuck 的电池仓一般放在腹部前后可以挪 10mm 左右这 10mm 对稳定性的影响比你想象的大。站立高度还决定了一个容易被忽略的参数——关节的力矩臂。站得越高腿越接近伸直膝角接近 180 度这时候力臂最短需要舵机输出更大的力矩才能维持。我实测下来把站立高度从 70mm 降到 60mm舵机工作温度明显下降走起来也稳一些。代价是抬腿空间变小步幅得跟着收。4.2 对角步态与四拍行走的取舍四足步态里常用的两种一种是四拍行走一种是两拍的对角小跑。四拍行走每次只抬一条腿剩下三条腿着地三个着地点构成一个三角形支撑面所以也叫三角步态。它的好处是稳重心投影始终在支撑三角形内部就算参数调得糙一点也不容易摔。坏处是慢而且四条腿轮流抬落机身会有明显的周期性摇摆。对角小跑是两条对角腿同时抬起、另两条同时着地周期短、速度快、看起来更利索。代价是支撑面缩小成一条对角线稳定性全靠惯量和控制频率撑着。我的建议是新手先用四拍行走把整条链路跑通能稳定走直线之后再切对角小跑。相位分配是这两种步态的核心区别。假设腿的顺序是左前、左后、右前、右后四拍行走的相位分别设为 0.0、0.5、0.75、0.25每条腿的支撑相占空比设 0.75对角小跑则是左前与右后同相位 0.0左后与右前同相位 0.5支撑相占空比设 0.5。参数表我整理在这儿可以直接抄参数四拍行走对角小跑支撑相占空比0.750.5步态周期0.8 - 1.2 s0.4 - 0.6 s抬腿高度15 - 25 mm20 - 30 mm步幅60 - 90 mm70 - 100 mm相位序列0 / 0.5 / 0.75 / 0.250 / 0.5 / 0.5 / 0摆动相曲线我用的是简单的正弦抬腿加线性前移。摆动相里足端在垂直方向按正弦抬升再落回水平方向从后极限位置线性推到前极限位置。支撑相则相反足端相对机身从前往后线性移动移动速度必须和期望行走速度匹配否则会看到脚在地上打滑。算个具体数四拍行走步幅取 80mm周期 1.0s支撑相 0.75s那么支撑相足端相对机身的速度就是 80 / 0.75 ≈ 107 mm/s。这个速度就是理论前进速度考虑打滑和实际效率机身实际速度大概在 70 到 85 mm/s 之间。跑一米的直线大概要十二三秒慢是慢但走得稳。4.3 在 MuJoCo 里预演与回放轨迹仿真环境我建议认真搭一次回报很高。MJCF 文件里要写清楚每个连杆的质量和惯量——惯量别偷懒用默认球体近似四足对惯量很敏感近似太粗会导致仿真里稳、实物上抖。驱动方式用 position 型执行器指定 kp 和 kv这两个参数直接决定关节的软硬。actuator position namelf_hip_pitch jointlf_hip_pitch_j kp60 kv2.0 ctrlrange-0.9 0.9/ /actuator调这两个参数的顺序是先调 kp 到关节能跟上指令再调 kv 抑制过冲。kp 太小腿会软绵绵跟不上太大则会在落地瞬间剧烈振荡。我最后定在 kp60、kv2.0 附近这个值跟实物舵机的响应特性大致对得上。仿真里最有价值的用法是轨迹录制与重新播放。一边调步态一边录下每一帧的关节角存成文件回头反复看哪一帧开始歪的比肉眼盯着看高效得多。回放的时候还能降速播放把 0.1 秒的动作放成 2 秒问题帧一眼就能揪出来。import time import numpy as np import mujoco import mujoco.viewer model mujoco.MjModel.from_xml_path(microduck.xml) data mujoco.MjData(model) # 第一步录制一段步态轨迹 frames [] mujoco.mj_resetData(model, data) for step in range(2000): phase (step * model.opt.timestep) % 1.0 data.ctrl[:] gait_controller(phase) # 你自己的步态函数 mujoco.mj_step(model, data) frames.append(data.qpos.copy()) np.save(gait_trace.npy, frames)import time import numpy as np import mujoco import mujoco.viewer model mujoco.MjModel.from_xml_path(microduck.xml) data mujoco.MjData(model) frames np.load(gait_trace.npy) # 第二步降速重新播放方便逐帧观察 scale 0.2 # 0.2 倍速 with mujoco.viewer.launch_passive(model, data) as viewer: for q in frames: data.qpos[:] q mujoco.mj_forward(model, data) viewer.sync() time.sleep(model.opt.timestep / scale)回放这段有个坑要说直接改 qpos 是运动学回放物理求解被绕过了所以你看到的姿态是纯几何正确的但看不到接触力和打滑。如果想看动力学表现得存 ctrl 序列然后重跑仿真那样慢一些但更真实。两种方式我都在用看姿态用前者查摔倒原因用后者。另外 viewer 里按键可以暂停暂停之后单步推进对定位某一帧的碰撞很有用。5. 常见故障排查与避坑经验5.1 抖动、发热、走偏的排查路径上电之后最容易出现的三类问题我按排查优先级整理成表。这个表是我自己踩了一圈之后总结的顺序很重要——先查电再查机械最后才动参数。很多人一看到抖就改 PID改了一天发现是电源掉压纯属浪费生命。现象优先排查方向具体方法处理静止时高频抖动供电噪声 / PWM 频率万用表看 6V 轨纹波示波器看脉宽加大电容数字舵机提到 300Hz某条腿持续发热机械卡涩 / 舵机互相拉扯断电手动推关节感受阻力检查同轴对齐重新归中行走时走偏机械零位不对称四条腿对称位置比高度重新归中软件补偿控制在 2 度内走一会儿突然复位主控供电跌落主控 5V 上挂示波器看跌落舵机与主控电源彻底分开落地瞬间关节异响齿损 / 螺盘松动拆开看齿面晃舵盘换金属齿舵盘螺丝上胶仿真稳实物抖惯量近似误差 / 关节柔度对比仿真与实测的落地曲线细化惯量kp 适当下调发热这一项要多说一句。舵机在保持位置时如果一直有较大电流说明它一直在对抗某个东西最常见的就是同一条腿的两个舵机在互相拉扯——比如髋俯仰和膝关节的目标角组合起来让足端位置矛盾了。这种时候舵机表面温度十分钟内就能到烫手的程度。我的判断标准是正常工作温度应该只是温热摸着明显烫手就一定是机械或者解算有问题。5.2 几条踩坑换来的一手经验第一条别在第一次装配时就上螺纹胶和扎带。调试阶段你会拆装很多次每拆一次都要剪扎带、清胶效率极低。等步态跑稳了再统一做最终固定。这个顺序调整让我第三只鸭子的调试时间缩短了一半。第二条电池电压监测要接。我早期没接结果鸭子走着走着突然软腿坐下查了半天以为是控制问题其实是电池放到 6.4V 以下UBEC 掉出稳压范围舵机集体没劲。加一个简单的分压采样进 ADC在固件里设个阈值报警能省掉大量误判。第三条足端加一层软胶。硬塑料足端在光滑地板上会打滑尤其是四拍行走只有三条腿着地的时候打滑会直接破坏支撑三角形的假设。我在足底贴了一层 1mm 的硅胶垫抓地力提升很明显代价是磨损快大概跑二十小时要换一次。第四条先跑直线再跑转向。转向涉及外展关节的参与和四足协调参数耦合比直线复杂得多。很多人一开始就想让鸭子画个圈结果调了两天连站都站不稳。我的做法是拿胶带在地上贴一条三米直线反复走走到能重复走同一条线不偏出 5cm再去碰转向。第五条仿真里的轨迹文件记得带时间戳一起存。我一开始只存 qpos后来发现不同版本的模型参数对不上回放出来的姿态全是错的。现在每次录制都把模型文件哈希和步态参数写进文件名回头查起来一目了然。最后再提一个我认为最容易被忽视的点给舵机留余量。不管是行程余量还是力矩余量都别用到极限。我现在的做法是关节角度只用到舵机标称行程的 80%抬腿高度只用到连杆能达到的最大值的 70%。这些余量在平地行走时看不出价值但一旦遇到地毯、门槛、被踢一脚的意外情况余量就是鸭子能不能自己找回平衡的分界线。装到第六只我才真正明白MicroDuck 这种小平台稳定性不是靠控制器算得多聪明而是靠一开始就别把自己逼到极限。