ROS Parameters and the dynamic_reconfigure Package in ROS Noetic

What are ROS Parameters?

Parameters are globally available values such as integers, floats, strings or booleans. Any node in ROS can access and modify these values. You should use parameters for data that you do not expect to change a lot over time.

Nodes (i.e. programs in C++/Python that exist inside ROS packages), can use parameters during runtime.

Parameters are stored inside a centralized Parameter Server. The Parameter Server is like a dictionary that contains the name of the parameter and the corresponding value of the parameter.

The Parameter Server is part of the ROS Master, so it launches automatically when you launch either roscore or roslaunch.

You can learn more about the Parameter Server on the ROS website. There is also a quick tutorial on ROS parameters here if you’d like to dive deep.

Let’s look at some basic commands now.

Most Common Parameter Commands

To get a list of the currently active parameters on your system, open a new terminal window, and type:

roscore
rosparam list

Here we see the name of the active parameters.

1-name-of-active-parametersJPG

If you want to see the value of the parameter, you use this syntax:

rosparam get <name_of_parameter>

For example, type:

rosparam get /rosdistro
2-name-of-ros-distroJPG

We see that the value of the /rosdistro (i.e. “ROS distribution”) is noetic, which is exactly what we would expect.

If you want to see the values of all parameters at once, you type this command:

rosparam get /

To assign a value to a parameter, you use this command.

rosparam set <name_of_parameter> <desired_value>

Followed by this command to complete the update of the parameter value.

rosservice call /clear

How to Update Parameters Using the dynamic_reconfigure Package

Imagine we have two nodes written in either Python or C++. One node sets the value of a particular parameter on the Parameter Server. The other node uses the value of that parameter to perform some computation. This latter node typically reads the value of the parameter only when the node is first launched. How will this latter node know if the value of the parameter has changed during runtime?

Fortunately, ROS has an efficient solution for this. To update the value of a parameter dynamically (i.e. “on-the-fly”) while a node is running, we can use the dynamic_reconfigure package. This package enables us to update parameters on the Parameter Server at runtime and push that change out to a given active node that needs the most current value of that parameter.

This is cool because it means we don’t have to restart a node in order for it to recognize the change in the value of a parameter.

A common use case for the dynamic_reconfigure package is when you’ve built a control system that needs to precisely control the speed of a motor. You might need to continuously tune the control parameters to make the robot move how you want it to move. Doing so requires continuous updates. The dynamic_reconfigure package provides an efficient means of doing this.

Let’s take a look at an example of how to use the dynamic_reconfigure package. The official ROS tutorial for this package is here (for both C++ and Python). We’ll run through the process below for C++.

How to Write a .cfg File

First, let’s create a package called parameter_server_basics.

In a new terminal window, move to the src (source) folder of your workspace.

cd ~/catkin_ws/src

Now create the package (everything below goes on one line in the terminal)

catkin_create_pkg parameter_server_basics std_msgs roscpp rospy dynamic_reconfigure

Now, let’s build the package.

cd ~/catkin_ws/
catkin_make

Now, move inside the package.

roscd parameter_server_basics

Create a cfg directory. This is where all the cfg files will be.

mkdir cfg

Move inside the cfg directory you just created.

cd cfg

Now let’s create a file named parameter_server_basics.cfg.

gedit parameter_server_basics.cfg

Write the following code:

#!/usr/bin/env python3

PACKAGE = "parameter_server_basics"

from dynamic_reconfigure.parameter_generator_catkin import *

gen = ParameterGenerator()

gen.add("int_param",    int_t,    0, "An Integer parameter", 50,  0, 100)
gen.add("double_param", double_t, 0, "A double parameter",    .5, 0,   1)
gen.add("str_param",    str_t,    0, "A string parameter",  "Hello World")
gen.add("bool_param",   bool_t,   0, "A Boolean parameter",  True)

size_enum = gen.enum([ gen.const("Small",      int_t, 0, "A small constant"),
                       gen.const("Medium",     int_t, 1, "A medium constant"),
                       gen.const("Large",      int_t, 2, "A large constant"),
                       gen.const("ExtraLarge", int_t, 3, "An extra large constant")],
                     "An enum to set size")

gen.add("size", int_t, 0, "A size parameter which is edited via an enum", 1, 0, 3, edit_method=size_enum)

exit(gen.generate(PACKAGE, "parameter_server_basics", "parameter_server_"))

