1.概述
欢迎来到Project 3: Map My World(绘制我的世界地图)!在这个项目中,将使用RTAB-Map包从模拟环境中使用机器人创建一个2D占用网格和3D octomap。RTAB-Map(基于实时外观的映射)是SLAM开发能够三维映射环境的机器人的流行解决方案。RTAB-Map具有良好的速度和内存管理,并为信息分析提供了定制开发的工具。尤其重要的是,ROS Wiki (rtabmap_ros - ROS Wiki)上的文档质量非常高,若能够结合利用好RTAB-Map与机器人,将给绘图及定位打下一个坚实的基础。
对于这个项目,我们将使用rtabmap_ros包,这是一个用于与RTAB-Map交互的ROS包装器(API)。在查看相关文档时请记住这一点。
项目说明
项目流程如下:
1)将开发自己的包来与rtabmap_ros包进行接口。
2)在上一个定位项目的基础上进行必要的更改,以便将机器人与RTAB-Map连接起来。这方面的一个例子是RGB-D相机的添加。
3)确保所有文件都在适当的位置,所有链接都正确连接,命名设置正确,主题映射正确。此外,还需要生成适当的启动文件来启动机器人并映射其周围环境。
4)当机器人启动后,teleop控制它在房间里移动,生成一个适当的环境地图。
2.仿真设置
设置catkin_ws文件夹以及src文件夹,然后从上一个项目抓取代码(复制上一个项目的模拟环境和机器人)至重新命名的文件包( 比如:myrobotb)中。即,创建用于启动Gazebo世界和机器人模拟的包。然后运行catkin_make和source devel/setup.bash脚本。启动world.launch以验证是否可以正常运行!
roslaunch myrobotb world.launch
3.RTAB-Map包
RTAB-Map Pacakge
尽管ROS提供了大量的包,但是集成ROS包需要理解包本身以及它如何连接到项目。最好从RTAB-Map ROS Wiki页面开始。
根据文档http://wiki.ros.org/rtabmap_ros/Tutorials/SetupOnYourRobot,推荐的机器人配置要求:
1)一个2D Laser,提供sensor_msgs/LaserScan消息的测程传感器;
2)提供nav_msgs/Odometry消息的3D 摄像传感器;
3)兼容openni_launch, openni2_launch或freenect_launch ROS包。
但似乎我们缺少3D摄像传感器!
4.传感器升级
在之前的项目中,使用RGB相机,现在是时候给机器人升级了。具体来说,我们将为RTAB-Map使用一个模拟Kinect摄像头。升级传感器如下:
增加optical
摄像头链接
对于URDF文件中的RGB-D相机,为了使Gazebo中的相机图像与机器人正确对齐,需要在相机链接上增加一个额外的链接和一个额外的关节。注意,camera_optical_joint的父链接应该正确配置为原始摄像机链接。在机器人的.xacro文件中添加以下关节和链接:
<joint name="camera_optical_joint" type="fixed">
<origin xyz="0 0 0" rpy="-1.5707 0 -1.5707"/>
<parent link="camera_link"/>
<child link="camera_link_optical"/>
</joint>
<link name="camera_link_optical">
</link>
配置RGB-D摄像头
为此,我们需要替换现有的相机及其共享目标文件:libgazebo_ros_camera. so到Kinect共享目标文件:libgazebo_ros_openni_kinect.so。同时,更新<frameName>为刚才创建的camera_link_optical链接。
除此之外,还需要为RGB-D相机设置额外的参数,并与现实世界中对应的驱动程序发布的主题相匹配。我们为下面的摄像机代码提供了一个示例。把它替换到现有的机器人的.gazebo文件中!
下面提供了一段摄像机代码:
<!-- RGBD Camera -->
<gazebo reference="camera_link">
<sensor type="depth" name="camera1">
<always_on>1</always_on>
<update_rate>20.0</update_rate>
<visualize>true</visualize>
<camera>
<horizontal_fov>1.047</horizontal_fov>
<image>
<width>640</width>
<height>480</height>
<format>R8G8B8</format>
</image>
<depth_camera>
</depth_camera>
<clip>
<near>0.1</near>
<far>20</far>
</clip>
</camera>
<plugin name="camera_controller" filename="libgazebo_ros_openni_kinect.so">
<alwaysOn>true</alwaysOn>
<updateRate>10.0</updateRate>
<cameraName>camera</cameraName>
<frameName>camera_link_optical</frameName>
<imageTopicName>rgb/image_raw</imageTopicName>
<depthImageTopicName>depth/image_raw</depthImageTopicName>
<pointCloudTopicName>depth/points</pointCloudTopicName>
<cameraInfoTopicName>rgb/camera_info</cameraInfoTopicName>
<depthImageCameraInfoTopicName>depth/camera_info</depthImageCameraInfoTopicName>
<pointCloudCutoff>0.4</pointCloudCutoff>
<hackBaseline>0.07</hackBaseline>
<distortionK1>0.0</distortionK1>
<distortionK2>0.0</distortionK2>
<distortionK3>0.0</distortionK3>
<distortionT1>0.0</distortionT1>
<distortionT2>0.0</distortionT2>
<CxPrime>0.0</CxPrime>
<Cx>0.0</Cx>
<Cy>0.0</Cy>
<focalLength>0.0</focalLength>
</plugin>
</sensor>
</gazebo>
5.RTAB-Map Launch文件
Launch文件
添加RTAB-Map的启动文件:mapping.launch
我们的映射启动文件充当主节点,它与能够使用RTAB-Map执行SLAM所需的所有部件进行接口。以下提供一个mapping.launch启动文件的标记模板。在launch文件夹创建mapping.launch启动文件。
通读代码和注释,了解每个部分实现了什么以及原因。请随意使用RTAB-Map的文档学习,以超越这个模板。这里的任务是将正确的主题重新映射到rtabmap所需的主题。
scan
rgb/image
depth/image
rgb/camera_info
在机器人的urdf文件中,找到机器人要发布到的实际主题。当找到正确的值时,把它们代入在此启动文件的开头 <arg> 标签,然后mapping 节点就可以找到执行RTAB-Mapping所需的所有信息!
<?xml version="1.0" encoding="UTF-8"?>
<launch>
<!-- Arguments for launch file with defaults provided -->
<arg name="database_path" default="rtabmap.db"/>
<arg name="rgb_topic" default="/camera/rgb/image_raw"/>
<arg name="depth_topic" default="/camera/depth/image_raw"/>
<arg name="camera_info_topic" default="/camera/rgb/camera_info"/>
<!-- Mapping Node -->
<group ns="rtabmap">
<node name="rtabmap" pkg="rtabmap_ros" type="rtabmap" output="screen" args="--delete_db_on_start">
<!-- Basic RTAB-Map Parameters -->
<param name="database_path" type="string" value="$(arg database_path)"/>
<param name="frame_id" type="string" value="base_footprint"/>
<param name="odom_frame_id" type="string" value="odom"/>
<param name="subscribe_depth" type="bool" value="true"/>
<param name="subscribe_scan" type="bool" value="true"/>
<!-- RTAB-Map Inputs -->
<remap from="scan" to="/scan"/>
<remap from="rgb/image" to="$(arg rgb_topic)"/>
<remap from="depth/image" to="$(arg depth_topic)"/>
<remap from="rgb/camera_info" to="$(arg camera_info_topic)"/>
<!-- RTAB-Map Output -->
<remap from="grid_map" to="/map"/>
<!-- Rate (Hz) at which new nodes are added to map -->
<param name="Rtabmap/DetectionRate" type="string" value="1"/>
<!-- 2D SLAM -->
<param name="Reg/Force3DoF" type="string" value="true"/>
<!-- Loop Closure Detection -->
<!-- 0=SURF 1=SIFT 2=ORB 3=FAST/FREAK 4=FAST/BRIEF 5=GFTT/FREAK 6=GFTT/BRIEF 7=BRISK 8=GFTT/ORB 9=KAZE -->
<param name="Kp/DetectorStrategy" type="string" value="0"/>
<!-- Maximum visual words per image (bag-of-words) -->
<param name="Kp/MaxFeatures" type="string" value="400"/>
<!-- Used to extract more or less SURF features -->
<param name="SURF/HessianThreshold" type="string" value="100"/>
<!-- Loop Closure Constraint -->
<!-- 0=Visual, 1=ICP (1 requires scan)-->
<param name="Reg/Strategy" type="string" value="0"/>
<!-- Minimum visual inliers to accept loop closure -->
<param name="Vis/MinInliers" type="string" value="15"/>
<!-- Set to false to avoid saving data when robot is not moving -->
<param name="Mem/NotLinkedNodesKept" type="string" value="false"/>
</node>
</group>
</launch>
更多信息参考:
6.RTAB-Map实时可视化
实时可视化
可以使用的另一个工具是rtabmapviz,它是用于特性映射、循环闭包等实时可视化的附加节点。由于计算开销,不建议在模拟中映射时使用此工具。Rtabmapviz非常适合在实时映射期间部署在真实的机器人上,以确保获得完成循环闭包所需的特性。
如果您希望为映射启用它,请将此代码片段添加到mapping.launch文件。这将启动rtabmapviz GUI,并为您提供实时特征检测、循环闭包和映射过程的其他相关信息。
<!-- visualization with rtabmapviz -->
<node pkg="rtabmap_ros" type="rtabmapviz" name="rtabmapviz" args="-d $(find rtabmap_ros)/launch/config/rgbd_gui.ini" output="screen">
<param name="subscribe_depth" type="bool" value="true"/>
<param name="subscribe_scan" type="bool" value="true"/>
<param name="frame_id" type="string" value="base_footprint"/>
<remap from="rgb/image" to="$(arg rgb_topic)"/>
<remap from="depth/image" to="$(arg depth_topic)"/>
<remap from="rgb/camera_info" to="$(arg camera_info_topic)"/>
<remap from="scan" to="/scan"/>
</node>
7.ROS Teleop包
在之前的实验和项目中,已经使用teleop节点通过键盘来控制机器人。在这里,我们还需要它,以便我们可以在环境中导航机器人并执行RTAB-Mapping。
克隆teleop包到Workspace src文件夹并编译!可以在这里找到代码: GitHub - ros-teleop/teleop_twist_keyboard: Generic Keyboard Teleop for ROS
8.Mapping: Map My World
Map My World!
一切都准备好了。启动ROS节点,让我们开始:
首先,启动Gazeboworld和RViz,在环境中生成机器人:
roslaunch myrobotb world.launch
然后,启动teleop节点:
rosrun teleop_twist_keyboard teleop_twist_keyboard.py
最后,启动映射节点:
roslaunch myrobotb mapping.launch
在模拟中导航机器人,为环境创建地图!当所有设置完成后,结束节点,可以在启动文件中指定的位置找到map db文件。如果没有修改参数,它将位于/root/. ros/ 文件夹。
最佳实践
先可以从较低的速度开始,我们的目标是用最少的关卡创造出一个很棒的地图。获取3个循环闭包就足够映射整个环境了。可以通过重复相似的路径两次或三次来最大化循环闭包。这允许最大限度的特征检测,促进更快的循环关闭!当完成映射后,请确保在映射新环境之前复制或移动数据库。记住,重新启动映射节点会删除之前的数据库!
9.Mapping:Database Viewer数据库查看器
rtabmap-databaseViewer是一个很好的工具,用于在生成数据库后探索数据库。它与ROS隔离,并允许对映射会话进行完整的分析。包括如何检查循环闭包,生成3D地图查看,提取图像,检查功能映射丰富的区域,以及更多!
让我们从打开映射数据库开始:rtabmap-databaseViewer ~/.ros/rtabmap.db
打开后,需要添加一些窗口,以便更好地查看相关信息,因此:
- Say yes to using the database parameters确认是否使用数据库参数
- View -> Constraint View
- View -> Graph View
这些选项已经足够使用,因为数据库查看器中内置了许多特性!
让我们来谈谈在上图中所看到的。在左边,是所有更新迭代的2D网格地图和机器人的路径。在中间是不同的图像从映射过程。在这里,可以通过图像来查看检测算法的所有特征。这些特征用黄色表示。那么,粉色是什么?粉红色表示两个图像有共同特征的地方,这些信息被用于创建相邻的链接和循环闭包!最后,在右边可以看到约束视图。在这里,可以确定在哪里以及如何创建相邻的链接和循环闭包。
可以在左下角看到循环闭包的数量。这些代码代表:邻居、邻居合并、全局循环关闭、按空间关闭本地循环、按时间关闭本地循环、用户关闭循环和优先链接。
当需要设计自己的环境时,这个工具可以作为一种很好的资源,用于检查环境的功能是否足够丰富,可以生成全局循环闭包。为了实现循环闭包,一个好的环境具有许多可以关联的特性。