ROSLAUNCH 的.launch/XML 语法

来源:互联网 发布:熊猫tv小葫芦数据 编辑:程序博客网 时间:2024/05/22 03:24

最近面临一个将ROS与机器人结合起来以扩展现有机器人的功能的任务,譬如将ABB的2400机器人接上ROS的moveit,然后通过ROS去控制机器人的运动,对于IRB2400这样的机器人实现还是蛮简单的,但是这种情况下,只知其然而不知其所以然,感觉就不好了,所以我得将这一套东西彻底的理解清楚,整理明白。在这里码下来记录一下我的学习与经历的过程,在面对这个问题时,首先想弄明白的就是roslaunch使用的.launch文件中到底写了些什么鬼!

对了,roslaunch文件的扩展名为.launch,是按照XML格式编写的,所以XML格式的文件也一样能解析。

    • 文件解析顺序
    • 置换参数
      • 1 env ENVIRONMENT_VARIABLE
      • 2 optenv ENVIRONMENT_VARIABLE
      • 3 optenv ENVIRONMENT_VARIABLE default_value
      • 4 find pkg
      • 5 anon name
      • 6 arg varible_name
      • 7 eval expression
    • IF 和 UNLESS 属性
    • 参考标签
      • 1 launch
      • 2 node
      • 3 param
      • 4 rosparam
      • 5 remap
      • 6 machine
      • 7 include
      • 8 env
      • 9 test
      • 10 arg
      • 11 group
    • launch文件的例子
      • 1 一个简单的例子
      • 2 一个复杂一点的例子
      • 3 设置参数

1. 文件解析顺序

roslaunch 以单程的方式解析XML格式文件,include是以深度优先的方式解析内容,而标签Tag以串行的方式处理,所以一个参数的最后一次设置被认定为有效值。
也就是说在.launch文件中同样的设置可能存在多处,比如在开头定义了一个变量,遵循着尽量节省空间的想法,在后面的定义中又对这个变量进行了重新赋值,以便重新利用,在这种情况下,在整个launch文件解析完成后,最终进行的那次设置是有效的,但也并不保证一定有效,不排除在其它的文件中对变量进行了重命名,所以推荐使用$(arg)/<arg>的方式进行覆写。

2. 置换参数

在roslaunch文件中,置换参数也称做置换符,是最常用的,可以提高变量的重用性。下面可用的置换参数如下所示:

2.1 $(env ENVIRONMENT_VARIABLE)

其中的“$”是一个置换处理标志(我是这么理解的),而“env”则是说明后面的变量被当做环境变量处理,毕竟“env”是“environment”(环境)的前面仨字母是吧。这行代码的意思就是用当前环境变量ENVIRONMENT_VARIABLE的值置换目标变量值,不能被<env>覆写,为什么不能覆写呢,后面有说明,如果想起来就把说明放这里,想不起来的话就到后面<env>里找找吧。所以环境变量是比较严肃的,如果用于置换的环境变量未设置,当你启动launch文件时则会显示失败。
对着例子再来啰嗦一下(感觉比较笨怕以后看到理解不了…想像一下这里配了一张悲伤脸的表情)

<param name="variable_name" value="$(env NUM_CPUS)" /> 

上面例子中param是launch文件中进行参数定义的关键字,name属性指定了要定义的变量的名称,value属性是对你前面指定的变量进行赋值或进行值替代,$(env NUM_CPUS)就是你指定要用于进行目标变量值替代的选用值,这个时候问题就来了,如果你的电脑环境变量中有名叫NUM_CPUS的环境变量,那没事,这行代码可以轻松通过,但是如果你的电脑里没有这个环境变量,那你运行这个launch文件的时候就是报错,所以相对来说,optenv更具有鲁棒性。

2.2 $(optenv ENVIRONMENT_VARIABLE)

optenv这个标识符就没有env那么严肃,毕竟它在env的前面加了opt,那就变成了optional environment了是吧,这一行代码就是说如果ENVIRONMENT_VARIABLE已设置,则用其替代目标变量,若没有设置,则用空字符串表示。但我觉得直接理解下面一条更全面。

2.3 $(optenv ENVIRONMENT_VARIABLE default_value)

此行代码可以这样理解,先看ENVIRONMENT_VARIABLE环境变量有没有设置, 若ENVIRONMENT_VARIABLE有设置,就用ENVIRONMENT_VARIABLE的值替代目标变量值,如果ENVIRONMENT_VARIABLE没有设置,那就看default_value是否有设置,如果default_value设置过了,那就用default_value的值去替代目标变量的值,如果default_value未给定则用空字符串去初始化目标变量值。
给以下三个例子:

