對於一些只訂閱一個話題的簡單節點來說,我們使用ros::spin()進入接收循環,每當有訂閱的話題發布時,進入回調函數接收和處理消息數據。但是更多的時候,一個節點往往要接收和處理不同來源的數據,並且這些數據的產生頻率也各不相同,當我們在一個回調函數里耗費太多時間時,會導致其他回調函數被阻塞,導致數據丟失。這種場合需要給一個節點開辟多個線程,保證數據流的暢通。
為了觀察不同話題的消息被阻塞的情況,可以參考以下實驗代碼
https://github.com/wenglihong/wlh_ros_demo/blob/master/multi_thread_demo/src/multi_topic_pub.cpp
https://github.com/wenglihong/wlh_ros_demo/blob/master/multi_thread_demo/src/multi_topic_sub.cpp
可以看到,發布程序中,以10hz的頻率發布了chatter1和chatter2兩個話題,在訂閱程序中,回調函數1中加入了2s的延時,導致了回調函數2也只能2s才能接收到一個數據,為了是回調函數2能正常接收數據,我研究一下在一個ROS節點中開辟多個線程的方法。
在ROS中,有兩種方法可以在一個節點中開辟多個線程
1.ros::MultiThreadedSpinner
MultiThreadedSpinner類似於ros::spin(),在構造過程中可以指定它所用線程數,但如果不指定線程數或者線程數設置為0,它將在每個cpu內核開辟一個線程。
用法如下
ros::MultiThreadedSpinner spinner(4); // Use 4 threads spinner.spin(); // spin() will not return until the node has been shutdown
2.ros::AsyncSpinner
AsyncSpinner比MultiThreadedSpinner更優,它有start() 和stop() 函數,並且在銷毀的時候會自動停止。下面的用法等價於上面的MultiThreadedSpinner例子。
ros::AsyncSpinner spinner(4); // Use 4 threads spinner.start(); ros::waitForShutdown();
以上代碼片參考了ROS wiki
http://wiki.ros.org/roscpp/Overview/Callbacks%20and%20Spinning
完整的工程代碼可以參考
https://github.com/wenglihong/wlh_ros_demo/tree/master/multi_thread_demo