3. 核心概念

在开始搭建AGV小车产线仿真项目之前,理解Isaac Sim的底层数据组织与仿真架构是至关重要的。许多初学者在刚接触Isaac Sim时,会被其庞大的功能面板和术语体系所困扰,往往急于拖拽资产、添加物理材质,却忽略了这些操作背后的核心逻辑。本章将系统性地拆解七个核心概念:USD场景、Stage、Prim、Transform、Physics Scene、Articulation与Sensor。我们将从数据结构的底层逻辑出发,逐步深入到物理仿真与感知仿真的应用层,帮助你建立一套清晰的认知框架,为后续的产线布局、AGV运动控制与传感器调试打下坚实基础。

USD Stage (场景) Prim (图元) 场景中的最小对象单元 如:Mesh、Camera、Light Transform (变换) 位置、旋转、缩放 定义Prim在空间中的位姿 Physics Scene (物理场景) 物理引擎的全局配置 重力、时间步长、求解器 Articulation (关节) 刚体+关节约束 用于构建AGV底盘、机械臂 Sensor (传感器) 感知仿真数据源 Camera、Lidar、IMU 数据输出 RGB图、点云、位姿数据 核心关系:Stage 是容器,Prim 是对象, Transform 定义位姿,Physics 与 Sensor 赋予行为

上图清晰地展示了这些核心概念之间的层级与依赖关系。USD Stage作为最顶层的容器,承载了所有数据;Prim是构成场景的基本元素;Transform则定义了每个Prim在空间中的位置与姿态。在物理仿真层面,Physics Scene提供了全局物理参数,而Articulation则通过关节约束将多个刚体连接成可运动的机构。Sensor则独立于物理计算,负责从场景中采集数据。下面我们将逐一深入解析。

3.1 USD场景与Stage:一切仿真的载体

核心原理:通用场景描述与舞台

USD(Universal Scene Description)是皮克斯开发的一种高性能、可扩展的3D场景描述与交换格式。它不仅仅是一个文件格式,更是一套完整的场景合成、组织与编辑框架。在Isaac Sim中,USD是唯一的数据基础。一个USD文件可以包含几何体、材质、灯光、相机、物理属性、动画序列甚至自定义元数据。

Stage是USD在内存中的运行时实例,可以理解为“正在被编辑或仿真的当前场景”。当你打开一个USD文件时,Isaac Sim会将其加载为一个Stage。所有在Stage上进行的操作——添加Prim、修改属性、运行仿真——都会实时反映在Stage中。Stage是Isaac Sim中所有操作的目标对象,无论是通过UI界面还是Python脚本,我们都在与Stage交互。

关键区别:USD文件是磁盘上的静态数据,而Stage是内存中的动态实体。你可以将USD文件想象成一份图纸,而Stage则是根据图纸搭建起来的实体沙盘。仿真过程中对场景的修改(如移动AGV)只存在于Stage中,除非你显式保存,否则不会写回USD文件。

操作流程:创建与加载Stage

  1. 新建Stage:在Isaac Sim中,通过菜单 File -> New Stage 创建一个空Stage。此时Stage中只有一个默认的 /World Prim,作为所有其他Prim的根节点。
  2. 加载USD:使用 File -> Open 选择已有的USD文件。Isaac Sim支持直接打开包含复杂装配体的USD文件,并自动解析其层级结构。
  3. 使用Python API:在脚本中,我们通常使用 omni.usd.get_context().get_stage() 获取当前Stage的句柄,然后通过该句柄进行所有操作。
# 获取当前Stage
from omni.usd import get_context
stage = get_context().get_stage()
# 在根节点下创建一个新的Xform Prim
from pxr import UsdGeom
xform = UsdGeom.Xform.Define(stage, '/World/MyAGV')
print(f"Stage路径: {stage.GetRootLayer().identifier}")

案例拆解:产线场景的层级规划

在搭建AGV产线时,合理的Stage层级结构能极大提升后续管理与脚本编写的效率。我们建议采用如下结构:

