Wiki
read-update-write控制週期
本文由簡體中文內容確定性轉換,並受版本化術語表保護。
本節回答:是誰在調 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 總覽 · 上一篇:硬件與控制器生命週期 · 下一篇:狀態廣播與機械人顯示