Wiki
實時循環與異步通信
本文由簡體中文內容確定性轉換,並受版本化術語表保護。
通信線程負責等設備,控制線程負責按週期處理最新數據。本節先把線程與數據所有權劃清楚,再接串口。
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 總覽 · 上一篇:管理器與資源管理源碼 · 下一篇:虛擬串口與模擬下位機