Nodelet介绍

1、nodelet简介

通常情况下,我们使用的ros节点都是独立的可执行文件,每个节点启动后在系统中都是以一个独立的进程存在的,即节点之间的通信就是进程间的通信,并且通信过程需要消耗网络的带宽。为了提高通信的效率和减少网络带宽的占用,ros中有一类特殊的节点-nodelet,这类节点可以在单个进程下以多个线程的形式运行,这样节点间的通信就是线程间的通信了。比如摄像头这类数据量大的传感器,可以使用nodelet方式与其他节点通信,从而大大提高传输效率。

2、nodelet的运行

2.1 环境配置

首先需要安装nodelet_tutorial_math功能包(通过sudo apt-get install ros-$ROS_DISTRO-nodelet-tutorial-math安装),并且在终端中运行roscore

2.2 运行管理器(manager)

所有的nodelet节点都是在manager下运行,所以首先运行manager

rosrun nodelet nodelet manager __name:=nodelet_manager

这里将manager 的名字改为nodelet_manager

2.3 运行nodelet节点

用如下命令运行一个nodelet节点,可执行程序nodelet会联系nodelet_manager,并且让他实例化一个nodelet_tutorial_math/Plus对象

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

如果你在终端中运行rostopic list,你可以看到

/foo
/nodelet1/out

如果你在终端中运行rosnode list,你可以看到

/nodelet1
/nodelet_manager

2.3.1 运行测试

在终端中运行

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

在终端中将会看到不断输出6.1,(5.0+1.1)

2.4 在roslaunch中运行

<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>

首先启动manager,然后运行三个nodelet节点。

3、创建自己的nodelet节点

如果还没有创建catkin工作空间,则首先创建catkin工作空间,然后在在src目录下创建一个功能包,可以命名为nodelet_test。

然后在/include/nodelet_test目录下新建一个文件MyNodeletClass.h,文件内容如下:

#include <nodelet/nodelet.h>

namespace nodelet_test
{

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

}

将类写在命名空间下是一种好的编程习惯,不是强制的。 定义的类MyNodeletClass继承自nodelet::Nodelet类,函数onInit()是类nodelet::Nodelet的纯虚函数,子类必须重新实现。并且manager动态加载MyNodeletClass类后,onInit()函数会自动执行。

在src目录下新建文件MyNodeletClass.cpp,内容如下

#include <pluginlib/class_list_macros.h>

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

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

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

因为要把类MyNodeletClass编译成插件(动态库),因此还需要新建文件nodelet_plugins.xml,内容如下

<library path="lib/libMyNodeletClass">
  <class name="nodelet_test/MyNodeletClass" type="nodelet_test::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>
...

CMakeLists.txt文件部分关键内容如下:

find_package(catkin REQUIRED COMPONENTS
  nodelet
)
...
catkin_package(
  INCLUDE_DIRS include
)

include_directories(
 include
  ${catkin_INCLUDE_DIRS}
)

## Declare a C++ library
add_library(${PROJECT_NAME}
   src/MyNodeletClass.cpp
)
target_link_libraries(${PROJECT_NAME}
   ${catkin_LIBRARIES}
)
...

最后利用catkin_make编译。

在/launch文件夹下新建文件nodelet_test.launch,内容如下

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

  <node pkg="nodelet" type="nodelet" name="MyNodeletClass" args="load nodelet_test/MyNodeletClass standalone_nodelet" output="screen">
  </node>
</launch>

猜你喜欢

转载自blog.csdn.net/qq_34493401/article/details/128890508