层级路径内容说明
/World根节点所有场景元素的父级
/World/Environment地面、墙壁、固定障碍物静态环境,不参与物理计算
/World/ProductionLine传送带、装配工位可包含动画或固定关节
/World/AGVs所有AGV小车的集合每辆AGV是一个独立的Articulation
/World/Sensors全局传感器(如顶视相机)用于产线监控

这种层级设计使得我们可以在脚本中通过路径快速定位对象,例如 stage.GetPrimAtPath("/World/AGVs/AGV_01")。同时,USD的层(Layer)机制允许我们将环境、AGV、传感器分别存储在不同的USD文件中,最后通过引用(Reference)或子层(SubLayer)合成到一个完整的Stage中,实现模块化开发。

常见误区:初学者经常混淆Stage与场景中的“地面”。地面只是Stage中的一个Prim(通常是一个Plane或Mesh),而Stage是整个场景的容器。删除地面不会影响Stage的存在,但删除Stage则意味着关闭整个仿真环境。

3.2 Prim与Transform:场景的基本单元与空间定位

核心原理:Prim的类型与属性

Prim是USD场景图中的基本节点,类似于文件系统中的文件或文件夹。每个Prim都有一个唯一的路径(如 /World/AGVs/AGV_01/Chassis),并可以包含任意数量的属性(Attribute)和子Prim。Prim的类型决定了其行为:

  • Xform:最通用的Prim类型,仅包含Transform信息,用于组织场景层级。
  • Mesh:包含几何体数据(顶点、面、法线),是可见物体的基础。
  • Camera:定义视锥体,用于渲染或作为传感器。
  • Light:定义光源。
  • RigidBodyAPI:不是独立Prim,而是附加在Mesh或Xform上的物理属性接口,使其参与刚体动力学计算。

Transform是每个Prim都具备的空间属性,由平移(Translate)、旋转(Rotate)和缩放(Scale)组成。在Isaac Sim中,Transform通常以4x4矩阵或平移+旋转(四元数)+缩放的形式存储。理解Transform的层级关系至关重要:子Prim的Transform是相对于父Prim的局部坐标。

判断方法:如何正确设置Transform

  1. 明确参考系:在设置Transform前,先确认是相对于世界坐标系还是父Prim的局部坐标系。
  2. 使用四元数避免万向锁:在脚本中设置旋转时,推荐使用四元数(Quatd)而非欧拉角。
  3. 利用XformOp:USD使用XformOp(如 translate、rotateXYZ)来记录Transform操作。直接修改这些Op的值比整体设置矩阵更安全。
# 设置AGV底盘的位置和朝向
chassis_prim = stage.GetPrimAtPath("/World/AGVs/AGV_01/Chassis")
# 获取或创建Transform操作
translate_op = chassis_prim.GetAttribute("xformOp:translate")
translate_op.Set(Gf.Vec3d(10.0, 5.0, 0.0))
# 设置旋转(绕Z轴旋转90度)
rotate_op = chassis_prim.GetAttribute("xformOp:rotateZ")
rotate_op.Set(90.0)

案例拆解:AGV小车的坐标体系

假设我们有一辆AGV,其结构为:底盘(Chassis)和顶部的货架(Rack)。底盘上安装有左右两个驱动轮。合理的Transform设置如下:

  • /World/AGVs/AGV_01:Xform,位于世界坐标 (0,0,0),旋转 (0,0,0)。这是AGV的根节点。
  • /World/AGVs/AGV_01/Chassis:Mesh,相对于根节点偏移 (0,0,0.2),表示底盘中心在轮子轴线上方0.2米。
  • /World/AGVs/AGV_01/LeftWheel:Mesh,相对于根节点偏移 (-0.5, 0.8, 0.1)。
  • /World/AGVs/AGV_01/RightWheel:Mesh,相对于根节点偏移 (-0.5, -0.8, 0.1)。

当我们需要移动AGV时,只需修改 /World/AGVs/AGV_01 的Transform,所有子Prim会跟随移动。这种层级化Transform管理是构建复杂机械结构的基础。

