RobotForge
Published·~13 min

Parameters, namespaces, and remapping

The runtime configuration system that keeps your code portable across robots. Declare a parameter once; set it from launch, CLI, YAML, or dynamic reconfigure. Remap topics to fit any neighbor.

by RobotForge
#ros2#parameters#configuration

A ROS 2 node hardcoding its config is a node that runs on exactly one robot. Parameters and remapping are how you write a node once and deploy it across robots, simulators, and generations of hardware. Understanding them turns "I have to fork this code" into "I'll change a YAML file."

Parameters: the configuration system

A parameter is a named, typed value owned by a node, settable at launch and (mostly) at runtime. Unlike topic data, parameters change rarely — wheel radius, control gains, sensor topic name. The framework gives you discoverability, type checking, and changeability for free.

Declare it in the node

class MyNode(Node):
    def __init__(self):
        super().__init__('my_node')
        self.declare_parameter('wheel_radius', 0.06)
        self.declare_parameter('cmd_topic', '/cmd_vel')
        self.declare_parameter('use_imu', True)

        self.r = self.get_parameter('wheel_radius').value
        self.cmd_topic = self.get_parameter('cmd_topic').value

Three parameters declared with default values. ROS 2 enforces declaration — undeclared get_parameter calls fail. (Unless you set allow_undeclared_parameters=True, which you should not.)

Set it at launch

Three options, in order of how they're used:

1. YAML file (preferred for production):

# config/my_robot.yaml
my_node:
  ros__parameters:
    wheel_radius: 0.058
    cmd_topic: /cmd_vel_safe
    use_imu: true
Node(
    package='my_robot', executable='my_node',
    parameters=[PathJoinSubstitution([FindPackageShare('my_robot'), 'config', 'my_robot.yaml'])],
)

2. Inline in launch (for one-offs):

Node(
    package='my_robot', executable='my_node',
    parameters=[{'wheel_radius': 0.058, 'use_imu': False}],
)

3. Command-line (for testing):

ros2 run my_robot my_node --ros-args -p wheel_radius:=0.058

Read or change at runtime

ros2 param list /my_node
ros2 param get /my_node wheel_radius
ros2 param set /my_node wheel_radius 0.062
ros2 param dump /my_node    # snapshot current values

Whether the change takes effect depends on whether the node has registered a parameter callback. By default, parameters can be set but the node won't re-read them. Add a callback for dynamic reconfigure:

self.add_on_set_parameters_callback(self.on_param_change)

def on_param_change(self, params):
    for p in params:
        if p.name == 'wheel_radius' and p.value > 0:
            self.r = p.value
            self.get_logger().info(f'wheel_radius updated to {self.r}')
    return SetParametersResult(successful=True)

Namespaces: organizing nodes by group

A namespace prefixes a node's name and all its topics, services, parameters. Useful when running multiple instances of the same node (e.g., one camera node per camera).

Node(
    package='cam_driver', executable='cam_node',
    namespace='left_cam',
)
Node(
    package='cam_driver', executable='cam_node',
    namespace='right_cam',
)

The two camera nodes now expose /left_cam/image_raw and /right_cam/image_raw instead of clashing on /image_raw. Their parameters are /left_cam/cam_node and /right_cam/cam_node.

Inside a node, topics declared with relative names (image_raw, no leading /) automatically pick up the namespace. Topics declared with absolute names (/image_raw) ignore it. The default-relative behavior is what makes namespaces work without the node code knowing.

Remapping: rewiring topics without code changes

You have a node that publishes to /cmd_vel. Your robot's base driver listens on /diff_drive_controller/cmd_vel_unstamped. Two options: change the node, or remap.

Node(
    package='nav2_controller', executable='controller_server',
    remappings=[('cmd_vel', '/diff_drive_controller/cmd_vel_unstamped')],
)

The node's internal name cmd_vel now resolves externally to /diff_drive_controller/cmd_vel_unstamped. The node code doesn't change.

Remapping syntax: internal_name:=external_name. Works on topics, services, and actions.

From the command line:

ros2 run nav2_controller controller_server --ros-args -r cmd_vel:=/diff_drive_controller/cmd_vel_unstamped

The four-way table for "where do I configure this?"

Concern Tool
Numeric / typed valueParameter
Topic name doesn't matchRemapping
Multiple instances of same nodeNamespace
Need to change at runtimeParameter + callback

Common gotchas

  • Re-declaring causes errors. declare_parameter twice on the same name throws. Use has_parameter if conditional.
  • YAML namespace mismatch. The YAML file's top key must match the fully-qualified node name. my_node vs /left_cam/my_node matters.
  • Topic remapping doesn't follow into wrappers. If your node spawns sub-nodes, they don't inherit remappings unless you set them up.
  • Wildcard YAML: "/**": as the top key applies to every node — useful for shared params like use_sim_time.
  • Param names use slashes: "controller.gains.kp" is a flat name with dots; only namespaces use slashes.

Patterns that scale

  • One YAML per role: config/sim.yaml, config/real.yaml, config/calib.yaml. Pick at launch time.
  • Inherit common values: import a common YAML, override specific nodes. YamlIncludeFile in launch files.
  • Validate at startup: range-check critical parameters in the constructor; fail loudly if invalid.
  • Log loaded values: print every parameter you read on startup. Saves "is the YAML even being read?" debugging later.

Why the discipline pays off

Ninety percent of "this works on my machine" robotics bugs are unconfigured parameters or wrong topic names. Force every node to declare every parameter; load every parameter from a YAML; remap topics rather than rename them in code. Once this is the habit, integrating someone else's node into your robot becomes a 30-minute YAML exercise instead of a fork.

Exercise

Take any small ROS 2 node from a tutorial. Replace every hardcoded value with a parameter. Replace every hardcoded topic name with a relative name. Write a YAML file. Launch with the YAML; verify it works. Now copy the launch file, change the YAML to a different config, launch a second instance with a different namespace. Two configurations of the same node, no code change.

Next

Nav2 — the mobile-navigation stack that uses every parameter and remapping idiom in this lesson.

Comments

    Sign in to post a comment.