Launch文件编写技巧

想要利用空间弥补时间,学会launch文件的编写!
launch

怕什么真理无穷,进一寸有一寸的欢喜

launch简介

ROS提供了一个同时启动节点管理器(master)和多个节点的途径,即使用启动文件(launch file)。事实上,在ROS功能包中,启动文件的使用是非常普遍的。任何包含两个或两个以上节点的系统都可以利用启动文件来指定和配置需要使用的节点。通常的命名方案是以.launch作为启动文件的后缀,启动文件是XML文件。一般把启动文件存储在取名为launch的目录中。

每个XML文件都必须要包含一个根元素。根元素由一对launch标签定义:<launch> … </launch>,元素都应该包含在这两个标签之内。下面贴出我们导航功能的launch启动文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
turtlebot3_navigation.launch
<launch>
<!-- Arguments -->
<arg name="model" default="$(env TURTLEBOT3_MODEL)" doc="model type [burger, waffle, waffle_pi]"/>
<arg name="map_file" default="$(find turtlebot3_navigation)/maps/map.yaml"/>
<arg name="open_rviz" default="true"/>
<arg name="move_forward_only" default="false"/>

<!-- Turtlebot3 -->
<include file="$(find turtlebot3_bringup)/launch/turtlebot3_remote.launch">
<arg name="model" value="$(arg model)" />
</include>

<!-- Map server -->
<node pkg="map_server" name="map_server" type="map_server" args="$(arg map_file)"/>

<!-- AMCL -->
<include file="$(find turtlebot3_navigation)/launch/amcl.launch"/>

<!-- move_base -->
<include file="$(find turtlebot3_navigation)/launch/move_base.launch">
<arg name="model" value="$(arg model)" />
<arg name="move_forward_only" value="$(arg move_forward_only)"/>
</include>

<!-- rviz -->
<group if="$(arg open_rviz)">
<node pkg="rviz" type="rviz" name="rviz" required="true"
args="-d $(find turtlebot3_navigation)/rviz/turtlebot3_navigation.rviz"/>
</group>
</launch>

launch 文件运行

用 roslaunch 命令启动 launch 文件有两种方式。

1.借助 ros package 路径启动,格式如下:
roslaunch pkg_name file_name.launch
2.直接给出 launch 文件的绝对路径,格式如下:
roslaunch path_to_launchfile

上述两种启动方式都可以在后边添加参数,比较常见的参数有:
–screen: 将node的信息(如果有的话)输出到屏幕上,而不是保存在某个 log 文件中,这样比较方便调试
–arg:=value: 如果 launch 文件中有待赋值的变量,可以通过这种方式赋值。

roslaunch 命令运行时首先会检测系统的master是否运行,如果已经启动,就用现有的 master;如果没有启动,会先启动master,然后再执行 launch 文件中的设置,一次性把多个节点按照我们预先的配置启动起来。
注:launch 文件不需要编译,设置好之后可以直接用上述方式运行。

launch 文件格式

launch文件是一种xml文件,可在部添加<?xml version="1.0"?>来高亮显示关键字,方便阅读。与其他 xml 格式的文件类似,launch 文件也是通过标签 (tag) 的方式书写。主要的 tag 如下:

1
2
3
4
5
6
7
8
9
10
11
<launch>                <!--根标签-->
<node> <!--需要启动的node及其参数-->
<remap> <!--设定 topic 映射-->
<include> <!--包含其他launch-->
<arg> <!--定义变量-->
<param> <!--定义参数到参数服务器-->
<rosparam> <!--加载yaml文件中的参数到参数服务器-->
<machine> <!--指定运行的机器-->
<env-loader> <!--设置环境变量-->
<group> <!--设定分组-->
</launch> <!--根标签-->

<launch>、<node>

这两个 tag 是 launch 文件的核心部分。基本格式如下:

1
2
3
4
<launch>
<!-- Map server -->
<node pkg="map_server" name="map_server" type="map_server" args="$(arg map_file)"/>
</launch>

其中,pkg是节点所在的 package 名,type是功能包中的可执行文件名,name是节点启动之后的名字, 每一个节点都要有自己独一无二的名字。
注: roslaunch 不能保证 node 的启动顺序,因此 launch 文件中所有的 node 都应该对启动顺序有鲁棒性。

