ROS学习笔记(四)- ROS的launch文件
书接上回,上次已经介绍到launch文件的一些内容了,这次详细记录学习一下。
在ROS中,launch文件是一种XML文件,用于描述ROS系统中的节点、话题、参数等信息,可以用来自动化启动多个节点和启动参数服务器。在实际应用中,launch文件可以让用户非常方便地组织ROS系统的启动和配置。下面详细介绍ROS的launch文件及其所有的使用方法和场景。
一,launch文件的基本结构
一个最简单的launch文件如下所示:
<launch> <node name="my_node" pkg="my_package" type="my_node.py" /> </launch>
这个launch文件中包含了一个节点的描述信息。它的基本结构包含两个部分:
<launch>
和</launch>
:用来标记launch文件的开始和结束。<node>
标签:用来描述一个ROS节点。这个标签包含了节点的名称、所在包、执行文件等信息。
在一个launch文件中可以包含多个节点的描述,这些节点可以相互连接,形成一个完整的ROS系统。
二,launch文件的使用方法
在ROS中,可以使用roslaunch命令来启动一个launch文件。命令格式如下:
roslaunch package_name launch_file_name.launch [arg_name:=arg_value]
其中,package_name是节点所在的ROS软件包的名称,launch_file_name是要启动的launch文件的名称。可以通过[arg_name:=arg_value]的方式向launch文件中传递参数。
在launch文件中,可以使用<arg>
标签来定义参数,如下所示:
<launch> <arg name="my_arg" default="hello" /> <node name="my_node" pkg="my_package" type="my_node.py" my_arg="$(arg my_arg)" /> </launch>
这个launch文件中定义了一个名为my_arg的参数,它的默认值是hello。然后在node标签中使用$(arg my_arg)的方式来引用这个参数。当使用roslaunch命令启动这个launch文件时,可以通过my_arg:=world
的方式修改这个参数的值。
三,launch文件的高级用法
除了基本的节点描述和参数传递,launch文件还支持一些高级用法。下面介绍一些常用的高级用法。
3.1. 组合多个launch文件
在ROS中,可以使用<include>
标签来组合多个launch文件。如下所示:
<launch> <include file="$(find my_package)/launch/my_subsystem.launch" /> <node name="my_node" pkg="my_package" type="my_node.py" /> </launch>
这个launch文件包含了另外一个名为my_subsystem.launch的launch文件,同时还启动了一个节点。在实际应用中,这种组合多个launch文件的方式可以让用户非常方便地组织ROS系统。
3.2. 使用节点组
在ROS launch文件中,可以通过group
标签来定义节点组。节点组是指一组节点,这些节点将同时启动或停止,可以一起进行管理。使用节点组可以方便地启动和停止多个节点,从而减少手动操作和出错的可能性。如下所示:
<launch> <group ns="robot1"> <node pkg="robot1" name="node1" type="node1" /> <node pkg="robot1" name="node2" type="node2" /> </group> <group ns="robot2"> <node pkg="robot2" name="node1" type="node1" /> <node pkg="robot2" name="node2" type="node2" /> </group> </launch>
在这个例子中,定义了两个节点组,robot1
和robot2
。每个节点组都包含两个节点。在这个例子中,ns
属性用于设置节点组的命名空间,以便在运行时可以区分不同的节点组。通过在命令行中指定命名空间,可以只启动或停止一个节点组。
在启动这个launch文件时,所有的节点将同时启动。可以使用rosnode list
命令来列出当前运行的所有节点。可以使用rosnode info
命令来查看特定节点的详细信息。
除了使用命名空间来区分节点组之外,还可以使用其他参数来进一步控制节点组的行为。例如,可以使用respawn="true"
参数来指定节点组中的节点是否应该在崩溃后自动重启。可以使用required="true"
参数来指定节点组中的节点是否是必需的,如果一个节点失败,整个节点组都将停止。
3.3. 参数替换。
可以在launch文件中定义参数,然后在节点的参数中使用这些参数进行替换,实现动态的配置管理。
假设我们有一个ROS节点my_node
,该节点需要在启动时设置一个参数my_param
,我们可以在launch文件中定义该参数并传递给该节点。
创建一个launch文件my_launch_file.launch
,并定义参数my_param
:
<launch> <arg name="my_param" default="default_value" doc="My custom parameter" /> <node name="my_node" pkg="my_package" type="my_node" output="screen"> <param name="my_param" value="$(arg my_param)" /> </node> </launch>
在上面的launch文件中,我们定义了一个参数my_param
,并设置了默认值为default_value
。然后我们启动了一个名为my_node
的节点,该节点从参数服务器中读取参数my_param
的值,并将其设置为节点的参数。
在启动时可以通过以下命令启动该launch文件,并设置参数my_param
的值为my_custom_value
:
roslaunch my_package my_launch_file.launch my_param:=my_custom_value
在上面的命令中,我们使用了:=
操作符来指定参数my_param
的值为my_custom_value
。
当launch文件启动时,参数my_param
将被替换为my_custom_value
,节点my_node
将使用新的参数值启动。
使用ROS launch文件实现参数替换可以方便地配置ROS系统,避免了手动修改参数文件的麻烦。
arg
用于从命令行传递参数到launch文件中,可以通过${arg 参数名}
的方式在launch文件中引用,例如:
<launch> <arg name="my_arg" default="hello" /> <node name="my_node" pkg="my_package" type="my_node" output="screen"> <param name="my_param" value="${arg my_arg}" /> </node> </launch>
在上面的例子中,定义了一个名为my_arg
的arg
,默认值为hello
。在my_node
节点的参数中,使用${arg my_arg}
的方式引用了这个参数,也就是说,my_param
参数的值将会是从命令行传递过来的my_arg
参数的值,如果没有从命令行传递,则使用默认值。
param
则是用于在launch文件内部传递参数的机制,可以通过${param 参数名}
的方式在launch文件中引用,例如:
<launch> <param name="my_param" value="hello" /> <node name="my_node" pkg="my_package" type="my_node" output="screen"> <param name="my_param" value="${param my_param}" /> </node> </launch>
在上面的例子中,定义了一个名为my_param
的param
,值为hello
。在my_node
节点的参数中,使用${param my_param}
的方式引用了这个参数,也就是说,my_param
参数的值将会是my_param
参数的值,如果没有定义,则使用默认值。
简单说,arg标签是用于将参数从命令行传递到launch文件中,param标签是用于将参数从launch文件传递到ROS节点代码中,从而可以在python代码里通过rospy.get_param()获取到该参数。
可以使用
if
和unless
来实现条件判断。if
表示条件成立时执行,unless
表示条件不成立时执行。下面是一个简单的例子,该例子实现了一个根据参数选择是否启动一个节点的功能:
<launch> <!-- 设置参数 --> <arg name="enable_node" default="false" /> <!-- 根据参数决定是否启动节点 --> <node name="my_node" pkg="my_package" type="my_node" output="screen" if="$(arg enable_node)"> </node> </launch>
在上面的例子中,首先通过arg
标签设置了一个参数enable_node
,默认值为false
。然后在node
标签中使用了if
参数,当enable_node
为true
时,节点my_node
才会启动。
另外,unless
参数可以用于在某个条件不成立时执行某个节点。例如,下面的例子会在参数roscore_running
为false
时启动节点my_node
:
<launch> <!-- 检查roscore是否正在运行 --> <node pkg="rosmon" type="rosmon" name="rosmon" args="-d 2" respawn="true"> <remap from="rosmon/monitoring" to="rosmon" /> <param name="max_processes" type="int" value="1" /> <param name="nodes/my_node/type" value="my_node" /> <param name="nodes/my_node/paused" value="false" /> <param name="nodes/my_node/unless" value="$(arg roscore_running)" /> </node> <!-- 启动节点my_node --> <node pkg="my_package" type="my_node" name="my_node" output="screen" unless="$(arg roscore_running)"> </node> </launch>
在这个例子中,首先通过rosmon
节点检查roscore
是否正在运行,并根据参数roscore_running
的值确定是否启动节点my_node
。然后在node
标签中使用了unless
参数,当roscore_running
为true
时,节点my_node
才会启动。