1. roslaunch 命令
roslaunch 命令允許我們一次啓動 launch 文件中定義的多個 ROS 節點,啓動參數等在啓動文件(launch 文件)中配置,並且如果系統之前沒有啓動 roscore,則 roslaunch 會自動啓動它。
roslaunch 的命令行用法如下:
roslaunch [package] [filename.launch]
例如:
roslaunch beginner_tutorials turtlemimic.launch
其中 beginner_tutorials 是 turtlemimic.launch 文件中定義的一個節點,那 launch 文件是什麼呢?我們來看下。
2. 解析 launch 文件
簡單來說 launch 文件就是一堆節點和參數的集合,使用 launch 文件的目的是爲了一鍵啓動。因爲目前運行在機器人上的 ROS 系統一般都要同時運行多個節點,如果我們開機啓動時,一個一個的輸入命令來啓動每一個節點,想想就可怕,所以 ROS 系統就給我們提供了這麼一個 launch 文件,可以方便我們將要啓動的節點和對應的參數全部寫到這個文件中,然後使用 roslaunch 命令一鍵啓動!
一個 lanunch 文件例子:
<launch>
<!-- local machine already has a definition by default.
This tag overrides the default definition with
specific ROS_ROOT and ROS_PACKAGE_PATH values -->
<machine name="local_alt" address="localhost" default="true" ros-root="/u/user/ros/ros/" ros-package-path="/u/user/ros/ros-pkg" />
<!-- a basic listener node -->
<node name="listener-1" pkg="rospy_tutorials" type="listener" />
<!-- pass args to the listener node -->
<node name="listener-2" pkg="rospy_tutorials" type="listener" args="-foo arg2" />
<!-- a respawn-able listener node -->
<node name="listener-3" pkg="rospy_tutorials" type="listener" respawn="true" />
<!-- start listener node in the 'wg1' namespace -->
<node ns="wg1" name="listener-wg1" pkg="rospy_tutorials" type="listener" respawn="true" />
<!-- start a group of nodes in the 'wg2' namespace -->
<group ns="wg2">
<!-- remap applies to all future statements in this scope. -->
<remap from="chatter" to="hello"/>
<node pkg="rospy_tutorials" type="listener" name="listener" args="--test" respawn="true" />
<node pkg="rospy_tutorials" type="talker" name="talker">
<!-- set a private parameter for the node -->
<param name="talker_1_param" value="a value" />
<!-- nodes can have their own remap args -->
<remap from="chatter" to="hello-1"/>
<!-- you can set environment variables for a node -->
<env name="ENV_EXAMPLE" value="some value" />
</node>
</group>
</launch>
下面是一個簡單的 launch 文件格式,我帶你一步一步解析它的標籤用法:
<launch>
<node .../>
<rosparam .../>
<param .../>
<include .../>
<env .../>
<remap .../>
<arg .../>
<group> </group>
</launch>
2.1 launch
launch 標籤是 launch 文件的根節點,它只作爲其他子標籤的容器,沒有其他功能。
<launch>
...
</launch>
2.2 node
node 標籤指定一個將要運行的 ROS 節點,node 標籤可以說是 launch 文件中最重要的標籤,因爲我們配置 launch 文件的目的就是一次啓動多個 ROS node。
常見的用法如下:
<node name="bar1" pkg="foo_pkg" type="bar" args="--test" respawn="true" output="sceen">
- name:節點名稱 bar1
- pkg:節點所在的包 foo_pkg
- type:節點類型是可執行文件(節點)的名稱,項目中必須要有一個相同名稱的可執行節點
- args:命令行啓動參數 --test
- respawn:是否自動重啓,true 表示如何節點未啓動,則自動重啓,false 則不重啓,默認 false
- output:是否將節點信息輸出到屏幕,如果不設置該屬性,則節點信息會被寫入到日誌文件
在 node 標籤下頁可以嵌套使用以下標籤:
- env:爲節點設置環境變量
- remap:爲節點設置重映射參數
- rosparam:爲節點加載 rosparam 文件
- param:爲節點設置參數
2.3 param
在項目中某些參數需要經常改變,如果在程序中寫死了,以後我們每次修改參數都需要重新 build 一遍程序,非常麻煩,param 便籤給我們提供了一個傳遞參數的方法。
param 標籤定義一個將要被設置到參數服務器的參數,它的參數值可以通過文本文件、二進制文件或命令等屬性來設置,另外 param 標籤可以嵌入到 node 標籤中,以此來作爲該 node 的私有參數。
常見用法如下:
<param name="publish_frequency" type="double" value="10.0">
- name:參數名稱 publish_frequency
- type:參數類型 double,str,int,bool,yaml
- value:參數值 10.0
param 標籤也可以爲一組 group 節點同時設置參數。
2.4 remap
remap 標籤提供了一種節點名稱的重映射方法,每個 remap 標籤包含一個元素名稱和一個新名稱,在系統運行後原始名稱會被替換爲新名稱。
常見用法如下:
<remap from="chatter" to="hello">
- from:原始名稱
- to:新名稱
可以這樣理解這個替換標籤:你有一個節點訂閱了「chatter」主題,但是你只有一個節點發布「hello」主題,而「hello」和「chatter」的類型相同,所以我們可以將「chatter」簡單地替換爲「hello」,從而實現訂閱「hello」主題。
2.5 machine
machine 標籤定義了節點所運行的機器信息,如果只是在本地運行節點則不需要配置這個標籤,它主要使用在 SSH 和遠程機器,不過也可以用來配置本地機器的相關信息。
常見用法如下:
<launch>
<machine name="foo" address="foo-address" env-loader="/opt/ros/kinetic/env.sh" user="someone">
<node machine="foo" name="footalker" pkg="test_ros" type="talker.py">
</launch>
- name:機器名稱
- address:機器的網絡地址
- env-loader:設置機器的環境變量,必須是一個設置了所有要求變量的 shell 腳本
- user:用戶名稱
2.6 rosparam
rosparam 標籤允許節點從參數服務器上 load、dump 和 delete YAML 文件,也可以使用在遠程機器上,需要注意的是 delete 必須在 load 或者 dump 之後進行。
常見用法如下:
# 參數較多使用 yaml 文件
<rosparam command="load" file="$(find rosparam)/example.yaml">
<rosparam command="delete" param="my/param">
# 傳遞數組
<rosparam param="a_list">[1, 2, 3, 4]</rosparam>
<rosparam>
a: 1
b: 2
</rosparam>
<arg name="whitelist" default="[3, 2]"/>
<rosparam param="whitelist" subt_value="True">$(arg whitelist)</rosparam>
- command:load,dump,delete
- file:參數文件的路徑
- param:參數名稱
- subt_value:是否允許在 YAML 中替換參數
補充下 yaml 文件基本用法,yaml 文件就是單純的來存儲啓動參數,格式如下:
a: 1
str: hello
c: 2.0
其中不需要指定變量類型,yaml 文件會自動確定類型。使用 yaml 文件的目的就是方便配置參數,如果有很多參數需要配置,不需要寫很多 rosparam 命令。
yaml 文件還有挺多複雜的寫法,後續項目中用到再總結出來。
2.7 include
include 類似編程語言中的 include 預處理,它可以導入其他 roslaunch 的啓動文件到當前 include 標籤所在的位置。
常見用法如下:
<include file="$(find package_name)/launch_file_name">
項目中使用絕對路徑不太方便,可以使用 find 來查找。
2.8 env
env 標籤可以在啓動的節點上設置環境變量,這個標籤基本只會使用在 launch、include、node、machine 這 4 個標籤內部,當使用在 launch 內部時,env 設置的環境標量會應用到內部定義的節點。
常見用法如下:
<env name="ENV_EXAMPLE" value="some value" />
- name:環境變量名稱
- value:環境變量值
2.9 test
test 標籤在語法上類似 node 標籤,但在功能上只表示當前的節點作爲測試節點去運行。
常見用法如下:
<test test-name="test_1" pkg="my_pkg" type="test_1.py" time-limit="10.0" args="--test1">
- test-name:測試節點名稱
- pkg:測試節點所在的包
- type:測試節點類型
- time-limit:超時時間
- arg:測試節點啓動的命令參數
2.10 arg
arg 標籤表示啓動參數,該標籤允許創建更多可重用和可配置的啓動文件,其可以通過命令行、include 標籤、定義在高級別的文件這 3 種方式配置值。
arg 標籤聲明的參數不是全局的,只能在聲明的單個啓動文件中使用,可以當成函數的局部參數來理解。
常見用法如下:
# 1. 命令行傳遞啓動參數
roslaunch my_file.launch my_arg:=my_value
# 2. 定義時賦值
<arg name="arg_name" default="arg_name">
<arg name="arg_name" value="arg_name">
這兩者有點區別,命令行傳遞的 arg 參數可以覆蓋 default,但不能覆蓋 value。
# 3. 通過 launch 文件傳遞,兩個 launch 文件中的 arg 參數值必須相同!
# my_file.launch
<include file="include.launch">
<arg name="hoge" value="fuga">
</include>
# include.launch
<launch>
<arg name="hoge" value="fuga">
</launch>
注意 arg 和 param 標籤的區別:
- arg:啓動時參數,只在啓動文件 launch 中有意義
- param:運行時參數,存儲在參數服務器中
2.11 group
group 標籤可以方便的將一組配置應用到組內的所有節點,它也具有命名空間 ns 特點,可以將不同的節點放入不同的 namespace。
常見用法如下:
<group ns="namespace">
<node pkg="pkg_name1" .../>
<node pkg="pkg_name2" .../>
...
</group>
配合 if 和 unless 使用:
- if=value:value 爲 true 則包含內部信息
- unless=value:value 爲 false 則包含內部信息
<group if="$(arg foo1)">
<node pkg="pkg_name1" .../>
</group>
<group unless="$(arg foo2)">
<node pkg="pkg_name2" .../>
</group>
- 當 foo1 == true 時包含其標籤內部
- 當 foo2 == false 時包含其標籤內部
本文原創首發於 同名微信公號「登龍」,微信搜索關注回覆「1024」你懂的!