跳转至

第 2 章 USD 与场景组织

Isaac Lab 的场景不是手写一棵 USD 树拼出来的,而是用 Python 配置类声明"有哪些实体、放在哪个 prim 路径、用什么生成器落进 stage",再由框架克隆成成百上千个并行环境。本章只取理解这套机制所需的 USD 最小集(prim / layer / stage),然后落到 InteractiveSceneCfg 的脚本化配置、资产与生成器、URDF/MJCF→USD 的资产管线,以及多环境的场景复用。

1. USD 的三要素

1.1 三要素与属性覆写

USD(Universal Scene Description)是 Isaac Sim 的场景描述格式,OpenUSD 规范定义了它的数据模型。Isaac Lab 侧只需抓住三个对象:

对象 全称 在 Isaac Lab 中的角色
stage scene stage 一整棵运行时场景树,是所有实体的容器
prim primary element stage 树里的一个节点,一个机器人、一盏灯、一块地面都是一个 prim
layer layer 磁盘上的 .usd/.usda/.usdc 文件,多个 layer 叠加(compose)成 stage 的一个视图

prim 用斜杠路径定位,如 /World/robot/base_link。Isaac Lab 里配置实体时的 prim_path 字段就是这个路径。场景的根约定为 /World(这是根 prim 的路径惯例,非某个类)。

一个关键机制是 prim 的属性覆写:一个从外部 .usd 资产引用来的 prim,其物理/视觉属性可以在生成时被就地改写,而无需改动源资产文件——这正是第 4、5 节 spawn 配置的作用。

三要素的包含关系(pxr 四组模块与之一一对应:Sdf 管 layer、Usd 管 stage 与 prim、UsdGeom 管几何、Pcp 管组合):

flowchart LR
    layer["layer:磁盘上的 .usd / .usda / .usdc"] -->|"compose 叠加"| stage["stage:运行时场景树"]
    stage --> prim["prim:树上的节点<br/>如 /World/robot/base_link"]

1.2 pxr:USD 的 Python API 形态

概念层之下是 OpenUSD 的 Python 绑定 pxr,四组模块与上文三要素一一对应:pxr.Sdf 管场景描述层(Layer、字段读写、.usda 序列化);pxr.Usd 是运行时视图(Usd.Stage.Open 开 stage,GetPrimAtPath 取 prim,属性读写);pxr.UsdGeom 是几何 schema(Xform 变换、Mesh、Camera、包围盒缓存 BBoxCache);pxr.Pcp 是组合架构解析(sublayer/reference/payload/variant 如何叠到同一个视图)。Isaac Sim 侧的 prim/资产工具就建在这几组之上。

什么时候下沉到 pxr:用 Isaac Lab 的 spawn 配置就能完成的事不要绕——那是声明式、可版本管理的;需要批量检查或改写已存资产时(校验碰撞体齐不齐、重写 material 绑定、批量改变换、算整棵 prim 树的包围盒)才直接写 pxr 脚本,此时上文的 layer/compose 语义决定你改的是“哪一层”,改错层会得到“改了但没生效”或“改到了不该改的资产”。

坑:改错 layer 会“改了没生效”

同一属性可能由 sublayer、reference 与本地层叠加而成;写进被覆盖的那一层,视图里看到的仍是上层值——先确认自己在改哪一层。

2. 场景的脚本化配置

场景由继承 InteractiveSceneCfg 的配置类声明,每个类属性是一个实体。框架按属性声明顺序加入场景,文档建议的顺序是:地形 → 物理资产(articulation、rigid body)→ 传感器 → 非物理资产(灯光)。

import isaaclab.sim as sim_utils
from isaaclab.scene import InteractiveSceneCfg
from isaaclab.terrains import TerrainImporterCfg
from isaaclab.utils import configclass, replace
from isaaclab_assets.robots.anymal import ANYMAL_C_CFG


@configclass
class MySceneCfg(InteractiveSceneCfg):
    # num_envs 决定这套实体被克隆成多少个并行环境
    num_envs: int = 4096
    env_spacing: float = 2.5

    # 地形:一个平面地面
    terrain = TerrainImporterCfg(prim_path="/World/ground", terrain_type="plane")

    # 机器人:把资产库里的 ANYMAL_C_CFG 放到每个环境的命名空间下
    robot = replace(ANYMAL_C_CFG, prim_path="{ENV_REGEX_NS}/Robot")

    # 灯光:半球环境光,所有环境共享
    light = sim_utils.DomeLightCfg(prim_path="/World/Light", intensity=3000.0)

要点:

  • {ENV_REGEX_NS} 是占位符,克隆时展开成每个环境独立的 prim 子树路径(如 /World/envs/env_7/Robot)。凡是要随环境复制的实体,其 prim_path 都应挂在 {ENV_REGEX_NS} 下。
  • 不随环境复制的全局实体(灯光、地形根),路径直接写在 /World/... 下。
  • replace(...) 从资产库既有配置派生并覆写字段,避免整段复制粘贴。

判据:声明式 spawn 优先,pxr 只用于批量改

能用 spawn 配置完成的事不要绕到 pxr;批量校验、重写 material 绑定、算包围盒这类对已存资产的操作才写脚本。

3. 资产类型与实体

场景实体按物理语义分为若干资产类,均继承 AssetBase,共享 prim_path、spawn、init_state 三个核心配置:

配置类 语义 典型用途
ArticulationCfg 关节体(有 articulation root) 机械臂、四足、带夹爪的机器人
RigidObjectCfg 单刚体 箱子、球
RigidObjectCollectionCfg 一批同类刚体 散落的多个小物体
DeformableObjectCfg 可变形体 cloth、软体(依后端支持)
CableObjectCfg 缆绳 柔性线约束

