Interesting Practice of Robot Programming 16-Synchronous Localization and Map Construction (SLAM)

The 360-degree laser is used for obstacle avoidance. How can it be done? It's totally overkill...

When performing SLAM in the Gazebo simulator, various environments and robot models can be selected or created in the virtual world. The SLAM simulation is very similar to the actual SLAM of TurtleBot3.

Through the keyboard remote control and autonomous obstacle avoidance driving in the three-dimensional environment, the basic usage has been fully mastered, and the SLAM link will be entered below.

Results as shown below:

This article does not contain the details of SLAM algorithm, follow-up blog update.

For more cool applications based on maps, please refer to the following:

Start the simulation world

Three Gazebo environments are prepared, but if you want to use SLAM to create a map, it is recommended to use TurtleBot3 World or TurtleBot3 House.
Use one of the following commands to load the Gazebo environment. In this instruction, TurtleBot3 World will be used.
Please use the correct keywords for the TURTLEBOT3_MODEL parameter in burger, waffle, waffle_pi.

  • world
  • $ export TURTLEBOT3_MODEL=burger
    $ ros2 launch turtlebot3_gazebo turtlebot3_world.launch.py
  • house
  • $ export TURTLEBOT3_MODEL=burger
    $ ros2 launch turtlebot3_gazebo turtlebot3_house.launch.py

Choose one of the above two options.

Run the SLAM node

Use Ctrl + Alt + T to open a new terminal from the remote PC and run the SLAM node. The Cartographer SLAM method is used by default.

  • $ export TURTLEBOT3_MODEL=burger
    $ ros2 launch turtlebot3_cartographer cartographer.launch.py use_sim_time:=True

Run autonomous obstacle avoidance nodes

Use Ctrl + Alt + T to open a new terminal from the remote PC, and then run the drive node from the PC.

ros2 run turtlebot3_gazebo turtlebot3_drive

Run remote operation node
Use Ctrl + Alt + T to open a new terminal from the remote PC, and then run the remote operation node from the remote PC.
  • ros2 run turtlebot3_teleop teleop_keyboard

Save the map

After successfully creating the map, use Ctrl + Alt + T to open a new terminal from the remote PC and save the map.

ros2 run nav2_map_server map_saver_cli -f ~/map

cartographer.launch

import osfrom ament_index_python.packages import get_package_share_directoryfrom launch import LaunchDescriptionfrom launch.actions import DeclareLaunchArgumentfrom launch_ros.actions import Nodefrom launch.substitutions import LaunchConfigurationfrom launch.actions import IncludeLaunchDescriptionfrom launch.launch_description_sources import PythonLaunchDescriptionSourcefrom launch.substitutions import ThisLaunchFileDir  def generate_launch_description():    use_sim_time = LaunchConfiguration('use_sim_time', default='false')    turtlebot3_cartographer_prefix = get_package_share_directory('turtlebot3_cartographer')    cartographer_config_dir = LaunchConfiguration('cartographer_config_dir', default=os.path.join(                                                  turtlebot3_cartographer_prefix, 'config'))    configuration_basename = LaunchConfiguration('configuration_basename',                                                 default='turtlebot3_lds_2d.lua')     resolution = LaunchConfiguration('resolution', default='0.05')    publish_period_sec = LaunchConfiguration('publish_period_sec', default='1.0')     rviz_config_dir = os.path.join(get_package_share_directory('turtlebot3_cartographer'),                                   'rviz', 'tb3_cartographer.rviz')     return LaunchDescription([        DeclareLaunchArgument(            'cartographer_config_dir',            default_value=cartographer_config_dir,            description='Full path to config file to load'),        DeclareLaunchArgument(            'configuration_basename',            default_value=configuration_basename,            description='Name of lua file for cartographer'),        DeclareLaunchArgument(            'use_sim_time',            default_value='false',            description='Use simulation (Gazebo) clock if true'),         Node(            package='cartographer_ros',            executable='cartographer_node',            name='cartographer_node',            output='screen',            parameters=[{'use_sim_time': use_sim_time}],            arguments=['-configuration_directory', cartographer_config_dir,                       '-configuration_basename', configuration_basename]),         DeclareLaunchArgument(            'resolution',            default_value=resolution,            description='Resolution of a grid cell in the published occupancy grid'),         DeclareLaunchArgument(            'publish_period_sec',            default_value=publish_period_sec,            description='OccupancyGrid publishing period'),         IncludeLaunchDescription(            PythonLaunchDescriptionSource([ThisLaunchFileDir(), '/occupancy_grid.launch.py']),            launch_arguments={'use_sim_time': use_sim_time, 'resolution': resolution,                              'publish_period_sec': publish_period_sec}.items(),        ),         Node(            package='rviz2',            executable='rviz2',            name='rviz2',            arguments=['-d', rviz_config_dir],            parameters=[{'use_sim_time': use_sim_time}],            output='screen'),    ])

Configuration file lua

include "map_builder.lua"include "trajectory_builder.lua" options = {  map_builder = MAP_BUILDER,  trajectory_builder = TRAJECTORY_BUILDER,  map_frame = "map",  tracking_frame = "imu_link",  published_frame = "odom",  odom_frame = "odom",  provide_odom_frame = false,  publish_frame_projected_to_2d = true,  use_odometry = true,  use_nav_sat = false,  use_landmarks = false,  num_laser_scans = 1,  num_multi_echo_laser_scans = 0,  num_subdivisions_per_laser_scan = 1,  num_point_clouds = 0,  lookup_transform_timeout_sec = 0.2,  submap_publish_period_sec = 0.3,  pose_publish_period_sec = 5e-3,  trajectory_publish_period_sec = 30e-3,  rangefinder_sampling_ratio = 1.,  odometry_sampling_ratio = 1.,  fixed_frame_pose_sampling_ratio = 1.,  imu_sampling_ratio = 1.,  landmarks_sampling_ratio = 1.,} MAP_BUILDER.use_trajectory_builder_2d = true TRAJECTORY_BUILDER_2D.min_range = 0.12TRAJECTORY_BUILDER_2D.max_range = 3.5TRAJECTORY_BUILDER_2D.missing_data_ray_length = 3.TRAJECTORY_BUILDER_2D.use_imu_data = falseTRAJECTORY_BUILDER_2D.use_online_correlative_scan_matching = true TRAJECTORY_BUILDER_2D.motion_filter.max_angle_radians = math.rad(0.1) POSE_GRAPH.constraint_builder.min_score = 0.65POSE_GRAPH.constraint_builder.global_localization_min_score = 0.7 -- POSE_GRAPH.optimize_every_n_nodes = 0 return options