在 PhysX 和 Newton 之间迁移策略#

参见

本指南是 isaaclab-transferring-policies-sim-to-sim 智能体技能的权威参考( 技能源文件 )。修改本页时,也应更新该技能,使智能体指导保持一致。参见 智能体技能 。

先按 为 Newton MJWarp 准备资产 和 isaaclab-preparing-assets-for-newton 技能 的说明,确保每个机器人和物体都符合 MJWarp 要求。

仿真间迁移是在不同于训练所用的物理后端中评估同一策略检查点。本指南同时介绍将 PhysX 训练策略部署到 Newton,以及将 Newton 训练策略部署到 PhysX。

检查点将有序观测映射到动作,不包含物理引擎。两个后端提供相同策略输入和输出时,才能迁移。应期待相近行为,而非完全相同的轨迹。成功迁移可以是迈向仿真到现实部署的第一步。

任务准备与检查点兼容性#

同一注册任务应在两个物理引擎中描述相同的马尔可夫决策过程(MDP)。选择 physics=isaacsim_physx 或 physics=newton_mjwarp ,会通过 PresetCfg 解析对应后端选项。应通过该机制配置有意区分后端的物理、资产和控制设置。物理预设不应静默改变策略侧的动作、观测、奖励、终止、指令或重置项。如果 MDP 项使用的 PresetCfg 确实选择了不同的行为,应将解析后配置视为不同任务:恢复统一的检查点接口约定,或根据新约定重新训练。

尝试迁移前,确认同一任务可在两个引擎中成功训练。然后解析各后端配置,检查策略接口。以下值必须完全一致:

约定

必须一致的内容

动作

项顺序、有序关节或刚体名称、维度、目标类型、缩放、偏移和限幅。

观测

组与项顺序、张量维度、历史长度、单位、坐标系、限幅和扰动行为。

策略状态

归一化统计量、循环状态形状与重置、指令,以及 actor 使用的特权输入。

时序

物理 dt 、控制降采样倍数、策略周期和动作保持行为。同一策略周期内,Newton 子步数可以不同。

机械结构

有序刚体与关节、主动自由度,以及 mimic 或等式耦合。

回合

重置与指令分布、奖励和终止含义、时域及成功定义。

mimic 关节动作的细节#

PhysX 和 Newton MJWarp 都保留主动与从动关节坐标,但不创建相同驱动图。Newton 将已编写的 mimic 关系导入为 mimic 约束, SolverMuJoCo 再将其转换为 MJWarp 使用的 MuJoCo mjEQ_JOINT 等式约束。因此,Franka 两个指关节只有一个主动驱动:驱动 panda_finger_joint1 ,由约束带动 panda_finger_joint2 。PhysX 创建原生双向关节体 mimic 约束,但从动关节仍被视为可驱动关节;约束不会禁用该关节上已有的驱动。

当 panda_finger_joint.* 等执行器表达式为两根手指都分配非零刚度和阻尼时,这一区别就很重要。PhysX 除 mimic 耦合外还有两个主动 PD 驱动。将同一逻辑夹爪指令写入两个手指目标时,PhysX 通过两个关节施加驱动力,相对于 MJWarp 单个受驱动手指,实际上应用了两次指令。对于 Franka 资产,我们通过只驱动主动关节、显式将从动关节设为被动来消除差异:

"panda_hand": ImplicitActuatorCfg(
    joint_names_expr=["panda_finger_joint1"],
    # physical limits, gains, and armature
),
"panda_finger2_passive": ImplicitActuatorCfg(
    joint_names_expr=["panda_finger_joint2"],
    stiffness=0.0,
    damping=0.0,
    # retain the follower's limits and armature
),

零刚度和零阻尼会禁用第二个 PD 驱动。从动关节仍保留在关节体中,由 mimic 约束带动。

关节体的关节与刚体排序#

对于分支机器人,PhysX 与 MJWarp 的关节和刚体顺序可能不同。跨后端回放时,应将 joint_ordering 和 body_ordering 两者都 设为训练所用后端, physics= 仍选择目标后端。下方任务表列出哪些任务需要覆盖,哪些不需要。

