← reports index
硬件事件 · 2026-09-08 凌晨

左臂肩抬舵机烧到 61°C —— 以及一个被推翻的"它坏了"

一次无人看管的远程遥操作把左臂开到伸展姿势后一直撑着,那一颗关节升到 61°C,温度守卫在极限处停机。之后它一动就让总线丢包,我据此判定「舵机劣化,该换」,并且已经写好了向主办方要备件的话。操作者一句「你应该做一个梯度测试才行呀」把这个结论推翻了——凉透之后它扛得住的负载比两个健康邻居还高。这一页记录数据、误判、和推翻它的那条曲线。

结论:舵机没坏,是过热降额,凉透后完全恢复。 真正的问题是那条把它烤到 61°C 的链 —— 长时间保持伸展姿势、无人看管、软件里没有任何刹车 —— 已经修好。

一、事件

那次会话 6889 拍里 6821 拍(99%)是 "holding position":手臂被开到一个伸展姿势之后就一直扛在那儿,没有任何东西让它退出来。承重最大的 shoulder_lift 一路升到 61°C。

[thermal] STOP: left shoulder_lift at 61C (limit 60C, confirmed twice)
left shoulder_lift reached 61C — stopping before the servo drops torque
on its own and the arm falls.

最后那句是守卫存在的意义:抢在舵机自己过热卸力矩之前停机。等舵机自保护,力矩会突然消失,手臂直接掉下去。

本次会话峰值shoulder_lift同臂其余五颗
左臂61°C34–43°C
右臂36°C34–42°C

只有那一颗。这排除了环境温度和整臂负载。

二、不是硬件天生有别

把两条臂都停在 home、静置对照(负载和电压是当晚新加进温度守卫的记录,总线流量一点没增加):

left  shoulder_lift  37°C / load 224 / 12.1V
right shoulder_lift  36°C / load 216 / 12.0V

同姿势下差 1°C。 所以 61°C 是姿势 + 无人看管造成的,不是左臂天生更热。

三、误判:我说它劣化了

61°C 之后约半小时,驱动它 2.6° 会产生 15/23/33 次总线通信失败,而同一条总线上负载更高的邻居一次都没有。我当时有三个点:

动作峰值负载通信失败
只上力矩、不动00
动 1.3°1170
动 2.6°(热态)184–21815 / 23 / 33

据此我给出「阈值约 150,超过就崩,判定劣化」。那个 150 是在两个点之间插出来的,不是测出来的。

四、梯度扫描推翻了它

ID2 shoulder_lift(当晚过热那颗) ID3 / ID4 健康对照(同总线、同供电、同线缆)
幅度 5 counts (0.4°) · 峰值负载 36 · 失败 0幅度 10 counts (0.9°) · 峰值负载 77 · 失败 0幅度 15 counts (1.3°) · 峰值负载 120 · 失败 0幅度 20 counts (1.8°) · 峰值负载 148 · 失败 0幅度 25 counts (2.2°) · 峰值负载 171 · 失败 0幅度 30 counts (2.6°) · 峰值负载 207 · 失败 0幅度 40 counts (3.5°) · 峰值负载 223 · 失败 0幅度 5 counts (0.4°) · 峰值负载 37 · 失败 0幅度 10 counts (0.9°) · 峰值负载 81 · 失败 0幅度 15 counts (1.3°) · 峰值负载 116 · 失败 0幅度 20 counts (1.8°) · 峰值负载 143 · 失败 0幅度 25 counts (2.2°) · 峰值负载 164 · 失败 0幅度 30 counts (2.6°) · 峰值负载 188 · 失败 0幅度 40 counts (3.5°) · 峰值负载 220 · 失败 0幅度 5 counts (0.4°) · 峰值负载 32 · 失败 0幅度 10 counts (0.9°) · 峰值负载 78 · 失败 0幅度 15 counts (1.3°) · 峰值负载 149 · 失败 0幅度 20 counts (1.8°) · 峰值负载 195 · 失败 0幅度 25 counts (2.2°) · 峰值负载 239 · 失败 0幅度 30 counts (2.6°) · 峰值负载 255 · 失败 0幅度 40 counts (3.5°) · 峰值负载 291 · 失败 0 ID2 291 ID3 223 ID4 220 010020030051015202530400.4°0.9°1.3°1.8°2.2°2.6°3.5° 峰值负载 动作幅度(counts / 角度)
凉透之后逐级加大动作幅度。三条曲线全程零通信失败,所以图上画的是各自的峰值负载——ID2 反而是最高的那条。生成:servo_load_probe.py --sweep
幅度角度ID2 失败/负载ID3 失败/负载ID4 失败/负载
50.4°0 / 320 / 360 / 37
100.9°0 / 780 / 770 / 81
151.3°0 / 1490 / 1200 / 116
201.8°0 / 1950 / 1480 / 143
252.2°0 / 2390 / 1710 / 164
302.6°0 / 2550 / 2070 / 188
403.5°0 / 2910 / 2230 / 220
30 counts(2.6°)正是一小时前失败 15/23/33 次的那个幅度。 现在零失败,而且 ID2 的峰值负载 291 高于两个健康对照(223 / 220)。 另外单独复现 3 轮 2.6°:全部零失败,峰值负载 265。