<param name="variable_name" value="$(optenv NUM_CPUS 1)" />   

上面这一行代码中,在我的计算机中NUM_CPUS 这个环境变量不存在,所以最后variable的值就是1这个缺省值。如果这个缺省值也没有设置,那最后将用空字符串替代目标变量值。

<param name="pkg_path_name" value="$(optenv PATH /home/catkin_ws/src)" />   

这一行代码中,PATH这个环境变量是存在的,所以名为pkg_path的变量值便为PATH的值。

<param name="variable_name" value="$(optenv VARIABLE ros rocks)" />

这一行是想说缺省设置的值可以是一个中间有空格隔开的字符串。

2.4 $(find pkg)

这行代码是用来进行相对路径的提取。
例如:

$(find rospy)/manifest.xml

便是找到包rospy的路径,并且会被内联替换。

2.5 $(anon name)

产生基于名称的匿名ID,主要用于节点名称属性中创建匿名节点,并检查是否有相同的匿名名字,因为ROS中名字作为标识符要求具有唯一性。其中的anon是anonymous的简写。
例如:

<node name="$(anon talk_01)" pkg="rospy_tutorials" type="talker.py" />   <node name="$(anon talk_01)" pkg="rospy_tutorials" type="talker.py" />

则会产生错误,因为系统检测到了两个节点具有相同的匿名名字。

2.6 $(arg varible_name)

解析由<arg>标签指定的变量值。
例如:

<param name="varible_name" value="$(arg my_varible)" />

要求在同一文件中my_varible已经由<arg>标签所指定。即在launch文件中存在以下定义:

<arg name="my_varible_name" value="defined_value">

这样在解析my_varible的值的时候才能正常进行。就如同你在表达式中用一个变量进行计算,你必须在计算之前就已经定义过这个变量才可以。
再如:

<node name="add_client" pkg="beginner" type="add_client" args="$(arg a) $(arg b)" />

其中的$(arg a)$(arg b)则是对节点所需要的变量进行声明,这样你在对节点进行参数传递的时候就可以用以下代码进行:

roslaunch beginner launch_file.launch a:=1 b:=5

假设以上代码是launch_file.launch中的片段,则在调用文件时要按所声明的变量名称要求进行参数的赋值。

2.7 $(eval <expression>)

允许计算任意复杂的表达式,而标识符(Tag)或说是标签eval其实是evaluation的前几个字母,表示计算评估的意思,而后面则可以使用表达式。
例如:

<param name="circumference" value="$(eval 2.* 3.1415 * arg('radius'))"/>

会根据给定的'radius'进行计算后对circumference赋值。作为限制,$(eval)的作用范围要跨越表示整个表达式的字符串,如果在其中插入其它属性是不可行的。
例如:

<param name="a_name" value="$(arg r_dis) $(eval 6*7) bar"/>

是不可行的。但可以:

"$(eval arg('sth') + env('PATH') + 'bar' + find('pkg'))"

在内部进行字符串相加操作。

3. IF 和 UNLESS 属性

所有的标签都支持if和unless属性,此类属性是基于计算的值包含或是排除一个标签的内容。

if = value (optional) 

如果value的值为真则包含标签及内容。

unless = value (optional) 

如果值为假,则包括此内容。

<group if="$(arg value)">  <!-- 如果值为真,则包含写在group里的内容 --></group><param name="varible_name" value="sth" unless="$(arg value)" />  <!-- 如果判断的值为真则不包含parma定义的变量 -->

4. 参考标签

4.1 <launch/>

<launch>标签为所有roslaunch文件的根标签,可以将其理解为所有其它标签的容器。以下为<launch>标签与其它标签的关系:

<launch>与其它标签的关系:

<launch>    <node/>    <param/>    <remap/>    <machine/>    <rosparam/>    <include/>    <env/>    <test/>    <arg/>    <group/></launch>

4.2 <node/>

用来启动节点,但不保证节点的启动顺序。其包含的属性如下所示:

pkg="mypackage"<!--指定所用的包-->type="nodetype"<!--指定对应的可执行程序的名字-->name="nodename"<!--指定节点名称,但不能在这里加入命名空间名称-->args="arg1 arg2 arg3"<!--声明或传递参数(optional)-->machine="machine-name"<!--在指定的机器上启动节点(optional)-->respawn="true"<!--如果节点失败则重新启动(optional)-->respawn_delay="30" <!--如果上rospawn属性为真,则等待一定的时间之后重新启动节点(optional, New in indigo)-->required="true"<!--将节点定义为必需节点,如果本节点失效,则关闭整个文件(optional)-->ns="nnss"<!--在一个命名空间中启动节点(optional)-->clear_params="true|false"<!--在节点启动之前是否清空所在命名空间中的变量(optional)-->output="log|screen"<!--指定输出的对象(optional)-->cwd="ROS_HOME|node"<!--指定node则节点工作路径与其可执行程序路径相同(optional)-->launch-prefix="prefix arguments"<!--预先处理指令或参数(optional,支持多种工具)-->

<node>节点作用范围之内可以使用的标签如下:

<node>    <env/>    <remap/>    <rosparam/>    <param/></node>

4.3 <param/>

用于在参数服务器中定义参数。其属性参数如下所示:

name="namespace/name"

参数名称。在这个名称定义中是可以使用命名空间的,而在node的名称定义中不能使用命名空间,这个是有区别的。但是应该避免指定全局的名称。

value="value"

定义参数的值,如果这一属性忽略掉了,但必须指定其它的文件或是命令等(optional)。

type="str|int|double|bool|yaml"

指定参数的类型(optional),如果不指定则会自动识别类型,规则如下:
1.有“.”的认为是浮点数,没有的则认为是整型。
2.”true” 和 “false” 被认为是逻辑变量 (not case-sensitive)。
3.其它的所有都为string型。

textfile="$(find pkg-name)/path/file.txt"

文件的内容被存储为string类型用以替代目标变量(optional)。

binfile="$(find pkg-name)/path/file"

内容将被存储为 base64-encoded XML-RPC 二进制对象用以替代目标变量(optional)。

command="$(find pkg-name)/exe '$(find pkg-name)/arg.txt'"(optional)

执行某项命令,命令的输出将被存储为一个string类型以替代目标变量。

举个栗子:

<param name="publish_frequency" type="double" value="10.0" />

以上代码就是在参数服务器中定义一个名为:publish_frequency,类型为:double,值为:10.0 的变量。

如果是加载YAML文件可以用以下代码:

<rosparam command="load" file="FILENAME" />

其中的file属性要指定路径和文件名。

4.4 <rosparam/>

支持从YAML文件进行参数的读取与卸载。其属性如下所示:

command="load|dump|delete" (optional, default=load)

rosparam的命令,可以指定 加载|卸载|删除 对应的参数。

file="$(find pkg-name)/path/my.yaml" (load or dump commands)

指定文件所要求的路径。
举个例子:

<rosparam command="load" file="$(find rosparam)/example.yaml" /><rosparam command="delete" param="my/param" /><rosparam param="a_list">[1, 2, 3, 4]</rosparam>

第一行代码是用来加载对应的YAML文件,第二代码是删除名为my的命名空间下的param变量,第三行代码是定义一个变量,而变量的值即为标签之间的所有内容 ,即将中间的所有内容作为字符串放入到变量a_list中。

param="param-name"

指定参数名称。

ns="namespace" (optional)

将参数设置到指定的命名空间。

subst_value=true|false (optional)

设置在YAML文本中是否允许使用替代标签。
举个栗子:

<arg name="whitelist" default="[3, 2]"/><rosparam param="blacklist" subst_value="True">$(arg whitelist)</rosparam>

如果在上一行代码中subst_valuefalse,则输出的blacklist只是一个字符串$(arg whitelist),表示不允许使用替代标签,但如果为true则表示允许使用替代标签,则blacklist输出的值为[3,2]

4.5 <remap/>

用来通过名称进行参数之间的映射。其属性如下:

from="original-name"

指定节点原来要监听的话题的名称。

to="new-name"

指定节点实际要监听的话题的名称。
例如:

<remap from="chatter" to="hello"/>

此行代码表明要将原来应监听chatter话题的节点改到监听hello话题。

4.6 <machine/>

如果在本地启动所有节点,则并不需要此标签,且此标签在F版本的ROS前后语法上是不同的,要参考对应的版本,这一标签内容在当前的任务暂时用不到,先挖个坑放这里。

4.7 <include/>

此标签允许在launch文件中包含其它的roslaunch文件或XML文件等。其属性如下所示:

file="$(find pkg-name)/path/filename.xml"

指定要包含的文件路径。

