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:
The node name in the YAML does not match
name=in the launch fileconfig/*.yamlis missing fromdata_files, or you did not rebuildros__parametersis misspelled (one underscore)
Previous: 6. Publisher and subscriber · Next: 8. tf2 — coordinate frames