当前位置:   article > 正文

ROS:ROS多线程订阅消息(ros::asyncspinner)

ros::asyncspinner

对于一些只订阅一个话题的简单节点来说,我们使用ros::spin()进入接收循环,每当有订阅的话题发布时,进入回调函数接收和处理消息数据。但是更多的时候,一个节点往往要接收和处理不同来源的数据,并且这些数据的产生频率也各不相同,当我们在一个回调函数里耗费太多时间时,会导致其他回调函数被阻塞,导致数据丢失。这种场合需要给一个节点开辟多个线程,保证数据流的畅通。 
为了观察不同话题的消息被阻塞的情况,可以参考以下实验代码 

publisher:

  1. #include "ros/ros.h"
  2. #include "std_msgs/String.h"
  3. #include <sstream>
  4. int main(int argc, char **argv)
  5. {
  6. ros::init(argc, argv, "multi_pub");
  7. ros::NodeHandle n;
  8. ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter1", 1);
  9. ros::Publisher pub2 = n.advertise<std_msgs::String>("chatter2", 1);
  10. ros::Rate loop_rate(10);
  11. int count = 0;
  12. while (ros::ok())
  13. {
  14. std_msgs::String msg;
  15. std::stringstream ss;
  16. ss << "hello world " << count;
  17. msg.data = ss.str();
  18. std_msgs::String msg2;
  19. std::stringstream ss2;
  20. ss2 << "hello " << count;
  21. msg2.data = ss2.str();
  22. ROS_INFO("%s", msg.data.c_str());
  23. ROS_INFO("%s", msg2.data.c_str());
  24. chatter_pub.publish(msg);
  25. pub2.publish(msg2);
  26. ros::spinOnce();
  27. loop_rate.sleep();
  28. ++count;
  29. }
  30. return 0;
  31. }

subscriber

  1. #include "ros/ros.h"
  2. #include "std_msgs/String.h"
  3. class multiReceiver
  4. {
  5. public:
  6. multiReceiver()
  7. {
  8. sub = nh.subscribe("chatter1", 1, &multiReceiver::chatterCallback1,this);
  9. sub2 = nh.subscribe("chatter2", 1, &multiReceiver::chatterCallback2,this);
  10. }
  11. void chatterCallback1(const std_msgs::String::ConstPtr& msg);
  12. void chatterCallback2(const std_msgs::String::ConstPtr& msg);
  13. private:
  14. ros::NodeHandle nh;
  15. ros::Subscriber sub;
  16. ros::Subscriber sub2;
  17. };
  18. void multiReceiver::chatterCallback1(const std_msgs::String::ConstPtr& msg)
  19. {
  20. ROS_INFO("I heard: [%s]", msg->data.c_str());
  21. ros::Rate loop_rate(0.5);//block chatterCallback2()
  22. loop_rate.sleep();
  23. }
  24. void multiReceiver::chatterCallback2(const std_msgs::String::ConstPtr& msg)
  25. {
  26. ROS_INFO("I heard: [%s]", msg->data.c_str());
  27. }
  28. int main(int argc, char **argv)
  29. {
  30. ros::init(argc, argv, "multi_sub");
  31. multiReceiver recOb;
  32. ros::spin();
  33. return 0;
  34. }

可以看到,发布程序中,以10hz的频率发布了chatter1和chatter2两个话题,在订阅程序中,回调函数1中加入了2s的延时,导致了回调函数2也只能2s才能接收到一个数据,为了是回调函数2能正常接收数据,我研究一下在一个ROS节点中开辟多个线程的方法。

在ROS中,有两种方法可以在一个节点中开辟多个线程 
1.ros::MultiThreadedSpinner 
MultiThreadedSpinner类似于ros::spin(),在构造过程中可以指定它所用线程数,但如果不指定线程数或者线程数设置为0,它将在每个cpu内核开辟一个线程。 

用法如下

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

2.ros::AsyncSpinner 

AsyncSpinner比MultiThreadedSpinner更优,它有start() 和stop() 函数,并且在销毁的时候会自动停止。下面的用法等价于上面的MultiThreadedSpinner例子。

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

  • 注意:ros::waitForShutdown() 函数,不会触发单独spin(),所以该例子将会4个线程同时循环。

    Please note that the ros::waitForShutdown() function does not spin on its own, so the example above will spin with 4 threads in total.

以上代码片参考了ROS wiki

源码:AsyncSpinner API (Jade)


声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/article/detail/49972
推荐阅读
相关标签
  

闽ICP备14008679号