To understand what the code is all about, check out this post.

Save the file and close the editor.

Make the code executable:

chmod +x parameter_server_basics.cfg

Now go back to the directory of the package.

roscd parameter_server_basics

Open the CMakeLists.txt file.

gedit CMakeLists.txt

Add these lines to the lines just underneath the “find_package()” block:

#add dynamic reconfigure api
#find_package(catkin REQUIRED dynamic_reconfigure)
generate_dynamic_reconfigure_options(
  cfg/parameter_server_basics.cfg
  #...
)
3-under-find-package-blockJPG

Add these lines to the very bottom of the file.

# make sure configure headers are built before any node using them
add_dependencies(parameter_server_basics ${PROJECT_NAME}_gencfg)

Click Save and close the editor window.

How to Make a Node Dynamically Reconfigureable in C++

Now we need to create a node that uses the cfg file. We will create a node in C++, but you can also create a node using Python.

Go to your parameter_server_basics package.

roscd parameter_server_basics 

Go inside the src folder.

cd src

Open a new C++ file named 

parameter_server_basics.cpp

Add the code below into the file. For a detailed explanation of what is going on inside the code, check out this post.

#include <ros/ros.h>

#include <dynamic_reconfigure/server.h>
#include <parameter_server_basics/parameter_server_Config.h>

void callback(parameter_server_basics::parameter_server_Config &config, uint32_t level) {
  ROS_INFO("Reconfigure Request: %d %f %s %s %d", 
            config.int_param, config.double_param, 
            config.str_param.c_str(), 
            config.bool_param?"True":"False", 
            config.size);
}

int main(int argc, char **argv) {
  ros::init(argc, argv, "parameter_server_basics");

  dynamic_reconfigure::Server<parameter_server_basics::parameter_server_Config> server;
  dynamic_reconfigure::Server<parameter_server_basics::parameter_server_Config>::CallbackType f;

  f = boost::bind(&callback, _1, _2);
  server.setCallback(f);

  ROS_INFO("Spinning node");
  ros::spin();
  return 0;
}

Let’s edit the CMakeLists.txt file for the parameter_server_basics package.

Open a new terminal window, and type this command:

roscd parameter_server_basics
gedit CMakeLists.txt

Now add these lines to the bottom of the CMakeLists.txt file. Make sure the add_dependencies line you added in the last section is between add_executable… and target_link_libraries:

add_executable(parameter_server_basics src/parameter_server_basics.cpp)
target_link_libraries(parameter_server_basics ${catkin_LIBRARIES})
3b-is-between-codeJPG

Now save and close the CMakeLists.txt file.

Open a new terminal window, and type the following commands to build all the nodes in the parameter_server_basics package:

cd ~/catkin_ws
catkin_make 

If everything goes, well, here is the message you should see:

4-here-is-the-message-you-should-seeJPG

We need to modify the rqt_reconfigure node so that it runs with Python 3.

Open up a new terminal window, and type:

sudo ln -s /usr/bin/python3 /usr/bin/python

This will make a symbolic link from /usr/local/bin/python to /usr/bin/python3.

Now that everything is setup, let’s run the node and the Dynamic Reconfigure Graphical User Interface.

Open a new terminal window to launch ROS.

roscore

In a new terminal tab, type:

rosrun parameter_server_basics parameter_server_basics

In another terminal tab, type:

rosrun rqt_reconfigure rqt_reconfigure

Click on parameter_server_basics on the left-hand side.

Here is what you should see:

5-here-is-what-you-should-seeJPG

To modify the parameters, drag any of the sliders. You can also uncheck the boolean checkbox there.

Each time you make a change to one of the parameters, you’ll see the change printed out to the terminal window where you ran rosrun parameter_server_basics parameter_server_basics.

7-modify-parametersJPG

When you’re finished, type Ctrl + C on all terminal windows to shutdown ROS.

How to Find the Path of a Package in ROS Noetic

Software in ROS is organized into packages (and packages exist inside the catkin_ws folder, your catkin workspace). 

Each package might contain a mixture of code (e.g. ROS nodes), data, libraries, images, documentation, etc. Every program you write in ROS will need to be inside a package.

To find the path of a package, you use the rospack command. For example, let’s find the path of the turtlesim package, a pre-installed ROS package.

rospack find turtlesim

Here is the output:

1-here-is-the-outputJPG

The syntax is:

rospack find [package_name]