完整的顺序约定、可接受的取值和故障排查见 关节与刚体顺序 。

索引顺序错乱有明显特征:运动策略在每个环境中都在几十步内摔倒,而不是逐渐表现变差。在将这种崩溃归因于接触、摩擦或执行器响应前,应先排除排序问题。各维度顺序一致后,迁移策略的存续时间应与源基线相当,剩余差距才属于求解器动力学。

迁移控制行为#

调节策略前,先匹配标称执行器响应:

  • 区分物理 actuator_velocity_limit 与求解器 joint_velocity_limit ;

  • 按关节设置驱动力、刚度、阻尼、摩擦和电枢惯量;

  • 保持 dt * decimation 和动作保持行为;

  • 使目标远离关节硬限位;

  • 监测饱和与连续动作符号变化。

通常需要增大阻尼以避免开关式控制。阻尼过小时,位置策略可能交替输出饱和指令,利用某一求解器的驱动积分或限位响应。电枢惯量在 MJWarp 中同样重要:它为广义质量矩阵添加折算惯量,避免小接触或驱动冲量产生过大的关节速度或角速度。增大电枢惯量后,应重新调整阻尼,因为有效固有频率和阻尼比会改变。执行器检查与物理参数来源指南见 为 Newton MJWarp 准备资产 。

引入域随机化#

域随机化有助于防止策略过拟合特定求解器。对关节增益、摩擦等与求解器相关的属性加入随机化,可提高策略适应求解器行为变化的能力。

类别

迁移用途

注意事项

机器人和物体摩擦

覆盖材质与接触模型的不确定性。

当前 Newton 事件只使用一个摩擦系数,PhysX 的静/动摩擦值和分桶不能一一对应。

物体质量与惯量

覆盖负载与几何变化。

保持惯量为正且物理一致,明确改变质量时是否重新计算惯量。

关节增益与摩擦

覆盖执行器辨识和损耗的不确定性。

即使引擎间使用相同属性,也要考虑求解器行为的变化。

关节电枢惯量

覆盖折算惯量的不确定性,以及 MJWarp 敏感的加速度行为。

使用有物理依据的正值范围,并一致地随机化耦合机构。

重力

简化抬升学习,覆盖负载变化。

逐步恢复完整标称重力,并在该条件下评估。零重力不是部署条件。

执行器响应

覆盖夹爪闭合速度或电机响应。

随机化驱动,以适应求解器行为差异。

重置位姿与几何

覆盖抓取和接触的多样性。

对每种几何变体重新执行碰撞有效性重置检查。

观测噪声

减少对后端特有状态估计的依赖。

匹配合理的传感器,始终保持张量形状和顺序不变。

域随机化应覆盖合理的建模不确定性,而不是任意宽的取值。如果必须采用极端分布才能迁移,应重新检查标称模型,以及策略利用的特性。

最终分布妨碍早期学习时,可使用课程学习。零重力、低观测噪声、更窄的重置范围或更宽松的终止边界可以作为初始阶段,但课程必须推进到最终部署分布。应保留独立、确定性的标称评估,避免随机采样掩盖后端差异。

验证完整组合矩阵#

评估每种训练/部署组合:

训练后端

部署后端

标记与用途

PhysX

PhysX

PP:PhysX 源基线。

PhysX

Newton

PN:PhysX 到 Newton 的迁移。

Newton

Newton

NN:Newton 源基线。

Newton

PhysX

NP:Newton 到 PhysX 的迁移。

具体入口可能因强化学习库而异。使用统一 Isaac Lab 入口时:

1. 在 PhysX 中训练:

uv run isaaclab train --rl_library rsl_rl --task TRAIN_TASK physics=isaacsim_physx

PP:在 PhysX 中复现源基线

uv run isaaclab play --rl_library rsl_rl --task PLAY_TASK \
    --checkpoint logs/rsl_rl/EXPERIMENT_DIRECTORY/RUN_DIRECTORY/model_ITERATION.pt physics=isaacsim_physx

PN:在 Newton 中部署 PhysX 检查点

