Files
Mujoco_WASM/docs/mobile-manipulator.md
chenlin f3a8a38acd
web-platform-ci / Standalone decision service (no cloud credentials) (push) Has been cancelled
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
web-platform-ci / Standalone decision service (no cloud credentials) (pull_request) Has been cancelled
web-platform-ci / TypeScript, lint, unit, build (pull_request) Has been cancelled
web-platform-ci / Playwright E2E (pull_request) Has been cancelled
lekiwi-compatibility / cpu-compatibility (pull_request) Has been cancelled
feat: release v1.0.1 CADWorld 网站与 LeKiwi 智能抓放
集成同源 BYOK 会话隔离、精简模型设置、官方订阅入口和 HTTPS 发布运维;保留本地训练/调参与控制能力。同步 npm 版本及 CHANGELOG,记录公网真实 API 验收仍待用户凭据。
2026-09-24 09:57:41 +08:00

155 lines
17 KiB
Markdown
Raw Permalink 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.
# 可拔插移动操作环境(mobile-manipulator-v2)
统一训练入口:主工作台「控制台 → 强化学习任务」。独立 `/mobile.html` 产品页已移除;主工作台另有「LeKiwi 智能抓放」,见 [智能任务](lekiwi-agent.md)。物理/ONNX/训练底层与 `/physics/mobile.html` 夹具保留。服务配置及完整点击流程见 [训练服务](../training_server/README.md) 和 [统一训练面板](../web_platform/TRAINING.md)。
任务**复用现有加载器、MuJoCo WASM 与 Three.js 查看器**,不替换 Go2 任务、不授予外部控制桥训练 RPC。v2 控制、分阶段训练与评估说明见 [训练课程](mobile-training-curriculum.md);旧 v1 策略不能继续使用。
## 1. 分层与文件规划
| 层 | 文件 | 职责 |
| ------------- | ---------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
| A:描述与加载 | `contracts/mobile-robots-v1.json`、`web_platform/src/mobile/RobotDescriptor.ts` | 强类型 `RobotConfig`;名称绑定、限位、默认姿态、底座混合矩阵、夹爪与末端配置 |
| A:场景 | `web_platform/src/mobile/SceneComposer.ts` | URDF bundle 独立适配;已展开 MJCF 中加入物体、目标、地面和 EEF site |
| A:生命周期 | `web_platform/src/mobile/RobotManager.ts` | ZIP 导入、双槽 VFS、候选验证、查看器提交、失败回滚、策略失效及资源释放 |
| B:任务契约 | `contracts/mobile-manipulator-v2.json`、`web_platform/src/mobile/TaskKernel.ts` | 归一化、动作映射、阶段奖励、成功/超时;不依赖渲染和 ONNX |
| B:WASM 环境 | `web_platform/src/mobile/MobileManipulatorWasmEnv.ts` | `reset/observe/step`、编译后地址缓存、物理积分与交互状态重置;另导出别名 `InteractiveManipulatorEnv` |
| C:推理 | `web_platform/src/mobile/ONNXPolicyRunner.ts` | 单飞 ONNX、元数据和 SHA-256 校验、过期结果隔离、延迟指标 |
| C:交互 | `app/components/WorkspaceToolsPanel.tsx`、`mobile/agent/`、`TaskDragController.ts` | 主工作台 RL / 智能任务;拖动模块供保留的物理夹具使用 |
| Python | `training_server/mobile_manipulator/{kernel,env}.py` | 同公式的 Gymnasium 环境,加载浏览器导出的同一份 MJCF |
| Python | `training_server/mobile_manipulator/{train,export_onnx,validate_rollout}.py` | 可选 SB3 PPO 入口、PyTorch 导出及 ORT 校验、跨引擎短轨迹校验 |
现有组件仅增加小型接入点:
- `PhysicsAdapter.load()` 的 `sceneComposer` 在 URDF 转换/地图组合后展开 include,再组合任务场景;`configureRobotRuntime: false` 允许使用模型配方而不安装旧外控运行时。任务增加了第二个 freejoint,不能调用要求“唯一自由基座”的旧 LeKiwi 外控绑定。
- ZIP **继续复用现有 `fflate`**(功能等价于此处使用 JSZip),保留路径穿越/文件数/解压大小检查;`MemfsWorkspace` 负责 `FS.mkdirTree/writeFile/unlink/rmdir`。不增加第二套 VFS 或依赖。
- `MuJoCoViewer` 的可选 `advance(now)` 回调提供唯一物理时钟。设置它之后查看器**不再调用** `SimulationSession.advance()`,避免双重步进。
## 2. 机器人与适配边界
| 描述符 | 本次实际验证的 ZIP | 机械臂 |
| --------------- | ----------------------------------------------------------------- | -------------------------------------------------------------------------------- |
| `lekiwi-v1` | `build/lekiwi/lekiwi-v1.zip` | 原始五臂轴 + `arm_gripper`;复用已有来源校验、全臂凸包和被动滚子配方 |
| `lekiwi-bundle` | `../Reference_Projects/LeKiwi/New_urdf/robot_urdf_bundle (1).zip` | `Link1…Link4` + `arm_wrist_roll` + `arm_gripper`;独立配方,不冒充旧外控 profile |
验证资产 SHA-256:
- 原始 ZIP:`a10ac577ea49cdf87f324f3f6e9a7a887a1e3c0254ae638059711fef9e385b04`
- bundle ZIP:`f35734d3b4e3d6ef8399491987f50974476bfdd9d6c18506b915bcb9497f5752`
文件名不能证明机械结构相同;历史上同目录其他 ZIP/同名导出可能有不同活动轴。本次支持以上具体结构,**不自动把未知活动轴按顺序重命名**。
新 bundle 配方保留新臂的关节框架、惯性及四个有界关节的限位,给连续腕轴/夹爪补充仿真限位和伺服;替换超过 MuJoCo 面数上限的轮视觉,并构建理想化三全向轮/被动滚子。重复碰撞仅在同网格、同局部变换时去重。新臂接触使用 MuJoCo 原生凸包近似,**没有套用原臂的离线凸分解数据**。底盘质量、驱动增益、夹爪行程和 EEF 偏移是仿真估计,未实机标定。
扩展其他机器人:提供预先带执行器的 MJCF ZIP 和 `recipe: "mjcf"` 的 `RobotConfig`,通过 `RobotManager.loadZip()` 开发接口载入;独立页的自定义 JSON 上传控件不再提供。底层支持:
- 任意数量轮子,`baseMix[nwheel][3]` 定义车体坐标 `vx, vy, wz → wheel rad/s`;差速轮可令第二列为零。
- 1–8 个标量机械臂关节;每个 `mode` 可为 `position` 或 `velocity`。目前要求移动根为 freejoint,不支持固定底座或任意浮动关节参数化的自动推断。
- 多个夹爪执行器可指定各自 `joint` 和 `closed/open`;观测使用 `gripperJoint` 的行程比,主关节必须由匹配行程的执行器控制。
- 指定 `eefSiteName` 时,组合器在 `eefBodyName` 上按 `eefOffset` 加 site;未指定时直接使用 body 原点/姿态。
- 编译后校验关节类型/限位、执行器 transmission、gear、控制类型和 ctrlrange;不兼容则回滚。
固定接口只保证任务/UI 不随 DOF 改写,**不保证同一策略能跨机器人泛化**。8 轴以外或需力矩动作时应创建新版本契约,不能静默截断。
## 3. 数学契约
世界坐标为右手 Z-up;米、秒、弧度;四元数一律 **wxyz**。姿态四元数归一化并采用 `w >= 0` 的符号。所有观测限制在 `[-1,1]`。区间均为左闭右开。
### Observation:`Float32Array(92)` / ONNX `[1,92]`
| 区间 | 内容 |
| --------- | ------------------------------------------------------------ |
| `[0,3)` | 底座世界位置 / 2 m |
| `[3,7)` | 底座四元数 |
| `[7,10)` | 底座世界线速度 / 2 m/s |
| `[10,13)` | 底座世界角速度 / 4 rad/s(freejoint 局部角速度先转世界坐标) |
| `[13,21)` | 8 个臂角槽:`2*(q-min)/(max-min)-1`;无效槽为 0 |
| `[21,29)` | 臂关节速度 / 4 rad/s;无效槽为 0 |
| `[29,37)` | 臂槽 mask(有效为 1) |
| `37` | 夹爪行程比 `g` 映射为 `2*g-1` |
| `[38,45)` | EEF 世界位置 / 2 m + 四元数 |
| `[45,52)` | 物体相对 EEF 的位置 / 2 m + 四元数 |
| `[52,59)` | 物体相对目标的位姿(目标坐标系) |
| `[59,66)` | 目标世界位置 / 2 m + 四元数 |
| `66,67` | 已抓取抬升标记、当前阶段稳定计数 / 10 |
| `[68,80)` | 上次实际施加的归一化动作 |
| `[80,92)` | 积分控制目标状态:臂位置与夹爪开度归一化,其余槽为 0 |
相对位姿严格使用 `p_rel = R_parent^T*(p_object-p_parent)`、`q_rel = inverse(q_parent)*q_object`,不是仅减世界 XYZ。
### Action:`Float32Array(12)` / ONNX `[1,12]`
- `[0,3)`:归一化车体 `vx,vy,wz`,先经过共享契约速度/加速度限制再经 `baseMix` 转轮速;超过 `wheelLimit` 时**同比缩放所有轮速**。
- `[3,11)`:8 个臂槽。位置模式是积分目标的归一化增量速度,目标每步最多移动 `min(velocityLimit,0.5)*dt`,并限制跟踪误差;速度模式同样限幅。不存在的槽忽略。零动作保持目标,不再映射到全行程中点。
- `11`:归一化开合速度,+1 张开、-1 闭合、0 保持;开度每秒最多变化 0.5。
- 输入完整校验有限值后才写 ctrl;越界有限数裁剪;NaN/Infinity/尺寸错误拒绝,不部分写入。
控制步长 `0.02 s`(50 Hz);复用源模型物理 timestep(旧全凸包配方 1 ms,新 bundle 2 ms),必须整除控制步长。每个 step 在积分后调用 `mj_forward`,使观测不是上一个积分边界的派生位置。
### 奖励、终止
- `reach = dt * 0.1 * exp(-8 * distance(eef, object))`
- `lift = dt * 0.3 * clip((object.z - 0.019) / 0.08, 0, 1)`
- 当抬升达到 8 cm、末端距物体小于 9 cm、夹爪开度小于 0.4 时锁存 `hasLifted`。
- `transport = hasLifted ? dt * 0.5 * exp(-4 * distance(object, goal)) : 0`
- 以上抓放密集项按仿真时间积分(`dt=0.02`),上界为 18。v2 另有导航进展/距离/朝向项、动作变化率惩罚及关节速度惩罚,见共享契约与训练课程。
- 已抬升后,物体距目标小于 4 cm、线速度小于 0.05 m/s、夹爪开度大于 0.65、EEF 已撤离 9 cm,连续稳定 10 步才成功:一次性 `success=20`,`terminated=true`。
- 1000 步未成功则 `truncated=true`;结束后必须 reset。不存在自动焊接/吸附物体,搬运依赖实际物理接触。奖励中的抓取是近距/开度/抬升启发式,不是双指接触传感器的证明。
- 导航/末端接近阶段分别使用接近位驻留、末端驻留成功条件,不以抓放成功判断导航。任务训练顺序为 `navigate → reach → pick-place`。
- `info` 包含 `reward_components,is_success,stage,safety_stop,navigation_distance,max_joint_velocity`。物理子步实测关节超速、底盘倾倒/越界均失败终止。
TS `step()` 返回借用的同一对象,obs、raw-state、ctrl、action 缓冲全部复用;需要历史时由调用者复制。Python 返回独立 obs/info,避免 replay buffer 存到后续被覆盖的引用。两端奖励/观测/动作数学相同;引擎浮点求解不承诺长时间逐位一致。
## 4. 浏览器操作与集成
主工作台训练使用 `SimulationSession` + `MobilePolicyController`,在同一视口中组合任务场景并加载策略,不创建第二个物理步进所有者。
1. 在主工作台导入对应 ZIP,进入「控制台 → 强化学习任务」选择已注册变体,按训练服务流程同步场景、训练并导入 ONNX。
2. 「LeKiwi 智能抓放」仅支持固定 A,使用另一套具名 SI 契约和独立接触评估,不改 RL 92/12 契约。进入 RL 时会重新载入 RL 场景,不能把智能任务双支撑台直接冒充训练快照。
3. 地图草稿保留;智能任务只使用隔离的空旷平地预设,编辑地图使旧模型请求失效。任意机器人/训练后台作业不会因切换智能任务而被远程取消。
4. `RobotManager.loadZip(file, config, entryPath)`、`TaskDragController` 与 `moveTaskEntity()` 仍供开发/物理夹具使用,包括 Shift 拖动、状态重置和两变体资源回归;不再维护第二个产品网页。
`ONNXPolicyRunner` 要求固定 float32 `observation:[1,92] → action:[1,12]`、匹配 v2 task/robot/controlDt/动作语义/训练阶段,以及模型与 RobotConfig SHA-256。**不要格式化训练包里的 `robot.json`**,它的原始字节是导出指纹来源。它校验配置而不是所有网格字节;更改几何/动力学后必须从新场景重新训练和导出,不能只改标签绕过。
推理是单飞异步、固定仿真步长锁步:等待 ORT 时继续渲染,但不积分物理;下一次 rAF 消费动作后才生成下一观测。这避免“持续施加上次动作”造成训练端没有的动作延迟;代价是慢策略导致仿真时钟落后墙钟。计时累计有界,不在恢复后狂追补步。reset、拖动、模式切换、重载和 dispose 都使迟到推理结果失效;ORT 等待在途 run 结束后才 release。
## 5. 后台训练与自动导出
用户只需在统一面板点击开始训练。浏览器内部上传完整资产、组合后的 `*.training.xml`、`robot.json`、`task.json`、`environment.json`;服务器验证并保存快照,作业仅引用服务器 ID。Python **不再次转换 URDF**。内部 ZIP 只是传输格式,不要求用户下载、解压或运行 Python。
使用独立 MuJoCo 3.11.0 + SB3 解释器,通过训练服务 `--mobile-python` 配置;不要升级已有 Go2/LeRobot 环境。`allow_version_mismatch=True` 仅供底层诊断,服务训练不会启用此绕过。
任务设置包括阶段、接续作业、示教步数、随机化、独立评估回合,以及采样步数、迭代数、环境数、设备和种子。训练按种子扰动物体/目标 XY,部署保留名义初态;评估用不同种子。日志输出共用迭代/损失/平均奖励协议,取消覆盖训练、评估与导出整个进程组。自动导出固定 float32 `[1,92] → [1,12]` 并用原生 ORT 对5组输入比对 PyTorch;元数据包含控制语义、阶段、实际评估、权重/RobotConfig/场景 SHA-256。
阶段门槛和实测导航结果见 [训练课程](mobile-training-curriculum.md)。短程冒烟不是已收敛的抓取策略;尚未验证抓放收敛或跨机器人泛化。底层 `export_policy()`、`--smoke` 及 `RobotManager.exportTrainingBundle()` 仅保留给开发测试,不是用户训练流程。
## 6. 验证与性能边界
```bash
npm run typecheck
npm run lint
npm test -- web_platform/src/mobile
build/venvs/mobile/bin/python -m unittest training_server.tests.test_mobile_manipulator -v
npm run test:e2e:mobile
```
浏览器测试需要两个上述 ZIP;也可用 `MOBILE_BUNDLE_ZIP=/path/to/file.zip` 指定新包。缺少本地资产会明确 skip。测试包括真实模型动作、8 次交替切换、模型/data `isDeleted()`、VFS 数量、候选绑定失败回滚、真正的鼠标拖动;主工作台 UI 另由 `test:e2e:agent` 验收。产物在 `build/mobile-validation/`;测试用 `/physics/mobile.html` 不进入生产构建。
跨引擎回归与真实 ONNX 测试:
```bash
# 先运行浏览器测试产生 bundle-training.zip 和 rollout.json
python -m zipfile -e build/mobile-validation/bundle-training.zip build/mobile-validation/package
build/venvs/mobile/bin/python -m training_server.mobile_manipulator.validate_rollout \
--package build/mobile-validation/package --rollout build/mobile-validation/rollout.json
build/venvs/mobile/bin/python -m training_server.mobile_manipulator.export_onnx \
--package build/mobile-validation/package --smoke --output build/mobile-validation/smoke.onnx
npm run test:e2e:mobile
```
单元对齐另有 Python 生成的 40 组随机/旋转/饱和动作 golden,覆盖两个机器人;成功、重置、超时、速度模式、NaN 原子拒绝、生命周期和过期 ONNX 结果分别测试。重新生成:`python -m training_server.tests.generate_mobile_golden`,之后 Prettier 格式化 fixture。
内存注意:官方 JS 绑定通过 `MjData.delete()`、`MjModel.delete()` 执行原生析构;查看器的 mjvScene/GPU 资源必须先 detach,VFS 随后清理。共享 WASM 线性内存不会缩小,**不能用 heap 不下降判定泄漏**。仅释放 model/data 还不够:新路径会扩大原生资产缓存。管理器串行化加载,并交替复用两个独占 VFS 根目录;编译使共享 heap 增长后,旧环境在回滚/恢复屏障刷新 typed-array views。
以下为 v1 的历史性能基线,不作为 v2 策略验收结果:本机无头 Chromium 短测,8 次交替切换后 heap 在约 862 MiB 稳定(完整 CAD 配方开销很高),VFS 仅保留活动槽,旧 model/data 已删除。记录的是短期稳态检查,不是无限次泄漏证明。原生/WASM 3.11.0 的 12 步对照:原 LeKiwi 最大 qpos 误差约 `1.3e-15`、obs 无差异;新 bundle 最大 qpos 误差约 `6.1e-6`、obs `1.2e-6`;smoke ORT 最近推理约 `0.1 ms`、冷启动约 `4.5 ms`,不代表真实大策略延迟。精确本次数据以 `traces.json`、`onnx-metrics.json` 为准。
60 FPS 是渲染目标而非保证:策略推理、旧臂上千凸包接触、软件 WebGL、加载峰值都会影响墙钟速度。请在目标 GPU 上录制至少 60 秒 FPS/物理耗时/推理 P95/P99 与长时堆曲线;若需硬实时或低内存部署,应先降面/优化碰撞和将推理放 Worker,而不是跳过物理子步或放宽对齐公式。