3、创建第一个仿真世界:SDF文件格式入门、构建简单地面与光照、保存与加载自定义世界
好,咱们正式开始动手了。
上一章我们把Gazebo装好、跑通了那个空荡荡的默认世界。说实话,我第一次看到那个灰色网格地面时,心里还挺激动的——但很快就不满足了。你想想看,一个仿真环境连个像样的地面都没有,怎么跑机器人?
这一章,我们就来亲手搭建第一个仿真世界。核心武器就是——SDF文件。
3.1 SDF到底是什么?
SDF,全称是Simulation Description Format。说白了,它就是Gazebo用来描述仿真世界的“剧本”。
你告诉它:这里放一块地面,那里打一束光,墙角放个箱子……SDF文件把这些信息全部写下来。Gazebo启动时,照着剧本把世界搭出来。
我个人习惯把SDF类比成HTML——HTML描述网页长什么样,SDF描述仿真世界长什么样。结构清晰,层级分明,一看就懂。
核心要点:
- SDF是XML格式,标签成对出现
- 根标签是
<sdf>,里面包<world> - 一个world里可以有多个model、light、plugin等
嗯,这里要注意:SDF有两个版本,1.6和1.7。Gazebo 9以上默认用1.7。我建议你直接用1.7,省得后面踩坑。
3.2 从零写一个SDF世界文件
别怕,咱们不搞复杂的。先写一个最简单的世界:一块地面,一束光。
<?xml version="1.0" ?>
<sdf version="1.7">
<world name="my_first_world">
<!-- 地面 -->
<model name="ground_plane">
<static>true</static>
<link name="link">
<collision name="collision">
<geometry>
<plane>
<normal>0 0 1</normal>
<size>100 100</size>
</plane>
</geometry>
</collision>
<visual name="visual">
<geometry>
<plane>
<normal>0 0 1</normal>
<size>100 100</size>
</plane>
</geometry>
<material>
<ambient>0.8 0.8 0.8 1</ambient>
<diffuse>0.8 0.8 0.8 1</diffuse>
</material>
</visual>
</link>
</model>
<!-- 光照 -->
<light name="sun" type="directional">
<cast_shadows>true</cast_shadows>
<pose>0 0 10 0 0 0</pose>
<diffuse>1 1 1 1</diffuse>
<specular>0.5 0.5 0.5 1</specular>
<direction>-0.5 0.1 -1</direction>
</light>
</world>
</sdf>
这段代码干了三件事:
- 定义了一个名为
my_first_world的世界 - 放了一个100x100的灰色地面,带碰撞和视觉属性
- 加了一束方向光,模拟太阳,带阴影
我在项目中遇到过有人把 <static> 写成 false,结果地面一碰就飞了……记住,地面必须是静态的,true 别写错。
3.3 保存与加载自定义世界
写好的文件怎么用?很简单。
第一步:保存
把上面的代码复制到一个文本文件里,命名为 my_first_world.sdf。我习惯放在 ~/.gazebo/worlds/ 目录下,方便管理。
mkdir -p ~/.gazebo/worlds
# 把文件保存到 ~/.gazebo/worlds/my_first_world.sdf
第二步:加载
启动Gazebo时,用 --world 参数指定你的SDF文件:
gazebo --world ~/.gazebo/worlds/my_first_world.sdf
或者,如果你已经打开了Gazebo,也可以通过菜单 File → Open World 来加载。
小技巧:
我曾经在调试时反复修改SDF文件,每次都要手动重启Gazebo,很烦。后来发现可以用 gzserver 和 gzclient 分开启动,改完SDF后只重启 gzserver 就行,快很多。
3.4 理解地面与光照的细节
咱们再深入一点,看看刚才代码里那些参数到底什么意思。
地面参数解析
| 参数 | 含义 | 我的建议 |
|---|---|---|
<normal> |
地面的法线方向 | 默认0 0 1(朝上),别改 |
<size> |
地面的长宽 | 100x100够用,太大影响性能 |
<ambient> |
环境光颜色 | 灰色0.8 0.8 0.8比较自然 |
<diffuse> |
漫反射颜色 | 和ambient保持一致即可 |
你可能会问:为什么地面要同时定义 collision 和 visual?
这是Gazebo的设计哲学——碰撞几何和视觉几何可以不一样。比如你做一个精细的机器人模型,视觉部分可以很复杂,但碰撞部分用简单的长方体就行,这样仿真跑得快。地面简单,所以两者保持一致。
光照参数解析
| 参数 | 含义 | 注意事项 |
|---|---|---|
type |
光源类型 | directional(方向光)、point(点光源)、spot(聚光灯) |
<cast_shadows> |
是否投射阴影 | true才有真实感,但耗性能 |
<direction> |
光线方向 | 负值表示从斜上方照下来 |
我记得有一次做室内仿真,用了点光源但忘了调 attenuation(衰减),结果整个房间亮得像白天……后来加了衰减参数才正常。如果你做室内场景,记得加上 <attenuation><range>20</range></attenuation>。
3.5 本章知识体系
下面这张图帮你理清SDF世界的核心结构:
从这张图可以看得很清楚:一个SDF世界文件,根节点是 <sdf>,里面包一个 <world>,world下面可以放任意多个model、light、plugin。每个model又包含static、link等子标签,link下面再细分collision、visual、inertial。
说白了,这就是一个树形结构。你只要记住这个骨架,写任何SDF文件都不会迷路。
3.6 动手试试
光看不练假把式。我建议你现在就做三件事:
- 把上面的SDF代码复制下来,保存成
my_first_world.sdf - 用Gazebo加载它,看看地面和光照效果
- 试着改改
<diffuse>的颜色值,比如改成0.2 0.6 0.2 1(绿色地面),重新加载看看变化
注意:
如果你改了SDF文件但Gazebo里没变化,别慌。先检查文件有没有保存,再确认Gazebo加载的是不是同一个文件。我曾经在这上面浪费了半小时——改完忘了保存,还以为是Gazebo出bug了。
好了,这一章的内容就到这儿。你亲手创建了第一个仿真世界,虽然简单,但这是万里长征的第一步。后面我们会往这个世界里加机器人、加传感器、让它动起来。
可可精品资料库