4. Gazebo仿真环境搭建:创建.world文件、添加光照与地面、导入静态物体
好,咱们进入Gazebo仿真环境搭建这一节。说实话,很多初学者一上来就急着让机器人动起来,结果发现仿真环境里一片漆黑,或者机器人直接掉到虚空里去了。嗯,这其实都是.world文件没搞对。
我个人习惯,在开始任何仿真之前,先把环境搭得像个样子。你想想看,一个连地面都没有的世界,机器人往哪站?
4.1 理解.world文件的结构
.world文件,说白了就是Gazebo世界的「剧本」。它告诉Gazebo:你的世界有多大、光照从哪来、地面长什么样、有哪些静态障碍物。
我见过不少项目,直接把.world文件写成几百行的大杂烩。其实没必要。一个干净的世界文件,核心就三块:
- 光照配置:决定场景亮不亮,阴影好不好看
- 地面参数:决定机器人会不会陷下去
- 静态物体:障碍物、桌子、墙壁等
来看一个最简的.world文件骨架:
<?xml version="1.0" ?>
<sdf version="1.6">
<world name="my_workshop">
<!-- 光照 -->
<include>
<uri>model://sun</uri>
</include>
<!-- 地面 -->
<include>
<uri>model://ground_plane</uri>
</include>
<!-- 静态物体 -->
<model name="table">
...
</model>
</world>
</sdf>
注意这个sdf version="1.6",我用的是1.6版本。为什么?因为ROS2和Gazebo Fortress搭配时,1.6最稳。我之前试过1.7,结果某些插件不兼容,折腾了半天。
4.2 添加光照:别让你的机器人活在黑暗中
光照这事,看着简单,其实坑不少。Gazebo默认的太阳光其实够用,但如果你做室内场景,就得自己加光源了。
我建议至少配两种光:
- 环境光:提供基础照明,避免全黑死角
- 方向光:模拟太阳,产生阴影
这里给一个我常用的光照配置:
<light type="directional" name="sun">
<cast_shadows>true</cast_shadows>
<pose>0 0 10 0 0 0</pose>
<diffuse>0.8 0.8 0.8 1</diffuse>
<specular>0.2 0.2 0.2 1</specular>
<direction>-0.5 0.1 -1</direction>
</light>
diffuse值别超过0.9,否则场景会过曝。我刚开始做仿真时,把diffuse设成1.0,结果整个场景白花花一片,连机器人轮廓都看不清。
还有一个容易被忽略的参数——cast_shadows。如果你做视觉相关的仿真(比如目标检测),阴影其实很重要。没有阴影,深度相机出来的数据会失真。
4.3 地面设置:别让机器人「陷」进去
地面这事,看起来简单,但参数调不好,机器人要么陷下去,要么弹起来。
Gazebo自带的ground_plane模型其实够用。但如果你需要自定义地面(比如不同材质、不同摩擦系数),就得自己写。
来看一个带摩擦参数的地面:
<model name="ground">
<static>true</static>
<link name="link">
<collision name="collision">
<geometry>
<plane>
<normal>0 0 1</normal>
<size>100 100</size>
</plane>
</geometry>
<surface>
<friction>
<ode>
<mu>1.0</mu>
<mu2>1.0</mu2>
</ode>
</friction>
</surface>
</collision>
<visual name="visual">
<geometry>
<plane>
<normal>0 0 1</normal>
<size>100 100</size>
</plane>
</geometry>
<material>
<ambient>0.5 0.5 0.5 1</ambient>
<diffuse>0.8 0.8 0.8 1</diffuse>
</material>
</visual>
</link>
</model>
mu和mu2分别代表两个方向的摩擦系数。如果你做全向轮机器人,这两个值最好设成一样,否则转弯时会偏。我曾经在这上面吃过亏,机器人原地转圈时总往一边滑。
地面的大小,我一般设100x100。太小了机器人跑几步就出界,太大了又浪费计算资源。你想想看,如果你的机器人最大速度是1m/s,100x100足够它跑50秒了。
4.4 导入静态物体:让世界丰富起来
静态物体,就是那些不会动的障碍物。桌子、椅子、墙壁、货架……这些在仿真中非常重要。
Gazebo里导入静态物体有两种方式:
| 方式 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| 直接写SDF | 简单几何体(立方体、圆柱) | 无需额外文件,加载快 | 复杂形状写起来麻烦 |
| 导入模型文件 | 复杂物体(桌子、货架) | 外观真实,可直接用现成模型 | 需要下载或自己建模 |
我个人更推荐第二种方式。为什么?因为真实项目里,你不可能用立方体当桌子。客户看到仿真里一个方块在那,会觉得你敷衍。
来看一个导入模型的例子:
<model name="table">
<static>true</static>
<pose>2.0 1.5 0 0 0 0</pose>
<include>
<uri>model://cafe_table</uri>
</include>
</model>
这里static>true</static>是关键。如果不加,物体受重力影响会掉下去。我之前犯过这个错,导入一张桌子,结果它直接砸到地面上,还弹了几下。
pose坐标,Z值要设对。比如桌子高度0.8米,那Z值就设0.4(因为pose是中心点坐标)。我见过有人把Z设成0.8,结果桌子悬在半空中。
4.5 完整的世界文件示例
好了,把上面这些拼起来,就是一个完整的.world文件。我直接给一个我项目里用过的版本:
<?xml version="1.0" ?>
<sdf version="1.6">
<world name="warehouse">
<!-- 光照 -->
<light type="directional" name="sun">
<cast_shadows>true</cast_shadows>
<pose>0 0 20 0 0 0</pose>
<diffuse>0.7 0.7 0.7 1</diffuse>
<specular>0.3 0.3 0.3 1</specular>
<direction>-0.2 0.1 -1</direction>
</light>
<!-- 环境光 -->
<light type="ambient" name="ambient">
<diffuse>0.3 0.3 0.3 1</diffuse>
</light>
<!-- 地面 -->
<include>
<uri>model://ground_plane</uri>
</include>
<!-- 静态障碍物:货架 -->
<model name="shelf_1">
<static>true</static>
<pose>3.0 2.0 0 0 0 0</pose>
<include>
<uri>model://shelf</uri>
</include>
</model>
<model name="shelf_2">
<static>true</static>
<pose>3.0 -2.0 0 0 0 0</pose>
<include>
<uri>model://shelf</uri>
</include>
</model>
<!-- 静态障碍物:桌子 -->
<model name="table">
<static>true</static>
<pose>-2.0 0 0.4 0 0 0</pose>
<include>
<uri>model://cafe_table</uri>
</include>
</model>
</world>
</sdf>
这个文件我实际用过,在一个仓储机器人项目里。货架摆两边,桌子放中间,机器人从中间过道穿行。效果还不错。
4.6 知识体系总览
下面这张图,是我自己总结的.world文件搭建流程。你照着这个顺序来,基本不会出错:
嗯,这张图基本概括了本章的核心。你照着这个顺序来,先搭骨架,再配光照,然后加地面,最后导入物体。每一步测试一下,别一口气写完再跑,那样出了问题很难排查。
好了,这一节的内容就到这。记住,.world文件是仿真世界的基石。地面、光照、静态物体,这三样配好了,你的机器人才能在一个「真实」的环境里跑起来。
可可精品资料库