跳到正文

Wiki

read-update-write控制週期

約 4 分鐘閱讀

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

本節回答:是誰在調 read?訂閱回撥和 update 是否處在同一個迴圈?period 為什麼不能直接寫成 0.01?

1.示例 1:從 main() 找到兩個執行路徑

開啟原始碼閱讀目錄中的 ros2_control/controller_manager/src/ros2_control_node.cpp,按下面順序閱讀:

rclcpp::init
  → 创建 Executor
  → 创建 ControllerManager
  → 创建控制线程 cm_thread
      → 取得当前时间与测得周期
      → cm->read
      → cm->update
      → cm->write
      → 等待下一轮
  → executor->spin

這裡是該版本獨立 ros2_control_node 的結構。Gazebo 後端的呼叫入口在模擬外掛裡,不能假設它也運行同一個獨立主函式。

2.示例 2:逐輪推演命令生效

假設本輪 read 完成之後,ROS 回撥才收到新目標:

第 N 轮 read:读取旧状态
ROS 回调:保存新目标
第 N 轮 update:如果读到新快照,更新 command
第 N 轮 write:下发更新后的 command
第 N+1 轮 read:取得命令作用后的反馈

如果回調發生在本輪 update 之後,新目標就可能到下一輪 update 才被使用。多執行緒排程下,不應承諾每次訊息都在固定的某一輪生效。

3.示例 3:比較頻率

啟動 mini 後,在另外兩個終端分別執行:

ros2 topic hz /joint_states
ros2 topic pub --rate 2 /forward_position_controller/commands \
  std_msgs/msg/Float64MultiArray "{data: [0.2, -0.1]}"

3.1.預期現象

即使命令以 2 Hz 到達,狀態仍可按更高頻率釋出。ros2 topic hz 測量的是接收端觀察到的話題頻率,不是控制執行緒每一輪的精確排程。

3.2.time 與 period 的引數意義

time 是本輪呼叫使用的 ROS 時間;period 是測得的時間間隔。模擬硬體用 period 推進模型,差速里程計用時間差積分。

教程參考版本的獨立節點原始碼中 read、update、write 分別取得當前時間,不能據此假定三個 time 數值逐納秒一致。計算積分應尊重傳入的週期和演算法需要。

Gazebo 使用模擬時間:暫停時模擬時間不前進,不能用現即時間已經過去幾秒來推斷模擬已經執行幾秒。

4.關鍵函式說明

  • ControllerManager::read() 把讀狀態任務交給資源管理器。
  • ControllerManager::update() 排程 active 控制器,並處理相關管理任務。
  • ControllerManager::write() 讓硬體後端處理命令。
  • Executor 負責 ROS 回撥、服務和 Action 等執行,不等於即時控制迴圈。

5.為什麼不要在 read 中 sleep

如果每輪預算約 10 ms,而序列埠讀取阻塞 100 ms,整個鏈路就無法維持原目標週期。後面的通訊實現會把接收放在獨立執行緒,read 只取最新完整反饋。

原始碼入口:ros2_control/controller_manager/src/ros2_control_node.cpp、ros2_control/controller_manager/src/controller_manager.cpp。順著函式呼叫追蹤到 ResourceManager,而不是隻停留在主函式中的三個名字。


返回 Humble 總覽 · 上一篇:硬體與控制器生命週期 · 下一篇:狀態廣播與機器人顯示