---
# System prepended metadata

title: micro-ROS 進階通訊篇
tags: [MCU, ROS 2, micro-ROS, NCKU]

---

# micro-ROS 進階通訊篇
## 一、前言與學習目標（Introduction & Objectives）  

### 1. 通訊模型擴展說明  
在嵌入式機器人與 ROS 生態系統中，單純的資料發布／訂閱（Publish/Subscribe）模型雖然強大，但已不足以涵蓋所有應用場景。舉例來說：

- 跳過 “一直發送資料” 的持續流（Publish/Subscribe）模式，當你面對「一次性請求／回應」的場景（例如：主機問 MCU 讀取一次感測器數值），就會用到 Service。  
- 當任務變為「長時間運行 + 多次回報進度」時（例如：機器手臂執行一組動作、導航器從 A 點移動到 B 點、或是感測器掃描整個房間），那麼 Action 模型就更合適。  
- 同時，在資源受限、網路條件不佳（如 Wi-Fi、UDPless、串口連線）或多節點協作的情況下，僅靠預設通訊參數可能產生封包遺失、延遲異常或系統不穩。這就是 Quality of Service（QoS）設定的重要性。  

本篇「進階通訊篇」的目的，就是在已熟悉 Publish/Subscribe 的基礎上，進一步補足 Service、Action 與 QoS 這三大進階維度。透過這樣，你將能在 ROS2／µROS 系統中：  
- 精準選用最合適的通訊模型  
- 調整通訊品質，匹配實務環境（MCU、網路限制、多節點協作）  
- 了解 Host ↔ Agent ↔ MCU 三端架構如何實作並優化  

### 2. 本篇實作方向  
為了使這些理論不只是紙上談兵，我們將採取以下路徑：  
1. **概念解析**：簡明剖析 Topic、Service、Action 三大模型的差異與適用場景。  
2. **參數升級**：深入 QoS 設定（Reliability、Durability、History、Depth 等）與 µROS／DDS／XRCE-DDS 相關限制。  
3. **架構走查**：從通訊協定（DDS／Micro XRCE-DDS）與 Agent 角色講起，理解 Host/MCU 如何互動。  
4. **實作骨架**：提供 Host（Python／C++）與 MCU（C、µROS）雙端程式碼範例，涵蓋 Publisher/Subscriber、Service 與 Action 的基本流程。  
5. **實務挑戰**：分享 MCU 記憶體、頻率、網路不穩、Agent 負載等「真實世界坑」，並給出優化建議。  
6. **延伸練習**：透過練習題或小案例（例如：／reset_device Service、感測器資料可靠傳送、簡單 Action 任務）幫你鞏固理解。  

### 3. 章節架構  
以下為本篇章節總覽：  
| 章節 | 主題 | 重點內容 |  
|------|------|---------|  
| 二 | 通訊模式比較 | Topic vs Service vs Action |  
| 三 | QoS 深入探討 | Reliability, Durability, History 等 |  
| 四 | Transport 與協定 | DDS / XRCE-DDS / Agent 架構 |  
| 五 | 自訂訊息升級 | .msg / .srv / .action 實作 |  
| 六 | Host / MCU 雙端實作 | Python/C++ Host + C Client |  
| 七 | 延伸練習與實務應用 | 多節點、IoT、實體移植 |  
| 八 | 結語與未來方向 | 系統擴充、性能量測、實務問題 |  

### 4. 學習目標  
完成本篇後，你將能：  
- 辨識並選用最適合的通訊模型（Topic／Service／Action）於 µROS／ROS2 系統中。  
- 理解並能設定 QoS 參數，使通訊在資源受限或不理想網路環境中依然穩定。  
- 明白 Host ↔ Agent ↔ MCU 三層架構的運作機制，並能撰寫雙端程式碼。  
- 使用自訂訊息型別（.msg／.srv／.action），並從概念到實作完成端到端範例。  

---

## 二、通訊模式比較（Communication Models）

### 1. Topic  
**定義與用途**  
在 ROS 2／micro‑ROS 中，Topic 是節點之間用來進行「持續資料傳輸」的主要通道。當你有持續、頻繁、非同步的資料流（例如：感測器讀值、機器人狀態、影像資料）時，就會用 Topic。
**進階關鍵點**  
- Topic 為多對多（Many-to-Many）模型：多個 Publisher、或多個 Subscriber 都可以參與。   
- Publisher 決定何時發送資料（非 Client 等待模式）
- 在嵌入式／µROS 環境，除了基本發送/訂閱，還要考慮 QoS 設定（稍後章節）與 Agent/Transport 繞過問題。  
**適用場景**  
- 感測器資料不斷輸出（如溫溼度、LiDAR、IMU）  
- 鏡頭影像串流  
- 機器人定位／狀態更新  
**不要用於**  
- 必須立即回應、等待結果的請求（如讀取檔案、觸發執行） → 這部分要用 Service。  
- 長時間任務且需要進度回報、可能被取消 → 用 Action。  

---

### 2. Service（Request／Response）  
**定義與用途**  
Service 是 ROS2 中提供「同步請求-回應」模型的通訊方式。當一個節點（Client）向另一個節點（Server）發送請求後，會等待回應。適合「一次性」、「快速結束」的操作。 
**結構與流程**  
- .srv 定義檔：包含 Request 與 Response 兩部分  
- Client 發出 request → Server 處理 → 回傳 response  
- 含有同步等待行為（Client 無法繼續直到得到回覆）  
**適用場景**  
- 查詢機器人當前電量／健康狀態  
- 啟動或停止某功能（如：清除地圖、重置設備）  
- 請求 MCU 執行「一次性任務」並回報結果  
**比較簡單的限制**  
- 適合任務短、等待時間可接受的情況  
- 如果任務長、或需要進度回報，會造成 Client 阻塞 → 改用 Action。  

---

### 3. Action（Goal／Feedback／Result）  
**定義與用途**  
Action 是用於「長時間任務」且可能需要「進度回報」或「可取消」的模型。Client 發送一個目標（Goal）後，Server 開始執行，並且能回傳 feedback、最後出結果（Result）。 
**三段結構簡述**  
1. **Goal**：欲達成的任務目標  
2. **Feedback**：執行期間回報進度或狀態  
3. **Result**：任務結束後的最終輸出（成功／失敗）  
**架構與行為特性**  
- 支援預設可取消（Cancelling）或中止（Aborting）任務  
- 客戶端（Client）不需等待整個任務結束即可繼續其餘邏輯  
- 背後實作通常結合 Topic + Service（例如：send_goal Service、feedback Topic、get_result Service） 
**適用場景**  
- 機器人從 A 點導航至 B 點（任務時間較長）  
- 圖像處理任務需掃描整張圖片並回報進度  
- 多步驟機械臂動作序列，需要回報動作進度  
**在 µROS／嵌入式中的考慮點**  
- 因資源受限（MCU 記憶體、RTOS 時間片、Agent 處理能力）使用較少，但理解仍重要  
- 考題可能問結構或選擇理由，而非要求你從零實作  

---

### 4. 模式選擇指引（When to Use Which）  
| 模式      | 適用情境                                  | 典型範例                                      |
|-----------|-------------------------------------------|-----------------------------------------------|
| Topic     | 資料流大、持續性強、不需回覆／請求        | 感測器數據、狀態廣播                           |
| Service   | 一次性請求／快速回應、不需進度回報        | 查詢電量、觸發重置、讀取一次數值               |
| Action    | 長時間任務、需進度回報或可取消            | 導航、掃描任務、機械臂執行多步驟動作            |

**記住這三句話**  
- 想「一直丟資料給大家」 → 用 Topic。  
- 想「發一個請求、要一個答案」 → 用 Service。  
- 想「下個任務給它、看它進度、結束或取消」 → 用 Action。  

---

### 5. 進階提示（對於 µROS／嵌入式環境特別注意）  
- 在 µROS 情境中，不要以為「Topic 一定最好」：因為架構跟 Host／Agent／Client（MCU）有額外通路和資源限制。  
- Service 若處理時間過長，會阻塞 Client，因此對 MCU 端不要用太複雜的 Service。  
- Action 雖然功能齊全，但 MCU 端若資源不足，用 Topic + 自訂同步邏輯有時會更「輕量」。  
- 在章節後續會講的 QoS、Transport、Agent 設定，對模式選擇也有影響：Topic／Service／Action 在不同 QoS 下的行為可能差很多。  

---

## 三、QoS（Quality of Service）深入探討  

### 1. QoS Profile 組成  
在 ROS 2／micro‑ROS 系統中，Quality of Service（QoS）設定允許你針對節點間通訊的「可靠性」「延遲」「資源使用」進行調整。 
以下是主要政策（policies）與其說明：  
- **History（歷史記錄）**：定義 Publisher 存留舊訊息給訂閱者的策略。選項包括 `KEEP_LAST`（僅保留最近 N 筆）或 `KEEP_ALL`（保留所有／受資源限制）。 
- **Depth（深度）**：配合 `KEEP_LAST` 使用，定義隊列（緩衝）大小。例如 depth = 5 表示保留最近五筆訊息。  
- **Reliability（可靠性）**：定義資料送達保障程度。`RELIABLE` 保證送達（有重傳機制），`BEST_EFFORT` 儘力送達但可能遺失。
- **Durability（耐久性）**：定義新訂閱者加入後是否可看到舊訊息。`VOLATILE`：不保留、只對當下訂閱者；`TRANSIENT_LOCAL`：保留最近一筆／幾筆資料供後加入者讀。 
- **Deadline**：定義預期兩次資料發布之間的最大時間間隔，若超過會觸發事件。
- **Lifespan**：定義資料被視為「過期／無效」之前的最大存活時間。 
- **Liveliness + LeaseDuration**：定義節點或出版者是否維護「活著」狀態的機制。

> **提醒**：只要 QoS 設定不相容（Publisher／Subscriber 或 Client／Server 之間），即便訊息型別、Topic 名稱都對，通訊仍可能失敗。  

---

### 2. micro-ROS 與 QoS 在嵌入式中的限制與考量  
在嵌入式／微控制器環境中使用 micro-ROS，雖然 QoS 概念與 ROS2 相同，但**實務限制**必須被納入設計。  
- MCU 的記憶體、Flash、CPU 通常比 Host 少很多，因此若設定 `KEEP_ALL` 或 depth 很大，可能導致記憶體不足甚至系統崩潰。  
- 在 micro-ROS 所用的底層通訊協定 Micro XRCE‑DDS 中，即便你選 `RELIABLE`，底層仍可能因為代理（Agent）＋UDP／串口傳輸造成遺失或延遲。  
- 在無線網路、RS-232、或頻率很高的場景，「少許資料遺失比整個系統卡住更好」的情況不少。這時候 `BEST_EFFORT` + 小隊列可能比 `RELIABLE` + 大隊列還更實際。  
- 設定 QoS 時，不只是程式碼中填值那麼簡單：你還要考慮通道（Transport）、Agent 負載、MCU 資源、頻率與資料量這些變數。  

---

### 3. 各通訊模型與 QoS 的搭配  
這裡快速比對「Topic／Service／Action」三種通訊模型在實務上常用的 QoS 設定建議。你在考場看到問 QoS ＋模型時就能秒答。  

| 通訊模型      | 建議 QoS 設定                                          | 為什麼                                               |
|---------------|--------------------------------------------------------|------------------------------------------------------|
| **Topic**     | 感測器資料流：`BEST_EFFORT` + 小隊列（depth 5-10）<br>關鍵狀態／命令：`RELIABLE` + 適中隊列（depth 10-20） | 資料量大、頻率高、偶有遺失可忍；狀態／命令不能遺失     |
| **Service**   | 通常 `RELIABLE` + 預設隊列                              | 是同步請求-回應模式，不能丟失結果                         |
| **Action**    | Goal: 快速觸發 <br>Feedback: 可用 `BEST_EFFORT` <br>Result: 使用 `RELIABLE` | 長任務需回報進度可容錯，結果不能遺失                     |

---

### 4. 實作範例（Host C++ + MCU C++）  

**Host（C++）範例：**  
```cpp
#include <rclcpp/rclcpp.hpp>
#include <my_pkg/msg/SensorData.hpp>

int main(int argc, char * argv[])
{
  rclcpp::init(argc, argv);
  auto node = rclcpp::Node::make_shared("sensor_publisher");

  auto qos_profile = rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(rmw_qos_profile_default))
                        .reliable()
                        .keep_last(5);

  auto publisher = node->create_publisher<my_pkg::msg::SensorData>("/sensor/data", qos_profile);

  rclcpp::Rate loop_rate(10); // 10 Hz
  while (rclcpp::ok()) {
    auto message = my_pkg::msg::SensorData();
    // 填充 message 的資料欄位……
    publisher->publish(message);
    rclcpp::spin_some(node);
    loop_rate.sleep();
  }

  rclcpp::shutdown();
  return 0;
}
````

**MCU（C++）範例：**

```cpp
#include <rclcpp/rclcpp.hpp>
#include <my_pkg/msg/SensorData.hpp>
#include "rclc/rclc.h"  // 假設使用 rclc 或對應 MCU C++ API

int main()
{
  // MCU 通常建立 rclc node, executor 等
  rcl_node_t * node = rclc_node_init_default(...);
  rcl_publisher_t publisher;

  rcl_publisher_options_t opts = rcl_publisher_get_default_options();
  opts.qos.reliability = RMW_QOS_POLICY_RELIABILITY_RELIABLE;
  opts.qos.history = RMW_QOS_POLICY_HISTORY_KEEP_LAST;
  opts.qos.depth = 5;

  rcl_publisher_init(
    &publisher,
    node,
    ROSIDL_GET_MSG_TYPE_SUPPORT(my_pkg, msg, SensorData),
    "/sensor/data",
    &opts
  );

  while (rcl_ok()) {
    my_pkg__msg__SensorData msg = my_pkg__msg__SensorData__create();
    // 填充資料
    rcl_publish(&publisher, &msg, nullptr);
    // MCU 需考慮延遲、記憶體、回呼處理
  }

  return 0;
}
```

> 補充說明：在 MCU 端你還要確保 static memory、stack size、回呼函式效能、串口／通道穩定這些條件。

---

### 5. 測試項目與預期結果

做這些實驗可幫你更理解 QoS 設定如何影響系統。也很適合在考前練一遍。

| 項目                        | 設定                  | 預期結果                                           |
| ------------------------- | ------------------- | ---------------------------------------------- |
| Reliability = RELIABLE    | depth = 10          | 資料可靠送達但延遲可能稍高                                  |
| Reliability = BEST_EFFORT | depth = 1           | 延遲低、資源用少，但可能頻繁遺失封包                             |
| Depth = 1 vs Depth = 10   | History = KEEP_LAST | 小 depth：舊訊息快速被覆蓋 <br>大 depth：保留較多訊息但記憶體／延遲負擔更高 |

---

### 6. 常見坑與除錯建議

* Publisher 設 `RELIABLE` 而 Subscriber 設 `BEST_EFFORT` → **不相容**，可能無法收到資料。
* 設定過深隊列在 MCU 上直接可能導致記憶體不足或系統卡住。
* 使用 `RELIABLE` 但頻率太高、沒有適當時間片在 MCU 上，很容易造成堆積延遲。
* 在無線/低速通道中硬用 `RELIABLE` 可能比用 `BEST_EFFORT`還差，因為重傳＋代理負載加大。
* 忘了 Durability 設定：若系統需要「新訂閱者加入後見到最後狀態」，必須用 `TRANSIENT_LOCAL`。

---

## 四、Transport 與協定（Transport & Protocol）  

### 1. Data Distribution Service (DDS) 架構概述  
在 ROS 2 中，DDS 是底層通訊的核心中介。DDS 定義了資料中心發佈／訂閱模型（Publish-Subscribe），同時支援 QoS 設定、探索機制（discovery）、跨平台互通。:contentReference[oaicite:2]{index=2}  
簡要說明：  
- Publisher／Subscriber 模型對應到 DDS 中的 DataWriter／DataReader。  
- Nodes（節點）成為 DDS Participants，加入 Global Data Space。  
- 透過 RTPS 或其他底層協定進行封包傳輸。  

### 2. DDS‑XRCE（µROS）架構與通訊鏈路  
當 MCU／微控制器要加入 ROS 2 生態（例如 micro‑ROS）時，不直接用 DDS，而是用 DDS-XRCE（DDS for eXtremely Resource Constrained Environments）。:contentReference[oaicite:5]{index=5}  
特色如下：  
- 採 Client-Server 架構：MCU 端為 XRCE Client，主機端為 XRCE Agent，Agent 代表 Client 存取 DDS Global Data Space。:contentReference[oaicite:6]{index=6}  
- 支援多傳輸通道：UDP、TCP、Serial 等。:contentReference[oaicite:7]{index=7}  
- 設計為低資源消耗：典型記憶體為 < 75 KB Flash + ~3 KB RAM。:contentReference[oaicite:8]{index=8}  

### 3. Agent／Client／Transport 三層資料流圖與解說  
在 micro-ROS 系統中，典型資料流程如下：  
- MCU（XRCE Client）透過 Transport（例如：UART、UDP）將資料傳送給 XRCE Agent。  
- Agent 接收 XRCE 封包後，轉成 DDS 訊息並發佈至 ROS2 系統內的 Subscriber。  
- 反方向亦然：ROS2 系統中的 Publisher 資料可經 Agent 傳至 MCU 端 Subscriber。  
**教學提醒**：在考場可能會出「Agent 是什麼角色？」「為什麼 MCU 不能直接用 DDS？」「Transport 層有哪些限制？」這類題。  

### 4. 傳輸通道選擇（Transport）與實務考量  
在 micro-ROS／嵌入式環境中，「傳輸」比你在 PC 開發時要複雜。你必須考慮通道、頻率、延遲、資源限制。部分常見通道與考量：  
- **Serial (UART)**：硬體需求低、能在 MCU 上使用，但頻率低、錯誤率高、可能因通道瓶頸導致資料堆積。  
- **UDP**：延遲較低、適合大量資料流，但不保證可靠性。  
- **TCP**：提供可靠性，但手續繁複、延遲可能增加、資源消耗較大。  
- **Shared Memory／RPMsg／OpenAMP**（當 MCU 與 Host 在同一 SoC 上）：延遲最小但硬體依賴強。  
**考試常見題**：  
> 若 MCU 選用 UART 傳資料，但資料頻率為 1 ms／筆、payload 500 bytes，哪裡最可能出問題？  
> → 通道頻寬、記憶體積壓、Agent／MCU 處理能力不足。  

### 5. 系統整合與效能瓶頸  
實務中你會遇到這些坑，考場也會問：  
- MCU → Agent → DDS 的轉換會產生額外延遲：Agent 必須解封包、轉格式、處理錯誤。  
- 若有大量 Topic、高頻率、大 payload 資料，MCU 可能因記憶體或 CPU 不夠而掉封包。  
- 傳輸通道如無線／低速環境時，要特別注意 QoS＋Transport 的配合。  
- Agent 需與 Host 網路同步：Topic／Participant 數量多可能造成負載高、處理延遲大。  
在考題中你可能被問：「系統延遲比預期高，可能原因是什麼？」你要從 Transport 層分析。  

### 6. 實作範例（C++）  
以下是簡化的 C++ 範例，描述 Agent 建立 UDP 傳輸與 MCU 端通訊流程（教學示範，實務中可能用 C 或特定 API）：

```cpp
// Host (Agent) 側：初始化 UDP Transport
#include <MicroXrceAgent.hpp>
#include <FastDDS/Publisher.hpp>

int main()
{
  XRCEAgent agent;
  agent.init_transport_udp("0.0.0.0", 7400);

  while (agent.running()) {
    XRCEMessage msg;
    if (agent.receive(msg)) {
      ddsPublisher.publish(msg.to_dds());
    }
  }
  return 0;
}
```

```cpp
// MCU (Client) 側：使用 XRCE Client 傳輸 SensorData
#include <MicroXrceClient.hpp>
#include <my_pkg/msg/SensorData.hpp>

int main()
{
  MicroXrceClient client;
  client.init_transport_udp("192.168.1.100", 7400);

  my_pkg::msg::SensorData data{1, 25.0f, 60.0f};
  while (true) {
    client.publish("/sensor/data", data);
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
  }
  return 0;
}
```

> 補充說明：實務中 Client 端還要設定 Token、Stream、連線保護、錯誤處理、記憶體池管理等。

---

## 五、自訂訊息升級（Custom Message Upgrade）

### 1. `.msg / .srv / .action` 檔案格式說明  
在 ROS 2／micro‑ROS 系統中，訊息、服務、動作的介面定義是透過三種檔案格式完成的：  
- `.msg` 檔案：用於定義一條資料流（message）。
- `.srv` 檔案：用於定義一次性請求回應的資料型別（service：Request／Response）。
- `.action` 檔案：用於定義一個長時任務（action），內含 Goal、Feedback、Result 三段資料。

這些檔案的格式都有固定語法，如 `.srv` 檔案中，Request 與 Response 之間用 `---` 分隔。  

---

### 2. 自訂 `.msg` 範例：`SensorData.msg`  
假設你要在 MCU /感測器系統上傳送自訂資料包，以下是一個範例：  
```text
int32 id
float32 temperature
float32 humidity
string source
````

這表示：

* `id`：整數型別感測器編號
* `temperature`：單精度浮點數溫度值
* `humidity`：單精度浮點數濕度值
* `source`：字串，描述資料來源或節點名稱

撰寫自訂 `.msg` 的步驟包括：

1. 在 interface package 下創建 `msg/` 資料夾。
2. 新建 `SensorData.msg` 檔案並填寫如上內容。
3. 在 `CMakeLists.txt` 及 `package.xml` 中加入生成指令與依賴設定。

---

### 3. 建置步驟（修改 `package.xml`／`CMakeLists.txt`）

為了讓你的自訂介面檔被編譯並可被其他節點使用（C++／C／Python），你必須做以下設定：

* 在 `package.xml` 中加入：

  ```xml
  <buildtool_depend>rosidl_default_generators</buildtool_depend>
  <exec_depend>rosidl_default_runtime</exec_depend>
  <member_of_group>rosidl_interface_packages</member_of_group>
  ```

  並宣告對其他用到的訊息包（如 `geometry_msgs`）的 `<depend>`。 ([The Robotics Back-End][2])
* 在 `CMakeLists.txt` 中加入：

  ```cmake
  find_package(rosidl_default_generators REQUIRED)
  rosidl_generate_interfaces(${PROJECT_NAME}
    "msg/SensorData.msg"
    "srv/…"
    "action/…"
    DEPENDENCIES geometry_msgs
  )
  ```
* build workspace：

  ````bash
  colcon build --packages-select <your_interfaces_package>
  source install/setup.bash
  ``` :contentReference[oaicite:8]{index=8}  
  ````

---

### 4. Python／C++ 節點使用自訂訊息範例

假設你已定義 `SensorData.msg` 並 build 成功，以下是在 Host（C++）端使用範例：

```cpp
#include <rclcpp/rclcpp.hpp>
#include <my_interfaces_pkg/msg/sensor_data.hpp>

void callback(const my_interfaces_pkg::msg::SensorData::SharedPtr msg)
{
  RCLCPP_INFO(
    rclcpp::get_logger("sub"),
    "Received id=%d temperature=%.2f humidity=%.2f source=%s",
    msg->id, msg->temperature, msg->humidity, msg->source.c_str()
  );
}

int main(int argc, char * argv[])
{
  rclcpp::init(argc, argv);
  auto node = rclcpp::Node::make_shared("sensor_subscriber");
  auto sub = node->create_subscription<my_interfaces_pkg::msg::SensorData>(
    "/sensor/data", 10, callback
  );
  rclcpp::spin(node);
  rclcpp::shutdown();
  return 0;
}
```

使用自訂服務 `.srv` 或動作 `.action` 的流程與此類似，只是你換成 `srv`／`action` 的 API，並注意 Goal／Feedback／Result 的架構。 

---

### 5. 延伸：`.srv`／`.action` 用法簡述

* **.srv** 範例：

  ```text
  int32 id
  float32 value
  ---
  bool success
  ```

  表示：Client 提交 `id` 與 `value`，Server 回傳 `success`。
* **.action** 範例：

  ```text
  int32 goal_id
  ---
  bool result_ok
  ---
  float32 progress
  ```

  表示：Goal 傳入 `goal_id`，Result 回傳 `result_ok`，Feedback 回傳 `progress`。
  你就能在動作執行時回報進度。

---

## 六、Host／MCU 雙端實作（Host & MCU Dual-end Implementation）

### 1. Host（C++）節點架構說明  
在 ROS 2（C++）端，我們典型使用 rclcpp 建立節點、Publisher／Subscriber、Service Client 或 Action Client。  
- 節點初始化：`rclcpp::init(argc, argv)` → 建立 `rclcpp::Node::make_shared("node_name")`  
- 建立通訊物件：publisher, subscription, client or action  
- 處理迴圈：使用 `rclcpp::spin(node)` 或者 `rclcpp::spin_some(node)` + `rclcpp::Rate`進行定周期操作  
範例流程：Publisher → 發送自訂訊息 → Subscriber 端處理 → MCU 端接收或回應。

### 2. MCU（C／C++）節點架構說明  
在 micro‑ROS（MCU）端，因資源受限，我們會選用 rclc (或微控制器支援的 ROS 客户端库)並搭配 XRCE-DDS 通訊。關鍵點：  
- 靜態記憶體分配：避免動態 new/delete，使用 static buffer 或 pool。  
- 建立節點：`rclc_node_init_default()` 或對應 C++ 封裝。  
- 建立 Publisher／Subscriber／Service／Action：使用 `rcl_publisher_init()`、`rcl_subscription_init()` 等低階 API。  
- 主迴圈注意：不允許阻塞過久、必須處理 Agent 連線、監控記憶體與時間片。

### 3. 建立 Publisher／Subscriber／Service／Action 程式碼骨架  
以下示範 C++ 語法骨架（Host 端）及 MCU 端（C++ 或 rclc）骨架，作為學習範本。

**Host（C++）Publisher 範例**：  
```cpp
#include <rclcpp/rclcpp.hpp>
#include <my_interfaces_pkg/msg/sensor_data.hpp>

int main(int argc, char * argv[])
{
  rclcpp::init(argc, argv);
  auto node = rclcpp::Node::make_shared("host_sensor_publisher");
  auto publisher = node->create_publisher<my_interfaces_pkg::msg::SensorData>("/sensor/data", 10);

  rclcpp::Rate rate(10); // 10 Hz
  while (rclcpp::ok()) {
    auto msg = my_interfaces_pkg::msg::SensorData();
    // 填充 msg.id, msg.temperature, msg.humidity, msg.source
    publisher->publish(msg);
    rclcpp::spin_some(node);
    rate.sleep();
  }
  rclcpp::shutdown();
  return 0;
}
````

**MCU（C++／rclc）Publisher 範例**：

```cpp
#include <rclc/rclc.h>
#include <my_interfaces_pkg/msg/sensor_data.h>

int main()
{
  rcl_allocator_t allocator = rcl_get_default_allocator();
  rclc_support_t support;
  rclc_support_init(&support, 0, nullptr, &allocator);

  rcl_node_t node;
  rclc_node_init_default(&node, "mcu_sensor_node", "", &support);

  rcl_publisher_t publisher;
  rcl_publisher_options_t opts = rcl_publisher_get_default_options();
  opts.qos.reliability = RMW_QOS_POLICY_RELIABILITY_RELIABLE;
  opts.qos.history = RMW_QOS_POLICY_HISTORY_KEEP_LAST;
  opts.qos.depth = 5;

  rcl_publisher_init(&publisher,
    &node,
    ROSIDL_GET_MSG_TYPE_SUPPORT(my_interfaces_pkg, msg, SensorData),
    "/sensor/data",
    &opts);

  while (rcl_ok()) {
    my_interfaces_pkg__msg__SensorData msg = my_interfaces_pkg__msg__SensorData__create();
    // 填充 msg fields
    rcl_publish(&publisher, &msg, nullptr);
    rclc_executor_spin_some(&support.executor, RCL_MS_TO_NS(100));
  }
  return 0;
}
```

### 4. 記憶體、資源與效能限制最佳化

在 MCU 端你必須特別注意以下限制：

* **記憶體池與 stack 大小**：訂閱／回呼數過多、隊列過大容易耗盡 RAM。
* **Publisher／Subscriber 頻率控制**：頻率太高 + 資料量過大 → Agent ／ MCU 端壓力大、可能遺失訊息或掉線。
* **串口／通道穩定性**：若使用 Serial／WiFi，連線不穩或重連機制不佳會導致通訊中斷。
* **Agent 延遲與 MCU 處理週期**：Host ⇄ Agent ⇄ MCU 的延遲必納入設計（尤其 QoS 選擇、頻率設計、隊列 depth 設定）。

### 5. 移植注意事項：Linux 模擬 vs 實體開發（ESP32／STM32）

* **Linux 模擬**：使用 ROS2 環境模擬 MCU 端，可快速調試 Topic、Service、Action，但無 RTOS／硬體限制，表現比真實 MCU 理想。
* **實體開發**：比如 ESP32 或 STM32，需考慮實體 MCU 規格、電源、通道、藍牙／WiFi、冷啟動、重連機制、代理負載、記憶體與 RTOS 時間片。
* **建議流程**：先在模擬環境完成邏輯，再移植至實體，並逐步測試 MCU 資源使用、連線穩定、延遲狀況。

### 6. 小練習

請你在 Host 端建立一個 Publisher 傳送 SensorData，自訂 .msg 檔案；MCU 端建一個 Subscriber 接收資料並回傳 ack 訊息（透過 Service 模型）。

* 測試 Topic 頻率從 10 Hz 提升到 100 Hz，觀察 MCU 端是否遺失訊息。
* 調整 QoS 設定（如 Reliable vs Best Effort），觀察 效果。
* 測試断線重連：MCU 重啟後訂閱 Topic 是否能恢復。

---

## 七、延伸練習與實務應用（Extended Exercises & Practical Applications）  

### 1. 多節點協作示例：感測器網絡與機器人集群  
在 micro-ROS／ROS 2 系統中，當你不只是單台 MCU＋Host，而是多個 MCU 節點、Host 節點、雲端伺服器協作時，下列為你可實作的架構：  
- 多個 MCU 節點（如 ESP32、STM32）分別連接不同感測器、執行不同控制任務；  
- 各 MCU 透過 Micro XRCE-DDS Agent 與 ROS 2 網絡連接，將資料匯聚到 Host／伺服器；  
- Host 節點中的 ROS 2 節點負責整合資料、策略決策或發布指令給機器人／裝置；  
- 將部分節點佈署在雲端／邊緣設備，用於資料儲存、分析、儀表板展示。  
你可以設計練習題：  
1. 建立 3 台 MCU 節點，每台分別發布不同資料（如溫度、濕度、加速度）至 ROS 2 網絡。  
2. Host 節點訂閱這些資料，進行合併與簡單邏輯（如：若溫度＞30 °C 且加速度＞x，則發出警報指令）。  
3. 將指令以 Service ／ Action 形式回送至 MCU 節點，讓 MCU 執行動作（如：啟動風扇、儲存資料、顯示警示）。  
4. 模擬通訊異常（如：斷線、頻率降低、資料遺失）並觀察 QoS／傳輸選擇對系統影響。  

### 2. IoT 與雲端整合應用  
嵌入式系統＋ ROS 2 不再侷限於機器人，亦可擴展至 IoT 與雲端架構。舉例：  
- 使用 MQTT ／ HTTP 與 ROS 2 整合，將 MCU 資料送至雲端平台；例如 EMQX + micro-ROS 整合應用。 :contentReference[oaicite:3]{index=3}  
- 在 智慧倉儲、智慧農業、智慧工廠中，部署多個 MCU 感測器＋機器人，透過 ROS 2 及 micro-ROS 實現分散式控制與協作。 :contentReference[oaicite:4]{index=4}  
- 將 ROS 2 節點、MCU 節點及雲端服務整合，在雲端呈現儀表板、資料分析、遠端監控。  
練習題：  
- 將 MCU 端資料通過 micro-ROS Agent → ROS 2 節點 → MQTT Broker，再送至雲端資料庫。  
- 設計雲端儀表板，監控多個節點的狀態（如：聯網狀態、資料頻率、漏包率），並在異常時發出通知。  

### 3. 實體移植與資源限制評估  
當你將系統從實驗環境移植至實體設備（如 STM32 ＋ FreeRTOS、ESP32、樹莓派＋MCU），需特別注意資源與環境限制：  
- 硬體通道／網路品質：WiFi、串口、CAN 總線、4G／5G 模組；  
- MCU 記憶體、Flash、CPU 頻率、RTOS／任務設計；  
- Agent 負載、節點數量、Topic 數量、頻率、資料大小；  
- 系統部署佈景：邊緣-雲架構、節點重啟／恢復機制、時延監控。  
練習題：  
1. 將 MCU 執行頻率從 10 Hz 提升至 100 Hz 並測量漏包／延遲。  
2. 在 WiFi 不穩條件下，改用 串口 ／ CAN 鏈路 ＋ depth ＝ 1、BEST_EFFORT QoS，觀察通訊品質差異。  
3. 部署 ROS 2 節點於邊緣設備，測試 Agent 重啟／ MCU 重啟後系統恢復流程。  

### 4. 練習題庫與模擬考題  
| 題號 | 題目 | 要點 |  
|------|------|------|  
| Q7-1 | 當 MCU 節點需要定期傳送資料給 Host／雲端，但通道時常不穩定，你會選哪種 QoS ＋ 通訊模型？ | 減少漏包／控制延遲／資源限制 |  
| Q7-2 | 在多節點協作系統中，若 Agent 負載過高造成延遲，你可以從哪三個維度著手優化？ | 節點數、頻率、傳輸通道 |  
| Q7-3 | 將 ROS 2 系統擴展至雲端整合時，資料安全／鑑權／資料一致性需考慮哪些？ | Protocol 選擇、Broker 結構、資料同步 |  

### 5. 實務應用案例展示  
- 在「智慧農業」專案中，多台 MCU 感測器部署於田間，使用 micro-ROS 透過 UDP 傳送資料至 Host，Host 再將資料上傳至雲端分析，並根據分析結果觸發灌溉裝置。  
- 在「機器人倉儲」系統中，機器人與 MCU 感測單元協作，透過 ROS 2 控制路徑規劃，同時 MCU 回報感測器資料並接受 Action 指令執行收／放貨流程。  

