ROS2 Nav2 Tutorial

In this ROS2 Nav2 tutorial you will learn the basics of the Navigation 2 stack, step by step.

You will first install the Nav2 stack on ROS2 Humble, then you will start directly to generate a map with SLAM. After this, we will check what’s inside the map, and then use this map with the Navigation 2 stack, so that we can make a robot navigate inside the map.

To do all that, you actually don’t need to buy any hardware, we will use the simulation of an already configured robot, the Turtlebot3, on Gazebo.

And this tutorial is in fact inspired by this 1H crash course video:

You can watch the video and use the written tutorial to get all the commands quickly.


You are learning Navigation 2 with ROS2?

Check out this ROS2 Nav2 course, and learn step by step, from scratch.


What is ROS2 Nav2?

Let’s quickly understand what Nav2 is and why we need it.

And before we get started, let’s just be clear on the terms we are going to use. When I write about Navigation, Navigation 2, Nav2, well this is all the same, I am writing about the Navigation 2 stack in ROS2 (also if I write ROS I also mean ROS2).

So, why do we need Nav2 in the first place? Well, as you probably already know, ROS is a great framework that allows you to develop new robotics applications in no time. You get a lot of “plumbing” already done for you, a huge set of plug & play libraries, a community to help you, etc.

Now, how do you go from knowing the ROS basics, to successfully implementing navigation for a mobile robot? This is not trivial at all, and fortunately, the Navigation 2 stack was developed just for that. The “stack” is a collection of packages that have been developed with one goal in mind.

And what is this goal? The main goal is to make a robot move from point A to point B, in a safe way. So, basically, to find a path that allows the robot to reach the destination, while making sure that it will not collide with other robots, with people, and obstacles.

ROS2 Nav2 Goal

To achieve this, we will do a 2 step process:

  1. We will create a map of the environment using SLAM.
  2. We will make the robot navigate using this map – with the Navigation functionalities and tools.

Install Nav2

As a prerequisite for this tutorial, make sure you have installed Ubuntu and ROS2 on your computer. I strongly recommend using a dual boot for Ubuntu, not a virtual machine (3D tools like Gazebo are usually not working well on VMs). If you do want to use a VM, choose VMWare Workstation (free version) over VirtualBox.

For the following, I will use Ubuntu 22.04 and ROS2 Humble.

So, once you have correctly installed and setup ROS2 on your computer, let’s install the Navigation 2 stack.

Here is how to install the Nav2 packages.

$ sudo apt install ros-humble-navigation2 ros-humble-nav2-bringup

As we will use a simulation of a robot on Gazebo, let’s install the packages for this robot (Turtlebot3).

$ sudo apt install ros-humble-turtlebot3*

And that’s it to get started!

Make the robot move in the environment

Before we generate a map with Nav2 and use it for navigation, we need to make sure that we can make our robot move in the environment.

If you were using a custom robot, you would need to adapt it first for Nav2. This process is really not easy, especially if you’re doing it for the first time. So, to make things easier – as the goal here is just to get an introduction of the stack – we will use the Turtlebot3 in Gazebo.

We first need to export an environment variable to choose which version of the Turtlebot3 we want to use (burger, waffle, waffle_pi).

Add this line at the end of your .bashrc: export TURTLEBOT3_MODEL=waffle. After doing that, make sure to source the .bashrc, or to open a new terminal.

Then, time to start the simulated robot in a Gazebo world.

$ ros2 launch turtlebot3_gazebo turtlebot3_world.launch.py

Note: the first time you launch this world, it may take some time (a few minutes) and you’ll have the impression that it froze on the loading screen. Don’t worry, just wait, don’t touch anything, and let it load the map. Then, when you start again, it will be much faster.

Turtlebot3 world in Gazebo

Great, now we have a robot inside a room. Let’s make it move. In a new terminal, start the teleop node.

$ ros2 run turtlebot3_teleop teleop_keyboard

You will see some instructions on the terminal. Press keys W, A, S, D, to make the robot move. It’s not necessarily super intuitive the first time you use it, so take a few minutes to familiarize yourself with the commands. And make sure your mouse is focused on the terminal when you press a key.

Once you can make the robot move in the world, you are ready for the next steps.

Generate a map with ROS2 Nav2 – using SLAM

In order to make the robot navigate autonomously in the world, we first need to generate a map of that world. And to do that, we’ll use the SLAM functionality of the ROS2 Nav2 stack.

Note: there are many possible tools and algorithms to do SLAM. To make it easier we’ll choose the default SLAM tool for Turtlebot3: cartographer. Later on you can choose to use other tools, such as slam_toolbox.

So, how to generate a map with SLAM?

Start the SLAM functionality and RViz

First make sure you have started the robot – here, Turtlebot3 in Gazebo.

$ ros2 launch turtlebot3_gazebo turtlebot3_world.launch.py

Then, let’s start the SLAM functionality for Turtlebot3.

$ ros2 launch turtlebot3_cartographer cartographer.launch.py use_sim_time:=True

Note: I provide the “use_sim_time” argument because we are running on Gazebo, so we want to use the Gazebo time. If using a real robot, skip this argument.

After running this command you will see RViz starting.

ROS2 Nav2 - SLAM in RViz

You can see the TFs of the robot, as well as the LaserScan from the Lidar sensor (red dots). Some pixels are already grey/black. As you make the robot move, pixels will be cleared into 3 categories:

  • Free space (will turn white),
  • Obstacle (will turn black),
  • Unknown space (will stay grey).

Generate and save the map

Now, make the robot move in the world. Here we start the Turtlebot3 teleop node.

$ ros2 run turtlebot3_teleop teleop_keyboard

