launch文件的使用

在ROS2中,可以使用ros2 run <package_name> <executable_name>命令来运行节点,对于有参数的节点,也可以使用ros2 param set命令来设置参数值。但是实际的项目往往是由多个节点组成的,而且每个节点往往也有着不止一个的参数。此时使用上述的命令行形式去启动多个节点或者修改多个参数就显得比较繁琐。在ROS2中,提供了launch文件这一功能,通过编写launch文件的内容,可以一次性启动多个节点,并且可以在launch文件中设置节点的参数值,从而简化了节点的启动和参数设置的操作。

在ROS2中,launch文件支持多种文件格式,包括Python、XML和YAML等格式,不同的格式有着不同的语法和使用方式。这里我们主要介绍Python格式的launch文件的使用方法,因为Python本来就是一种非常适合编写脚本的语言,而且Python格式的launch文件在ROS2中使用得也比较广泛。

使用launch文件启动多个节点

要使用launch文件,需要在一个package中创建一个名字为launch的文件夹,并且在该文件夹中创建一个名字为<launch_file_name>.launch.py的Python文件。然后在该Python文件中编写launch文件的内容。
一个简单的launch文件示例如下:

# start.launch.py
import launch
import launch_ros

# 固定名称的函数,generate_launch_description()是ROS2中launch文件的标准入口函数
# 当你运行ros2 launch命令时,ROS2会调用这个函数来获取launch描述信息
def generate_launch_description():
    action_node_turtle_sim_node1 = launch_ros.actions.Node(
        package = 'turtlesim',
        executable='turtlesim_node',
        name='turtle1',
        output = 'screen',
    )

    action_node_turtle_sim_node2 = launch_ros.actions.Node(
        package = 'turtlesim',
        executable='turtlesim_node',
        name='turtle2',
        output = 'screen',
    ) 

    return launch.LaunchDescription(
        [ # action动作 
            action_node_turtle_sim_node1,
            action_node_turtle_sim_node2,
        ]
    )

注意,在使用之前要在CMakeLists.txt文件中添加对launch文件的安装指令,示例如下:

install(
  DIRECTORY launch
  DESTINATION share/${PROJECT_NAME}/
)
# 将launch文件夹安装到share/<package_name>目录下,这样在运行ros2 launch命令时,ROS2才能找到该launch文件。

你可以使用ros2 launch <package_name> <launch_file_name>命令来运行一个launch文件。

在该段代码中,generate_launch_description()这个函数是一个固定名称的函数,必须一个字不差的定义。这个函数是ROS2中launch文件的标准入口函数,当你运行ros2 launch命令时,ROS2会调用这个函数来获取launch描述信息。该函数必须返回一个LaunchDescription对象,这个对象中包含了所有的launch描述信息。

在launch文件中,其所做的大部分事情都被抽象成一个个动作(action),包括启动节点,设置参数,启动其他launch文件等。上面代码中,使用launch_ros.actions.Node这个动作来启动节点。该动作的参数包括:

  • package:节点所在的包名
  • executable:节点的可执行文件名
  • name:节点的名称
  • output:节点的输出方式

其中,packageexecutable是必须要指定的参数,nameoutput是可选参数(当然可选参数不只有这些)。name参数用于指定节点的名称,如果不指定,则默认使用可执行文件名作为节点名称。output参数用于指定节点的输出方式,可以设置为screen或者log,分别表示将节点的输出打印到屏幕上或者写入日志文件中。

当定义完毕后,将所有的动作对象构成一个列表,并作为LaunchDescription对象的参数传递进去。且将LaunchDescription对象作为generate_launch_description()函数的返回值返回即可。这样,当启用该launch文件时,ROS2就会按照定义的动作顺序依次执行这些动作,从而启动多个节点。执行的结果如下

alt text

在launch文件中设置节点参数

类似与上述的方式,在launch文件中也可以设置节点启动时的参数值。设置参数的方式有两种,一种是直接在Node动作中设置参数,另一种是使用launch_ros.actions.SetParameter动作来设置参数。

import launch
import launch_ros


