この記事は
「Ubuntu Server20.04.2 LTS」OSの「Raspberry Pi 4 Model B」を使って「ROS2 Foxy」の学習ログを書き記した自分用ノート
になります。
と思ったことありませんか?
このページを読むことで
publisher-subscriberのノード間通信
ノード間でのメッセージの受け渡し
Pythonでの作成・実行方法
を知ることができ、ノード間通信の様子も図で説明しているので、図から理解したい方にもオススメです。
また、この記事はROS2 Foxy公式チュートリアルである
ROS2公式チュートリアル:Writing a simple publisher and subscriber (Python)
を日本語訳+αした記事になるので、是非チュートリアルと並行してご覧になってください。
それでは早速始めていきましょう。
pub-subノード間通信の準備
パッケージとプログラムを作成する
まずはpublisher subscriberのノード間通信用パッケージを作成していきます。
でディレクトリを移動し
と「py_pubsub」というパッケージを作成しました。
パッケージを作成したら
などでディレクトリを「py_pubsub」へ移動し
を実行し、Gitからpublisher_member_function.pyをダウンロードします。
ls コマンドで確認してみると、__init__.pyともう一つ、publisherファイルが増えていることが確認できますね。
そしたら、このpublisher_member_function.pyの中身を
などお好みの編集方法で確認してみましょう。
publisherのプログラム説明
publisher_member_function.pyの全文はROS2 Foxy公式チュートリアルに記載されているので、プログラムの要所要所を日本語解説していきます。
import rclpy from rclpy.node import Node
ROS2には
というクライアントライブラリAPIがあり、そのPythonバージョンがrclpyになります。
ここではROS2のクライアントライブラリであるrclpyをインポートして、Nodeクラスを使用できるようにしています。
from std_msgs.msg import String
publisherノードがsubscriberノードのトピック間で渡すデータ(メッセージ)の型宣言で、ここでは文字列を示すStringをインポートしています。
この型宣言には
といった、Twist型のメッセージなども存在します。
class MinimalPublisher(Node):
Nodeから継承するクラス名を宣言しています。
def __init__(self): super().__init__('minimal_publisher') self.publisher_ = self.create_publisher(String, 'topic', 10) timer_period = 0.5 # seconds self.timer = self.create_timer(timer_period, self.timer_callback) self.i = 0
クラスのコンストラクタ定義で
はNodeクラス名を付けます。
また、create_publisherは「topic」というトピック(データ通信の道)を介して文字列String型のメッセージを送信しており、キューサイズが10に指定されています。
def timer_callback(self): msg = String() msg.data = 'Hello World: %d' % self.i self.publisher_.publish(msg) self.get_logger().info('Publishing: "%s"' % msg.data) self.i += 1
timer_callbackは、msgデータにString()型のHello World を格納し、get_logger().infoを使用してコンソールにデータを公開(表示)します。
あとはmain文でRCLの初期化やMinimalPublisher()クラスを呼び出し
rclpy.init(args=args) # RCLの初期化 minimal_publisher = MinimalPublisher() # Nodeのインスタンス化 rclpy.spin(minimal_publisher) # minimal_publisherのループ minimal_publisher.destroy_node() # ノードの破壊 rclpy.shutdown() # ROSのシャットダウン
rclpy.spinでminimal_publisherのループ、.destroy_node()でノードの破壊、rclpy.shutdown()でシャットダウンを宣言しています。
ROS2チュートリアルでは、rclpy.spinなど細かい説明がないので追記しておきました。
セットアップファイルなどの編集
publisher_member_function.pyの大まかなプログラム内容を理解したら、セットアップファイルなどに実行のための編集を加えていきます。
でディレクトリを変え「package.xml」や「setup.py」を
とお好みのモードで編集します。
package.xml
<description>pubsub</description> <maintainer email="ubunbu@todo.todo">ubuntu</maintainer> <license>Apache License 2.0</license> <exec_depend>rclpy</exec_depend> <exec_depend>std_msgs</exec_depend>
上記、上図のように編集し、rclpy、std_msgsを追加します。
setup.py
maintainer='ubuntu', maintainer_email='ubuntu@todo.todo', description='pubsub', license='Apache License 2.0', entry_points={ 'console_scripts': [ 'talker = py_pubsub.publisher_member_function:main', ], },
エントリーポイントにはpublisher_member_functionを追加します。
また、保存するとsetup.cfgが下図のように反映されます。
ここまでできたら、talkerのpublisher_member_function.pyの設定は完了なので、同様にsubscriber nodeも作成しましょう。
へディレクトリを移動し
を実行してsubscriber_member_function.pyを作成しましょう。
作成ができたら、setup.pyのエントリーポイントへlistenerとしてsubscriber_member_functionを追加しておきます。
setup.py
entry_points={ 'console_scripts': [ 'talker = py_pubsub.publisher_member_function:main', 'listener = py_pubsub.subscriber_member_function:main', ], },
ここまでできたら、実際にpub-subのノード間通信を実行してみましょう。
ROS2 pub-subのノード間通信の実行と理解
ROS2のノード間通信を実行する
まずは
でROS2のワークスペースへディレクトリを移動し
とpy_pubsubパッケージをビルドします。
ビルドが完了したら、新しくターミナルを開き
とディレクトリを移動したら
. install/setup.bash
ros2 run py_pubsub talker
を実行すると
Publishing:”Hello World:0”Publishing:”Hello World:1”
と表示されます。
そしたら新しくターミナルを開き、~/dev_wsからセットアップファイルを再度取得し
でlistenerの方も実行してみましょう。
無事、publisherノードとsubscriberノード間でHello Worldという文字列がメッセージとして送受信できていれば完了です。
pub-subのノード間通信を図から理解する
ここまでpub-subノード間通信を行ってみて、ある程度は理解できたでしょうか?
このノード間通信を図で確認するには、新しくターミナルを開き
を実行します。
すると、ノード間通信を図が表示されます。
Messageの図は編集で追加しましたが、イメージは上図の通りで
publisherノードからMessageというデータを
トピックというデータの通信経路を通じてsubscriberノードへ伝える
通信が行われています。
ROS2にはノード、トピック、メッセージなど語句が多いので、この機会に是非覚えてしまいましょう!
publisher と subscriberのノード間通信は理解できたでしょうか?
私もまだチュートリアルの途中なので、徐々に覚えていければ良いと思っています。
お疲れ様でした。