Launch Files¶
A robot system in ROS or ROS2 consist of several interconnected nodes, which are responsible for different tasks, e.g.:
localization,
locomotion,
path planning,
mapping,
reading out sensor data,
visualization and so on.
Instead of invoking every node on its own, use a launch file! One launch file can start multiple nodes. It is a perfect tool for managing the processes of a more complex ROS2 application. On top, a launch file can include other launch files, which makes it even easier to structure the complex starting process of a robot system. For better organization launch files should be placed in a folder named launch inside the ROS2 package.
Create a launch file named turtle.launch.py:
$ cd ~/robot_ws/src/myfirstpackage/
$ mkdir launch
$ cd launch
$ touch turtle.launch.py
Instead, you can also create the launch folder and the launch file using the graphical user interface or inside your IDE.
Multiple Nodes in one launch file¶
Include the nodes turtlesim_node and draw_square of the package turtlesim in the turtle.launch.py file. The example given below shows the basic syntax of a launch file.
#!/usr/bin/env python3
from launch import LaunchDescription
from launch_ros.actions import Node
def generate_launch_description():
return LaunchDescription([
Node(
package='turtlesim',
node_executable='turtlesim_node',
node_name='my_turtle',
output='screen'),
Node(
package='turtlesim',
node_executable='draw_square',
node_name='draw_square',
output='log'),
])
For a Node you can define parameters in a launch file, e.g.:
package → name of the package that holds the executable
node_executable → name of the executable
node_name → (free to choose) name for the running process in ROS2
output → location of the output (screen or log, as desired)
Every launch file needs the generate_launch_description function and the return value LaunchDescription to be able to startup the dedicated Nodes.
Before we can start our launch file, it is necessary to once add launch
files to our setup.py
file in our package. Open the setup.py
file
and add the following two imports at the beginning of the file:
import os
from glob import glob
Afterwards add the following code to the data_files parameter in line 15:
--- /mnt/c/Users/Patrick/Documents/academy-sphinx/_resources/code/tutorials/scripts/node_setup.py
+++ /mnt/c/Users/Patrick/Documents/academy-sphinx/_resources/code/tutorials/scripts/launch_setup.py
@@ -1,3 +1,5 @@
+import os
+from glob import glob
from setuptools import setup
package_name = 'myfirstpackage'
@@ -10,6 +12,7 @@
('share/ament_index/resource_index/packages',
['resource/' + package_name]),
('share/' + package_name, ['package.xml']),
+ (os.path.join('share', package_name), glob('launch/*.launch.py')),
],
install_requires=['setuptools'],
zip_safe=True,
We only need to do that once. Using this line all future launch files will be included automatically after building the package with colcon. So build the package again:
$ cd ~/robot_ws
$ colcon build
Start the launch file:
$ ros2 launch myfirstpackage turtle.launch.py
# ros2 launch <package_name> <launch_file_name>
The ros2 launch command executes a launch file.
Start one Node multiple times¶
It is also possible to run the same Node multiple times, using namespaces. In the following example we add another turtlesim instance to our turtle.launch.py file and just add the parameter namespace with the value new_turtle to run the same node just with a different name:
#!/usr/bin/env python3
from launch import LaunchDescription
from launch_ros.actions import Node
def generate_launch_description():
return LaunchDescription([
Node(
package='turtlesim',
node_executable='turtlesim_node',
node_name='my_turtle',
output='screen'),
Node(
package='turtlesim',
node_executable='turtlesim_node',
node_name='my_turtle',
node_namespace='new_turtle',
output='screen'),
Node(
package='turtlesim',
node_executable='draw_square',
node_name='draw_square',
node_namespace='new_turtle',
output='log'),
])
If you build the package and start the launch file again, you should see two turtlesim instances now. This new one is quite boring, because it does not move yet.
→ Please add another draw_circle Node to the launch file using the same namespace new_turtle.
→ Create another launch file turtle2.launch.py and move the 2nd turtlesim and the second draw_circle including the namespace parameter to that new turtle2.launch.py file. Don’t forget to delete them from your initial turtle.launch.py.
Include a launch file in a launch file¶
We should now have organized our two turtles in two seperate launch files. If we now want to start both of them, we can create another launch file starting both turtles. Create another launch file and name it multi_turtle.launch.py. It should include the previous launch files turtle.launch.py and turtle2.launch.py. Use the given example below.
#!/usr/bin/env python3
import os
from ament_index_python.packages import get_package_share_directory
from launch import LaunchDescription
from launch_ros.actions import Node
from launch.actions import IncludeLaunchDescription
from launch.launch_description_sources import PythonLaunchDescriptionSource
def generate_launch_description():
my_first_pkg = get_package_share_directory('myfirstpackage')
return LaunchDescription([
IncludeLaunchDescription(
PythonLaunchDescriptionSource(
os.path.join(my_first_pkg, 'turtle.launch.py')
),
),
IncludeLaunchDescription(
PythonLaunchDescriptionSource(
os.path.join(my_first_pkg, 'turtle2.launch.py')
),
),
])
→ Start the multi_turtle.launch.py launch file.
→ Include your node myfirstnode into the multi_turtle.launch.py file, build and restart it and check all active nodes of your system.
For further information: https://index.ros.org/doc/ros2/Tutorials/Launch-system/
Parameters¶
A parameter is a configuration value of a node. You can think of parameters as node settings. A node can store parameters as integers, floats, booleans, strings and lists. In ROS 2, each node maintains its own parameters. All parameters are dynamically reconfigurable. Parameters are accessible via:
command line,
*.yaml file or
launch file.
Access Parameters via command line¶
Start the ROS2 nodes turtlesim_node and turtle_teleop_key of the package turtlesim and list all available parameters:
$ ros2 param list
You will see the node namespaces, /teleop_turtle
and /turtlesim
,
followed by the dedicated parameters of the nodes.
Every node has the parameter use_sim_time
; it’s not unique to turtlesim.
To read out the current value of a parameter, e.g. the background_g
parameter
of the node turtlesim, use:
$ ros2 param get /turtlesim background_g
# ros2 param get <node_name> <parameter name>
You should receive the output:
Integer value is: 86
This is the green part of the RGB color code from the background of the turtlesim window. Now that we know that it is an integer value, we can change it to a different integer value:
$ ros2 param set /turtlesim background_g 177
# ros2 param set <node_name> <parameter name> <value>
Hint
If you additionally set the red value to 0 and the blue value to 172, you will get a nice FH Aachen mint green background.
You can save the current parameters of the Node for a later use:
$ cd ~/robot_ws/src/myfirstpackage
$ mkdir config
$ cd config
$ ros2 param dump /turtlesim
# ros2 param dump <node_name>
This command will save the parameter setup in a *.yaml file in the current directory where the command is executed.
For now in ROS2 we need to slightly modify this file so that it will also
work with namespaces, e.g. in launch files. Open the turtlesim.yaml
now and replace the node name turtlesim
by double asterisk /**
:
--- /mnt/c/Users/Patrick/Documents/academy-sphinx/_resources/code/tutorials/config/turtlesim_dump.yaml
+++ /mnt/c/Users/Patrick/Documents/academy-sphinx/_resources/code/tutorials/config/turtlesim_asterisk.yaml
@@ -1,4 +1,4 @@
-turtlesim:
+/**:
ros__parameters:
background_b: 172
background_g: 177
Access parameters via *.yaml files¶
Go to the directory, where you stored your turtlesim.yaml file that you have created. Create a copy for further steps:
$ cd ~/robot_ws/src/myfirstpackage/config
$ cp turtlesim.yaml turtlesim_fh.yaml
Open the file now. It should have the following content:
/**:
ros__parameters:
background_b: 172
background_g: 177
background_r: 0
use_sim_time: false
We can now start turtlesim with this configuration using the
--ros-args
and --param-file
flag:
$ cd ~/robot_ws/src/myfirstpackage/config
$ ros2 run turtlesim turtlesim_node --ros-args --params-file ./turtlesim_fh.yaml
# ros2 run <package_name> <executable_name> --ros-args --params-file <file_name>
This method does only work, if we pass the complete path to the *.yaml file. A more smart way is to use a launch file instead.
Access parameters via launch file¶
We can include paramater files in launch files. This is very useful to start ROS2 Nodes with a predifened setup. This could for example be a camera driver Node with parameters for resolution and frame rate. So it would be possible to create different configurations for resolution and frame rate and start the dedicated launch file - always using the same Node, but with a different configuration.
Let’s modify our turtle.launch.py file for this purpose:
$ cd ~/robot_ws/src/myfirstpackage/launch
In line 12 we add:
parameters=[os.path.join(my_first_pkg, 'turtlesim_fh.yaml')],
Of course we need to define the my_first_pkg variable and import the necessary libraries as shown in the following:
--- /mnt/c/Users/Patrick/Documents/academy-sphinx/_resources/code/tutorials/launch/simple_launch_file.launch.py
+++ /mnt/c/Users/Patrick/Documents/academy-sphinx/_resources/code/tutorials/launch/simple_params_launch_file.launch.py
@@ -1,14 +1,19 @@
#!/usr/bin/env python3
+
+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():
+ my_first_pkg = get_package_share_directory('myfirstpackage')
return LaunchDescription([
Node(
package='turtlesim',
node_executable='turtlesim_node',
node_name='my_turtle',
+ parameters=[os.path.join(my_first_pkg, 'turtlesim_fh.yaml')],
output='screen'),
Node(
package='turtlesim',
Before we can start our modified launch file with parameters, it is necessary
to once add *.yaml files from our config folder to our setup.py
, like we
did for launch files.
$ cd ~/robot_ws/src/myfirstpackage
Open the setup.py
file and add the the following
code to the data_files parameter in line 16:
--- /mnt/c/Users/Patrick/Documents/academy-sphinx/_resources/code/tutorials/scripts/launch_setup.py
+++ /mnt/c/Users/Patrick/Documents/academy-sphinx/_resources/code/tutorials/scripts/params_setup.py
@@ -12,7 +12,8 @@
('share/ament_index/resource_index/packages',
['resource/' + package_name]),
('share/' + package_name, ['package.xml']),
- (os.path.join('share', package_name), glob('launch/*.launch.py')),
+ (os.path.join('share', package_name), glob('launch/*.launch.py')),
+ (os.path.join('share', package_name), glob('config/*.yaml')),
],
install_requires=['setuptools'],
zip_safe=True,
Finally build the package and start the modified turtle.launch.py:
$ cd ~/robot_ws
$ colcon build --packages-select myfirstpackage
# colcon build --packages-select <package_name>
$ ros2 launch myfirstpackage turtle.launch.py
Hint
You can use the flag --packages-select
with colcon build
to only build one specific package in the workspace.
You should now see the FH Aachen mint green turtlesim background like in the following figure:

Figure 3 Turtlesim with FH Aachen mint green background.¶
Now create a copy of the turtlesim_fh.yaml file and name it turtlesim_random.yaml
$ cd ~/robot_ws/src/myfirstpackage/config $ cp turtlesim_fh.yaml turtlesim_random.yaml
→ Open the new file and change the RGB values to any integer number that you like (only values from 0 to 255 are valid for color codes).
→ Modify the turtle2.launch.py in the launch folder of your package myfirstpackage and include the new turtlesim_random.yaml as a paramater for your second turtlesim instance.
→ Now start the multi_turtle.launch.py launch file from myfirstpackage. Don’t forget to build your package first to install new *.yaml parameter file and the modified launch file.
For further information: http://design.ros2.org/articles/ros_parameters.html
Create your own parameters in a Node¶
In ROS2 it is quite simple to create parameters in your Node. For that purpose create a copy of myfirstnode.py:
$ cd ~/robot_ws/src/myfirstpackage/myfirstpackage
$ cp myfirstnode.py param_node.py
Don’t forget to add an entry point for this node in the setup.py:
--- /mnt/c/Users/Patrick/Documents/academy-sphinx/_resources/code/tutorials/scripts/params_setup.py
+++ /mnt/c/Users/Patrick/Documents/academy-sphinx/_resources/code/tutorials/scripts/multiple_nodes_setup.py
@@ -25,6 +25,7 @@
entry_points={
'console_scripts': [
'myfirstnode = myfirstpackage.myfirstnode:main',
+ 'param_node = myfirstpackage.param_node:main',
],
},
)
In some special cases you do not want your executable to do ROS related stuff only.
In that cases and only in such cases, it makes sense to replace the rclpy.spin()
by a rclpy.spin_once()
. Remember: the spin() function loops our Node and
waits for work for our Node to do. spin_once() instead will only ask the ROS2
system once, if there is work for the Node to do and not continously in a loop.
That allows us to do something after the spin_once() request within the executable.
Again: This is only useful in special cases and not recommended as a general approach.
We will anyway do this now for our parameter example.
Open your param_node.py Node and replace the
`rclpy.spin`
by `rclpy.spin_once`
and rename the Node meanwhile:
--- /mnt/c/Users/Patrick/Documents/academy-sphinx/_resources/code/tutorials/scripts/simple_python_node2_with_shutdown.py
+++ /mnt/c/Users/Patrick/Documents/academy-sphinx/_resources/code/tutorials/scripts/simple_python_node2_with_spin_once.py
@@ -4,12 +4,11 @@
def main():
rclpy.init()
- myfirstnode = rclpy.create_node('myfirstnode')
+ myfirstnode = rclpy.create_node('my_param_node')
try:
- rclpy.spin(myfirstnode)
+ rclpy.spin_once(myfirstnode, timeout_sec=1.0)
except KeyboardInterrupt:
pass
-
myfirstnode.destroy_node()
rclpy.shutdown()
We should set the timeout_sec to 0.0
in case there is some blocking function.
To create our own parameter, we will add the following code in line 8 after creating the Node:
myfirstnode.declare_parameter('my_param', 13)
#<nodename>.declare_parameter('<parameter_name>', <parameter_default_value>)
That’s already it.
→ To see that it is working, run the Node and check the parameter value from command line.
To see that our parameter is actively affected by changing its value, we can also ask the current parameter value in our Node using:
myfirstnode.get_parameter('my_param').value
#nodename.get_parameter('<parameter_name>').value
We can print the parameter value in a while loop so that we see the current value within the Node.
Using rclpy we can loop around our spin_once unless it is ok:
while rclpy.ok():
To not spam in our terminal, it is also useful to use a delay in the loop, let’s say of 1 second. For that purpose we can use the Python sleep() function from the time library:
from time import sleep # add this line in the beginning of your Python script
sleep(1.0) # blocks the code for 1 second inside the loop
Your final Python Node should now look like this:
#!/usr/bin/env python3
import rclpy
from time import sleep
def main():
rclpy.init()
myfirstnode = rclpy.create_node('my_param_node')
myfirstnode.declare_parameter('my_param', 13)
while rclpy.ok():
try:
rclpy.spin_once(myfirstnode, timeout_sec=1.0)
except KeyboardInterrupt:
pass
print(myfirstnode.get_parameter('my_param').value)
sleep(1.0)
myfirstnode.destroy_node()
rclpy.shutdown()
if __name__ == '__main__':
main()
Congratulations! You are now familiar with the basics of the ROS2 Filesystem.