ROS多線程訂閱

原文地址:http://blog.csdn.net/yaked/article/details/50776224



背景

因爲在一些點雲處理的程序中,出現多個訂閱者訂閱同一個topic,由於內部處理的時間不同,最後造成顯示界面出現卡頓,現象就是用鼠標拖動點雲的視角會感覺非常卡,不順暢。爲此,決定先走一遍官方的多線程系列教程。

https://github.com/ros/ros_tutorials/tree/jade-devel/roscpp_tutorials

http://wiki.ros.org/roscpp_tutorials/Tutorials

關於Spin和SpinOnce的解釋來自英文書《A Gentle Introduction to ROS》P59頁


什麼時候用ros::spin()和ros::spinOnce()呢,如果僅僅只是響應topic,就用ros::spin()。當程序中除了響應回調函數還有其他重複性工作的時候,那就在循環中做那些工作,然後調用ros::spinOnce()。如下面的用spinOnce,循環調用print( )函數。


這裏一直在打印while 中的部分,並且處理message queue。

而下面的打印輸出不會更新,相當於只執行了一次,但是它會不斷處理ROS 的message queue(下圖右邊的subscriber 開頭的打印函數只調用了一次,然後一直響應訂閱的消息)。


這裏只在一開始進入main的時候調用了一次print函數,其餘的都在響應topic 去了。


spinOnce( )較常用的做法是while裏放publisher所要發佈的msg的賦值處理,然後一直循環發佈topic。

[cpp] view plain copy
  1. ros::Rate loop_rate(10);  
  2.   
  3.   while (ros::ok())  
  4.   {  
  5.     std_msgs::String msg;  
  6.   
  7.     std::stringstream ss;  
  8.     ss << "hello world " << count;  
  9.     msg.data = ss.str();  
  10.   
  11.     chatter_pub.publish(msg);  
  12.   
  13.     ros::spinOnce();  
  14.     loop_rate.sleep();  
  15.   }  


1. customer_callback_processing
自定義消息隊列處理線程關鍵字:JOIN,在主線程spinOnce進入自定義處理線程。

http://wiki.ros.org/roscpp/Overview/Callbacks%20and%20Spinning這裏官網給出了補充說明

[cpp] view plain copy
  1. #include "ros/ros.h"  
  2. #include "ros/callback_queue.h"  
  3. #include "std_msgs/String.h"  
  4.   
  5. #include <boost/thread.hpp>  
  6.   
  7. /** 
  8.  * This tutorial demonstrates the use of custom separate callback queues that can be processed 
  9.  * independently, whether in different threads or just at different times. 
  10.  */  
  11.   
  12. void chatterCallbackMainQueue(const std_msgs::String::ConstPtr& msg)  
  13. {  
  14.   ROS_INFO_STREAM("I heard: [ " << msg->data << "] in thread [" << boost::this_thread::get_id() << "] (Main thread)");  
  15. }  
  16.   
  17.   
  18. void chatterCallbackCustomQueue(const std_msgs::String::ConstPtr& msg)  
  19. {  
  20.   ROS_INFO_STREAM("I heard: [ " << msg->data << "] in thread [" << boost::this_thread::get_id() << "]");  
  21. }  
  22.   
  23. /** 
  24.  * The custom queue used for one of the subscription callbacks 
  25.  */  
  26. ros::CallbackQueue g_queue;  
  27. void callbackThread()  
  28. {  
  29.   ROS_INFO_STREAM("Callback thread id=" << boost::this_thread::get_id());  
  30.   
  31.   ros::NodeHandle n;  
  32.   while (n.ok())  
  33.   {  
  34.     g_queue.callAvailable(ros::WallDuration(0.01));  
  35.   }  
  36. }  
  37.   
  38. int main(int argc, char **argv)  
  39. {  
  40.   ros::init(argc, argv, "listener_with_custom_callback_processing");  
  41.   ros::NodeHandle n;  
  42.   
  43.   /** 
  44.    * The SubscribeOptions structure lets you specify a custom queue to use for a specific subscription. 
  45.    * You can also set a default queue on a NodeHandle using the NodeHandle::setCallbackQueue() function. 
  46.    * 
  47.    * AdvertiseOptions and AdvertiseServiceOptions offer similar functionality. 
  48.    */  
  49.   ros::SubscribeOptions ops = ros::SubscribeOptions::create<std_msgs::String>("chatter", 1000,  
  50.                                                                               chatterCallbackCustomQueue,  
  51.                                                                               ros::VoidPtr(), &g_queue);  
  52.   ros::Subscriber sub = n.subscribe(ops);  
  53.   
  54.   ros::Subscriber sub2 = n.subscribe("chatter", 1000, chatterCallbackMainQueue);  
  55.   
  56.   boost::thread chatter_thread(callbackThread);  
  57.   
  58.   ROS_INFO_STREAM("Main thread id=" << boost::this_thread::get_id());  
  59.   
  60.   ros::Rate r(1);  
  61.   while (n.ok())  
  62.   {  
  63.     ros::spinOnce();  
  64.     r.sleep();  
  65.   }  
  66.   
  67.   chatter_thread.join();  
  68.   
  69.   return 0;  
  70. }  

