A launch file is the difference between a robot that starts and a robot that starts the same way every time. Once a project has more than three nodes, typing commands into five terminals stops being a workflow. A launch file records the whole system: nodes, parameters, remaps, namespaces and order.
This tutorial covers ROS 2 Python launch files from the first node to arguments, includes and conditions, with the mistakes that silently start the wrong robot.
What a launch file replaces
| Without a launch file | With a launch file |
|---|---|
| Five terminals and a note on a whiteboard | One command, versioned in git |
| Parameters retyped or forgotten | Declared defaults, overridden per robot |
| Topic names patched by hand | Remaps recorded next to the nodes |
| Two robots collide on one topic | Namespaces keep them apart |
| Startup order left to luck | Event handlers and delays where needed |
The smallest useful launch file
A Python launch file returns a LaunchDescription containing actions. The most common action is a Node. Save this as bringup.launch.py inside a package’s launch folder.
from launch import LaunchDescription
from launch_ros.actions import Node
def generate_launch_description():
return LaunchDescription([
Node(
package='demo_nodes_cpp',
executable='talker',
name='talker',
output='screen',
),
Node(
package='demo_nodes_cpp',
executable='listener',
name='listener',
output='screen',
),
])Run it with ros2 launch my_package bringup.launch.py. The launch system starts both processes, prefixes their output with the node name and stops everything when you press Ctrl+C.
Arguments make one file serve many robots
Arguments turn a launch file into a template. Declare each one with a default, then read it with LaunchConfiguration. This is how the same file starts a simulation or a real robot, or two robots with different namespaces.
from launch import LaunchDescription
from launch.actions import DeclareLaunchArgument
from launch.substitutions import LaunchConfiguration
from launch_ros.actions import Node
def generate_launch_description():
use_sim_time = LaunchConfiguration('use_sim_time')
robot_ns = LaunchConfiguration('robot_ns')
return LaunchDescription([
DeclareLaunchArgument('use_sim_time', default_value='false'),
DeclareLaunchArgument('robot_ns', default_value='robot1'),
Node(
package='my_robot',
executable='controller',
namespace=robot_ns,
parameters=[{'use_sim_time': use_sim_time}],
output='screen',
),
])Override at run time with ros2 launch my_package bringup.launch.py use_sim_time:=true robot_ns:=robot2. A boolean argument passed as a string is a classic bug: launch substitutions are strings unless a node declares the parameter type. Declare parameter types in the node or use a YAML parameter file.
Parameters belong in YAML
Long parameter lists do not belong in Python. Put them in a YAML file and pass the path to the node. This keeps the launch file readable and lets you version tuning separately for simulation, lab and production.
my_robot:
ros__parameters:
wheel_radius: 0.05
wheel_separation: 0.32
max_speed: 0.6
use_sim_time: falseLoad it with parameters=['config/robot.yaml'] in the Node action, or with a ParameterFile substitution if the path is computed. The node name in the YAML must match the node name in the launch file, including any namespace.
Remaps and namespaces
A remap renames a topic, service or action at launch time. It is how you connect a generic driver to your robot’s naming convention without editing the driver. A namespace prefixes every name a node creates, which is how two identical robots share one ROS 2 graph.
Node(
package='my_robot',
executable='driver',
namespace='robot1',
remappings=[('/scan', 'lidar/scan'), ('/cmd_vel', 'cmd_vel')],
)Watch the leading slash. An absolute name like /scan ignores the namespace, while a relative name like scan becomes /robot1/scan. Mixing the two is the most common reason a node appears to publish nothing.
Include, conditions and order
Large systems compose launch files. Use IncludeLaunchDescription to pull in a driver or a navigation stack, and IfCondition or UnlessCondition to start parts only when an argument says so. A simulation launch file can include the same robot description as the hardware file, with a different controller.
ROS 2 starts actions in the order they appear, but it does not wait for one node to be ready before starting the next. If a node needs the clock or a transform before it can initialise, add a TimerAction delay or an event handler rather than assuming the order is enough.
XML and YAML launch files
ROS 2 also supports XML and YAML launch descriptions. They are easier for simple compositions and for people who prefer configuration to code. Python remains the most flexible option once you need conditions, computed paths or custom events. Pick one convention per repository and stay with it.
Debugging a launch file
ros2 launch my_package bringup.launch.py --show-argslists every declared argument and its default.--printshows the launch description without running it. Useful for checking substitutions.- Add
output='screen'to every node while debugging; the default log file hides the error you need. - Check the node list with
ros2 node listand the graph withros2 topic listafter startup. - Dump the running parameters with
ros2 param dump /node_nameto confirm the YAML actually loaded.
Errors you will meet
| Symptom | Cause | Fix |
|---|---|---|
| Node starts and immediately exits | Parameter type mismatch or missing file | Run the node directly to see the error |
| Two nodes cannot communicate | Namespace or remap mismatch | Echo the topic and compare fully qualified names |
| Parameters ignored | YAML node name does not match | Match the name and namespace exactly |
| Works in sim, fails on hardware | use_sim_time left true or false | Make it an argument with the right default |
| Launch finds no executable | Package not built or sourced | Rebuild and source the workspace |
| Everything starts twice | Launch file included twice | Check the include tree |
Related: ROS 2 for beginners, Nav2 tutorial, Gazebo ROS 2 tutorial, SLAM for beginners, Raspberry Pi 5 robot guide.
What is a launch file in ROS 2?
A launch file starts multiple nodes with their parameters, remaps and namespaces in one command. It replaces a set of manual terminal commands with a versioned description of the system.
Should I write launch files in Python, XML or YAML?
Python is the most flexible and handles conditions and computed paths well. XML and YAML are simpler for basic compositions. Pick one style per repository.
How do I pass arguments to a ROS 2 launch file?
Declare them with DeclareLaunchArgument, read them with LaunchConfiguration, and override on the command line with name:=value.
Why is my launch file not loading parameters?
Usually the node name or namespace in the YAML does not match the running node. Use ros2 param dump to see what the node actually received.
How do I start a node only in simulation?
Use an IfCondition or UnlessCondition tied to a launch argument, and set that argument differently in the simulation and hardware launch files.
Launch files start nodes; choosing how they talk is the next decision: topics, services and actions in ROS 2.
A launch file usually loads a robot description too; see building a URDF for ROS 2.
Older tutorials use ROS 1 launch XML; ROS 2 vs ROS 1 explains why the file changed.
Launch files drive lifecycle transitions with event handlers, and the lifecycle nodes tutorial shows the sequencing pattern.
Sources and further reading
- ROS 2 launch tutorials — official examples for Python, XML and YAML launch files.
- ROS 2 parameters — parameter files, types and overrides.
- ROS 2 design documents — launch architecture and composition.
- Nav2 documentation — launching a real navigation stack with parameters and remaps.


