背景与目标
为 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 的依赖共存实测)。
- 核心对象:
ModelBuilder(add_mjcf/add_urdf/add_usd)→ finalize() 产出 Model;运行时三件套 State(joint_q/joint_qd/body_q/body_qd)/ Control(joint_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_positions、get/set_root_transforms/velocities、get_link_transforms/velocities、set_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_qd 是 COM 参考点的世界系空间速度;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)
- 契约:
SimBackend(src/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_vel 是 world 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_BACKENDS(src/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):
materialization.py:SceneCfg → MJCF(复用 mujoco 冷路径 helper 处理 fragment_files);ModelBuilder.add_mjcf 建 template → 自行解析 task-level XML 的 <keyframe> 写入 builder.joint_q → replicate(template, num_envs) → finalize()。
SolverMuJoCo(model, nconmax=…, njmax=…);state0/state1 = model.state()、control = model.control();设 use_coord_layout_targets=True;ArticulationView(model, <robot label>) 建批量读写视图。
- 冷路径绑定:actuator/joint/body 名称表、
get_root_state_layout、joint 索引五件套、keyframe 表、DR 能力声明(首期预期为空 capabilities,非空 plan fail-closed,与 mjwarp 一致)。
- 传感器补偿层:对 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_*.py 建 test_newton_*.py(capabilities / host cache / identity)。
Child issue 拆分(每个单独确认,各自满足单 issue 规模上限)
- Child 1 — 运行时验证 + 环境文档:实测
newton==<pin> 与主仓库 torch 2.7/2.9、warp-lang 版本共存(in-process 结论的最终确认,若不可解则回到本 roadmap 升级方案);跑通官方 G1 示例;scripts/tools/ 下安装/自检脚本 + docs/sphinx 后端页。遵循 Evidence only。
- Child 2 —
NewtonBackend 实现:src/unilab/base/backend/newton/(backend + materialization + dependencies + runtime)+ 工厂/registry 接入 + keyframe/sensor 补偿层 + conformance 测试参数。
- 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。
背景与目标
为 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 核实)
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 的依赖共存实测)。ModelBuilder(add_mjcf/add_urdf/add_usd)→finalize()产出Model;运行时三件套State(joint_q/joint_qd/body_q/body_qd)/Control(joint_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 假设吻合。SolverMuJoCo(即 mujoco_warp 的包装);构造参数含nconmax/njmax(对应 UniLab 的mjwarp_nconmax/njmax旋钮先例);默认 integrator 是implicitfast(与 MuJoCo 默认 euler 不同,接入时需显式选择与声明)。newton.selection.ArticulationView提供get/set_dof_positions、get/set_root_transforms/velocities、get_link_transforms/velocities、set_dof_forces,全部支持(world_count,)bool mask——partial reset 的现成载体;MuJoCo solver 下 mask set 后无需手动eval_fk。<keyframe>不导入、<sensor>不导入(见"接入设计")。body_qd是 COM 参考点的世界系空间速度;PD target 布局需设newton.use_coord_layout_targets=True。newton._src.*私有 API 无保障。→ 依赖必须 pin 精确版本,版本跟随是常态维护动作。UniLab 接入面(已核实,行号对应 dev/issue-1042-manager-based-api head)
SimBackend(src/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)。get_base_quat是 wxyz;get_base_ang_vel是 world frame;*_vel_b定义为quat_apply_inverse(quat_w, vel_w)的解析计算;getter 禁止触发隐式设备传输(mjwarp 的 pinned host cache + 显式 barrier 模式是直接模板)。pelvis_gyro/pelvis_local_linvel/torso_gyro等 sensor 名,经bind_sensor_data(names)契约消费——Newton 不导入 MJCF sensor,这是本接入最大的实工作量点。<keyframe>必须在 task-level XML,后端冷路径读取(get_keyframe_qpos(name))——Newton 不导入 keyframe,需在 Python 层自行解析。_SUPPORTED_SIM_BACKENDS(src/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)。src/unilab/utils/sim2sim.py),这是配置契约的既有要求,不属于额外测评工作。dependencies.py(find_spec 探活 + 版本钉死)、materialization.py(SceneCfg → 模型)、pinned host cache barrier、DR 能力如实声明为空并 fail-closed。架构结论
方案:in-process 后端,pip 依赖 pin 精确版本。
NewtonBackend满足SimBackendnumpy 契约,物理在本进程 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):
materialization.py:SceneCfg → MJCF(复用 mujoco 冷路径 helper 处理fragment_files);ModelBuilder.add_mjcf建 template → 自行解析 task-level XML 的<keyframe>写入builder.joint_q→replicate(template, num_envs)→finalize()。SolverMuJoCo(model, nconmax=…, njmax=…);state0/state1 = model.state()、control = model.control();设use_coord_layout_targets=True;ArticulationView(model, <robot label>)建批量读写视图。get_root_state_layout、joint 索引五件套、keyframe 表、DR 能力声明(首期预期为空 capabilities,非空 plan fail-closed,与 mjwarp 一致)。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(D2Hjoint_q/joint_qd/body_q/body_qd切片 + sensor 读数)。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。randomizationpayload 非空即 fail-closed(与 mjwarp 一致)。配置与注册:
registry.py:42加"newton";create_backend加分支;conf/<algo>/task/<task>/newton.yamlowner 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_*.py建test_newton_*.py(capabilities / host cache / identity)。Child issue 拆分(每个单独确认,各自满足单 issue 规模上限)
newton==<pin>与主仓库 torch 2.7/2.9、warp-lang 版本共存(in-process 结论的最终确认,若不可解则回到本 roadmap 升级方案);跑通官方 G1 示例;scripts/tools/下安装/自检脚本 +docs/sphinx后端页。遵循 Evidence only。NewtonBackend实现:src/unilab/base/backend/newton/(backend + materialization + dependencies + runtime)+ 工厂/registry 接入 + keyframe/sensor 补偿层 + conformance 测试参数。newton.yamlowner 配置(DENYLIST 与 base 逐字一致)、task 注册、短时训练与 play 冒烟跑通。不做跨后端对比测评。预计规模与永久维护成本
newton.yaml,DENYLIST 字段跨后端一致;Non-goals
wp.to_torch())不在本期。SimBackend现有方法语义、runner/lifecycle、reward/config contract。audit_sim2sim_contracts.py的后端对(属测评方向,后续立项)。Roadmap acceptance
NewtonBackend通过 conformance 参数化测试(无 GPU/无依赖环境正确 skip)。newton.yamlowner 配置落地,DENYLIST 字段与 base 逐字一致。contract_snapshot正常写入。make test-all通过,PR 按治理要求记录 gate 结果。Stop conditions
SimBackend契约或形成独立长期 API。分支与 PR
main。main最新 head 创建dev/issue-1338-newton-backend集成分支;各 child 从集成分支建分支并 PR 合回,最终由集成分支 PR 合回main。make test-all;base 为main的 PR 按治理要求等待远程 CI 通过。