How to Install ROS 2 Navigation (Nav2) – ROS 2 Jazzy

In this tutorial, I will walk you through the process of installing the ROS 2 Navigation (Nav2) stack. By the end of this tutorial, you will have Nav2 fully installed on your system, and you will be able to run this demo:

install-ros2-nav2-jazzy

We will use concepts both from the official Nav2 website as well as the official tutorials.

What is ROS 2 Navigation (Nav2)?

ROS 2 Navigation, or Nav2 for short, is a set of ROS 2 packages that provide a complete solution for autonomous robot navigation. It includes modules for localization, mapping, path planning, and control, allowing robots to navigate through their environment safely and efficiently. Nav2 is built on top of the ROS 2 framework, leveraging its modularity, scalability, and robustness.

Real-World Applications

Nav2 has numerous real-world applications across various industries. Some examples include:

  • Warehouse automation: Autonomous mobile robots (AMRs) equipped with Nav2 can navigate warehouses, pick up and deliver goods, and optimize inventory management.
  • Healthcare and hospitality: Robots powered by Nav2 can assist in hospitals, hotels, and restaurants, navigating through dynamic environments and interacting with humans.
  • Agricultural robotics: Nav2 enables autonomous tractors and harvesters to navigate fields, monitor crops, and perform precision farming tasks.

Types of Robots That Can Use ROS 2 Navigation

Nav2 is versatile and can be used with a wide range of robot platforms, including:

  • Differential drive robots: Robots with two independently driven wheels, such as the TurtleBot and the iRobot Create.
  • Holonomic robots: Robots that can move in any direction without changing their orientation, like the Yahboom ROSMASTER X3.
  • Ackermann steering robots: Robots with car-like steering, such as autonomous vehicles and some agricultural robots.

Prerequisites

All my code for this project is located here on GitHub.

Create Packages

Navigate to your workspace, and create the following packages. You can replace the maintainer-name and maintainer email with your own information.

cd ~/ros2_ws/src/yahboom_rosmaster/
ros2 pkg create --build-type ament_cmake \
                --license BSD-3-Clause \
                --maintainer-name ubuntu \
                --maintainer-email automaticaddison@todo.com \
                yahboom_rosmaster_localization
ros2 pkg create --build-type ament_cmake \
                --license BSD-3-Clause \
                --maintainer-name ubuntu \
                --maintainer-email automaticaddison@todo.com \
               yahboom_rosmaster_navigation

Update the package.xml files for all packages, including the metapackage. Be sure to add a good description line for each.

You can also update the metapackage with the new packages you just created.

cd yahboom_rosmaster
gedit package.xml
<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
  <name>yahboom_rosmaster</name>
  <version>0.0.0</version>
  <description>ROSMASTER series robots by Yahboom (metapackage).</description>
  <maintainer email="automaticaddison@todo.todo">ubuntu</maintainer>
  <license>BSD-3-Clause</license>

  <buildtool_depend>ament_cmake</buildtool_depend>

  <exec_depend>yahboom_rosmaster_bringup</exec_depend>
  <exec_depend>yahboom_rosmaster_description</exec_depend>
  <exec_depend>yahboom_rosmaster_gazebo</exec_depend>
  <exec_depend>yahboom_rosmaster_localization</exec_depend>
  <exec_depend>yahboom_rosmaster_navigation</exec_depend>
  <exec_depend>yahboom_rosmaster_system_tests</exec_depend>

  <test_depend>ament_lint_auto</test_depend>
  <test_depend>ament_lint_common</test_depend>

  <export>
    <build_type>ament_cmake</build_type>
  </export>
</package>

Edit package.xml

Now let’s make sure some key packages are installed.

Open a terminal window, and go to your package.xml folder inside the yahboom_rosmaster_navigation package.

cd ~/ros2_ws/src/yahboom_rosmaster/yahboom_rosmaster_navigation

Open the package.xml file.

Make sure it has these blocks:

…
 <description>Navigation package for ROSMASTER series robots by Yahboom</description>
…

  <depend>navigation2</depend>
  <depend>nav2_bringup</depend>
  <depend>nav2_simple_commander</depend>
  <depend>slam_toolbox</depend>
…

