注:上一章中使用到的ros_control需要apt-get命令安装一下,否则这里的launch文件运行不起来,可以通过下列命令安装:
$ sudo apt-get install ros-kinetic-gazebo-ros-control
1、模型显示
一、为link添加惯性参数和碰撞属性
之前我们创建xacro文件的时候,每个物体只有一个简单的可视化属性,如果要在Gazebo中实现的话,需要对这些可视化模型的每个link添加碰撞属性以及惯性参数。以base_link为例:
<link name="base_link">
<visual>
<origin xyz=" 0 0 0" rpy="0 0 0" />
<geometry>
<cylinder length="${base_length}" radius="${base_radius}"/>
</geometry>
<material name="yellow" />
</visual>
<collision>
<origin xyz=" 0 0 0" rpy="0 0 0" />
<geometry>
<cylinder length="${base_length}" radius="${base_radius}"/>
</geometry>
</collision>
<cylinder_inertial_matrix m="${base_mass}" r="${base_radius}" h="${base_length}" />
</link>
可以对比一下第六章里面的base_link,会发现其下面多了一个collision以及inertial_matrix,这里需要对每一个link都添加这些属性。关于惯性矩阵的运算,可以自行百度。这里也通过宏定义的形式给出了一个惯性矩阵的计算方式:
<xacro:macro name="sphere_inertial_matrix" params="m r">
<inertial>
<mass value="${m}" />
<inertia ixx="${2*m*r*r/5}" ixy="0" ixz="0"
iyy="${2*m*r*r/5}" iyz="0"
izz="${2*m*r*r/5}" />
</inertial>
</xacro:macro>
<xacro:macro name="cylinder_inertial_matrix" params="m r h">
<inertial>
<mass value="${m}" />
<inertia ixx="${m*(3*r*r+h*h)/12}" ixy = "0" ixz = "0"
iyy="${m*(3*r*r+h*h)/12}" iyz = "0"
izz="${m*r*r/2}" />
</inertial>
</xacro:macro>
上面一个为球体的惯性矩阵计算公式,下面为柱体的计算公式。然后在后面通过调用这些宏来实现惯性矩阵的计算。
同样的,需要给所有的link添加惯性参数和碰撞属性。
二、为link添加gazebo标签。
标签的主要内容是为了配置每个link在gazebo中的颜色,例如:
<gazebo reference="base_link">
<material>Gazebo/Blue</material>
</gazebo>
虽然我们之前在rviz仿真中对于每个link设置了颜色标签,但是这些标签在gazebo中是识别不出来的,两个颜色不能互相使用。关于Gazebo/Blue是Gazebo内部定义颜色,具体可以参考Gazebo的官网。主动轮以及支撑轮的设置也是类似。
另外这里还设置了一个重力属性:
<gazebo reference="base_footprint">
<turnGravityOff>false</turnGravityOff>
</gazebo>
这个用在base_footprint中,设置这个的主要原因在于轨迹是一个映射,理论上应该是没有重力的,所以这里我们关闭它的重力属性。
三、为joint添加传动装置。
由于gazebo的控制是针对于joint做控制的,例如我有一个真实的机器人,如果我想让它的轮子动起来,那么我需要一个电机驱动这个轮子做运动。这一步的内容就相当于给我们的机器人模型添加一个电机,也就是一个传动装置:
<transmission name="${prefix}_wheel_joint_trans">
<type>transmission_interface/SimpleTransmission</type>
<joint name="${prefix}_wheel_joint" >
<hardwareInterface>hardware_interface/VelocityJointInterface</hardwareInterface>
</joint>
<actuator name="${prefix}_wheel_joint_motor">
<hardwareInterface>hardware_interface/VelocityJointInterface</hardwareInterface>
<mechanicalReduction>1</mechanicalReduction>
</actuator>
</transmission>
这里使用一个transmission这样一个标签,设置一个速度控制接口来控制运动,就相当于我们在这个joint上安装了一个电机。我们通过控制这个电机来控制这个机器人运动。hardware_interface/VelocityJointInterface为接口类型,这里为速度控制接口;1为减速比,1代表1:1。
四、添加gazebo控制器插件。
我们现在相当于有了一个模型,通过第三步我们模型有了电机,那我们要让这个电机转起来我们还需要一个控制器,我们给控制器发送一个目标速度这个控制器会发送具体转速给电机,所以在我们的模型文件我们添加一个控制器:
<gazebo>
<plugin name="differential_drive_controller"
filename="libgazebo_ros_diff_drive.so"> <!-- gazebo提供得差速控制器插件 -->
<!-- 控制器所需参数 -->
<rosDebugLevel>Debug</rosDebugLevel>
<publishWheelTF>true</publishWheelTF>
<robotNamespace>/</robotNamespace><!-- 机器人命名空间 订阅和发布得话题 前面 会加上命名空间 /说明没有添加-->
<publishTf>1</publishTf>
<publishWheelJointState>true</publishWheelJointState>
<alwaysOn>true</alwaysOn>
<updateRate>100.0</updateRate>
<legacyMode>true</legacyMode>
<leftJoint>left_wheel_joint</leftJoint> <!-- 控制得joint在哪里,必须和上面得joint名称一致 -->
<rightJoint>right_wheel_joint</rightJoint><!-- 控制得joint在哪里,必须和上面得joint名称一致 -->
<wheelSeparation>${wheel_joint_y*2}</wheelSeparation><!-- 两个轮子得间距 -->
<wheelDiameter>${2*wheel_radius}</wheelDiameter>
<broadcastTF>1</broadcastTF>
<wheelTorque>30</wheelTorque>
<wheelAcceleration>1.8</wheelAcceleration>
<commandTopic>cmd_vel</commandTopic> <!-- 订阅得话题:速度控制指令 -->
<odometryFrame>odom</odometryFrame>
<odometryTopic>odom</odometryTopic> <!-- 发布里程计信息 -->
<robotBaseFrame>base_footprint</robotBaseFrame><!-- 设置controler所控制的机器人的坐标系是哪个坐标系 -->
</plugin>
</gazebo>
注意:这里的代码中有一些中文注释,但是在实际代码中是没有的,xacro中最好不要出现中文,否则可能会报参数问题导致无法正常启动。
<plugin name="differential_drive_controller为控制器的名称,可以自己取;filename="libgazebo_ros_diff_drive.so为控制器调用的具体的插件路径,这个插件可以在ROS的路径下找到。下面内容为该插件调用时需要使用到的数据。
五、编写launch文件:
这里的launch文件与前面xacro的文件是不同的,具体代码如下:
<launch>
<!-- 设置launch文件的参数 -->
<arg name="paused" default="false"/>
<arg name="use_sim_time" default="true"/>
<arg name="gui" default="true"/>
<arg name="headless" default="false"/>
<arg name="debug" default="false"/>
<!-- 运行gazebo仿真环境 -->
<include file="$(find gazebo_ros)/launch/empty_world.launch">
<arg name="debug" value="$(arg debug)" />
<arg name="gui" value="$(arg gui)" />
<arg name="paused" value="$(arg paused)"/>
<arg name="use_sim_time" value="$(arg use_sim_time)"/>
<arg name="headless" value="$(arg headless)"/>
</include>
<!-- 加载机器人模型描述参数 -->
<param name="robot_description" command="$(find xacro)/xacro --inorder '$(find mbot_description)/urdf/xacro/gazebo/mbot_gazebo.xacro'" />
<!-- 运行joint_state_publisher节点,发布机器人的关节状态 -->
<node name="joint_state_publisher" pkg="joint_state_publisher" type="joint_state_publisher" ></node>
<!-- 运行robot_state_publisher节点,发布tf -->
<node name="robot_state_publisher" pkg="robot_state_publisher" type="robot_state_publisher" output="screen" >
<param name="publish_frequency" type="double" value="50.0" />
</node>
<!-- 在gazebo中加载机器人模型-->
<node name="urdf_spawner" pkg="gazebo_ros" type="spawn_model" respawn="false" output="screen"
args="-urdf -model mrobot -param robot_description"/>
</launch>
可以看出,其首先启动了一个gazebo的仿真环境(find gazebo_ros)/launch/empty_world.launch),然后加载一个机器人模型,同样的在下面启动一个joint_state_publisher以及robot_state_publisher。最后通过<node name=“urdf_spawner” pkg=“gazebo_ros” type=“spawn_model” respawn=“false” output="screen"节点把机器人放置到gazebo中去。
然后我们可以启动这个launch文件,在shenlan的源码中这个文件在mbot_gazebo文件夹下:
$ roslaunch mbot_gazebo view_gazebo_empty_world.launch
不出意外的话就可以在gazebo中得到一个机器人模型了,但是这里gazebo的启动比较慢,因为它需要远程访问一些国外的网站加载一些模型。可能还会出现连接失败的问题。这里为了保证模型顺利加载,我们也可以将模型文件下载并放置到~/.gazebo/models下。.gazebo为隐藏文件,在home文件夹下,ctrl+h可以显示。下载地址:
https://bitbucket.org/osrf/gazebo_models/downloads/
这里我一开始没有下载的,等了有五六分钟才加载出来,终端还出现了两个警告。
2、创建仿真环境
当我们的机器人出现在gazebo的时候,可以看到我们加载的文件里面只有一个机器人,那我们希望能给它添加一些障碍物,这时应该怎么做呢?
方法一、直接添加环境模型
如果有从上面网址下载过模型放置到model文件夹下的,可以直接在gazebo的左侧列表点击“insert”,可以看到里面会有很多的模型,我们只需要从列表中拖出我们需要的模型放置到仿真环境中就可以了。如果这些模型不能满足建模需求也可以自己通过三维软件搭建模型放到文件夹中使用。例如solidworks建模
方法二、使用building editor环境设计
在gazebo软件上面列表点击:edit-building editor,可以出现一个类似于画板的界面,这个界面可以用于图形编辑,比如说绘制三维场景中的一堵墙或者一个门。
编辑完成后我们点击file-save保存我们的文件,然后退出编辑界面,就可以看到我们的仿真环境已经在gazebo中显示了
然后再点击file-save world as保存我们创建的环境。这里我保存在mbot_gazebo/worlds/文件夹下,命名为room2.world。
如果启动gazebo时希望加载这个模型,可以在launch文件最前面添加:
<arg name="world_name" value="$(find mbot_gazebo)/worlds/room2.world"/>
同时在仿真环境中添加变量:
<arg name="world_name" value="$(arg world_name)"/>
就可以正常启动了。
不过这里我加载出来似乎有点小问题,那张桌子大小变掉了。
另外这里建图保存后会把机器人模型一并保存,所以如果要建立一个空白的gazebo地图的话可以使用:
roslaunch gazebo_ros empty_world.launch
3、机器人仿真
我们首先启动一个仿真环境:
$ roslaunch mbot_gazebo view_mbot_gazebo_play_ground.launch
我们希望它能动起来,那么打开一个键盘控制节点:
$ roslaunch mbot_teleop mbot_teleop.launch
这样就可以使用键盘控制机器人动起来了,同时也可以通过监听odom数据观察机器人的位置。
4、传感器仿真
光有一个机器人的话显的比较单薄,我们希望它能与环境交互,那么我们需要给机器人添加传感器。
类似于之前的控制器插件,gazebo同样拥有很多的传感器插件。
一、摄像头仿真:
这里我们需要一个摄像头的xacro文件,它需要添加碰撞属性以及惯性属性外,还需要添加摄像头传感器插件,具体代码如下:
<?xml version="1.0"?>
<robot xmlns:xacro="http://www.ros.org/wiki/xacro" name="camera">
<xacro:macro name="usb_camera" params="prefix:=camera">
<link name="${prefix}_link">
<inertial>
<mass value="0.1" />
<origin xyz="0 0 0" />
<inertia ixx="0.01" ixy="0.0" ixz="0.0"
iyy="0.01" iyz="0.0"
izz="0.01" />
</inertial>
<visual>
<origin xyz=" 0 0 0 " rpy="0 0 0" />
<geometry>
<box size="0.01 0.04 0.04" />
</geometry>
<material name="black"/>
</visual>
<collision>
<origin xyz="0.0 0.0 0.0" rpy="0 0 0" />
<geometry>
<box size="0.01 0.04 0.04" />
</geometry>
</collision>
</link>
<gazebo reference="${prefix}_link">
<material>Gazebo/Black</material>
</gazebo>
<gazebo reference="${prefix}_link">
<sensor type="camera" name="camera_node">
<update_rate>30.0</update_rate><!-- 摄像头发布频率 -->
<camera name="head">
<horizontal_fov>1.3962634</horizontal_fov><!-- 摄像头可视范围 -->
<image>
<width>1280</width><!-- 摄像头分辨率 -->
<height>720</height><!-- 摄像头分辨率 -->
<format>R8G8B8</format><!-- 摄像头数据格式 -->
</image>
<clip>
<near>0.02</near><!-- 最近距离 -->
<far>300</far><!-- 最远距离 -->
</clip>
<noise>
<type>gaussian</type><!-- 摄像头高斯噪声 -->
<mean>0.0</mean>
<stddev>0.007</stddev>
</noise>
</camera>
<plugin name="gazebo_camera" filename="libgazebo_ros_camera.so"><!-- 加载插件,实现摄像头功能 -->
<alwaysOn>true</alwaysOn>
<updateRate>0.0</updateRate>
<cameraName>/camera</cameraName><!-- 命名空间 -->
<imageTopicName>image_raw</imageTopicName><!-- 发布图片信息话题名称 -->
<cameraInfoTopicName>camera_info</cameraInfoTopicName><!-- 发布摄像头信息话题名称 -->
<frameName>camera_link</frameName><!-- 数据的坐标系统 -->
<hackBaseline>0.07</hackBaseline>
<distortionK1>0.0</distortionK1>
<distortionK2>0.0</distortionK2>
<distortionK3>0.0</distortionK3>
<distortionT1>0.0</distortionT1>
<distortionT2>0.0</distortionT2>
</plugin>
</sensor>
</gazebo>
</xacro:macro>
</robot>
以及这个带摄像头的模型的launch文件:
<launch>
<!-- 设置launch文件的参数 -->
<arg name="world_name" value="$(find mbot_gazebo)/worlds/playground.world"/><!-- 改这 -->
<arg name="paused" default="false"/>
<arg name="use_sim_time" default="true"/>
<arg name="gui" default="true"/>
<arg name="headless" default="false"/>
<arg name="debug" default="false"/>
<!-- 运行gazebo仿真环境 -->
<include file="$(find gazebo_ros)/launch/empty_world.launch">
<arg name="world_name" value="$(arg world_name)" />
<arg name="debug" value="$(arg debug)" />
<arg name="gui" value="$(arg gui)" />
<arg name="paused" value="$(arg paused)"/>
<arg name="use_sim_time" value="$(arg use_sim_time)"/>
<arg name="headless" value="$(arg headless)"/>
</include>
<!-- 加载机器人模型描述参数 -->
<param name="robot_description" command="$(find xacro)/xacro --inorder '$(find mbot_description)/urdf/xacro/gazebo/mbot_with_camera_gazebo.xacro'" /> <!-- 改这 -->
<!-- 运行joint_state_publisher节点,发布机器人的关节状态 -->
<node name="joint_state_publisher" pkg="joint_state_publisher" type="joint_state_publisher" ></node>
<!-- 运行robot_state_publisher节点,发布tf -->
<node name="robot_state_publisher" pkg="robot_state_publisher" type="robot_state_publisher" output="screen" >
<param name="publish_frequency" type="double" value="50.0" />
</node>
<!-- 在gazebo中加载机器人模型-->
<node name="urdf_spawner" pkg="gazebo_ros" type="spawn_model" respawn="false" output="screen"
args="-urdf -model mrobot -param robot_description"/>
</launch>
然后这时候我们运行一下相关的launch文件:
$ roslaunch mbot_gazebo view_mbot_with_camera_gazebo.launch
这时候就可以得到一个新的机器人模型显示在gazebo中了。
我们可以打开它的消息列表,会看到里面有很多关于camera的消息发布出来,然后我们运行一个rqt工具查看一下具体的图像内容:
$ rqt_image_view
最上面选择image_raw就可以显示图像了。
然后我们再启动一个键盘控制节点:
$ roslaunch mbot_teleop mbot_teleop.launch
通过移动机器人的位置我们会发现图像也是会跟随改变的。
二、kinect RGB-D相机仿真
这里加载另外一个launch文件:
$ roslaunch mbot_gazebo view_mbot_with_kinect_gazebo.launch
通过启动rviz界面显示一下摄像头的效果:
$ rosrun rviz rviz
通过添加一个pointcloud2,topic选择/kinect/depth/points。fixed frame选择Kinect_link就可以看到相应的点云信息了。
同样也可以选择添加一个image显示图像信息。
三、激光雷达仿真
同样的需要一个xacro文件:
<?xml version="1.0"?>
<robot xmlns:xacro="http://www.ros.org/wiki/xacro" name="laser">
<xacro:macro name="rplidar" params="prefix:=laser">
<link name="${prefix}_link"> <!-- link标签 -->
<!-- 惯性属性 -->
<inertial>
<mass value="0.1" />
<origin xyz="0 0 0" />
<inertia ixx="0.01" ixy="0.0" ixz="0.0"
iyy="0.01" iyz="0.0"
izz="0.01" />
</inertial>
<visual>
<origin xyz=" 0 0 0 " rpy="0 0 0" />
<geometry>
<cylinder length="0.05" radius="0.05"/>
</geometry>
<material name="black"/>
</visual>
<!-- 碰撞属性 -->
<collision>
<origin xyz="0.0 0.0 0.0" rpy="0 0 0" />
<geometry>
<cylinder length="0.06" radius="0.05"/>
</geometry>
</collision>
</link>
<gazebo reference="${prefix}_link">
<material>Gazebo/Black</material>
</gazebo>
<gazebo reference="${prefix}_link"> <!-- 这个sensor代表的link -->
<sensor type="ray" name="rplidar"> <!-- 这个sensor的类型: ray (射线)-->
<pose>0 0 0 0 0 0</pose>
<visualize>false</visualize>
<update_rate>5.5</update_rate> <!-- 数据更新速率-->
<ray>
<scan><!-- 扫描范围-->
<horizontal>
<samples>360</samples>
<resolution>1</resolution>
<min_angle>-3</min_angle>
<max_angle>3</max_angle>
</horizontal>
</scan>
<range><!-- 扫描距离-->
<min>0.10</min>
<max>6.0</max>
<resolution>0.01</resolution><!-- 精度-->
</range>
<noise>
<type>gaussian</type>
<mean>0.0</mean>
<stddev>0.01</stddev>
</noise>
</ray>
<plugin name="gazebo_rplidar" filename="libgazebo_ros_laser.so"><!-- gazebo中激光雷达插件 -->
<topicName>/scan</topicName>
<frameName>laser_link</frameName>
</plugin>
</sensor>
</gazebo>
</xacro:macro>
</robot>
启动一个launch文件:
$ roslaunch mbot_gazebo view_mbot_with_laser_gazebo.launch
同样可以启动rviz可视化界面查看参数:
$ rosrun rviz rviz
先add一个robotmodel,fixed frame选择odom,可以显示一个机器人模型。
再添加一个laserscan,topic选择scan。就可以在rviz中显示出激光信息了。