集成同源 BYOK 会话隔离、精简模型设置、官方订阅入口和 HTTPS 发布运维;保留本地训练/调参与控制能力。同步 npm 版本及 CHANGELOG,记录公网真实 API 验收仍待用户凭据。
17 KiB
可拔插移动操作环境(mobile-manipulator-v2)
统一训练入口:主工作台「控制台 → 强化学习任务」。独立 /mobile.html 产品页已移除;主工作台另有「LeKiwi 智能抓放」,见 智能任务。物理/ONNX/训练底层与 /physics/mobile.html 夹具保留。服务配置及完整点击流程见 训练服务 和 统一训练面板。
任务复用现有加载器、MuJoCo WASM 与 Three.js 查看器,不替换 Go2 任务、不授予外部控制桥训练 RPC。v2 控制、分阶段训练与评估说明见 训练课程;旧 v1 策略不能继续使用。
1. 分层与文件规划
| 层 | 文件 | 职责 |
|---|---|---|
| A:描述与加载 | contracts/mobile-robots-v1.json、web_platform/src/mobile/RobotDescriptor.ts |
强类型 RobotConfig;名称绑定、限位、默认姿态、底座混合矩阵、夹爪与末端配置 |
| A:场景 | web_platform/src/mobile/SceneComposer.ts |
URDF bundle 独立适配;已展开 MJCF 中加入物体、目标、地面和 EEF site |
| A:生命周期 | web_platform/src/mobile/RobotManager.ts |
ZIP 导入、双槽 VFS、候选验证、查看器提交、失败回滚、策略失效及资源释放 |
| B:任务契约 | contracts/mobile-manipulator-v2.json、web_platform/src/mobile/TaskKernel.ts |
归一化、动作映射、阶段奖励、成功/超时;不依赖渲染和 ONNX |
| B:WASM 环境 | web_platform/src/mobile/MobileManipulatorWasmEnv.ts |
reset/observe/step、编译后地址缓存、物理积分与交互状态重置;另导出别名 InteractiveManipulatorEnv |
| C:推理 | web_platform/src/mobile/ONNXPolicyRunner.ts |
单飞 ONNX、元数据和 SHA-256 校验、过期结果隔离、延迟指标 |
| C:交互 | app/components/WorkspaceToolsPanel.tsx、mobile/agent/、TaskDragController.ts |
主工作台 RL / 智能任务;拖动模块供保留的物理夹具使用 |
| Python | training_server/mobile_manipulator/{kernel,env}.py |
同公式的 Gymnasium 环境,加载浏览器导出的同一份 MJCF |
| Python | training_server/mobile_manipulator/{train,export_onnx,validate_rollout}.py |
可选 SB3 PPO 入口、PyTorch 导出及 ORT 校验、跨引擎短轨迹校验 |
现有组件仅增加小型接入点:
PhysicsAdapter.load()的sceneComposer在 URDF 转换/地图组合后展开 include,再组合任务场景;configureRobotRuntime: false允许使用模型配方而不安装旧外控运行时。任务增加了第二个 freejoint,不能调用要求“唯一自由基座”的旧 LeKiwi 外控绑定。- ZIP 继续复用现有
fflate(功能等价于此处使用 JSZip),保留路径穿越/文件数/解压大小检查;MemfsWorkspace负责FS.mkdirTree/writeFile/unlink/rmdir。不增加第二套 VFS 或依赖。 MuJoCoViewer的可选advance(now)回调提供唯一物理时钟。设置它之后查看器不再调用SimulationSession.advance(),避免双重步进。
2. 机器人与适配边界
| 描述符 | 本次实际验证的 ZIP | 机械臂 |
|---|---|---|
lekiwi-v1 |
build/lekiwi/lekiwi-v1.zip |
原始五臂轴 + arm_gripper;复用已有来源校验、全臂凸包和被动滚子配方 |
lekiwi-bundle |
../Reference_Projects/LeKiwi/New_urdf/robot_urdf_bundle (1).zip |
Link1…Link4 + arm_wrist_roll + arm_gripper;独立配方,不冒充旧外控 profile |
验证资产 SHA-256:
- 原始 ZIP:
a10ac577ea49cdf87f324f3f6e9a7a887a1e3c0254ae638059711fef9e385b04 - bundle ZIP:
f35734d3b4e3d6ef8399491987f50974476bfdd9d6c18506b915bcb9497f5752
文件名不能证明机械结构相同;历史上同目录其他 ZIP/同名导出可能有不同活动轴。本次支持以上具体结构,不自动把未知活动轴按顺序重命名。
新 bundle 配方保留新臂的关节框架、惯性及四个有界关节的限位,给连续腕轴/夹爪补充仿真限位和伺服;替换超过 MuJoCo 面数上限的轮视觉,并构建理想化三全向轮/被动滚子。重复碰撞仅在同网格、同局部变换时去重。新臂接触使用 MuJoCo 原生凸包近似,没有套用原臂的离线凸分解数据。底盘质量、驱动增益、夹爪行程和 EEF 偏移是仿真估计,未实机标定。
扩展其他机器人:提供预先带执行器的 MJCF ZIP 和 recipe: "mjcf" 的 RobotConfig,通过 RobotManager.loadZip() 开发接口载入;独立页的自定义 JSON 上传控件不再提供。底层支持:
- 任意数量轮子,
baseMix[nwheel][3]定义车体坐标vx, vy, wz → wheel rad/s;差速轮可令第二列为零。 - 1–8 个标量机械臂关节;每个
mode可为position或velocity。目前要求移动根为 freejoint,不支持固定底座或任意浮动关节参数化的自动推断。 - 多个夹爪执行器可指定各自
joint和closed/open;观测使用gripperJoint的行程比,主关节必须由匹配行程的执行器控制。 - 指定
eefSiteName时,组合器在eefBodyName上按eefOffset加 site;未指定时直接使用 body 原点/姿态。 - 编译后校验关节类型/限位、执行器 transmission、gear、控制类型和 ctrlrange;不兼容则回滚。
固定接口只保证任务/UI 不随 DOF 改写,不保证同一策略能跨机器人泛化。8 轴以外或需力矩动作时应创建新版本契约,不能静默截断。
3. 数学契约
世界坐标为右手 Z-up;米、秒、弧度;四元数一律 wxyz。姿态四元数归一化并采用 w >= 0 的符号。所有观测限制在 [-1,1]。区间均为左闭右开。
Observation:Float32Array(92) / ONNX [1,92]
| 区间 | 内容 |
|---|---|
[0,3) |
底座世界位置 / 2 m |
[3,7) |
底座四元数 |
[7,10) |
底座世界线速度 / 2 m/s |
[10,13) |
底座世界角速度 / 4 rad/s(freejoint 局部角速度先转世界坐标) |
[13,21) |
8 个臂角槽:2*(q-min)/(max-min)-1;无效槽为 0 |
[21,29) |
臂关节速度 / 4 rad/s;无效槽为 0 |
[29,37) |
臂槽 mask(有效为 1) |
37 |
夹爪行程比 g 映射为 2*g-1 |
[38,45) |
EEF 世界位置 / 2 m + 四元数 |
[45,52) |
物体相对 EEF 的位置 / 2 m + 四元数 |
[52,59) |
物体相对目标的位姿(目标坐标系) |
[59,66) |
目标世界位置 / 2 m + 四元数 |
66,67 |
已抓取抬升标记、当前阶段稳定计数 / 10 |
[68,80) |
上次实际施加的归一化动作 |
[80,92) |
积分控制目标状态:臂位置与夹爪开度归一化,其余槽为 0 |
相对位姿严格使用 p_rel = R_parent^T*(p_object-p_parent)、q_rel = inverse(q_parent)*q_object,不是仅减世界 XYZ。
Action:Float32Array(12) / ONNX [1,12]
[0,3):归一化车体vx,vy,wz,先经过共享契约速度/加速度限制再经baseMix转轮速;超过wheelLimit时同比缩放所有轮速。[3,11):8 个臂槽。位置模式是积分目标的归一化增量速度,目标每步最多移动min(velocityLimit,0.5)*dt,并限制跟踪误差;速度模式同样限幅。不存在的槽忽略。零动作保持目标,不再映射到全行程中点。11:归一化开合速度,+1 张开、-1 闭合、0 保持;开度每秒最多变化 0.5。- 输入完整校验有限值后才写 ctrl;越界有限数裁剪;NaN/Infinity/尺寸错误拒绝,不部分写入。
控制步长 0.02 s(50 Hz);复用源模型物理 timestep(旧全凸包配方 1 ms,新 bundle 2 ms),必须整除控制步长。每个 step 在积分后调用 mj_forward,使观测不是上一个积分边界的派生位置。
奖励、终止
reach = dt * 0.1 * exp(-8 * distance(eef, object))lift = dt * 0.3 * clip((object.z - 0.019) / 0.08, 0, 1)- 当抬升达到 8 cm、末端距物体小于 9 cm、夹爪开度小于 0.4 时锁存
hasLifted。 transport = hasLifted ? dt * 0.5 * exp(-4 * distance(object, goal)) : 0- 以上抓放密集项按仿真时间积分(
dt=0.02),上界为 18。v2 另有导航进展/距离/朝向项、动作变化率惩罚及关节速度惩罚,见共享契约与训练课程。 - 已抬升后,物体距目标小于 4 cm、线速度小于 0.05 m/s、夹爪开度大于 0.65、EEF 已撤离 9 cm,连续稳定 10 步才成功:一次性
success=20,terminated=true。 - 1000 步未成功则
truncated=true;结束后必须 reset。不存在自动焊接/吸附物体,搬运依赖实际物理接触。奖励中的抓取是近距/开度/抬升启发式,不是双指接触传感器的证明。 - 导航/末端接近阶段分别使用接近位驻留、末端驻留成功条件,不以抓放成功判断导航。任务训练顺序为
navigate → reach → pick-place。 info包含reward_components,is_success,stage,safety_stop,navigation_distance,max_joint_velocity。物理子步实测关节超速、底盘倾倒/越界均失败终止。
TS step() 返回借用的同一对象,obs、raw-state、ctrl、action 缓冲全部复用;需要历史时由调用者复制。Python 返回独立 obs/info,避免 replay buffer 存到后续被覆盖的引用。两端奖励/观测/动作数学相同;引擎浮点求解不承诺长时间逐位一致。
4. 浏览器操作与集成
主工作台训练使用 SimulationSession + MobilePolicyController,在同一视口中组合任务场景并加载策略,不创建第二个物理步进所有者。
- 在主工作台导入对应 ZIP,进入「控制台 → 强化学习任务」选择已注册变体,按训练服务流程同步场景、训练并导入 ONNX。
- 「LeKiwi 智能抓放」仅支持固定 A,使用另一套具名 SI 契约和独立接触评估,不改 RL 92/12 契约。进入 RL 时会重新载入 RL 场景,不能把智能任务双支撑台直接冒充训练快照。
- 地图草稿保留;智能任务只使用隔离的空旷平地预设,编辑地图使旧模型请求失效。任意机器人/训练后台作业不会因切换智能任务而被远程取消。
RobotManager.loadZip(file, config, entryPath)、TaskDragController与moveTaskEntity()仍供开发/物理夹具使用,包括 Shift 拖动、状态重置和两变体资源回归;不再维护第二个产品网页。
ONNXPolicyRunner 要求固定 float32 observation:[1,92] → action:[1,12]、匹配 v2 task/robot/controlDt/动作语义/训练阶段,以及模型与 RobotConfig SHA-256。不要格式化训练包里的 robot.json,它的原始字节是导出指纹来源。它校验配置而不是所有网格字节;更改几何/动力学后必须从新场景重新训练和导出,不能只改标签绕过。
推理是单飞异步、固定仿真步长锁步:等待 ORT 时继续渲染,但不积分物理;下一次 rAF 消费动作后才生成下一观测。这避免“持续施加上次动作”造成训练端没有的动作延迟;代价是慢策略导致仿真时钟落后墙钟。计时累计有界,不在恢复后狂追补步。reset、拖动、模式切换、重载和 dispose 都使迟到推理结果失效;ORT 等待在途 run 结束后才 release。
5. 后台训练与自动导出
用户只需在统一面板点击开始训练。浏览器内部上传完整资产、组合后的 *.training.xml、robot.json、task.json、environment.json;服务器验证并保存快照,作业仅引用服务器 ID。Python 不再次转换 URDF。内部 ZIP 只是传输格式,不要求用户下载、解压或运行 Python。
使用独立 MuJoCo 3.11.0 + SB3 解释器,通过训练服务 --mobile-python 配置;不要升级已有 Go2/LeRobot 环境。allow_version_mismatch=True 仅供底层诊断,服务训练不会启用此绕过。
任务设置包括阶段、接续作业、示教步数、随机化、独立评估回合,以及采样步数、迭代数、环境数、设备和种子。训练按种子扰动物体/目标 XY,部署保留名义初态;评估用不同种子。日志输出共用迭代/损失/平均奖励协议,取消覆盖训练、评估与导出整个进程组。自动导出固定 float32 [1,92] → [1,12] 并用原生 ORT 对5组输入比对 PyTorch;元数据包含控制语义、阶段、实际评估、权重/RobotConfig/场景 SHA-256。
阶段门槛和实测导航结果见 训练课程。短程冒烟不是已收敛的抓取策略;尚未验证抓放收敛或跨机器人泛化。底层 export_policy()、--smoke 及 RobotManager.exportTrainingBundle() 仅保留给开发测试,不是用户训练流程。
6. 验证与性能边界
npm run typecheck
npm run lint
npm test -- web_platform/src/mobile
build/venvs/mobile/bin/python -m unittest training_server.tests.test_mobile_manipulator -v
npm run test:e2e:mobile
浏览器测试需要两个上述 ZIP;也可用 MOBILE_BUNDLE_ZIP=/path/to/file.zip 指定新包。缺少本地资产会明确 skip。测试包括真实模型动作、8 次交替切换、模型/data isDeleted()、VFS 数量、候选绑定失败回滚、真正的鼠标拖动;主工作台 UI 另由 test:e2e:agent 验收。产物在 build/mobile-validation/;测试用 /physics/mobile.html 不进入生产构建。
跨引擎回归与真实 ONNX 测试:
# 先运行浏览器测试产生 bundle-training.zip 和 rollout.json
python -m zipfile -e build/mobile-validation/bundle-training.zip build/mobile-validation/package
build/venvs/mobile/bin/python -m training_server.mobile_manipulator.validate_rollout \
--package build/mobile-validation/package --rollout build/mobile-validation/rollout.json
build/venvs/mobile/bin/python -m training_server.mobile_manipulator.export_onnx \
--package build/mobile-validation/package --smoke --output build/mobile-validation/smoke.onnx
npm run test:e2e:mobile
单元对齐另有 Python 生成的 40 组随机/旋转/饱和动作 golden,覆盖两个机器人;成功、重置、超时、速度模式、NaN 原子拒绝、生命周期和过期 ONNX 结果分别测试。重新生成:python -m training_server.tests.generate_mobile_golden,之后 Prettier 格式化 fixture。
内存注意:官方 JS 绑定通过 MjData.delete()、MjModel.delete() 执行原生析构;查看器的 mjvScene/GPU 资源必须先 detach,VFS 随后清理。共享 WASM 线性内存不会缩小,不能用 heap 不下降判定泄漏。仅释放 model/data 还不够:新路径会扩大原生资产缓存。管理器串行化加载,并交替复用两个独占 VFS 根目录;编译使共享 heap 增长后,旧环境在回滚/恢复屏障刷新 typed-array views。
以下为 v1 的历史性能基线,不作为 v2 策略验收结果:本机无头 Chromium 短测,8 次交替切换后 heap 在约 862 MiB 稳定(完整 CAD 配方开销很高),VFS 仅保留活动槽,旧 model/data 已删除。记录的是短期稳态检查,不是无限次泄漏证明。原生/WASM 3.11.0 的 12 步对照:原 LeKiwi 最大 qpos 误差约 1.3e-15、obs 无差异;新 bundle 最大 qpos 误差约 6.1e-6、obs 1.2e-6;smoke ORT 最近推理约 0.1 ms、冷启动约 4.5 ms,不代表真实大策略延迟。精确本次数据以 traces.json、onnx-metrics.json 为准。
60 FPS 是渲染目标而非保证:策略推理、旧臂上千凸包接触、软件 WebGL、加载峰值都会影响墙钟速度。请在目标 GPU 上录制至少 60 秒 FPS/物理耗时/推理 P95/P99 与长时堆曲线;若需硬实时或低内存部署,应先降面/优化碰撞和将推理放 Worker,而不是跳过物理子步或放宽对齐公式。