Skip to content

Wiki

Robot Navigation Navigation2 (Entity Edition)

About 22 min read

Existing English translations were reused. 1 current source blocks remain in Simplified Chinese, without triggering paid translation.

1.Preparation

  1. Physical Object

  2. Already ran through the robot navigation Navigation2 (simulation chapter)

  3. This chapter only covers the general implementation approach. Generally, as long as you understand the simulation chapter, you will understand how to implement it after looking at the general approach in the physical object chapter.

  4. This chapter is not based on Zhao Xuzuo's tutorial; it is my own implementation approach, for reference only. Teacher Zhao may have a better method, but he has not yet released the physical object chapter tutorial.

  5. This chapter uses a 4-wheel Mecanum wheel implementation, for reference only.

以下代码都在下方这个github仓库里:

https://github.com/CyberNaviRobot/CyberRobot_ROS2_WS

The tutorial below only provides implementation ideas and will not include source code, so it is recommended to clone this repository and look at the source code.

2.Navigation Parameter Reference

https://docs.nav2.org/configuration/index.html

3.SLAM Localization and Mapping

3.1.slam_toolbox

According to the node description above, we need to subscribe to /scan and /tf.

Generally, the manual for a LiDAR will provide source code to publish /scan, so please refer to your hardware's manual for this.

/tf requires us to publish the transform from odom_frame to base_frame; we must use C++ code to dynamically publish the odom coordinate transform.

However, here you need to publish /odom so that the robot's position and orientation are known, which allows the robot's position in the map to be inferred.

Make sure that the parameters of the SLAM Toolbox are not set incorrectly, especially the coordinate frames and so on; other parameters can be fine-tuned according to the documentation.

Ensure that the topic published by the LiDAR is /scan.

First start the LiDAR

Restart the URDF model and publish TF at the same time.

Finally, start SLAM.

ros2 launch mycar_slam_slam_toolbox online_sync_launch.py use_sim_time:=false

3.2.cartographer

According to the cartographer documentation, we only need /scan and /odom.

First open the serial port receiving node to receive data transmitted from the STM32.

Then open the odometry node and publish the odom topic.

Publish TF again. You can directly use launch to start robot_state_publisher and joint_state_publisher, and open the URDF model to publish TF.

Start the LiDAR node and publish the scan topic.

Wait until /odom, /scan, and TF are all published, then open Cartographer for mapping, and then you can check whether the TF for the map is published.

Check the TF tree as follows:

Construct the graph as follows

4.Map Service

4.1.Save Map (Serialization)

mkdir ./map
ros2 run nav2_map_server map_saver_cli -f map/my_map

4.2.Read map (deserialize)

ros2 launch mycar_map_server map_server.launch.py

5.AMCL Adaptive Monte Carlo Localization

First, map data is required, and the /map topic is published.

Next, LiDAR data is required, i.e., the /scan topic.

Then a coordinate transformation message is needed, namely the /tf topic.

Then that /initial_pose topic is the initial position on the 2D map, which can be published using rviz2 or using C++ code.

Then the parameters need to be modified:

This is the parameter's official website:

https://docs.nav2.org/configuration/packages/configuring-amcl.html#

After modifying Launch, modify the params parameter.

Here, OmniChassis does not only refer to an omnidirectional wheel chassis, but to omnidirectional wheel chassis in a broad sense; for example, both omnidirectional wheel chassis and Mecanum wheel chassis are omnidirectional wheel chassis. Of course, custom chassis types are also possible.

Set the use_sim_time at the very top of this configuration file to False.

6.Navigation Server

There are too many topics involved, so we have listed them in a table:

  1. Subscribed topics
