在 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 使用的特权输入。 |
时序 |
物理 |
机械结构 |
有序刚体与关节、主动自由度,以及 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 替换为下列目录。
任务 |
实验目录 |
说明 |
|---|---|---|
|
|
无需覆盖排序,两种后端的关节和刚体顺序相同。 |
|
|
分支拓扑:PN 添加 |
|
|
分支拓扑:使用与 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 资源,检查点仍可能需要指定顺序约定,原因如下:
USD 名称标识物理关节和刚体,但不会规定各求解器必须采用相同的张量轴顺序。
PhysX 与 MJWarp 采用不同的拓扑遍历和内部表示方式,构建原生关节体视图。
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 对象建立以下约定:
表面 |
顺序约定 |
|---|---|
|
公共顺序 |
|
公共顺序 |
关节体命令与属性写入器 |
公共输入顺序 |
|
后端顺序 |
|
后端顺序 |
|
公共顺序与后端顺序之间的转换 |
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 。高层关节体数据会自动进行这些转换。
排序无法解决的问题#
顺序兼容保证名称始终对应相同的向量元素,但不保证仿真轨迹一致。策略行为仍可能因以下因素而不同:
接触生成与求解
摩擦
恢复系数
积分方法
时间步长与子步数
求解器收敛
通过 求解器差异 诊断和调节这些差异,不要将它们误判为顺序问题。
验证与故障排查#
迁移后的策略行为异常时,按以下顺序检查:
比较公共
joint_names、body_names与backend_joint_names、backend_body_names。如果策略或任务同时使用关节和刚体向量,确认两者的源顺序约定。
对照训练运行,验证观测和动作维度。
检查自定义代码中是否直接访问
root_view。按物理名称比较源值和目标值,而不是按原始列位置比较。
如果名称到向量元素的对应关系已经稳定,但运动仍有差异,应将问题归为求解器动力学问题,并继续参考 求解器差异 。