🔖

rclcpp code reading 3 (TimersInterface)

2023/11/19に公開

はじめに

rclcppのコードリーディングをしています。
基本的にはardent branchのものを読んでいます。(コード量が少ないのと、把握してから変更点を追いかける方針)
なんちゃってロボットエンジニアなので間違っていれば教えてください。
コードは下記から引用しております。
https://github.com/ros2/rclcpp
https://github.com/ros2/rcl
https://github.com/ros2/rcutils
https://github.com/ros2/tutorials

timers interface

tutorialの最初でtimerを作成しています

class MinimalPublisher : public rclcpp::Node
{
  public:
    MinimalPublisher()
    : Node("minimal_publisher"), count_(0)
    {
      publisher_ = this->create_publisher<std_msgs::msg::String>("topic", 10);
      timer_ = this->create_wall_timer(
      500ms, std::bind(&MinimalPublisher::timer_callback, this));
    }

https://github.com/ros2/rclcpp/blob/bea1a52e24eaea0ad141a4d13dfa4606fcf190e7/rclcpp/include/rclcpp/node_impl.hpp#L141-L153

https://github.com/ros2/rclcpp/blob/bea1a52e24eaea0ad141a4d13dfa4606fcf190e7/rclcpp/include/rclcpp/timer.hpp#L180-L181

GenericTimerを作ってadd_timerを呼んでいますね。
add_timer実装はNodeTimersInterfaceを継承するNodeTimersクラスです

https://github.com/ros2/rclcpp/blob/bea1a52e24eaea0ad141a4d13dfa4606fcf190e7/rclcpp/include/rclcpp/node_interfaces/node_timers.hpp#L31

add_timer関数の定義しかないですね。
https://github.com/ros2/rclcpp/blob/bea1a52e24eaea0ad141a4d13dfa4606fcf190e7/rclcpp/include/rclcpp/node_interfaces/node_timers_interface.hpp#L29-L41

実装はtimerをcallback_groupに追加しているだけ。
https://github.com/ros2/rclcpp/blob/bea1a52e24eaea0ad141a4d13dfa4606fcf190e7/rclcpp/src/rclcpp/node_interfaces/node_timers.cpp#L28-L46

rcl_trigger_guard_conditionについては別でまとめます。

GenericTimerをもう少し追います。
まず、GenericTimerはTimerBaseを継承しており、
TimerBaseはrcl_timerをラップしています。
また、rcl_timer_initの第3引数はcallbackを設定できますが、ここではnullptrを渡しています。
https://github.com/ros2/rclcpp/blob/bea1a52e24eaea0ad141a4d13dfa4606fcf190e7/rclcpp/src/rclcpp/timer.cpp#L22-L59

execute_callbackで指定されたcallbackを呼び出します。
callbackはrclではなくrclcpp側で管理する構成になっていますね。
https://github.com/ros2/rclcpp/blob/bea1a52e24eaea0ad141a4d13dfa4606fcf190e7/rclcpp/include/rclcpp/timer.hpp#L131-L166

callbackを呼ぶ前にrcl_timer_callを呼んでいますが、rcl側のcallbackはnullptrなので
実質やってるのはlast_call_timeの設定だけになります。

https://github.com/ros2/rcl/blob/b41d4e333e2b977f7c93a18009cd93a8db5e87f0/rcl/src/rcl/timer.c#L96-L123

その1の記事で説明したように、executorでTimerBaseのコールバックを呼んでます。

https://github.com/ros2/rclcpp/blob/bea1a52e24eaea0ad141a4d13dfa4606fcf190e7/rclcpp/src/rclcpp/executor.cpp#L314-L318

実行可能かどうかはget_next_timerで判定
https://github.com/ros2/rclcpp/blob/bea1a52e24eaea0ad141a4d13dfa4606fcf190e7/rclcpp/src/rclcpp/executor.cpp#L523-L531

callback_groupから、TimerInterfaceを探して、is_readyがtrueならcallbackが実行されます。

https://github.com/ros2/rclcpp/blob/bea1a52e24eaea0ad141a4d13dfa4606fcf190e7/rclcpp/src/rclcpp/executor.cpp#L497-L521

最後に、is_readyの判定がどうなっているか

https://github.com/ros2/rcl/blob/b41d4e333e2b977f7c93a18009cd93a8db5e87f0/rcl/src/rcl/timer.c#L125-L161

ここを読むと、last_call + periodとnowを比較しているということがわかります。

Discussion