129 lines
8.4 KiB
Markdown
129 lines
8.4 KiB
Markdown
# 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 外力拖拽
|
||
- 导入单文件 `.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`。
|
||
|
||
## Python 控制器
|
||
|
||
Python 控制器是可信的单文件脚本,必须同步定义 `step(ctx, state)`;可选定义 `NAME`、`CONTROL_HZ`(限制为 1–500 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/slide;ball/free joint 只读。
|
||
- MuJoCo WASM 本身不支持 DAE mesh。平台会移除 DAE visual,并以 collision 几何显示;DAE collision 会替换为半径 0.05 m 的占位球体并在界面警告。高精度仿真应先将 DAE 转为 OBJ/STL 或改为 URDF primitive。
|
||
- 导入工程只存在当前页面内存,刷新页面后需重新导入。
|