4. 机器人模型导入:URDF与USD格式转换、使用Import功能导入机器人、关节与链接的层级结构、配置机器人初始位姿
好,我们进入第四章。这一章要解决一个很实际的问题——怎么把机器人模型弄进Isaac Sim里。
你手头可能有URDF文件,也可能有STEP或STP的CAD模型。但Isaac Sim原生用的是USD格式。所以,核心就两个事:格式转换,以及导入后的配置。
我个人习惯先把URDF吃透,因为ROS生态里URDF太常见了。你想想看,一个机械臂、一台AGV,甚至人形机器人,URDF几乎是标配。但Isaac Sim不直接吃URDF,它要的是USD。怎么办?两种路子:要么用内置的Import功能直接转,要么用官方提供的urdf_importer脚本。
4.1 URDF与USD:到底差在哪?
先搞清楚这两个格式的本质区别,不然你后面遇到问题会懵。
| 特性 | URDF | USD (Universal Scene Description) |
|---|---|---|
| 出身 | ROS社区,纯文本XML | Pixar,好莱坞级3D场景描述 |
| 核心能力 | 描述运动学树(关节+连杆) | 描述整个虚拟世界(灯光、材质、物理、动画) |
| 几何支持 | 简单几何体(box, cylinder, mesh) | 任意复杂网格、NURBS、点云 |
| 物理属性 | 通过<inertial>和<collision>定义 |
通过PhysicsSchema、ArticulationSchema定义 |
| 扩展性 | 弱,需要xacro预处理 | 强,支持层叠、继承、引用 |
说白了,URDF是“机器人专用格式”,而USD是“全能格式”。Isaac Sim选择USD,是因为它要同时处理机器人、环境、传感器、灯光——一个URDF根本装不下这么多东西。
核心认知:URDF描述的是机器人的“骨架”和“皮肤”,USD描述的是整个“舞台”。导入过程就是把骨架和皮肤搬到舞台上,并告诉舞台“这个家伙有物理属性,能动”。
4.2 使用Import功能导入机器人
Isaac Sim的Import功能藏在菜单栏 File -> Import 里。但别急着点,先做准备工作。
4.2.1 准备工作:检查URDF文件
我曾经遇到过一个问题:导入后机器人直接趴在地上,关节乱飞。查了半天,发现URDF里<origin>标签写错了,导致连杆原点偏移。所以,导入前我建议你先用ROS自带的check_urdf工具扫一遍:
# 终端执行
check_urdf my_robot.urdf
这个命令会输出机器人的关节树,如果有语法错误或缺失的mesh路径,它会直接报错。嗯,这一步能省掉你后面80%的排查时间。
4.2.2 正式导入:两种方式
方式一:GUI菜单导入
- 打开Isaac Sim,新建一个空Stage。
- 点击
File -> Import,选择你的URDF文件。 - 在弹出的对话框中,勾选
Fix Base Link(如果你的机器人是固定基座)。 - 点击
Import,等待几秒钟。
导入成功后,你会在Stage面板里看到一堆以_joint和_link结尾的Prim。这就是USD格式的机器人了。
方式二:Python脚本导入
如果你需要批量处理,或者想把导入流程自动化,用脚本更靠谱:
import omni.kit.commands
import carb
# 设置URDF路径
urdf_path = "/path/to/your/robot.urdf"
# 执行导入
omni.kit.commands.execute(
"URDFImportCommand",
urdf_path=urdf_path,
import_as="articulation", # 导入为关节体
fix_base=True, # 固定基座
merge_fixed_joints=False # 不合并固定关节
)
print("URDF导入完成")
我的经验:导入时merge_fixed_joints这个参数要小心。如果设为True,所有固定关节(比如法兰盘和末端工具之间的关节)会被合并成一个刚体,这会丢失关节信息。我一般设为False,保持关节树完整。
4.3 关节与链接的层级结构
导入完成后,你需要在Stage面板里理解这个层级。说白了,这就是一个树状结构,根节点是机器人本体,下面挂着一堆关节和连杆。
举个例子,一个六轴机械臂的层级大概长这样:
/World
/robot_name (ArticulationRoot)
/base_link (RigidBody)
/base_link_visual (Mesh)
/base_link_collision (Mesh)
/joint_1 (Joint)
/link_1 (RigidBody)
/link_1_visual (Mesh)
/joint_2 (Joint)
/link_2 (RigidBody)
...
这里有几个关键点:
- ArticulationRoot:整个机器人的根节点,Isaac Sim用它来识别这是一个“可动机构”。
- RigidBody:每个连杆都是一个刚体,包含质量、惯性、碰撞形状。
- Joint:关节,定义了父子连杆之间的相对运动(旋转、平移)。
- Mesh:视觉和碰撞网格,挂在对应的连杆下面。
避坑指南:我曾经导入一个AGV模型,发现轮子不转。检查层级发现,轮子的关节被错误地挂在了base_link下面,而不是ArticulationRoot下面。Isaac Sim要求所有关节必须直接或间接挂在ArticulationRoot下,否则物理引擎不认。导入后一定要检查根节点类型是不是ArticulationRoot。
4.4 配置机器人初始位姿
机器人导入后,默认位姿是URDF里定义的<origin>。但很多时候,你需要调整它的初始位置和姿态,比如把机器人放在工作台面上,或者让机械臂处于一个“准备姿态”。
4.4.1 通过Transform组件调整
最简单的方法:在Stage面板选中ArticulationRoot节点,在Property面板里找到Transform组件,直接修改Translate和Rotate值。
但注意,这里有个坑:如果你直接修改ArticulationRoot的Transform,物理引擎可能会把整个机器人“瞬移”过去,导致穿模。我建议先暂停仿真,调整好位姿,再启动仿真。
4.4.2 通过Python脚本设置初始关节角度
更专业的做法是,在仿真开始前,把机器人的关节设置到目标角度。比如,让六轴机械臂的J1和J2转到特定位置:
import omni.physx as physx
from pxr import UsdPhysics, Gf
# 获取机器人根节点
robot_prim = stage.GetPrimAtPath("/World/robot_name")
# 获取关节API
articulation = UsdPhysics.ArticulationRootAPI(robot_prim)
# 设置关节目标位置(弧度)
joint_paths = [
"/World/robot_name/base_link/joint_1",
"/World/robot_name/base_link/joint_2"
]
joint_angles = [0.5, -0.3] # 单位:弧度
for path, angle in zip(joint_paths, joint_angles):
joint_prim = stage.GetPrimAtPath(path)
joint_api = UsdPhysics.JointAPI(joint_prim)
# 设置驱动目标
joint_api.GetTargetPositionAttr().Set(angle)
# 更新物理场景
physx.update_physics_stage()
我的习惯:我会在导入脚本的最后,加一段位姿配置代码。这样每次重新导入,机器人都会自动摆到预设位置,省得手动拖拽。你想想看,如果每次调试都要手动调整,那效率太低了。
4.5 本章知识结构图
下面这张图总结了URDF导入Isaac Sim的完整流程和关键节点:
4.6 常见问题与避坑
- 导入后机器人是透明的?——检查Mesh路径。URDF里的
<mesh filename>必须是路径,或者相对于URDF文件的路径。我遇到过相对路径写错,导致Isaac Sim找不到Mesh文件。 - 关节不动?——检查
ArticulationRoot是否设置正确。如果根节点是Xform而不是ArticulationRoot,物理引擎不会驱动机器人。 - 机器人掉出地面?——初始位姿的Z值设得太低了。把
Translate的Z值抬高,让机器人刚好接触地面。 - 导入报错“Failed to parse URDF”?——URDF文件里有中文注释或特殊字符。把URDF用UTF-8 without BOM编码保存。
我曾经踩过的坑:有一次导入一个协作机器人,URDF里用了<gazebo>标签来定义传动比。Isaac Sim的Import功能不解析<gazebo>标签,导致关节驱动参数丢失。解决办法是:在URDF里直接用<transmission>和<joint>标签定义驱动,或者导入后用Python脚本手动设置关节驱动参数。