By ihsumlee , 9 June 2026
content

Position in the full course

This is the ninth step of the course.

The full learning order is:

1. ROS 2 node/topic/launch review
2. TF2 frame concept
3. Static sensor frames
4. Dynamic odometry frame
5. URDF + robot_state_publisher
6. SLAM mapping
7. AMCL localization
8. Nav2 path planning
9. RViz goal navigation
10. TF2 debugging in Nav2

In Step 8, you checked Nav2 path planning using command-line actions.

In Step 9, you will use RViz2 to send a navigation goal.

The main goal is:

Use RViz2 to set the robot initial pose.
Use RViz2 to send a navigation goal.
Observe Nav2 planning, control, and robot movement.

1. Learning objectives

After this module, you should be able to:

  1. Explain the purpose of RViz2 in Nav2 navigation.
  2. Set the robot initial pose using 2D Pose Estimate.
  3. Send a navigation goal using Nav2 Goal or 2D Goal Pose.
  4. Observe the global path in RViz2.
  5. Observe local and global costmaps.
  6. Observe robot motion toward the goal.
  7. Check /navigate_to_pose action feedback.
  8. Check /cmd_vel output.
  9. Understand the difference between planning and full navigation.
  10. Debug common RViz goal navigation problems.

2. Suggested teaching duration

Suggested duration: 2 hours

| Time | Activity | | ----------- | -------------------------------------- | | 0–15 min | Review Step 8 Nav2 planning | | 15–30 min | Explain RViz2 navigation workflow | | 30–45 min | Launch map, AMCL, and Nav2 | | 45–60 min | Configure RViz2 displays | | 60–75 min | Set initial pose | | 75–95 min | Send navigation goal | | 95–110 min | Observe path, costmaps, and /cmd_vel | | 110–120 min | Summary and homework |


3. What RViz2 does in Nav2

RViz2 is a visualization and interaction tool.

In Nav2, you use RViz2 to:

view the map
view the robot model
view TF frames
view LiDAR scan
view costmaps
view planned path
set the initial pose
send a navigation goal
monitor navigation behavior

RViz2 does not control the robot directly.

Instead, RViz2 sends requests to Nav2.

For example:

RViz2 goal tool
   ↓
NavigateToPose action
   ↓
BT Navigator
   ↓
Planner Server
   ↓
Controller Server
   ↓
/cmd_vel
   ↓
Robot moves

4. Review: what must work before using RViz goal navigation

Before you send a goal in RViz2, you should already have:

map loaded
AMCL localization working
Nav2 navigation stack active
TF tree connected
LiDAR scan available
odometry available
/cmd_vel accepted by robot or simulation

Check these commands first:

ros2 topic echo /map --once
ros2 topic echo /scan --once
ros2 topic echo /odom --once
ros2 run tf2_ros tf2_echo map base_link
ros2 action list | grep navigate

You should see:

/navigate_to_pose

5. Target TF tree

Before full navigation, your TF tree should look like this:

map
 └── odom
      └── base_link
            β”œβ”€β”€ base_laser
            β”œβ”€β”€ camera_link
            └── imu_link

Meaning:

| Transform | Usually published by | | ------------------------- | ------------------------ | | map β†’ odom | AMCL | | odom β†’ base_link | odometry | | base_link β†’ base_laser | URDF or static transform | | base_link β†’ camera_link | URDF or static transform | | base_link β†’ imu_link | URDF or static transform |

Check the TF tree:

ros2 run tf2_tools view_frames
xdg-open frames.pdf

6. Launch system for RViz goal navigation

Option A: TurtleBot simulation

This is the easiest classroom option.

source /opt/ros/jazzy/setup.bash

ros2 launch nav2_bringup tb3_simulation_launch.py \
  headless:=False \
  slam:=False \
  map:=$HOME/ros2_ws/maps/classroom_map.yaml

Important:

The map must match the simulation world.
If the map and world do not match, AMCL and navigation will fail.

Option B: Your own AMR

For your own AMR, start the robot bringup first.

You need:

LiDAR driver
odometry node
robot_state_publisher
AMCL localization
Nav2 navigation stack
RViz2

Example sequence:

Terminal 1: Robot bringup