uv run isaaclab play --rl_library rsl_rl --task PLAY_TASK \
    --checkpoint logs/rsl_rl/EXPERIMENT_DIRECTORY/RUN_DIRECTORY/model_ITERATION.pt physics=newton_mjwarp \
    env.scene.robot.joint_ordering=physx env.scene.robot.body_ordering=physx

2. 在 Newton 中训练:

uv run isaaclab train --rl_library rsl_rl --task TRAIN_TASK physics=newton_mjwarp

NN:在 Newton 中复现源基线

uv run isaaclab play --rl_library rsl_rl --task PLAY_TASK \
    --checkpoint logs/rsl_rl/EXPERIMENT_DIRECTORY/RUN_DIRECTORY/model_ITERATION.pt physics=newton_mjwarp

NP:在 PhysX 中部署 Newton 检查点

uv run isaaclab play --rl_library rsl_rl --task PLAY_TASK \
    --checkpoint logs/rsl_rl/EXPERIMENT_DIRECTORY/RUN_DIRECTORY/model_ITERATION.pt physics=isaacsim_physx \
    env.scene.robot.joint_ordering=mjwarp env.scene.robot.body_ordering=mjwarp

任务的关节和刚体顺序在后端间已经一致时,删除两项排序覆盖。见 关节体的关节与刚体排序 。

经过验证的迁移示例#

以下任务已验证跨后端迁移。将上述通用命令中的 TRAIN_TASK / PLAY_TASK 替换为任务 ID,将 EXPERIMENT_DIRECTORY 替换为下列目录。

任务

实验目录

说明

Isaac-Lift-Franka

lift_franka

无需覆盖排序,两种后端的关节和刚体顺序相同。 play 入口自动应用 play_mode 覆盖。

Isaac-Velocity-Rough-G1

g1_rough

分支拓扑:PN 添加 env.scene.robot.joint_ordering=physx env.scene.robot.body_ordering=physx ,NP 添加对应的 mjwarp 设置。

Isaac-Velocity-Rough-AnymalD

anymal_d_rough

分支拓扑:使用与 G1 相同的排序覆盖。

迁移演示#

这些视频展示了 PhysX 训练的策略在 Newton MJWarp 中无需重新训练即可运行,但不代表完整的 PP/PN/NN/NP 验证。两个后端并排显示。

ANYmal-D 崎岖地形运动 ( Isaac-Velocity-Rough-AnymalD )

Allegro 手立方体重定向 ( Isaac-Reorient-Cube-Allegro ,仅展示 PhysX 到 Newton 的方向)

小技巧

对于 Allegro 迁移,关键参数是接触刚度( ke )、接触阻尼( kd )、接触摩擦、关节阻尼和关节摩擦。将求解器子步数增加至 4–16,可显著提高手内操作的接触稳定性。

关节与刚体顺序#

PhysX 和 MJWarp 对同一关节系统的关节与刚体排序可能不同。设置 joint_ordering 和 body_ordering,可以让各后端中的名称对应相同的张量元素。本节介绍支持的排序约定、转换开销和直接访问后端视图的方法。后端选择及功能支持见 物理后端 。

关节系统的排序为何不同#

即使两个后端加载相同的 USD 资源,检查点仍可能需要指定顺序约定,原因如下:

  1. USD 名称标识物理关节和刚体,但不会规定各求解器必须采用相同的张量轴顺序。

  2. PhysX 与 MJWarp 采用不同的拓扑遍历和内部表示方式,构建原生关节体视图。

  3. Isaac Lab 在关节体初始化时解析一次所请求的名称,之后通过高层 API 暴露选定的公共顺序。

后端架构 中介绍的后端选择决定创建哪一种原生视图;顺序选择决定高层 API 如何呈现该视图。

公共接口顺序与后端顺序#

在 ArticulationCfg 中设置 joint_ordering 和 body_ordering 。各字段接受以下任一值:

  • None :后端原生顺序,也是无需转换的默认值,详见下文。

  • "physx" :PhysX 或 OVPhysX 关节体视图顺序。

  • "mjwarp" :Newton 或 MJWarp 关节体视图顺序。

  • "robot_schema" :资源的 isaac:physics:robotJoints (关节)或 isaac:physics:robotLinks (刚体)关系中定义的顺序。

  • 显式、完整的名称排列:一个 list 或 tuple ,恰好包含每个关节或刚体的名称一次。

