ROS多进程回调的实现

单线程Spinning

ros::spin()是最简单的单线程自循, 它会一直调用直到结束
用法: ros::spin(); 也可用ros::getGlobalCallbackQueue()->callAvailable(ros::WallDuration(0.1));
另一个单线程spinning是ros::spinOnce(),它定期调用等待在那个点上的所有回调
用法: ros::spinOnce(); 也可用ros::getGlobalCallbackQueue()->callAvailable(ros::WallDuration(0));


以上,是它的基础用法,那么spin到底做了什么呢?
  首先, 当我们调用ros::spin时, 会有一个互斥锁, 把你的回调队列加锁, 防止执行混乱. 然后, 检测如果回调队列不为空, 则读取回调队列.最后,当while(nh.ok())为true时, 调用当前队列中的所有函数,如果有不满足的, 会重新放回队列中.所以在listener中, 就一直执行这ros::spin来监听话题了.从这样看来,spin和spinOnce的区别之一,就是while(nh::ok())执行块的大小了. 另一个是等待时间, spin在执行时, 会指定一个返回前可以等待调用的时间. spin会等待0.1s而spinonce不会.spinOnce使得pub/sub为非阻塞锁 spin是客户端的, 因此是阻塞的.这样就很好理解talker要用SpinOnce,有需要talk的时候发出,没有的时候不发送.而listener一直在阻塞着听.

  这样,再来说之前很流传的一句关于解释spin的话, “所有的回调函数都是spin调用的”. 这是一句形象而不准确的话. 回调函数一直等待在回调队列中, 只要条件一满足就会发生回调, 而spin的作用, 只是创建了线程给这个回调函数去执行它, 这样多线程就不会影响其他的作业.之所以用spin, 是因为rospy不愿指定线程模型, 在程序中将线程暴露出来, 而用spin来把它封装起来. 但你可以用多线程调用任意数量的回调函数.没有用户订阅, 服务和回调是不会被调用的.


多线程Spinning

roscpp内部支持调用多线程, 有两个: ros::MultiThreadedSpinner、ros::AsyncSpinner (since 0.10)
ros::MultiThreadedSpinner
  ros::MultiThreadedSpinner是阻塞式的spinner, 类似于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)
  一个更有用的线程spinner是AsyncSpinner.不是阻塞式的,类似ros::spinOnce(),拥有start()和stop()两个函数, start()等待在那个点上的所有回调,stop()停止回调,并且在销毁时自动停止.

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

自定义消息队列处理线程

1.用 ros::CallbackQueue定义需要的回调队列

#include "ros/ros.h" 
#include "std_msgs/String.h"
#include <ros/callback_queue.h>

ros::CallbackQueue callback_queue;
void state_callback(const std_msgs::String::ConstPtr& msg)
{
   init_state_flag=1;//也可在需要位置置1
}
int main(int argc,char **argv)
{
   ros::init(argc,argv,"example");

   //monitor the state of the hand.
   ros::NodeHandle nh;

ros::SubscribeOptions ops=ros::SubscribeOptions::create<std_msgs::String>("state",1, 
                          state_callback, ros::VoidPtr(),&callback_queue); //指定一个自定义队列

   ros::Subscriber listen_state= nh.subscribe(ops);	// 必须添加,ros::SubscribeOptions自定义的队列才能回调
   
   ros::AsyncSpinner state_spinner(1,&callback_queue);

   while(ros::ok())
   {
       if(init_state_flag == 1)
       {
           state_spinner.stop();
           break;
       }
       state_spinner.start();

}
}

2.用setCallbackQueue(&callback_queue)定义需要的回调队列

ros::NodeHandle nh;
nh.setCallbackQueue(&callback_queue);

也可以使用NodeHandle NodeHandle::setCallbackQueue(&callback_queue)函数设置自定义队列,这个可使用所有订阅、服务、定时器等。


回调通过callback_queue而不是 roscpp的默认队列.意味着ros::spin()和ros::spinOnce()不会处理这些回调,你需要单独处理这些回调.
(1)通过手工调用 ros::CallbackQueue::callAvailable() 和ros::CallbackQueue::callOne()方法处理。
callavailable()调用队列里所有的,callone()只会调用回调在队列最旧的;callAvailable()和callOne()都会有一个超时选项,在返回前,它会在超时时间内等待回调有效;如果是0,同时队列没有回调,则直接返回。

callback_queue.callAvailable(ros::WallDuration());
callback_queue.callOne(ros::WallDuration()) to only call a single callback instead of all available

(2)也可以通过ros::AsyncSpinner spinner(1, &callback_queue);第一个参数代表几个进程,第二个参数代表需要单独处理回调队列.

  • 3
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
ROS中,可以使用多线程来处理回调函数。ROS提供了两种多线程回调处理的方法:ros::MultiThreadedSpinner和ros::AsyncSpinner。 ros::MultiThreadedSpinner是一个多线程回调处理类,它通过启动指定数量的Spinner线程并发执行Callback队列中的可用回调来处理回调函数。你可以通过指定回调队列来控制线程的数量和执行方式。 ros::AsyncSpinner是另一种多线程回调处理方法,它使用异步的方式来启停Spinner线程。你可以指定要开启的线程数量,并发执行Callback队列中的可用回调。 这两种多线程回调处理方法都能够在处理回调函数时提高效率,充分利用系统资源,同时保证其他回调函数不会被阻塞。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [ROS多线程服务话题定时器等回调函数处理](https://blog.csdn.net/GeForeverr/article/details/108776801)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *3* [【ROS回调的多线程问题](https://blog.csdn.net/lemonxiaoxiao/article/details/128422748)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值