TechMagicでは、いくつかのプロジェクトでROS 2を使用しています。今回は、使っている中で問題になった点をTipsとして紹介したいと思います。
ServiceやActionを呼びたい!
ROS 2でロボットのソフトウェアを設計する場合、Nodeが実行単位の基本になります。Nodeは、ROS 2の基本的な4つの機能である、Topic, Service, Action, Parameterのサーバーを提供します。このあたりの基本については、まずROS 2のチュートリアルを参照ください。
さて、それらのサーバーがあったとして、呼び出すクライアント側も作りたいでしょう。チュートリアルには以下のようなクライアントNodeの例が載っています。
これらはとても単純なクライアントの例で、cppの場合は、async_send_request()やasync_send_goal()を呼び出し、spin_until_future_complete()という関数で、返ってくるfutureオブジェクトの完了を待っています。関数名は微妙に違いますが、Pythonでも同じです。
コールバックの中から呼びたい!
ある程度複雑なNodeでは、ActionやServiceやTimerのコールバックの中から、他のServiceやActionをクライアントとして呼びたくなる場合が多いと思います。
例えば、移動ロボットがA地点、B地点、C地点を順番に巡回するような”MoveABC”というActionを提供するNodeを作成したいとしましょう。そして、A地点に移動するAction (MoveA)、B地点に移動するAction (MoveB)、C地点に移動するAction (MoveC)は、他のNodeが提供しているとします。この場合、”MoveABC”を提供するNodeは、そのActionのコールバックの中でまずMoveAをクライアントとして呼び、その完了を待ち、その後同様にMoveB, MoveCを順番に呼ぶことで実現するはずです。
Actionサーバーのコールバック内で別のActionを呼ぶ例
他にも、たとえば1秒おきに周期的に何らかのActionを呼ぶNodeが欲しいとします。ROS2では周期処理のためにはTimerを作成し、そのコールバック関数が周期的に呼ばれ、その中からクライアントとしてActionやServiceを呼び出すことになります。このような使い方は、実際のロボットシステムのいろいろなところに出てきます。
しかし、これらを行う場合にはチュートリアルには書かれていない注意点がいくつかあり、それを知らないとすごくハマります。というか、ハマりました…以下、Actionのコールバックを例にして紹介します。
これから例として作るNodeは、以下のような動作とします。
-
Actionとして /proxy (action_tutorial_interfaces/Fibonacci.action)を提供する
-
Nodeの中では実際のフィボナッチ数列の計算は行わない
-
コールバックの中でaction_tutorial_cppのfibonacci_action_server/fibonacciを呼び出し、その結果をそのまま返す
-
つまり、コールバックのなかで別のactionを呼んでその結果を返す、いわゆる代理サーバーとして動作する
例として作成するノード client_within_action_x
ではまず、これをrclcppで実装してみましょう!(次回へ続く)