4、SDF模型格式入门:SDF与URDF的区别、SDF文件结构、基本标签、构建一个简单盒子模型
好,咱们进入仿真工作流的第四站。前面几章我们聊了URDF,很多同学可能觉得URDF挺顺手。但到了Gazebo里,你会发现URDF有些力不从心。这时候,SDF就该登场了。
说白了,SDF是Gazebo的亲儿子。它专门为仿真而生,能描述URDF搞不定的东西——比如物理属性、传感器、甚至整个场景。我个人习惯是:URDF做机器人本体描述,SDF做仿真环境描述。两者配合,干活不累。
4.1 SDF与URDF的区别
先说说为什么要有两套格式。URDF是ROS时代的产物,它擅长描述机器人的运动学树——关节、连杆、传动。但URDF有个硬伤:它描述不了场景。你想想看,仿真里除了机器人,还有地面、墙壁、障碍物、灯光……这些URDF统统管不了。
SDF就不一样了。它从一开始就是为仿真设计的。我记得第一次用SDF时,最直观的感受是:一个SDF文件就能搞定整个仿真世界。机器人、场景、物理参数、传感器,全写在一个文件里,清爽得很。
| 对比维度 | URDF | SDF |
|---|---|---|
| 设计目标 | 机器人本体描述 | 完整仿真场景描述 |
| 物理属性 | 需手动添加<gazebo>扩展 | 原生支持摩擦、阻尼等 |
| 传感器 | 不支持 | 原生支持激光、相机、IMU等 |
| 场景元素 | 不支持 | 支持地面、灯光、重力等 |
| 多机器人 | 需多个文件组合 | 一个文件支持多个模型 |
| 版本迭代 | ROS1时代产物,更新慢 | Gazebo主导,持续演进 |
4.2 SDF文件结构
SDF的文件结构其实很直观。它采用XML格式,根标签是<sdf>,里面包含<world>或<model>。我习惯把SDF文件想象成一棵倒挂的树——根在最上面,枝叶往下展开。
一个典型的SDF文件骨架长这样:
<?xml version="1.0" ?>
<sdf version="1.7">
<world name="my_world">
<include>
<uri>model://ground_plane</uri>
</include>
<model name="my_box">
<link name="box_link">
<visual name="visual">
<geometry>
<box>
<size>1.0 1.0 1.0</size>
</box>
</geometry>
</visual>
</link>
</model>
</world>
</sdf>
嗯,这里要注意:SDF的版本号很重要。我用的是1.7,这是Gazebo 11的默认版本。如果你用老版本,有些标签可能不支持。
4.3 基本标签详解
咱们把常用标签过一遍。这些是我在项目中反复用的,你记牢了,后面写模型会非常顺手。
<sdf> 根标签
所有SDF文件的根。必须指定version属性。我个人习惯用1.7,兼容性最好。
<world> 世界标签
定义整个仿真世界。包含场景、物理参数、模型、灯光等。一个SDF文件可以有多个world,但Gazebo一次只能加载一个。
<model> 模型标签
描述一个具体的物体或机器人。模型由多个<link>和<joint>组成。注意:SDF的模型可以没有关节——比如一个静态的盒子,一个link就够了。
<link> 连杆标签
代表刚体。每个link包含视觉、碰撞、惯性三大部分。我刚开始学的时候总搞混:<visual>是你看得见的,<collision>是物理引擎算碰撞用的,<inertial>是算动力学用的。三者可以不一样!
<geometry> 几何标签
支持多种几何体:<box>、<sphere>、<cylinder>、<mesh>。其中<mesh>可以加载STL、DAE等格式的文件。
<pose> 位姿标签
定义模型或link的位置和朝向。格式是:x y z roll pitch yaw。注意单位:位置是米,角度是弧度。
<pose>是相对于父坐标系的。如果你在<model>里写<pose>,它是相对于世界坐标系。如果在<link>里写,是相对于模型坐标系。千万别搞反了,否则你的模型会飞到天上去。
4.4 构建一个简单盒子模型
理论说完了,咱们动手。我带你写一个完整的盒子模型SDF文件。这个盒子有颜色、有质量、有碰撞属性。
<?xml version="1.0" ?>
<sdf version="1.7">
<model name="red_box">
<pose>0 0 0.5 0 0 0</pose>
<link name="box_link">
<!-- 视觉部分:红色立方体 -->
<visual name="visual">
<geometry>
<box>
<size>1.0 1.0 1.0</size>
</box>
</geometry>
<material>
<ambient>1 0 0 1</ambient>
<diffuse>1 0 0 1</diffuse>
</material>
</visual>
<!-- 碰撞部分:和视觉一样大 -->
<collision name="collision">
<geometry>
<box>
<size>1.0 1.0 1.0</size>
</box>
</geometry>
</collision>
<!-- 惯性部分:质量1kg -->
<inertial>
<mass>1.0</mass>
<inertia>
<ixx>0.1667</ixx>
<ixy>0</ixy>
<ixz>0</ixz>
<iyy>0.1667</iyy>
<iyz>0</iyz>
<izz>0.1667</izz>
</inertia>
</inertial>
</link>
</model>
</sdf>
这个盒子边长1米,质量1公斤,红色。你可能会问:惯性矩的数值怎么来的?对于立方体,绕中心轴的惯性矩公式是 I = (1/12) * m * (a² + b²)。这里a=b=c=1,所以 I = 1/12 * 1 * (1+1) = 0.1667。嗯,数学没白学吧?
gz sdf -k your_model.sdf来检查。它会告诉你惯性矩是否合理。我曾经有个模型因为惯性矩写错了,仿真时盒子像气球一样飘起来……排查了半天才发现是惯性矩少了个零。
保存这个文件为red_box.sdf,然后在终端运行:
gazebo --verbose red_box.sdf
你会看到一个红色的立方体稳稳地落在Gazebo的地面上。如果它掉下去了,检查一下<pose>的z值——我设的是0.5,因为盒子高1米,中心在0.5时底面刚好贴地。
好了,这就是SDF的入门。说白了,SDF就是把URDF做不到的事情补上,而且做得更彻底。你掌握了这些基础标签,后面写复杂的机器人模型、传感器配置、场景搭建,都会轻松很多。
- SDF是Gazebo的原生格式,比URDF更适合仿真
- 文件结构:sdf → world/model → link → visual/collision/inertial
- 视觉、碰撞、惯性三者可以不同,碰撞模型越简单仿真越快
- 惯性矩要算对,否则物理行为会出问题
- pose的坐标系层级要搞清楚,否则模型位置会乱
可可精品资料库