def generate_launch_description():

    # 1. 通过launch_ros.actions.Node()的固定参数来输入参数值
    action_node_start1 = launch_ros.actions.Node(
        package = 'turtlesim',
        executable = 'turtlesim_node',
        parameters = [
            {'background_r': 255},
            {'background_g': 255},
            {'background_b': 255},
        ],
        name = 'turtle1',
        output = 'screen',
    )


    # 2. 通过launch.actions.DeclareLaunchArgument()来声明参数,并通过launch.substitutions.LaunchConfiguration()来获取参数值

    # 注册launch中的参数及其默认值
    action_param_r = launch.actions.DeclareLaunchArgument('background_r', default_value='255')
    action_param_g = launch.actions.DeclareLaunchArgument('background_g', default_value='255')
    action_param_b = launch.actions.DeclareLaunchArgument('background_b', default_value='255')
    # 将launch接收到的参数值拿出来
    param_r = launch.substitutions.LaunchConfiguration('background_r', default='255')
    param_g = launch.substitutions.LaunchConfiguration('background_g', default='255')
    param_b = launch.substitutions.LaunchConfiguration('background_b', default='255')
    # 3. 通过launch_ros.actions.Node()的固定参数来输入参数值
    action_node_start2 = launch_ros.actions.Node(
        package = 'turtlesim',
        executable = 'turtlesim_node',
        parameters = [
            {'background_r': param_r},
            {'background_g': param_g},
            {'background_b': param_b},
        ],
        name = 'turtle2',
        output = 'screen',
    )

    return launch.LaunchDescription(
        [ # action动作
            action_node_start1,
            action_param_r,
            action_param_g,
            action_param_b,
            action_node_start2,
        ]
    ) 

最后运行该launch文件,结果如下

alt text

从结果上看,两个turtlesim节点的背景颜色都被设置为白色。但是实际上这两种写法有着本质的区别。第一种写法是直接在Node动作中设置参数值,这种方式只能设置固定的参数值,无法在运行时动态修改参数值。而第二种写法是通过DeclareLaunchArgument动作来声明参数,并通过LaunchConfiguration来获取参数值,这种方式可以在启用launch文件时,通过命令行传入参数值,从而实现动态修改参数值的功能。

比如,在运行launch文件时,可以通过如下命令来传入参数值:

ros2 launch <package_name> <launch_file_name> <parameter_name>:=<parameter_value>

在本例中,可以通过如下命令来启动launch文件,并将turtlesim节点的背景颜色设置为红色:

ros2 launch <package_name> <launch_file_name> background_r:=255 background_g:=0 background_b:=0

此时,第二个turtlesim节点的背景颜色就会被设置为红色,而第一个turtlesim节点的背景颜色仍然是白色。

alt text

注意,使用DeclareLaunchArgument动作声明的参数名以及Python中的变量名和节点中的参数名是没有任何关系的,唯一的关系就是在使用LaunchConfiguration来获取参数值时,传入的参数名必须和DeclareLaunchArgument动作中声明的参数名一致,否则就无法获取到参数值。也就是说,DeclareLaunchArgument动作中声明的参数名不需要和节点中的参数名一致,只需要在LaunchConfiguration中获取参数值时,传入的参数名和DeclareLaunchArgument动作中声明的参数名一致即可。

可以将上述写法优化为如下的形式:

import launch
import launch_ros

def generate_launch_description():

    params = {
        'background_r' : launch.substitutions.LaunchConfiguration('background_r', default='255'),
        'background_g' : launch.substitutions.LaunchConfiguration('background_g', default='255'),
        'background_b' : launch.substitutions.LaunchConfiguration('background_b', default='255'),
    }

    action_node_start = launch_ros.actions.Node(
        package = 'turtlesim',
        executable = 'turtlesim_node',
        parameters = [params],
        name = 'turtle',
        output = 'screen',
    )

    return launch.LaunchDescription(
        [
            launch.actions.DeclareLaunchArgument('background_r', default_value='255'),
            launch.actions.DeclareLaunchArgument('background_g', default_value='255'),
            launch.actions.DeclareLaunchArgument('background_b', default_value='255'),
            action_node_start,
        ]
    ) 

上述写法通过提前构建出一个字典来存储参数名和参数值的对应关系,然后在Node动作中直接传入这个字典,从而简化了代码的书写。同时可以看到,LaunchConfiguration作用是将Python中的变量和launch文件中的参数关联起来,从而实现动态修改参数值的功能,并不是运行后直接获取参数值的意思。参数值仅在运行时才会被传入到launch文件中,所以DeclareLaunchArgumentLaunchConfiguration的顺序是没有关系的,只要在LaunchConfiguration中传入的参数名和DeclareLaunchArgument动作中声明的参数名一致即可。

posted @ 2026-08-27 14:53  凪风sama  阅读(55)  评论(0)    收藏  举报