在这个-SLAM建图和导航仿真实例-项目中,主要分为三个部分,分别是
该项目的slam_bot已经上传我的Github。
由于之前的虚拟机性能限制,我在这个项目中使用了新的ubantu 16.04环境,虚拟机配置
使用Solidworks建立模型如下图,其中有很多部分值得注意。
值得注意的是,在下图中有两个坐标系,分别是坐标系1和coordinate0。在一开始,我没有意识到使用coordinate0作为坐标原点是一个多么错误的选择。在后来使用skid_steer_drive_controller
gazebo插件时,模型一直在原地转圈,直到我在rviz中查看tf转换关系时,才发现是错误的tf转换,导致了插件的控制错误。所以一定要严格遵循上述所说的坐标系建立规则。
使用solidworks的urdf_exporter插件导出urdf和模型文件。在图1-2中base_link忘记选择参考坐标系了,若以上图坐标系为准,则需要选择 - 坐标系1。
关于更多urdf_exporter安装和使用可以参考我的博客-【从零开始的ROS四轴机械臂控制】(一)- 实际模型制作、Solidworks文件转urdf与rviz仿真.。
若选择无误,就可以导出模型了。
我在Github中提供了最初始的slam_bot package文件。
导航到urdf文件夹
$ ~/catkin_ws/src/slam_bot/urdf
将slam_bot.urdf
更名成slam_bot.xacro
,并新建slam_bot.gazebo.xacro
文件。
添加xacro namespace。
<robot name="slam_bot" xmlns:xacro="http://www.ros.org/wiki/xacro">
添加slam_bot.gazebo.xacro,导入gazebo插件
<xacro:include filename="$(find slam_bot)/urdf/slam_bot.gazebo.xacro" />
在base_link节点之前添加base_footprint节点
<link name="base_footprint"> link>
<joint name="base_link_joint" type="fixed">
<origin xyz="0 0 0" rpy="0 0 0" />
<parent link="base_footprint"/>
<child link="base_link" />
joint>
在camera节点之后添加laser节点
<link name="hokuyo">
<collision>
<origin xyz="0 0 0" rpy="0 0 0"/>
<geometry>
<mesh filename="package://slam_bot/meshes/hokuyo.dae"/>
geometry>
collision>
<visual>
<origin xyz="0 0 0" rpy="0 0 0"/>
<geometry>
<mesh filename="package://slam_bot/meshes/hokuyo.dae"/>
geometry>
<material name="red">
<color rgba="1.0 0 0 1.0"/>
material>
visual>
<inertial>
<mass value="1e-5" />
<origin xyz="0 0 0" rpy="0 1.57 0"/>
<inertia ixx="1e-6" ixy="0" ixz="0" iyy="1e-6" iyz="0" izz="1e-6" />
inertial>
link>
<joint name="hokuyo_joint" type="fixed">
<axis xyz="0 0 0" />
<origin xyz="0 0 0" rpy="0 0 0"/>
<parent link="base_link"/>
<child link="hokuyo"/>
joint>
更改各个joint设置,如joint_wheel_FR。注意
的设置,否则也会导致错误的控制。
<joint
name="joint_wheel_FR"
type="continuous">
<origin
xyz="0.0800000000000013 -0.0799999999999997 0.04"
rpy="0 0 0" />
<parent
link="base_link" />
<child
link="link_wheel_FR" />
<axis
xyz="0 1 0" />
joint>
joint type设置为“continuous”,类似于转动关节,但对其旋转没有限制。它可以绕一个轴连续旋转。关节会有自己的旋转轴axis
,一些特定的关节动力学dynamics
与关节的物理特性(如“摩擦”)相对应,以及对该关节施加最大“努力”和“速度”的某些限制limits
。这些限制对于物理机器人是有用的约束,并且可以帮助在仿真中创建更健壮的机器人模型。
点击这里来更好地理解这些限制。
RGB-D点云是默认朝上,需向slam_bot.xacro中添加如下的link和joint
<link name="camera_depth_optical_frame" />
<joint name="camera_depth_optical_joint" type="fixed">
<origin rpy="-1.57079632679 0 -1.57079632679" xyz="0 0 0" />
<parent link="camera"/>
<child link="camera_depth_optical_frame" />
joint>
添加如下插件
skid_steer_drive_controller
libgazebo_ros_openni_kinect
head_hokuyo_sensor
<robot>
<gazebo>
<plugin name="skid_steer_drive_controller" filename="libgazebo_ros_skid_steer_drive.so">
<alwaysOn>truealwaysOn>
<updateRate>100.0updateRate>
<robotNamespace>/robotNamespace>
<leftFrontJoint>joint_wheel_FLleftFrontJoint>
<rightFrontJoint>joint_wheel_FRrightFrontJoint>
<leftRearJoint>joint_wheel_BLleftRearJoint>
<rightRearJoint>joint_wheel_BRrightRearJoint>
<wheelSeparation>0.16wheelSeparation>
<wheelDiameter>0.08wheelDiameter>
<robotBaseFrame>base_footprintrobotBaseFrame>
<torque>20torque>
<commandTopic>cmd_velcommandTopic>
<odometryTopic>odomodometryTopic>
<odometryFrame>odomodometryFrame>
<broadcastTF>1broadcastTF>
plugin>
gazebo>
<gazebo reference="camera">
<sensor type="depth" name="camera">
<always_on>truealways_on>
<visualize>falsevisualize>
<update_rate>15.0update_rate>
<camera name="front">
<horizontal_fov>1.047197horizontal_fov>
<image>
<format>B8G8R8format>
<width>400width>
<height>300height>
image>
<clip>
<near>0.01near>
<far>8far>
clip>
camera>
<plugin name="camera_controller" filename="libgazebo_ros_openni_kinect.so">
<baseline>0.1baseline>
<alwaysOn>truealwaysOn>
<updateRate>15.0updateRate>
<cameraName>cameracameraName>
<imageTopicName>/camera/rgb/image_rawimageTopicName>
<cameraInfoTopicName>/camera/rgb/camera_infocameraInfoTopicName>
<depthImageTopicName>/camera/depth/image_rawdepthImageTopicName>
<depthImageCameraInfoTopicName>/camera/depth_registered/camera_infodepthImageCameraInfoTopicName>
<pointCloudTopicName>/camera/depth_registered/pointspointCloudTopicName>
<frameName>camera_depth_optical_frameframeName>
<pointCloudCutoff>0.35pointCloudCutoff>
<pointCloudCutoffMax>4.5pointCloudCutoffMax>
<CxPrime>0CxPrime>
<Cx>0Cx>
<Cy>0Cy>
<focalLength>0focalLength>
<hackBaseline>0hackBaseline>
plugin>
sensor>
gazebo>
<gazebo reference="hokuyo">
<sensor type="ray" name="head_hokuyo_sensor">
<pose>0 0 0 0 0 0pose>
<visualize>falsevisualize>
<update_rate>40update_rate>
<ray>
<scan>
<horizontal>
<samples>720samples>
<resolution>1resolution>
<min_angle>-1.570796min_angle>
<max_angle>1.570796max_angle>
horizontal>
scan>
<range>
<min>0.10min>
<max>30.0max>
<resolution>0.01resolution>
range>
<noise>
<type>gaussiantype>
<mean>0.0mean>
<stddev>0.01stddev>
noise>
ray>
<plugin name="gazebo_ros_head_hokuyo_controller" filename="libgazebo_ros_laser.so">
<topicName>/slam_bot/laser/scantopicName>
<frameName>hokuyoframeName>
plugin>
sensor>
gazebo>
robot>
在worlds中储存gazebo world。world是模型的集合,还可以定义此world特定的其他几个物理属性。
让我们创建一个简单的世界,其中没有将在以后的gazebo中启动的对象或模型。
$ cd worlds
$ nano slam.world
将以下内容添加到 slam.world
<sdf version="1.4">
<world name="default">
<include>
<uri>model://ground_planeuri>
include>
<include>
<uri>model://sunuri>
include>
<gui fullscreen='0'>
<camera name='world_camera'>
<pose>4.927360 -4.376610 3.740080 0.000000 0.275643 2.356190pose>
<view_controller>orbitview_controller>
camera>
gui>
world>
sdf>
.world
文件使用 XML 文件格式来描述所有被定义为 Gazeboeboard 环境的元素。在上面创建的简单世界有以下元素
: 基本元素,封装了整个文件结构和内容。
:世界元素定义了世界描述和与世界相关的几个属性。每个模型或属性可以有更多的元素来描述它。例如,camera
有一个pose
元素,定义了它的位置和方向。
:include元素和
元素一起,提供了通往特定模型的路径。在Gazebo中,有几个模型是默认包含的,可以在创建环境时包含它们。
创建一个新的启动文件,这将有助于加载URDF文件。
$ cd ~/catkin_ws/src/slam/launch/
$ nano robot_description.launch
将以下内容复制到上述文件中。
<launch>
<param name="robot_description" command="$(find xacro)/xacro --inorder '$(find slam_bot)/urdf/slam_bot.xacro'" />
<node name="joint_state_publisher" pkg="joint_state_publisher" type="joint_state_publisher">
<param name="use_gui" value="false"/>
node>
<node name="robot_state_publisher" pkg="robot_state_publisher" type="robot_state_publisher" respawn="false" output="screen"/>
launch>
上面的代码定义了一个参数robot_description,该参数用于设置单个命令,以使用xacro软件包从xacro文件生成URDF。
借助robot_description生成的URDF文件,gazebo_ros包生成对应模型。
接下来创建一个launch文件。ROS中的启动文件使我们可以同时执行多个节点,这有助于避免在单独的shell或终端中定义和启动多个节点的繁琐工作。
$ nano slam.launch
将以下内容添加到启动文件中。
<launch>
<include file="$(find slam_bot)/launch/robot_description.xml"/>
<arg name="world" default="empty"/>
<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"/>
<include file="$(find gazebo_ros)/launch/empty_world.launch">
<arg name="world_name" value="$(find slam_bot)/worlds/kitchen_dining.world"/>
<arg name="paused" value="$(arg paused)"/>
<arg name="use_sim_time" value="$(arg use_sim_time)"/>
<arg name="gui" value="$(arg gui)"/>
<arg name="headless" value="$(arg headless)"/>
<arg name="debug" value="$(arg debug)"/>
include>
<node name="urdf_spawner" pkg="gazebo_ros" type="spawn_model" respawn="false"
output="screen" args="-urdf -param robot_description -model slam_bot"/>
<node name="rviz" pkg="rviz" type="rviz" respawn="false"/>
launch>
和.world
文件一样,.launch
文件也是基于XML的。
首先,使用
元素定义某些参数。每个这样的元素都会有一个name
属性和一个default
值。
然后,在gazebo_ros
包中包含了empty_world.launch
文件。empty_world文件包含了一组重要的定义,这些定义被我们创建的world所继承。使用 world_name
参数和传递给该参数的value
的.world
文件的路径,所以我们能够在 Gazebo 中启动world。
现在可以使用启动文件来启动Gazebo环境。
$ cd ~/catkin_ws/
$ catkin_make
$ source devel/setup.bash
$ roslaunch slam slam.launch
若gazebo长时间打不开,解决办法如下
cd ~/
hg clone https://bitbucket.org/osrf/gazebo_models
下载完成后将gazebo_models复制到~/.gazebo
文件夹中,重命名为models
。
若模型正常运行,则如图3-1所示。
这次,凉亭和RViz都应该启动。加载后
选择RViz窗口,然后在左侧的Displays中:
点击“Add”按钮,然后
机器人模型应在RViz中加载。
在凉亭中,单击“插入”,然后从列表中添加机器人前面世界中的任何物品。
至此应该能够在Rviz中的“pointcloud2”查看器中看到该项目,并且也可以对该对象进行激光扫描。
图3-2来自较旧版本的模型,所以看起来与之前模型会有所不同。
在上述所有内容仍在运行时,打开一个新的终端窗口,然后输入
$ rostopic pub /cmd_vel geometry_msgs/Twist "linear:
x: 0.1
y: 0.0
z: 0.0
angular:
x: 0.0
y: 0.0
z: 0.0"
上面的命令会将消息发布到cmd_vel,这是在驱动器控制器插件中定义的主题。
可以看到模型正常移动,gazebo因为录屏软件奔溃了,不过正常运行是不会这样的。
模型应当沿x轴正方向移动,如果出现运动不正常的现象,可以检查
skid_steer_drive_controller
定义rosrun tf view_frames
以查看tf信息创建和查看tf-tree是确保所有链接顺序正确的好方法。