Open a terminal window, and go to your package.xml folder inside the yahboom_rosmaster_localization package.

cd ~/ros2_ws/src/yahboom_rosmaster/yahboom_rosmaster_localization

Open the package.xml file.

Make sure it has these blocks:

…
 <description>Localization package for ROSMASTER series robots by Yahboom</description>
…

  <depend>robot_localization</depend>

…

Edit CMakeLists.txt

Now open the CMakeLists.txt file of the yahboom_rosmaster_navigation package, and add this block:

find_package(navigation2 REQUIRED)
find_package(nav2_bringup REQUIRED)
find_package(slam_toolbox REQUIRED)

Now open the CMakeLists.txt file of the yahboom_rosmaster_localization package, and add this block:

find_package(robot_localization REQUIRED)

Build the Workspace

Now let’s build our workspace.

cd ~/ros2_ws/
rosdep install --from-paths src --ignore-src -r -y

Install any required dependencies. You should then see:

#All required rosdeps installed successfully

If you encounter errors installing the navigation and localization packages, type this:

echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/ros-archive-keyring.gpg] http://packages.ros.org/ros2/ubuntu $(. /etc/os-release && echo $UBUNTU_CODENAME) main" | sudo tee /etc/apt/sources.list.d/ros2.list > /dev/null
sudo apt-get update -y
sudo apt-get upgrade -y

Then try building again:

cd ~/ros2_ws/
rosdep install --from-paths src --ignore-src -r -y
colcon build && source ~/.bashrc

Let’s add a shortcut alias to make building our workspace quicker:

echo "alias build='cd ~/dev_ws/ && colcon build && source ~/.bashrc'" >> ~/.bashrc

Now going forward, any time you want to build you workspace, just type:

build

Test Your Installation

To test your installation, type the following command in the terminal window:

ros2 launch nav2_bringup tb3_simulation_launch.py headless:=False

To move the robot around, first set the initial pose in RViz based on where you think the robot is located and the direction you think the robot is pointed. 

Click the 2D Pose Estimate button.

2-2d-pose-estimate

Click and hold where you think the robot is and then drag your mouse in the direction the robot is oriented.

Now click the Nav2 Goal button.

3-nav2-goal

Click and hold where you want to send the robot. And drag in the direction of your desired goal orientation.

The robot will move to the goal.

4-move-to-goal

Press CTRL + C to close everything.

To test mapping, open a terminal window, and type the following command:

ros2 launch nav2_bringup tb4_simulation_launch.py slam:=True headless:=False

Click and hold where you want to send the robot. And drag in the direction of your desired goal orientation.

5-creating-a-map

The robot will move to the goal and map in the process.

6-creating-a-map-2

Press CTRL + C when you’re done.

That’s it. Keep building!

How to Completely Uninstall ROS 2

In this tutorial, I will show you how to completely uninstall ROS 2 from your system.

Uninstall ROS 2

If you want to uninstall the current version of ROS 2 that you have on your computer, type the following commands in the terminal window:

sudo apt remove ~nros-${ROS_DISTRO}-* && sudo apt autoremove

Otherwise, if you want to completely uninstall ROS 2 from your system, type this command:

sudo apt remove ros-* && sudo apt autoremove

Remove ROS 2 References in the .bashrc

Remove all ROS 2-related lines from your ~/.bashrc file.

gedit ~/.bashrc

For example, you can remove:

source ~/ros2_ws/install/setup.bash

Save the file.

Delete the Workspace

Now delete your ROS 2 workspace. For example, if your workspace is named ros2_ws, type:

rm -rf ~/ros2_ws

Remove the Repository

Finally Remove the repository:

sudo apt-get update
sudo rm /etc/apt/sources.list.d/ros2.list
sudo apt-get update
sudo apt autoremove
sudo apt-get upgrade

Reboot Your Machine

sudo reboot

That is it! Now you are back to a fresh system with no ROS 2 installed.

Keep building!

How to Write a ROS 2 Service in C++ – ROS 2 Jazzy

In this tutorial, we’ll create a ROS 2 service using C++

A ROS 2 service is a way for different parts of a robot system to communicate with each other by sending a request and receiving a response, similar to making a phone call and waiting for an answer. This form of communication is different from the publish-subscribe communication method, where one part of the system continuously broadcasts information, and any other parts that are interested can listen in, like a radio station broadcasting to many listeners. 

