ROS nodelet的使用


  ROS是一種基於分布式網絡通訊的操作系統,整個機器人控制系統是由一個Master主節點和若干個功能相對獨立的Node子節點組成,這也是ROS系統最主要的特點就是分布式以及模塊化的設計。在ROS通訊過程中Master節點存儲着各個子節點的topics和services的注冊信息,每個功能節點在請求服務之前先向主節點進行注冊,然后節點之間就可以直接進行信息傳遞。ROS的底層通信都是基於XML-RPC協議實現的。    

  XML-RPC協議是XML Remote Prodecure Call的簡稱,是一種遠程過程調用的分布式網絡協議。它允許跨平台的軟件間通過發送和接收XML格式的消息進行遠程調用,即允許不同的操作系統、不同環境中的程序實現基於Internet過程調用的規范和一系列方法的實現。這種遠程過程調用使用http作為傳輸協議,XML作為傳送信息的編碼格式。

  XML-RPC的遠程調用過程為:首先客戶端發起請求后需要按照協議格式對請求信息進行填充;填充完畢以后XML格式的信息會被轉化為數據流,通過傳輸層進行傳輸。服務端收到客戶端發出來的數據流,會將其再轉化為XML格式的信息,然后按照XML-RPC協議獲取客戶端的請求信息,並對請求信息進行處理,處理完畢以后將反饋信息發送給客戶端。

  以XML-RPC的方式傳輸數據存在一定的延時和阻塞。在數據量小、頻率低的情況下,傳輸耗費的時間可以忽略不計。但當傳輸圖像流,點雲等數據量較大的消息,或者執行有一定的實時性要求的任務時,因傳輸而耗費的時間就不得不考慮。Nodelet包就是為改善這一狀況設計的,它提供一種方法,可以讓多個算法程序在一個進程中用 shared_ptr 實現零拷貝通信(zero copy transport),以降低因為傳輸大數據而損耗的時間。簡單講就是可以將多個node捆綁在一起管理,使得同一個manager里面的topic的數據傳輸更快。    

 

 運行nodelet 

  nodelet用法:

nodelet manager               - Launch a nodelet manager node.  啟動一個manager
nodelet load pkg/Type manager - Launch a nodelet of type pkg/Type on manager manager. 向manager中加載nodelet
nodelet standalone pkg/Type - Launch a nodelet of type pkg/Type in a standalone node.
nodelet unload name manager - Unload a nodelet a nodelet by name from manager. 從manager中移除nodelet

 

  下面看一個簡單的nodelet例子,程序會將內部變量value加上輸入in的值,然后再發布到out話題上。首先在終端中運行roscore打開ROS master節點,然后輸入下面指令開啟一個名字為nodelet_manager的manager節點(A nodelet will be run inside a NodeletManager)

rosrun nodelet nodelet manager __name:=nodelet_manager

  注意rosrun命令中可以顯式設置節點的名稱,語法為:rosrun package-name executable-name __name:=node-name  這種方法將使用node-name參數給出的名稱覆蓋節點的默認名。

  然后向創建的nodelet_manager中加載pkg/Type為nodelet_tutorial_math/Plus的nodelet節點,並將其重命名為nodelet1,nodelet1/in話題重映射為foo,value值設為1.1

rosrun nodelet nodelet load nodelet_tutorial_math/Plus nodelet_manager __name:=nodelet1 nodelet1/in:=foo _value:=1.1

  輸入rostopic list命令查看topic:

  輸入rosnode list查看當前運行的節點:

  下面我們在foo話題上發布消息,相當於給in賦值5.0

rostopic pub /foo std_msgs/Float64 5.0 -r 10

  使用rostopic echo查看out的結果:

rostopic echo /nodelet1/out

  可以看出結果為6.1(5.0+1.1=6.1):

  輸入rqt_graph命令,可以在GUI界面中直觀地查看節點間的交互方式 :

rqt_graph 

 

  也可以在roslaunch文件中使用nodelet. 下面的例子中先創建一個名為standalone_nodelet的manager,然后向其中加載Plus和Plus2這兩個nodelet節點:

<launch>
    <node pkg="nodelet" type="nodelet" name="standalone_nodelet"  args="manager" output="screen"/>

    <node pkg="nodelet" type="nodelet" name="Plus" args="load nodelet_tutorial_math/Plus standalone_nodelet" output="screen">
        <remap from="/Plus/out" to="Plus2/in"/>
    </node>          

    <rosparam param="Plus2" file="$(find nodelet_tutorial_math)/plus_default.yaml"/>
    <node pkg="nodelet" type="nodelet" name="Plus2" args="load nodelet_tutorial_math/Plus standalone_nodelet" output="screen">
        <rosparam file="$(find nodelet_tutorial_math)/plus_default.yaml"/>
    </node>

    <node pkg="nodelet" type="nodelet" name="Plus3" args="standalone nodelet_tutorial_math/Plus" output="screen">
        <param name="value" type="double" value="2.5"/>
        <remap from="Plus3/in" to="Plus2/out"/>
    </node>