Topic Interface Description
/goal_pose geometry_msgs/msg/PoseStamped Navigation goal point, used to trigger navigation tasks
/tf tf2_msgs/msg/TFMessage Coordinate transformation messages, used for conversions between different coordinate frames
/odom nav_msgs/msg/Odometry Odometry data, providing robot position and motion information
Topic Interface Description
/global_costmap/footprint geometry_msgs/msg/Polygon Footprint information of the robot (or any mobile platform). The footprint is the spatial shape occupied by the robot on the map, usually represented as a polygon.
/map nav_msgs/msg/OccupancyGrid Publishes the environment map, especially the Occupancy Grid Map used for navigation.
/scan sensor_msgs/msg/LaserScan Laser scan data.
Topic Interface Description
/odom nav_msgs/msg/Odometry Odometry information of the robot, including position, velocity, and pose
/speed_limit nav2_msgs/msg/SpeedLimit Speed limit information during navigation, used to dynamically adjust the robot's movement speed
Topic Interface Description
/local_costmap/footprint geometry_msgs/msg/Polygon Footprint polygon of the robot or mobile platform, used for local costmap computation
/scan sensor_msgs/msg/LaserScan Scan data from the laser scanner, used for environment perception and obstacle avoidance
Topic Interface Description
/clock rosgraph_msgs/msg/Clock ROS system time
/cmd_vel_teleop geometry_msgs/msg/Twist Teleoperation commands, used to control the robot's linear and angular velocity
/local_costmap/costmap_raw nav2_msgs/msg/Costmap Raw data of the local costmap
/local_costmap/published_footprint geometry_msgs/msg/PolygonStamped Published footprint of the robot in the local costmap
/preempt_teleop std_msgs/msg/Empty Teleoperation preemption signal, used to interrupt the current teleoperation
Topic Interface Description
/global_costmap/costmap_raw nav2_msgs/msg/Costmap Raw data of the global costmap, used for path planning
/global_costmap/published_footprint geometry_msgs/msg/PolygonStamped Footprint representation of the robot in the global costmap
Topic Interface Description
/cmd_vel_nav geometry_msgs/msg/Twist Topic for receiving velocity control commands from other nodes
  1. Published topics
Topic Interface Description
/plan nav_msgs/msg/Path The global path from the current position to the target point
Topic Interface Description
/global_costmap/costmap nav_msgs/msg/OccupancyGrid Publishes the current state of the global costmap.
/global_costmap/costmap_raw nav2_msgs/msg/Costmap Raw costmap data without further processing.
/global_costmap/costmap_updates map_msgs/msg/OccupancyGridUpdate Updates to the global costmap; this message can efficiently update the map.
/global_costmap/published_footprint geometry_msgs/msg/PolygonStamped Publishes the robot footprint, i.e., the shape of the space occupied by the robot on the map.
Topic name Message type Description
/cmd_vel_nav geometry_msgs/msg/Twist Publishes control commands, including linear and angular velocities, to control the robot to move along the planned path.
/cost_cloud sensor_msgs/msg/PointCloud2 Publishes point cloud data in the costmap for obstacle avoidance and path planning.
/local_plan nav_msgs/msg/Path Publishes the local path planning result, i.e., how the robot should reach a point near the current target point.
/marker visualization_msgs/msg/MarkerArray Publishes visualization markers for displaying paths, obstacles, and other information in visualization tools such as RViz.
/received_global_plan nav_msgs/msg/Path Publishes the global path received from the global planner, i.e., the path from the current position to the target point.
/transformed_global_plan nav_msgs/msg/Path Publishes the coordinate-transformed global path to ensure the path is consistent with the robot's current coordinate frame.
Topic Interface Description
/local_costmap/clearing_endpoints sensor_msgs/msg/PointCloud2 Clears obstacle point cloud data on the costmap, typically used for dynamic obstacle handling
/local_costmap/costmap nav_msgs/msg/OccupancyGrid The local costmap, representing the traversability of the environment around the robot
/local_costmap/costmap_raw nav2_msgs/msg/Costmap The unprocessed local costmap, which may contain more detailed information
/local_costmap/costmap_updates map_msgs/msg/OccupancyGridUpdate Update information for the local costmap, including which areas have changed
/local_costmap/published_footprint geometry_msgs/msg/PolygonStamped The published robot footprint polygon; the timestamp indicates the publication time
/local_costmap/voxel_grid nav2_msgs/msg/VoxelGrid Voxel grid data, used for spatial partitioning and optimization in costmap generation
Topic Interface Description
/cmd_vel geometry_msgs/msg/Twist Velocity commands sent to the low-level controller
Topic Interface Description
/plan_smoothed nav_msgs/msg/Path The smoothed global path
Topic Interface Description
/cmd_vel geometry_msgs/msg/Twist Topic for publishing processed or smoothed velocity control commands

