liyang aed6e20a90 双臂操作沙盒(MuJoCo WASM 浏览器版)首次入库
从 ~/mujoco-web-spike 抽出 manip.html 的依赖闭包:
- manip.html + src/{manip,autograsp,scene-bridge,math}.js
- scenes/so101_pair(桌面并排两台 SO-101,默认)与 scenes/p7_bimanual(P7 双臂 + SO-101 夹爪)
  —— 自包含 MJCF,网格已内联
- serve.py(COOP/COEP + no-store 的静态服务器)、start.sh、README
- tools/export_manip_scene.py 场景生成脚本(仅供参考,跑页面不需要)

快照对应 2026-08-31 的最后一次改动(自动抓取规划 autograsp.js 落地版)。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016tgfYxR5mWNRKQ67PKga4T
2026-09-01 17:16:41 +08:00

双臂操作沙盒(浏览器 WASM 版)

~/mujoco-web-spike 抽出来的自包含子集:只含 manip.html 跑起来需要的文件。 物理引擎是 MuJoCo 的 WASM 构建,全部在浏览器里运行,服务器只负责发静态文件。 版本快照:2026-08-31 最后一次改动(自动抓取规划 autograsp.js 落地那一版)。

启动

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 构建,浏览器只在"跨源隔离"页面里放开 SharedArrayBufferhttp.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/.venvmujoco、numpy、tyro+
                              linker-sim 资产库 + SO-101 MJCF,跑页面不需要它

完整项目(其它页面 arm/sort/policy/urdf 等)仍在 ~/mujoco-web-spike,本包只是双臂抓取这一条线。

S
Description
No description provided
Readme 2.3 MiB
Languages
JavaScript 44.1%
HTML 31.9%
Python 23.7%
Shell 0.3%