DEEP 09 · 第一辑 · 运动控制核心 · LEARN NOTES

收进学习手册 · 2026-09-11 · duck.whatled.com

解读 09 · robotd/main.rs + control.rs:守护进程的控制循环

解读对象:robotd/src/main.rs(7561 行,本篇读主干)、robotd/src/control.rs(706 行)
需要的前置:解读 04(安全层)、解读 03(ONNX 策略)

1. 健康度决定了形状

main.rs 头 20 行先讲"为什么长这样"(main.rs:6-10):更新器的自动回滚只在 robot.health 有意义时才有意义,而它一度只意味着"循环跑过一拍"。现在健康意味着循环在赶上周期:"一个跑在目标 60% 的循环活着、应答每个请求,而且坏得很彻底"。第二条原则(main.rs:16-19):每个方法都必须在机器人状态很糟时可以应答,所以 IPC 侧只读控制循环发布的原子量,从不调进循环——卡死的循环报告自己不健康,而不是把客户端挂住。

进程骨架在 main(main.rs:867):加载参数,spawn_control_thread(main.rs:1022)把控制循环放到专属 OS 线程 + current-thread 运行时上——总线读是阻塞式串口 IO,共享运行时会占住一个 worker(main.rs:1016-1021);独立运行时让 IPC 排不进一拍前面。退出时置 shutdown 并 control.join(),让循环做完手里那笔总线事务(main.rs:963-966)。

2. 一拍里的顺序

control_loop(main.rs:1553)每拍依次:读总线(失败计数,第 1 次和每第 10 次打日志,main.rs:1799-1801)→ 读失败时按 COAST_TICKS = 3(main.rs:120)沿用最后一个好样本滑行——掉一次事务是常态,实测约每分钟 8 次;过去每次掉读都停策略回 hold 位,就是用户报的"随机小抽搐"→ safety.observe → intents.snapshot → safety.gate(死手开关在这里读 twist 的年龄)→ 判定 driving(main.rs:2535-2543,七个条件:使能、Ready、有控制器、不在摔落序列、有样本、IMU 已收敛、未断电)→ controller.step → safety.apply 写回(main.rs:2834)。

节拍器:tokio::time::interval + MissedTickBehavior::Skip(main.rs:1641)。注释拿实测说话:用 Delay(每拍从"现在"重排下拍)时循环报 43.1 Hz 而目标 50 Hz、missed = 0——不是干不完活,是每次唤醒延迟都被累加进周期。

3. control.rs:只提议,不指挥

control.rs 模块注释给 Controller 划了界(control.rs:2-5):它不持有任何 IO 句柄,构造上就命令不了电机,只能产出 Step { targets, label, gain, busy }(control.rs:118)。Controller::step(control.rs:425)按写死的优先链选网络:skill > ground pick > 坐/起 > 按幅值选站立 > 走(control.rs:477),然后 targets[joint] = DEFAULT_POSITION[joint] + scale * offsets[joint](control.rs:601-604),再对头和腿做一阶低通(head_lowpass = 0.5、legs_lowpass = 0.7,训练值,control.rs:59-63)。默认调参集中在 Tuning::default(control.rs:66-77):action_scale 0.9、站立增益比 0.8、gain 200——测试 the_defaults_match_the_prototype 逐个钉住。

两处注释点名"容易好心改坏"的怪癖:踢腿窗口按站立项调参跑(踢腿观测里命令全零,原型恰好由此触发站立过渡,control.rs:24-28);窗口在用过之后才推进,"原型在电机写之后推进相位"(control.rs:623-625)。

4. 循环之外:让健康度可计算

循环每 1 秒窗口(RATE_WINDOW,main.rs:85)算一次实际频率存进 achieved_hz(main.rs:2887-2893);超期的拍计进 missed(main.rs:2883-2885)。健康判定在 RobotState:上次打卡距今超过 stall_periods 个周期 → 不健康"control loop stalled for N ms"(main.rs:778-783);频率低于下限 → 不健康(main.rs:785-791)。safe_to_restart 只在"正在走且没摔"时说不可重启——"行走中重启电机控制是摔倒的方式"(main.rs:850-858)。

你带走的收获

延伸

什么鸭 WHATDUCK · 复刻学习笔记 ← 全部手册 · 首页