准确的可接受值列表见 joint_ordering 。

在 Python 配置中,优先使用 apply_articulation_ordering_preset() ,一次调用将两个字段设置为相同约定,使关节与刚体顺序保持一致:

from isaaclab.assets import apply_articulation_ordering_preset

robot_cfg = apply_articulation_ordering_preset(robot_cfg, "mjwarp")

警告

通过 CLI 或 Hydra 覆盖配置时, 同时设置 joint_ordering 和 body_ordering 。只设置 joint_ordering 会让刚体仍保持后端顺序,且不会提示;如果检查点的刚体向量遵循源后端约定,就会产生不匹配。

初始化后,关节体及其 ArticulationNameMap 对象建立以下约定:

表面

顺序约定

joint_names 和 body_names

公共顺序

ArticulationData 的关节与刚体属性

公共顺序

关节体命令与属性写入器

公共输入顺序

backend_joint_names 和 backend_body_names

后端顺序

root_view 元数据与数组

后端顺序

joint_ordering 和 body_ordering 映射

公共顺序与后端顺序之间的转换

None 是无需转换的默认值。公共名称遵循当前后端,不建立顺序映射,不分配重排暂存区,也不启动重排内核。显式约定或名称序列如果最终解析为后端顺序,会在初始化时经过一次名称解析后规范化为 None ,从而达到完全相同的零转换状态。因此,非 None 的顺序映射始终表示实际发生了排列变换。

小技巧

配置顺序后,比较 joint_names 与 backend_joint_names ,以及 body_names 与 backend_body_names ,确认解析后的公共轴顺序。跨后端约定通过模拟对应后端的顺序规则解析,因此应抽查结果是否符合检查点的预期顺序。

高层 MDP 项#

使用高层关节体数据的标准 MDP 项采用公共索引,包括按名称解析关节或刚体选择后,索引公共顺序下的 ArticulationData 属性,或调用高层关节体写入器的项。

材质随机化会显式跨越后端边界:先将选定的公共刚体 ID 转换为后端刚体 ID,再计算相应的后端形状范围。访问 root_view 的自定义或后端专用 MDP 代码绕过了这些高层转换,必须自行转换索引和张量。

转换开销#

约定解析和映射构建只在初始化时进行一次。对于非恒等映射,受影响的读写可能需要持久暂存内存,以及 gather/scatter 内核调用。恒等映射避免了这些持续转换路径。

在 Newton 后端中,非恒等顺序还会在步进及 CUDA 图捕获区域内,记录每一步固定的核心状态缓冲区重排,包括关节位置和速度、刚体位姿和速度。每一步都会将后端顺序状态写入公共顺序缓冲区,因此存在较小的固定步进开销,与访问属性的频率无关。

运行时间和内存开销随环境数量、关节或刚体数量,以及受影响属性和写入器的访问频率而变化。应测量具体任务与访问模式;不存在与硬件无关的每秒步数或固定开销比例。

直接访问后端视图#

警告

原始求解器视图( root_view )返回的数组始终采用后端求解器顺序,不受 joint_ordering 或 body_ordering 配置影响。 joint_names 、 body_names 、 find_joints 和 find_bodies 提供的是公共顺序索引,不能直接用于索引 root_view 数组。请使用已按公共顺序工作的资源 data 缓冲区与写入 API,或先通过资源的 joint_ordering/body_ordering 映射转换索引。

尽可能使用高层关节体 API,其数据和写入约定均采用公共顺序。即使 joint_names 或 body_names 使用其他约定,直接访问 root_view 仍采用后端顺序。当少量索引需要用于视图数组时,使用 map_joint_ids_to_backend() 或 map_body_ids_to_backend() 转换,而不是手动索引顺序映射;恒等顺序下,两者均原样返回输入。

Torch 转换#

