第 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让一套场景配置被克隆成成千上万个并行环境,是向量化仿真的配置入口。