ROS学习(十四):ROS Spinning

ROS 单线程与多线程 Spinning

roscpp 不为应用程序指定具体的线程模型。

允许回调函数调用任意数量的线程

必须要调用线程,否则订阅、服务等回调将永远不会被调用

常见的解决方案是,在主函数开头用 ros::spin()

注意:回调序列对内部的网络通讯没有影响,只能影响回调发生的时刻。它们将影响订阅序列,取决于处理回调函数的速度、消息到达的速度、消息是否丢弃等。

1、单线程

最简单最常用的单线程为:ros::spin()

ros::init(argc, argv, "my_node");
ros::NodeHandle nh;
ros::Subscriber sub = nh.subscribe(...);
...
ros::spin();

所有用户的调用程序将从 ros::spin()开始调用。只到节点关闭(ros::shutdown() or a Ctrl-C),ros::spin()才有返回值。

另一个常用的模式是周期性的 ros::spinOnce()

ros::Rate r(10); // 10 hz
while (should_continue)
{
  ... do some work, publish some messages, etc. ...
  ros::spinOnce();
  r.sleep();
}

ros::spinOnce()将在那一刻调用所有等待调用的函数。

执行一个自己的spin()函数很简单:

#include <ros/callback_queue.h>
ros::NodeHandle n;
while (ros::ok())
{
  ros::getGlobalCallbackQueue()->callAvailable(ros::WallDuration(0.1));
}

spinOnce() 类似:

#include 

ros::getGlobalCallbackQueue()->callAvailable(ros::WallDuration(0));

注:spin()和spinonce()真的意味着单线程应用程序,而不是从多个线程中调用的一次优化。

2、多线程

ros::MultiThreadedSpinner

阻塞式线程,类似于ros::spin(),你可以在它的构造器上指定一定数量的线程数,但如果不指定或设置为0,则会在每个CPU上执行一个线程。

ros::MultiThreadedSpinner spinner(4); // Use 4 threads
spinner.spin(); // spin() will not return until the node has been shutdown

ros::AsyncSpinner (since 0.10)

一个更有用的线程。它不用spin() 回调,而用start()stop(),当它销毁时候就会自动关闭

ros::AsyncSpinner spinner(4); // Use 4 threads
spinner.start();
ros::waitForShutdown();

3、回调序列

创建回调序列:


#include 
...
ros::CallbackQueue my_queue;

CallbackQueue 有两种方法调用回调函数: callAvailable() 和callOne()。

callavailable()调用队列里所有的。callone()只会调用回调在队列最旧的。

callAvailable()和callOne()都会有一个超时选项,在返回前,它会在超时时间内等待回调有效。

如果是0,同时队列没有回调,则直接返回。

4、高级回调序列

上面spin()执行的语句,有调用到 ros::getGlobalCallbackQueue(),默认所有的回调都会放到全局队列,由ros::spin() 处理。

自定义回调序列:

1、subscribe(), advertise(), advertiseService()

2、NodeHandle

ros::AsyncSpinner spinner(0, &my_callback_queue);
spinner.start();

这个可使用所有订阅,服务,定时器等,回调通过my_callback_queue而不是 roscpp的默认队列。意味着ros::spin() 和ros::spinOnce() 不会处理这些回调。你需要单独处理这些回调。

你可以通过手工调用 ros::CallbackQueue::callAvailable() 和ros::CallbackQueue::callOne()方法处理。

my_callback_queue.callAvailable(ros::WallDuration());
// alternatively, .callOne(ros::WallDuration()) to only call a single callback instead of all available

各种*Spinner对象可以使用指向回调队列的指针而不是默认值:

ros::AsyncSpinner spinner(0, &my_callback_queue);
spinner.start();

或者:

ros::MultiThreadedSpinner spinner(0);
spinner.spin(&my_callback_queue);

参考

http://wiki.ros.org/roscpp/Overview/Callbacks%20and%20Spinning

你可能感兴趣的:(ROS)