In this tutorial, I will show you how to load a new map at runtime using the command line. We will work with ROS 2. The use case for this tutorial is a robot that needs to navigate between floors of a multi-floor building.
Update: There is a new way to load a new map for navigation at runtime. You can use the changeMap() method provided by the Nav 2 Simple Commander API.
Prerequisites
- ROS 2 Foxy Fitzroy installed on Ubuntu Linux 20.04 or newer. I am using ROS 2 Galactic, which is the latest version of ROS 2 as of the date of this post.
- You have already created a ROS 2 workspace. The name of our workspace is “dev_ws”, which stands for “development workspace.”
- You have Python 3.7 or higher.
- (Optional) You have completed my Ultimate Guide to the ROS 2 Navigation Stack.
- (Optional) You have a package named two_wheeled_robot inside your ~/dev_ws/src folder, which I set up in this post. If you have another package, that is fine.
- (Optional) You know how to load a world file into Gazebo using ROS 2.
You can find the files for this post here on my Google Drive.
Directions
Suppose you have a room service robot that is running on ROS 2. The robot is moving around the 5th floor of a hospital.
A hospital patient on the 5th floor has finished his meal and summons the robot to his room so the robot can carry the dirty dishes down to the kitchen of the hotel’s cafe. Suppose the hotel cafe is located on the 2nd floor of the building.
We want our robot to navigate from the 5th floor of the hospital –> elevator –> hospital cafe (2nd floor).
The process for performing multi-floor navigation might look something like this:
- Navigate to the Patient’s Room
- Pick up the Dirty Dishes
- Navigate to the Elevator Door
- Press the Down Button
- Wait for the Elevator to Open
- Enter the Elevator
- Press the Elevator Button for the 2nd Floor
- Wait for the Elevator to Reach the 2nd Floor
- Exit the Elevator
- Load a New Map of the 2nd Floor Hospital Cafe
Let’s take a look at how to do step 11.
Load the hospital world by opening a new terminal window and typing:
cd ~/dev_ws/
ros2 launch two_wheeled_robot hospital_world_v1.launch.py
Here is what the 5th floor of the hospital looks like:
Now, let’s assume the robot has done steps 1-10 in the list I posted earlier. It is now on the 2nd floor where the cafe is.
Let’s load a map of the cafe. We need to make a ROS 2 service call to the LoadMap service. ROS 2 services work well when you want a request-response interaction.
Let’s see what services we have.
ros2 service list
We could also have used the following command to see the type of each service.
ros2 service list -t
We can see that we have a service called /map_server/load_map. Let’s see the service type.
ros2 service type /map_server/load_map
The output is:
nav2_msgs/srv/LoadMap
Let’s see the structure of the input arguments for this service.
ros2 interface show nav2_msgs/srv/LoadMap
You will see the variable string map_url. Since this is above the —, this piece is the request structure. Everything below the —, is the response structure.
For a ros2 service call, everything above the — are the arguments needed to call the service.
Now we need to call the /map_server/load_map service. The syntax is as follows:
ros2 service call <service_name> <service_type> <arguments>
All of this below is a single command.
ros2 service call /map_server/load_map nav2_msgs/srv/LoadMap "{map_url: /home/focalfossa/dev_ws/src/two_wheeled_robot/maps/cafe_world/cafe_world.yaml}"
…where cafe_world.yaml is the new map file. Notice you need to provide the full path to the map file.
Here is what RViz looks like after running the command.
You can go in RViz and uncheck the local costmap.
The outline of the reception desk is due to the fact that the robot is still in the hospital world inside Gazebo, so its global costmap is updating accordingly.
Below is what the cafe world actually looks like in Gazebo. You will see that the new map above comes from this cafe world.
That’s how you load a new map at runtime using ROS 2. That’s it. Keep building!