ROS 单线程与多线程 Spinning
roscpp 不为应用程序指定具体的线程模型。
允许回调函数调用任意数量的线程
必须要调用线程,否则订阅、服务等回调将永远不会被调用
常见的解决方案是,在主函数开头用 ros::spin()
注意:回调序列对内部的网络通讯没有影响,只能影响回调发生的时刻。它们将影响订阅序列,取决于处理回调函数的速度、消息到达的速度、消息是否丢弃等。
最简单最常用的单线程为: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()真的意味着单线程应用程序,而不是从多个线程中调用的一次优化。
阻塞式线程,类似于ros::spin()
,你可以在它的构造器上指定一定数量的线程数,但如果不指定或设置为0,则会在每个CPU上执行一个线程。
ros::MultiThreadedSpinner spinner(4); // Use 4 threads
spinner.spin(); // spin() will not return until the node has been shutdown
一个更有用的线程。它不用spin()
回调,而用start()
和stop()
,当它销毁时候就会自动关闭
ros::AsyncSpinner spinner(4); // Use 4 threads
spinner.start();
ros::waitForShutdown();
创建回调序列:
#include
...
ros::CallbackQueue my_queue;
CallbackQueue 有两种方法调用回调函数: callAvailable() 和callOne()。
callavailable()调用队列里所有的。callone()只会调用回调在队列最旧的。
callAvailable()和callOne()都会有一个超时选项,在返回前,它会在超时时间内等待回调有效。
如果是0,同时队列没有回调,则直接返回。
上面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