2. listenner_multiple_spin 

思想:利用一個類的不同成員函數實現同一個topic的不同處理(在一個線程中)。

[cpp] view plain copy
  1. #include "ros/ros.h"  
  2. #include "std_msgs/String.h"  
  3.   
  4. /** 
  5.  * This tutorial demonstrates simple receipt of messages over the ROS system, with 
  6.  * multiple callbacks for the same topic.  See the "listener" tutorial for more 
  7.  * information. 
  8.  */  
  9.   
  10. class Listener  
  11. {  
  12. public:  
  13.   void chatter1(const std_msgs::String::ConstPtr& msg) { ROS_INFO("chatter1: [%s]", msg->data.c_str()); }  
  14.   void chatter2(const std_msgs::String::ConstPtr& msg) { ROS_INFO("chatter2: [%s]", msg->data.c_str()); }  
  15.   void chatter3(const std_msgs::String::ConstPtr& msg) { ROS_INFO("chatter3: [%s]", msg->data.c_str()); }  
  16. };  
  17.   
  18. void chatter4(const std_msgs::String::ConstPtr& msg)  
  19. {  
  20.   ROS_INFO("chatter4: [%s]", msg->data.c_str());  
  21. }  
  22.   
  23. int main(int argc, char **argv)  
  24. {  
  25.   ros::init(argc, argv, "listener");  
  26.   ros::NodeHandle n;  
  27.   
  28.   Listener l;  
  29.   ros::Subscriber sub1 = n.subscribe("chatter", 10, &Listener::chatter1, &l);  
  30.   ros::Subscriber sub2 = n.subscribe("chatter", 10, &Listener::chatter2, &l);  
  31.   ros::Subscriber sub3 = n.subscribe("chatter", 10, &Listener::chatter3, &l);  
  32.   ros::Subscriber sub4 = n.subscribe("chatter", 10, chatter4);  
  33.   
  34.   ros::spin();  
  35.   
  36.   return 0;  
  37. }  

3. listener_threaded_spin 

思想:利用一個類的不同成員函數實現同一個topic的不同處理(在四個不同線程中)。

