ROSLAUNCH 的.launch/XML 語法

最近面臨一個將ROS與機器人結合起來以擴展現有機器人的功能的任務,譬如將ABB的2400機器人接上ROS的moveit,然後通過ROS去控制機器人的運動,對於IRB2400這樣的機器人實現還是蠻簡單的,但是這種情況下,只知其然而不知其所以然,感覺就不好了,所以我得將這一套東西徹底的理解清楚,整理明白。在這裏碼下來記錄一下我的學習與經歷的過程,在面對這個問題時,首先想弄明白的就是roslaunch使用的.launch文件中到底寫了些什麼鬼!

對了,roslaunch文件的擴展名爲.launch,是按照XML格式編寫的,所以XML格式的文件也一樣能解析。

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>
發佈了27 篇原創文章 · 獲贊 32 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章