上一节:第 6 章 BusLinker舵机控制器开发 从20Hz到100Hz,串口通信的血泪史
第二部分:串口舵机——从协议到实战
第 7 章 舵机控制的高级话题 速度曲线、扭矩管理、通信可靠性、寿命维护——那些规格书不会告诉你的真相
前两章讲了怎么让舵机动起来、怎么搭一个100Hz的控制器。但如果你以为「能控制舵机」就等于「能用好舵机」,那你还差得远。这一章不讲协议,不讲代码框架,讲的是我在实际使用中碰到的那些「阴暗面」——速度曲线怎么选、堵转怎么保护、指令丢了怎么办、舵机用久了会怎样。以下内容全部来自实测,希望能帮你少走弯路。
7.1 舵机速度与加速度控制
7.1.1 move_time:一个被低估的参数
move_time是舵机协议中最重要的参数没有之一。它告诉舵机:从当前位置转到目标位置,需要花多少毫秒。这个参数同时影响速度和加速度。
我第一次测试时,把move_time设成0ms——心想「越快越好嘛」。结果舵机像打了鸡血一样,发出刺耳的啸叫声执行命令,整个人像个格斗选手一样。因为move_time=0意味着舵机以最大功率加速,到达目标位置后急停,惯性导致机械系统产生振荡。
然后我试了1000ms——确实不抖了,但问题变成了滞后:你发指令让它抬腿,它慢悠悠地抬,等你指令让它落脚了,它腿还没抬到位。在100Hz的控制循环中,舵机永远追不上目标位置。
经过反复测试,我们最终把move_time定在8ms。这个数字不是拍脑袋决定的,而是基于100Hz控制循环的精确计算。
7.1.2 8ms的设计逻辑
100Hz控制频率意味着每10ms发一次指令。如果move_time等于控制周期,可能出现的情况是:舵机还没完成上次运动,新指令就到了,导致运动不连续,微观上表现为「一顿一顿」的微抖动。
所以我们需要move_time略小于控制周期。8ms是一个经过验证的值:舵机在10ms内完成运动,剩余2ms留给串口传输和舵机内部处理。核心原则:move_time应该略小于控制周期,给通信和计算留出余量。
move_time的选择原则:
move_time = 控制周期 - 2ms。
对于100Hz(10ms周期),move_time = 8ms;
对于50Hz(20ms周期),move_time = 16ms。
不要设0ms(会抖动),不要超过控制周期(会滞后)。
7.1.3 梯形速度 vs S曲线:为什么我们选梯形
舵机内部的速度曲线有两种:梯形速度曲线(加速-匀速-减速)和S曲线(平滑加速)。梯形速度计算简单,舵机MCU处理快;缺点是加速和减速阶段有「拐点」——加速度突变,产生微小冲击。S曲线运动极其平滑,但计算复杂,对MCU算力要求高。
HTD-45H舵机内部使用的是梯形速度曲线。因为它的MCU性能有限,S曲线计算量太大。而且梯形速度的拐点冲击在机械系统里被齿轮间隙和结构件柔性吸收掉了,实际表现并不差。示波器抓取的位置响应曲线显示,梯形速度在拐点处有约0.3°的超调,但50ms内就收敛了。对118元一个的舵机来说,梯形速度是务实的选择。
7.1.4 速度限制:316°/s从哪来
HTD-45H的规格书说:转速0.18 sec/60°。换算:60° / 0.18s = 333°/s(空载最大转速)。但实际负载条件下,舵机能达到的最大转速约316°/s。我们在行走步态规划中,每一步的角度变化都限制在316°/s以内,确保舵机始终能跟上指令。超过这个速度,控制器以为舵机转到了目标角度,实际它没到,累积误差越来越大,最终机器人失去平衡。
| 参数 | 空载值 | 负载实测值 | 说明 |
|---|---|---|---|
| 最大转速 | 333°/s | 316°/s | 负载下约95%空载性能 |
| move_time | 0ms(不可用) | 8ms | 100Hz控制周期下的最优值 |
| 加速度 | 瞬时 | 梯形曲线 | 舵机内置梯形速度 |
| 位置超调 | 0.2° | 0.3° | 梯形拐点处的微小超调 |
| 收敛时间 | N/A | <50ms | 超调后50ms内收敛 |
7.1.5 梯形速度曲线的数学实现
虽然舵机内部已经实现了梯形速度,但理解它的数学原理对你调试运动参数很有帮助。梯形速度曲线分为三个阶段:加速段(加速度恒定)、匀速段(速度恒定)、减速段(减速度恒定)。三个阶段的持续时间由目标角度差和move_time共同决定。
以下是在控制层实现梯形速度规划的代码——不是给舵机执行的,而是用于上层轨迹规划,确保每次发给舵机的角度增量在速度限制以内:
deftrapezoidal_step(current,target,max_vel,dt):"""单步梯形速度规划 current: 当前角度 (deg) target: 目标角度 (deg) max_vel: 最大速度 (deg/s), HTD-45H=316 dt: 控制周期 (s), 10ms=0.01 returns: 下一步角度 (deg) """error=target-current max_step=max_vel*dt# 单步最大角度变化ifabs(error)<max_step:returntarget# 足够近, 直接到位else:# 限制在最大速度内returncurrent+math.copysign(max_step,error)这个函数特别简单,但极其有效。它确保了每次发给舵机的角度增量不会超过316°/s * 0.01s = 3.16°。对于大角度运动(比如从站立到迈步需要转动30°),经过约10个控制周期(100ms)就能到达目标,舵机完全跟得上。
你也可以在这个基础上实现更精细的S曲线。S曲线的核心思想是让加速度本身也平滑变化——用加加速度(jerk)来限制加速度的变化率。但说实话,对于HTD-45H这种舵机,S曲线的效果提升微乎其微,因为它的齿轮间隙和机械柔性已经起到了天然的“平滑器”作用。
这里有一个我在调试时学到的经验:如果你发现舵机在拐点处有微小的“咯噔”声,那不是梯形速度的问题,而是齿轮间隙造成的。减小move_time不会消除这个声音,反而会让它更明显。正确的做法是检查齿轮间隙是否过大(超过0.15mm就需要更换),或者给关键帧之间增加过渡时间。
7.2 舵机负载与扭矩管理
45kg·cm的扭矩听起来很大,但在实际使用中你会发现:有时候够用,有时候不够。关键是理解在什么情况下不够,以及如何保护舵机不被烧毁。
7.2.1 45kg·cm在实际中的表现
45kg·cm意味着舵机在1cm力臂处能输出45kg的力,在10cm力臂处能输出4.5kg的力。我们的机器人腿长约30cm,髋关节能输出的力是:45kg·cm / 30cm = 1.5kg。机器人总重约3kg,两条腿各承担1.5kg——刚好够。但这是静态站立的情况。
走路时,一条腿支撑全身重量,另一条腿抬起来。支撑腿的髋关节要承受3kg的力,而我们刚算出来髋关节只能输出1.5kg——问题来了。实际上45kg·cm是堵转扭矩,运动扭矩通常小于堵转扭矩,但动态条件下舵机还需要克服惯性力。走路时髋关节的负载峰值接近额定扭矩的90%,是系统的瓶颈。
7.2.2 堵转检测:电流3A与温度70°C
舵机堵转是最危险的情况之一。堵转时,电机通电但不转,所有电能都转化为热量。HTD-45H的堵转电流约3A,堵转时功率约33W(11.1V x 3A)。我们实测,堵转10秒后舵机外壳温度从室温升到60°C,20秒后超过80°C。
我们的保护策略是双重阈值:电流3A是瞬态保护(堵转几秒内触发,将舵机目标位置设为当前位置让它停止运动),温度70°C是累积保护(长期高负载触发,所有舵机归到中位「躺平」降温)。
在实际代码中,我们并没有实时监控这些值。因为读位置指令会阻塞舵机约80-100ms,我们在平衡控制循环之外单独开一个线程做低频巡检(每5秒读一次)。
堵转保护的核心代码逻辑(简化版):
ifservo.current>3000:# mAservo.target=servo.current_position# 停止运动log_warning('Servo %d stalled!'%servo.id)ifservo.temperature>70:forsinall_servos:s.target=500# 归中位log_error('Overheat! All servos to neutral.')7.2.3 重力补偿:各关节的负载分析
不同姿态下,各关节承受的负载差异巨大。站立时,受力最大的关节是髋关节前后(hip_pitch),承受整个上半身的重量,力臂是躯干高度,电流约1.2A。膝关节(knee)在腿伸直时力臂短,电流约0.8A;一旦膝盖弯曲,力臂变长,电流会迅速上升到1.5A以上。踝关节前后(ankle_pitch)受力最小约0.3A,但精度要求最高。
最危险的情况是机器人后仰——身体向后倒,髋关节要往前拉才能恢复。但髋关节本身已经承受了大部分体重,再加上紧急恢复的力矩,很容易超过额定扭矩。这也是为什么我们在ZMP控制器里限制了最大踝关节角度(12°)和最大躯干倾斜角。
| 关节 | 静态站立电流 | 走路峰值电流 | 堵转风险 | 说明 |
|---|---|---|---|---|
| 髋关节前后 (hip_pitch) | 1.2A | 2.5A | 高 | 承受上半身重量,力臂最长 |
| 膝关节 (knee) | 0.8A | 1.8A | 中 | 弯曲时力臂变长,负载激增 |
| 踝关节前后 (ankle_pitch) | 0.3A | 0.8A | 低 | 受力小,但精度要求高 |
| 髋关节侧向 (hip_roll) | 0.5A | 1.2A | 中 | 侧向平衡时负载增加 |
| 踝关节侧向 (ankle_roll) | 0.4A | 0.9A | 低 | 侧向调整,负载较小 |
| 腰部 (torso) | 0.6A | 1.0A | 低 | 后仰补偿时负载增加 |
7.2.4 髋关节保护策略
既然髋关节是最容易堵转的关节,我们专门做了四层保护:第一层——角度限制(髋关节前后方向最大运动范围±30°);第二层——速度限制(髋关节角速度限制在200°/s,比其它关节的316°/s更保守);第三层——恢复跨步(倾斜超过阈值时不硬拉,而是迈一步用重力恢复平衡);第四层——紧急停机(如果以上三层都失效了,检测到髋关节电流超过3A持续2秒以上,立即停止所有舵机指令,让机器人自然倒下)。
摔坏3D打印结构件只要几块钱,电机坏了118块,很容易算清楚。
7.3 舵机通信的可靠性
串口总线舵机最大的优势是接线简单,但最大的劣势是通信可靠性。一根线串起21个舵机,任何一个节点出问题都可能影响整条总线。
7.3.1 校验和:不是万能的
每条指令末尾都有一个校验和字节,算法是取反求和。校验和只能检测到「数据变了」,不能纠正。理论上,通信错误导致校验和「恰好正确」的概率是1/256,约0.4%。
在实际使用中,出错的常见原因:电磁干扰(舵机大电流启停时产生电磁干扰,如果信号线和电源线绑在一起走,干扰会耦合到信号线上,偶尔导致位错误);长线缆(从嵌入式主板到脚踝舵机约80cm,TTL电平3.3V在长线缆上衰减严重);接插件松动(PH2.0接插件反复插拔后接触电阻增大,导致信号质量下降)。
7.3.2 没有ACK机制:指令丢了怎么办
串口总线舵机协议有一个致命缺陷:没有ACK(确认)机制。你发一条指令,舵机不回确认。你不知道它收到了没有,也不知道它执行了没有。
那在100Hz的控制循环中,指令丢了怎么办?答案是:不做特殊处理,靠高频发送来覆盖。因为100Hz意味着每10ms发一次指令,如果某条指令丢了,10ms后下一条指令到达,舵机继续运动。对于平衡控制来说,10ms的延迟是可接受的。
所以问题的关键不是「指令丢了怎么办」,而是「如何保证丢帧率足够低」。这也是为什么乐宝机器人便宜的地方,但是随之而来的就是可靠性会低,不过对于我们用来验证整体框架逻辑也够了。
7.3.3 串口错误处理
UART通信有几种常见的错误类型:帧错误(Framing Error)由波特率不匹配或信号质量差导致,舵机端检测到后会丢弃当前帧等待下一个帧头;溢出错误(Overrun Error)发生在接收缓冲区满时,我们不在100Hz循环中回读数据,只在低频巡检时才读;奇偶校验错误(Parity Error)我们没开奇偶校验,所以不存在这个问题。
在python-pyserial中,可以通过设置超时和错误回调来处理这些异常。但在我们的buslinker控制器中,由于性能要求,我们选择了最简单的方案:不检测错误,依赖高频发送和校验和来覆盖。
7.3.4 100Hz下的丢帧率实测
我专门做过一次测试:用逻辑分析仪抓取总线波形,统计发送的指令数和舵机实际执行的指令数。在正常运行条件下(无外部干扰、线缆长度<50cm、接插件牢固),发送指令10000条,舵机执行9991条,丢帧9条,丢帧率0.09%。
这个0.09%的丢帧率在平衡控制中基本没有影响。但如果你发现丢帧率明显高于0.5%,就需要排查了:
- 检查接插件是否松动(最常见原因);
- 缩短线缆长度;
- 检查电源是否干净,舵机电源加滤波电容(1000uF电解电容并联0.1uF陶瓷电容);
- 不要降低波特率,降低波特率只会让问题更糟,因为每帧传输时间变长,更容易被干扰。
7.4 舵机寿命与维护
舵机是消耗品。不管你多爱惜,它总会磨损。关键是了解磨损的规律,提前做好维护方案。
7.4.1 金属齿轮的磨损
HTD-45H用的是全金属齿轮(铜齿轮+钢齿轮)。我们使用的3个月后,拆开检查了负载最重的髋关节舵机。发现齿轮间隙从出厂时的约0.05mm增加到约0.15mm。这个间隙变化导致两个后果:位置精度下降(空行程从0.2°增加到约0.6°,对平衡控制有影响),回差导致控制振荡(在PD控制中,舵机在齿轮间隙区间来回摆动,无法精确停在目标位置,表现为微小的「嗡嗡」振动)。
齿轮磨损的速度取决于负载。髋关节磨损最快,踝关节磨损最慢。我们建议:每3个月更换一次髋关节舵机,每6个月更换一次膝关节舵机,踝关节和手臂舵机可以撑到一年。
顺便说一下,舵机的螺丝安装孔,也会因为经常运动,或者关节来回拆装,导致螺丝孔会变大,或者安装的时候,直接螺丝顶歪了,把孔给撑大了。
7.4.2 舵机更换:快速替换流程
换一个舵机听起来简单,但如果你不按流程来,可能会引发连锁问题。正确流程:
- 断电。别带电操作——串口总线上的舵机带电插拔可能会损坏通信芯片。
- 拆下旧舵机,记下它的ID。
- 把新舵机单独接上串口主板,用厂家自带的软件改ID为旧舵机的ID。
- 把新舵机装到机器人上,通电测试。
- 确认方向。用guanjieceshi工具确认方向,如果方向反了,在代码中翻转(不要改舵机硬件)。
- 运行关节标定(第8章会详细讲),确认新舵机的零位和运动范围。
最常见的一个错误是:新舵机忘了改ID,直接插上总线。如果新舵机出厂ID=1,而整个系统没有ID=1的舵机,然后就是这个关节永远不动。
另一个容易忽略的点:新舵机的机械安装角度可能和旧舵机有差异。即使ID和方向一致,同样的目标角度下,新舵机的实际位置可能偏了1-2°。必须重新标定,这个一般厂家的软件会有标定的功能,这里就跳过了。
7.4.3 舵机故障的常见症状
根据我们的使用经验,舵机故障通常有以下几种表现:
抖动: 舵机在目标位置附近来回摆动,无法稳定。通常是齿轮磨损导致间隙过大,或是电位器接触不良。齿轮是焊接在舵机内部的,无法单独更换,只能换舵机。
异响: 舵机运动时发出「咔咔」声或刺耳的啸叫声。可能是齿轮有异物、轴承缺油、或者齿轮齿崩了。先尝试加润滑脂,如果无效则换舵机。但是一般可以听得出来是机械故障,还是操作故障,如果是后者通常还是在程序上找找问题。
不响应: 舵机完全不运动。首先检查供电和信号线,如果供电正常,用厂商的软件发指令看是否有响应。如果完全没有响应,可能是通信芯片烧了,通常是因为带电插拔。
位置漂移: 舵机在不受控的情况下自己慢慢转动。这是最诡异的问题——你发指令让它停在120°,它自己慢慢转到了125°。原因是电位器老化,输出信号漂移,MCU以为「当前位置」变了,于是驱动电机去纠正。解决方法是换舵机,电位器无法维修。
| 故障症状 | 可能原因 | 严重程度 | 处理方法 |
|---|---|---|---|
| 抖动 | 齿轮磨损/电位器故障 | 中 | 换舵机 |
| 异响(咔咔) | 齿轮异物/缺油 | 中 | 加润滑脂,无效则换 |
| 异响(啸叫) | 轴承磨损/齿轮崩齿 | 高 | 换舵机 |
| 不响应 | 通信芯片烧坏/供电问题 | 高 | 检查供电,换舵机 |
| 位置漂移 | 电位器老化 | 高 | 换舵机 |
| 温度过高 | 堵转/长时间高负载 | 高 | 检查机械限位,增加散热 |
7.5 避坑清单
避坑清单: 1. move_time不要设0ms——舵机会像打了鸡血一样抖动甚至啸叫。正确做法是设为控制周期减2ms,100Hz下用8ms。 说明:0ms让舵机以最大功率加速急停,惯性导致机械振荡。 2. move_time不要超过控制周期——舵机永远追不上目标位置,控制效果大打折扣。 说明:滞后会让控制器以为舵机到位了,实际没有,累积误差越来越大。 3. 不要忽略舵机的速度限制——HTD-45H负载下最大316°/s,超过这个速度舵机跟不上,累积误差导致失衡。 说明:316°/s是从空载333°/s经实测反推的负载最大速度。 4. 髋关节是系统瓶颈——站立时承受全身重量,走路时负载峰值接近额定扭矩90%。必须加多层次保护(角度限制、速度限制、恢复跨步、紧急停机)。 说明:摔坏3D打印结构件只要几块钱,电机坏了118块,很容易算清楚。 5. 堵转保护不能只靠温度——温度上升有延迟,等检测到70°C时舵机可能已经烧了。必须同时监控电流(3A阈值)。 说明:双重阈值——电流3A是瞬态保护,温度70°C是累积保护。 6. 不要在100Hz循环中读舵机位置——读位置会阻塞舵机80-100ms,控制频率骤降到10Hz。开独立线程做低频巡检(每5秒一次)。 说明:这是第6章「只写不读」原则的延伸。 7. 接插件松动是通信故障的元凶——PH2.0接插件反复插拔后接触电阻增大,导致信号质量下降。建议定期检查,必要时更换。 说明:我们遇到过最诡异的问题:机器人自己会动,查了一整天发现是接插件接触不良。 8. 信号线不要和电源线绑在一起走——舵机大电流启停时产生的电磁干扰会耦合到信号线上。信号线和电源线至少间隔5cm。 说明:电磁干扰会让串口信号产生50-100mV噪声,偶尔导致位错误。 9. 换舵机必须断电——带电插拔会烧通信芯片。换完后必须重新标定(ID、方向、零位、运动范围)。 说明:新舵机出厂ID默认=1,不先改ID直接插上总线,这个关节永远不动。 10. 齿轮磨损是不可避免的——每3个月更换髋关节舵机,每6个月更换膝关节舵机。螺丝孔也会被撑大,预留备件预算。 说明:舵机是消耗品,提前买好备件,别等坏了再买。