[cpp] view plain copy
  1. #include "ros/ros.h"  
  2. #include "std_msgs/String.h"  
  3.   
  4. #include <boost/thread.hpp>  
  5.   
  6. /** 
  7.  * This tutorial demonstrates simple receipt of messages over the ROS system, using 
  8.  * a threaded Spinner object to receive callbacks in multiple threads at the same time. 
  9.  */  
  10.   
  11. ros::Duration d(0.01);  
  12.   
  13. class Listener  
  14. {  
  15. public:  
  16.   void chatter1(const std_msgs::String::ConstPtr& msg)  
  17.   {  
  18.     ROS_INFO_STREAM("chatter1: [" << msg->data << "] [thread=" << boost::this_thread::get_id() << "]");  
  19.     d.sleep();  
  20.   }  
  21.   void chatter2(const std_msgs::String::ConstPtr& msg)  
  22.   {  
  23.     ROS_INFO_STREAM("chatter2: [" << msg->data << "] [thread=" << boost::this_thread::get_id() << "]");  
  24.     d.sleep();  
  25.   }  
  26.   void chatter3(const std_msgs::String::ConstPtr& msg)  
  27.   {  
  28.     ROS_INFO_STREAM("chatter3: [" << msg->data << "] [thread=" << boost::this_thread::get_id() << "]");  
  29.     d.sleep();  
  30.   }  
  31. };  
  32.   
  33. void chatter4(const std_msgs::String::ConstPtr& msg)  
  34. {  
  35.   ROS_INFO_STREAM("chatter4: [" << msg->data << "] [thread=" << boost::this_thread::get_id() << "]");  
  36.   d.sleep();  
  37. }  
  38.   
  39. int main(int argc, char **argv)  
  40. {  
  41.   ros::init(argc, argv, "listener");  
  42.   ros::NodeHandle n;  
  43.   
  44.   Listener l;  
  45.   ros::Subscriber sub1 = n.subscribe("chatter", 10, &Listener::chatter1, &l);  
  46.   ros::Subscriber sub2 = n.subscribe("chatter", 10, &Listener::chatter2, &l);  
  47.   ros::Subscriber sub3 = n.subscribe("chatter", 10, &Listener::chatter3, &l);  
  48.   ros::Subscriber sub4 = n.subscribe("chatter", 10, chatter4);  
  49.   
  50.   /** 
  51.    * The MultiThreadedSpinner object allows you to specify a number of threads to use 
  52.    * to call callbacks.  If no explicit # is specified, it will use the # of hardware 
  53.    * threads available on your system.  Here we explicitly specify 4 threads. 
  54.    */  
  55.   ros::MultiThreadedSpinner s(4);  
  56.   ros::spin(s);  
  57.   
  58.   return 0;  
  59. }  

4. listener_async_spin 
因爲這裏用的是spinOnce,主線程每隔(1/5秒)打印,然後sleep把控制權交給系統,系統然後就把控制權分配到四個子線程,所以結果看到一共是五個線程。
[cpp] view plain copy
  1. #include "ros/ros.h"  
  2. #include "std_msgs/String.h"  
  3.   
  4. #include <boost/thread.hpp>  
  5.   
  6. /** 
  7.  * This tutorial demonstrates simple receipt of messages over the ROS system, using 
  8.  * an asynchronous Spinner object to receive callbacks in multiple threads at the same time. 
  9.  */  
  10.   
  11. ros::Duration d(0.01);  
  12.   
  13. class Listener  
  14. {  
  15. public:  
  16.   void chatter1(const std_msgs::String::ConstPtr& msg)  
  17.   {  
  18.     ROS_INFO_STREAM("chatter1: [" << msg->data << "] [thread=" << boost::this_thread::get_id() << "]");  
  19.     d.sleep();  
  20.   }  
  21.   void chatter2(const std_msgs::String::ConstPtr& msg)  
  22.   {  
  23.     ROS_INFO_STREAM("chatter2: [" << msg->data << "] [thread=" << boost::this_thread::get_id() << "]");  
  24.     d.sleep();  
  25.   }  
  26.   void chatter3(const std_msgs::String::ConstPtr& msg)  
  27.   {  
  28.     ROS_INFO_STREAM("chatter3: [" << msg->data << "] [thread=" << boost::this_thread::get_id() << "]");  
  29.     d.sleep();  
  30.   }  
  31. };  
  32.   
  33. void chatter4(const std_msgs::String::ConstPtr& msg)  
  34. {  
  35.   ROS_INFO_STREAM("chatter4: [" << msg->data << "] [thread=" << boost::this_thread::get_id() << "]");  
  36.   d.sleep();  
  37. }  
  38.   
  39. int main(int argc, char **argv)  
  40. {  
  41.   ros::init(argc, argv, "listener");  
  42.   ros::NodeHandle n;  
  43.   
  44.   Listener l;  
  45.   ros::Subscriber sub1 = n.subscribe("chatter", 10, &Listener::chatter1, &l);  
  46.   ros::Subscriber sub2 = n.subscribe("chatter", 10, &Listener::chatter2, &l);  
  47.   ros::Subscriber sub3 = n.subscribe("chatter", 10, &Listener::chatter3, &l);  
  48.   ros::Subscriber sub4 = n.subscribe("chatter", 10, chatter4);  
  49.   
  50.   /** 
  51.    * The AsyncSpinner object allows you to specify a number of threads to use 
  52.    * to call callbacks.  If no explicit # is specified, it will use the # of hardware 
  53.    * threads available on your system.  Here we explicitly specify 4 threads. 
  54.    */  
  55.   ros::AsyncSpinner s(4);  
  56.   s.start();  
  57.   
  58.   ros::Rate r(5);  
  59.   while (ros::ok())  
  60.   {  
  61.     ROS_INFO_STREAM("Main thread [" << boost::this_thread::get_id() << "].");  
  62.     r.sleep();  
  63.   }  
  64.   
  65.   return 0;  
  66. }  