</launch>

  launch文件中使用remap標簽將Plus的輸出重映射到Plus2的輸入,並將Plus2的輸出重映射到Plus3的輸入上,可以實現疊加功能。

  plus_default.yaml中的內容如下,即Plus2節點中的value值為10:

value: 10

  下面運行plus.launch文件:

roslaunch nodelet_tutorial_math plus.launch

  然后在Plus的輸入端發布數據:

rostopic pub -r 10 /Plus/in std_msgs/Float64 1.0 

  查看Plus2的輸出(1+10=11):

  查看Plus3的輸出(11+2.5=13.5):

   使用rqt_graph命令查看節點:

 

 

 編寫nodelet 

   編寫一個nodelet(nodelet基於pluginlib插件機制)的步驟如下:

  • add the necessary #includes
  • get rid of int main()
  • subclass nodelet::Nodelet (基類nodelet::Nodelet,任何nodelet繼承自它可以使用plugin的方式動態加載)
  • move code from constructor to onInit() (實現onInit純虛函數,用於初始化)
  • add the PLUGINLIB_EXPORT_CLASS macro (加入宏,將子類聲明為插件類,並編譯為動態庫)
  • add <build_depend> and <run_depend> dependencies on nodelet in the package manifest.

  • add the <nodelet> item in the <export> part of the package manifest

  • create the .xml file to define the nodelet as a plugin
  • make the necessary changes to CMakeLists.txt

 

  plus.cpp代碼功能就是兩個數相加:

#include <pluginlib/class_list_macros.h>
#include <nodelet/nodelet.h>
#include <ros/ros.h>
#include <std_msgs/Float64.h>
#include <stdio.h>

#include <math.h> //fabs

namespace nodelet_tutorial_math  // The usage of the namespace is a good practice but not mandatory
{

class Plus : public nodelet::Nodelet
{
public:
  Plus(): value_(0)
  {}

private:
  virtual void onInit() //當nodelet插件類被nodelet_manager加載時,nodelet插件類的onInit方法就會被調用,用於初始化插件類
  {
    ros::NodeHandle& private_nh = getPrivateNodeHandle();
    private_nh.getParam("value", value_);
    pub = private_nh.advertise<std_msgs::Float64>("out", 10);
    sub = private_nh.subscribe("in", 10, &Plus::callback, this);
  }

  void callback(const std_msgs::Float64::ConstPtr& input)
  {
    std_msgs::Float64Ptr output(new std_msgs::Float64());
    output->data = input->data + value_;
    NODELET_DEBUG("Adding %f to get %f", value_, output->data);
    pub.publish(output);
  }

  ros::Publisher pub;
  ros::Subscriber sub;
  double value_;
};

PLUGINLIB_DECLARE_CLASS(nodelet_tutorial_math, Plus, nodelet_tutorial_math::Plus, nodelet::Nodelet);
}

  注意為了允許類被動態加載,它必須被標記為導出類。這通過特殊宏PLUGINLIB_EXPORT_CLASS/PLUGINLIB_DECLARE_CLASS來完成,通常放在導出類的.cpp文件的末尾。 宏的參數分別為:pkg, class_name, class_type, base_class_type. 

 

  為了讓pluginlib查詢ROS系統上的所有可用插件,每個包必須顯式指定它導出的插件。相應的package.xml中要加入下面內容:

...
<build_depend>nodelet</build_depend>
<run_depend>nodelet</run_depend>

<export> <nodelet plugin="${prefix}/nodelet_math.xml" /> </export> ...

 

  插件描述文件是一個XML文件,用於存儲有關插件的所有重要信息。 它包含有關插件所在的庫的信息,插件的名稱,插件的類型等 。nodelet_math.xml如下:

<library path="lib/libnodelet_math">
  <class name="nodelet_tutorial_math/Plus" type="nodelet_tutorial_math::Plus" base_class_type="nodelet::Nodelet">
    <description> 
      A node to add a value and republish.
    </description>
  </class>
</library>

 

 

參考: 

nodelet

ROS中nodelet的使用

ROS nodelet 使用詳解

ROS與C++入門教程-nodelet-介紹

nodelet的使用方法以及傳輸時間測試

ROS nodelet-----編寫一個nodelet插件


免責聲明!

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



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