经验提醒:在Isaac Sim的UI中,使用移动/旋转工具时,注意切换坐标空间(世界/局部)。在脚本中,建议始终使用局部坐标设置子Prim,避免因父级旋转导致坐标计算错误。

3.3 Physics Scene与Articulation:物理仿真与运动机构

核心原理:物理引擎的全局与局部

Physics Scene是Isaac Sim中物理仿真的全局配置中心。它定义了重力加速度、仿真时间步长、求解器迭代次数、碰撞检测方式等参数。一个Stage中只能有一个Physics Scene,通常位于 /PhysicsScene 路径下。通过调整Physics Scene的属性,我们可以控制仿真的精度与速度。

Articulation是Isaac Sim中用于构建多刚体运动机构的核心概念。一个Articulation由多个刚体(RigidBody)通过关节(Joint)连接而成。关节类型包括旋转关节(RevoluteJoint)、棱柱关节(PrismaticJoint)、球关节(SphericalJoint)等。Articulation的典型应用包括:AGV的转向机构、机械臂的关节、传送带的滚轮。

操作流程:创建Physics Scene与Articulation

  1. 添加Physics Scene:在Stage中创建 /PhysicsScene Prim,并添加 PhysxSceneAPI。设置重力为 (0, 0, -9.81)。
  2. 定义刚体:为需要参与物理计算的Mesh添加 RigidBodyAPI,并设置质量、惯性张量等属性。
  3. 添加关节:在两个刚体之间创建关节Prim,指定关节类型和连接的两个刚体路径。
  4. 构建Articulation根:在Articulation的根Prim上添加 ArticulationRootAPI,Isaac Sim会自动识别其下的所有刚体和关节。
# 创建Physics Scene
physics_scene = UsdPhysics.Scene.Define(stage, "/PhysicsScene")
physics_scene.CreateGravityDirectionAttr().Set(Gf.Vec3f(0, 0, -1))
physics_scene.CreateGravityMagnitudeAttr().Set(9.81)
# 为底盘添加刚体属性
from omni.physx.scripts import physicsUtils
chassis_prim = stage.GetPrimAtPath("/World/AGVs/AGV_01/Chassis")
physicsUtils.add_rigid_body(chassis_prim, "kg", 50.0)
# 添加旋转关节(驱动轮)
joint_prim = stage.DefinePrim("/World/AGVs/AGV_01/LeftWheelJoint", "RevoluteJoint")
UsdPhysics.RevoluteJoint.Define(stage, "/World/AGVs/AGV_01/LeftWheelJoint")
joint = UsdPhysics.RevoluteJoint(stage.GetPrimAtPath("/World/AGVs/AGV_01/LeftWheelJoint"))
joint.CreateBody0Rel().SetTargets(["/World/AGVs/AGV_01/Chassis"])
joint.CreateBody1Rel().SetTargets(["/World/AGVs/AGV_01/LeftWheel"])

案例拆解:AGV底盘的运动学模型

以差速驱动AGV为例,其运动学模型依赖于两个驱动轮的独立旋转。在Isaac Sim中,我们构建如下Articulation:

组件类型关键属性
ChassisRigidBody质量50kg,重心在几何中心
LeftWheelRigidBody + RevoluteJoint关节轴沿Y轴,可施加驱动扭矩
RightWheelRigidBody + RevoluteJoint关节轴沿Y轴,可施加驱动扭矩
FrontCasterRigidBody + SphericalJoint被动万向轮,提供支撑

在仿真中,我们通过设置左右轮关节的 drive:angularVelocity 属性来控制AGV的运动。例如,设置左轮速度为1.0 rad/s,右轮速度为0.5 rad/s,AGV将向右转弯。这种基于Articulation的控制方式,使得我们能够精确模拟AGV的动力学特性,包括惯性、摩擦和打滑。

常见误区:不要将Articulation与简单的刚体堆叠混淆。如果只是将多个刚体通过固定约束连接,而不使用ArticulationRootAPI,Isaac Sim将无法正确计算关节的驱动力和反馈力,导致仿真不稳定。

3.4 Sensor:感知仿真的数据入口

核心原理:传感器类型与数据流

