7. Launch files and parameters

A real robot runs a dozen nodes. Starting each in its own terminal does not scale. This topic fixes that.

Parameters — settings outside the code

In topic 6 the speed 0.2 was hard-coded. Make it a parameter instead:

class SpeedSender(Node):
    def __init__(self):
        super().__init__('speed_sender')
        # declare with a default
        self.declare_parameter('speed', 0.2)
        self.pub = self.create_publisher(Twist, '/cmd_vel', 10)
        self.timer = self.create_timer(0.1, self.tick)

    def tick(self):
        # read on every use, so it can change while running
        speed = self.get_parameter('speed').value
        msg = Twist()
        msg.linear.x = speed
        self.pub.publish(msg)

Set it when starting:

ros2 run my_robot speed_sender --ros-args -p speed:=0.1

Or change it while running:

ros2 param set /speed_sender speed 0.05

Tip

Read the parameter every time you use it, not once in __init__.

If you read it once and keep the variable, ros2 param set has no visible effect — the value really does change, but your code never reads it again.

This bites people constantly while tuning.

Move settings into YAML

As settings multiply, put them in config/robot.yaml:

speed_sender:
  ros__parameters:
    speed: 0.15

wheel_driver:
  ros__parameters:
    port: /dev/ttyUSB0
    baud: 115200

Warning

🔴 This two-level structure has to be exact — node name outside, ros__parameters inside, with two underscores between ros and parameters.

Get it wrong and ROS 2 loads the file without an error but uses none of the values. The node silently falls back to its defaults.

Always confirm with ros2 param get after starting the node.

The outer name must match the node name set in super().__init__('speed_sender') — not the file name, not the package name.

Launch files — start many nodes at once

Create ~/ros2_ws/src/my_robot/launch/robot.launch.py:

import os
from ament_index_python.packages import get_package_share_directory
from launch import LaunchDescription
from launch_ros.actions import Node


def generate_launch_description():
    config = os.path.join(
        get_package_share_directory('my_robot'),
        'config', 'robot.yaml')

    return LaunchDescription([
        Node(
            package='my_robot',
            executable='speed_sender',
            name='speed_sender',       # must match the YAML key
            parameters=[config],
            output='screen',
        ),
        Node(
            package='my_robot',
            executable='speed_watcher',
            name='speed_watcher',
            output='screen',
        ),
    ])

Tell setup.py to install those files

Danger

🔴 Skip this and you get a file not found that is hard to trace.

The launch and YAML files live in src/, but at run time the system looks in install/. If you do not say to copy them, they are not there.

Edit setup.py:

import os
from glob import glob

setup(
    # ...
    data_files=[
        ('share/ament_index/resource_index/packages',
            ['resource/' + package_name]),
        ('share/' + package_name, ['package.xml']),
        (os.path.join('share', package_name, 'launch'),
            glob('launch/*.launch.py')),
        (os.path.join('share', package_name, 'config'),
            glob('config/*.yaml')),
    ],
)

Note

Changing setup.py always requires a rebuild, even with --symlink-install. That flag only helps with .py files already registered — not with new files or a changed install list.

Run it

cd ~/ros2_ws
colcon build --symlink-install --packages-select my_robot
source install/setup.bash
ros2 launch my_robot robot.launch.py

Both nodes start from one command, and one Ctrl+C stops them all.

You can override a value at launch:

ros2 launch my_robot robot.launch.py speed:=0.05

Confirm the values arrived

ros2 param get /speed_sender speed

Important

Do this every time you edit the YAML. If you get 0.2 (the code default) while the YAML says 0.15, the file was not loaded. Three causes, in order of how often they happen:

  1. The node name in the YAML does not match name= in the launch file

  2. config/*.yaml is missing from data_files, or you did not rebuild

  3. ros__parameters is misspelled (one underscore)


Previous: 6. Publisher and subscriber · Next: 8. tf2 — coordinate frames