实际上 <node> 中除了 pkg、type、name 之外还可以设置更多参数,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
<launch>
<node
pkg=""
type=""
name=""
respawn="true"
required="true"
launch-prefix="xterm -e"
output="screen"
ns="some_namespace"
args=""
/>
</launch>

上述命令中:
respawn:若该节点关闭,是否可以自动重新启动。
required:若该节点关闭,是否要关闭其他所有节点。
launch-prefix:是否新开一个新的终端窗口执行。
output:默认情况下,launch 启动 node 的信息会存入下面的 log 文件中,可以通过此处参数设置,令信息显示在屏幕上。
ns:将node归入不同的 namespace,即在 node name 前加 ns 指定的前缀。
args:传递参数到节点。argument参数只在launch文件中合法(相当于局部变量),不直接传给节点,所以需要通过node中的args属性进行传递.。
基本格式:

1
2
<node pkg="rviz" type="rviz" name="rviz" required="true"
args="-d $(find turtlebot3_navigation)/rviz/turtlebot3_navigation.rviz"/>(利用find寻找路径)

注:$() 这个符号出现的任何地方,roslaunch命令都将会把它替换成给定argument 的值(value)。

另一个例子:

1
2
<node name="add_two_ints_client" pkg="beginner_tutorials" 
type="add_two_ints_client" args="$(arg a) $(arg b)" />

这样设置之后,在启动 roslaunch 时,可以为 args 赋值
roslaunch beginner_tutorials launch_file.launch a:=1 b:=5

<remap>

经常作为 node tag 的子 tag 出现,可以用来修改 topic。简单地说,remap 的作用就是将topic_name进行重映射,方便同一个 node 文件被应用到不同的环境中,用 remap 从外部修改一下 topic 即可,不需要改变源文件。
基本格式:

1
2
3
<node pkg="pkg"  type="type"  name="name">
<remap from="type" to="type_new" />
</node>

<include>

这个标签的作用是将另一个 launch 文件添加到本 launch 文件中,类似 launch 文件的嵌套。为了程序的可移植性,最好借助 find 命令给出文件路径。
基本格式:

1
2
<!-- AMCL -->
<include file="$(find turtlebot3_navigation)/launch/amcl.launch"/>

上述命令中,$(find turtlebot3_navigation) 等价于本机中相应包的路径。这样即使换了其他机子,只要安装了同样的功能包,就可以找到对应的路径。
有时,另一个 launch 引入的 node 可能需要统一命名,或者具有类似特征的 node 名字,比如 /vehicle1/gps, /vehicle1/lidar, /vehicle1/imu,即 node 具有统一的前缀,方便查找。这可以通过设置 ns (namespace)属性来实现,命令如下:

1
2
<include file="$(find package-name)/launch-file-name " 
ns="namespace_name" />

<arg>

通过 <arg> tag 可以使参数重复使用,也便于多处同时修改。
<arg> 标签三种常用方法:
<arg name="foo">: 声明一个 arg,但不赋值。稍后可以通过命令行赋值,或者通过 <include> tag 赋值。
<arg name="foo" default="1">: 赋默认值。这个值可以被命令行和 <include> tag 重写。
<arg name="foo" value="1">: 赋固定值,这个值不可以被改写.
基本格式:

1
2
3
4
5
<!-- Arguments -->
<arg name="model" default="$(env TURTLEBOT3_MODEL)" doc="model type [burger, waffle, waffle_pi]"/>
<arg name="map_file" default="$(find turtlebot3_navigation)/maps/map.yaml"/>
<arg name="open_rviz" default="true"/>
<arg name="move_forward_only" default="false"/>

变量替换 $(find *) 和 $(arg *)

在 launch 文件中常用的变量替换形式有两种。
$(find pkg):如果可能,强烈推荐这种基于 package 的路径设置。
基本格式:

1
2
<arg name="map_file" default="$(find turtlebot3_
navigation)/maps/map.yaml"/>

$(arg arg_name):将此处替换成 <arg> tag 指定的 arg value.
基本格式:

1
2
<arg name="model" default="$(env TURTLEBOT3_MODEL)" 
doc="model type [burger, waffle, waffle_pi]"/>