source ~/ros2_ws/install/setup.bash

# Example only:
# ros2 launch your_robot_bringup robot_bringup.launch.py

Terminal 2: Localization

source /opt/ros/jazzy/setup.bash

ros2 launch nav2_bringup localization_launch.py \
  map:=$HOME/ros2_ws/maps/classroom_map.yaml \
  use_sim_time:=False

Terminal 3: Navigation

source /opt/ros/jazzy/setup.bash

ros2 launch nav2_bringup navigation_launch.py \
  use_sim_time:=False

Terminal 4: RViz2

source /opt/ros/jazzy/setup.bash
rviz2

7. Configure RViz2 for Nav2

In RViz2, set:

Fixed Frame = map

Add these displays:

| Display | Topic or setting | | -------------- | ----------------------------- | | Map | /map | | TF | Show frame names | | RobotModel | robot_description | | LaserScan | /scan | | Odometry | /odom | | Path | /plan or planner path topic | | PoseArray | /particle_cloud | | Global Costmap | /global_costmap/costmap | | Local Costmap | /local_costmap/costmap |

Recommended RViz2 displays:

Map
TF
RobotModel
LaserScan
Odometry
Path
PoseArray
Global Costmap
Local Costmap

8. Step 1 in RViz2: Set initial pose

Before sending a navigation goal, you must tell AMCL approximately where the robot is.

In RViz2:

1. Click 2D Pose Estimate.
2. Click the robot's approximate position on the map.
3. Drag the arrow in the robot's facing direction.
4. Release the mouse button.

This publishes to:

/initialpose

You can verify it:

ros2 topic echo /initialpose

Then click 2D Pose Estimate again in RViz2.

If the terminal shows a message, RViz2 successfully published the initial pose.


9. Check localization after setting initial pose

After setting the initial pose, check:

ros2 run tf2_ros tf2_echo map odom

Then check:

ros2 run tf2_ros tf2_echo map base_link

You should see transform values.

In RViz2, you should observe:

LiDAR scan aligns with the map.
Robot model is near the correct position.
Particle cloud is near the robot.

If the robot is not aligned with the map, set the initial pose again.


10. Step 2 in RViz2: Send a navigation goal

In RViz2, use the goal tool.

Depending on your RViz2/Nav2 configuration, the button may appear as:

Nav2 Goal
2D Goal Pose
2D Nav Goal

Use the Nav2 goal tool if available.

Steps:

1. Click Nav2 Goal or 2D Goal Pose.
2. Click a reachable point on the map.
3. Drag the arrow to set the final robot orientation.
4. Release the mouse button.

This sends a navigation request to Nav2.

Conceptually, RViz2 sends:

/navigate_to_pose

The goal contains:

goal x position
goal y position
goal orientation
frame_id = map

11. What should happen after sending a goal?

After sending a valid goal, you should observe:

A global path appears.
The local costmap updates.
The controller publishes velocity commands.
The robot starts moving.
The robot follows the path.
The robot stops near the goal.

In RViz2, look for:

planned path
robot movement
costmap changes
LiDAR scan alignment
particle cloud stability

12. Check NavigateToPose action

Open a terminal:

ros2 action list

You should see:

/navigate_to_pose

Check action type:

ros2 action type /navigate_to_pose

Expected type:

nav2_msgs/action/NavigateToPose

You can inspect the interface:

ros2 interface show nav2_msgs/action/NavigateToPose

13. Send a navigation goal from command line

RViz2 is convenient, but command-line testing is also useful.

Example:

ros2 action send_goal /navigate_to_pose nav2_msgs/action/NavigateToPose \
"{
  pose: {
    header: {
      frame_id: 'map'
    },
    pose: {
      position: {
        x: 1.0,
        y: 0.5,
        z: 0.0
      },
      orientation: {
        x: 0.0,
        y: 0.0,
        z: 0.0,
        w: 1.0
      }
    }
  },
  behavior_tree: ''
}"

This asks Nav2:

Navigate to x = 1.0, y = 0.5 in the map frame.
Final orientation uses quaternion w = 1.0.

To get feedback during navigation, use:

ros2 action send_goal --feedback /navigate_to_pose nav2_msgs/action/NavigateToPose \
"{
  pose: {
    header: {
      frame_id: 'map'
    },
    pose: {
      position: {
        x: 1.0,
        y: 0.5,
        z: 0.0
      },
      orientation: {
        w: 1.0
      }
    }
  },
  behavior_tree: ''
}"

14. Observe /cmd_vel

When Nav2 controls the robot, it usually publishes velocity commands.

Check:

ros2 topic echo /cmd_vel

You should see values like:

linear:
  x: 0.1
angular:
  z: 0.2

Meaning:

linear.x controls forward/backward speed.
angular.z controls turning speed.

If /cmd_vel is active but the robot does not move, possible reasons include:

motor driver is not subscribed to /cmd_vel
wrong command velocity topic
robot emergency stop is active
simulation is paused
controller output is being remapped

15. Observe path and costmap topics

Check path topics:

ros2 topic list | grep plan
ros2 topic list | grep path

Check costmap topics:

ros2 topic list | grep costmap

Common topics:

/plan
/global_costmap/costmap
/local_costmap/costmap
/global_costmap/published_footprint
/local_costmap/published_footprint

In RViz2, display:

global costmap
local costmap
planned path
robot footprint

This helps you understand why Nav2 chooses a path.


16. Cancel a navigation goal

If the robot is moving incorrectly, cancel the goal.

In RViz2:

Use the Nav2 panel Cancel button if available.

From command line, you can also send Ctrl+C if the goal was sent using ros2 action send_goal.

For a real robot, always prepare a physical emergency stop.

Important safety note:

For real AMR testing, keep the robot speed low, keep the area clear, and prepare an emergency stop.

17. Good navigation behavior

Good navigation usually looks like this:

The robot starts from the correct pose.
The LiDAR scan aligns with the map.
The global path avoids obstacles.
The local costmap updates near the robot.
The robot moves smoothly.
The robot stops near the goal.
The final orientation is close to the goal arrow direction.

18. Bad navigation behavior

Bad navigation may look like this:

The robot starts from the wrong map position.
The robot spins in place.
The robot moves away from the goal.
The robot cannot plan a path.
The robot stops immediately.
The global path crosses obstacles.
The costmap blocks the whole area.
The robot reaches the goal position but not orientation.

When this happens, debug in this order:

1. Check map.
2. Check initial pose.
3. Check TF tree.
4. Check scan alignment.
5. Check costmaps.
6. Check Nav2 lifecycle.
7. Check /cmd_vel.
8. Check robot driver.

19. Create a simple RViz configuration package

If you want a cleaner classroom setup, create an RViz configuration package or store the RViz file in your existing amr_navigation package.

Open RViz2, configure displays, then save:

File β†’ Save Config As

Save it as:

~/ros2_ws/src/amr_navigation/rviz/nav2_goal_navigation.rviz

Then modify your launch file to load it automatically.

Example RViz2 node in launch file:

rviz_node = Node(
    package='rviz2',
    executable='rviz2',
    name='rviz2',
    output='screen',
    arguments=['-d', rviz_config_file]
)

This makes your course easier because you do not need to manually add displays every time.


20. Optional: Create one launch file for localization, navigation, and RViz2

You can create a single launch file for classroom use.

Create:

cd ~/ros2_ws/src/amr_navigation
nano launch/nav2_goal_navigation.launch.py

Example launch file:

import os

from ament_index_python.packages import get_package_share_directory

from launch import LaunchDescription
from launch.actions import IncludeLaunchDescription
from launch.launch_description_sources import PythonLaunchDescriptionSource

from launch_ros.actions import Node