With a service, the communication is direct and specific, where the caller sends a request to a particular service provider and waits for a response before proceeding. In contrast, publish-subscribe allows for more flexible and asynchronous communication between multiple parts of the system without waiting for specific responses.

Services are useful when you need a quick but specific task done, and you need to wait for it to finish before moving on. You generally do not want to use a service if you need to make continuous calls for information. If you need to make continuous calls for information, topics are better suited.

Real-World Applications

Here are some real-world examples of how ROS 2 service and client nodes can be used in robotic applications:

  • Starting a Robot Vacuum Cleaner
    • Service: A service node called start_cleaning is created. When this service is called, it initiates the cleaning process of the robot vacuum cleaner.
    • Client: A client node calls the start_cleaning service to begin the cleaning process. It waits for a response from the service confirming that the cleaning process has started.
  • Localization on a Map
    • Service: A service node determines the current position and orientation of a robot on a map based on a provided map and LIDAR scans.
    • Client: A client node requests the current position and orientation of a robot on a map.
  • Gripper Control
    • Service: A service node controls the robotic arm’s gripper to open or close.
    • Client: A client node sends requests to the gripper service to open the gripper to release an object into a bin.

Prerequisites

All my code for this project is located here on GitHub.

Creating a Cleaning Service for a Robotic Vacuum Cleaner  

Let’s imagine we have a fictitious robotic vacuum cleaner:

  • If this service is called with a value of True, the robot will start cleaning.
  • If this service is called with a value of False, the robot will stop cleaning.

The name of the service is /set_cleaning_state.

We will call the service using the following syntax:

ros2 service call <service_name> <service_type> <arguments>

To start cleaning, we will run this command:

ros2 service call /set_cleaning_state yahboom_rosmaster_msgs/srv/SetCleaningState "{desired_cleaning_state: true}"

To stop cleaning, we will run this command:

ros2 service call /set_cleaning_state yahboom_rosmaster_msgs/srv/SetCleaningState "{desired_cleaning_state: false}"

Create a Custom Service Definition

Create the srv folder inside the yahboom_rosmaster_msgs package:

cd ~/ros2_ws/src/yahboom_rosmaster/yahboom_rosmaster_msgs
mkdir srv

Create the service definition file SetCleaningState.srv inside the srv folder:

cd srv

Open the SetCleaningState.srv file and add the following content:

# Request
bool desired_cleaning_state  # Request: true to start cleaning, false to stop
---
bool success                 # Response: whether the request was successful
string message               # Response: information about the result

Update CMakeLists.txt

Add these lines to yahboom_rosmaster_msgs/CMakeLists.txt:

# Find required packages
find_package(ament_cmake REQUIRED)
find_package(rosidl_default_generators REQUIRED)

# Generate interfaces
rosidl_generate_interfaces(${PROJECT_NAME}
  "action/TimedRotation.action"
  "srv/SetCleaningState.srv"
)

ament_package()

Build the Service Messages

cd ~/ros2_ws
colcon build
source ~/.bashrc

Confirm the service creation:

ros2 interface show yahboom_rosmaster_msgs/srv/SetCleaningState
1-create-a-service

Write the Service Node

Let’s write the service node.

Create the set_cleaning_state_service.cpp file inside the src directory of yahboom_rosmaster_system_tests:

cd ~/ros2_ws/src/yahboom_rosmaster/yahboom_rosmaster_system_tests/src

Add the following content:

/**
 * @file set_cleaning_state_service.cpp
 * @brief ROS 2 node that implements a service to set the cleaning state of a robot
 *
 * This program implements a ROS 2 node that provides a service to set the cleaning state
 * of a robot. It demonstrates the use of service servers in ROS 2.
 *
 * Subscription Topics:
 *   None
 *
 * Publishing Topics:
 *   None
 *
 * Services:
 *   /set_cleaning_state (yahboom_rosmaster_msgs/srv/SetCleaningState):
 *     Sets the cleaning state of the robot
 *
 * @author Addison Sears-Collins
 * @date November 26, 2024
 */
