3. SDF模型转换与适配
做Gazebo仿真,模型转换这块儿,说实话是绕不过去的坎儿。URDF是ROS的宠儿,但Gazebo更认SDF。你想想看,一个机器人要在仿真环境里动起来,模型格式不对,后面全是白搭。我这些年踩过的坑,十有八九都跟模型转换有关。今天咱们就把这块儿掰开了揉碎了讲清楚。
3.1 URDF转SDF:一条命令搞定?没那么简单
很多人以为URDF转SDF就是敲一行命令的事。嗯,理论上确实如此:
gz sdf -p your_robot.urdf > your_robot.sdf
或者用老版本的:
gzsdf print your_robot.urdf > your_robot.sdf
但我在项目中遇到过,这条命令跑完,生成的SDF文件直接报错。为什么?因为URDF里有些标签SDF根本不认。比如<transmission>标签,URDF里写得好好的,转成SDF就丢了。说白了,这个转换工具只做了一对一的标签映射,复杂的传动关系、控制器配置,它管不了。
<link>和<joint>的惯性参数,URDF的惯性矩阵经常写得不对,转过去就歪了。
3.2 SDF版本兼容性:版本不对,模型白费
SDF格式从1.2一路走到1.9,每个版本都有变化。我记得有一次,同事给我一个模型,死活加载不上。折腾了半天,发现他用的SDF 1.6,我用的Gazebo 9只支持到1.4。版本不兼容,模型直接罢工。
怎么查版本?看SDF文件的第一行:
<?xml version="1.0" ?>
<sdf version="1.6">
<model name="my_robot">
...
</model>
</sdf>
Gazebo版本和SDF版本的对应关系,我整理了一张表:
| Gazebo版本 | 支持的SDF版本 | 备注 |
|---|---|---|
| Gazebo 7 | 1.4 | 老项目常见 |
| Gazebo 9 | 1.4 - 1.6 | 稳定版,用得最多 |
| Gazebo 11 | 1.7 - 1.8 | 新特性多 |
| Gazebo Ignition | 1.9+ | 完全重写 |
gz sdf -v 就能看到。我个人习惯在模型文件里显式声明版本号,避免莫名其妙的问题。
3.3 模型坐标系调整:歪了?转一下就好
坐标系问题,说白了就是你的模型在仿真里站没站相。URDF默认是右手坐标系,X向前,Z向上。但有些模型设计的时候,Z可能是向后的,或者Y是向上的。转成SDF后,模型直接躺地上。
怎么调?我一般用两种方法:
- 方法一:改URDF的
<origin>标签。在<joint>里调整xyz和rpy,把模型扶正。比如:
<joint name="base_joint" type="fixed">
<parent link="world"/>
<child link="base_link"/>
<origin xyz="0 0 0" rpy="0 0 1.57"/> <!-- 绕Z轴转90度 -->
</joint>
- 方法二:直接在SDF里加
<pose>标签。SDF的<model>标签下可以直接写:
<model name="my_robot">
<pose>0 0 0 0 0 1.57</pose> <!-- x y z roll pitch yaw -->
...
</model>
你想想看,这两种方法本质一样,但SDF的<pose>更直观。我建议你优先用SDF的<pose>,因为改起来快,不用重新转格式。
3.4 材质与纹理丢失处理:模型变白了?别慌
模型加载进去,一片惨白。嗯,这是材质丢了。URDF里用<material>指定颜色,但转成SDF后,Gazebo不认URDF的材质定义。它有自己的<material>标签,而且纹理路径经常对不上。
我曾经有个项目,模型在RViz里漂漂亮亮的,一进Gazebo就变白板。查了半天,发现纹理图片路径是相对路径,Gazebo的工作目录跟URDF的不一样。
解决办法分三步:
- 检查纹理路径:确保
file://路径是路径,或者相对于模型文件的位置。比如:
<material>
<script>
<uri>file:///home/user/models/textures/metal.png</uri>
<name>Metal</name>
</script>
</material>
- 手动添加材质:如果转换后材质丢了,直接在SDF里补上。SDF的材质支持
<ambient>、<diffuse>、<specular>和<emissive>四个通道。我一般这么写:
<material>
<ambient>0.8 0.8 0.8 1</ambient>
<diffuse>0.6 0.6 0.6 1</diffuse>
<specular>0.2 0.2 0.2 1</specular>
</material>
- 使用
gz sdf -p的--include-materials选项:有些版本的转换工具支持保留材质信息,但效果嘛...只能说聊胜于无。
meshes子目录里,用相对路径引用。
3.5 嵌套模型加载失败:模型套模型,套出问题
嵌套模型,说白了就是一个SDF文件里引用另一个SDF文件。比如你的机器人底盘是一个模型,机械臂是另一个模型,你想把它们组合起来。Gazebo支持用<include>标签嵌套:
<model name="my_robot">
<include>
<uri>model://chassis</uri>
<pose>0 0 0 0 0 0</pose>
</include>
<include>
<uri>model://arm</uri>
<pose>0.5 0 0 0 0 0</pose>
</include>
</model>
但问题来了——嵌套模型经常加载失败。我遇到过的情况有:
- 模型路径找不到:Gazebo的
GAZEBO_MODEL_PATH环境变量没设置对。子模型必须在这个路径下,否则报错。 - 命名冲突:两个子模型有同名的link或joint,Gazebo直接崩溃。你想想看,两个模型都叫
base_link,Gazebo分不清谁是谁。 - 版本不一致:子模型是SDF 1.4,父模型是1.6,加载时可能报错。
<model name>跟父模型里的引用名对不上。记住,<include>里的name属性必须唯一,而且不能跟子模型内部的name冲突。
解决嵌套模型问题,我总结了一个检查清单:
- 确认
GAZEBO_MODEL_PATH包含了所有子模型的父目录 - 检查所有子模型的
<model name>是否唯一 - 确保子模型和父模型的SDF版本一致
- 用
gz model --check your_model.sdf命令做语法检查
嗯,模型转换这块儿,说白了就是细心活。你只要把坐标系、材质、版本、嵌套这几个点盯住了,大部分问题都能提前规避。我这些年做仿真,模型转换占了调试时间的三分之一。但一旦你把这些套路摸熟了,后面就顺了。
可可精品资料库