def generate_launch_description():

    package_name = 'amr_navigation'

    bringup_dir = get_package_share_directory('nav2_bringup')

    map_file = os.path.join(
        os.path.expanduser('~'),
        'ros2_ws',
        'maps',
        'classroom_map.yaml'
    )

    params_file = os.path.join(
        get_package_share_directory(package_name),
        'config',
        'nav2_params.yaml'
    )

    rviz_config_file = os.path.join(
        get_package_share_directory(package_name),
        'rviz',
        'nav2_goal_navigation.rviz'
    )

    localization_launch = IncludeLaunchDescription(
        PythonLaunchDescriptionSource(
            os.path.join(bringup_dir, 'launch', 'localization_launch.py')
        ),
        launch_arguments={
            'map': map_file,
            'use_sim_time': 'false',
            'params_file': params_file
        }.items()
    )

    navigation_launch = IncludeLaunchDescription(
        PythonLaunchDescriptionSource(
            os.path.join(bringup_dir, 'launch', 'navigation_launch.py')
        ),
        launch_arguments={
            'use_sim_time': 'false',
            'params_file': params_file
        }.items()
    )

    rviz_node = Node(
        package='rviz2',
        executable='rviz2',
        name='rviz2',
        output='screen',
        arguments=['-d', rviz_config_file]
    )

    return LaunchDescription([
        localization_launch,
        navigation_launch,
        rviz_node
    ])

Important:

This launch file assumes your robot bringup is already running.
It does not start LiDAR, odometry, or robot_state_publisher.

21. Build and run the combined launch file

Build:

cd ~/ros2_ws
colcon build --packages-select amr_navigation
source install/setup.bash

Run:

ros2 launch amr_navigation nav2_goal_navigation.launch.py

Then in RViz2:

1. Set initial pose using 2D Pose Estimate.
2. Wait until scan aligns with map.
3. Send goal using Nav2 Goal or 2D Goal Pose.
4. Observe path and robot motion.

22. How Step 9 connects to Step 10

In Step 9, you used RViz2 to send goals and observe navigation.

In Step 10, you will debug TF2 and Nav2 problems.

The reason is:

Most Nav2 failures are caused by TF, frame name, timestamp, costmap, or localization problems.

Step 10 will help you answer questions such as:

Why does RViz2 show No transform?
Why does Nav2 fail to plan?
Why is the robot not moving?
Why does the robot move in the wrong direction?
Why does the costmap block the path?

23. Common problems and solutions

Problem 1: RViz2 goal button is missing

Possible reasons:

Nav2 RViz plugin is not loaded.
RViz2 configuration does not include the Nav2 panel.
The button name is different in your RViz2 setup.

Solution:

Check the top toolbar for Nav2 Goal, 2D Goal Pose, or 2D Nav Goal.
Open Panels and add the Nav2 panel if available.
You can also send /navigate_to_pose from command line.

Problem 2: Robot does not move after sending goal

Possible reasons:

Nav2 nodes are not active.
Goal is invalid.
No path is found.
Controller is not active.
No /cmd_vel output.
Robot driver is not subscribed to /cmd_vel.
Emergency stop is active.

Check:

ros2 lifecycle get /bt_navigator
ros2 lifecycle get /planner_server
ros2 lifecycle get /controller_server
ros2 topic echo /cmd_vel
ros2 action list

Problem 3: Goal is rejected or aborted

Possible reasons:

Goal is outside the map.
Goal is inside an obstacle.
Robot is not localized.
Costmap blocks the goal.
TF map β†’ base_link is missing.

Check:

ros2 run tf2_ros tf2_echo map base_link
ros2 topic echo /global_costmap/costmap --once

Solution:

Set initial pose again.
Choose a goal in free space.
Check the costmap in RViz2.

Problem 4: Robot moves in the wrong direction

Possible reasons:

base_link frame direction is wrong.
Wheel odometry sign is wrong.
cmd_vel interpretation is wrong.
Robot model x-axis is not forward.
LiDAR frame is misconfigured.

Check:

ros2 run tf2_ros tf2_echo odom base_link
ros2 topic echo /cmd_vel

Important convention:

For a mobile robot, base_link x-axis should point forward.

Problem 5: Robot spins in place

Possible reasons:

Initial orientation is wrong.
AMCL localization is poor.
Goal orientation is difficult to reach.
Controller parameters are not tuned.
Odometry yaw is noisy.

Solution:

Set initial pose again.
Choose a nearby goal.
Reduce speed.
Check odometry and IMU fusion.
Tune controller parameters later.

Problem 6: LiDAR scan does not align with map

Possible reasons:

Initial pose is wrong.
base_link β†’ base_laser transform is wrong.
Map does not match the environment.
AMCL is not converged.
LiDAR scan topic is wrong.

Solution:

Use 2D Pose Estimate again.
Check base_link β†’ base_laser.
Check /scan in RViz2.
Use the correct map.

Problem 7: Costmap blocks the whole area

Possible reasons:

Robot radius is too large.
Inflation radius is too large.
Unknown space is treated as occupied.
Obstacle layer receives bad scan data.
TF is wrong.

Check:

ros2 topic echo /global_costmap/costmap --once
ros2 topic echo /local_costmap/costmap --once

Solution:

Inspect costmap in RViz2.
Check robot_radius.
Check inflation_radius.
Check scan data.
Check TF.

Problem 8: RViz2 shows β€œNo transform”

Possible reasons:

Fixed Frame is wrong.
map β†’ odom is missing.
odom β†’ base_link is missing.
base_link β†’ sensor frame is missing.
use_sim_time setting is wrong.

Check:

ros2 run tf2_tools view_frames
ros2 run tf2_ros tf2_echo map base_link

Solution:

Set Fixed Frame to map.
Check AMCL.
Check odometry.
Check robot_state_publisher.
Check use_sim_time.

24. Practice assignment

Assignment title

Send a Nav2 Goal Using RViz2

Task 1: Check system readiness

Submit screenshots of:

ros2 topic echo /map --once
ros2 topic echo /scan --once
ros2 topic echo /odom --once
ros2 run tf2_ros tf2_echo map base_link

Task 2: Check Nav2 actions and lifecycle

Submit screenshots of:

ros2 action list
ros2 lifecycle get /bt_navigator
ros2 lifecycle get /planner_server
ros2 lifecycle get /controller_server

Expected state:

active

Task 3: Configure RViz2

In RViz2, set:

Fixed Frame = map

Add:

Map
TF
RobotModel
LaserScan
PoseArray
Path
Global Costmap
Local Costmap

Submit a screenshot.


Task 4: Set initial pose

Use:

2D Pose Estimate

Submit a screenshot showing:

Robot model on the map
LiDAR scan aligned with the map
Particle cloud near the robot

Task 5: Send navigation goal

Use:

Nav2 Goal or 2D Goal Pose

Submit a screenshot showing:

Goal pose
Planned path
Robot moving or reaching goal
Costmaps

Task 6: Check /cmd_vel

Run while the robot is moving:

ros2 topic echo /cmd_vel

Submit a screenshot.


Task 7: Explain the result

Write a short explanation:

The map topic is:
The scan topic is:
The odometry topic is:
The navigation action is:
The command velocity topic is:
The initial pose was set using:
The goal was sent using:
The robot successfully reached the goal: yes/no
One problem I observed was:
How I fixed or would fix it:

25. Mini quiz

  1. What is RViz2 used for in Nav2?
  2. What button is used to set the robot initial pose?
  3. What button is used to send a navigation goal?
  4. What action is used for full navigation to one goal pose?
  5. What topic usually carries velocity commands?
  6. Why must AMCL localization work before sending a goal?
  7. What should you check if the robot does not move?
  8. What should you check if the scan does not align with the map?
  9. What should you check if RViz2 shows β€œNo transform”?
  10. Why is the goal orientation important?
  11. Why should you keep speed low when testing a real AMR?
  12. What is the difference between a planned path and robot movement?

26. Key summary

In this module, you learned how to use RViz2 for Nav2 goal navigation.

The normal workflow is:

1. Launch robot bringup.
2. Launch localization.
3. Launch Nav2 navigation.
4. Open RViz2.
5. Set Fixed Frame to map.
6. Set initial pose using 2D Pose Estimate.
7. Confirm scan aligns with map.
8. Send goal using Nav2 Goal or 2D Goal Pose.
9. Observe path, costmaps, /cmd_vel, and robot motion.

You learned that RViz2 sends a navigation request to:

/navigate_to_pose

Nav2 then uses:

BT Navigator
Planner Server
Controller Server
Costmaps

to move the robot toward the goal.

The most important idea is:

RViz2 is the user interface.
Nav2 is the navigation system.
The robot moves only when Nav2 produces valid /cmd_vel commands and the robot driver accepts them.

In the next module, you will learn:

TF2 debugging in Nav2

This final module will help you diagnose the most common problems in mapping, localization, planning, and RViz goal navigation.

Tags