ROS专题----nodelet简明笔记

------


此页面包含使用nodelet的教程。强烈建议您已经回顾了​​pluginlib教程​​做这些教程了。


  1. ​运行节点​
  2. 这将显示如何在系统中运行节点。

  3. ​将节点移植到节点​


来自使用nodelet的其他包/堆栈的教程:



------

$ ​roslaunch nodelet_tutorial_math plus.launch

... logging to /home/relaybot/.ros/log/7f42ed06-088b-11e7-99c2-70f1a1ca7552/roslaunch-relaybot-desktop-8447.log

Checking log directory for disk usage. This may take awhile.

Press Ctrl-C to interrupt

Done checking log file disk usage. Usage is <1GB.


started roslaunch server http://relaybot-desktop:34104/


SUMMARY

========


PARAMETERS

 * /Plus2/value: 10

 * /Plus3/value: 2.5

 * /rosdistro: kinetic

 * /rosversion: 1.12.7


NODES

  /

    Plus (nodelet/nodelet)

    Plus2 (nodelet/nodelet)

    Plus3 (nodelet/nodelet)

    standalone_nodelet (nodelet/nodelet)


ROS_MASTER_URI=http://localhost:11311


core service [/rosout] found

process[standalone_nodelet-1]: started with pid [8485]

process[Plus-2]: started with pid [8486]

process[Plus2-3]: started with pid [8487]

process[Plus3-4]: started with pid [8488]

[ INFO] [1489489721.430571269]: Loading nodelet /Plus of type nodelet_tutorial_math/Plus to manager standalone_nodelet with the following remappings:

[ INFO] [1489489721.430679072]: /Plus/out -> /remapped_output

[ INFO] [1489489721.439768636]: waitForService: Service [/standalone_nodelet/load_nodelet] has not been advertised, waiting...

type is nodelet_tutorial_math/Plus

[ INFO] [1489489721.444581734]: Loading nodelet /Plus2 of type nodelet_tutorial_math/Plus to manager standalone_nodelet with the following remappings:

[ INFO] [1489489721.451421641]: waitForService: Service [/standalone_nodelet/load_nodelet] has not been advertised, waiting...

[ INFO] [1489489721.872693083]: Initializing nodelet with 4 worker threads.

[ INFO] [1489489721.886004455]: waitForService: Service [/standalone_nodelet/load_nodelet] is now available.

[ INFO] [1489489721.891109441]: waitForService: Service [/standalone_nodelet/load_nodelet] is now available.


ROS专题----nodelet简明笔记_nodelet

------


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

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

private:
virtual void 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);
}



------


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



------

运行节点


建立


我们假设​​nodelet_tutorial_math​​已经被编译并且roscore正在运行。

rosmake nodelet_tutorial_math
roscore


打开经理


一个nodelet会内运行​​NodeletManager​​。节点管理器是一个c ++程序,它被设置为监听ROS服务,并且是动态加载节点的可执行文件。在这种情况下,我们将运行一个独立的管理器,但在许多情况下,这些管理器将嵌入在运行的节点中。

rosrun nodelet nodelet manager __name:= nodelet_manager


为了清楚起见,我们已将此节点重命名为nodelet_manager。

启动节点


Nodelet也通过使用nodelet可执行文件远程启动。

这个代码做什么:这里调用的nodelet可执行文件将联系nodelet_manager并要求它实例化nodelet_tutorial_math / Plus节点的一个实例。它将通过名称nodelet1,以及任何重新映射,如果应用于nodelet中的代码。参数也出现在右边的命名空间中。

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


如果你做一个rostopic列表,你会看到:

/ foo
/ nodelet1 / out


如果你看看rosnode列表的输出,你会看到:

/ nodelet1
/ nodelet_manager


测试操作


在单独的端子运行:

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


将显示:6.1是5.0 + 1.1。

在roslaunch文件中使用


下面是一个示例启动文件(在​​nodelet_tutorial_math​​​ pkg 中​​可用​​),其中多个nodelet在同一独立管理器上运行:

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


------

将节点移植到nodelet


工作进行中...(参见nodelet_tutorial_math一个例子)

  • 添加必要的#includes
  • 去掉int main()
  • 子类nodelet :: Nodelet
  • 将代码从构造函数移动到onInit()
  • 添加PLUGINLIB_EXPORT_CLASS宏
  • 在包清单中对节点添加<build_depend>和<run_depend>依赖项。

  • 请在包清单的<export>部分中添加<nodelet>项

  • 创建.xml文件以将nodelet定义为插件
  • 对CMakeLists.txt进行必要的更改(注释掉一个rosbuild_add_executable,添加一个rosbuild_add_library)

最小节点


MyNodeletClass.h

#include <nodelet / nodelet.h>

命名空间example_pkg
{

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

}}


MyNodeletClass.cpp

//这应该是在实现(.cpp文件)
#include <pluginlib / class_list_macros.h>

//仔细观察大小写
PLUGINLIB_EXPORT_CLASS(example_pkg :: MyNodeletClass,nodelet :: Nodelet)

命名空间example_pkg
{
void MyNodeletClass :: onInit()
{
NODELET_DEBUG(“正在初始化nodelet ...”);
}}
}}


nodelet_plugins.xml

<library path =“lib / libMyNodeletClass”>
<class name =“example_pkg / MyNodeletClass”type =“example_pkg :: MyNodeletClass”base_class_type =“nodelet :: Nodelet”>
<description>
这是我的节点。
</ 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>
<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>


------

