拙著「ROS2とPythonで作って学ぶAIロボット入門」(講談社)を授業で使用する場合の講義資料のたたき台です.
今回は, [第2章 はじめてのROS2] の2.6節 トピック通信プログラムのつくり方を説明します.
概 要
- ROS2の通信方式にはトピック通信とサービス通信があり、トピック通信は1対多(一つのノードから多くのノードに通信可能)の非同期通信で、メッセージ通信は1体1(一つのノードからはある特定のノートにしか通信できない)の同期通信です。ここではトピック通信を学びます。トピック通信では送り手と受け手がTopic(トピック)とよばれる名前付きのバス(伝送路)を介してデータをやり取りしています。送り手のことをPublisher(配信者)、受け手のことをSubscriber(購読者)、データのことをメッセージとよびます。
準 備
- 端末Terminatorを開き、端末を上下に2分割する。Terminatorの使い方は教科書P25を参照.
パブリッシャ (Publisher)
1.サンプルプログラムの説明:このサンプルプログラムhappy_publisher_node.pyは文字列をパブリッシュする簡単なものです.詳しい説明は,教科書2.6.1 パブリッシャのサンプルプログラムの説明(P55)を参照してください.
import rclpy # ROS2のPythonモジュール from rclpy.node import Node # rclpy.nodeモジュールからNodeクラスをインポート from std_msgs.msg import String # std_msgs.msgモジュールからStringクラスをインポート class HappyPublisher(Node): # "Happy World"とパブリッシュ並びに表示するクラス def __init__(self): # コンストラクタ super().__init__('happy_publisher_node') self.pub = self.create_publisher(String, 'topic', 10) # パブリッシャの生成 self.timer = self.create_timer(1, self.timer_callback) # タイマーの生成 self.i = 10 def timer_callback(self): # コールバック関数 msg = String() if self.i > 0: msg.data = f'ハッピーワールド{self.i}' else: msg.data = f"終わり" self.destroy_timer(self.timer) self.pub.publish(msg) self.get_logger().info(f'パブリッシュ: {msg.data}') self.i -= 1 def main(args=None): # main関数 rclpy.init() node = HappyPublisher() try: rclpy.spin(node) except KeyboardInterrupt: print('Ctrl+Cが押されました.') finally: node.destroy_node() rclpy.shutdown()
2.パッケージの作成
- ノード名happy_publisher_nodeを指定してhappy_topicパッケージを作成します.
-
$ cd ~/airbot_ws/src
$ ros2 pkg create --build-type ament_python --node-name happy_publisher_node happy_topic
3.ビルド
- 上の端末で以下のコマンドでビルドしよう。
$ cd ~/airobot_ws
$ colcon build
4. 実行
- 上の端末で次のコマンドを実行して、happy_publisher_nodeノードを実行する。
$ cd ~/airobot_ws
$ source install/setup.bash
$ ros2 run happy_topic happy_publisher_node
サブスクライバ (Subscriber)
1. ソースコードと説明
次に、メッセージの受け手であるsubscriber(購読者)の簡単なプログラムを示します。このプログラムhappy_subscriber_node.pyはhappy_publisher_nodeがパブリッシュしたトピックtopicをサブスクライブして、その文字列を標準出力に出力する簡単なプログラムです。詳しい説明は,教科書2.6.3 サブスクライバの説明(P56)を参照してください.
import rclpy from rclpy.node import Node from std_msgs.msg import String # Sring型メッセージをサブスクライブして端末に表示するだけの簡単なクラス class HappyPublisher(Node): def __init__(self): # コンストラクタ super().__init__('happy_subscriber_node') # サブスクライバの生成 self.sub = self.create_subscription(String, 'topic', self.callback, 10) def callback(self, msg): # コールバック関数 self.get_logger().info(f'サブスクライブ: {msg.data}') def main(args=None): # main¢p rclpy.init() node = HappyPublisher() try: rclpy.spin(node) except KeyboardInterrupt: print('Ctrl+Cが押されました.') finally: rclpy.shutdown()
では、happy_ubscriber_nodeを作ろう。
VSCodiumにコピペしてhappy_subscriber_node.pyと名前を付けて、~/airobot_ws/src/happy_topic/happy_topicディレクトリに保存する。
2. package.xmlの編集:依存関係の追加
happy_topicパッケージはパブリッシャで作成したので~/airobot_ws/src/happy_topicディレクトリに setup.py、setup.cfg、package.xmlが作られている。package.xmlの5行から7行を必要に応じて変更する。次に、依存関係を示す10行目から12行目を追加する。この3つのモジュールはソースコードでインポートしており、実行時に必要になる。
3. setup.pyの編集:エントリポイントの追加
次に、setup.pyをエディタで開いて、エントリポイントとなる次の1行を24行目に挿入する。エントリーポイントには実行するファイルと関数を指定する。23行目に関しては、パッケージを作成するときにノード名happy_publisher_nodeを指定したので自動で作られた。
-
- ‘happy_subscriber_node = happy_topic.happy_subscriber_node:main’,
4. ビルド
では、以下のコマンドでビルドして実行しよう。
$ cd ~/airobot_ws
$ colcon build
5. 実行
- 端末を2つに分割する.
- 上の端末でhappy_publisher_nodeノードを起動する。
$ cd ~/airobot_ws
$ source install/setup.bash
$ ros2 run happy_topic happy_publisher_node
- 下の端末でhappy_subscriber_nodeノードを起動する。
$ cd ~/airobot_ws
$ source install/setup.bash
$ ros2 run happy_topic happy_subscriber_node
- 教科書P59 図2.18のように端末に表示されていたら成功です.
お疲れ様!
ホームワーク
- 教科書P59 チャレンジ2.8をやってみよう!
参考サイト
終わり
コメント