Files
Mujoco_WASM/web_platform/README.md
T
chenlin 3b4ced6437
web-platform-ci / TypeScript, lint, unit, build (push) Has been cancelled
web-platform-ci / Playwright E2E (push) Has been cancelled
feat(web-platform): release V0.7 地图模块
2026-09-01 14:23:49 +08:00

165 lines
12 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.
# MuJoCo Web 仿真平台
基于 MuJoCo 官方 `@mujoco/mujoco` JavaScript/WASM 包的中文桌面仿真平台。物理引擎使用默认单线程入口,模型和资源只写入浏览器内的 Emscripten MEMFS,不上传到服务器。
## MVP 功能
- 导入单个/多个 MJCF(XML)、URDF 和关联资源
- 兼容常见 ROS URDF:规范化重复 material、解析 `package://` 工程内资源路径
- URDF 导入时可选为 hinge/slide 关节生成 motor 驱动器,并可用 kp/kv 调整对应 MJCF 关节刚度与阻尼,并将可调位置/朝向的摄像头固连到指定机器人 Body
- 导入保留相对路径的文件夹或 ZIP 工程
- 多模型入口选择、中文加载和编译错误
- Three.js primitive、mesh、材质/贴图显示与对象选择
- 播放、暂停、单步、重置、0.25×–4× 速度
- actuator 滑杆、hinge/slide 关节拖动、动态 body 外力拖拽
- 内置平地、坡道、楼梯、可复现随机障碍物及 9 类系统参数化地形,可配置尺寸、摩擦、难度、种子与高度场采样精度
- 导入单文件 `.py` 控制器,通过本地 Pyodide 在 `mj_step` 前按仿真时间同步执行
- 导入 mjlab 导出的 `policy.onnx`,在浏览器本地执行 Go2-W 平衡/速度策略推理
- 从图形界面向本机训练桥接服务发起 mjlab 强化学习训练、查看进度/日志、停止任务并导入训练生成的 ONNX
- FPS、物理耗时和主线程步进预算提示
## 开发
从仓库根目录运行:
```bash
npm install
npm run dev
```
打开 Vite 输出的 HTTP 地址。应用**不支持**通过 `file://` 直接打开,也不注册 Service Worker/PWA。
## 质量检查
```bash
npm run typecheck
npm run lint
npm test
npm run build
npm run test:e2e
# 或执行除 E2E 外的完整检查
npm run check
```
E2E 默认使用系统安装的 Google Chrome。若没有 Chrome,可修改 `playwright.config.ts` 或运行 `npx playwright install chromium` 后移除 `channel: 'chrome'`
## 生产构建与本地静态部署
```bash
npm run build
python3 -m http.server 8080 --directory web-platform-dist
```
访问 <http://127.0.0.1:8080/>。构建使用 `base: './'`,可部署到任意静态子目录。静态服务器需将 `.wasm` 返回为 `application/wasm`Python 3.11+、Vite preview、Nginx 等常见服务器均支持。
## 工程导入约定
- 文件夹和 ZIP 中必须至少有一个根元素为 `<mujoco>``<robot>``.xml`/`.urdf`
- 只有一个入口时自动加载;多个入口优先根目录 `model.xml``scene.xml` 或唯一 URDF,否则弹窗选择。
- XML 的 `include`、mesh 和贴图路径必须相对于入口/编译器配置可解析。
- 路径穿越、绝对路径、加密 ZIP、重复路径会被拒绝。
- 默认限制:2000 个文件、单文件 128 MiB、总解压大小 512 MiB、ZIP 文件 128 MiB。
- 文件夹或 ZIP 中的 `.py` 会显示在“控制 → Python 控制器”;也可以在加载模型后单独导入不超过 1 MiB 的 `.py`
## 地图模块
模型加载后打开右侧“地图”标签,可以选择平地、坡道、楼梯、随机障碍物、系统参数化地形或工程内地图包。参数化地形包括离散障碍、沟壑、倒金字塔阶梯、深坑、金字塔阶梯、轨道、随机粗糙、踏石和波浪地形;相同参数与随机种子会确定性生成相同碰撞层。点击“应用并重新编译”后,平台会在当前入口同目录生成临时组合 MJCF;原始工程文件不会被修改。模型编译失败时保留上一个可用仿真会话。
工程地图由 `map.json`、静态 MJCF 碰撞层和可选的自包含 GLB 视觉层组成:
```text
maps/warehouse/
├── map.json
├── physics/world.xml
├── physics/meshes/*.obj
├── visuals/scene.glb
└── authoring/map.scene.json # V3 可选创作层
```
最小描述示例:
```json
{
"schemaVersion": 1,
"id": "warehouse",
"name": "仓库",
"coordinateSystem": { "units": "m", "up": "Z", "forward": "+X" },
"physics": { "source": "physics/world.xml" },
"visual": { "source": "visuals/scene.glb" },
"spawnPoints": [{ "id": "main", "name": "主入口", "position": [0, 0, 0.35], "yawDeg": 0 }]
}
```
物理地图仅允许静态 `worldbody` 以及 mesh、heightfield、texture、material 等基础 asset,不允许 joint、mocap body、actuator、sensor、include 或 default class。OBJ/STL 应使用简化碰撞模型;高精度模型只放入 GLB。GLB 必须是 2.0 自包含文件,外部 URI 会被拒绝。地图统一使用米制、Z-up、+X 前向坐标系。
V3 可编辑地图使用 `schemaVersion: 2`,并增加 `"authoring": { "source": "authoring/map.scene.json" }`。创作层支持方盒、圆柱、胶囊、坡道、楼梯和出生点。“场景 · 资产库”中的认证资产可点击添加或拖到画布落位;没有可编辑地图时,首个资产会立即创建 Schema V2 场景草稿,不触发 MuJoCo 重编译。新增对象支持三种放置方式:自动贴地、沿世界 `-Z` 落到最高静态承载面的自动重力落位,以及禁止位姿编辑的锁定模式。只有点击“应用并重新编译”后才提交物理层。可以通过表单或视口 TransformControls 修改位置、绕 Z 轴旋转和原语尺寸,支持移动/旋转吸附、视口拾取、复制、删除及对齐地面;`W`/`E`/`S` 切换移动、旋转和缩放工具,`Delete` 删除,`Ctrl+Z`/`Ctrl+Y` 撤销重做。编辑只更新 Three.js 草稿预览,点击编辑器内“应用并重新编译”后才生成确定性的静态 MJCF。失败时保留旧仿真和草稿。浏览器不会直接写回原目录,可使用“导出地图 ZIP”下载当前已提交地图包。没有 `authoring.source` 的 V1/V2 地图默认只读;仅由 `box``cylinder``capsule` 构成且不含 asset、材质、碰撞过滤或隐藏姿态语义的静态 MJCF,可通过“创建可编辑副本”显式升级。转换会生成 `authoring/map.scene.json`、Schema V2 描述和确定性物理层;任何不可逆语义都会导致整体拒绝,不会静默丢失内容。
物理地图超过 2000 个 geom 会产生性能警告,超过 10000 个会被拒绝;GLB 超过 100 万三角面会警告,超过 300 万会被拒绝。当前原生 URDF 模式不支持地图,请切换到“转换为 MJCF”。
## Python 控制器
Python 控制器是可信的单文件脚本,必须同步定义 `step(ctx, state)`;可选定义 `NAME``CONTROL_HZ`(限制为 1500 Hz)、`init(api)``command(name, state)``reset(state)``dispose(state)``init` 可用 `api.joint(name)``api.actuator(name)``api.sensor(name)``api.body(name)` 预解析 ID`step` 可用 `ctx.qpos(id)``ctx.qvel(id)``ctx.sensor(id)``ctx.body_quat(id)``ctx.body_position(id)` 读取状态,并用 `ctx.set_control(id, value)` 写入经过有限值检查和 actuator 限幅的控制量。定义 `command` 后,界面会显示停止、前进、后退、左转、右转和起跳按钮,并分别传入 `stop``forward``backward``turn_left``turn_right``jump`。所有回调都必须同步;异常会自动停止控制器或显示诊断,运行期异常还会暂停仿真并清零 `ctrl`
当前 Python 与 MuJoCo 都运行在主线程,以保证闭环调用严格位于 `mj_step` 前。仅运行可信脚本;死循环仍可能阻塞页面。Pyodide 及 Python 标准库由 npm 包随生产构建离线发布,不从 CDN 下载;暂不支持第三方 Python 包、`pip` 或多文件 import。
## 本地强化学习训练
训练仍由本机 Python/mjlab 进程执行,但可以从右侧“控制 → 本地强化学习训练”直接发起和管理。先使用安装了 mjlab、PyTorch 及训练依赖的 Python 启动本地桥接服务:
```bash
npm run training-server -- \
--trainer-root /path/to/unitree_rl_mjlab \
--trainer-python /path/to/training-env/bin/python
```
服务启动时会在终端输出一个随机访问令牌;在界面中填写该令牌后连接。令牌仅保存在当前标签页的 `sessionStorage`。界面默认连接 `http://127.0.0.1:8765`,可选择服务端允许的任务、并行环境数、训练迭代、随机种子、CPU/GPU、GPU 编号和实验记录方式。W&B 默认为本地离线模式,无需登录或 API Key;也可完全禁用,只有明确选择在线模式时才会联网登录。训练期间页面轮询迭代进度与最近日志,可以停止任务;训练成功后点击“导入策略”,生成的 `policy.onnx` 会进入现有 ONNX 加载流程。
桥接服务只监听本机回环地址,并检查 Host、Origin 和 Bearer Token;仅接受允许列表中的任务和经过范围校验的参数,不执行前端提供的 Shell 命令;一次只运行一个训练进程。当前任务使用 `unitree_rl_mjlab` 自带的机器人资产与环境配置,**不会自动把浏览器中临时编辑的 MJCF/URDF 作为训练环境**。自定义浏览器模型训练需要先在 mjlab 中注册对应 task。服务配置、接口和安全边界见 [`../training_server/README.md`](../training_server/README.md)。
## ONNX 强化学习策略
当前内置任务兼容 `unitree_rl_mjlab` Go2 velocity 的部署观测顺序:
```text
base_ang_vel(3) + projected_gravity(3) + velocity_command(3)
+ gait_phase(2) + joint_pos_rel(12) + joint_vel_rel(12) + last_action(12)
= 47 维观测
```
策略必须具有一个 `float32` 输入和至少一个 `float32` 输出,输入末维为 47、输出末维为 12。动作按 `FL、FR、RL、RR` 的 hip/thigh/calf 顺序解释,转换为 `default_joint_pos + 0.25 * action` 的关节目标。对于 motor 模型,平台使用与部署配置一致的 kp/kd 执行位置 PD;对于 position actuator,直接写入目标位置。Go2-W 的四个轮电机在此首版腿式策略中保持零力矩。
使用步骤:
1. 导入浮动基座 Go2-W MJCF/URDF,确保腿部关节与 actuator 使用 Unitree 标准命名;
2. 打开右侧“控制 → ONNX 强化学习策略”;
3. 从工程中选择或单独导入 `policy.onnx`
4. 加载策略,设置前向、侧向和偏航速度,启用策略后播放仿真。
ONNX Runtime Web 的推理接口是异步的。物理循环会在每个 `mj_step` 前持续施加最近一次已完成的动作,并以 50 Hz 提交新观测;界面会显示推理耗时和次数。ONNX 与 Python 控制器互斥,启用其中一个会停止另一个。
> [!IMPORTANT]
> 当前内置契约是参考 mjlab Go2 的 12 腿关节策略,不是包含四个轮电机动作的 16 自由度 Go2-W 专用策略。若训练 Go2-W 轮式策略,需要后续同时扩展训练端部署配置和浏览器任务清单,确保观测、动作及归一化完全一致。
## 示例
`fixtures/` 包含(用于测试和手工验收,不会打进生产构建):
- `mjcf_include/`MJCF include、OBJ/STL mesh 和 PNG texture
- `urdf_mesh/`:引用 OBJ 的 URDF
- `python_controller/`:倒立摆模型及 `balance.py` PD 控制器;
- `invalid.xml`:无效模型;
- `missing-resource.xml`:缺失资源错误示例。
在“打开文件夹”中选择夹具目录即可加载。
## 当前限制
- 仅面向桌面版 Chrome、Edge、Firefox;未适配手机和平板。
- 物理运行在主线程、单线程 WASM。超出每帧预算时限制追帧并提示。
- ONNX Runtime Web 当前使用单线程 WASM;策略必须将观测归一化包含在导出的 ONNX 图内,平台不会额外加载训练 checkpoint 的运行均值。
- 不支持 Xacro、账号或云端保存;Python 控制器暂不支持第三方包和不可信代码隔离。
- 关节拖动只支持 hinge/slideball/free joint 只读。
- MuJoCo WASM 本身不支持 DAE mesh。平台会移除 DAE visual,并以 collision 几何显示;DAE collision 会替换为半径 0.05 m 的占位球体并在界面警告。高精度仿真应先将 DAE 转为 OBJ/STL 或改为 URDF primitive。
- 导入工程只存在当前页面内存,刷新页面后需重新导入。