为什么之前会误判:热态那批测试的起始温度也是 34°C —— 但外壳凉不代表绕组凉。 61°C 之后又过了约一小时、全程力矩 off,才恢复到上表。表面温度传感器骗了我。

五、当晚修好的(都有测试)

空闲自动停放 —— 防止再发生

无操作 3 分钟 → 缓慢缩回 home → 保持力矩停在那儿
任何按键 → 立刻中止,控制权交还

三条边界,测试逐条守住:保留夹爪状态(直接用 home 位姿会张开爪、把杯子扔了)、不卸力矩(卸了手臂会掉,而 home 姿势保持力矩实测只有 37°C)、按键立刻中止(归位分支有 continue,不中止的话按键会被无视好几秒)。

判据是「没有真实操作」而不是「没有数据」—— XLeVR 的网页即使不戴头显也在持续推位姿,按「有没有数据」判的话只要页面开着就永远不会触发,而那正是烧电机的场景。

温度守卫顺手记负载和电压

原来只记温度,「这颗在使劲」和「这颗坏了」分不开。现在三个寄存器轮换,每拍仍只读一次,每颗舵机 1.2 秒拿到温度/负载/电压各一次。停机判据一个字没动。

left:  shoulder_lift=61C/load108/11.6V  elbow_flex=36C/load22/12.4V ...

当晚就是靠这个新增的负载数据,才把「姿势问题」和「硬件问题」分开的。

teleop 两个 bug

① XLeVR 网页即使不戴头显也推逐位相同的位姿,于是键盘增量每拍被 VR 分支覆盖 —— 按一次 W,y 跳 +5 mm,下一拍回原位,手臂原地抖。判据:真实追踪永远有抖动,连续 15 拍逐位相同 = 合成流。

② (是①的修复暴露的)filt 只在归位分支和 VR 分支里绑定,「goal 是 None 且归位完成」那条路用的是上一轮循环的残留 —— 按左臂的键改右臂的目标位姿,再把结果发给左臂。

修好后实机验证:操作者连点 S 四十秒,左臂 y 0.12863 → 0.09563 单调后退净走 33 mm,右臂 0.14848 全程一个数字没变。

六、还开着的问题

同一位置已经换过一颗舵机。 舵机本身没坏,所以不用订备件,但机械阻力这条没排除 —— 如果那个关节转起来比对侧费劲,同样的动作它就要出更多力、更容易到 60°C,而这是软件保护解决不了的。

需要现场做的实验(几十秒、零成本):断电后用手分别掰两条臂的 shoulder_lift,比较阻力。 左边明显更紧 → 机械问题;两边差不多 → 空闲保护已经够了。

七、这一页答不了什么

2026-09-08 凌晨 · 全部数据为本机实测 · 工具 03-software/scripts/servo_load_probe.py --sweep · 交接 HANDOFF-2026-09-08-LEFT-SHOULDER.md
当前状态:17 颗舵机力矩全部 off,温度 32–34°C,左臂已回到 home 位姿