Sensor在Isaac Sim中是一类特殊的Prim,它们不参与物理计算,而是从场景中采集数据并生成仿真结果。常见的传感器包括:

  • Camera:生成RGB图像、深度图、语义分割图。
  • Lidar:生成3D点云数据。
  • IMU:输出线加速度和角速度。
  • Contact Sensor:检测碰撞事件。

传感器的核心是渲染/计算管线。例如,Camera传感器依赖于Isaac Sim的渲染引擎,通过设置视锥体参数(FOV、分辨率)来生成图像。Lidar则通过模拟激光发射与接收来计算点云坐标。

操作流程:配置与读取传感器数据

  1. 添加传感器Prim:在Stage中创建Camera或Lidar Prim,并设置其Transform以确定安装位置和朝向。
  2. 配置传感器参数:设置分辨率、帧率、FOV、点云密度等。
  3. 通过Python读取数据:使用 omni.sensor 模块或ROS2桥接获取数据。
# 创建并配置相机
from omni.sensor import create_camera
camera = create_camera(stage, "/World/Sensors/AGV_Camera")
camera.GetFocalLengthAttr().Set(12.0)
camera.GetHorizontalApertureAttr().Set(20.955)
# 设置相机位置(在AGV前方)
camera.GetPrim().GetAttribute("xformOp:translate").Set(Gf.Vec3d(2.0, 0.0, 1.5))
# 读取图像数据(伪代码)
from omni.sensor import get_sensor_data
rgb_data = get_sensor_data("/World/Sensors/AGV_Camera", "rgb")

案例拆解:AGV视觉导航传感器布局

在AGV产线仿真中,我们通常需要多种传感器协同工作。以下是一个典型的传感器配置方案:

传感器安装位置用途关键参数
前视相机AGV前方顶部识别产线标识、避障1280x720, FOV 90°
顶视LidarAGV顶部中央构建2D地图、定位360°扫描, 10Hz
IMU底盘中心姿态估计、运动补偿200Hz输出
接触传感器保险杠碰撞检测布尔输出

在仿真中,我们通过同步读取这些传感器的数据,可以模拟AGV的感知-决策-控制闭环。例如,前视相机检测到前方障碍物,Lidar提供精确距离,IMU提供当前速度与朝向,控制算法据此调整驱动轮的转速。

经验提醒:传感器数据的同步是一个常见难点。在Isaac Sim中,可以使用 on_tick 事件或定时器来同步读取所有传感器,确保数据对应同一仿真时刻。此外,传感器渲染会消耗GPU资源,在大型产线场景中应合理控制传感器数量与分辨率。

3.5 总结复盘:概念间的协作与常见误区

通过本章的解析,我们明确了Isaac Sim中核心概念的分工与协作关系。USD Stage是承载一切的容器,Prim是构成场景的积木,Transform定义了积木的摆放位置,Physics Scene提供了物理规律,Articulation构建了可运动的机构,Sensor则赋予场景感知能力。在实际项目中,这些概念往往交织在一起:一个AGV小车既是Articulation(物理运动),又挂载了多个Sensor(感知),同时其外观由多个Mesh Prim组成,并通过Transform组织成层级结构。

以下是初学者最容易犯的五个错误,务必警惕:

  1. 忽略Physics Scene的全局设置:未正确设置重力或时间步长,导致仿真物体漂浮或穿透。
  2. Transform层级混乱:在父级旋转后,子级仍使用世界坐标设置位置,导致部件错位。
  3. Articulation缺少根节点:忘记添加ArticulationRootAPI,导致关节无法驱动。
  4. 传感器未设置正确Transform:相机朝向错误,导致采集不到有效图像。
  5. 混淆USD文件与Stage:在仿真过程中修改了Stage,但未保存,重启后所有更改丢失。

核心要点:掌握这些概念的关键在于理解“数据流”。USD定义了“有什么”,Transform定义了“在哪里”,Physics定义了“怎么动”,Sensor定义了“怎么看”。当你能够清晰回答这四个问题时,你就已经具备了搭建复杂仿真项目的基础能力。