ArticulationCfg 额外携带 actuators: dict[str, ActuatorBaseCfg](关节执行器模型,按 name 正则匹配关节)与 articulation_root_prim_path(从 USD 文件加载时指定 root 相对路径)。init_state 声明 spawn 时的位姿与关节角:

robot.init_state.pos = (0.0, 0.0, 0.6)       # root 初始位置
robot.init_state.rot = (0.0, 0.0, 0.0, 1.0)  # root 初始姿态四元数,顺序为 (x, y, z, w),identity 的 w 在末位

4. 生成器与属性覆写

实体的 spawn 字段是一个 SpawnerCfg,决定这个 prim 如何进入 stage。生成器分两类:

  • 从文件生成:spawn_from_urdf、spawn_from_mjcf、spawn_from_usd、spawn_from_mesh,以及便捷的地面 spawn_ground_plane(GroundPlaneCfg)。
  • 属性覆写(PhysxSchema 类):给已生成的 prim 贴物理/碰撞属性,如 RigidBodyPropertiesCfg、CollisionPropertiesCfg、ArticulationRootPropertiesCfg。

一个 spawn 配置可同时携带"来源 + 物理覆写",例如从 USD 引用机器人并强制开碰撞:

robot.spawn = sim_utils.UrdfFileCfg(
    asset_path="./my_robot.usd",
    rigid_props=sim_utils.RigidBodyPropertiesCfg(
        solver_position_iteration_count=8,   # 位置迭代次数,影响接触稳定与开销
        max_linear_velocity=1000.0,
    ),
)

这类属性默认值的归属容易踩坑——覆写属性只作用于它挂载的那个 prim,而非整棵子树;需要作用到全部 link 时应确认属性作用域。

5. 资产管线与格式转换

已有 CAD/URDF/MJCF 资产时,经转换器产出缓存的 .usd,再由生成器引用。转换器在 isaaclab.sim.converters 下:UrdfConverter(配 UrdfConverterCfg)、MjcfConverter、MeshConverter。

Isaac Lab 3.0 的 URDF 导入走 URDF Importer 3.0(底层 urdf-usd-converter 库),关键配置:

urdf_cfg = sim_utils.UrdfConverterCfg(
    asset_path="./my_arm.urdf",
    fix_base=True,                    # 把 base 焊死到世界(固定基座机械臂)
    merge_fixed_joints=True,          # 合并固定关节,减少 prim 数量与求解负担
    collision_from_visuals=False,     # False=用 URDF 里的 collision 几何
    collision_type="Convex Hull",     # 碰撞简化:Convex Hull / Decomposition / Sphere / Cube
    joint_drive=sim_utils.UrdfConverterCfg.JointDriveCfg(
        gains=sim_utils.UrdfConverterCfg.JointDriveCfg.PDGainsCfg(
            stiffness=200.0,          # 关节驱动刚度;也可用自然频率/阻尼比表达
            damping=20.0,
        ),
    ),
)

与 mujoco-textbook 的 URDF→MJCF 对照,两条管线在概念上高度平行,但默认值与归属不同,平移经验时须逐项核对:

维度 URDF→USD(Isaac Lab) URDF→MJCF(MuJoCo)
固定关节 merge_fixed_joints 合并 MuJoCo 编译器合并 weld
碰撞形状 collision_type 简化策略 MJCF <geom> 直接给形状
驱动增益 joint_drive.gains(可 PD 或自然频率) <generalclass>/<position> actuator
base fix_base 布尔 root body 是否 free joint

一个 importer 3.0 的行为差异:早期用于仿人/多指手形的 convert_mimic_joints_to_normal_joints 选项在当前 URDF 导入器已不支持,写死会告警。

6. 多环境场景复用

InteractiveSceneCfg.num_envs 是向量化的总开关:同一套实体配置被 cloner 复制成 num_envs 份,每份落在 {ENV_REGEX_NS} 展开出的独立 prim 子树下,共享全局实体(地形、灯光)。这就是"配一次场景、跑上千个环境"的机制——克隆与向量化运行时语义的展开归第 4 章,本章只确立"配置类是模板、num_envs 决定实例数、env_spacing 决定相邻环境间距"这条复用线。

7. 要点

  • 场景 = 一个继承 InteractiveSceneCfg 的配置类,每个属性是一个实体;加入顺序敏感,按"地形→物理资产→传感器→灯光"排布。
  • prim 路径用 {ENV_REGEX_NS} 占位以随环境克隆;全局实体(灯光/地形根)直接挂 /World。
  • 资产类按物理语义分(ArticulationCfg/RigidObjectCfg/…),共享 prim_path/spawn/init_state;执行器模型经 actuators 按 name 正则绑关节。
  • spawn 同时承担"来源"(spawn_from_*)与"属性覆写"(RigidBodyPropertiesCfg 等),覆写只作用于挂载 prim,作用域要确认。
  • 资产管线经 UrdfConverter/MjcfConverter 产 .usd,URDF 导入走 Importer 3.0(urdf-usd-converter);与 mujoco-textbook 的 URDF→MJCF 概念平行但默认值不同,逐项核对。
  • num_envs 让一套场景配置被克隆成成千上万个并行环境,是向量化仿真的配置入口。

参考文献与延伸阅读

  • OpenUSD. 规范与文档. 文档
  • Isaac Sim. 文档入口. 文档
  • Isaac Lab. 文档入口. 文档