launch文件的來龍去脈


  在節點少,程序小的情況下可以一個一個節點來啟動,測試運行效果,但是當工程規模大,需要的節點多時就顯得比較費勁,用.launch文件來啟動可以將需要的節點同時啟動,不用再一個一個進行。為工程搭建提高了效率,里面還有很多參數靈活使用會帶來非常高效的調試。

1 <launch>
2   <node pkg="ros_tutorials_topic" type="topic_publisher" name="topic_publisher1"/>
3   <node pkg="ros_tutorials_topic" type="topic_subscriber" name="topic_subscriber1"/>
4   <node pkg="ros_tutorials_topic" type="topic_publisher" name="topic_publisher2"/>
5   <node pkg="ros_tutorials_topic" type="topic_subscriber" name="topic_subscriber2"/>
6 </launch>

 pkg="ros_tutorials_topic"為對應的功能包的名稱

type="topic_publisher" 節點對應的可執行文件名,一般為.cop的文件名字ros::init(argc,argv,"topic_publisher"); //初始化發布者節點名稱對應

name="topic_publisher1"運行時顯示的節點名稱,也就是用命令rosnode list 所看到的節點列表里的名稱。這兒定義的名字優先會覆蓋可執行程序(如.cpp里面init()賦予的節點名)當兩者不一樣是以name為准。

查看運行效果:

1 roslaunch ros_tutorials_topic topic.launch --screen//--screen是將通信消息發送到屏幕端

1 roslaunch ros_tutorials_topic topic.launch //沒有--screen屏幕上不顯示通信的消息,但是會正常收發,只是不在終端顯示

  查看節點列表:

查看節點關系圖:rqt_graph,從圖中看到兩個發布者同時向兩個訂閱者發布消息,原因是我們只改變了節點的名稱,而沒有改變要使用的消息名字,下面在launch文件里添加一個命名空間標記就可以解決。

  •  respawn="true" 當roslaunch啟動完所有該啟動的節點之后,會監測每一個節點,保證它們正常的運行狀態。對於任意節點,當它終止時,roslaunch 會將該節點自動重啟
  • required="true" 必要節點,這個出問題了,整個launch結束;注意此屬性不可以與respawn="true"一起描述同一個節點

 

 修改后的launch文件如下;output="screen“,用於將話題信息打印到屏幕。roslaunch ros_tutorials_topic topic.launch后面不用加 --screen也可以實現屏幕顯示信息。

 1 <launch>
 2  <group ns="ns1">
 3   <node pkg="ros_tutorials_topic" type="topic_publisher" name="topic_publisher" output="screen"/>
 4   <node pkg="ros_tutorials_topic" type="topic_subscriber" name="topic_subscriber" output="screen"/>
 5  </group>
 6  <group ns="ns2">
 7   <node pkg="ros_tutorials_topic" type="topic_publisher" name="topic_publisher" output="screen"/>
 8   <node pkg="ros_tutorials_topic" type="topic_subscriber" name="topic_subscriber" output="screen"/>
 9  </group>
10 </launch>

運行查看:roslaunch ros_tutorials_topic topic.launch

 

 查看節點關系圖:

  • group標簽對node的批量管理,可以同時終止在同一個group中的節點
<group if="1-or-0">
……
……
……
</group>

<group unless="1-or-0">
……
……
……
</group>

  第一種情況,當if屬性的值為0的時候將會忽略掉<group>       </group>之間的標簽。第二種恰好相反,當if屬性的值為1的時候將會忽略掉<group>       </group>之間的標簽。但是我們通常不會直接用1或0來定義if標簽。因為這樣不夠靈活。通常會搭配$(arg arg_name)來使用。


 

  •  <remap>重映射
  在上圖中我們看到topic_publisher發布的話題是ros_tutorial_msg,topic_subscriber接收的話題同樣是ros_tutorial_msg,它們才能形成通訊
