# 双臂操作沙盒(浏览器 WASM 版) 从 `~/mujoco-web-spike` 抽出来的**自包含**子集:只含 `manip.html` 跑起来需要的文件。 物理引擎是 MuJoCo 的 WASM 构建,全部在浏览器里运行,服务器只负责发静态文件。 版本快照:2026-08-31 最后一次改动(自动抓取规划 `autograsp.js` 落地那一版)。 ## 启动 ```bash tar xzf wasm-bimanual-grasp-20260901.tar.gz cd wasm-bimanual-grasp-20260901 python3 serve.py 8000 # 或 ./start.sh 8000 ``` 然后用 **Chrome / Edge** 打开: | 场景 | 地址 | |---|---| | 默认:桌面上并排两台 SO-101(5 自由度臂 + 二指夹爪) | http://127.0.0.1:8000/manip.html | | P7 双臂工作站,末端换成 SO-101 夹爪(7 自由度臂) | http://127.0.0.1:8000/manip.html?scene=p7_bimanual | 首屏会依次显示「载入 MuJoCo WASM → 下载场景 → 编译 MJCF」,编译要几秒(网格已内联, so101_pair 1.8 MB / p7_bimanual 5.3 MB)。 ### 环境要求 - **Python 3**(只用标准库 `http.server`,不需要 venv、不需要 pip 装任何东西) - **能上网**:three.js 0.170.0 和 `@mujoco/mujoco` WASM 都从 jsDelivr CDN 拉,断网会白屏 - **桌面版 Chrome / Edge**:页面用到 SharedArrayBuffer(多线程 WASM), `serve.py` 已经发好 `Cross-Origin-Opener-Policy` / `Cross-Origin-Embedder-Policy` 两个头 ### 为什么不能直接 `python3 -m http.server` 可以起来,但页面会**卡在「初始化 MuJoCo…」不报错也不动**—— `@mujoco/mujoco` 是 pthread 构建,浏览器只在"跨源隔离"页面里放开 SharedArrayBuffer, 而 `http.server` 不发那两个头。`serve.py` 就是 `http.server` + 这两个头 + `Cache-Control: no-store` (ES 模块缓存极死,改了 `src/*.js` 普通刷新照样跑旧代码,所以开发期一律不缓存)。 ## 页面怎么用 - **拖动物体**(鼠标直接拖桌上的易拉罐/瓶子/罐子/玩具琴/玩偶)→ 右侧实时出**判定卡**: 自动选哪只臂、下爪方向罗盘、左右两臂 IK 残差并排;两臂都够不着会明确给出「不可抓」 - **自动抓取** 按钮:按判定结果执行 抵近 → 预收爪口 → 下探 → 合爪 → 抬升;**中止** 随时停 - **手动模式**:选 左臂/右臂 → `X± Y± Z±` 步进末端 → 朝向约束(朝下/朝前/不约束)→ 张开/夹紧 - 物体面板可改**位置和重量**,点 **应用** 生效(运行时改 `body_mass`,不重编译) - **抓放记录**:物体离抓取点 < 9 cm 且高于原位 5 cm 并保持 0.5 s = 抓取成功; 松手后静止落在台面 = 放置成功;掉到台下 = 失败 ## 已知状态(08-31 实测) - 判定侧 6/6 准确(含正确拒绝够不着的情况) - 执行侧 **3/5**:立着的易拉罐、罐子、玩偶稳定成功;**躺倒的瓶子和玩具琴还抓不住**。 根因是二指爪全开时爪尖比爪中点低 2.6 cm,下探先顶到桌面;已加「按物体宽度预收爪口」 但仍不够,尝试过的三种夹持点选择策略都没救回来,细节见 `src/autograsp.js` 顶部注释 - **切到别的标签页仿真会暂停**(浏览器对后台标签的 rAF 节流),抓取过程中别切走 - `@mujoco/mujoco` 走的是 CDN 上的 `+esm` 最新版(打包时 jsDelivr latest = 3.12.0), 没有钉版本;如果哪天 CDN 升级后页面报 `xxx is not a function`,先把 `manip.html` 里的 `@mujoco/mujoco/+esm` 改成 `@mujoco/mujoco@3.12.0/+esm` 试 ## 文件 ``` manip.html 页面 + 启动编排(渲染、UI、事件) serve.py 静态服务器(COOP/COEP + no-store) start.sh python3 serve.py 的包装,顺带打印地址 src/manip.js ArmController(阻尼最小二乘 IK、零空间次要目标)、GraspMonitor(抓放判定) src/autograsp.js GraspPlanner:拖动后实时判定选臂/下爪方向,自动抓取状态机 src/scene-bridge.js MuJoCo mjModel/mjData → three.js 网格与每帧位姿 src/math.js 旋转矩阵 → 四元数 scenes/so101_pair/ 默认场景:model.xml(自包含 MJCF)+ meta.json(臂/爪/物体索引) scenes/p7_bimanual/ P7 双臂场景,同上 tools/export_manip_scene.py ★ 仅供参考:生成上面两个场景的脚本, 依赖 ~/unitree_rl_mjlab/.venv(mujoco、numpy、tyro)+ linker-sim 资产库 + SO-101 MJCF,跑页面不需要它 ``` 完整项目(其它页面 arm/sort/policy/urdf 等)仍在 `~/mujoco-web-spike`,本包只是双臂抓取这一条线。