Wiki
Robot Navigation Navigation2 (Entity Edition)
Existing English translations were reused. 1 current source blocks remain in Simplified Chinese, without triggering paid translation.
1.Preparation
-
Physical Object
-
Already ran through the robot navigation Navigation2 (simulation chapter)
-
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.
-
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.
-
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:
- 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 |
- 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