Skip to content

roadmap: Newton 物理后端接入 #1338

Description

@TATP-233

背景与目标

为 UniLab 引入 Newton 物理后端,使其作为与 mujoco / mjwarp / motrix / drake 平级的 SimBackend 实现接入仓库,遵循现有 env / backend / config / sim2sim 契约。

Newton(newton-physics/newton,Linux Foundation 项目,Apache-2.0)是构建在 NVIDIA Warp 之上的 GPU 物理引擎,也是 Isaac Lab 实验性后端与 G1/Go2/ANYmal 策略示例的承载引擎。跨后端物理测评与算法迁移是后续的总体方向,不在本 roadmap 范围内——本 roadmap 只交付后端接入本身。

本 issue 是 roadmap + umbrella 规划,不直接授权开发;各 child issue 单独确认后开工。

已核实的事实

Newton 侧(来源:官方仓库与 docs,2026-08-27 核实)

  • PyPI 包名 newton,当前 1.5.0;Python ≥3.10;唯一硬依赖 warp-lang>=1.16.0不依赖 torch。→ 与主仓库 requires-python = ">=3.10,<3.14" + torch 2.7/2.9 兼容,in-process 集成初步可行(最终确认见 Child 1 的依赖共存实测)。
  • 核心对象:ModelBuilderadd_mjcf/add_urdf/add_usd)→ finalize() 产出 Model;运行时三件套 Statejoint_q/joint_qd/body_q/body_qd)/ Controljoint_f/joint_target_q/joint_target_qd)/ Contacts;标准循环 solver.step(state_in, state_out, control, contacts, dt) + 双 buffer 交换。
  • 并行多环境:scene.replicate(template, world_count=N),同质场景下 world i 的关节切片为连续区间;SolverMuJoCo 多 world 默认 separate_worlds=True,要求各 world 结构完全一致——与 UniLab 的同质 env 假设吻合。
  • 求解器:关节机器人 RL 的事实选择是 SolverMuJoCo(即 mujoco_warp 的包装);构造参数含 nconmax/njmax(对应 UniLab 的 mjwarp_nconmax/njmax 旋钮先例);默认 integrator 是 implicitfast(与 MuJoCo 默认 euler 不同,接入时需显式选择与声明)。
  • 批量读写与 reset:newton.selection.ArticulationView 提供 get/set_dof_positionsget/set_root_transforms/velocitiesget_link_transforms/velocitiesset_dof_forces,全部支持 (world_count,) bool mask——partial reset 的现成载体;MuJoCo solver 下 mask set 后无需手动 eval_fk
  • 两个已确认的导入 gap:MJCF 的 <keyframe> 不导入<sensor> 不导入(见"接入设计")。
  • 约定差异:Newton 四元数存储 (x,y,z,w)(UniLab 契约是 wxyz);body_qdCOM 参考点的世界系空间速度;PD target 布局需设 newton.use_coord_layout_targets=True
  • 稳定性风险:每月一个 minor 版本;deprecation 后只保留一个 minor 周期(实际窗口约 1–2 个月);只维护最新 minor 线不 backport;newton._src.* 私有 API 无保障。→ 依赖必须 pin 精确版本,版本跟随是常态维护动作。