将后端顺序的关节张量转换为公共顺序时,枚举公共输出列,并通过 user_to_backend_indices 选择对应的后端源列:

ordering = robot.joint_ordering
if ordering is None:
    joint_pos_public = joint_pos_backend
else:
    joint_pos_public = joint_pos_backend[:, list(ordering.user_to_backend_indices)]

反方向转换时,枚举后端输出列,并通过 backend_to_user_indices 选择对应的公共源列:

ordering = robot.joint_ordering
if ordering is None:
    joint_target_backend = joint_target_public
else:
    joint_target_backend = joint_target_public[:, list(ordering.backend_to_user_indices)]

对于以刚体为索引的轴,以相同方式使用 robot.body_ordering 。保留对 None 的判断:它表示不存在映射对象,也能避免不必要的 gather 操作。

Warp 转换#

isaaclab.assets.articulation.ordering_kernels 中的逐元素重排内核,将原始视图数组在后端顺序与公共顺序之间转换。例如, reorder_2d_backend_to_user 将一个 (environment, joint) 数组按公共顺序收集:

import warp as wp

from isaaclab.assets.articulation.ordering_kernels import reorder_2d_backend_to_user


ordering = robot.joint_ordering
if ordering is None:
    joint_pos_public = joint_pos_backend
else:
    joint_pos_public = wp.empty(
        (robot.num_instances, robot.num_joints),
        dtype=wp.float32,
        device=robot.device,
    )
    wp.launch(
        reorder_2d_backend_to_user,
        dim=(robot.num_instances, robot.num_joints),
        inputs=[joint_pos_backend, ordering.user_to_backend],
        outputs=[joint_pos_public],
        device=robot.device,
    )

调用方负责输出分配、启动维度、数据类型,以及所有不属于关节体的轴。从公共顺序收集到后端顺序时,使用 ordering.backend_to_user 。两个设备端映射均应视为只读。

reorder_2d 和 reorder_3d 内核在 *_backend_to_user 与 *_user_to_backend 两个方向上,共同构成这组公开的逐元素重排接口。 isaaclab.assets.articulation.ordering_kernels 中其他内核均为内部实现,可能不经弃用流程就发生变化。

关节映射只覆盖具名关节,不包含浮动基座的广义坐标。转换原始雅可比矩阵或质量矩阵时,保留开头的 robot.num_base_dofs 个坐标,并将映射后的关节索引加上该数量。对质量矩阵的两个广义坐标轴均应用关节排列,其他轴保持不变。

公共浮动基座雅可比矩阵的刚体行采用完整的公共刚体顺序,转换原始后端雅可比矩阵时,应使用完整刚体映射进行 gather。固定基座的原始后端雅可比矩阵省略固定根刚体,因此不能直接应用完整刚体映射。应省略公共根刚体索引 0,并将其余映射后的后端刚体 ID 减去 1,转换成雅可比矩阵行号。固定根刚体始终排在首位,因此这一转换定义明确。准确的刚体轴约定见 body_link_jacobian_w 。高层关节体数据会自动进行这些转换。

排序无法解决的问题#

顺序兼容保证名称始终对应相同的向量元素,但不保证仿真轨迹一致。策略行为仍可能因以下因素而不同:

  • 接触生成与求解

  • 摩擦

  • 恢复系数

  • 执行器模型与配置

  • 积分方法

  • 时间步长与子步数

  • 求解器收敛

通过 求解器差异 诊断和调节这些差异,不要将它们误判为顺序问题。

验证与故障排查#

迁移后的策略行为异常时,按以下顺序检查:

  1. 比较公共 joint_names 、 body_names 与 backend_joint_names 、 backend_body_names 。

  2. 如果策略或任务同时使用关节和刚体向量,确认两者的源顺序约定。

  3. 对照训练运行,验证观测和动作维度。

  4. 检查自定义代码中是否直接访问 root_view 。

  5. 按物理名称比较源值和目标值,而不是按原始列位置比较。

  6. 如果名称到向量元素的对应关系已经稳定,但运动仍有差异,应将问题归为求解器动力学问题,并继续参考 求解器差异 。

另请参阅#