在Gazebo中搭建无人机飞行的仿真场景。
环境:Ubuntu18.04、ROS Melodic、Gazebo 9.19
官方教程
Gazebo鼠标操作方法
按住左键:平移
按住右键:缩放
滚轮:缩放
按住滚轮拖动:移动视角
一些重要的路径
Gazebo模型的路径:~/.gazebo/models/
,Gazebo会优先在这里寻找模型
PX4模型的路径:~/PX4_Firmware/Tools/sitl_gazebo/models
PX4世界文件的路径:~/PX4_Firmware/Tools/sitl_gazebo/worlds
。在该路径下的.world
文件,可以被位于~/PX4_Firmware/launch
下的launch文件以<arg name="world" default="$(find mavlink_sitl_gazebo)/worlds/xxx.world"/>
的形式找到,并可用以下方式启动:
roslaunch px4 xxx.launch
SDF文件
使用后缀为.world
的SDF文件描述一个Gazebo的世界场景。虽然在Gazebo中也可以通过可视化的方式搭建世界场景,但其生成的.world
文件中会添加许多默认配置的参数,会使得文件看起来非常杂乱庞大,不易修改。此处通过直接写SDF文件的方法搭建世界场景。
SDF文件官方文档,里面描述了各个标签的含义。
<sdf version="1.6">
<world name="world">
...
</world>
</sdf>
在写SDF文件的时候注意各标签之间的缩进关系。
可以参考官方模型的SDF文件的写法。
所有的参数都可以在Gazebo中调整好之后填入SDF文件中。
光源
日光
<!-- A global light source -->
<include>
<uri>model://sun</uri>
</include>
可调光源
<light name='user_directional_light' type='directional'>
<pose frame=''>2.30045 -0.072071 1 0 -0 0</pose>
<diffuse>0.5 0.5 0.5 1</diffuse>
<specular>0.1 0.1 0.1 1</specular>
<direction>0.1 0.1 -0.9</direction>
<attenuation>
<range>20</range>
<constant>0.5</constant>
<linear>0.01</linear>
<quadratic>0.001</quadratic>
</attenuation>
<cast_shadows>1</cast_shadows>
</light>
还有一种光源类型是type='point'
。
地平面
<!-- A ground plane -->
<include>
<uri>model://ground_plane</uri>
</include>
这个地平面默认是灰色的,而且尺寸好像无法修改。
注意一定要有地平面,不然在物理引擎下,仿真启动之后,其余物体会往下掉。(qaq)
plane
<model name="ground_plane">
<static>true</static>
<link name="link">
<collision name="collision">
<geometry>
<plane>
<normal>0 0 1</normal>
<size>5000 5000</size>
</plane>
</geometry>
<friction>
<ode>
<mu>100</mu>
<mu2>50</mu2>
</ode>
</friction>
</collision>
...
</link>
</model>
可以在其上添加多个<visual>
。
plane一定要设置碰撞属性,不然在它上面的物体也会掉下去。
调整初始视角
<gui fullscreen='0'>
<camera name='user_camera'>
<pose frame=''>46.9439 -26.8589 6.90853 -0 0.125646 3.13697</pose>
<view_controller>orbit</view_controller>
<projection_type>perspective</projection_type>
</camera>
</gui>
修改相机的位姿即可。
背景
<scene>
<grid>0</grid>
<origin_visual>0</origin_visual>
<ambient>0.592 0.624 0.635 1</ambient>
<sky>
<clouds>
<speed>12</speed>
</clouds>
</sky>
<background>0.35 0.35 0.35 1</background>
<shadows>1</shadows>
</scene>
<sky>
的效果是背景有按设定速度移动的云。
圆柱体
<model>
一般由<link>
和<joint>
组成。对于一个静止的场景物体,可以不使用<joint>
,也没有添加惯性属性。
主要是<pose>
、<collision>
和<visual>
的书写,目前还未涉及<inertial>
。
<pose>
的格式为<x y z roll pitch yaw>
。由于可以分别为<model>
、<link>
、<collision>
和<visual>
设置<pose>
,因此对于坐标的计算要清晰。可以在Gazebo中右键单击模型,选择View -> Link Frames
查看模型的坐标系。个人的写法是:<model>
下的<pose>
用于确定整个模型在场景中的位姿,多个<link>
、<collision>
和<visual>
下的<pose>
用来确定模型内各连杆的相对位姿。
一般保持<collision>
和<visual>
的外观、位姿等属性一致。
在<visual>
中可以用<material>
添加颜色或纹理等,见Gazebo Materials。
圆柱体由<cylinder>
定义。
<model name="cylinder">
<pose>-11 20 0 0 0 0</pose>
<link name="link">
<pose>0 0 2.5 0 0 0</pose>
<collision name="collision">
<geometry>
<cylinder>
<radius>0.5</radius>
<length>5</length>
</cylinder>
</geometry>
</collision>
<visual name="visual">
<geometry>
<cylinder>
<radius>0.5</radius>
<length>5</length>
</cylinder>
</geometry>
<material>
<script>
<uri>file://media/materials/scripts/gazebo.material</uri>
<name>Gazebo/SkyBlue</name>
</script>
</material>
</visual>
</link>
</model>
长方体
长方体由<box>
定义。
<model name="box">
<pose>5 13 0 0 0 1.57519</pose>
<link name="block">
<pose>0 0 2.5 0 0 0</pose>
<visual name="visual">
<geometry>
<box>
<size>6 0.2 5</size>
</box>
</geometry>
<material>
<script>
<uri>file://media/materials/scripts/gazebo.material</uri>
<name>Gazebo/Wood</name>
</script>
</material>
</visual>
<collision name="collision">
<geometry>
<box>
<size>6 0.2 5</size>
</box>
</geometry>
</collision>
</link>
</model>
圆环
圆的曲线实际上是由折线近似的,由<polyline>
定义,需要给出每个端点的坐标。计算代码如下:
import numpy
import matplotlib.pyplot as plt
from math import cos, sin, pi
xs = []
ys = []
x0, y0 = 0, 0 # origin
r = 1.1 # radius
for angle in range(0, 360, 20):
x = x0 + r * cos(angle * pi / 180)
y = y0 + r * sin(angle * pi / 180)
xs.append(x)
ys.append(y)
xs.append(x0 + r * cos(360 * pi / 180))
ys.append(y0 + r * sin(360 * pi / 180))
# plt.plot(xs, ys)
# plt.show()
for i in range(len(xs)):
print ('<point>' + str(xs[i]) + ' ' + str(ys[i]) + '</point>')
分别生成外圆和内圆的点,并将输出的内容复制到SDF文件中的相应部分即可。
圆环与其基座
此处所搭建的圆环具有两个部分:圆环和支撑圆环的柱子。由于这两个部分是连接在一起的,因此如果写两个<link>
的话,一定要把<joint>
写上,否则仿真开始运行之后这两部分会分崩离析qaq。
还有一种写法是只写一个<link>
,但是分别设置两对<collision>
和<visual>
。在这里分别为<collision>
和<visual>
设置了位姿。
<model name="RING">
<pose>8 -14 0 0 0 0</pose>
<link name='ring'>
<visual name='ring_visual'>
<pose>0 0 4 1.57519 0 0</pose>
<geometry>
<polyline>
<height>0.1</height>
<point>1.0 0.0</point>
<point>0.9396926207859084 0.3420201433256687</point>
<point>0.766044443118978 0.6427876096865393</point>
<point>0.5000000000000001 0.8660254037844386</point>
<point>0.17364817766693041 0.984807753012208</point>
<point>-0.1736481776669303 0.984807753012208</point>
<point>-0.4999999999999998 0.8660254037844387</point>
<point>-0.7660444431189779 0.6427876096865395</point>
<point>-0.9396926207859083 0.3420201433256689</point>
<point>-1.0 1.2246467991473532e-16</point>
<point>-0.9396926207859084 -0.34202014332566866</point>
<point>-0.766044443118978 -0.6427876096865393</point>
<point>-0.5000000000000004 -0.8660254037844384</point>
<point>-0.17364817766693033 -0.984807753012208</point>
<point>0.17364817766692997 -0.9848077530122081</point>
<point>0.5000000000000001 -0.8660254037844386</point>
<point>0.7660444431189778 -0.6427876096865396</point>
<point>0.9396926207859084 -0.3420201433256686</point>
<point>1.0 -2.4492935982947064e-16</point>
</polyline>
<polyline>
<height>0.1</height>
<point>1.1 0.0</point>
<point>1.0336618828644994 0.37622215765823563</point>
<point>0.8426488874308758 0.7070663706551933</point>
<point>0.5500000000000002 0.9526279441628825</point>
<point>0.19101299543362346 1.0832885283134288</point>
<point>-0.19101299543362335 1.0832885283134288</point>
<point>-0.5499999999999998 0.9526279441628827</point>
<point>-0.8426488874308757 0.7070663706551935</point>
<point>-1.0336618828644992 0.3762221576582358</point>
<point>-1.1 1.3471114790620887e-16</point>
<point>-1.0336618828644994 -0.3762221576582356</point>
<point>-0.8426488874308758 -0.7070663706551933</point>
<point>-0.5500000000000005 -0.9526279441628823</point>
<point>-0.19101299543362338 -1.0832885283134288</point>
<point>0.191012995433623 -1.083288528313429</point>
<point>0.5500000000000002 -0.9526279441628825</point>
<point>0.8426488874308756 -0.7070663706551936</point>
<point>1.0336618828644994 -0.37622215765823547</point>
<point>1.1 -2.6942229581241775e-16</point>
</polyline>
</geometry>
<material>
<script>
<uri>file://media/materials/scripts/gazebo.material</uri>
<name>Gazebo/Yellow</name>
</script>
</material>
</visual>
<collision name='ring_collision'>
...
</collision>
<visual name="pole_visual">
<pose>0 -0.05 1.5 0 0 0</pose>
<geometry>
<box>
<size>0.1 0.1 3</size>
</box>
</geometry>
<material>
<script>
<uri>file://media/materials/scripts/gazebo.material</uri>
<name>Gazebo/Yellow</name>
</script>
</material>
</visual>
<collision name="pole_collision">
<pose>0 -0.05 1.5 0 0 0</pose>
<geometry>
<box>
<size>0.1 0.1 3</size>
</box>
</geometry>
</collision>
</link>
</model>
<polyline>
中的<height>
即是圆环的高度。将其设置大一点,圆环就成了圆筒。
运动的圆环
actor
使用<actor>
搭建具有简单运动的圆环。
一个SDF文件里只能有一个<actor>
。
<actor name="MOVING_RING">
<pose>-3 0 0 0 0 1.57519</pose>
<link name='moving_ring'>
...
</link>
<script>
<loop>true</loop>
<delay_start>0.000000</delay_start>
<auto_start>true</auto_start>
<trajectory id="0" type="line">
<waypoint>
<time>0.0</time>
<pose>-3 0 0 0 0 1.57519</pose>
</waypoint>
<waypoint>
<time>3.0</time>
<pose>-3 -6 0 0 0 1.57519</pose>
</waypoint>
<waypoint>
<time>6.0</time>
<pose>-3 0 0 0 0 1.57519</pose>
</waypoint>
</trajectory>
</script>
</actor>
plugin
另一种搭建运动模型的方式是编写插件。
仿真环境的运行
以静止的方式运行仿真环境:
gazebo -u field.world
直接运行仿真环境:
gazebo field.world
仿真复位
rosservice call /gazebo/reset_simulation "{}"