ns="namespace_name" (optional)

指定要导入文件的命名空间。

clear_params="true|false" (optional Default: false)

以上代码意味着在文件加载之前是否要清空所有命名空间中的参数,缺省为false,此参数要谨慎使用,用之前要核对好命名空间名称。

pass_all_args="true|false" (optional Default: false) 

这一属性选择是否将当前情景下的参数传递到子情景之中。
<include>标签范围内可以使用的标签如下:

<include>    <env/>    <arg/></include>

4.8 <env/>

此标签用来设置接下来要启动的节点的环境变量,其可以在<launch>,<include>,<node><machine>标签中使用。当在<launch>中使用时,<env>标签作用于其后声明的所有节点。但是用此标签声明的环境变量通过$(env …)不可见,所以并不能用$(env …)对其它变量的值进行置换,所以<env>标签不能用来参数化launch文件。其属性如下所示:

name="environment-variable-name"

此属性用来设置环境变量名称。

value="environment-variable-value"

此属性用来设置环境变量值。

4.9 <test/>

<test>标签在语法上类似于<node>标签,都是指定一个ROS节点运行,但是<test>标签表明当前要运行的节点是一个测试节点。

<test><node> 具有大部分相同的属性,但以下内容是不同的:
• 没有respawn属性 (测试节点必须要被终止,所以它们没有重启属性)
• 没有输出属性,因为测试节点有其输出记录机制。
• Machine属性被忽略。

<test>标签所必须的几个属性如下:

pkg="mypackage"

这一属性是必需的属性,指定节点的包名称。

test-name="test_name"

必须的属性,指定测试节点的名称。

type="nodetype"

必须的属性,指定测试节点所对应的可执行程序名称。
<test>标签可选择的属性如下:

name="nodename"

节点名称。PS:名称中不能包含命名空间,如果要指定要使用ns属性,如果此属性未指定,则test-name将被作为节点名称。

args="arg1 arg2 arg3"

用测试节点传递参数。

clear_params="true|false"

如果是true,则在启动之前清空当前节点私有命名空间中的全部参数。

cwd="ROS_HOME|node"

指定工作路径。如果是node则节点的工作目录与节点的可执行程序目录相同。

launch-prefix="prefix arguments"

节点启动之前的预置参数或命令。

ns="namespace_name"

在指定的命名空间中启动节点。

retry="0"

用于有时可能失效的随机过程,设置重新尝试的次数。

time-limit="60.0"

认定节点启动失败之前要经历的时间,缺省为60s。
例如:

<test test-name="test" pkg="mypkg" type="test.py" time-limit="10.0" args="--test1 --test2" />

上行代码指定要测试的节点的名称,包名称,可执行程序名称,测试时间跨度和要传递的参数。
标签的作用范围中可以使用以下标签:

<test>    <env/>    <remap/>    <rosparam/>    <param/></test>

4.10 <arg/>

<arg>指令允许创建可以通过传递参数值进行重复使用与配置的launch文件。但<arg>标签是非全局的,一个声明只针对一个launch文件,如同局部变量一样,如果要在其它文件中使用,则必须要明确的进行值传递。

标签的属性有以下几种:

name="arg_name"

指定变量名。

default="default value" (optional)

指定变量缺省值,不能与value属性一起使用。

value="value" (optional)

指定变量值,不能与default属性一起使用。

doc="description for this arg" (optional) New in Indigo

进行变量描述。

<arg>可以通过以下三种方式使用:

(1) 声明变量的存在

<arg name="variable_name" />

对于只进行了变量声明的变量,必须通过参数传递进行使用,通过命令行传递或通过<include>标签进行传递。
(2) 声明变量,并赋予一个缺省值

<arg name="variable_name" default="1" />

可以通过命令行或<include>标签进行值传递使用。
(3) 用一个常量定义变量,值不能被覆盖

<arg name="variable_name" value="defined_somevalue" />

这种用法可以内部参数化而不需要将参数化过程暴露于更高层次,意思就是如果你是用value属性对值直接进行定义的,那么你是无法再你其传递参数,即不能对变量值进行覆写。

例如:在test.launch中写入以下代码:

<launch>    <include file="$(find your_pkg)/launch/included.launch">        <arg name="s_name" value="rose" />    </include></launch>

而在included.launch中写入以下代码:

<launch>   <arg name="s_name" />    <param name="param" value="$(arg s_name)"/></launch>

