トピック通信の実装
Categories:
目的
ここまでにトピック通信の仕組み,ROS2によるパッケージやプログラミング方法を学びました. それら学んだ内容を活用し,簡易シミュレータturtlesimと作成したノード間のトピック通信をプログラミングにより実装します. これにより,ロボットのローレベルな制御が可能となります.
プログラミングによる配信と購読
パッケージの作成
前回の講義で作成したワークスペース practice_ws
の中に新たに turtlesim_practice
パッケージを作成します.
パッケージ作成時に与えるノードの名前は turtlesim_practice_node
とします.
パッケージの作成方法が分からない人は前回の講義資料を参考にしてください.
プログラミング
以前の講義でコマンドラインによってシミュレータ上のロボットを操作しました.
同じ内容をプログラムで実現します.
パッケージを作成した際に生成されるturtlesim_practice_node.py
に下記のコードを入力しましょう.
|
|
実行
プログラムの中身を理解する前に実行してみましょう. 実行方法は前回と同じですが,turtlesimシミュレータを起動しないと正しく動作しないので注意してください. 正しく実行できるとロボットが前後運動し,ターミナルにx座標が出力されます.
プログラムの内容
それでは,作成したプログラム実行時の挙動を確認した上で,プログラムの中身を順番に見ていきましょう.
|
|
まずはプログラム冒頭のimport文です.
1行目のrclpyは,ROS2のpythonモジュールです.
ROS2の機能を使用する場合には必ず必要なモジュールとなります.
2行目は,プログラム中でノードを作成するためにrclpy.nodeモジュールからNodeクラスをimportします.
3,4行目はトピック通信に必要なメッセージファイルをimportしています.
書き方が少し難解ですが,from パッケージ名.msg import メッセージ型
と書くと覚えましょう.
|
|
TurtleSim
というクラスを定義してます.
class
という単語の後に任意のクラス名を定義できます.
次にコンストラクタを定義しています.
pythonではdef
で関数を定義します.
classから始まる構文の中に__init__
という関数が定義されています.
これがコンストラクタとなりインスタンスを作成されると最初に実行される関数となります.
__init__
の中では,ノードの作成,配信,購読,タイマーのオブジェクトを生成しています.
重要な処理をしているので詳しく見ていきましょう.
|
|
この1行でturtlesim_practice_node
という名前のノードを作成しています.
Pythonでは,あるクラスを元にして同じ構造を持ちつつ拡張したクラスを定義することができます.
元のクラスを基底クラス,拡張することをクラスの継承,継承したクラスを派生クラスと言います.
基底クラスのNode
のコンストラクタを呼び出してクラスを継承しています.
|
|
create_publisher
を用いて配信者(Publisher)を作成しています.
第1引数はトピック通信で使用するメッセージの型,
第2引数は文字列型で表すトピック名,
第3引数は通信品質(QoS : Quality of Service)です.
QoSプロファイルにより通信の状態に合わせて配信することもできます.
QoSプロファイルは使用せず,デフォルトの10という値にしています.
配信する際に1度バッファに格納し,バッファに格納された古いデータから順番に配信され,配信されたデータは破棄されます.
問題なく通信できる環境であれば常に新しいデータが配信されることになりますが,
ネットワークに遅延等の問題が発生している場合には,バッファにデータが溜まり続けます.
今回の場合は,Twist
というメッセージの型を用いてturtle1/cmd_vel
という名前のトピックを配信する準備をしています.
|
|
create_subscription
を用いて購読者(Subscriber)を作成しています.
第1引数はトピック通信で使用するメッセージの型,
第2引数は文字列型で表すトピック名,
第3引数はコールバック関数,
第4引数は通信品質(QoS : Quality of Service)です.
通信品質については先ほどと同じです.
上記の場合には,Pose
というメッセージの型を用いたturtle1/pose
という名前のトピックを購読した場合,pose_callback関数を実行することになります.
|
|
指定した間隔で動作するタイマーを作成しています.
create_timer
の第1引数は繰り返し間隔,第2引数は実行するコールバック関数です.
上記の場合,1.0秒間隔でtimer_callback
関数を実行することになります.
|
|
後ほど使用するフラグをTrue
で初期化しています.
このフラグは,ロボットが前進するか後退するかを表すフラグとなります.
|
|
タイマーで指定した間隔でtimerCallback
関数を実行します.
先ほど初期化したis_forward
というフラグがTrue
であれば,引数0.2を伴いset_move_vector関数を実行し,
is_forward
がTrue
以外であれば,引数-0.2を伴いset_move_vector関数を実行します.
21行目では,フラグis_forward
を反転させてます.
True
であったならばFalse
に,False
であったならばTrue
になります.
|
|
並進速度と角速度を0としてトピックを配信します. linear_xには0.2もしくは-0.2が代入されているため,このトピックをロボットが購読するとロボットは前進もしくは後退します.
|
|
指定したトピックを購読する度にposeCallback
を実行します.
pythonのprint関数のように,ROSにはターミナルに表示するためのメソッドが用意されています.
少しわかりにくいですが,基底クラスNode
にてget_logger().info()が定義されています.
infoの括弧内は,print関数と同じ書式で記述できます.
今回はturtle1/pose
というトピックを購読する度にロボットのx座標を表示しています.
print関数はターミナルに表示するだけですが,上記の書き方によりログファイルにも出力されます. 規模が大きなシステムを構築する場合に,ログファイルからシステムの挙動を確認したいことがあります. そのような場合にはprint関数ではなく,上記の方法により記述した方が便利です. get_loggerでは,infoの他にwarningやerror,debug等が用意されています.
|
|
34行目で初期化し,35行目でturtleSimクラスのインスタンスを生成しています. rclpyはROS2のpythonモジュールですので,ROS2の機能を使う場合には必ず初期化が必要です. 36行目のspin関数により待ち状態(終了しない限り実行され続ける)が発生し,必要に応じでコールバック関数が呼び出されます. 38行目はノードを破壊し,39行目で終了処理を行います.
以上でプログラミングにより配信と購読することができます. 前々回に学んだノードやトピック,メッセージの情報をROSのコマンドで取得する方法, 今回学んだトピック通信の実装方法で,ロボットを自律制御することが可能となります.
課題
- setMoveVector関数の引数に与える値を変え,その際の挙動を予想しなさい.そして結果と比較しなさい.
- 購読している全ての情報(ヒント : x座標以外に4つの情報があります)をget_logger().info()により出力しなさい.
- ロボットに正四角形の軌跡を描かせるプログラムを作成しなさい.
- ロボットを座標(5,5)に移動させなさい.座標は購読した情報を使用すること.
- トピック「/turtle1/color_sensor」を購読してget_logger().info()により出力しなさい.
- ロボットが直進する際に,スムーズに加速,減速するような加減速制御を行いなさい.