Make the robot move around until you get a satisfying result. By the way, what is a satisfying result? Well if you can manage to clear most of the free space (white pixels), and get most of the obstacles (black pixels), that’s good enough, and navigation will work fine. No need to clear 100% of the pixels.

ROS2 Nav2 - Generated map in RViz with SLAM

Once you get a good enough result, it’s time to save the map. Make sure you don’t stop the navigation terminal before you save the map, otherwise you’ll have to start everything again.

To save the map, open a new terminal and run this command.

$ ros2 run nav2_map_server map_saver_cli -f my_map

With the optional “-f” argument you can specify the path/name for the map. Don’t add any extension, this will be done automatically for you.

Once you run this, you should see some logs in white and maybe yellow. If it doesn’t work (red error logs), try again several times.

Your map has now been generated, and you can stop all the commands in all the terminals.

What’s in the map?

You should now have 2 new files:

  • my_map.yaml
  • my_map.pgm

The PGM file is the image representing the map, with white (free space), black (obstacles) and grey pixels (unknown space).

Generated map with Nav2 SLAM

The YAML file contains important info about the map. This will be used by the Navigation stack.

image: my_map.pgm
mode: trinary
resolution: 0.05
origin: [-2.97, -2.57, 0]
negate: 0
occupied_thresh: 0.65
free_thresh: 0.25

Here is more info about the most important fields:

  • image: the relative path from the YAML file to the PGM file.
  • resolution: in meters per pixels. So, here 0.05 meters per pixels. One pixel represents 5 cm. That gives you the precision of the map.
  • origin: the coordinates of the robot (when it started) relative to the lowest left point on the map.
  • negate: if you set it to 1, then free and occupied space will be inverted.
  • occupied_tresh and free_tresh: very basically put, when mapping, each pixel will be given a probability about whether there is an obstacle or not. With the values that you see here, if the probability is greater than 65%, we consider the space to be occupied. If the probability is less than 25%, the space is free.

Quick fix and DDS issue with Nav2

Before we continue with Navigation, we need to fix 2 small things.

First, as you may know, ROS2 communication is based on DDS (for the middleware). No need to dive into this now, you just have to know that there are several possible DDS implementations, and the default one for ROS2 is Fast DDS. Unfortunately it doesn’t work so well with Nav2, so it’s been recommended to use Cyclone DDS instead.

Let’s install and setup Cyclone DDS for ROS2.

$ sudo apt install ros-humble-rmw-cyclonedds-cpp

Cyclone DDS is now installed, now you need to tell ROS2 to use it instead of the default one.

Add this line into your .bahsrc: export RMW_IMPLEMENTATION=rmw_cyclonedds_cpp. You can put it just before sourcing ROS2 for example.

Great, DDS problem solved!

One more thing to do, and this is a Turtlebot3 specific issue.

Open this param file:

$ sudo gedit /opt/ros/humble/share/turtlebot3_navigation2/param/waffle.yaml

Find this line, and replace it like you see below.

    ...
    #robot_model_type: "differential"
    robot_model_type: "nav2_amcl::DifferentialMotionModel"
    ...

Make the robot navigate using the map and ROS2 Nav2

Great, you now have a map, and everything setup so you can make the robot navigate autonomously, while avoiding obstacles.

Start Navigation 2 for the robot

Let’s start from a clean environment – stop everything, close and reopen all terminals. There are a lot of things that can go wrong with RViz and Gazebo, so we make sure to reduce the risks.

Now, start the robot again.

$ ros2 launch turtlebot3_gazebo turtlebot3_world.launch.py

In another terminal, start the Navigation stack, and provide the map as an argument.

$ ros2 launch turtlebot3_navigation2 navigation2.launch.py use_sim_time:=True map:=path/to/my_map.yaml

Note: use “use_sim_time” only if running with Gazebo. For the “map” argument, provide the path to the YAML file of the map.

If you don’t see the map on RViz, try finding the “map” topic options on the left panel, and set to “transient local” instead of “volatile”. You might also try to restart everything, and even reboot your computer.

Now, you should just see the map on the screen, but no robot. You’ll also see some kinds of error logs in the terminal. This is because Nav2 doesn’t know where your robot is, and you need to provide the first 2D pose estimate.

Nav2 - Navigation using generated map

2D pose estimate and Navigation goals

Click on the “2D pose estimate” button on RViz. Then click on the map where the robot is (you should see that on Gazebo). Maintain the click to also specify the orientation with a green arrow.

Once you’re done, you should see something like that on RViz.

Nav2 2D Pose Estimate in RViz

Finally, you can give navigation commands! Click on “Nav2 Goal”, then click on the map to select a position + orientation, and the robot should start to go to that pose. You can verify on Gazebo, to see that the robot is actually moving.

Nav2 Navigation Goal in RViz

Now, you can experiment with different poses. Give valid ones, and also invalid ones (ex: a point that cannot be reached).

Going further with ROS2 Nav2

In this tutorial you have seen how to get started with the Navigation 2 stack. You should now have a better idea of how it works and how to use it.

Now to go further and really understand how things work, you can continue your learning with the ROS2 Nav2 course (6 hours of content). In this course you’ll also:

  • Understand how Nav2 works behind the hoods, with all components: global/local planner, parameters, TFs, etc.
  • Learn how to build your own simulated world in Gazebo to be able to use Nav2 for your own office/classroom/building.
  • Get an intro on how to adapt a custom robot for Nav2, with all the steps.
  • Program with Nav2 directly using Python instead of the buttons on RViz.
  • And even more tips and best practices.

Did you find this tutorial useful?

Do you want to learn Nav2 from scratch?

If yes, this course is for you:

ROS2 Nav2 Stack Course

>> ROS2 Nav2 Course - with SLAM and Navigation <<