UniLab 接入面(已核实,行号对应 dev/issue-1042-manager-based-api head)

  • 契约:SimBackendsrc/unilab/base/backend/base.py:230)纯 numpy 接口,约 12 个 abstract 方法 + 一组默认 fail-closed 的能力方法。action 无单独入口——env 层 apply_action 把 policy action 转成 ctrl,热路径唯一写入口是 step(ctrl: (N,nu), nsteps);partial reset 唯一入口是 set_state(env_indices, qpos, qvel, randomization)(root 列序:world xyz + wxyz quat / world linvel + body-frame angvel)。
  • getter 语义红线:全部返回 batched host numpy;get_base_quat 是 wxyz;get_base_ang_velworld frame*_vel_b 定义为 quat_apply_inverse(quat_w, vel_w) 的解析计算;getter 禁止触发隐式设备传输(mjwarp 的 pinned host cache + 显式 barrier 模式是直接模板)。
  • 观测依赖 MJCF sensor:manager-based G1 task 的 observation terms 引用 pelvis_gyro / pelvis_local_linvel / torso_gyro 等 sensor 名,经 bind_sensor_data(names) 契约消费——Newton 不导入 MJCF sensor,这是本接入最大的实工作量点
  • keyframe 约定:<keyframe> 必须在 task-level XML,后端冷路径读取(get_keyframe_qpos(name))——Newton 不导入 keyframe,需在 Python 层自行解析
  • 注册点:_SUPPORTED_SIM_BACKENDSsrc/unilab/base/registry.py:42)加 "newton"create_backend()src/unilab/base/backend/__init__.py:98)加分支 + 懒加载;owner YAML 走 task=<task>/newton;conformance 参数化在 tests/base/test_backend_conformance.py:85_BACKEND_PARAMS + skip 谓词 + _BACKEND_CLASS_NAMES)。
  • sim2sim 契约义务:新增后端的 owner YAML 必须显式声明 DENYLIST 字段且与共享 base 逐字一致(src/unilab/utils/sim2sim.py),这是配置契约的既有要求,不属于额外测评工作。
  • mjwarp 后端是同族(Warp/CUDA)最佳模板:dependencies.py(find_spec 探活 + 版本钉死)、materialization.py(SceneCfg → 模型)、pinned host cache barrier、DR 能力如实声明为空并 fail-closed。

架构结论

方案:in-process 后端,pip 依赖 pin 精确版本NewtonBackend 满足 SimBackend numpy 契约,物理在本进程 GPU 上跑;照 mjwarp 模式做懒加载 + find_spec 探活 + 带安装提示的依赖错误。求解器固定首选 SolverMuJoCo,backend 内部保留 solver 接缝但不对外暴露配置。

host-numpy profile:与 mjwarp 相同——getter 只返回 pinned host cache 的 numpy view,cache 仅在 step() / set_state() 的显式 barrier 刷新,禁止任何隐式 .numpy() 传输。

接入设计(SimBackend → Newton API 映射)

冷路径(构造 / materialize)

  1. materialization.py:SceneCfg → MJCF(复用 mujoco 冷路径 helper 处理 fragment_files);ModelBuilder.add_mjcf 建 template → 自行解析 task-level XML 的 <keyframe> 写入 builder.joint_qreplicate(template, num_envs)finalize()
  2. SolverMuJoCo(model, nconmax=…, njmax=…)state0/state1 = model.state()control = model.control();设 use_coord_layout_targets=TrueArticulationView(model, <robot label>) 建批量读写视图。
  3. 冷路径绑定:actuator/joint/body 名称表、get_root_state_layout、joint 索引五件套、keyframe 表、DR 能力声明(首期预期为空 capabilities,非空 plan fail-closed,与 mjwarp 一致)。
  4. 传感器补偿层:对 task 引用的 MJCF sensor 名,冷路径建立"sensor 名 → Newton 数据来源"映射(SensorIMU,或由 body_qd 解析计算 gyro/local_linvel),实现 bind_sensor_data 的零元数据热路径 reader。映射语义差异(site 位置 vs COM 参考点、body-frame 定义)必须在 child issue 中逐项核实并写进测试

热路径

  • step(ctrl, nsteps):ctrl (N,nu) → staging buffer → H2D 写 control.joint_target_q(PD position 模式,actuator gain 冷路径从 joint_target_ke/kd 设定)→ state0.clear_forces() → nsteps × solver.step(state0, state1, control, None, dt) + swap → sync → 刷新 pinned host cache(D2H joint_q/joint_qd/body_q/body_qd 切片 + sensor 读数)。
  • getter:全部返回 cache view;get_base_quat 负责 xyzw→wxyz 转换;get_base_ang_vel(world)与 gyro(body frame)按各自定义分别实现;*_vel_b 按解析定义计算,COM 参考点差异需核实后处理。

partial reset(set_state):校验 rows → 转换 root 列序(world xyz + wxyz → Newton 布局;world linvel + body angvel → Newton 布局)→ ArticulationView.set_* (..., mask=env_mask) → 选择性刷新 cache。randomization payload 非空即 fail-closed(与 mjwarp 一致)。