则当运行test.launch文件时,s_name参数会从test.launch的<include>中传递进入included.launch文件中,从而产生一个变量名为param而值为rose的变量。但是由于<arg>定义的为一个文件内部的局部变量(类似于类内的私有变量),无法从更高一级或外部进行访问,即不能通过命令行进行赋值,所以,当运行:

roslaunch %YOUR_ROS_PKG% test.launch s_name:=my_value

时,s_name的值还是原来设定的value值,而不管你在局部的<arg>属性中是用value属性还是default属性。如果想用自己的定义值在命令行中进行覆盖,则<arg>标签要使用更高一层级的default属性指定。即修改test.launch如下所示:

<launch>    <arg name=”temp”  default=”rose”/>    <include file="$(find your_pkg)/launch/included.launch">        <arg name="s_name" value="$(arg temp)" />    </include></launch>

即定义一个更高一层次的<arg>标签来执行值传递,从更高一层级传递到局部再传递到included.launch文件中。

4.11 <group/>

<group>标签可以对一组节点进行设置,并且可以通过ns属性将一组节点放到一个隔离开的命名空间中。
其具有以下属性:

ns="namespace" (optional)

将一组节点指定到一个特定的命名空间中,命名空间可以是全局的或是局部的,但并有推荐使用全局的命名空间。

clear_params="true|false" (optional)

在节点启动之前清空<group>命名空间中的所有参数,谨慎使用。
内部可使用的标签如下所示:

<group>    <node/>    <param/>    <remap/>    <machine/>    <rosparam/>    <include/>    <env/>    <test/>    <arg/><group/>

5. launch文件的例子

5.1 一个简单的例子:

<launch>  <node name="talker" pkg="rospy_tutorials" type="talker" /></launch>

在本地使用当前ros环境启动rospy_tutorials包中的可执行程序为talker的节点,节点名称定义为talker

5.2 一个复杂一点的例子:

<launch>   <machine name="local_alt" address="localhost" default="true" ros-root="/u/user/ros/ros/" ros-package-path="/u/user/ros/ros-pkg" />    <!-- 本地的机器已经进行了缺省定义,这个标签的作用是用指定的ROS_ROOT和ROS_PACKAGE_PATH值对其重新赋值-->  <node name="listener-1" pkg="rospy_tutorials" type="listener" />  <!-- 启动一个收听节点 -->  <node name="listener-2" pkg="rospy_tutorials" type="listener" args="-foo arg2" />  <!-- 向监听节点中传递参数 -->  <node name="listener-3" pkg="rospy_tutorials" type="listener" respawn="true" />  <!-- 一个可以重新启动的节点 -->  <node ns="wg1" name="listener-wg1" pkg="rospy_tutorials" type="listener" respawn="true" />  <!-- 在 'wg1' 命名空间中启动一个节点 -->  <group ns="wg2">  <!-- 在 'wg2' 命名空间中启动一组节点 -->    <remap from="chatter" to="hello"/>    <!-- remap在group范围内作用于在其后声明的所有节点 -->    <node pkg="rospy_tutorials" type="listener" name="listener" args="--test" respawn="true" />    <node pkg="rospy_tutorials" type="talker" name="talker">      <param name="talker_1_param" value="a value" />      <!-- 设置局部变量 -->      <remap from="chatter" to="hello-1"/>      <!-- 节点可以有其自己私有的remap指令 -->      <env name="ENV_EXAMPLE" value="some value" />      <!-- 为节点设置环境变量 -->    </node>  </group></launch>

5.3 设置参数

<launch>  <param name="somestring1" value="bar" />  <!-- 值类型为string类型 -->  <param name="somestring2" value="10" type="str" />  <!-- 强制使用string类型而不是整型定义参数 -->  <param name="someinteger1" value="1" type="int" />  <!-- 指定为整型 -->  <param name="someinteger2" value="2" />  <!-- 自动识别为整型 -->  <param name="somefloat1" value="3.14159" type="double" />  <!-- 指定为浮点型数据 -->  <param name="somefloat2" value="3.0" />  <!-- 自动识别为浮点型数据 -->  <param name="wg/childparam" value="a child namespace parameter" />  <!-- 在子命名空间中设置参数 -->  <param name="configfile" textfile="$(find roslaunch)/example.xml" />  <!-- 向参数服务器中加载文本文件内容 -->  <param name="binaryfile" binfile="$(find roslaunch)/example.xml" />  <!-- 向参数服务器中加载二进制文件内容 --></launch>
阅读全文
0 0
原创粉丝点击