首页/新闻资讯/正文详情

microduck 通过 BLE 从手机更新机器人:btd 路由、updaterd 进度流与连接车道设计全解析

发布时间:2026/9/25 11:49:27 来源:云帆数科 栏目:资讯中心
microduck 通过 BLE 从手机更新机器人:btd 路由、updaterd 进度流与连接车道设计全解析
机器人嵌入式强化学习人工智能智能硬件计算机视觉音视频【免费下载链接】microduckA Tiny biped duck robot 项目地址https://gitcode.com/gh_mirrors/mi/microduck点击查看免费下载本文是对 microduck 项目中从手机更新机器人BLE 更新路径这一能力的技术复盘它记录了btdBLE 传输适配器、updaterd更新引擎与duckctl手机应用的替身客户端三者之间一次端到端打通时发现并修复的缺陷、做出的安全边界决策以及留给后续工作的约束。读完本文你将理解BLE 会话中车道lane为什么是必要的、进度通知如何被压缩进 20 字节的 MTU 管道、update.check为何必须用try_lock立即回答BUSY以及手机触发的更新在回复后约 5 秒断开连接这一正常现象应当如何被客户端消化。该路径的机制记录在其所在代码旁边app-path-design.md§3.5 定义了连接车道、§3.1 定义了被路由的调用子集而btd/src/route.rs为每一条被路由或被拒绝的调用注释了决策理由。1. 背景大部分已就绪只差有人驱动BLE 更新路径在本次工作前已经完成了大半只是没人驾驶过它。三个组件各自已具备关键能力btd已经路由了更新子集hello、update.check、update.apply、update.status、update.subscribe、update.log、update.listInstalled已经能到达updaterdrobot.health能到达robotd。本次工作没有向协议新增任何一个方法。updaterd已经会流式输出自己的进度run_mutating会把update.progress通知写到发起 apply 的那条连接上在回复之前btd把上游的每一行原样泵入会话而不去读它客户端只需持续等待即可。因此一个 BLE 客户端在 apply 期间无需订阅就能收到进度。更新中途重连的客户端不会丢失状态updaterd为每个组件保留最新的Progress并在新订阅者接入时重放update.status在更新进行中也总是能回答——它来自缓存快照并实时打上当前阶段。回复先于传输死亡发出updaterd和btd是更新永不重启的两个单元两者都在回复之后约 5 秒才被重启详见restart-order.md§1。而duck-btctl文档中曾声称apply 在独立连接上是静默的直到完成——本次工作证明事实恰好相反该声明随后被修正。2. 驱动过程中发现的问题三处修复、一次决策、两处记录2.1 长调用让会话的其余部分静默 ·btd·已修复Pool原本为每个服务持有一条连接而updaterd与robotd都是一次一条连接、一次一个请求的服务模型读一行、等待整个调用完成、再读下一行见updater/src/ipc.rs::handle_connection与configd/src/main.rs::handle。于是两个致命的调用顺序出现了客户端操作实际发生了什么update.subscribe之后update.applystream_progress独占它的连接直到对端离开、且从不读下一个请求apply 被写进一个没人读的 socket它从未运行、从未回复、从未报错。机主点更新机器人毫无反应而且任何地方都找不到错误update.apply之后update.status同样的缺陷症状较轻——状态轮询超时而机器人其实一切正常、正在更新这正是app-path-design.md§3.5 记录的场景调用现在按它们占用连接的时间分组每组拥有自己的连接。btd/src/route.rs中destination_for依据协议里定义的Lane给出每个调用所属的通道车道占用连接的时间承载的调用Prompt一次查询那么长hello、update.status、update.log、update.listInstalled、robot.health、net.status、net.forget、system.*、pad.status、pad.forgetSlow数秒——网络或无线电扫描update.check、net.scanOperation需要多久就多久且改变机器人状态update.apply、update.rollback、update.select、net.connect、pad.pairStream永远且不回答任何请求update.subscribe共享车道即排队而每一组恰好是排队是正确的答案的场景updaterd在文件锁后对变更操作单飞第二个会立即得到BUSYconfigd上同时发起两个无线电操作也不是该有的行为。update.check刻意不放在Operation车道上——在更新进行中询问它有即时答案排队只会把BUSY变成一个几分钟后才消解的转圈。每服务每会话最多四个 socket实践中通常是两个。每次调用一条连接是更整洁的模型但那需要btd解析回复以得知调用何时结束——这正是它从不做的事也是路由子集保持传输层而非API 的第二个实现的关键性质。车道划分是本次工作中手机应用无法绕过的唯一修复两个失败场景都有对应的测试缺少该修复时测试会失败见btd/src/route.rs中的an_apply_shares_its_connection_with_nothing_a_client_does_during_one与nothing_else_travels_on_the_stream_lane。2.2 进度是一条瞄向 20 字节管道的消防水带 ·updaterd·已修复下载源会为每一个写出的 HTTP 块报告进度——一个发布构件有数千个块——而每个订阅者都要为它们全部买单。一条进度行约一百字节在btd按 20 字节下限分帧时就是五六条通知一旦客户端落后btd会丢弃行。结果手机看到的是百分比的任意子集进度条在 12 → 61 → 34 之间跳。duck-ble/src/framing.rs定义了这条管道的物理约束FLOOR_MTU 20每个 BLE 链路都要求支持的载荷MAX_LINE 8 KiB入站安全上限MAX_REPLY_LINE 64 KiB出站上限。btd/src/link.rs的队列深度也因此是一条编译期断言QUEUE * 20 framing::MAX_LINE——20 是 BLE 保证的最小载荷因此也是客户端可能使用的最小块。修复在updater/src/engine.rs中即数字产生的地方做合并现在每个整百分比至多一条通知每秒至多四条。合并逻辑是一个专门的admit(percent, now)门ProgressGate无总量时没有百分比可合并间隙gap是唯一约束百分比未变化则丢弃percent self.sent时返回 false不发布被间隙抑制的百分比在下载结束时仍会被发布flush()或让快速下载可见地停在 97%。注释把旧行为钉在案上客户端看到任意百分比子集、进度条 12 → 61 → 34 乱跳每百分比一条、每秒四条是一个平滑移动的条也是一条 20 字节管道能承载的流。由于合并发生在引擎层robotctl update watch获得的是完全相同的流。三个测试固定了这些性质a_whole_download_publishes_at_most_one_notification_per_percent、an_unchanged_percent_is_never_republished不变的百分比不是新闻这压缩了下载尾部大量落在同一整百分比上的块、a_percent_held_back_by_the_gap_is_published_when_the_download_ends。2.3update.check阻塞在引擎锁上 ·updaterd·已修复updater/src/ipc.rs在文件头部就写明了规则——只读请求使用try_lock这样status和subscribe在更新期间保持可应答——而check没有遵守它。在 apply 进行中询问它它会在 apply 结束后才回答几分钟后这在手机上与机器人已停止应答无法区分。现在它立即回答BUSYupdate.pin同样如此。ipc.rs的代码注释说明了理由try_lock失败映射为crate::Error::Busy回复proto::code::BUSY an update is in progress; retry shortly——立即回答正是让客户端能说出口的方式阻塞产生了一个几分钟后才消解的 spinner。2.4 决策回退从手机可达update.rollback和update.select原本被拒绝现在两者都已路由update.pin与update.resetToGolden保持拒绝。决策理由完整写在btd/src/route.rs的对应 match 分支注释中也在app-path-design.md§3.1 有总结。核心推理update.apply原本就已路由而且是三者中最有后果的——它从网络安装一段从未在这块板子上运行过的代码。而rollback和select只是移动到昨天已在板上运行过的版本不下载任何东西并且像任何其他转换一样被 health gate 门控、被自动回退Engine::rollback与Engine::select都走transition_to。引擎自身的自动回退覆盖的是未通过健康门的版本——那并非机主拿起手机求助的场景。机主求助的场景是版本安装成功、通过门控、然后表现得更糟——一条走路不稳的策略、一个停止重连的 pad。除了人没有任何东西会回退这种情况而那个人手里拿着手机、没有 ssh。两者同时打开而非只开rollback是因为update.listInstalled已经路由应用可以列出板上每一个已安装版本——能展示却不能选择才是奇怪的一半。select需要从列表里挑一个版本这是更大的表面、更容易误触出错这是被接受的成本。pin是最有趣的拒绝错误的一次select距离被撤销只差一个版本而且机器人会告诉你它在哪个版本上而一个被误触 pin 住的机器人会拒绝之后每一次更新并把自己报告为最新——这是这里唯一看起来像正确行为的失败模式它需要robotctl和一位确实想这么干的人。resetToGolden是名副其实的出厂重置永远不通过无线电。注意rollback/select被路由并不削弱这条——两者都不丢弃任何东西。对应测试going_back_is_reachable_from_the_phone断言这两个调用都路由到Upstream::Updater的Operation车道并注释引用 §2.4 的决策。2.5 手机触发的更新被记录为btd·记录在案未修复updaterd通过SO_PEERCRED在每一次变更操作上记录调用者的 uid 和 pid——这正是支持人员回答谁触发了这次回滚的依据。在ipc.rs中可以看到uid{} gid{} pid{}的日志行以及allow_uids/allow_gids的授权策略。但通过 BLE 时答案永远是btd——对每一部手机都一样。btd原样转发参数给它加一个who字段会把它从一条管道变成请求的作者。只有当支持需要区分两部手机时才值得重新打开。顺带一提btd之所以能通过updaterd的变更授权是因为deploy/updater.toml里allow_users [btd, mediad]——注释明确这是btd 可以中继应用的更新请求而不是robot 组里的任何东西都可以替换固件还有一个测试断言 shipped 配置绝不允许allow_groups [robot]。2.6 客户端截止时间是总额而非空闲 ·duckctl·已修复一个固定预算要么切断一次正在正常工作的更新要么等死一台死掉的机器人——而真正有用的信号其实一直在到达每一条进度通知都是机器人还活着的证明。duckctl/src/main.rs现在的截止时间是静默时长REPLY_TIMEOUT15 秒普通调用的静默预算SLOW_REPLY_TIMEOUT60 秒net.connect等慢调用UPDATE_IDLE_TIMEOUT从duck_ipc_proto::UPDATE_MAX_SILENCE_SECONDS推导60 秒余量——即三分钟。注释解释更新中合法的最大间隙是 pre-install hook 的上限该 hook 可能安装 ONNX Runtime、以及为mediad的 GStreamer 栈安装约 100 MB 的 apt 包而不是更新能持续多久低于这个上限的预算会把一次正常更新报告成机器人停止应答操作员的下一步就是打断一次本来没事的更新。FOLLOW_TIMEOUT24 小时update watch的任意上界它实际以 Ctrl-C 结束。关键实现是 deadline随每条到达的通知向后推next_chunk循环里deadline now timeout所以慢镜像在几秒内失败仍然成立。测试an_update_is_given_the_longest_silence固定了这种不对称。手机应用继承的是这个原则不是这段代码。2.7 守护进程 apply 回复后约 5 秒链接断开这不是缺陷——正是 §1 的次序在起作用——但每个客户端都必须预期它而且机器人宣布的断开绝不能读作一次失败的更新。要按这个序列来构建update.apply回复其结果。那就是答案更新完成了。约 5 秒后btd重启连接断开。重连读update.status。last_attempt携带结果所以错过第 1 步回复的客户端仍能报告它。机制在restart-order.md§2 步骤 16–18updaterd与btd通过systemd-run --on-active5s的临时单元延迟重启一个systemctl restart updaterd会杀死updaterd的整个 cgroup而更新锁的子进程就在其中定时器在回复写出之前就绪所以 5 秒从步骤 16 起算、而非从客户端看到答案起算。duckctl会在第 2 步发生之前打印出来——工具在 apply 的输出中附上note: the robot restarts its daemons now, andbtdabout five seconds after this reply — so this connection drops. That is the update working.2.8 刻意保持开放from_dirover BluetoothApplyOptions.from_dir在机器人上指定一个目录——对手机毫无意义在 bench 上有用。过滤它意味着route.rs要根据参数而非方法做决定而检查参数正是btd不做的事。Preflight 已经拒绝所有咬人的情况并且会说明所以这里维持原状并在文档中具名让下一个人看到的是一次决策而非一处疏漏。3.duckctl现在提供什么duckctl原名duck-btctl因名字按与什么对话而非用哪个无线电命名而更名提供version与update子命令check、apply、status、versions、log、rollback、select、watch——与robotctl update使用完全相同的词所以在机器人上学到的命令在无线电上同样可用详见duckctl.md。两个值得注意的实现细节参数由duck_ipc_proto自身的类型构建而非手写 JSON——这正是call留给打字者的坑update.apply的目标是一个外部标记枚举所以--ref与--version是不同的 JSON 形状写错一个就是一个里面没有任何可操作信息的解析错误。进度按事件在 stderr 上打一行。回复走 stdout漂亮 JSON、进度与诊断走 stderr所以duckctl update apply outcome.json把进度留在屏幕上、把结果留在文件里。这与文档页早已承诺、而工具此前并未做到的行为一致。duckctl是一个过渡工具stopgap而这正是它重要的地方§2.1、§2.2、§2.3 都是机器人侧的修复应用直接继承而 §2.6 的截止时间形态是客户端侧的所以工具把它做对了而应用自己的设计笔记必须说明为什么。4. 剩余工作以上一切都没有在真实板子上跑过。每一项都有测试覆盖但测试看不到手机看到的东西进度能否在真实的 20 字节链路上平滑到达、apply 的回复能否在btd重启前到达客户端、以及每个服务第四条 socket 在 Zero 3W 上是否值得。这是下一个会话的事对着开发板执行duckctl update apply --ref。另外一点值得记录duckctl.md中那条过时声明apply 在独立连接上是静默的是从读代码修正的不是从板子。如果 BLE 上的 apply 事后被证明真的是静默的要检查的机制是btd/src/link.rs中的出站队列而不是路由。5. 刻意不做的事没有取消。引擎没有 cancel而半应用的更新比慢的更新更糟。客户端走开的场景已经处理好了更新会完成。没有来自手机的自动应用开关。deploy/updater.toml刻意不把客户端机器人纳入无人值守重启——auto_apply mandatory只允许清单里min_supported兜底的强制版本自动安装普通版本仍等待客户端决定重启时机。在有一支机队可以据此推理之前这不是该暴露成开关的决策。没有加密。app-path-design.md§8.1 拥有这个话题它在这里没有阻塞任何东西。而上面关于无线电范围内的对等方能做什么的每一条陈述都建立在加密仍然关闭的前提上--require-pairing存在但默认关闭因为默认开启会让 CoreBluetooth 在版本读取上挂死。这是机器人交到任何人手里之前必须关闭的阻塞项。赞分享机器人嵌入式强化学习人工智能智能硬件计算机视觉音视频【免费下载链接】microduckA Tiny biped duck robot 项目地址https://gitcode.com/gh_mirrors/mi/microduck点击查看免费下载相关推荐microduck 的 BLE 配置通道:从 btd/configd 架构到 NetworkManager 迁移、PIN 认证与路由安全边界的完整拆解microduck 的 BLE 配置通道:从 btd/configd 架构到 NetworkManager 迁移、PIN 认证与路由安全边界的完整拆解 本文基于机器人嵌入式强化学习人工智能智能硬件计算机视觉音视频microduck WebRTC 远程访问设计本地信令、双数据通道与控制通道如何接上机器人 APImicroduck WebRTC 远程访问设计本地信令、双数据通道与控制通道如何接上机器人 API 本篇基于 microduck 仓库的设计文档 remote机器人嵌入式强化学习人工智能智能硬件计算机视觉音视频FakeNet-NG HTML报告功能详解可视化网络行为分析FakeNet NG HTML报告功能详解可视化网络行为分析 FakeNet NG是一款强大的下一代动态网络分析工具其HTML报告功能为用户提供了直观、高效上一篇RIOT 的 CI 工具链解析静态测试、GitHub 注解与 Fast CI 增量构建判断下一篇OBS多平台直播插件终极指南5分钟实现一键多平台同步推流创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关推荐

会背书 ≠ 懂生命!LifeOmni榜单揭示大模型生命科学实战短板 | 生命科学评测
会背书 ≠ 懂生命!LifeOmni榜单揭示大模型生命科学实战短板 | 生命科学评测

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 11:49:21

启动盘集成多个PE:用EasyBoot、UltraISO与WinHex的配置步骤
启动盘集成多个PE:用EasyBoot、UltraISO与WinHex的配置步骤

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 11:49:21

BlockNote 混合样式段落的 Markdown 导出:从快照测试到源码序列化实现
BlockNote 混合样式段落的 Markdown 导出:从快照测试到源码序列化实现

前端富文本UI组件AI 应用 【免费下载链接】BlockNote A React Rich Text Editor thats block-based (Notion style) and extensible. Built on top of Prosemirror and Tiptap. 项目地址: https://gitcode.com/gh_mirrors/bl/BlockNote 点击查看 免费下载 导读 本… · 2026/9/25 11:49:21

我用一个MCP工具让Claude帮我管理了整个项目:TaoToken统一Key接入与配置文件骨架
我用一个MCP工具让Claude帮我管理了整个项目:TaoToken统一Key接入与配置文件骨架

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 12:28:07

openclaw平替之nanobot源码解析(六):子智能体(Subagents)配置与验证
openclaw平替之nanobot源码解析(六):子智能体(Subagents)配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 12:28:01

