How to Manage Parameters in ROS 2 Using C++

👩🏻‍💻 Core Concepts, Practical Implementation, and CLI Tools

In ROS 2 development, parameter management is a fundamental capability for building flexible, configurable, and adaptive robotic systems. Any autonomous robot must be able to modify its behavior without recompilation: sensor frequencies, maximum speed, module activation, safety limits, and numerous other factors depend on values that must be adjustable at runtime.

ROS 2 provides a powerful distributed parameter server integrated directly inside each node. This design replaces the centralized approach of ROS 1, offering improved safety, predictability, and modularity—exactly what modern robotic systems demand.

In this article, we explore:

  • what parameters are and why they matter,

  • how to implement them in C++,

  • how to interact with them through ROS 2 CLI tools,

  • how to verify everything through a hands-on laboratory exercise.

Some theoretical concepts overlap with the earlier article “ROS 2 Lifecycle Node in C++”, but here the focus is exclusively on parameter management.

🤔 What Parameters Are and Why They Matter

A parameter is simply a value associated with a node, and it may represent numbers, booleans, strings, arrays, or structured data. Unlike internal variables, parameters are:

  • externally visible,

  • runtime-modifiable,

  • persistent within the node,

  • managed through validation callbacks,

  • declared explicitly.

This makes them ideal for configuring a robot without touching the source code.
In ROS 2, each node has its own parameter infrastructure, responsible for declaration, updates, and validation—removing the need for a global parameter server.

Compared to ROS 1, this approach increases isolation, predictability, and safety.

🏗️ Implementing Parameters in C++

Below is the complete code, followed by a block-by-block explanation.

</> Complete Code

				
					#include "rclcpp/rclcpp.hpp"

class SimpleParam : public rclcpp::Node
{
public:
  SimpleParam() : Node("simple_param_node")
  {
    this->declare_parameter<std::string>("my_param", "world");
    timer_ = this->create_wall_timer(
      std::chrono::seconds(1),
      std::bind(&SimpleParam::timer_callback, this));
  }

private:
  void timer_callback()
  {
    std::string my_param = this->get_parameter("my_param").as_string();
    RCLCPP_INFO(this->get_logger(), "Hello %s", my_param.c_str());
  }

  rclcpp::TimerBase::SharedPtr timer_;
};

int main(int argc, char *argv[])
{
  rclcpp::init(argc, argv);
  rclcpp::spin(std::make_shared<SimpleParam>());
  rclcpp::shutdown();
  return 0;
}

				
			

🧩 Breaking Down the Code

Library inclusion

				
					#include "rclcpp/rclcpp.hpp"

				
			

This imports the full ROS 2 C++ API, including tools for creating nodes, parameters, timers, and logging.

Node class definition

				
					class SimpleParam : public rclcpp::Node
{

				
			

We define a class inheriting from rclcpp::Node, enabling access to all node-level features such as timers and parameter handling.

Node constructor

				
					SimpleParam() : Node("simple_param_node")
{
    this->declare_parameter<std::string>("my_param", "world");
    timer_ = this->create_wall_timer(
      std::chrono::seconds(1),
      std::bind(&SimpleParam::timer_callback, this));
}

				
			

Two essential operations occur here:

Parameter declaration

				
					this->declare_parameter<std::string>("my_param", "world");

				
			

ROS 2 requires all parameters to be declared explicitly.
Here we declare "my_param" as a string with default value "world".

Timer creation

				
					create_wall_timer(...)

				
			

The node will execute timer_callback() every second, allowing us to print the updated value of the parameter.

Timer callback

				
					void timer_callback()
{
    std::string my_param = this->get_parameter("my_param").as_string();
    RCLCPP_INFO(this->get_logger(), "Hello %s", my_param.c_str());
}

				
			

The callback:

  1. retrieves the current value of "my_param"—even if updated dynamically via CLI;

  2. prints the value using the node logger.

Every time the parameter changes, the message updates automatically.

Main function

				
					int main(int argc, char *argv[])
{
  rclcpp::init(argc, argv);
  rclcpp::spin(std::make_shared<SimpleParam>());
  rclcpp::shutdown();
  return 0;
}

				
			

ROS 2 is initialized, the node is launched, and spin() keeps it active while listening for parameter updates and timer events.

🤖 Laboratory: Working with Parameters via ROS 2 CLI

Start the node:

				
					ros2 run my_pkg simple_param_node

				
			

List available parameters:

				
					ros2 param list

				
			

Read a parameter:

				
					ros2 param get /simple_param_node my_param

				
			

Update it dynamically:

				
					ros2 param set /simple_param_node my_param "ROS 2"

				
			

The node will now output:

				
					Hello ROS 2

				
			

all without recompiling or restarting the program.

This workflow shows how essential dynamic parameters are for real robots, where behavior must often change at runtime.

🎯 Conclusion

Parameters are one of the most powerful and flexible tools available in ROS 2. They allow nodes to be reconfigured at runtime, ensure predictable interactions, and enable both simple prototypes and full-scale robotic architectures.

In this article, you learned how parameters work, how to declare them, how to retrieve and update them in C++, and how to interact with them from the command line.

But this is only the beginning.
In real robot architectures, parameters become hierarchical, loaded from YAML files, and integrated into complex systems such as navigation, perception, motion planning, and controller tuning.

 

 

Want to learn more?

If you want to learn how to design and build professional robotic systems, check out our "Self Driving and ROS 2 - Learn by doing! Odometry & Control" course
DISCOUNT
es_ES

Discover BumperBot Kit

Assemble your robot and get started to learn Robotics!