#include <memory>
#include "rclcpp/rclcpp.hpp"
#include "yahboom_rosmaster_msgs/srv/set_cleaning_state.hpp"

/**
 * @class SetCleaningStateService
 * @brief A ROS 2 node that provides a service to set the cleaning state of a robot
 */
class SetCleaningStateService : public rclcpp::Node
{
public:
  /**
   * @brief Constructor for the SetCleaningStateService class.
   *
   * Initializes the node with the name "set_cleaning_state_service"
   * and creates the service server for the "/set_cleaning_state" service.
   */
  SetCleaningStateService()
  : Node("set_cleaning_state_service")
  {
    service_ = this->create_service<yahboom_rosmaster_msgs::srv::SetCleaningState>(
      "/set_cleaning_state",
      std::bind(&SetCleaningStateService::set_cleaning_state_callback, this,
                std::placeholders::_1, std::placeholders::_2));

    RCLCPP_INFO(this->get_logger(), "Cleaning Service Server is ready.");
  }

private:
  /**
   * @brief Callback function for the set_cleaning_state service.
   *
   * This function is called when a request is received for the "/set_cleaning_state" service.
   * It checks the desired cleaning state in the request and sets the appropriate response.
   *
   * @param request The request shared pointer for the set_cleaning_state service.
   * @param response The response shared pointer for the set_cleaning_state service.
   */
  void set_cleaning_state_callback(
    const std::shared_ptr<yahboom_rosmaster_msgs::srv::SetCleaningState::Request> request,
    std::shared_ptr<yahboom_rosmaster_msgs::srv::SetCleaningState::Response> response)
  {
    if (request->desired_cleaning_state) {
      RCLCPP_INFO(this->get_logger(), "Starting cleaning...");
      response->success = true;
      response->message = "Robot started cleaning";
    } else {
      RCLCPP_INFO(this->get_logger(), "Stopping cleaning...");
      response->success = true;
      response->message = "Robot stopped cleaning";
    }

    RCLCPP_INFO(this->get_logger(), "Response sent: %s", response->message.c_str());
  }

  /// Service server for setting cleaning state
  rclcpp::Service<yahboom_rosmaster_msgs::srv::SetCleaningState>::SharedPtr service_;
};

/**
 * @brief Main function to run the SetCleaningStateService node.
 *
 * @param argc Number of command-line arguments.
 * @param argv Array of command-line arguments.
 * @return int Exit status of the program.
 */
int main(int argc, char * argv[])
{
  rclcpp::init(argc, argv);
  auto node = std::make_shared<SetCleaningStateService>();
  rclcpp::spin(node);
  rclcpp::shutdown();
  return 0;
}

Update CMakeLists.txt

Edit the CMakeLists.txt file:

add_executable(set_cleaning_state_service 
  src/set_cleaning_state_service.cpp
)

ament_target_dependencies(set_cleaning_state_service
  rclcpp
  yahboom_rosmaster_msgs
)

install(TARGETS
  set_cleaning_state_service
  DESTINATION lib/${PROJECT_NAME}
)

Build the Package

cd ~/ros2_ws
colcon build
source ~/.bashrc

Run the Service Node

Open a new terminal window, and type:

ros2 run yahboom_rosmaster_system_tests set_cleaning_state_service
2-cleaning-service-server-is-ready
ros2 service list -t

The ros2 service list -t command lists all the available services along with their corresponding service types. It shows that the /set_cleaning_state service uses the yahboom_rosmaster_msgs/srv/SetCleaningState service type.

3-ros2-service-list

Open a new terminal window, and call the service to start cleaning:

ros2 service call /set_cleaning_state yahboom_rosmaster_msgs/srv/SetCleaningState "{desired_cleaning_state: true}"
4-ros2-service-call

Now call the service to stop cleaning:

ros2 service call /set_cleaning_state yahboom_rosmaster_msgs/srv/SetCleaningState "{desired_cleaning_state: false}"
5-ros2-service-call-false

You see how we called the service via the terminal. You can also create an actual program that is the service client that calls the service just like we did in the terminal.

This tutorial showed you a simple service that:

  • Listens for requests
  • Processes the requests
  • Returns appropriate responses

All services are structured this way, so you can use this as a template for any service you create.

That’s it! Keep building!