nodelet


高水平


Nodelets旨在提供一种在单个进程中在单个机器上运行多个算法的方法,而不会在传递消息进程时产生复制成本。roscpp具有在同一节点内的发布和订阅调用之间进行零拷贝指针传递的优化。为了做到这一点,nodelet允许将类动态加载到同一个节点,然而它们提供了简单的单独命名空间,使得尽管nodelet在同一个进程中,它仍然像一个独立的节点。这进一步扩展了,它在运行时使用​​pluginlib​​是动态可加载的。

应用程序


  • 高吞吐量数据流可以由许多节点组成,然后加载到同一进程,以避免复制和网络流量。

设计目标


  • 使用现有的C ++ ROS接口。
  • 允许节点之间的数据的零拷贝传递
  • 动态加载为插件以打破构建时间依赖性
  • 位置透明,除了性能改进
  • 在节点或节点中编写代码将有最小的不同。

技术


  • 定义将用于动态加载的基类nodelet :: Nodelet。所有nodelet都将继承这个基类,并且可以使用pluginlib进行动态加载。
  • 它将提供命名空间,自动重映射参数和参数,就像它们是第一个类节点一样。
  • 将有一个nodelet_manager进程,一个或多个nodelet可以加载到其中。它们之间的任何通信都可以使用带有boost共享指针的零拷贝roscpp发布调用。

基本用法

节点使用:
nodelet加载pkg /类型管理器 - 在管理器管理器上启动pkg / Type类型的节点
nodelet standalone pkg / Type - 在独立节点中启动pkg / Type类型的节点
nodelet unload name manager - 按名称从manager卸载nodelet节点
nodelet管理器 - 启动节点管理器节点


对于命令行和启动文件示例,请参阅本教程​​运行节点​

API


Nodelet基类:


​nodelet :: Nodelet​

公共方法:

​切换行号​


1 Nodelet()//动态加载时使用的默认构造函数
2 void init(const std :: string&name,const ros :: M_string&remapping_args,const std :: vector < std :: string >&my_argv); //这个方法是一个nodelet应该如何启动。参数是管理器启动节点所需的参数。这将初始化nodelet基类,然后调用子类的onInit()方法。
3


子类中使用的受保护成员和方法:

​切换行号​


1 std :: string              getName()//获取nodelet的名称
2 ros :: NodeHandle& getNodeHandle()//获取节点句柄(提供此节点的自定义重映射和名称)
3 ros :: NodeHandle& getPrivateNodeHandle()//获取私有节点句柄(在其私有命名空间中提供此节点的自定义重映射)
4 ros :: NodeHandle& getMTNodeHandle()//使用Multi Threaded回调队列获取节点句柄。(提供此节点的自定义重映射和名称)
5 ros :: NodeHandle& getMTPrivateNodeHandle()//使用多线程回调队列获取私有节点句柄。(在其私有命名空间中提供此节点定制重新映射)
6 ros :: CallbackQueue& getMTCallbackQueue()//获取回调队列(从管理器可用线程池)
7 std :: vector < std :: string > getMyArgv()//获取命令行参数到剥离ROS和nodelet特定args的nodelet。
8


用于在子类中启动ROS API的初始化方法:

​切换行号​


1 virtual  void  onInit()= 0  // Virtual,并且必须被子类覆盖。必须将ROS基础结构的所有初始化都放入此函数中。
2


NODELET ROSCONSOLE MACROS


这些是​​rosconsole​​​宏周围的​​节点​​感知包装器。它们包括详细程度级别DEBUG,INFO,WARN,ERROR和FATAL。这些宏只会在nodelet方法中编译。

它们通过在运行的nodelet的名称中设置命名的日志记录器来操作,以便您可以 区分在运行的两个相同类型的节点的输出 同一位经理。他们也有优势,你可以转一个具体nodelet进入调试,而不是所有特定类型的节点。

​切换行号​


1 #包括“nodelet / nodelet.h”
2
3 // ...在一个nodelet方法
4 NODELET_DEBUG(“ 我的调试语句”)
5 NODELET_DEBUG_STREAM(“ 我的调试语句” <<(double)1.0)
6 NODELET_DEBUG_COND(1 == 1,“ my debug_statement ”)
7 NODELET_DEBUG_STREAM_COND(1 == 1,“ 我的调试语句” <<(double)1.0)


从Nodelet发布


如果希望no-copy pub / sub工作,您必须将消息发布为shared_ptr。有关更多详细信息,请参阅​​roscpp / Overview / Publishers和订阅者#Intraprocess_Publishing​​。

线程模型


节点管理器具有线程池,该线程池在管理器内运行的所有节点之间共享。这由参数“num_worker_threads”设置。

在nodelet中运行的代码中有两种可能的线程API。默认线程模型有一个线程用于所有回调。还有一个多线程API。

onInit


这个方法在init上调用,不应该阻塞或做重要的工作。

单线程API


使用方法getNodeHandle()和getPrivateNodeHandle()将保证所有回调串行到达。

多线程API


使用方法getMTNodeHandle()和getMTPrivateNodeHandle()回调将分布在管理器的线程池中。

其他线程


它是节点创建自己的线程进行操作的有效操作。这些线程应该在析构函数中正确清理。

线程共享


所有nodelet共享管理器的线程池。如果nodelet阻塞线程,它们可能会阻止其他nodelet获得回调。确保管理器配置了足够的线程以防止阻止。注意:即使单个线程的节点句柄也可以每个节点使用池的1个线程。



------