============2016.11====一次訂閱四個topic===============

http://wiki.ros.org/message_filters#ApproximateTime_Policy


https://github.com/tum-vision/rgbd_demo/blob/master/src/example.cpp

[cpp] view plain copy
  1. #include <message_filters/subscriber.h>  
  2. #include <message_filters/synchronizer.h>  
  3. #include <message_filters/sync_policies/approximate_time.h>  
  4. #include <sensor_msgs/Image.h>  
  5. #include <sensor_msgs/CameraInfo.h>  
  6. #include <cv_bridge/cv_bridge.h>  
  7. #include <opencv2/imgproc/imgproc.hpp>  
  8. #include <opencv2/highgui/highgui.hpp>  
  9. #include <iostream>  
  10. #include <ros/ros.h>  
  11. #include <pcl_ros/point_cloud.h>  
  12. #include <pcl/point_types.h>  
  13.   
  14. // Note: for colorized point cloud, use PointXYZRGBA  
  15. typedef pcl::PointCloud<pcl::PointXYZ> PointCloud;  
  16.   
  17. using namespace std;  
  18. using namespace sensor_msgs;  
  19. using namespace message_filters;  
  20.   
  21. ros::Publisher pointcloud_pub;  
  22.   
  23. void callback(const ImageConstPtr& image_color_msg,  
  24.         const ImageConstPtr& image_depth_msg,  
  25.         const CameraInfoConstPtr& info_color_msg,  
  26.         const CameraInfoConstPtr& info_depth_msg)   
  27. {  
  28.     // Solve all of perception here...  
  29.     cv::Mat image_color = cv_bridge::toCvCopy(image_color_msg)->image;  
  30.     cv::Mat image_depth = cv_bridge::toCvCopy(image_depth_msg)->image;  
  31.   
  32.     cvtColor(image_color,image_color, CV_RGB2BGR);  
  33.   
  34.     // colorize the image  
  35.     cv::Vec3b color(255,0,0);  
  36.     for(int y=0;y<image_color.rows;y++)   
  37.        {  
  38.         for(int x=0;x<image_color.cols;x++)   
  39.           {  
  40.             float depth = image_depth.at<short int>(cv::Point(x,y)) / 1000.0;  
  41.   
  42.             if( depth == 0)   
  43.                       {  
  44.                 image_color.at<cv::Vec3b>(cv::Point(x,y)) = cv::Vec3b(0,0,255);  
  45.             }  
  46.             if( depth > 1.00)   
  47.                       {  
  48.                 image_color.at<cv::Vec3b>(cv::Point(x,y)) = cv::Vec3b(255,0,0);  
  49.             }  
  50.         }  
  51.     }  
  52.   
  53.     //cout <<"depth[320,240]="<< image_depth.at<short int>(cv::Point(320,240)) / 1000.0 <<"m"<< endl;  
  54.     image_color.at<cv::Vec3b>(cv::Point(320,240)) = cv::Vec3b(255,255,255);  
  55.   
  56.     // get camera intrinsics  
  57.     float fx = info_depth_msg->K[0];  
  58.     float fy = info_depth_msg->K[4];  
  59.     float cx = info_depth_msg->K[2];  
  60.     float cy = info_depth_msg->K[5];  
  61.     //cout << "fx="<< fx << " fy="<<fy<<" cx="<<cx<<" cy="<<cy<<endl;  
  62.   
  63.     // produce a point cloud  
  64.     PointCloud::Ptr pointcloud_msg (new PointCloud);  
  65.     pointcloud_msg->header = image_depth_msg->header;  
  66.   
  67.     pcl::PointXYZ pt;  
  68.     for(int y=0;y<image_color.rows;y+=4)   
  69.         {  
  70.         for(int x=0;x<image_color.cols;x+=4)   
  71.               {  
  72.             float depth = image_depth.at<short int>(cv::Point(x,y)) / 1000.0;  
  73.   
  74.             if(depth>0)   
  75.                   {  
  76.                 pt.x = (x - cx) * depth / fx;  
  77.                 pt.y = (y - cy) * depth / fy;  
  78.                 pt.z = depth;  
  79.                 //cout << pt.x<<" "<<pt.y<<" "<<pt.z<<endl;  
  80.                 pointcloud_msg->points.push_back (pt);  
  81.             }  
  82.         }  
  83.     }  
  84.     pointcloud_msg->height = 1;  
  85.     pointcloud_msg->width = pointcloud_msg->points.size();  
  86.     pointcloud_pub.publish (pointcloud_msg);  
  87.   
  88.     cv::imshow("color", image_color);  
  89.   
  90.     cv::waitKey(3);  
  91. }  
  92.   
  93. int main(int argc, char** argv)   
  94. {  
  95.     ros::init(argc, argv, "vision_node");  
  96.   
  97.     ros::NodeHandle nh;  
  98.   
  99.     message_filters::Subscriber<Image> image_color_sub(nh,"/camera/rgb/image_raw", 1);  
  100.     message_filters::Subscriber<Image> image_depth_sub(nh,"/camera/depth_registered/image_raw", 1);  
  101.     message_filters::Subscriber<CameraInfo> info_color_sub(nh,"/camera/rgb/camera_info", 1);  
  102.     message_filters::Subscriber<CameraInfo> info_depth_sub(nh,"/camera/depth_registered/camera_info", 1);  
  103.     pointcloud_pub = nh.advertise<PointCloud> ("mypoints", 1);  
  104.   
  105.     typedef sync_policies::ApproximateTime<Image, Image, CameraInfo, CameraInfo> MySyncPolicy;  
  106.     Synchronizer<MySyncPolicy> sync(MySyncPolicy(10), image_color_sub, image_depth_sub, info_color_sub, info_depth_sub);  
  107.   
  108.     sync.registerCallback(boost::bind(&callback, _1, _2, _3, _4));  
  109.   
  110.     ros::spin();  
  111.   
  112.     return 0;  
  113. }  
