Files
Mujoco_WASM/docs/robot-interface.md
T
chenlin 3ad29356c9
web-platform-ci / TypeScript, lint, unit, build (push) Has been cancelled
web-platform-ci / Playwright E2E (push) Has been cancelled
lekiwi-compatibility / cpu-compatibility (push) Has been cancelled
feat(lekiwi): release V0.10.1 初步集成 LeKiwi,优化碰撞模型
集成通用机器人数值接口、本机控制桥、LeRobot 插件和统一键盘遥操作。采用离线 CoACD 全臂碰撞配方 revision 4、局部装配区切分与结构自接触,限制直接关节位姿写入并保留安全看门狗。同步版本号、变更记录、来源许可证和兼容性验证。
2026-09-20 14:42:30 +08:00

112 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 机器人接口 V1:实时控制与任务层分离
## 能力与兼容矩阵
| 层 | 已验证内容 | 不支持 / 不承诺 |
| ------------------------------------ | ------------------------------------------------------------------------------- | ----------------------------------------------- |
| `RobotDescriptor/Action/Observation` | 通用 SI 标量、单关节与 LeKiwi 后端 | 任意远程可执行插件 |
| LeKiwi profile v1 | 三轮底盘、五个臂关节、夹爪、实测反馈、reset | 实机标定、可靠抓取、崎岖地形或 sim-to-real 保证 |
| `lerobot_robot_mujoco` | 实际 LeRobot 0.6.1 的 Robot/Config、发现、工厂、九维控制循环 | 冒充硬件 ZMQ 服务、官方所有 CLI 原样运行 |
| 仿真 | 官方浏览器 MuJoCo WASM 3.11.0 | 用原生 MuJoCo 测试代替浏览器物理验收 |
| 环境 | Ubuntu 24.04 x86_64、Python 3.12、CPU torch 2.11.0+cpu / torchvision 0.26.0+cpu | 修改既有训练 `.venv` 或加载物理机器人 |
| V1 能力标志 | `lockstep=false`、`cameras=false`、`training=false` | 相机、LeRobot 数据采集、Gym/RL 训练 |
普通 MJCF/URDF、Pyodide 控制器和 Go2 ONNX/训练链保持独立。未知模型不会因关节数相似自动套用 LeKiwi。平台自己的有界遥测 CSV/JSON 仍可使用,但不是 LeRobot dataset。
## 运行链路
```text
LeRobot Robot / 通用 SimRobotClient(同步 HTTP)
→ 本机 aiohttp broker(认证、租约、限流)
→ 浏览器 ExternalControlClient(WS,仅数值消息)
→ RobotRuntime(校验、最新目标邮箱、watchdog)
→ MuJoCoRobotAdapter + ModelBindings
→ 固定 dt 的 mj_step → 实测 observation / applied ACK
```
`ModelBindings` 缓存关节/执行器名称、qpos/dof 地址和标量传动约束,复用于 Python 和 Go2 绑定。Embind 临时查询句柄及时释放;关节 ID 不直接当作 qpos/dof 地址。
`ControlArbiter` 只有 `manual | python | policy | external` 一个所有者。每次 claim 创建新的身份票据,旧 Python `dispose/step`、旧 ONNX 结果或旧 socket 回调不能覆盖新控制者。非所有者退出不清除另一个控制者的目标。
外控使用同一 JS 线程上的约 120 Hz 物理调度器,仍按模型固定 dt 积分并遵循单次 8 ms / 100 步追帧预算;网络事件只入队,不在物理步内 await。普通手动/Python/ONNX 保留原渲染驱动步进。观测约 30 Hz,WS 独立发送;React 完整快照约 5 Hz,不用 UI 帧率充当控制/观测时钟。
外控绘制上限 30 FPS。检测到 SwiftShader/llvmpipe 等软件渲染时,profile 关闭阴影,外控绘制上限 5 FPS,为物理/通信留出主线程时间;几何和接触动力学不变。仍非硬实时:主线程卡顿/系统休眠时不能保证及时回调,恢复后先拒绝过期动作。
## 协议与身份
权威结构:[JSON Schema](../contracts/robot-v1.schema.json)、[共享 fixture](../contracts/fixtures/single-joint.json)。不要根据本页重新发明字段名称。
- descriptor:`protocolVersion=1`、`profileId/profileVersion`、`modelFingerprint`、`frame`、`actionChannels/observationChannels`、`capabilities`。
- 通道:`id/unit/min/max/mode`。只接受有限标量;未知字段、额外通道、重复通道、bool、NaN/Infinity 被拒绝。
- 身份:`sessionId + modelEpoch + leaseId`。重置递增 epoch;重载新建 session;租约只对当前授权代次有效。
- action:身份、`protocolVersion=1`、递增 `actionSeq` 和完整 `values`。
- observation:`protocolVersion/sessionId/modelEpoch/sequence/simTime/appliedActionSeq/paused/values`。`sequence` 可在新 epoch 中重启,同 epoch 不可倒退。
- action result:身份、`actionSeq/simTime/values`。它在物理步之后确认 **接受的目标**,不是实际位置;实际状态必须读 observation。
### HTTP 与 WS
HTTP 前缀 `/api/control/v1`,均需要 `Authorization: Bearer …`:
| 方法 / 路径 | 作用 |
| ------------------ | --------------------------------------------- |
| GET `/health` | 本机桥状态 |
| GET `/robot` | 当前 descriptor |
| GET `/observation` | 新鲜的实测状态 |
| POST `/lease` | 用 session/epoch/fingerprint 申请单写入者租约 |
| DELETE `/lease` | 释放,带 `X-Control-Lease` |
| POST `/action` | 完整 action,带 `X-Control-Lease` |
| POST `/reset` | 请求新 epoch 的暂停状态,带 `X-Control-Lease` |
WS `/ws/control/v1`:先发送 `{type:"auth",token:…}`;注册 descriptor/状态,再交换带 request id 的 claim/action/release/reset RPC、结果和状态更新。以 `ExternalControlClient.ts` 和 `server.py` 为实现依据,SDK 用户无需手写 WS。
错误码:`INVALID_MESSAGE`、`INCOMPATIBLE_MODEL`、`UNSUPPORTED`、`UNAUTHORIZED`、`CONFLICT`、`STALE`、`PAUSED`、`TIMEOUT`、`SUPERSEDED`、`DISCONNECTED`。缺能力显式失败,不伪造零图像或假训练支持。
## LeKiwi 映射与校验
唯一参数源:[lekiwi-v1.json](../robot_profiles/lekiwi-v1.json),Python 包通过 package-data 发布同一份 JSON。
- canonical 机体系:X 前、Y 左、Z 上;CAD +Y 前向经 -π/2 绕 Z 转换。
- 五个臂角:LeRobot 度 ↔ profile 符号/零偏修正后的 rad;夹爪 0–100 ↔ ratio 0–1 ↔ 关节 -0.18…0.9 rad。CAD 夹爪轴反向,使递增开度对应物理张开;闭合限位不再允许两指交叉。
- 底盘 `x.vel/y.vel` 为 m/s,LeRobot `theta.vel` 为 deg/s,通用接口为 rad/s。
- 轮顺序 left/back/right,半径 0.05 m、基座半径 0.125 m;最大 4.601942363656923 rad/s,三轮同比缩放而非分别削顶。
- LeRobot 九维反馈使用实测轮速里程计以兼容上游;通用 observation 另有真实机身位姿/速度,因此碰撞/打滑时两者可能不同。
- LeRobot 部分动作仅保持最后 **确认** 的臂/夹爪目标,省略底盘速度为零。连接初始保持值来自实测观测。拒绝 `use_degrees=False`、相机配置、物理校准目录以及非法 scalar。
URDF 和整臂 18 个视觉 STL 必须匹配固定来源 SHA-256;导出 MJCF 必须含受支持的 profile、version、source SHA、`platform_lekiwi_collision_revision=4` 和当前 `platform_lekiwi_collision_recipe_sha256`(旧配方,包括 revision 3,必须从原始 URDF 重新转换)。再校验编译后的浮动根、关节/执行器、传动、轴向、限位、增益和力限等。缓存编辑继承当前显式 profile,校验失败保留旧场景但不恢复外部授权。
启用机器人 profile 后,关节角仅作实测显示:禁止 `setJointPosition()` 或 `resetJoints()` 直接写 qpos,禁用关节拖动/单独重置关节,也禁止忽略关节限位;完整仿真 reset 的撤权/epoch 行为不变。旧滑条是暂停时的姿态编辑而非物理运动,任何碰撞体都不能防止这种直接插入。需要运动时播放仿真,通过执行器目标或外控驱动;普通非 profile 模型的姿态编辑不变,外控仍排斥手动执行器写入。
`modelFingerprint` 是最终输入 XML 字节的 SHA-256,不是语义哈希或所有 mesh 的合并内容哈希;资源另有 `source-manifest.json`。导出保留 `platform_robot_profile`、`platform_robot_profile_version`、`platform_robot_source_sha256`,并添加 `platform_robot_source_fingerprint` 追溯已加载源。重新序列化/导入会重新计算指纹;标记不是签名,也不能代替运行时校验。需要限定精确模型时设置插件的 `expected_model_fingerprint`。
## 停止、冻结与回滚
超过 500 ms 没有有效动作、观测过期、用户暂停/停止、控制者离线、页面隐藏/退出、模型替换都会撤销 lease/授权,清除待应用目标,停止轮目标、保持实测臂姿态并暂停。重新出现的 WS 事件也不能续期已经过期的租约;第一恢复物理步再次检查期限。心跳不等于新观测。
`authorizationGeneration` 隔离旧 release/stop/error/reset 的清理回调。新授权后迟到的旧消息不能把新 lease 清掉。reset 的 observation 序号在新 epoch 中可以从 1 重新开始;同 epoch 回退仍然拒绝。
浏览器 token 只在当前页面内存。本机 bearer token 不防已经获得 token 的本机恶意进程;不应开放到局域网/公网。详见 [桥接安全边界](../control_bridge/README.md)。
## 验证、性能与升级
- 普通 CI:合成单关节真实 SDK→桥接→浏览器 WASM;协议、身份、超时、队列和现有功能测试。不下载 LeKiwi,不安装 LeRobot。
- 独立 `lekiwi-compatibility` CI:固定资产 revision、固定 CPU 环境、实际上游发现/工厂、完整物理和工作台测试;依赖缺失即失败,不以 skip 通过。
- revision 4 工作台实测(本机 Ubuntu 24.04、WASM 3.11.0、SwiftShader):60.022 s / 1800 次动作,仿真推进约 59.636 s;整轮“观测→动作确认→诊断回读”平均 22.6 ms、P95 75.2 ms、最大 151.9 ms;最大观测仿真时间间隔 136 ms,超时/丢弃为 0。外控活跃样本的软件渲染平均约 4.90 FPS;绘制间累计物理耗时最高 139.6 ms,60 次采样中 59 次出现 `overBudget`(至少一次调度仍有待追帧时间),不能宣称无超预算或硬实时。热身后 JS 堆采样约 132.56 MiB、WASM 堆容量 564592640 字节,首末采样无增长。完整碰撞与 1 ms 步长比旧简化模型开销更大;500 ms 看门狗、8 ms/100 步调度预算不变,这不是跨机器性能保证。
- 专用测试记录逐秒 FPS、step budget、JS 堆、WASM 堆容量及实际机体移动。JSON、物理轨迹和截图输出到 `build/e2e/lekiwi/`;堆容量不等同于实际已用内存,60 秒稳定不等于长期无泄漏证明。
- revision 4 从整臂 18 个视觉网格(包括焊接舵机/附件)离线 CoACD 生成 538 个凸包,再按配合区边界切分成 1,220 个碰撞凸包,替代旧胶囊/手工分段,显式启用 5,581 对相邻结构接触。仅保留有几何边界的装配配合例外,不整对排除相邻 body。生成/缓存、固定依赖、来源/许可证与审核边界见 [碰撞数据说明](../robot_profiles/NOTICE.md)。
- `Mirror / Square` 回归使用实际可达的肩旋 0/±0.8 rad:肘目标 −1.3 rad 被挡在约 −0.07953 rad,接触点离轴约 71.8 mm(不是轴承锁死);峰值软穿入约 0.158 mm,稳定约 0.046 mm。反向到 +0.3 rad 后实测约 +0.29135,接触解除。
- 上臂/臂座组件测试中,安装板或肩部结构夹片先于 `Base_08q` 本体阻挡:抬升目标 +0.6 rad,实测约 +0.119(肩旋 0)/+0.243(肩旋 ±0.8);反向到 −0.3 后实测约 −0.2913、接触解除。完整几何下部分抬升/腕俯仰目标会提前遇阻;没有缩小声明的关节范围来隐藏问题。肩旋配合区跨边界凸包切分后,±0.942 rad 双向扫掠实测可达且无配合区接触,不再把轴承锁死冒充结构阻挡。
- 夹爪闭合/半开/全开的指间距约 1.47/41.10/64.88 mm,三者无指间穿入接触,张开空隙不误封堵;静态 16 mm 球体阻挡闭合,峰值软穿入约 0.320 mm、稳定低于 0.020 mm。间距使用独立三角面距离 oracle:WASM 3.11 的一次薄凸包 `mj_geomDistance` 查询返回零,但两见证点相距超过 50 mm,不能拿该零值作真实间距;没有为通过测试而改 solver 或放宽间隙断言。
- 另有原始 STL 六向极值的 108 次覆盖探针、六关节各两个目标(上下限的 60%)的 0.4 rad/s 扫掠及数值稳定性检查。这些是有限场景验证,不是全表面几何误差证明、所有关节组合的穷举、自动避障或可靠抓取保证。
- 浏览器真实物理包括 30 秒站稳、±0.1 m/s 两秒位移约 0.195–0.199 m、双向转动、臂/夹爪以及墙体阻挡;另外测试真实 PTY 键盘输入、Pyodide 旧回调、重载/缓存回滚、reset、崩溃、隐藏事件、CDP 暂停整个 JS 执行后恢复。
- 本次整臂回归:110 个文件 / 482 个 Vitest、7 个离线生成器单测;专用 LeKiwi 物理/插件/工作台 **14 个 E2E 全部通过,无跳过**,最终证据在 `build/e2e/lekiwi-full-collision-final/`。16 个桥接、19 个 LeRobot/键盘 Python 单测通过,命令见示例 README。旧普通浏览器与训练服务覆盖率记录不是本次重新执行结果,不混作当前碰撞验收。
- 已知限制:开发诊断强制注入严重重叠 qpos 后的原生几何查询曾触发 WASM 2 GiB 上限/中止;不是受支持的运动路径,未修复引擎对任意穿透初态的健壮性。正常入口已禁止 profile qpos 瞬移,不应把有限动态回归解释为任意姿态保证。详见碰撞数据说明。
- CI 配置增加隔离的离线分解重建检查;上述数字来自本机执行,不声称已运行远端 GitHub Actions。固定 revision 下载与本地参考目录重建得到相同 ZIP;wheel 已验证包含 canonical profile 和许可证。
升级上游/profile/依赖时:审查许可证与源码差异 → 更新 source hash/版本和映射 → 重建资产及 wheel → 跑跨语言 golden、真实物理、完整 60 秒及旧功能回归 → 更新约束文件、环境记录和 CHANGELOG。不要仅改版本号后绕过模型校验。
## 后续任务 / RL 层(尚未实现)
新增后端需要实现 `RobotAdapter` 的 describe/validateAction/applyAction/readObservation/safeStop/reset/dispose,使用可信代码显式注册;无需修改通用桥接。不要把可执行工厂放入用户导入 JSON。
在其上单独增加 task 层:原生 MuJoCo 后端、`step(action,n_substeps)`、seed/reset、reward/terminated/truncated、Gym wrapper,再做批量训练/策略部署。需要先验证原生与 WASM 的模型、单位、动作语义一致。当前实时浏览器 bridge 不能冒充确定性锁步或高吞吐训练环境。