Oracle数据库时区升级实战:DBMS_DST脚本包使用与避坑指南
Oracle数据库时区升级实战:DBMS_DST脚本包使用与避坑指南

简介:本资源为Oracle数据库时区版本调整脚本包,面向需要将数据库时区版本升级至最新版本的DBA与运维人员,通常配合时区补丁使用,可解决因时区版本过旧导致的日期时间计算偏差、跨时区业务数据不一致等问题。压缩包共4个文件&#… · 2026/9/25 12:27:36

vllm 切换模型下载源与安全设置:TaoToken 统一 Key 通道下的 config.toml 骨架与验证
vllm 切换模型下载源与安全设置:TaoToken 统一 Key 通道下的 config.toml 骨架与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 12:27:36

Mediago 前端优化指南:按用户意图预加载重型分包,降低感知延迟
Mediago 前端优化指南:按用户意图预加载重型分包,降低感知延迟

音视频桌面应用后端 【免费下载链接】mediago 跨平台视频提取工具:支持流媒体下载、视频下载、m3u8 下载及 B站视频下载,提供 Windows 和 Mac 桌面客户端。Cross-platform video extraction tool: Supports streaming download, video download, m3u8 do… · 2026/9/25 12:27:24

TaoToken 统一 Key 接入 Claude Sonnet 5 Medium 免费试用:settings.json 配置与验证
TaoToken 统一 Key 接入 Claude Sonnet 5 Medium 免费试用:settings.json 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 12:27:12

数值优化(Numerical Optimization)学习系列-03-共轭梯度方法(Conjugate Gradient)
数值优化(Numerical Optimization)学习系列-03-共轭梯度方法(Conjugate Gradient)

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:31

创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战
创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:31

MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX
MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:37

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码