Since Zhao Xuzuo rewrote the official source code in the workspace, this would be more troublesome for beginners. For beginners, it is recommended to use the official bringup node. Below is the usage method I summarized based on the official Wiki: (Here, choose to use the official bringup node instead of Teacher Zhao Xuzuo's node.)

The following are the configurednav2.launch.pyfiles:

import os

from ament_index_python.packages import get_package_share_directory
from launch import LaunchDescription
from launch.actions import DeclareLaunchArgument
from launch.actions import IncludeLaunchDescription
from launch.launch_description_sources import PythonLaunchDescriptionSource
from launch.substitutions import LaunchConfiguration

# from launch_ros.actions import Node

def generate_launch_description():
    navigation2_dir = get_package_share_directory('nav05_navigation2')
    nav2_bringup_dir = get_package_share_directory('nav2_bringup')

    # launch的参数的优先级比yaml的参数优先级高
    use_sim_time = LaunchConfiguration('use_sim_time', default='flase')
    map_yaml_path = LaunchConfiguration('map',default=os.path.join(navigation2_dir,'map','house.yaml'))
    nav2_param_path = LaunchConfiguration('params_file',default=os.path.join(navigation2_dir,'params','nav2.yaml'))

    return LaunchDescription([
        DeclareLaunchArgument('use_sim_time',default_value=use_sim_time,description='Use simulation (Gazebo) clock if true'),
        DeclareLaunchArgument('map',default_value=map_yaml_path,description='Full path to map file to load'),
        DeclareLaunchArgument('params_file',default_value=nav2_param_path,description='Full path to param file to load'),

        IncludeLaunchDescription(
            PythonLaunchDescriptionSource([nav2_bringup_dir,'/launch','/bringup_launch.py']),
            launch_arguments={
                'map': map_yaml_path,
                'use_sim_time': use_sim_time,
                'params_file': nav2_param_path}.items(),
        ),
    ])

Below arerviz2.launch.py:

import os

from ament_index_python.packages import get_package_share_directory
from launch import LaunchDescription
from launch.actions import DeclareLaunchArgument
from launch.substitutions import LaunchConfiguration
from launch_ros.actions import Node

def generate_launch_description():
    navigation2_dir = get_package_share_directory('nav05_navigation2')

    use_sim_time = LaunchConfiguration('use_sim_time', default='false')

    rviz_config_dir = os.path.join(navigation2_dir,'rviz','nav2.rviz')

    return LaunchDescription([
        DeclareLaunchArgument('use_sim_time',default_value=use_sim_time,description='Use simulation (Gazebo) clock if true'),

        Node(
            package='rviz2',
            executable='rviz2',
            name='rviz2',
            arguments=['-d', rviz_config_dir],
            parameters=[{'use_sim_time': use_sim_time}],
            output='screen'),
    ])

The following isnav2.yamlconfiguration file (differential drive model + DWE local planner):

amcl:
  ros__parameters:
    use_sim_time: false
    alpha1: 0.2
    alpha2: 0.2
    alpha3: 0.2
    alpha4: 0.2
    alpha5: 0.2
    base_frame_id: "base_link"
    beam_skip_distance: 0.5
    beam_skip_error_threshold: 0.9
    beam_skip_threshold: 0.3
    do_beamskip: false
    global_frame_id: "map"
    lambda_short: 0.1
    laser_likelihood_max_dist: 2.0
    laser_max_range: 100.0
    laser_min_range: -1.0
    laser_model_type: "likelihood_field"
    max_beams: 60
    max_particles: 2000
    min_particles: 500
    odom_frame_id: "odom"
    pf_err: 0.05
    pf_z: 0.99
    recovery_alpha_fast: 0.0
    recovery_alpha_slow: 0.0
    resample_interval: 1
    robot_model_type: "nav2_amcl::DifferentialMotionModel"
    save_pose_rate: 0.5
    sigma_hit: 0.2
    tf_broadcast: true
    transform_tolerance: 1.0
    update_min_a: 0.2
    update_min_d: 0.25
    z_hit: 0.5
    z_max: 0.05
    z_rand: 0.5
    z_short: 0.05
    scan_topic: scan

amcl_map_client:
  ros__parameters:
    use_sim_time: false

amcl_rclcpp_node:
  ros__parameters:
    use_sim_time: false

bt_navigator:
  ros__parameters:
    use_sim_time: false
    global_frame: map
    robot_base_frame: base_link
    odom_topic: /odom
    bt_loop_duration: 10
    default_server_timeout: 20

    # 'default_nav_through_poses_bt_xml' and 'default_nav_to_pose_bt_xml' are use defaults:

    # nav2_bt_navigator/navigate_to_pose_w_replanning_and_recovery.xml

    # nav2_bt_navigator/navigate_through_poses_w_replanning_and_recovery.xml

    # They can be set here or via a RewrittenYaml remap from a parent launch file to Nav2.
    plugin_lib_names:
    - nav2_compute_path_to_pose_action_bt_node
    - nav2_compute_path_through_poses_action_bt_node
    - nav2_smooth_path_action_bt_node
    - nav2_follow_path_action_bt_node
    - nav2_spin_action_bt_node
    - nav2_wait_action_bt_node
    - nav2_back_up_action_bt_node
    - nav2_drive_on_heading_bt_node
    - nav2_clear_costmap_service_bt_node
    - nav2_is_stuck_condition_bt_node
    - nav2_goal_reached_condition_bt_node
    - nav2_goal_updated_condition_bt_node
    - nav2_globally_updated_goal_condition_bt_node
    - nav2_is_path_valid_condition_bt_node
    - nav2_initial_pose_received_condition_bt_node
    - nav2_reinitialize_global_localization_service_bt_node
    - nav2_rate_controller_bt_node
    - nav2_distance_controller_bt_node
    - nav2_speed_controller_bt_node
    - nav2_truncate_path_action_bt_node
    - nav2_truncate_path_local_action_bt_node
    - nav2_goal_updater_node_bt_node
    - nav2_recovery_node_bt_node
    - nav2_pipeline_sequence_bt_node
    - nav2_round_robin_node_bt_node
    - nav2_transform_available_condition_bt_node
    - nav2_time_expired_condition_bt_node
    - nav2_path_expiring_timer_condition
    - nav2_distance_traveled_condition_bt_node
    - nav2_single_trigger_bt_node
    - nav2_is_battery_low_condition_bt_node
    - nav2_navigate_through_poses_action_bt_node
    - nav2_navigate_to_pose_action_bt_node
    - nav2_remove_passed_goals_action_bt_node
    - nav2_planner_selector_bt_node
    - nav2_controller_selector_bt_node
    - nav2_goal_checker_selector_bt_node
    - nav2_controller_cancel_bt_node
    - nav2_path_longer_on_approach_bt_node
    - nav2_wait_cancel_bt_node
    - nav2_spin_cancel_bt_node
    - nav2_back_up_cancel_bt_node
    - nav2_drive_on_heading_cancel_bt_node

bt_navigator_rclcpp_node:
  ros__parameters:
    use_sim_time: false

controller_server:
  ros__parameters:
    use_sim_time: false
    controller_frequency: 20.0
    min_x_velocity_threshold: 0.001
    min_y_velocity_threshold: 0.5
    min_theta_velocity_threshold: 0.001
    failure_tolerance: 0.3
    progress_checker_plugin: "progress_checker"
    goal_checker_plugins: ["general_goal_checker"] # "precise_goal_checker"
    controller_plugins: ["FollowPath"]

    # Progress checker parameters
    progress_checker:
      plugin: "nav2_controller::SimpleProgressChecker"
      required_movement_radius: 0.5
      movement_time_allowance: 10.0

    # Goal checker parameters
    #precise_goal_checker:

    #  plugin: "nav2_controller::SimpleGoalChecker"

    #  xy_goal_tolerance: 0.25

    #  yaw_goal_tolerance: 0.25

    #  stateful: True
    general_goal_checker:
      stateful: True
      plugin: "nav2_controller::SimpleGoalChecker"
      xy_goal_tolerance: 0.25
      yaw_goal_tolerance: 0.25

    # DWB parameters
    FollowPath:
      plugin: "dwb_core::DWBLocalPlanner"
      debug_trajectory_details: True
      min_vel_x: 0.0
      min_vel_y: 0.0
      max_vel_x: 0.26
      max_vel_y: 0.0
      max_vel_theta: 1.0
      min_speed_xy: 0.0
      max_speed_xy: 0.26
      min_speed_theta: 0.0

      # Add high threshold velocity for turtlebot 3 issue.

      # https://github.com/ROBOTIS-GIT/turtlebot3_simulations/issues/75
      acc_lim_x: 2.5
      acc_lim_y: 0.0
      acc_lim_theta: 3.2
      decel_lim_x: -2.5
      decel_lim_y: 0.0
      decel_lim_theta: -3.2
      vx_samples: 20
      vy_samples: 5
      vtheta_samples: 20
      sim_time: 1.7
      linear_granularity: 0.05
      angular_granularity: 0.025
      transform_tolerance: 0.2
      xy_goal_tolerance: 0.25
      trans_stopped_velocity: 0.25
      short_circuit_trajectory_evaluation: True
      stateful: True
      critics: ["RotateToGoal", "Oscillation", "BaseObstacle", "GoalAlign", "PathAlign", "PathDist", "GoalDist"]
      BaseObstacle.scale: 0.02
      PathAlign.scale: 32.0
      PathAlign.forward_point_distance: 0.1
      GoalAlign.scale: 24.0
      GoalAlign.forward_point_distance: 0.1
      PathDist.scale: 32.0
      GoalDist.scale: 24.0
      RotateToGoal.scale: 32.0
      RotateToGoal.slowing_factor: 5.0
      RotateToGoal.lookahead_time: -1.0

controller_server_rclcpp_node:
  ros__parameters:
    use_sim_time: false

local_costmap:
  local_costmap:
    ros__parameters:
      update_frequency: 5.0
      publish_frequency: 2.0
      global_frame: odom
      robot_base_frame: base_link
      use_sim_time: false
      rolling_window: true
      width: 3
      height: 3
      resolution: 0.05
      robot_radius: 0.22
      plugins: ["static_layer", "obstacle_layer", "voxel_layer", "inflation_layer"]
      inflation_layer:
        plugin: "nav2_costmap_2d::InflationLayer"
        cost_scaling_factor: 3.0
        inflation_radius: 0.55
      obstacle_layer:
        plugin: "nav2_costmap_2d::ObstacleLayer"
        enabled: True
        observation_sources: scan
        scan:
          topic: /scan
          max_obstacle_height: 2.0
          clearing: True
          marking: True
          data_type: "LaserScan"
          raytrace_max_range: 3.0
          raytrace_min_range: 0.0
          obstacle_max_range: 2.5
          obstacle_min_range: 0.0
      voxel_layer:
        plugin: "nav2_costmap_2d::VoxelLayer"
        enabled: True
        publish_voxel_map: True
        origin_z: 0.0
        z_resolution: 0.05
        z_voxels: 16
        max_obstacle_height: 2.0
        mark_threshold: 0
        observation_sources: scan
        scan:
          topic: /scan
          max_obstacle_height: 2.0
          clearing: True
          marking: True
          data_type: "LaserScan"
          raytrace_max_range: 3.0
          raytrace_min_range: 0.0
          obstacle_max_range: 2.5
          obstacle_min_range: 0.0
      static_layer:
        plugin: "nav2_costmap_2d::StaticLayer"
        map_subscribe_transient_local: True
      always_send_full_costmap: True

  local_costmap_client:
    ros__parameters:
      use_sim_time: false
  local_costmap_rclcpp_node:
    ros__parameters:
      use_sim_time: false

global_costmap:
  global_costmap:
    ros__parameters:
      update_frequency: 1.0
      publish_frequency: 1.0
      global_frame: map
      robot_base_frame: base_link
      use_sim_time: false
      robot_radius: 0.22
      resolution: 0.05
      track_unknown_space: true
      plugins: ["static_layer", "obstacle_layer", "inflation_layer"]
      obstacle_layer:
        plugin: "nav2_costmap_2d::ObstacleLayer"
        enabled: True
        observation_sources: scan
        scan:
          topic: /scan
          max_obstacle_height: 2.0
          clearing: True
          marking: True
          data_type: "LaserScan"
          raytrace_max_range: 3.0
          raytrace_min_range: 0.0
          obstacle_max_range: 2.5
          obstacle_min_range: 0.0
      static_layer:
        plugin: "nav2_costmap_2d::StaticLayer"
        map_subscribe_transient_local: True
      inflation_layer:
        plugin: "nav2_costmap_2d::InflationLayer"
        cost_scaling_factor: 3.0
        inflation_radius: 0.55
      always_send_full_costmap: True

  global_costmap_client:
    ros__parameters:
      use_sim_time: false
  global_costmap_rclcpp_node:
    ros__parameters:
      use_sim_time: false

map_server:
  ros__parameters:
    use_sim_time: false
    yaml_filename: "house.yaml"

map_saver:
  ros__parameters:
    use_sim_time: false
    save_map_timeout: 5.0
    free_thresh_default: 0.25
    occupied_thresh_default: 0.65
    map_subscribe_transient_local: True

planner_server:
  ros__parameters:
    expected_planner_frequency: 20.0
    use_sim_time: false
    planner_plugins: ["GridBased"]
    GridBased:
      plugin: "nav2_navfn_planner/NavfnPlanner"
      tolerance: 0.5
      use_astar: false
      allow_unknown: true

planner_server_rclcpp_node:
  ros__parameters:
    use_sim_time: false

smoother_server:
  ros__parameters:
    use_sim_time: false
    smoother_plugins: ["simple_smoother"]
    simple_smoother:
      plugin: "nav2_smoother::SimpleSmoother"
      tolerance: 1.0e-10
      max_its: 1000
      do_refinement: True

behavior_server:
  ros__parameters:
    costmap_topic: local_costmap/costmap_raw
    footprint_topic: local_costmap/published_footprint
    cycle_frequency: 10.0
    behavior_plugins: ["spin", "backup", "drive_on_heading", "wait"]
    spin:
      plugin: "nav2_behaviors/Spin"
    backup:
      plugin: "nav2_behaviors/BackUp"
    drive_on_heading:
      plugin: "nav2_behaviors/DriveOnHeading"
    wait:
      plugin: "nav2_behaviors/Wait"
    global_frame: odom
    robot_base_frame: base_link
    transform_tolerance: 0.1
    use_sim_time: false
    simulate_ahead_time: 2.0
    max_rotational_vel: 1.0
    min_rotational_vel: 0.4
    rotational_acc_lim: 3.2

robot_state_publisher:
  ros__parameters:
    use_sim_time: false

waypoint_follower:
  ros__parameters:
    loop_rate: 20
    stop_on_failure: false
    waypoint_task_executor_plugin: "wait_at_waypoint"
    wait_at_waypoint:
      plugin: "nav2_waypoint_follower::WaitAtWaypoint"
      enabled: True
      waypoint_pause_duration: 200

velocity_smoother:
  ros__parameters:
    use_sim_time: false
    smoothing_frequency: 20.0
    scale_velocities: False
    feedback: "OPEN_LOOP"
    max_velocity: [0.26, 0.0, 1.0]
    min_velocity: [-0.26, 0.0, -1.0]
    max_accel: [2.5, 0.0, 3.2]
    max_decel: [-2.5, 0.0, -3.2]
    odom_topic: "odom"
    odom_duration: 0.1
    deadband_velocity: [0.0, 0.0, 0.0]
    velocity_timeout: 1.0

7.Multi-vehicle platooning