配置与注册registry.py:42"newton"create_backend 加分支;conf/<algo>/task/<task>/newton.yaml owner YAML(DENYLIST 字段与 base 逐字一致、不支持的 DR 事件显式置 null、env.newton_nconmax/njmax 旋钮显式声明——EnvCfg 加字段走 env_backend_kwargs 先例);task __init__.py 注册 register_env(..., sim_backend="newton")

测试:conformance 加 param + skip 谓词(无 GPU / 无 newton 依赖时 skip)+ _BACKEND_CLASS_NAMES;参照 test_mjwarp_*.pytest_newton_*.py(capabilities / host cache / identity)。

Child issue 拆分(每个单独确认,各自满足单 issue 规模上限)

  1. Child 1 — 运行时验证 + 环境文档:实测 newton==<pin> 与主仓库 torch 2.7/2.9、warp-lang 版本共存(in-process 结论的最终确认,若不可解则回到本 roadmap 升级方案);跑通官方 G1 示例;scripts/tools/ 下安装/自检脚本 + docs/sphinx 后端页。遵循 Evidence only。
  2. Child 2 — NewtonBackend 实现src/unilab/base/backend/newton/(backend + materialization + dependencies + runtime)+ 工厂/registry 接入 + keyframe/sensor 补偿层 + conformance 测试参数。
  3. Child 3 — 首个 task 配置接入与冒烟验证:先 1 个 task 的 newton.yaml owner 配置(DENYLIST 与 base 逐字一致)、task 注册、短时训练与 play 冒烟跑通。不做跨后端对比测评。

预计规模与永久维护成本

  • 规模:3 个 child issue / 3 个 child PR + 1 个最终 integration PR;每个 child 默认不超过 15 文件、800 行净手写改动,超限即停止拆分。Child 2 预计 10–14 文件、≤800 行。
  • 永久维护成本(诚实估计):
    • Newton 版本跟随是常态工作:每月 minor + 1–2 个月 deprecation 窗口 + 不 backport,pin 升级需定期投入;
    • 每个支持的 task × algo 一份 newton.yaml,DENYLIST 字段跨后端一致;
    • MJCF keyframe/sensor 补偿层的语义映射需随 Newton 上游能力变化维护(上游若原生支持则收敛删除);
    • 一层 Newton API 适配 + pinned host cache 设施 + conformance 测试。

Non-goals

  • 不做跨后端物理测评 / sim2sim 对比报告,不做算法迁移工具链(后续总体方向,另行立项)。
  • 不追求训练吞吐优化;CUDA graph、torch 零拷贝互通(wp.to_torch())不在本期。
  • 不启用 Newton 的非 MuJoCo solver、可微物理、heterogeneous worlds(experimental)、USD 资产管线。
  • 不改变 SimBackend 现有方法语义、runner/lifecycle、reward/config contract。
  • 不泛化 audit_sim2sim_contracts.py 的后端对(属测评方向,后续立项)。

Roadmap acceptance

  • NewtonBackend 通过 conformance 参数化测试(无 GPU/无依赖环境正确 skip)。
  • 至少 1 个 task 的 newton.yaml owner 配置落地,DENYLIST 字段与 base 逐字一致。
  • 该 task 在 newton 后端下短时训练与 play 冒烟通过;训练 run 的 contract_snapshot 正常写入。
  • keyframe/sensor 补偿层的语义映射有明确容差内的数值测试。
  • 每个 child 的本地 make test-all 通过,PR 按治理要求记录 gate 结果。

Stop conditions

  • 依赖共存实测失败,in-process 不可行(需回到本 issue 升级为 subprocess 方案)。
  • keyframe/sensor 语义映射无法在明确容差内对齐(观测维度或数值无法匹配 MJCF sensor 语义)。
  • Newton API 变动导致接入层需要绕过 SimBackend 契约或形成独立长期 API。
  • 任一 child 超过 15 文件或 800 行净手写改动。

分支与 PR

  • Declared base branch:main
  • 本 roadmap 获批后,从 main 最新 head 创建 dev/issue-1338-newton-backend 集成分支;各 child 从集成分支建分支并 PR 合回,最终由集成分支 PR 合回 main
  • 每个 PR 在创建或更新前于最终 head 运行 make test-all;base 为 main 的 PR 按治理要求等待远程 CI 通过。
  • 每个 child 合并后停止;roadmap 的批准不授权自动执行下一个 child。

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions