ros 多執行緒模式

MKT-porter發表於2024-09-06

ros::spin() 的作用

在 ROS 中,ros::spin() 的主要作用是:

  • 讓 ROS 節點持續執行,並處理所有註冊的回撥函式。
  • 在內部,它不斷地檢查 ROS 網路中的訊息、服務請求,並呼叫相應的回撥函式來處理它們。

內部原理

  1. 事件迴圈 (Event Loop)

    • ros::spin() 進入一個事件迴圈。這個迴圈不斷地輪詢 ROS 網路,檢查是否有新的訊息到達或者服務請求到達。
    • 如果有訊息到達,它會觸發與該訊息相關聯的回撥函式。
    • 這個迴圈會持續執行,直到程式結束或者節點被關閉。
  2. 訊息佇列 (Message Queue)

    • ROS 使用訊息佇列來儲存接收到的訊息。每個訂閱者都與其訂閱的主題關聯,並將收到的訊息放入佇列中。
    • ros::spin() 從佇列中獲取訊息,並呼叫相應的回撥函式來處理這些訊息。
  3. 執行緒與多工處理

    • ROS 的實現通常是單執行緒的,但可以透過 ros::AsyncSpinner 來支援多執行緒處理,以便併發處理訊息和服務請求。

使用 ros::spin() 的情境

  • 單執行緒節點:如果你的節點需要處理多個訂閱者的回撥,並且你希望在主執行緒中處理所有的回撥,可以使用 ros::spin()
  • 多執行緒節點:如果你希望你的節點能夠在多個執行緒中處理回撥,可以使用 ros::AsyncSpinner,它允許你建立多個執行緒來併發處理訊息。

ros::AsyncSpinner 是 ROS 提供的一個工具,用於在多個執行緒中併發地處理訊息和服務請求。它適用於需要在節點中併發處理多個回撥函式的場景,尤其是當你希望在後臺執行緒中處理訊息或服務請求時。

為什麼使用 ros::AsyncSpinner?

  • 併發處理ros::AsyncSpinner 允許你建立多個執行緒來處理訊息,這樣可以提高程式的響應性,尤其是在訊息處理比較複雜或計算密集型的情況下。
  • 非阻塞的 spin:與 ros::spin() 不同,ros::AsyncSpinner 不會阻塞主執行緒。這使得你可以在主執行緒中執行其他任務(如週期性計算、控制邏輯等)。

#include <ros/ros.h>
#include <std_msgs/String.h>
#include <iostream>

void messageCallback(const std_msgs::String::ConstPtr& msg)
{
    ROS_INFO("Received message: [%s]", msg->data.c_str());
}

int main(int argc, char** argv)
{
    ros::init(argc, argv, "async_spinner_example");
    ros::NodeHandle nh;

    // 建立訂閱者
    ros::Subscriber sub = nh.subscribe("chatter", 1000, messageCallback);

    // 建立 AsyncSpinner 物件,指定使用 4 個執行緒
    ros::AsyncSpinner spinner(4);

    // 啟動 spinner
    spinner.start();

    // 主執行緒可以執行其他操作
    ros::Rate rate(1);  // 1 Hz
    while (ros::ok())
    {
        ROS_INFO("Main thread doing other work...");
        rate.sleep();
    }

    // 停止 spinner
    spinner.stop();

    return 0;
}

  

相關文章