5. listener_with_userdata 

利用boost_bind向消息回調函數傳入多個參數

關於boost_bind以前寫過一個用法簡介http://blog.csdn.net/yaked/article/details/44942773

這裏是boost::bind(&listener::chatterCallback, this,  _1, "User 1" )也即this->chatterCallback( "User1"), _1表示第一個輸入參數, 是個佔位標記。

[cpp] view plain copy
  1. #include "ros/ros.h"  
  2. #include "std_msgs/String.h"  
  3.   
  4. /** 
  5.  * This tutorial demonstrates a simple use of Boost.Bind to pass arbitrary data into a subscription 
  6.  * callback.  For more information on Boost.Bind see the documentation on the boost homepage, 
  7.  * http://www.boost.org/ 
  8.  */  
  9.   
  10.   
  11. class Listener  
  12. {  
  13. public:  
  14.   ros::NodeHandle node_handle_;  
  15.   ros::V_Subscriber subs_;  
  16.   
  17.   Listener(const ros::NodeHandle& node_handle): node_handle_(node_handle)  
  18.   {  
  19.   }  
  20.   
  21.   void init()  
  22.   {  
  23.     subs_.push_back(node_handle_.subscribe<std_msgs::String>("chatter", 1000, boost::bind(&Listener::chatterCallback, this, _1, "User 1")));  
  24.     subs_.push_back(node_handle_.subscribe<std_msgs::String>("chatter", 1000, boost::bind(&Listener::chatterCallback, this, _1, "User 2")));  
  25.     subs_.push_back(node_handle_.subscribe<std_msgs::String>("chatter", 1000, boost::bind(&Listener::chatterCallback, this, _1, "User 3")));  
  26.   }  
  27.   
  28.   void chatterCallback(const std_msgs::String::ConstPtr& msg, std::string user_string)  
  29.   {  
  30.     ROS_INFO("I heard: [%s] with user string [%s]", msg->data.c_str(), user_string.c_str());  
  31.   }  
  32. };  
  33.   
  34. int main(int argc, char **argv)  
  35. {  
  36.   ros::init(argc, argv, "listener_with_userdata");  
  37.   ros::NodeHandle n;  
  38.   
  39.   Listener l(n);  
  40.   l.init();  
  41.   
  42.   ros::spin();  
  43.   
  44.   return 0;  
  45. }  

