YouDuck.ai

Microduck 系统架构

最后更新

Microduck 的机上软件是 Rust 写的,一个 workspace,没有框架。由 systemd 负责生命周期、崩溃重启、启动顺序和 watchdog。

理解这张图的价值在于排查:知道某个功能归谁管,就知道该看哪个进程的日志。

守护进程分工

Microduck 守护进程架构图 七个守护进程通过 Unix socket 上的 JSON-RPC 控制平面通信;robotd 独占电机总线,传感器数据平面由各自的守护进程直接发布,不经过 robotd。 JSON-RPC 2.0 Unix socket 控制平面 robotd 电机 · 策略 · 安全 mediad 摄像头 · WebRTC configd wifi · 身份 · 配对 updaterd 更新 · 回滚 padd 手柄(非特权) btd BLE(不持状态) tofd 8×8 深度矩阵 15 个舵机 · 50 Hz tof.stream 直接订阅 不经过 robotd
七个守护进程共用一套 JSON-RPC 控制平面。传感器数据走各自的订阅通道,不经 robotd 转发——这也是为什么手柄原始流要在 padd 上看,而不是在机器人状态里找。
服务 负责 说明
robotd 电机控制、运动学、里程计、步态策略、传感器循环、安全 准实时核心,对一切可能伤到机器人的事情有最终权威
mediad 摄像头/麦克风、编码、感知、WebRTC 与远程网关 最重的服务,同时是远程 API 的前门
updaterd 更新引擎 安装签名过的发布版,机器人起来不健康时自动回滚
configd wifi、机器人身份、电源、手柄配对
btd BLE GATT 服务端 纯传输适配器,不持有任何状态
padd 读取手柄 刻意设计成非特权客户端
tofd 头部 ToF 传感器(HAT I²C 总线上的 8×8 深度矩阵) 只拥有一个传感器并发布帧,不读取任何东西

几个切分决策,以及为什么

这些不是随意划分的,每一条都有具体理由。

mediadrobotd 拆出去,是为了让媒体/感知的崩溃不会带走电机控制。

tofd 是同一条规则用在更小的传感器上,而具体细节让这个决定更站得住脚:

  • 启动一个 VL53L5/8CX 需要通过 I²C 上传约 90 KB 固件,耗时数秒;
  • 这条总线和音频编解码器共用
  • 大多数鸭子根本没装这个传感器。

为这种情况写一个重试循环,不该放在拥有电机的那个进程里。而且控制循环不读深度数据,所以移出去没有任何损失。

它也刻意不放进 mediad:深度是总线上的一个传感器,不是媒体管线;而且它在有摄像头可标注之前很久就有用了。

手柄配对放在 configd 而不是 padd,因为绑定一个设备需要 root 和 BlueZ,而 padd 被刻意设计成非特权客户端。

配置归 configd 自己管,因为它必须在 robotd 已经死掉时仍然可达,同时 btd 又不能拥有任何状态——所以它不归这两者中任何一个管。

进程间通信

控制平面:Unix socket 上的 JSON-RPC 2.0

所有守护进程通过 Unix socket 上的一套 JSON-RPC 契约通信。

这里有一条对使用者很重要的性质:

每一个客户端——手机 App、控制台、手柄、你自己写的脚本——发送的是完全相同的调用。

也就是说,你脚本能做的事和官方 App 能做的事,接口上没有区别。

控制平面与数据平面是分开的

数据平面(传感器流)不走控制平面。消费者订阅拥有该数据的那个守护进程自己的 socket——比如 ToF 数据订阅 tof.stream,手柄原始流订阅 padd——而不是绕经 robotd

tofd 发布的是传感器视角的原始数据,不假装自己能算出它算不出的几何。要把一帧深度重投影到机器人自身坐标系,需要把它和 robot.state 里的关节状态、以及 kinematics crate 的头部正运动学结合起来。

版本与健康:两个不同的问题

官方设计文档里有一节专门讲这个,值得单独记住:

「正在运行的版本」和「已安装的版本」是两个不同的问题。 这就是为什么 robotctl version 会同时报告两者并在不一致时警告——更新之后某个守护进程仍在跑旧代码,看起来和你刚修的 bug 没修好一模一样。

健康是一个问题,所以它是一条命令。 robotctl health 把硬件和软件放在一份报告里,而不是让你去分别查七个进程。

里程计不是一个服务

里程计是控制循环里的一个结构体,不是独立服务。理由很直接:它的输入恰好就是循环已经读到的那一份采样

这也解释了 robotctl monitor 里那张轨迹图的性质:它来自足底触地和 IMU,没有磁力计,所以是相对运动且会漂移。它能回答“它是不是走了一圈”,回答不了“它现在在哪”。

相关