Open-RMF stands for Open Robotics Middleware Framework, and it is a Common Language for Robot Interoperability.
It is a modular software system that enables sharing and interoperability between multiple fleets of robots and physical infrastructure, like doors, elevators, and building management systems.
This post is an introduction to the map you will need in order to use Open-RMF.
ROS Inside!
ROS Inside
Before anything else, if you want to use the logo above on your own robot or computer, feel free to download it and attach it to your robot. It is really free. Find it in the link below:
In order to follow this tutorial, we need to have ROS2 and Open-RMF installed in our system, and ideally a ros2_ws (ROS2 Workspace). To make your life easier, we have already prepared a rosject with a simulation for that: https://app.theconstructsim.com/l/51e404da/.
You can download the rosject on your own computer if you want to work locally, but just by copying the rosject (clicking the link), you will have a setup already prepared for you.
After the rosject has been successfully copied to your own area, you should see a Run button. Just click that button to launch the rosject (below you have a rosject example).
How to create a map for Robot Fleet Management Open-RMF – Run rosject (example of the RUN button)
After pressing the Run button, you should have the rosject loaded. Now, let’s head to the next section to get some real practice.
Why do we need a map, after all?
When we use Open-RMF, we want to control a fleet of robots, and since robots move around, we need a way to go through the building, and for that, we need a map.
If we check the rmf_demos repository, it shows an image of a blueprint of a building,
Open-RMF hotel world by Open-Robotics
In order to move the robot around, Open-RMF has a pipeline that goes as follows:
We start with the blueprint of a building
Use the Traffic Editor to paint the walls and the paths that the robot can follow in the building. The robots have autonomous navigation but we still limit the robots to certain areas. If we check the image above, we see two paths, a blue and an orange one. This means that there are two fleets of robots operating in this area. Each fleet can move in one of these paths.
We start from the blueprint and create a simulation from that blueprint
But we found that most of the time we already have a simulation of a building, for example, and we want to make Open-RMF adapt to our simulation, instead of making our simulation adapt to Open-RMF.
That is what is this post about: How to make your own map to be used by Open-RMF.
Starting the simulation
After having opened the rosject, let’s start a simulation. For that, let’s open a terminal by clicking the Open a new terminal button.
Open a new Terminal
Once inside the terminal, let’s run the commands below:
After a few seconds, we should have a simulation open, like in the image below (if for any reason you think the simulation is empty, just zoom out using the mouse to find the simulation):
Starbots Coffee simulation for Open-RMF on The Construct
Now that you see the simulation, we basically want to make a map of that building that appears in the simulation.
Normally, everyone who has a Gazebo simulation already has a map of that area to make the robot move around. In this case, the cartographer_slam package has been used to create a map of the environment.
The image below is what we are talking about when we say we already have a map of the environment:
Starbots Coffee Cartographer Map for Open-RMF
If you want to see that image of the map, it is available in the following path in the rosject:
~/ros2_ws/src/starbots_rmf/maps/starbots_sim.png
In order to download that file, you can just use the IDE (Code Editor) for that. If you don’t know how to open it, please check the image below:
Open the IDE – Code EditorAfter opening the Code Editor, just right-click on ~/ros2_ws/src/starbots_rmf/maps/starbots_sim.png, and then click Download.
Bear in mind that the Cartographer Slam package generates PGM files. We used a tool to convert the PGM files to PNG (image format).
Starting the Traffic Editor
Now that the basic introductions have been made, let’s start with the Traffic Editor. For that, you can open a second terminal and type the following command:
traffic-editor
After a few seconds, you should have it open (a new window should pop up).
To create a new map, just click Buidling -> New.
How to create a map for Robot Fleet Management Open-RMF -Building New
To make things simpler, you can save the map in the same location as the existing maps:
/home/user/ros2_ws/src/starbots_rmf/maps/
You can name the map “test” and click the save button.
Traffic Editor – Creating a new level
Now that we have a blank map of the building in the Traffic Editor, let’s create a new level. Let’s name it L1 (level 1) and let’s select the /home/user/ros2_ws/src/starbots_rmf/maps/starbots_sim.png map that we mentioned earlier. For that, let’s click the Add button, then click Find to select the map, as we can see in the image below:
Open-RMF Traffic Editor – Adding a new level
Traffic Editor – Creating a new lane
After the new level has been created, we can now create a new lane that specifies the paths that the robot can move. The robot will be able to move only in those areas. For that, click New Lane, and by clicking in different areas of the map, draw a lane where the robot can move:
Open-RMF Traffic Editor – Adding a new lane
Traffic Editor – Naming the spots
After drawing the lane in the previous image, you see that we have some small circles that form the intersections, and we have them also at the beginning and at the end of the lane we draw.
When we click on any of these spots, we see some properties on the right side. Please click in each circle spot and name them, like start, end,kitchen, etc by entering the name in the name input.
By selecting the green lines, you can also define if the movement is bidirectional or not, for example.
You can have as many lanes as you want, but you have to make sure they are somehow connected if you want the robot to move the whole area.
Now, to make sure your changes will not be lost, just click Building -> Save.
After hitting Save, you should see all the information related to the map at:
We expect everything to finish successfully. Among other output messages, the following message is expected:
# ...
Generating Lane Graphs in Generating Lane Graphs in /home/user/ros2_ws/build/starbots_rmf/maps/test/nav_graphs/
# ...
The thing that most interests us here is the following path:
/home/user/ros2_ws/build/starbots_rmf/maps/test/
If we check the content of that directory, we will find a test.world file (because our Building was called test).
ls /home/user/ros2_ws/build/starbots_rmf/maps/test/
ls /home/user/ros2_ws/build/starbots_rmf/maps/test/nav_graphs/
If we check /home/user/ros2_ws/build/starbots_rmf/maps/test/nav_graphs/, we will find a file named 0.yaml, which is the main element we need to get started with Open-RMF map.
Changing the launch file to open our newly generated map
Using the code editor, please open the following file:
now we can launch the simulation again in the first terminal (Please remember to terminate the simulation that was launched previously in the first terminal):
ros2 launch starbots_rmf rmf_schedule.launch.xml
If everything worked perfectly, you should now see an RViz window with the map ready for Open-RMF to use it. If we had setup our robots correctly, they should appear on top of the map:
How to create map for Robot Fleet Management Open-RMF generated map on RViz
Congratulations. You just learned how to create a map to be used by Open-RMF.
We hope this post was really helpful to you. If you want a live version of this post with more details, please check the video in the next section.
Youtube video
So this is the post for today. Remember that we have the live version of this post on YouTube. If you liked the content, please consider subscribing to our youtube channel. We are publishing new content ~every day.
Keep pushing your ROS Learning.
Related Courses & Training
If you want to learn more about ROS and ROS2, we recommend the following courses:
ROS2 parameters are great for configurable nodes that you can adapt to your robot configuration simply by changing a configuration file or a launch file. However, if we just implemented the basics you will have to re-run your node each time you change a parameter. You can’t change the parameter on-the-fly and have it updated in the robot. But by adding a callback function that updates the variables in our code, it is possible to do a live parameter update while a program is running, removing the need for a tedious node restart. Learn how to do it in this post.
ROS Inside!
ROS Inside
Before anything else, if you want to use the logo above on your own robot or computer, feel free to download it and attach it to your robot. It is really free. Find it in the link below:
In order to follow this tutorial, we need to have ROS2 installed in our system, and ideally a ros2_ws (ROS2 Workspace). To make your life easier, we have already prepared a rosject with a simulation for that: https://app.theconstructsim.com/l/53e75e28/.
You can download the rosject on your own computer if you want to work locally, but just by copying the rosject (clicking the link), you will have a setup already prepared for you.
After the rosject has been successfully copied to your own area, you should see a Run button. Just click that button to launch the rosject (below you have a rosject example).
Learn how to enable live parameter updates (C++) – Run rosject (example of the RUN button)
After pressing the Run button, you should have the rosject loaded. Now, let’s head to the next section to get some real practice.
Starting the simulation
After having opened the rosject, let’s start a simulation. For that, let’s open a terminal by clicking the Open a new terminal button.
Open a new Terminal
Once inside the terminal, let’s run the commands below:
If everything went well, you should have a simulation loaded and opened automatically in a few seconds. The simulation will open from a top view, but you can use the mouse to move the simulation to a different perspective.
How to enable live parameter updates (C++)
Understanding the problem
Below is an example node in which we have only implemented the barebone basics of parameters in ROS2.
Let’s see it in action and see how it behaves, especially when we update its parameter values.
In a second terminal, let’s run the node for Obstacle Avoidance.
source ~/ros2_ws/install/setup.bash
ros2 run rule_based_obstacle_avoidance obstacle_avoidance
If you watch the simulation for a while, you will see that when the robot detects the wall, it rotates and moves forward until it detects another wall, and repeats the process.
The node name is obstacle_avoidance_node (you can check it in a third terminal by running: ros2 node list)
Now, let’s list the parameters of the node in a third terminal:
Now, still in the third terminal, let’s check the value of the safety_distance parameter:
ros2 param get /obstacle_avoidance_node safety_distance
The output we should have got should be the following:
Double value is: 1.5
Now, let’s set the parameter to a new value:
ros2 param set /obstacle_avoidance_node safety_distance 1.0
The expected output is:
Set parameter successful
Ok, so far so good. But with the new value, we expect the robot to get closer to the wall before turning around because now the safe distance was set from 1.5 meters to 1.0. The problem is that the robot is not considering the new value that we just set.
We can follow the same idea to try to make the robot move faster. Let’s check the current velocity of the robot:
ros2 param get /obstacle_avoidance_node linear_x_velocity
The output we should have got should be the following:
Double value is: 0.2
If we increase the speed:
ros2 param set /obstacle_avoidance_node linear_x_velocity 0.5
The expected output is:
Set parameter successful
The parameter was reported as successfully set, yet the robot does not move faster, because it still uses the value loaded when the node started.
In the current code, parameter values are fixed. As such, every time a parameter value changes, the parameter value in the code stays the same even though you may have expected it to update based on the latest value set.
In order to solve this, we must add a parameter callback function to your code so that the variable in the code gets the freshest data.
Before moving to the next section, please kill the simulation and all nodes running by pressing Ctrl+C on all terminals.
Solution: Add a parameter callback method
Alright, have you closed all programs by pressing CTRL+C on all terminals?
If you check around line 45 on that file, you will find the “private:” section, where we define the private variables of our class, something like the following:
Now, above that “private:” section, around line 38, let’s add the following code to instantiate a ParameterEventHandler, providing the current ROS node to use to create the required subscriptions:
Below the param_subscriber_ we have to set a callback method, in this case, a lambda function:
// Set a callback for this node's parameter, "linear_x_velocity"
auto callback_linear_x = [this](const rclcpp::Parameter &p) {
RCLCPP_INFO(this->get_logger(),
"callback_linear_x: Received an update to parameter \"%s\" "
"of type %s: \"%f\"",
p.get_name().c_str(), p.get_type_name().c_str(),
p.as_double());
linear_x_velocity_ = p.as_double();
};
Then we set “callback_linear_x” as the callback to invoke whenever linear_x_velocity is updated. We store the handle that is returned by “add_parameter_callback“; otherwise, the callback will not be properly registered.
Now that our package has been rebuilt and sourced, let’s launch the simulation again:
ros2 launch neo_simulation2 simulation.launch.py
The simulation should have been opened just like before, but now we will see the parameters affecting the simulation in “real-time”.
Before changing the parameters, let’s also launch the Obstacle Avoidance node, just like before, using the second terminal:
ros2 run rule_based_obstacle_avoidance obstacle_avoidance
You should see the robot approaching the wall, and turning around when getting close to it.
Changing the x velocity using ROS 2 Parameters
Ok, now that the robot is moving, let’s retrieve again the current value of the linear x velocity using the third terminal:
ros2 param get /obstacle_avoidance_node linear_x_velocity
Just like before, the expected output is:
Double value is: 0.2
Now let’s change that value:
ros2 param set /obstacle_avoidance_node linear_x_velocity 1.0
We expect a successful output:
Set parameter successful
If you look at the simulation now, you should see that when the robot is moving forward (not turning around), it moves really faster. So, as we can see, we are now able to make ROS2 Parameters be reflected “instantly”.
This opens up really many different possibilities.
We hope this post was really helpful to you. If you want a live version of this post with more details, please check the video in the next section.
Youtube video
So this is the post for today. Remember that we have the live version of this post on YouTube. If you liked the content, please consider subscribing to our youtube channel. We are publishing new content ~every day.
Keep pushing your ROS Learning.
Related Courses & Training
If you want to learn more about ROS and ROS2, we recommend the following courses:
In this post, you will learn how to create ros2 XML launch files. You’ll discover how ros2 XML launch files are similar to and different from their ros1 counterparts.
Step 1: Get a Copy of the ROS package containing the code used in the post
Click here to copy the project. It would be copied to your cloud account at The Construct. That done, open the project using the Run button. This might take a few moments, please be patient.
PS: If you don’t have an account on the The Construct, you would need to create one. Once you create an account or log in, you will be able to follow the steps to read and write parameters in ros1 and ros2.
You might also want to try this on a local PC if you have ROS installed. In that case you need to read on and duplicate the source code of the package in your own local workspace. However, please note that we cannot support local PCs and you will have to fix any errors you run into on your own.
Step 2: Explore the source code using the IDE
Open the IDE by clicking on the icon as shown above. You should now see something similar to the image below:
The main file we will work with in this post is the one highlighted in red in the image above:
Double-click on the file in the IDE to open and study the contents. We will discuss this file in the following steps.
Step 3: Understand how to create ros2 XML launch files
Wait first! I thought ros2 launch files are only written in Python! Yes, Python is one of the options when writing ros2 launch files; we can also use XML files, especially if we are writing simple launch files that do not need to leverage Python’s powerful API.
On line 2, we define an argument (variable) use_sim_time with a default value of true.
On line 3, we include another launch file, turtlebot3_world.launch.py for launching the TurtleBot3 world. The launch file can be found in the turtlebot3_gazebo package.
On line 4, we pass a required argument use_sim_time to the included launch file, assigning it the value of the use_sim_time defined on line 2.
On line 6, we define a node to be started by the launch file. This node can be found in the package patrol_action_server, the node executable is patrol_action_server_exe and the name of the node would appear as patrol_action_server.
In short, this launch file launches the TurtleBot3 world and starts the Patrol action server. The same launch file can be written in Python, but this XML looks simpler and easier to understand. And it does all we want it to do, and we can even include Python-based launch files!
Step 4: Understand how ros2 XML launch files are similar to/different from ros1 XML launch files
If you are familiar with ros1 launch files, you should already notice some similarities:
The same <launch> tag.
Similar <arg> tag.
Familiar <include> tag.
Similar <node> tag.
Now if we were writing the same launch file in ros1, it would be something like this (PS: we can’t include ros2 launch file in a ros1 launch file in reality):
Did you like this post? Do you have any questions about how to read and write parameters in ros1 and ros2? Whatever the case, please leave a comment on the comments section below, so we can interact and learn from each other.
If you want to learn about other ROS topics, please let us know in the comments area and we will do a video or post about it.
In this post, you will learn how to read and write parameters in ros1 and ros2, using C++ nodes. You will see the slight differences in the ros1 and ros2 nodes and parameter files.
Step 1: Get a Copy of the ROS package containing the code used in the post
Click here to copy the project. It would be copied to your cloud account at The Construct. That done, open the project using the Run button. This might take a few moments, please be patient.
PS: If you don’t have an account on the The Construct, you would need to create one. Once you create an account or log in, you will be able to follow the steps to read and write parameters in ros1 and ros2.
You might also want to try this on a local PC if you have ROS installed. In that case you need to read on and duplicate the source code of the package in your own local workspace. However, please note that we cannot support local PCs and you will have to fix any errors you run into on your own.
Step 2: Explore the source code using the IDE
Open the IDE by clicking on the icon as shown above. You should now see something similar to the image below:
The six main files we will work with in this post are highlighted in red in the image above. These files are:
Double-click on each of the files in the IDE to open and study the contents. We will examine some of these files in the following steps.
Step 3: Understand how to read and write (load) parameters in ROS1
Now it’s time to see how to read and write parameters in ros1, working in the ros1 workspace.
Open a web shell and run the following commands:
cd ~/catkin_ws
source /opt/ros/noetic/setup.bash
source devel/setup.bash
roscore
The code block above changes to the ros1 workspace, sources it, and then starts the roscore (needed for ros1). Now let’s see a list of the current ros1 parameters available. Open another web shell and type the following:
But wait…are we getting the parameters in the YAML file (catkin_ws/src/yaml_parameters_ros1/config/params_demo_ros1.yaml) and their correct values? Let’s see what’s the in there!
Gosh, we are not getting these parameters nor their values, and you probably know why! So far we have been reading the parameters but have loaded them. Now let’s get that done: enter the launch file catkin_ws/src/yaml_parameters_ros1/launch/ros1_params_cpp_demo.launch.
Can you spot the differences between the formal and the latter outputs of these commands? Sure you can! So, well, that’s how to read and load parameter in ros1!
Step 4: Understand how to read and write (load) parameters in ROS2
Now let’s change to the ros2 workspace.
cd ~/ros2_ws
source /opt/ros/foxy/setup.bash
source install/setup.bash
In ros2 we need to have a node running before we can check for parameters, because there is no parameter server in ros2. Let’s try running the node then. The logic behind this node is contained in the ros2_ws/src/yaml_parameters/src/yaml_params_ros2.cpp file:
#include <rclcpp/rclcpp.hpp>
class MainNode : public rclcpp::Node {
public:
MainNode() : rclcpp::Node("node", rclcpp::NodeOptions()) {
// example: declare parameters, default value given
declare_parameter("param0", 1);
declare_parameter("param1", 0.1);
declare_parameter("param2", "default");
declare_parameter("param3.weight", 1);
declare_parameter("param3.name", "default");
declare_parameter("param4", false);
// example: declare a variable when declaring a parameter
declare_parameter("param5", std::vector<bool>(3, false));
declare_parameter("param6", std::vector<int64_t>(4, 1));
declare_parameter("param7", std::vector<double>(4, 0.1));
declare_parameter("param8", std::vector<std::string>(5, "default"));
// Get parameter values one by one
auto p0 = get_parameter("param0").as_int();
auto p1 = get_parameter("param1").as_double();
auto p2 = get_parameter("param2").as_string();
auto p3weight = get_parameter("param3.weight").as_int();
auto p3name = get_parameter("param3.name").as_string();
auto p4 = get_parameter("param4").as_bool();
auto p5 = get_parameter("param5").as_bool_array();
auto p6 = get_parameter("param6").as_integer_array();
auto p7 = get_parameter("param7").as_double_array();
auto p8 = get_parameter("param8").as_string_array();
// Print parameters
RCLCPP_INFO(get_logger(), "Integer parameter: %ld", p0);
RCLCPP_INFO(get_logger(), "Double parameter: %f", p1);
RCLCPP_INFO(get_logger(), "String parameter: %s", p2.c_str());
RCLCPP_INFO(get_logger(), "Nested integer parameter: %ld", p3weight);
RCLCPP_INFO(get_logger(), "Nested string parameter: %s", p3name.c_str());
RCLCPP_INFO(get_logger(), "Boolean parameter: %d", p4);
RCLCPP_INFO(get_logger(), "Boolean vector parameter [0]: %d",
static_cast<int>(p5[0]));
RCLCPP_INFO(get_logger(), "Integer vector parameter [0]: %d",
static_cast<int>(p6[0]));
RCLCPP_INFO(get_logger(), "Double vector parameter [0]: %f",
static_cast<double>(p7[0]));
RCLCPP_INFO(get_logger(), "String vector parameter [0]: %s", p8[0].c_str());
}
};
int main(int argc, char **argv) {
rclcpp::init(argc, argv);
rclcpp::spin(std::make_shared<MainNode>());
rclcpp::shutdown();
return 0;
}
No, we are not :(. But not to worry, the launch file ros2_ws/src/yaml_parameters/launch/yaml_parameters.launch.py comes to the rescue! Let’s examine its content.
#!/usr/bin/env python3
import os
from launch import LaunchDescription
from launch_ros.actions import Node
from ament_index_python.packages import get_package_share_directory
def generate_launch_description():
return LaunchDescription([
Node(
package='yaml_parameters',
executable='main_node',
name='parameter_types_example',
parameters=[os.path.join(
get_package_share_directory('yaml_parameters'),
'config', 'params_demo_ros2.yaml')],
output='screen'),
])
Oh my, it’s a Python! Let’s set it loose and see what happens! Stop the currently running program with Ctrl + C and run the following in its place and check that your output is similar.
The launch file simply loads the parameters in the YAML file and also runs the node we run earlier.
Well, that’s it!
Step 5: Check your learning
Do you understand how to read and write parameters in ros1 and ros2, using C++ nodes?
Did you notice the slight differences in the format of the YAML files for ros1 and ros2?
Did you notice that you the ros2 parameters are tied to specific nodes vs existing in a parameter server in ros1?
If you didn’t get any of the points above, please go over the post again, more carefully this time.
Extra Step: Watch the video to understand how to read and write parameters in ros1 and ros2
Here you go:
Feedback
Did you like this post? Do you have any questions about how to read and write parameters in ros1 and ros2? Whatever the case, please leave a comment on the comments section below, so we can interact and learn from each other.
If you want to learn about other ROS topics, please let us know in the comments area and we will do a video or post about it.
In this post, we will see how to program drones using ROS2. Perhaps you have programmed drones using ROS1, found that programming drones using ROS2 is not as straightforward, and have been wondering, “how the heck do you program drones using ROS2?” You have come to the right place!
Step 1: Grab the required source code
You can program drones using ROS2 on your local PC by following the instructions in this repository step by step. However if you use the rosject you copied below, we have already done most of the heavy lifting for you and you just need to run a few commands to get your drone flying!
Click here to get your own copy of the project (PS: If you don’t have an account on the ROS Development Studio, you would need to create one. Once you create an account or log in, we will copy the project to your workspace).
That done, open the project using the Run button. This might take a few moments, please be patient.
Step 2: Understand the basic components
The ros2 drone system used in this post consists of three main parts:
A ros2 simulation containing the simulation and the plugin that connects to the rest of the system.
cd ~/ros2_ws
source install/setup.bash
ros2 launch ls2n_drone_simulation single_drone_trajectory_sitl.launch.py
By this time, you should have the simulation running. Open the Gazebo app (if not opened automatically) to see it. Right click on the drone model on the left pane and select “Follow” to keep seeing the drone when it takes off.
Now, open another web shell and start the PX-4 system:
cd ~
cd px4-autopilot/Tools/
./gazebo_sitl_multiple_run_only_px4.sh
Finally, start the ground control system in another web shell:
user:~$ cd squashfs-root/
user:~/squashfs-root$ ./AppRun
The ground control GUI should load shortly. Open the Graphical Tools app to see it, if not opened automatically:
Time to take off the drone!
Ensure the top-left corner of the controller says “Ready to Fly” in a green background.
Click the Takeoff button on the top left.
In the bottom middle, drag the slider to the right to confirm takeoff. You should see something similar to the image below.
If the takeoff does not work, repeat 2 & 3.
After takeoff, the button changes to “Land”. Use it to land the drone.
Step 4: Consolidate your learning
Do you understand how to program drones using ROS2 after watching the video? If not, please review the material again and perhaps go over the video again. Let us know any problems you are seeing in the comments.
Extra Step: Watch the video for the sights and sounds version of how to program drones using ROS2
Did you like this post? Do you have any questions about the explanations? Whatever the case, please leave a comment on the comments section below, so we can interact and learn from each other. If you want to learn about other ROS2 topics, please let us know in the comments area and we will do a video or post about it.
PS: If you don’t have an account on the ROS Development Studio, you would need to create one. Once you create an account or log in, you will be able to follow the steps to setup MoveIt! for a Robot Arm. You will also get access to the robot arm in our remote real robot lab, among other features.
You might also want to try this on a local PC if you have ROS installed. However, please note that we cannot support local PCs and you will have to fix any errors you run into on your own.
Step 2: Watch the video to understand how to setup MoveIt! for a Robot Arm
Main point: you just need to have the URDF file for the robot arm and you feed that into MoveIt!
Here you go:
Step 3: Consolidate your learning
Do you understand how to setup MoveIt! for a Robot Arm? If not, have you gone over the video again? If you have any problems with setting up MoveIt! for the arm, please let us know in the comments.
Did you like this post? Do you have any questions about how to setup MoveIt! for a Robot Arm? Whatever the case, please leave a comment on the comments section below, so we can interact and learn from each other.
If you want to learn about other ROS topics, please let us know in the comments area and we will do a video or post about it.