·【SLAM】基于explore_lite的移动机器人自主建图
·【SLAM】基于rrt_explore的移动机器人自主建图
·【问题解决】rrt_exploration功能包使用过程中报错处理
前面我们尝试了基于explore_lite的自主建图,本篇文章我们对基于rrt的自主建图算法进行探索尝试,并对其原理进行简述,然后进行在ubuntu16.04和ubuntu20.04虚拟机上都进行仿真实验,指出需要进行修改的地方以便于我们仿真通过。
这个功能包是基于2D的,通常采用图像算法的边缘检测来检测已知区域与未知区域的边界。基于Rapidly-exploring Random Trees(快速搜索随机树RRT)的探索策略。由于RRT基本上是朝向未知区域的(unexplored and unvisited),并且RRT可以扩展到更高维区域。同时采用local tree与global tree来检查边缘点,使得机器人的exploration更加高效。
一旦检测到边缘后,就会取其中心为目标点,然后让机器人去探索该点。而为了检测边缘点,需要对整张地图进行处理,而这个操作通常是耗时的,为此大量的研究人员花费精力在检测frontier edges的效率上。
本包中,RRT树只是用于search边缘点,而检测到的边缘点经过滤波就会依次安排给机器人。当机器人接收到point时,就会运动到对应的点。在此期间,机器人上的传感器将会扫描建图。
而通过多个独立的RRT树来加速边缘点的检测,则是本包的创新点。
如下图所示,这个功能包主要分为三个模块。
而本包还需要与SLAM及path planning模块(move_base)相结合来使用。
关于global detect与local detector节点,当检测到一个边界点时,local detector会重置,并且会基于机器人当前的位置重新生长。这带来两个好处:
但随着地图的变大,global detector会越来越慢(或者说,随着树的变大,exploration会变慢),为此需要local detector进行加速。
frontier_opencv_detector节点是另一个边界检测器,但它不是基于 RRT。该节点使用 OpenCV 工具来检测边界点。它旨在单独运行,并且在多机器人配置中只应运行一个实例(运行此节点的其他实例没有任何区别,也就是说opencv是选装,不装照样能跑功能包)。
最初,这个节点是为了与基于 RRT 的边界检测器进行比较而实现的。在 RRT 检测器(本地和全局)旁边运行此节点可以提高 frotiner 点检测的速度。
注意:您可以运行任何类型和任意数量的检测器,所有检测器都将发布在过滤器节点订阅的同一主题上。
过滤器节点从所有检测器接收检测到的边界点,过滤这些点,并将它们传递给分配器节点以指挥机器人。过滤包括旧点和无效点的剔除,也包括多余点的剔除。
分配节点接收目标并探索目标,即过滤节点发布的过滤边界点,并据此指挥机器人向过滤后的边界点移动。分配者节点通过 move_base_node 命令机器人。
进入到你的工作空间的src目录中,运行以下代码:
git clone https://github.com/hasauino/rrt_exploration.git
或进入这个网址,手动下载
然后下载相关的依赖:
OpenCV(cv2)
sudo apt-get install python-opencv
gmapping
sudo apt-get install ros- kinetic - gmapping
navigation
sudo apt-get install ros- kinetic - navigation
Sklearn
sudo apt-get install python-scikits-learn
Numpy
sudo apt-get install python-numpy
如果Numpy和SKlearn下载不了可以使用pip下载
- pip install numpy
- pip install scikits-learn
订阅的话题:全局识别器订阅地图数据和clicked_point 数据
发布的话题:全局识别器发布检测到的点和形状
参数:
订阅的话题:局部识别器和全局识别器基本相同,是订阅地图数据和clicked_point 数据。
发布的话题:全局识别器发布检测到的点和形状
参数:
订阅的话题:opencv识别器只订阅地图数据
发布的话题:全局识别器发布检测到的点和形状。
参数:
订阅的话题:过滤器订阅地图数据、robot_x/move_base_node/global_costmap/costmap和目标主题
发布的话题:过滤器发布前沿、质心和filters_points
参数:
下面两个主题都是使用多机器人联合建图时用到,单机器人保持默认值即可
订阅的话题:全局识别器订阅地图数据、过滤边界点主题和目标主题。
发布的话题:无
参数:
最终这些参数的设置都放在了simple.launch中
-
-
- <launch>
- <arg name="eta" value="1.0"/>
- <arg name="Geta" value="15.0"/>
- <param name="namespace_init_count" value="1"/>
-
-
- <node pkg="rrt_exploration" type="global_rrt_detector" name="global_detector" output="screen">
- <param name="eta" value="$(arg Geta)"/>
- <param name="map_topic" value="/map"/>
- node>
-
- <node pkg="rrt_exploration" type="local_rrt_detector" name="local_detector" output="screen">
- <param name="eta" value="$(arg eta)"/>
- <param name="map_topic" value="/map"/>
- <param name="robot_frame" value="/base_link"/>
- node>
-
-
- <node pkg="rrt_exploration" type="filter.py" name="filter" output="screen">
- <param name="map_topic" value="/map"/>
- <param name="info_radius" value="1"/>
- <param name="costmap_clearing_threshold" value="70"/>
- <param name="goals_topic" value="/detected_points"/>
- <param name="namespace" value=""/>
- <param name="n_robots" value="1"/>
- <param name="rate" value="100"/>
- node>
-
- <node pkg="rrt_exploration" type="assigner.py" name="assigner" output="screen">
- <param name="map_topic" value="/map"/>
- <param name="global_frame" value="/map"/>
- <param name="info_radius" value="1"/>
- <param name="info_multiplier" value="3.0"/>
- <param name="hysteresis_radius" value="3.0"/>
- <param name="hysteresis_gain" value="2.0"/>
- <param name="frontiers_topic" value="/filtered_points"/>
- <param name="n_robots" value="1"/>
- <param name="namespace" value=""/>
- <param name="delay_after_assignement" value="0.5"/>
- <param name="rate" value="100"/>
- node>
-
- launch>
如果使用rrt作者提供的例程,成功运行这个功能包很简单,只需要:
- roslaunch rrt_exploration_tutorials simple.launch
- roslaunch rrt_exploration simple.launch
但是如果想在我们自己搭建的仿真环境中使用就需要进行比较多的改动:
这里我把原来加载机器人模型的部分进行了注释,保留了源代码中给出的move_base文件和rviz配置文件,然后接下来对move_base文件进行修改:
首先,我将这里的激光雷达话题重映射进行了注释,因为我们自己搭建的雷达模型输出话题是/scan。
然后是这里的重映射,给move_base发送的速度控制指令,我们机器人的速度控制话题是/cmd_vel,不需要重映射,应该是作者使用的机器人速度控制指令是/mobile_base/commands/velocity。
最后就是文件最后的几个话题、坐标系需要换成我们搭建的机器人的名字。
另外要注意一点,如果想使用自己的move_base文件,这里需要修改为move_base_node,因为作者在rrt代码中对move_base的命名是这个,否则就需要修改源代码。
最后的仿真结果如下,开始仿真:
建图完成:
另外,如果要在ubuntu20.04上使用这个包,需要对文件进行修改:
首先是rrt_exploration包中的simple.launch,需要将所有的frame_id前面的"/" 都去掉,而所有的topic前面都需要带着"/":
-
-
- <launch>
- <arg name="eta" value="1.0"/>
- <arg name="Geta" value="15.0"/>
- <param name="namespace_init_count" value="1"/>
-
-
- <node pkg="rrt_exploration" type="global_rrt_detector" name="global_detector" output="screen">
- <param name="eta" value="$(arg Geta)"/>
- <param name="map_topic" value="/map"/>
- node>
-
- <node pkg="rrt_exploration" type="local_rrt_detector" name="local_detector" output="screen">
- <param name="eta" value="$(arg eta)"/>
- <param name="map_topic" value="/map"/>
- <param name="robot_frame" value="base_link"/>
- node>
-
-
- <node pkg="rrt_exploration" type="filter.py" name="filter" output="screen">
- <param name="map_topic" value="/map"/>
- <param name="info_radius" value="1"/>
- <param name="costmap_clearing_threshold" value="70"/>
- <param name="goals_topic" value="/detected_points"/>
- <param name="namespace" value=""/>
- <param name="n_robots" value="1"/>
- <param name="rate" value="100"/>
- node>
-
- <node pkg="rrt_exploration" type="assigner.py" name="assigner" output="screen">
- <param name="map_topic" value="/map"/>
- <param name="global_frame" value="map"/>
- <param name="info_radius" value="1"/>
- <param name="info_multiplier" value="3.0"/>
- <param name="hysteresis_radius" value="3.0"/>
- <param name="hysteresis_gain" value="2.0"/>
- <param name="frontiers_topic" value="/filtered_points"/>
- <param name="n_robots" value="1"/>
- <param name="namespace" value=""/>
- <param name="delay_after_assignement" value="0.5"/>
- <param name="rate" value="100"/>
- node>
-
- launch>
然后对于rrt_exploration包中的move_baseSafe.launch也需要进行上述修改:
- <launch>
- <master auto="start"/>
-
- <arg name="namespace"/>
- <arg name="odom_frame_id" default="odom"/>
- <arg name="base_frame_id" default="base_link"/>
- <arg name="global_frame_id" default="map"/>
- <arg name="laser_frame_id" default="laser_link" />
- <arg name="laser_topic" default="/scan" />
-
-
- <param name="use_sim_time" value="true" />
-
- <node pkg="gmapping" type="slam_gmapping" name="slam_gmapping" output="screen" >
- <remap from="/scan" to="$(arg laser_topic)"/>
- <param name="map_frame" value="$(arg global_frame_id)"/>
- <param name="odom_frame" value="$(arg odom_frame_id)"/>
- <param name="base_frame" value="$(arg base_frame_id)"/>
- <param name="map_update_interval" value="2.0"/>
- <param name="maxUrange" value="50.0"/>
- <param name="maxRange" value="50.0"/>
- <param name="sigma" value="0.05"/>
- <param name="kernelSize" value="1"/>
- <param name="lstep" value="0.05"/>
- <param name="astep" value="0.05"/>
- <param name="iterations" value="5"/>
- <param name="lsigma" value="0.075"/>
- <param name="ogain" value="3.0"/>
- <param name="lskip" value="0"/>
- <param name="srr" value="0.01"/>
- <param name="srt" value="0.02"/>
- <param name="str" value="0.01"/>
- <param name="stt" value="0.02"/>
- <param name="linearUpdate" value="0.01"/>
- <param name="angularUpdate" value="0.01"/>
- <param name="temporalUpdate" value="0.1"/>
- <param name="resampleThreshold" value="0.5"/>
- <param name="particles" value="30"/>
- <param name="xmin" value="-5.0"/>
- <param name="ymin" value="-5.0"/>
- <param name="xmax" value="5.0"/>
- <param name="ymax" value="5.0"/>
- <param name="delta" value="0.1"/>
- <param name="llsamplerange" value="0.01"/>
- <param name="llsamplestep" value="0.01"/>
- <param name="lasamplerange" value="0.005"/>
- <param name="lasamplestep" value="0.005"/>
- <param name="minimumScore" value="0.005"/>
- node>
-
-
- <node pkg="move_base" type="move_base" respawn="false" name="move_base_node" output="screen">
- <param name="footprint_padding" value="0.01" />
- <param name="controller_frequency" value="5.0" />
- <param name="controller_patience" value="3.0" />
- <param name="oscillation_timeout" value="30.0" />
- <param name="oscillation_distance" value="0.5" />
- <param name="planner_patience" value="1" />
- <param name="controller_patience" value="1" />
- <remap from="/cmd_vel" to="/cmd_vel"/>
- <param name="recovery_behavior_enabled" value="false" />
- <rosparam file="$(find rrt_exploration_tutorials)/param/costmap_common_params.yaml" command="load" ns="global_costmap" />
- <rosparam file="$(find rrt_exploration_tutorials)/param/costmap_common_params.yaml" command="load" ns="local_costmap" />
- <rosparam file="$(find rrt_exploration_tutorials)/param/local_costmap_params.yaml" command="load" />
- <rosparam file="$(find rrt_exploration_tutorials)/param/global_costmap_params.yaml" command="load" />
- <rosparam file="$(find rrt_exploration_tutorials)/param/base_local_planner_params.yaml" command="load" />
- <param name="global_costmap/global_frame" value="$(arg global_frame_id)"/>
- <param name="global_costmap/robot_base_frame" value="$(arg base_frame_id)"/>
- <param name="global_costmap/laser_scan_sensor/sensor_frame" value="$(arg laser_frame_id)"/>
- <param name="global_costmap/laser_scan_sensor/topic" value="$(arg laser_topic)"/>
- <param name="local_costmap/global_frame" value="$(arg odom_frame_id)"/>
- <param name="local_costmap/robot_base_frame" value="$(arg base_frame_id)"/>
- <param name="local_costmap/laser_scan_sensor/sensor_frame" value="$(arg laser_frame_id)"/>
- <param name="local_costmap/laser_scan_sensor/topic" value="$(arg laser_topic)"/>
- <param name="local_costmap/obstacle_layer/laser_scan_sensor/topic" value="$(arg laser_topic)"/>
- node>
-
- launch>
在ubuntu20.04中的仿真效果如下: