第三讲:Gazebo仿真世界搭建
各位同学,欢迎来到第三讲。上一讲我们把Nav2的框架搭起来了,但说实话,没有场景的机器人就像瞎子摸象。今天我们就来亲手搭建一个仿真世界——从零开始,用SDF格式创建静态世界,添加障碍物和墙壁,设置光照和地面纹理,最后再用Building Editor快速生成室内场景。
我个人习惯把仿真世界比作「机器人的幼儿园」。在这里,它要学习走路、避障、认路。世界搭得好不好,直接决定了后续导航算法的表现。我见过太多同学在仿真里跑得飞起,一上实车就翻车——原因往往就是仿真世界太「理想」了。
核心要点:仿真世界不是越复杂越好,而是越「真实」越好。真实意味着有光照变化、有纹理干扰、有合理的障碍物布局。
3.1 SDF格式:为什么选它?
SDF(Simulation Description Format)是Gazebo的原生格式。你可能会问:URDF不行吗?URDF当然可以,但它更偏向机器人本身的描述。SDF对场景、光照、物理属性支持更好。
说白了,URDF描述「机器人长什么样」,SDF描述「世界长什么样」。两者各司其职。
来看一个最简单的SDF世界文件:
<?xml version="1.0" ?>
<sdf version="1.6">
<world name="my_world">
<include>
<uri>model://sun</uri>
</include>
<include>
<uri>model://ground_plane</uri>
</include>
</world>
</sdf>
嗯,这里要注意:model://是Gazebo内置模型的路径。如果你有自己的模型,可以用file://指定本地路径。
我的经验:刚开始做仿真时,我总喜欢把所有东西写在一个文件里。后来发现维护起来太痛苦了。建议把地面、墙壁、障碍物拆成独立的SDF文件,用<include>引用。这样改一个障碍物位置,不用动整个文件。
3.2 添加障碍物与墙壁
静态世界最核心的就是障碍物。没有障碍物,导航算法就没法验证。我建议你从最简单的立方体开始,逐步增加复杂度。
下面是一个带墙壁和障碍物的世界示例:
<?xml version="1.0" ?>
<sdf version="1.6">
<world name="warehouse">
<include>
<uri>model://sun</uri>
</include>
<!-- 地面 -->
<include>
<uri>model://ground_plane</uri>
</include>
<!-- 墙壁1:左侧墙 -->
<model name="wall_left">
<pose>-5 0 1 0 0 0</pose>
<link name="body">
<collision name="collision">
<geometry>
<box>
<size>0.2 10 2</size>
</box>
</geometry>
</collision>
<visual name="visual">
<geometry>
<box>
<size>0.2 10 2</size>
</box>
</geometry>
<material>
<ambient>0.8 0.8 0.8 1</ambient>
<diffuse>0.8 0.8 0.8 1</diffuse>
</material>
</visual>
</link>
</model>
<!-- 障碍物:一个箱子 -->
<model name="box_obstacle">
<pose>2 1 0.5 0 0 0</pose>
<link name="body">
<collision name="collision">
<geometry>
<box>
<size>1 1 1</size>
</box>
</geometry>
</collision>
<visual name="visual">
<geometry>
<box>
<size>1 1 1</size>
</box>
</geometry>
<material>
<ambient>0.2 0.5 0.8 1</ambient>
<diffuse>0.2 0.5 0.8 1</diffuse>
</material>
</visual>
</link>
</model>
</world>
</sdf>
你想想看,这里最关键的是什么?是<pose>标签。它定义了模型的位置和朝向。格式是:x y z roll pitch yaw。我刚开始经常搞混顺序,后来养成了习惯:先写位置,再写角度。
避坑指南:我曾经在项目里把障碍物的z坐标设成了0,结果它半截埋在地里。导航算法死活绕不过去,我还以为是路径规划有问题。排查了半天才发现是障碍物位置不对。记住:障碍物的z坐标应该是它高度的一半。
3.3 设置光照与地面纹理
光照和纹理看起来是「美化」工作,但实际上对导航影响很大。为什么?因为激光雷达和摄像头对光照敏感。仿真里的光照太均匀,实车上的传感器就会「不适应」。
来看一个带自定义光照和纹理的例子:
<!-- 自定义光照 -->
<light name="sun_light" type="directional">
<pose>0 0 10 0 0 0</pose>
<diffuse>1 0.95 0.9 1</diffuse>
<specular>0.1 0.1 0.1 1</specular>
<direction>-0.5 0.1 -1</direction>
<attenuation>
<range>100</range>
<constant>0.9</constant>
<linear>0.01</linear>
<quadratic>0.001</quadratic>
</attenuation>
<cast_shadows>true</cast_shadows>
</light>
<!-- 地面纹理 -->
<model name="ground">
<static>true</static>
<link name="link">
<collision name="collision">
<geometry>
<plane>
<normal>0 0 1</normal>
<size>20 20</size>
</plane>
</geometry>
</collision>
<visual name="visual">
<geometry>
<plane>
<normal>0 0 1</normal>
<size>20 20</size>
</plane>
</geometry>
<material>
<script>
<uri>model://ground_plane/materials/scripts/ground_plane.material</uri>
<name>GroundPlane/Grass</name>
</script>
</material>
</visual>
</link>
</model>
这里有几个关键参数:
| 参数 | 作用 | 我的建议 |
|---|---|---|
| diffuse | 漫反射颜色 | 别用纯白,稍微偏暖色更真实 |
| direction | 光照方向 | 模拟下午的阳光,角度别太垂直 |
| cast_shadows | 是否投射阴影 | 一定要开,否则传感器数据太假 |
| 地面纹理 | 视觉参考 | 用纹理能让视觉SLAM有更多特征点 |
小技巧:如果你想让地面纹理更丰富,可以自己制作Ogre材质脚本。我在一个仓储项目里,用棋盘格纹理做地面,这样机器人经过时能明显看到里程计的漂移——这对调试非常有帮助。
3.4 使用Building Editor创建室内场景
手动写SDF文件搭建复杂室内场景太累了。Gazebo自带的Building Editor就是干这个的。它是个图形化工具,你画墙、放门、加窗户,它自动生成SDF。
启动方法很简单:
gz building_editor
界面打开后,你会看到三个视图:俯视图、3D视图、属性面板。操作逻辑跟画图软件差不多:
- 画墙:点击「Wall」工具,在俯视图上点两个点,墙就出来了。按住Shift可以画直线。
- 加门:选中一段墙,右键选择「Add Door」。门的位置可以拖动调整。
- 加窗户:类似门,选中墙后添加。窗户高度可以调。
- 放家具:左侧模型库里有桌子、椅子、柜子,拖进去就行。
- 导出:画完后,File → Export as SDF。会生成一个.world文件和对应的模型文件夹。
导出后的文件结构是这样的:
my_building/
├── my_building.world
└── models/
└── my_building/
├── model.sdf
└── model.config
你只需要把my_building.world里的内容复制到你的世界文件中,或者直接用gz sim my_building.world启动。
注意:Building Editor导出的模型默认是静态的。如果你想让门可以动(比如作为可开关的门),需要手动修改SDF,添加<joint>标签。这个我们后面讲动态世界时会详细说。
知识体系总览
下面这张图总结了本章的核心逻辑:
这张图把本章的知识点串起来了。你会发现,四个分支最终都指向同一个目标:搭建一个真实、可复用的仿真测试环境。SDF是基础,障碍物和墙壁是内容,光照和纹理是真实感,Building Editor是效率工具。
我个人建议的学习顺序是:先手动写一个简单的SDF世界,理解每个标签的含义。然后用Building Editor快速生成复杂场景。最后再回头手动调整细节——比如光照角度、纹理贴图。这样既有深度,又有广度。
好了,这一讲的内容就到这里。记住:仿真世界是你的试验田,花时间把它搭好,后续的导航调试会事半功倍。