13 KiB
13 KiB
Code Context
Files Retrieved
wasm/web_platform/src/simulation/SimulationSession.ts(lines 1-107)- 仿真步进、控制器生命周期、模型名称解析和mj_step前控制写入的核心集成点。wasm/web_platform/src/simulation/PhysicsAdapter.ts(lines 12-110)- UI 与 session 的稳定门面;模型切换、资源释放和 Go2-W URDF 增强发生于此。wasm/web_platform/src/app/App.tsx(lines 37-78, 100-105)- 工程导入、控制器状态、错误反馈、右侧栏 wiring。wasm/web_platform/src/app/components/SidebarPanel.tsx(lines 19-35)- 当前“控制”tab 仅嵌入 Python 控制器,是 ONNX 面板的最小 UI 插槽。wasm/web_platform/src/controller/PythonControllerRuntime.ts(lines 30-120)- 可复用的控制器生命周期/状态设计;同时揭示现有控制回调必须同步。wasm/web_platform/src/controller/types.ts(lines 1-42)- 当前状态被写死为language:'python',且 step API 可读关节、sensor、body quaternion。wasm/web_platform/src/project/importer.ts(lines 1-48, 184-223)- 所有二进制文件已原样进入 manifest,ONNX 无需进入模型 entry 发现逻辑。wasm/web_platform/src/project/types.ts(lines 1-41)- ProjectFile/大小上限;单文件允许 128 MiB、工程 512 MiB。wasm/package.json(scripts/dependencies)- 已有 Vitest/Playwright,尚无onnxruntime-web。wasm/web_platform/vite.config.ts(lines 1-27)- Pyodide 本地资产复制是 ORT wasm 离线资产处理的直接范例。wasm/src/go2_w_balance.py(lines 1-约480)- 仓库已有 Go2-W 手写 200 Hz 平衡/轮速控制,可作模型命名、IMU 和安全回退参考,但不是 RL 策略。/home/cen/Embodied_Workspace/unitree_rl_mjlab/deploy/robots/go2/config/policy/velocity/v0/params/deploy.yaml(lines 1-56)- 部署时序、动作变换及精确 observation 顺序。/home/cen/Embodied_Workspace/unitree_rl_mjlab/deploy/robots/go2/src/State_RLBase.cpp(lines 6-31)- 部署约定为params/deploy.yaml+exported/policy.onnx,输出经 action manager 处理后按 joint map 下发。/home/cen/Embodied_Workspace/unitree_rl_mjlab/src/tasks/velocity/config/go2/env_cfgs.py(lines 1-约160)- flat 任务移除 height scan,Go2 base 为base_link。
Key Code
已有正确插入顺序
SimulationSession.singleStep/advance 均执行:控制器 → 外力 → mj_step(SimulationSession.ts:46-57)。ONNX 动作必须沿用该位置,而不能在 React frame snapshot 后直接写 ctrl,否则会引入一物理步延迟和不稳定的渲染帧时序。
参考部署契约
Go2 deploy YAML 定义:
step_dt: 0.02,即策略 50 Hz;仿真步可保持 0.002 s,动作 hold 10 步。- observation 串接顺序和维数:
base_ang_vel(3), projected_gravity(3), velocity_commands(3), gait_phase(2), joint_pos_rel(12), joint_vel_rel(12), last_action(12),总计 47 float32。 - action 为 12 维位置目标:
processed = raw * 0.25 + default_joint_pos;默认位姿见 YAML lines 3-5/18-20。 - joint 顺序不能取 MuJoCo ID 偶然顺序;部署
joint_ids_map=[3,4,5,0,1,2,9,10,11,6,7,8]表示 RL 顺序与硬件/模型顺序存在显式重排。 - ONNX 与参数是配套件:
params/deploy.yaml+exported/policy.onnx(State_RLBase.cpp:12-16)。仅导入.onnx无法可靠解释 observation/action。
最小文件级实现方案(建议,不修改)
- 新增独立策略层:
src/policy/types.ts,OnnxPolicyRuntime.ts,Go2VelocityTask.ts。OnnxPolicyRuntime只负责 ORT session、输入/输出名称与 shape 校验、generation cancellation、dispose。Go2VelocityTask固化首个 task 的 47→12 契约、命令/phase/lastAction、名称到 joint/actuator 的显式映射、PD 目标或 position actuator 输出。- 不应把 ONNX 逻辑塞入
PythonControllerRuntime;其 Pyodide proxy 与同步函数假设完全不同。
SimulationSession.ts:将单一pythonController最小泛化为互斥 controller slot,或新增onnxPolicy并在同一个runController()中互斥调度;load/remove/reset/dispose 复用 generation 防模型切换竞态。添加只读 observation helpers(按 joint/body/sensor 名称解析),避免 UI 从 snapshot 拼向量。禁用/异常时必须ctrl.fill(0)、暂停并保留错误。- 异步风险处理:
onnxruntime-web的session.run()返回 Promise,不能直接 await 于当前同步advance()while loop。最小侵入方案是“最新完成动作 hold”:到 50 Hz 时复制 observation 发起一次推理(仅允许一个 in-flight),后续物理步继续持有上次动作,完成后原子替换;首帧保持安全默认位姿而非零力矩。状态须显示 inference latency/overrun。若要求训练等价的严格每 20 ms 动作,则需把物理 loop 改为异步/worker,已非最小侵入。 PhysicsAdapter.ts:接口新增loadOnnxPolicy(policyBytes, config),setPolicyEnabled,setVelocityCommand,removePolicy;MainThread adapter 只转发,模型releaseCurrent()自动 dispose。不要把 policy 写入 MuJoCo MEMFS,ORT 可直接吃Uint8Array。- 项目导入:
importer.ts已保留任意扩展名,ZIP/目录中的.onnx/.yaml会存在manifest.files;无需修改discoverEntries(它只应发现模型)。在 App 中按配套目录约定寻找exported/policy.onnx及params/deploy.yaml,首版更稳妥的是新增浏览器可直接解析的 JSON policy manifest;不要为 YAML 引入重量解析器后猜测任意训练配置。独立单文件导入应沿用 Python 的 upsert 流程,但 accept 改.onnx并施加专用上限。 - 依赖/构建:
wasm/package.json加onnxruntime-web;vite.config.ts仿照 Pyodide 将 ORT wasm 文件复制到固定相对目录并设置ort.env.wasm.wasmPaths,否则离线base:'./'构建容易 404。首版使用 wasm CPU 单线程,避免 WebGPU/COOP-COEP 扩大范围。 - UI:新增
PolicyPanel.tsx,插在SidebarPanel.tsx:32的控制 tab,与 Python 控制器并列;展示模型/config、47×12 shape、50 Hz、启停、速度 x/y/yaw、推理耗时/错误。App.tsx:40,55,72-77,104按现有 controller 状态模式增加 policy 状态及 callbacks;加载另一控制器时明确移除/禁用前一个,不能二者同时写 ctrl。 - 首个 Go2-W 任务边界:参考仓库提供的是 Go2 12-DOF velocity policy,不是 Go2-W policy;Go2-W 多四个轮关节。首版可把 12 个腿关节按该 policy 控制、轮 actuator 固定阻尼/零速,仅称“Go2-W 腿式站立/速度实验”,不能宣称与训练分布一致。真正轮式平衡/速度需要 Go2-W 专属训练导出(observation/action 很可能含轮速和 16 维动作)。
Architecture
浏览器文件 → ProjectManifest.files(二进制 ONNX 已保留)→ App 选择配套 policy/config → PhysicsAdapter → SimulationSession 拥有 policy runtime。每个 MuJoCo 子步前 task 从 MjData 组 observation;每 0.02 s 异步提交 ONNX,完成输出经 scale/offset、显式 joint mapping 和限幅后成为 held action;物理 loop 每步应用 held action。snapshot 仅向 UI报告状态,不作为 observation 数据源。
观测/动作风险与严重度
- blocker:参考资产无 Go2-W ONNX,且仓库参考目录下 Go2 velocity 的
exported/policy.onnx实际不存在;不能验证 input/output 名或数值一致性。 - blocker:Go2 12-DOF policy 与 Go2-W 16 actuator 拓扑不匹配。若按
model.njnt/nactuator顺序拼接会 shape 错误或静默错控。 - high:
projected_gravity必须是重力单位向量由世界系旋到 body/IMU 局部系。MuJoCoxquat为 wxyz;符号、quat inverse、IMU 安装姿态任一错误都会使策略立刻摔倒。加速度计并不等价于无噪声 projected gravity。 - high:
base_ang_vel需 body/local frame;直接使用 free jointqvel[3:6]或 gyro sensor前必须确认 MuJoCo sensor frame与训练定义一致。 - high:
joint_pos_rel = q-default,joint_vel 和 action 都必须是 YAML 的 RL 顺序;四足 FL/FR/RL/RR 次序在当前手写 Go2-W controller 与 deploy map 中并不天然一致。 - high:输出是 normalized action,不是 torque;必须 scale+offset 后交给 position actuator/PD。当前
setActuator只写 ctrl,URDF 自动生成的是 motor(PhysicsAdapter.ts:68),因此若直接写位置值会被当 N·m。需要 task 内 PD torque,或为该 task 构造 position actuator。 - medium:gait phase 是 0.6 s 周期的 sin/cos,但应确认零点、sin/cos 顺序以及站立零命令时是否冻结;YAML 没编码完整函数语义。
- medium:异步 ORT latency 若超过 20 ms 会跳过策略 tick;必须统计 dropped/late inference,且避免并发堆积。
- medium:reset 应同时清 lastAction、phase、in-flight generation 和 held action;否则旧 Promise 可污染新 episode。
- medium:导入不可信 ONNX 可能造成大内存/计算消耗;现有 128 MiB 文件上限不足以约束 tensor shape/运行时内存。
测试建议
src/policy/Go2VelocityTask.test.ts:固定 qpos/qvel/quaternion/command,逐元素断言 47 维顺序、dtype、projected gravity、phase、joint reorder;固定 raw action 断言*0.25+offset和 actuator 映射。src/policy/OnnxPolicyRuntime.test.ts:mock ORT,覆盖 input/output shape/name 错误、NaN/Inf、single-flight、超时/overrun、generation cancellation、dispose;用极小 identity ONNX fixture 做一次真实 wasm smoke test。- 新增
SimulationSession.test.ts(当前该核心类无测试):mock MainModule 验证 controller 在mj_step前执行、50 Hz decimation、held action、reset/disable/error 清 ctrl、Python/ONNX 互斥、模型切换后旧推理无效。 PhysicsAdaptercontract test:load/remove/dispose 转发及失败后 workspace/runtime 都释放。importer.test.ts:ZIP/目录保留.onnx与 config、路径规范化、重复/超限拒绝;entry discovery 不把 ONNX 当模型。PolicyPanel.test.tsx+SidebarPanel测试:导入、启停、命令范围、shape/错误展示、另一控制器启用时互斥。- Playwright:导入 Go2-W 工程+fixture policy,启用后推进若干秒,断言页面不崩、policy 状态与命令变化;数值验收应另做离线 golden trajectory(相同初态前 N 次 observation/action 与 Python/ORT reference 对齐),容差逐元素约
1e-5,并检查 base height/倾角安全阈值。 - 常规命令:
npm run typecheck:platform,npm run lint:platform,npm run test:platform,npm run build:platform, 最后npm run test:e2e:platform。
Start Here
先打开 wasm/web_platform/src/simulation/SimulationSession.ts:44-93:这是唯一能保证 observation 采样、控制输出和 mj_step 顺序正确,并统一 reset/error/dispose 语义的位置。
Residual Risks
- 未获得 Go2-W 专属 ONNX 与导出 metadata,无法完成真实 shape/name/golden 验证。
- unitree_rl_mjlab 的 YAML 说明字段顺序与缩放,但 gait phase、frame convention 等函数语义仍需用实际导出/运行器确认。
- 主线程异步 inference 的 held-action 方案是最小侵入折衷,不提供硬实时或训练环境严格等价。
{
"criteriaSatisfied": [
{
"id": "criterion-1",
"status": "satisfied",
"evidence": "已给出 SimulationSession、PhysicsAdapter、App/Sidebar、导入与测试结构的具体文件/行范围方案,并按 blocker/high/medium 列出观测动作风险。"
}
],
"changedFiles": [],
"testsAddedOrUpdated": [],
"commandsRun": [
{
"command": "find/grep/read/nl(只读仓库与 unitree_rl_mjlab 参考配置)",
"result": "passed",
"summary": "确认现有控制步序、项目导入行为、测试布局及 Go2 deploy 的 47维观测/12维动作约定。"
}
],
"validationOutput": [
"参考 deploy.yaml: step_dt=0.02,观测 3+3+3+2+12+12+12=47,动作 12,scale=0.25。",
"参考部署约定为 params/deploy.yaml + exported/policy.onnx;当前 Go2 目录未发现实际 ONNX。",
"当前仓库 package dependencies 未包含 onnxruntime-web。"
],
"residualRisks": [
"缺少 Go2-W 专属 ONNX/metadata,参考仅为 Go2 12-DOF。",
"异步浏览器 ORT 与同步物理 loop 存在时序折衷。",
"projected gravity、角速度 frame、joint mapping 必须做 golden 对齐。"
],
"noStagedFiles": true,
"diffSummary": "只读分析;未修改仓库文件,仅写入指定 context.md 报告。",
"reviewFindings": [
"blocker: /home/cen/Embodied_Workspace/unitree_rl_mjlab/deploy/robots/go2 - 未发现 Go2 velocity policy.onnx,无法验证模型 I/O。",
"blocker: deploy.yaml:1-56 - 参考策略为 12-DOF Go2,与 Go2-W 16 actuator 不匹配。",
"high: wasm/web_platform/src/simulation/SimulationSession.ts:49-57 - 同步物理 while loop 无法直接 await ORT Promise。",
"high: wasm/web_platform/src/simulation/PhysicsAdapter.ts:68-70 - URDF 自动生成 motor,normalized position action 不可直接写 ctrl。"
],
"manualNotes": "报告已写入权威路径;除 context.md 外未改动项目。"
}