ROS nodelet - 零拷贝的通信方式

Nodelet

  1. ROS 中 Publisher/Subscriber 通信机制方便灵活,但是每次接收的数据都会拷贝一份,对于数据量较大的 msg 如lidar,效率十分低下
  2. Nodelet 提供了一种方式, 能让多个运行的算法节点之间不用这种低效的拷贝,达到共享数据的方式.

Nodelet 设计目的

  1. use the existing C++ ROS interfaces. 使用当前ros 的接口
  2. allow zero copy passing of data between nodelets 零拷贝
  3. dynamically load as plugins to break build time dependencies
  4. location transparent except for performance improvements。
  5. writing code in a node or a nodelet will be minimally different. 节点内的代码尽量少的改变

Nodelet 技术实现

  • 定义 nodelet::Nodelet 基类,这个类将会被动态的载入, 所有的nodelets会动态的重载此类
  • 这个类将会提供 命名空间,参数
  • 一个 nodelet_manager 将会处理一个或多个 nodelets,任何nodelet 之间的信息传输将会使用 boost::shared_ptr , 从而避免了多次拷贝
  • Define a base class nodelet::Nodelet which will be used for dynamic loading. All nodelets will inherit from this base class, and be dynamically loadable using pluginlib.
  • It will provide the namespace, remapping arguments and parameters automatically, like they were a first class node.
  • There will be a nodelet_manager process into which one or more nodelets can be loaded. Any communications between them can use the zero copy roscpp publish call with a boost shared pointer.

Nodelet 的使用

# nodelet usage:
nodelet load pkg/Type manager #Launch a nodelet of type pkg/Type on manager manager
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
nodelet manager              # Launch a nodelet manager node

Bring up a manager

A nodelet will be run inside a NodeletManager. A nodelet manager is a c++ program which is setup to listen to ROS services and will be the executable in which the nodelet is dynamically loaded. In this case we will run a standalone manager, but in many cases these managers will be embedded within running nodes.

rosrun nodelet nodelet manager __name:=nodelet_manager

We have renamed this node to nodelet_manager for clarity.

Launching the nodelet

Nodelets are launched remotely by using the nodelet executable as well.

What this code does: The nodelet executable, called here, will contact the nodelet_manager and ask it to instantiate an instance of the nodelet_tutorial_math/Plus nodelet. It will pass through the name, nodelet1, and also any remappings if applied to the code inside the nodelet. And parameters appear in the right namespace too.

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

If you do a rostopic listyou will see:

/foo
/nodelet1/out

If you look at the output of rosnode list you will see:

/nodelet1
/nodelet_manager

Testing Operation
In separate terminals run:

rostopic pub /foo std_msgs/Float64 5.0 -r 10
rostopic echo /nodelet1/out

Will show: 6.1 which is 5.0 + 1.1 .

Using within roslaunch files

Here is an example launch file (available in nodelet_tutorial_math pkg) with multiple nodelets running on the same standalone manager:

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

  <node pkg="nodelet" type="nodelet" name="Plus"
        args="load nodelet_tutorial_math/Plus standalone_nodelet">
    <remap from="/Plus/out" to="remapped_output"/>
  </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">
    <rosparam file="$(find nodelet_tutorial_math)/plus_default.yaml"/>
  </node>
  
  <node pkg="nodelet" type="nodelet" name="Plus3" args="standalone nodelet_tutorial_math/Plus">
    <param name="value" type="double" value="2.5"/>
    <remap from="Plus3/in" to="Plus2/out"/>
  </node>
  
</launch>

Porting nodes to nodelets

MyNodeletClass.h
#include <nodelet/nodelet.h>

namespace example_pkg
{

    class MyNodeletClass : public nodelet::Nodelet
    {
        public:
            virtual void onInit();
    };

}
MyNodeletClass.cpp
// this should really be in the implementation (.cpp file)
#include <pluginlib/class_list_macros.h>

// Include your header
#include <example_pkg/MyNodeletClass.h>

// watch the capitalization carefully
PLUGINLIB_EXPORT_CLASS(example_pkg::MyNodeletClass, nodelet::Nodelet)

namespace example_pkg
{
    void MyNodeletClass::onInit()
    {
        NODELET_DEBUG("Initializing nodelet...");
    }
}
nodelet_plugins.xml

This file should be placed along with the package.xml file

<library path="lib/libMyNodeletClass">
  <class name="example_pkg/MyNodeletClass" type="example_pkg::MyNodeletClass" base_class_type="nodelet::Nodelet">
  <description>
  This is my nodelet.
  </description>
  </class>
</library>
package.xml
<build_depend>nodelet</build_depend>
<run_depend>nodelet</run_depend>
<export>
  <nodelet plugin="${prefix}/nodelet_plugins.xml" />
</export>
mynodelet.launch

Launch file should be placed under the launch/ repertory of your package, you can create it if it does not exist.

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

  <node pkg="nodelet" type="nodelet" name="MyNodeletClass" args="load example_pkg/MyNodeletClass standalone_nodelet" output="screen">
  </node>
</launch>
  • launch 文件中单独启动一个 nodelet manager
  • 自己编写的 nodelet 节点需要加入参数 args, 先载入自己的, 再载入manager 名字

参考文档

  1. nodelet 官方介绍
  2. nodelet Tutorials - Running a nodelet
  3. nodelet Tutorials - Porting nodes to nodelets

2020.02.12

Turku . Finland

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值