先日のROS 2ノードのライフサイクルを理解する (1)の続きです。
本日は、以下に従って、実際にROS 2のライフサイクルの実装方法を見てきます。
Publisher実装
簡単なPublisherのサンプルプログラムでは、main
関数にwhile
ループを直に書いてPublishすることが多かったと思います。
しかし、ライフサイクルを実現するROS 2ノードは、状態遷移後に呼び出されるコールバックメソッドを実装する必要があります。 そのインタフェースを提供しているクラスが、rclcpp_lifecycle::LifecycleNode
です。
https://github.com/ros2/demos/blob/master/lifecycle/src/lifecycle_talker.cpp
を見ると、確かにon_configure()
のように、on_
状態名のメソッドが並んでいます。 クラスのpublicメソッド宣言だけ抜き出しました。
class LifecycleTalker : public rclcpp_lifecycle::LifecycleNode
{
public:
explicit LifecycleTalker(const std::string & node_name,
bool intra_process_comms = false);
void publish();
rcl_lifecycle_ret_t on_configure(const rclcpp_lifecycle::State &);
rcl_lifecycle_ret_t on_activate(const rclcpp_lifecycle::State &);
rcl_lifecycle_ret_t on_deactivate(const rclcpp_lifecycle::State &);
rcl_lifecycle_ret_t on_cleanup(const rclcpp_lifecycle::State &);
}
どのコールバックメソッドも引数に一つ前の状態を引数に、状態遷移の成功・失敗を返り値に取るようです。 rcl_lifecycle_ret_t
は以下の3値を取ります。
RCL_LIFECYCLE_RET_OK # 成功
RCL_LIFECYCLE_RET_FAILURE # 失敗
RCL_LIFECYCLE_RET_ERROR # 捕捉されない例外発生
publish()
メソッドはタイマー呼び出しで実行されるPublishのためのメソッドです。
Subscriber実装
https://github.com/ros2/demos/blob/master/lifecycle/src/lifecycle_listener.cpp
を見ると、Subscriberはrclcpp::node::Node
を使って実装しています。 これはROS 2ノードの基本クラスで、前回のデモのmain
関数では、
auto node = rclcpp::node::Node::make_shared("listener");
という形で、このクラスをそのまま使っていましたが、後述する便利機能を使うため、継承して使用します。 こちらも、クラスのpublicメソッド宣言だけ抜き出しました。
class LifecycleListener : public rclcpp::node::Node
{
public:
explicit LifecycleListener(const std::string & node_name);
void data_callback(const std_msgs::msg::String::SharedPtr msg)
void notification_callback(const lifecycle_msgs::msg::TransitionEvent::SharedPtr msg)
};
data_callback()
メソッドは、トピック受信時に呼び出されるコールバックメソッドです。
もう一つのnotification_callback()
メソッドが、ROS 2特有のコールバックメソッドで、ノードのライフサイクル遷移をトピックとして扱い、Subscribeした場合に呼び出されるメソッドです。
トピックのメッセージの型はlifecycle_msgs::msg::TransitionEvent
です。 これをコールバックメソッドで監視することで、例えば、ノードAがActive状態に遷移した後、ノードBはUnconfigured状態からActive状態に遷移する、といったノード起動の順序関係を制御、プログラミングすることができるようになります。
ROS 1では、このノードのライフサイクルという考え方がなかったため、ノードAが起動し終わるまで、ノードBの起動は少しsleep()
を挟んで待って…、というような場当たり的な制御しかできませんでした。
実行
このデモの実行方法は
https://github.com/ros2/ros2/wiki/Managed-Nodes
に書いてますが、その方法ではPub/Subが始まりませんでした。おそらく情報が古いのでしょう。 深く原因は探っていませんが、
https://github.com/ros2/demos/blob/master/lifecycle/launch/lifecycle_demo_launch.py
というものがあり、これを実行すると同じように実行されました。
その過程で、launch
モジュールを知ったのですが、これがroslaunch
の代わりになっていくんでしょうか? 後で掘り下げて調べてみます。
Comments powered by Disqus.