先设置默认值,如果没有额外的赋值,就用这个默认值

1
2
3
4
<!-- Turtlebot3 -->
<include file="$(find turtlebot3_bringup)/launch/turtlebot3_remote.launch">
<arg name="model" value="$(arg model)" /> #变量替换
</include>

<param> 与 <rosparam>

提到 param 首先要知道 parameter server, 它由 Master 管理,提供了一个共享的字典 (dict) 类型数据。节点通过这个 server 存储、获取运行时所需的参数。
param server 是全局可获取, 我们可以很容易的查看其中的 param 并且修改。param 的命名与 topic 和 node 相同,都是有 namespace hierarchy 结构的,这可以防止不同来源的名字冲突。它的存取也是体现了结构性,例如下边的 params:

1
2
3
4
/camera/left/name: leftcamera
/camera/left/exposure: 1
/camera/right/name: rightcamera
/camera/right/exposure: 1.1

对于上述数据,
读取参数 /camare/left/name ,可得到 leftcamera
读取 param /camera/left
可得到dict为{name: leftcamera, exposure: 1}
读取 param /camera
可得到dict为{left: {name: leftcamera, exposure: 1}, right: {name: rightcamera, exposure: 1.1}}

<param>

与 arg 不同,param 是共享的,并且它的取值不仅限于 value,还可以是文件,甚至是一行命令。
基本格式:

1
2
3
<param name="param_name" type="type1" value="val"/>     # type可以省略,系统自动判断
<param name="param_name" textfile="$(find pkg)/path/file"/> # 读取 file 存成 string
<param name="param_name" command="$(find pkg)/exe '$(find pkg)/arg.txt'"/>

param 可以是在 global scope 中,它的 name 就是原本的 name,也可以在某个更小的 scope 中,比如 node,那么它在全局的名字就是 node/param 形式.
例如在 global scope 中定义如下 param
<param name="frequency" type="double" value="10.0"/>
再在 node scope 中定义如下 param

1
2
3
<node name="node1" pkg="pkg1" type="exe1">
<param name="param1" value="False"/>
</node>

如果用 rosparam list列出server 中的 param,则有

1
2
/frequency
/node1/param1 # 自动加上了 namespace 前缀

注意:虽然 param1 名字前加了 namespace,但依然是全局变量。

<rosparam>

<param> 只能对单个 param 操作,而且只有三种:value, textfile, command 形式,返回的是单个 param 的内容。
<rosparam> 则可以批量操作,还包括一些对参数设置的命令,如 load,dump,delete 等。
load: 从 YAML 文件中加载一批 param,格式如下:
<rosparam command="load" file="$(find pkg)/param.yaml" />
delete: 删除某个 param
<rosparam command="delete" param="my_param" />
类似 <param> 的赋值操作
<rosparam param="my_param">[1,2,3,4]</rosparam>
或者

1
2
3
4
<rosparam>
a: 1
b: 2
</rosparam>

<rosparam> tag 也可以放在 <node> tag 中, 此时 param 名字前边都加上 node namespace.

注:argument和parameter的区别:
尽管术语argument和parameter在许多计算机环境中可以互换使用,它们的含义在ROS中有很大的不同。Parameters(参数)在一个运行的ROS系统中是变量(values),它被存储在参数服务器中,运行的节点通过ros::param::get()函数访问它,并且用户可以通过 rosparam 命令行工具使用它。相比之下,arguments只有在launch文件里合法,它们的值不是直接提供给节点。

<group>

如果要对多个 node 进行同样的设置,可以用 <group>tag包含所有 node。在 group 中可以使用所有常见的 tag 进行设置,例如:

1
2
3
4
5
6
7
<group ns="wg2">
<remap from="chatter" to="talker"/> # 对该 group 中后续所有 node 都有效
<node ... />
<node ... >
<remap from="chatter" to="talker1"/> # 各个 node 中可以重新设置 remap
</node>
</group>

例:

1
2
3
4
5
<!-- rviz -->
<group if="$(arg open_rviz)">
<node pkg="rviz" type="rviz" name="rviz" required="true"
args="-d $(find turtlebot3_navigation)/rviz/turtlebot3_navigation.rviz"/>
</group>

-------------本文结束 感谢阅读-------------
0%