第 5 章 周边服务:更新、媒体、感知流与"个性"
本章代码走读:
Call枚举的update.*与detector.*组、docs/design/的更新与重启设计文档、kinematics的性能化改造。
5.1 updaterd:更新是一套动词,不是一次动作
第 3 章的 Call 枚举里,update.* 是最大的命名空间之一,动词清单本身就是更新系统的状态机:
// ── update.* ─────────────────────────────────────────────────────────────
Check(ComponentParams),
Apply(ApplyParams),
Rollback(ComponentParams),
ResetToGolden(ComponentParams),
Select(SelectParams),
Pin(PinParams),
Status,
ListInstalled(ComponentParams),
Log(LogParams),
/// One run's full transcript. `update.log` says which runs exist; this says what one did.
Show(ShowParams),
/// Turns the connection into a stream of [`method::PROGRESS`] notifications.
Subscribe,
Apply/Rollback/ResetToGolden(恢复出厂金色镜像)/Select(选通道)/Pin(钉住当前版本)——每个动词对应一个真实的运维场景,进度通过 Subscribe 转成通知流。配套的设计文档有三篇:updater-design.md、restart-order.md(服务重启顺序——多守护进程系统里"谁先起谁后死"是要写下来的)、boot-recovery-net.md(变砖后的网络恢复路径)。
更新与健康门禁的联动藏在 robotd 的开篇注释里——main.rs 第一行就自报家门:
//! The 50 Hz control loop, the `robot.*` socket, and the health the updater gates on
robotd 对外提供 RobotHealth 与 RobotSafeToRestart 两个调用(第 3 章见过),而 updaterd 以它们为门禁:机器人正在走路时不可安全重启,更新引擎必须问过控制循环才能动手。健康不是仪表盘上的装饰数字,是更新流程的前置条件——"检测到不健康的组件就回滚"因此有了权威数据源。
策略的更新与守护进程的更新是两条独立通道(第 1 章 Cargo.toml 的 [workspace.metadata.policies]:官方策略集在 HF Hub,"步态重训不应要求守护进程发版"),但共享同一套哲学:任何能远程到达机器人的东西,都要有版本、校验和回滚。
5.2 mediad:WebRTC 主路径与检测模型联动
第 2 章从 AGENTS.md 读过媒体策略:消费者走 WebRTC(端到端加密、同会话携带控制信道、有回传路径),media.stream(WebSocket 推帧)只是程序消费纯帧流的兜底。这里补一个 Call 枚举里的联动细节:
// ── detector.* ───────────────────────────────────────────────────────────
/// What detector is installed and what the Hub offers; see [`method::DETECTOR_CHECK`].
DetectorCheck,
/// Install a detector and restart `mediad` onto it.
DetectorInstall(PolicyInstallParams),
视觉检测模型(跑在 RK3566 的 NPU 上,duck-detect crate)与 RL 策略走同一套安装参数结构(PolicyInstallParams)和同一套 Hub 分发通道——"模型即资产"不区分它是神经网络检测器还是步态策略。安装检测器会"把 mediad 重启到它上面",媒体管线与感知管线在同一个进程里交汇。
5.3 tofd 与传感器流:订阅制
深度与 IMU 不在 Call 的请求-应答里,而是专门的流订阅:
/// Subscribe to the raw pad input stream. Answered by `padd`, not `configd`.
PadInput,
/// Subscribe to the ToF depth stream. Answered by `tofd`.
TofStream,
/// Subscribe to the head IMU (BMI088 on the HAT); see [`method::HEAD_IMU_STREAM`].
HeadImuStream,
注释顺带披露了硬件细节:头上那枚 IMU 是 BMI088,焊在 HAT 板上。流式接口与第 3 章"连续调用是通知"的节奏分类一脉相承——高频数据只订阅,不请求。
5.4 声音与个性:theremin、chorale 与一只鸭子的灵魂
robot.* 组里有三个"不像正经机器人功能"的调用,它们是产品人格的载体,也是工程上最讨巧的部分:
/// Play a voice-bank sound.
RobotSound(SoundParams),
/// Pick the ToF theremin up or put it down. Discrete; the answer is [`ThereminResult`].
RobotTheremin(ThereminParams),
ToF 特雷门琴:深度传感器测手距,映射为音高——传感器流(TofStream)的消费端除了避障还可以是乐器。配合 sounds crate 的语音库、chorale 的多鸭合唱(第 3 章),以及 pet-detect(宠物检测)驱动的互动行为,一只鸭子的"性格"由这些小模块拼出来。研究平台会把它们当 demo,产品公司把它们当核心资产——这个仓库的认真程度(theremin 有专门的 ThereminState 结构和结果类型)说明团队清楚自己在做后者。
5.5 代码走读:kinematics——为 50 Hz 而生的编译式 FK
kinematics/src/lib.rs 的模块注释是一次教科书级的性能化改造记录:
//! MJCF-driven forward kinematics, compiled for the control loop.
//!
//! The prototype's `microduck_kinematics` crate proved the approach — parse the
//! training MJCF, walk the tree — but its query path was built for convenience:
//! joint angles travelled in a `HashMap<String, f64>`, and asking for one site
//! recomputed every body in the robot into a freshly allocated `Vec`. Fine at
//! bench cadence; wasteful inside a 50 Hz loop that asks for both feet every
//! tick.
//!
//! Here the model is *compiled* once at load: names are resolved to indices,
//! and each site gets its own flattened root→site chain of links. A query is
//! then a fold over that chain — no hashing, no allocation, no bodies the site
//! does not hang from. Angles are a plain `&[f64]` indexed by [`Model`]'s joint
//! order; resolve names to indices once with [`Model::joint_index`], not per
//! query.
//!
//! Correctness is pinned two ways: `tests/fk_against_mujoco.rs` compares every
//! site against MuJoCo's own `mj_kinematics` on 64 random poses, and
//! [`head`] pins the sign conventions the rest of the system steers by.
叙事结构值得仿写:原型验证了路线(解析训练同源的 MJCF)→ 指出查询路径的两个罪状(字符串哈希、每次查询全树重算加分配)→ 给出编译式方案(加载时名字解析成索引、每个 site 一条展平的链、查询即折叠)→ 正确性双保险(对 MuJoCo 自身结果比对 64 个随机姿态 + 符号约定单独钉死)。"与 MuJoCo 逐点对齐"正是第 9 章 sim2real 哲学在几何层的回声:仿真用的模型与部署用的运动学必须同源互证。
5.6 本章小结
周边服务群展示了三条产品级思路:更新是带门禁的状态机而非单次动作;所有模型(检测器与策略)共用一条带校验的分发通道;高频数据一律订阅流。加上 theremin 与合唱这些"人格模块",一台消费级机器人的软件版图就此完整。下一章看这些服务如何在没有硬件的情况下整体运转起来。