4. 导入外部3D模型

任务说明

本案例目标是在 Isaac Sim 中导入外部机器人模型(URDF 或 USD 格式),并通过代码调整模型的位置与缩放,使其正确显示在仿真场景中。我们将使用 Isaac Sim 自带的 omni.isaac.urdf 扩展来解析 URDF 文件,或直接使用 usd 接口加载 USD 文件,随后将导入的模型添加到 Stage 中并设置其 transform。

实现方案

我们提供两个独立函数:import_urdf 用于导入 URDF 模型,import_usd 用于导入 USD 模型。两者均返回导入模型的 Prim 路径,并支持通过参数指定位置(position)和缩放(scale)。核心逻辑是:先创建或获取 Stage,然后调用对应导入接口,最后通过 UsdGeom.Xformable 设置平移与缩放属性。

模型导入与变换流程 URDF 文件 .urdf / .xml USD 文件 .usd / .usda / .usdc import_urdf() omni.isaac.urdf import_usd() usd 接口 设置 Transform position: (x, y, z) scale: (sx, sy, sz) orientation: 可选 UsdGeom.Xformable Stage 中的 Prim 可交互/可仿真 验证方法 GetPrimAtPath + GetAttribute

代码实现

# 文件: import_model.py
# 依赖: isaacsim 2023.1+ / omni.isaac.urdf
from omni.isaac.core.utils.stage import get_current_stage
from omni.isaac.urdf import _urdf
import omni.usd
from pxr import UsdGeom, Gf

def import_urdf(urdf_path: str, prim_path: str,
                position=(0.0, 0.0, 0.0), scale=(1.0, 1.0, 1.0)):
    """
    导入 URDF 模型并设置位置与缩放。
    :param urdf_path: URDF 文件路径
    :param prim_path: 目标 Prim 路径,如 "/World/robot"
    :param position: 平移 (x, y, z)
    :param scale: 缩放 (sx, sy, sz)
    :return: 导入后的 Prim 路径
    """
    urdf_interface = _urdf.acquire_urdf_interface()
    # 设置解析参数:使用 meters 单位,不合并固定关节
    result = urdf_interface.parse_urdf(
        urdf_path=urdf_path,
        path=prim_path,
        merge_fixed_joints=False,
        fix_base=False,
        make_default_prim=True,
        self_collision=False
    )
    if not result.success:
        raise RuntimeError(f"URDF 导入失败: {result.status_message}")

    # 设置位置与缩放
    stage = get_current_stage()
    prim = stage.GetPrimAtPath(prim_path)
    if not prim.IsValid():
        raise RuntimeError(f"Prim 无效: {prim_path}")

    xform = UsdGeom.Xformable(prim)
    xform.ClearXformOpOrder()
    # 先平移,再缩放(顺序影响最终结果)
    xform.AddTranslateOp().Set(Gf.Vec3d(*position))
    xform.AddScaleOp().Set(Gf.Vec3f(*scale))
    return prim_path

def import_usd(usd_path: str, prim_path: str,
               position=(0.0, 0.0, 0.0), scale=(1.0, 1.0, 1.0)):
    """
    导入 USD 模型并设置位置与缩放。
    :param usd_path: USD 文件路径
    :param prim_path: 目标 Prim 路径,如 "/World/robot"
    :param position: 平移 (x, y, z)
    :param scale: 缩放 (sx, sy, sz)
    :return: 导入后的 Prim 路径
    """
    # 将 USD 文件作为子层引用添加到当前 Stage
    success = omni.usd.get_context().get_stage().GetRootLayer().subLayerPaths.append(usd_path)
    if not success:
        # 若 subLayer 方式失败,则使用引用方式
        stage = get_current_stage()
        prim = stage.DefinePrim(prim_path, "Xform")
        prim.GetReferences().AddReference(usd_path)
    else:
        # subLayer 方式下,需要找到实际模型根节点
        # 这里假设 USD 文件根节点即为模型根节点
        stage = get_current_stage()
        prim = stage.GetPrimAtPath("/" + usd_path.split("/")[-1].split(".")[0])
        if not prim.IsValid():
            # 若找不到,则使用目标路径
            prim = stage.GetPrimAtPath(prim_path)

    if not prim.IsValid():
        raise RuntimeError(f"USD 导入失败: {usd_path}")

    # 设置位置与缩放
    xform = UsdGeom.Xformable(prim)
    xform.ClearXformOpOrder()
    xform.AddTranslateOp().Set(Gf.Vec3d(*position))
    xform.AddScaleOp().Set(Gf.Vec3f(*scale))
    return prim.GetPath().pathString

# 使用示例(在 Isaac Sim 的 Python 脚本中执行)
if __name__ == "__main__":
    # 示例 1: 导入 URDF
    # robot_path = import_urdf("/path/to/robot.urdf", "/World/robot",
    #                          position=(1.0, 0.0, 0.5), scale=(0.01, 0.01, 0.01))
    # print(f"URDF 模型已导入: {robot_path}")

    # 示例 2: 导入 USD
    # robot_path = import_usd("/path/to/robot.usd", "/World/robot",
    #                         position=(0.0, 0.0, 0.0), scale=(1.0, 1.0, 1.0))
    # print(f"USD 模型已导入: {robot_path}")
    pass

落地与验证

运行方式:在 Isaac Sim 的 Script Editor 中执行上述代码,或保存为 .py 文件后通过 ./python.sh import_model.py 运行。需要提前在 Omniverse 环境中安装 omni.isaac.urdf 扩展。

验证方法:执行导入后,在 Viewport 中观察模型是否出现在指定位置且大小符合预期。同时可通过以下代码检查 Transform 属性:

from pxr import UsdGeom
stage = get_current_stage()
prim = stage.GetPrimAtPath("/World/robot")
xform = UsdGeom.Xformable(prim)
# 读取并打印平移与缩放值
for op in xform.GetOrderedXformOps():
    print(f"Op: {op.GetOpType()}, Value: {op.Get()}")

判定标准:若 Viewport 中模型位置与代码中 position 参数一致,且模型尺寸相对原始文件按 scale 参数正确缩放,则视为导入成功。对于 URDF 文件,若模型单位是毫米而场景使用米,需设置 scale=(0.001, 0.001, 0.001) 进行单位换算。