[Documentation] [TitleIndex] [WordIndex

Note: This tutorial assumes that you have completed the previous tutorials: Stereo outdoor mapping.
(!) Please ask about problems and questions regarding this tutorial on answers.ros.org. Don't forget to include in your question the link to this page, the versions of your OS & ROS, and also add appropriate tags.

Stereo Outdoor Navigation

Description: This tutorial shows how to integrate autonomous navigation with RTAB-Map in context of outdoor stereo mapping.

Tutorial Level: ADVANCED

2D Navigation

Example of navigation with only a stereo camera:

The planner used in the video is move_base. The global costmap is generated from the "/map" (nav_msgs/OccupancyGrid) topic and the local costmap is updated using the "openni_points" (sensor_msgs/PointCloud2) topic. Here an example of launch file with the related move_base config files. The sections below show how these topics come from.

For info and for a complete example launch file, all the snippets below were integrated together with 3D stereo mapping in az3_mapping_robot_stereo_nav.launch.

Global costmap

The rtabmap node can generate a 2D occupancy grid (named "/rtabmap/proj_map") from the projection of the 3D cloud map on the ground. The empty cells are filled by projecting the ground on the xy plane. The occupied cells are filled by projecting the obstacles on the xy plane. For each point cloud, the obstacles and the ground are segmented. Since the ground is not even, the ground is segmented by normal filtering: all points with normal in the +z direction (+- fixed angle) are labelled as ground, all the others are labelled as obstacles. The images below show an example.

obs0

obs1

obs2

obs3

obs4

   ...
   <remap from="map" to="/rtabmap/proj_map"/>
   ...

Local costmap

For the local costmap update, we feed it a point cloud with only the obstacles without the ground. The rtabmap_ros/obstacles_detection nodelet is used. This nodelet uses the same ground/obstacles segmentation approach described for the global costmap. Note that in local_costmap_params.yaml, because the robot can be at any height from its odom/map referentials, we set the min_obstacle_height and max_obstacle_height to high values (-99999 and 99999). The cloud used for segmentation is generated from the disparity image of stereo_image_proc using the rtabmap_ros/point_cloud_xyz nodelet.

   <group ns="/stereo_camera" >
      
      <!-- Generate a point cloud from the disparity image -->
      <node pkg="nodelet" type="nodelet" name="disparity2cloud" args="load rtabmap_ros/point_cloud_xyz stereo_nodelet">
         <remap from="disparity/image"       to="disparity"/>
         <remap from="disparity/camera_info" to="right/camera_info_throttle"/>
         <remap from="cloud"                to="cloudXYZ"/>
         
         <param name="voxel_size" type="double" value="0.05"/>
         <param name="decimation" type="int" value="4"/>
         <param name="max_depth" type="double" value="4"/>
      </node>

      <!-- Create point cloud for the local planner -->
      <node pkg="nodelet" type="nodelet" name="obstacles_detection" args="load rtabmap_ros/obstacles_detection stereo_nodelet">
         <remap from="cloud" to="cloudXYZ"/>
         <remap from="obstacles" to="/planner_cloud"/>

         <param name="frame_id" type="string" value="base_footprint"/>
         <param name="map_frame_id" type="string" value="map"/>
         <param name="min_cluster_size" type="int" value="20"/>
         <param name="max_obstacles_height" type="double" value="0.0"/>
       </node>
   </group>

2019-11-16 13:19