6. timers

可以參考官網http://wiki.ros.org/roscpp/Overview/Timers

[cpp] view plain copy
  1. #include "ros/ros.h"  
  2.   
  3. /** 
  4.  * This tutorial demonstrates the use of timer callbacks. 
  5.  */  
  6.   
  7. void callback1(const ros::TimerEvent&)  
  8. {  
  9.   ROS_INFO("Callback 1 triggered");  
  10. }  
  11.   
  12. void callback2(const ros::TimerEvent&)  
  13. {  
  14.   ROS_INFO("Callback 2 triggered");  
  15. }  
  16.   
  17. int main(int argc, char **argv)  
  18. {  
  19.   ros::init(argc, argv, "talker");  
  20.   ros::NodeHandle n;  
  21.   
  22.   ros::Timer timer1 = n.createTimer(ros::Duration(0.1), callback1);  
  23.   ros::Timer timer2 = n.createTimer(ros::Duration(1.0), callback2);  
  24.   
  25.   ros::spin();  
  26.   
  27.   return 0;  
  28. }  


======================2016.07=====定時器帶入附加參數===============

[cpp] view plain copy
  1. #include "ros/ros.h"  
  2. #include "cstring"  
  3. #include "iostream"  
  4. #include "han_agv/SocketClient.h"  
  5.   
  6. #include "han_agv/VelEncoder.h"  
  7.   
  8. using namespace std;  
  9.   
  10. const float_t PI = 3.14159;  
  11. const int ENCODER_PER_LOOP = 900;  
  12. const float_t WHEEL_RADIUS = 0.075;  
  13.   
  14. ClientSocket soc;  
  15.   
  16. // ros_tutorials/turtlesim/tutorials/draw_square.cpp  
  17. void timerCallback(const ros::TimerEvent&, ros::Publisher vel_pub)  
  18. {  
  19.   ROS_INFO("Timer callback triggered");  
  20.   AGVDATA buffer;  
  21.   AGVSENSORS buffer_left_encoder_start;  
  22.   AGVSENSORS buffer_right_encoder_start;  
  23.   
  24. //  if(soc.recvMsg(buffer) == 0)  
  25. //  {  
  26. //      cout << "Failed to receive message." << endl;  
  27. //      return;  
  28. //  }  
  29.   
  30.   // Reverse the High and Low byte.  
  31.   double time_delay = 0.1;  
  32.   ros::Duration(time_delay).sleep ();  
  33.   
  34.   buffer.SensorsData.WheelLeft_Encoder[0] = buffer.SensorsData.WheelLeft_Encoder[3];  
  35.   buffer.SensorsData.WheelLeft_Encoder[1] = buffer.SensorsData.WheelLeft_Encoder[2];  
  36.   
  37.   buffer.SensorsData.WheelRight_Encoder[0] = buffer.SensorsData.WheelRight_Encoder[3];  
  38.   buffer.SensorsData.WheelRight_Encoder[1] = buffer.SensorsData.WheelRight_Encoder[2];  
  39.   
  40.    han_agv::VelEncoder vel;  
  41.    vel.left_velocity = 1.0;  
  42.    vel.right_velocity = 2.0;  
  43.   
  44.    vel_pub.publish(vel);  
  45. }  
  46.   
  47. int main(int argc, char** argv)  
  48. {  
  49.         ros::init(argc, argv, "TCPDecode_node");  
  50.         ros::NodeHandle nh;  
  51.         ROS_INFO("create node successfully!");  
  52.   
  53.         ros::Publisher vel_pub = nh.advertise<han_agv::VelEncoder>("HansAGV/encoder_vel", 1);  
  54.         ros::Timer decoder_timer = nh.createTimer(ros::Duration(0.1), boost::bind(timerCallback, _1, vel_pub));  
  55.   
  56.          ros::spin();  
  57. }  

7. notify_connect

[cpp] view plain copy
  1. #include "ros/ros.h"  
  2. #include "std_msgs/String.h"  
  3.   
  4. #include <sstream>  
  5.   
  6. /** 
  7.  * This tutorial demonstrates how to get a callback when a new subscriber connects 
  8.  * to an advertised topic, or a subscriber disconnects. 
  9.  */  
  10.   
  11. uint32_t g_count = 0;  
  12.   
  13. void chatterConnect(const ros::SingleSubscriberPublisher& pub)  
  14. {  
  15.   std_msgs::String msg;  
  16.   std::stringstream ss;  
  17.   ss << "chatter connect #" << g_count++;  
  18.   ROS_INFO("%s", ss.str().c_str());  
  19.   msg.data = ss.str();  
  20.   
  21.   pub.publish(msg);  // This message will get published only to the subscriber that just connected  
  22. }  
  23.   
  24. void chatterDisconnect(const ros::SingleSubscriberPublisher&)  
  25. {  
  26.   ROS_INFO("chatter disconnect");  
  27. }  
  28.   
  29. int main(int argc, char **argv)  
  30. {  
  31.   ros::init(argc, argv, "notify_connect");  
  32.   ros::NodeHandle n;  
  33.   
  34.   /** 
  35.    * This version of advertise() optionally takes a connect/disconnect callback 
  36.    */  
  37.   ros::Publisher pub = n.advertise<std_msgs::String>("chatter", 1000, chatterConnect, chatterDisconnect);  
  38.   
  39.   ros::spin();  
  40.   
  41.   return 0;  
  42. }  
rosrun beginner_tutorials listener_with_userdata 和另外其他任何一個,因爲其他的node名字都重複了,都叫listener。

斷開連接,通知延後了一分多鐘。囧囧!!

發佈了45 篇原創文章 · 獲贊 27 · 訪問量 14萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章