ROS話題訂閱與namespace使用出現的問題彙總
1 什麼情況下會用到namespace(以下簡稱ns)
當我們需要運行同一個pkg的同一個node,雖然可以在launch檔案中給他們命名成不同的name但是,我們希望使用<group ns=""></group>來更加清晰的區分他們之間的不同。但是加上ns後,常常會出現以下問題,需要我們解決。比如,原先不新增ns的時候一切執行正常,但是當我們新增ns後,無法執行等一類問題。
2 理解什麼是namespace
ns就是把你原先執行的pkg---node放到一個名稱空間中去,這個名稱空間就是ns,例如:
<launch> <group ns="name1"> <node pkg="your_pkg" type="your_node_name" name="whatever" /> </group> <group ns="name2"> <node pkg="your_pkg" type="your_node_name" name="whatever" /> </group> </launch>
我們執行的pkg---node---name都可以一樣,但是必須在不同的ns中,這樣ROS才可以區分他們,否則會認為重複,第二個node會覆蓋掉第一個node,這樣始終只有一個node在執行。
在rosnode list 你可以看到:
/name1/whatever
/name2/whatever
而在rostopic list中,所有話題也會被追加上name1和name2
3 新增namespace後提示tf,no laser scan data等問題
這就是由於第二2節中的ns改變了原來會話題的名字。例如,在新增ns之前,該node需要訂閱 /scan的雷達資料,但是新增ns後,雷達的資料釋出的話題追加了ns的名稱空間,變成了/name1/scan ,這時候你再訂閱/scan,肯定是沒有資料的,因為不存在/scan這個話題了,雷達釋出的資料話題從/scan變成了/name1/scan。解決辦法是使用<remap from="/name1/scan" to="/scan" />,這樣的重對映才會使得資料訂閱釋出之間重新構建正確的關係。
同樣,你可以通過檢視rqt_graph來確認你的node是否都正確的訂閱了你的話題,哪些需要remap的,可以很清晰的查閱到。
4 發現你的話題無論怎麼remap,rqt_graph都不發生改變,還是原來的話題
這看起來顯示remap失效了,然而執行launch時沒有報錯,又表明你的話題引數都是存在切正確的。
沒錯,這個也困擾了我很久。
4.1 在使用remap時。要注意remap的作用範圍,remap只能在<node />,<group /><launch />
如果你放在<include />裡面不會報錯也沒有警告,但是命令列會顯示說,“無效的remap”仔細看可以看到。
注意這裡說的在<node />,<group /><launch />下可以有效的使用remap,是在直接tag標籤下,間接地也是不行的。例如:
<launch>
.......
<remap from="xx" to="xx" />
</launch>
這個叫做在<launch>標籤下直接使用,是合法有效的。
但是下面這種就是在<launch>標籤下間接使用,在<include>下直接使用,這樣是無效的。但是執行不會提示error和warnning。這一點要十分注意。
<launch>
.......
<include file="$(find pkg)/.....">
<remap from="xx" to="xx" />
</include>
</launch>
4.2 在解決4.1的正確使用remap後,如果問題仍然沒有解決,那麼就是你的remap沒有正確的尋找到你的話題
這是由於你的話題,你沒有使用絕對路徑導致的。例如:
<launch>
<node pkg="your_pkg" type="your_node_name" name="whatever">
<remap from="name1/scan" to="scan" />
</node>
</launch>
這樣remap後,如果你的話題沒有成功的建立訂閱關係,即讓rqt_graph的圖中name1/scan話題還存在,你的訂閱沒有連線到/scan話題上,那麼就是話題的絕對路徑導致的ROS系統未能找到指定的話題,這個在執行launch時也不會有error和warnning提示。解決辦法就是在話題前加上“/”即可。例如:
<launch>
<node pkg="your_pkg" type="your_node_name" name="whatever">
<remap from="/name1/scan" to="/scan" />
</node>
</launch>
這樣新增上“/”,話題的路徑就變成絕對路徑了。問題就解決了。
5 從yaml檔案像launch檔案傳遞引數
5.1 什麼是yaml檔案
這個概念自行查詢。總結來說就是,yaml檔案存放的是一個字典(可以粗糙的這樣理解,不完全合理!),它有鍵值對成對出現,同樣也可以是巢狀的字典。例如
1.yaml
var1: 12
var2: name
var3: base_link
2.yaml
var1: 2323
var2: {
scan_frame: robot0_laser0
topic: robot0/laser_0
}
var3: robot0
1.yaml是比較典型的沒有巢狀,2.yaml中的var2是巢狀,他的值又是由一個字典組成。
5.2 yaml檔案中的所有的鍵都可以理解成變數,值就是這些變數的初始值,是可以通過rosparam set改變的。當我們在launch檔案中load這個yaml檔案時就是,將這些變數新增到ROS的引數伺服器,並且按照yaml檔案中的值,給這些變數賦予初始值。
這就不難理解了,yaml檔案中的建就是ROS引數伺服器中的引數。因此在launch檔案中,load一個yaml檔案後,可以直接通過<param name=" " value=" " />來修改yaml檔案中的值,
<launch>
<rosparam file="$(find your_pkg)/1.yaml" command="load" />
<param name="var1" value="1222222" />
</launch>
這樣就實現了yaml檔案像launch檔案傳遞引數的功能:
當然你也可以這樣:
<launch>
<arg name="var1_value" default="33333" />
<rosparam file="$(find your_pkg)/1.yaml" command="load" />
<param name="var1" value="$(arg var1_value)" />
</launch>
在ROS的官網,官方也給出了一種方法,我測試過和上面的效果一樣。
如下所示:
rosparam 有一個屬性叫做subst_value,如果設定成true就可以直接修改yaml檔案中的引數預設值。
例子如下:
<launch>
<arg name="whitelist" default="[3, 2]"/>
<rosparam commond="load" file="$(find your_pkg)/...">
<rosparam param="whitelist" subst_value="True">$(arg whitelist)</rosparam>
</launch>
這也是完全正確的。