解读 107 · model.rs:常量、关节表与电池
解读对象:
duck-control/src/model.rs(241 行)
需要的前置:解读 07(导览)、解读 92(电池常数的使用方)
导览见解读 07,本篇逐函数下钻:补上"单变体宣言"、出厂值的设计意图、寄存器表的其余三项,以及电池函数的完整契约。
1. 只有一个变体的机器人
模块注释(model.rs:1-9)开头是宣言:只有一个变体 alpha,因为"这是唯一存在的机器人";v1/v1.5/v1.6 是历史,"第二个修订版会变成第二组表——在真有第二台机器人可以泛化之前,这是诚实的做法"。数值出处随后声明(model.rs:7-9):这些数抄自 microduck_runtime 的 motor.rs,是"对着硬件量出来的,不是推导出来的",从数据手册重推"恰恰是那种看起来对、走起来错的改动"。表格:NUM_JOINTS = 15(model.rs:12);JOINT_IDS(model.rs:15-19)三段排布——左腿 ID 20–24、颈头嘴 30–34、右腿 10–14,右腿在数组尾部而非身体顺序;JOINT_NAMES 从协议 crate pub use 再导出(model.rs:24),"顺序不许有两份副本"。joint_index(name)(model.rs:103-105)是 15 项线性扫描,注释直说只用于启动期和测试——热路径用不上。
2. home 位、嘴与编译期纪律
DEFAULT_POSITION(model.rs:39-55)的 15 个弧度值各带名字注释,文档藏着两个事实:躯干比 v1.5 前移约 5 mm,"让重心落在踝轴上方——旧姿势让机器人重心偏后"(model.rs:33-35);它必须与训练环境的 HOME_FRAME 一致,因为策略观测的是相对 home 位的角度,"这里差一点,就是 14 个观测槽上的常数偏移"(model.rs:36-38)。嘴的控制面是四个成员:MOUTH_INDEX = 9(model.rs:31,"命名是为了让省略是故意的")、MOUTH_CLOSED(−5°)与 MOUTH_OPEN(+30°,沿用 v1.6 的 range,model.rs:62-63)、mouth_target(model.rs:67-74)——开合比例 clamp(0.0, 1.0),非有限输入归零(model.rs:68-72)。编译期纪律只一条:const _: () = assert!(JOINT_NAMES.len() == NUM_JOINTS);(model.rs:26)。
3. 出厂值是留给替换流程的抓手
三个常量构成一组设计:IMU_DXL_ID = 200(model.rs:78)、BAUD_RATE = 1_000_000(model.rs:80)、FACTORY_ID = 1 与 FACTORY_BAUD_RATE = 57_600(model.rs:85-86)。后两个的文档说破意图(model.rs:82-84):ID 1 与 57600 波特"在这条总线上被刻意闲置——没有关节是 ID 1,也没有东西跑那个速度",这正是换舵机时把出厂新舵机从旧成员里认出来的依据(收养见解读 99),测试逐项钉死(model.rs:163-175)。EXPECTED_REGISTERS(model.rs:95-100)是启动期逐台校验的四组寄存器;07 讲过承重的 return_delay_time = 0,其余三项:baud_rate = 3 注明"3 = 1 Mbps,必须与 BAUD_RATE 一致"(model.rs:97),pwm_slope = 255(model.rs:98),shutdown = 52 是"过载、过热、输入电压故障时锁存的错误掩码"(model.rs:99)。
4. 电池:一个函数就是全部电量计
分节注释(model.rs:107-112)先交代测量条件:没有燃料计、没有 ADC,唯一读数是舵机上报的自身供电,"是隔着总线看到的电池——带负载下坠、静止回升",所以区间是"带负载可用",不是电芯化学区间。BATTERY_FULL_V = 8.2、BATTERY_EMPTY_V = 6.6(model.rs:115、119),battery_percent(model.rs:130-135)一行线性映射加 .clamp(0.0, 1.0)。两个契约由测试钉着:非有限或非正读数返回 0(model.rs:131-133)——"那意味着总线没回答,调用方应报告未知",测试连 NaN 和 −1 都列了(model.rs:206-210);区间外钳制而非外推——刚充满会超 8.2 V,跑趴窝会低于 6.6 V,但"都不许给调用方 0–100 之外的百分比"(model.rs:196-201)。还有一句组织学(model.rs:122-126):映射"住在这里而不是 robotd,只能有一份——原型写了两份,两块屏幕对同一块电池各执一词"。
你带走的收获
- 单变体不是偷懒,是诚实:没有第二台机器人之前,泛化层只会编造不存在的约束。
- 出厂默认值可以是一种资源:刻意闲置 ID 1 与 57600,换舵机流程才有"新面孔"可认。
- 校验寄存器表把协议约定变成启动期断言,每项附出处与症状。
- 换算函数的边界就是产品行为:NaN 返回 0、区间外钳制、映射只留一份。