ros::Publisher ros_tutorial_pub = nh.advertise<ros_tutorials_topic::MsgTutorial>("ros_tutorial_msg", 100);(在
topic_publisher.cpp中
ros::Subscriber ros_tutorial_sub =nh.subscribe<ros_tutorials_topic::MsgTutorial>("ros_tutorial_msg", 100, msgCallback);

(在topic_subscriber.cpp中),只有這兩者對應起來才能,接收和發布的話題相同才能成功通訊。
  然而在使用別人給的功能包時候,自己發送的話題和它接收的可能名稱不同,但是內容,格式相同,這時候我們就可以在launch進行重映射。
ros::Publisher ros_tutorial_pub = nh.advertise<ros_tutorials_topic::MsgTutorial>("ros_tutorial_msg", 100);(在topic_publisher.cpp中
ros::Subscriber ros_tutorial_sub =nh.subscribe<ros_tutorials_topic::MsgTutorial>("remap/ros_tutorial_msg", 100, msgCallback);

(在topic_subscriber.cpp中),這時候訂閱者訂閱的話題為"remap/ros_tutorial_msg",發布者發布的話題為“ros_tutorial_msg",這時就不能進行通訊,需要發生重映射。

在沒有加重映射之前啟動節點查看話題會看到如下結果

如果把launch文件的話題進行一個重映射如下(最好將映射放到node標簽的前面,這樣后面所有使用這個話題的節點都可以更新

<launch>
<remap from="ros_tutorial_msg" to="remap/ros_tutorial_msg"/> <group ns="ns1"> <node pkg="ros_tutorials_topic" type="topic_publisher" name="topic_publisher" output="screen"/> <node pkg="ros_tutorials_topic" type="topic_subscriber" name="topic_subscriber" output="screen"/> </group> <group ns="ns2"> <node pkg="ros_tutorials_topic" type="topic_publisher" name="topic_publisher" output="screen"/> <node pkg="ros_tutorials_topic" type="topic_subscriber" name="topic_subscriber" output="screen"/> </group> </launch>
<remap from="ros_tutorial_msg" to="remap/ros_tutorial_msg"/>這樣寫意味着將ros_tutorial_msg變為remap/ros_tutorial_msg,其實是將發布者發布的話題修改

 

<remap from="remap/ros_tutorial_msg" to="ros_tutorial_msg"/>這樣寫意味着將remap/ros_tutorial_msg變為ros_tutorial_msg,其實是將訂閱者訂閱的話題修改,一般用這種比較多,也容易理解,意思是,我訂閱者想訂閱一個話題但是你的跟我想要的不同,那么我就將自己的話題映射成與你發布的一樣就可以啦。

 

 

  • 當然也可以將<remap>作為節點的子類包含在節點中(只更新該節點的訂閱消息)
<launch>
 <group ns="ns1">
  <node pkg="ros_tutorials_topic" type="topic_publisher" name="topic_publisher" output="screen"/>
  <node pkg="ros_tutorials_topic" type="topic_subscriber" name="topic_subscriber" output="screen"/>
  <remap from="remap/ros_tutorial_msg" to="ros_tutorial_msg"/>
</node> </group> <group ns="ns2"> <node pkg="ros_tutorials_topic" type="topic_publisher" name="topic_publisher" output="screen"/> <node pkg="ros_tutorials_topic" type="topic_subscriber" name="topic_subscriber" output="screen"/> </group> </launch>
 
        

 

 

 

  •  <param>參數的用法:

參數的用法——利用參數創建節點中我們利用命令(rosparam set /calculation_method  2)改變參數calculation_method“來實現加減乘除運算,那么現在我們launch參數命令來改變程序中的參數,看看會是什么效果。

  sevice.launch文件如下:順便啟動服務器節點去等待客戶端請求

 

<launch>
  <param name="calculation_method" type="int" value="3" />
  <node pkg="ros_tutorials_service" type="service_server" name="service_server" output="screen"/>
  
</launch>

同時將這句屏蔽//nh.setParam("calculation_method", PLUS);(在service_server.cpp中),我們從launch文件中給定參數。然后編譯運行:

 


 

<arg>參數的用法:

  arg雖然也是參數命令,但不儲存在參數服務器中,不能提供給節點使用,只能在launch文件中使用,用來在運行中或直接在文件中修改launch文件中被arg定義的變量中。param則是儲存在參數服務器中,可以被節點使用,這是最本質的區別。

  還以現在這個例子來說,<param name="calculation_method" type="int" value="3" />將節點中參數的值賦值為3是進行乘法運算,但是當要進行除法運算時要求將參數變為4,但是在運行時,在launch中變為4,還得編譯重新運行,那么用arg來定義一個變量,用這個變量去改變calculation_method的值就實現的運行過程中的改變:launch文件內容變為如下:

<launch>
  <arg name="updata_value" default="1"/>
  <param name="calculation_method" type="int" value="$(arg updata_value)" />
  <node pkg="ros_tutorials_service" type="service_server" name="service_server" output="screen"/>
</launch> 

  開始默認為1,運行加法運算,那么在運行是我們將其值變為4,執行除法運算:roslaunch ros_tutorials_service service.launch updata_value:=4

<arg name="arg-name" default="arg-value" />  注意default定義的值在roslaunch時才可以改變
<arg name="arg-name" value="arg-value" />    注意value定義的值在roslaunch時不可以改變


 

  • <rosparam>加載一個.yaml的配置文件

   在上面我們實現了在launch文件中修改程序的參數問題。但是想象一下如果有成千上萬個參數的時候我們該怎么改,也這樣一句句定義是不現實的。那就用rosparam加載一個配置文件來實現。在功能包下面建一個config文件夾,放入參數配置文件service.yaml;內容為calculation_method: 3;(執行乘法運算)

 

 

 launch文件內容變為:

<launch>

  <node pkg="ros_tutorials_service" type="service_server" name="service_server" output="screen"/>

  <rosparam command="load" file="$(find ros_tutorials_service)/config/service.yaml"/>
</launch>

編譯執行效果為:

 

 


 

  •  <include>的用法

  <include>用於包含其它launch文件,被包含的launch文件將會被一同啟動。

  <include file="$(find pkg_name)/launch/demo.launch"/> 

  • 如果要給<include > 包含進來的launch元素賦值,由於arg是局部的只能改變本launch文件的參數值,因此需要建立一個包含在<include >標簽之間的arg.格式如下:

<include file="path-to-launch-file">
<arg name="arg-name" value="arg-value"/>
. . .
</include>

  • 如果改變<include > 包含進來的launch元素用的arg名稱與本launch文件的一樣的話需寫為如下格式:位置還放在上面<include >標簽之間

<arg name="arg-name" value="$(arg arg-name)" />

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM