跳到正文

Wiki

實時循環與異步通信

約 4 分鐘閱讀

本文由簡體中文內容確定性轉換,並受版本化術語表保護。

通信線程負責等設備,控制線程負責按週期處理最新數據。本節先把線程與數據所有權劃清楚,再接串口。

1.示例 1:把兩條執行路徑畫出來

通信线程
  接收字节 → 拼帧 → 校验 → 保存完整反馈快照
  读取待发目标 → 打包 → 异步写设备

控制线程
  read → 取最新完整反馈,更新状态接口
  update → 控制器处理目标与反馈
  write → 保存待发目标,不等待设备回复

串口可能以 50 Hz 返回,控制循環以 100 Hz 運行。某一輪沒有新反饋時,可以使用上一份仍有效的快照;超過明確的超時時間則進入錯誤處理。

2.示例 2:閲讀 realtime buffer

打開 realtime_tools/include/realtime_tools/realtime_buffer.hpp,定位:

  • writeFromNonRT(data):非實時側寫入。
  • readFromRT():實時側嘗試取得最新數據。

當前版本 readFromRT 使用 try-lock;拿不到鎖時繼續返回現有實時側數據。它不是“每讀一次都等待寫線程完成”。writeFromNonRT 則可能等待,所以不能因為類型名字包含 realtime,就把所有成員函數都放進實時循環。

2.1.為什麼控制器採用固定大小的 Target

在從零編寫控制器中,目標快照只有兩個 double 和一個標記。數據驗證在接收回調完成,update 只讀快照並寫接口,減少控制週期中的字符串處理與動態分配。

readFromRT() 返回的指針不應被任意線程長期保存後繼續訪問。按類的併發約定使用,並在當前 update 中複製需要的數據。

3.示例 3:判斷一段 read 是否合適

下面是反例偽代碼,不應作為插件實現:

read:
  阻塞读取,直到收到完整一帧
  等待设备回复
  sleep 100 ms
  返回

如果一輪只有約 10 ms 預算,上述等待會拖延所有使用該管理器的控制器。

下一章提供可運行的學習實現:接收與寫串口都在獨立 Asio 線程;read/write 用 try-lock 交接固定大小數據;取不到鎖保留上一份快照,並用反饋時間戳檢查過期。

3.1.try-lock 是否就等於硬實時

不是。線程調度、驅動、原子操作實現、內存、日誌和算法都影響實時性。下一章代碼是可觀察的通信教學實現,沒有宣稱經過硬實時認證。

4.數據交接的四個問題

問題 本教程的處理
一次反饋是否完整 先拼幀、解析、驗證,再更新整組快照
數據是否過期 單調時鐘記錄最近有效反饋時間
消費速度低於產生速度 狀態只保留最新值,丟棄過期快照
發包是否堆積 同一時刻只保留一個異步寫操作

“只保留最新值”適合連續位置目標,未必適合使能、復位或離散任務。後者往往需要可靠隊列、序號與確認機制。

5.兩種超時必須區分

上游命令超時意味着目標不再更新;下游反饋超時意味着設備狀態不再可信。差速控制器的 cmd_vel_timeout 不能代替硬件反饋看門狗,ROS 節點退出也不能代替下位機獨立看門狗。

源碼:realtime_tools/include/realtime_tools/realtime_buffer.hpp、ros2_controllers/forward_command_controller/src/forward_controllers_base.cpp。對照 writeFromNonRT 和 readFromRT 的調用線程,而不只看函數名。


返回 Humble 總覽 · 上一篇:管理器與資源管理源碼 · 下一篇:虛擬串口與模擬下位機