注目キーワード
  1. Photoshop
  2. Python
  3. Raspberry Pi
  4. Arduino

ROS2で単純なPublisher&Subscriberのノード間通信をPythonで作成・実行してみた

  • 2021年5月31日
  • 2021年6月1日
  • ROS2

この記事は

「Ubuntu Server20.04.2 LTS」OSの「Raspberry Pi 4 Model B」を使って「ROS2 Foxy」の学習ログを書き記した自分用ノート

になります。

 

taku
publisher-subscriber間の通信の概要は分かったけど、しっくりこない…

と思ったことありませんか?

 

このページを読むことで

publisher-subscriberのノード間通信

ノード間でのメッセージの受け渡し

Pythonでの作成・実行方法

を知ることができ、ノード間通信の様子も図で説明しているので、図から理解したい方にもオススメです。

 

また、この記事はROS2 Foxy公式チュートリアルである

ROS2公式チュートリアル:Writing a simple publisher and subscriber (Python)

を日本語訳+αした記事になるので、是非チュートリアルと並行してご覧になってください。

 

それでは早速始めていきましょう。

 

pub-subノード間通信の準備

 

パッケージとプログラムを作成する

まずはpublisher subscriberのノード間通信用パッケージを作成していきます。

 

cd ~/dev_ws/src

でディレクトリを移動し

ros2 pkg create –build-type ament_python py_pubsub

「py_pubsub」というパッケージを作成しました。

 

パッケージを作成したら

cd ./py_pubsub/py_pubsub

などでディレクトリを「py_pubsub」へ移動し

 

wget https://raw.githubusercontent.com/ros2/examples/foxy/rclpy/topics/minimal_publisher/examples_rclpy_minimal_publisher/publisher_member_function.py

を実行し、Gitからpublisher_member_function.pyをダウンロードします。

 

ros2pubsubtutorial_01

 

ls コマンドで確認してみると、__init__.pyともう一つ、publisherファイルが増えていることが確認できますね。

 

そしたら、このpublisher_member_function.pyの中身を

sudo nano publisher_member_function.py

などお好みの編集方法で確認してみましょう。

 

ros2pubsubtutorial_02

 

publisherのプログラム説明

publisher_member_function.pyの全文はROS2 Foxy公式チュートリアルに記載されているので、プログラムの要所要所を日本語解説していきます。

 

import rclpy
from rclpy.node import Node

ROS2には

各プログラミング言語に共通する機能を提供するrcl

というクライアントライブラリAPIがあり、そのPythonバージョンがrclpyになります。

ここではROS2のクライアントライブラリであるrclpyをインポートして、Nodeクラスを使用できるようにしています。

 

from std_msgs.msg import String

publisherノードがsubscriberノードのトピック間で渡すデータ(メッセージ)の型宣言で、ここでは文字列を示すStringをインポートしています。

この型宣言には

from geometry_msgs.msg import Twist

といった、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

クラスのコンストラクタ定義で

super().__init__(‘minimal_publisher’)

は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の大まかなプログラム内容を理解したら、セットアップファイルなどに実行のための編集を加えていきます。

 

cd ~/dev_ws/src/py_pubsub

でディレクトリを変え「package.xml」や「setup.py」を

sudo nano package.xml

とお好みのモードで編集します。

 

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>

 

ros2pubsubtutorial_03

 

上記、上図のように編集し、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',
        ],
},

 

ros2pubsubtutorial_04

 

エントリーポイントにはpublisher_member_functionを追加します。

また、保存するとsetup.cfgが下図のように反映されます。

ros2pubsubtutorial_05

 

ここまでできたら、talkerのpublisher_member_function.pyの設定は完了なので、同様にsubscriber nodeも作成しましょう。

 

cd ~/dev_ws/src/py_pubsub/py_pubsub

へディレクトリを移動し

 

wget https://raw.githubusercontent.com/ros2/examples/foxy/rclpy/topics/minimal_subscriber/examples_rclpy_minimal_subscriber/subscriber_member_function.py

を実行して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のノード間通信を実行する

まずは

cd ~/dev_ws

でROS2のワークスペースへディレクトリを移動し

colcon build –packages-select py_pubsub

とpy_pubsubパッケージをビルドします。

 

ビルドが完了したら、新しくターミナルを開き

cd ~/dev_ws

とディレクトリを移動したら

. install/setup.bash

ros2 run py_pubsub talker

を実行すると

Publishing:”Hello World:0”Publishing:”Hello World:1”

と表示されます。

 

そしたら新しくターミナルを開き、~/dev_wsからセットアップファイルを再度取得し

ros2 run py_pubsub listener

でlistenerの方も実行してみましょう。

 

ros2pubsubtutorial_06

 

無事、publisherノードとsubscriberノード間でHello Worldという文字列がメッセージとして送受信できていれば完了です。

 

pub-subのノード間通信を図から理解する

ここまでpub-subノード間通信を行ってみて、ある程度は理解できたでしょうか?

 

このノード間通信を図で確認するには、新しくターミナルを開き

rqt graph

を実行します。

 

ros2pubsubtutorial_07

すると、ノード間通信を図が表示されます。

 

Messageの図は編集で追加しましたが、イメージは上図の通りで

publisherノードからMessageというデータを

トピックというデータの通信経路を通じてsubscriberノードへ伝える

通信が行われています。

 

ROS2にはノード、トピック、メッセージなど語句が多いので、この機会に是非覚えてしまいましょう!

 

publisher と subscriberのノード間通信は理解できたでしょうか?

私もまだチュートリアルの途中なので、徐々に覚えていければ良いと思っています。

お疲れ様でした。

ros2pubsubtutorial_topthumbnail
学びに関する情報をチェック!