[Documentation] [TitleIndex] [WordIndex

(訳注:最新の情報は原文を参照してください.)

Note: This tutorial assumes that you have completed the previous tutorials: ROSのmsgやsrvなどを作る.
(!) Please ask about problems and questions regarding this tutorial on answers.ros.org. Don't forget to include in your question the link to this page, the versions of your OS & ROS, and also add appropriate tags.

シンプルな配信者(Publisher)と購読者(Subscriber)を書く(Python)

Description: このチュートリアルでは, 配信者(Publisher)と購読者(Subscriber)のPythonでの書き方について学びます

Tutorial Level: BEGINNER

Next Tutorial: シンプルなPublisherとSubscriberを実行してみる

配信者ノードを書く

"Node" は ROS のネットワークにつながった実行可能なものを表す ROS 用語です。ここでは、メッセージをずっと発信する 配信者(Publisher)"talker" のノードを作りましょう。

creating a packageで作ったbeginner_tutorialsのディレクトリに移動しましょう:

$ roscd beginner_tutorials

コード

まず、Pythonのコードを入れておくscriptsフォルダを作りましょう:

$ mkdir scripts
$ cd scripts

そしてスクリプト例のtalker.pyを先ほど作ったscriptsディレクトリにダウンロードし、ファイルを実行可能にしておきます:

$ wget https://raw.github.com/ros/ros_tutorials/indigo-devel/rospy_tutorials/001_talker_listener/talker.py
$ chmod +x talker.py

 $ rosed beginner_tutorials talker.py でファイルを確認するか、または以下を見てください。

   1 #!/usr/bin/env python
   2 # license removed for brevity
   3 import rospy
   4 from std_msgs.msg import String
   5 
   6 def talker():
   7     pub = rospy.Publisher('chatter', String, queue_size=10)
   8     rospy.init_node('talker', anonymous=True)
   9     r = rospy.Rate(10) # 10hz
  10     while not rospy.is_shutdown():
  11         str = "hello world %s"%rospy.get_time()
  12         rospy.loginfo(str)
  13         pub.publish(str)
  14         r.sleep()
  15 
  16 if __name__ == '__main__':
  17     try:
  18         talker()
  19     except rospy.ROSInterruptException: pass

コード解説

では、コードを少しづつ見ていきましょう。

   1 #!/usr/bin/env python

すべてのPython ROS Nodeは、この宣言が先頭にあります。この1行によって、スクリプトファイルがPython スクリプトとして確実に実行されます。

   3 import rospy
   4 from std_msgs.msg import String

ROS Nodeを書く際はrospyをインポートする必要があります。std_msgs.msgのインポートは、std_msgs/String のメッセージのタイプ (文字列のみを保持する)を配信に再利用するためです。

   7     pub = rospy.Publisher('chatter', String, queue_size=10)
   8     rospy.init_node('talker', anonymous=True)

このコードの部分は、ROSの残りのtalkerのインターフェースを定義しています。pub = rospy.Publisher("chatter", String)は、ノードがchatterというトピックに Stringというメッセージのタイプで送っていることを宣言しています。 ここで、Stringは実際はstd_msgs.msg.Stringをさします。 New in ROS hydro では、購読者が十分な速度でメッセージを受け取らないでいる場合、引数queue_sizeはメッセージ・キューの量を制限します。ROSの古いディストリビューションでは、この引数は単純に省略します。

次の行では、rospy.init_node(NAME)はrospyにノード名を通知するのでとても大切です。rospyがこの情報を得ない限り、ROSのMasterと通信を始めることができません。この場合、ノード名はtalkerになります。NOTE:名前は、base nameでなければなりません。つまり、 "/"を含んではいけません。

   9     r = rospy.Rate(10) # 10hz

この行はRate オブジェクト rを生成しています。Rateのメソッドsleep()助けによって、要求された速度でループする便利な方法が提供されます。その引数‘10’によって、1秒あたり10回ループが回ると推定できるでしょう。(処理時間が1秒の1/10番目を越えていない限り!)

  10     while not rospy.is_shutdown():
  11         str = "hello world %s"%rospy.get_time()
  12         rospy.loginfo(str)
  13         pub.publish(str)
  14         r.sleep()

このループは、rospyのかなり標準的な構成です。rospy.is_shutdown()を毎回チェックして、すべき処理を実行します。is_shutdown()を確認して、プログラムが止まるべきかを判断します。(例えば、 Ctrl-Cが押された等です).。この場合、すべき処理とは、新しく作られたメッセージをpub.publish(String(str))によってchatterトピックに配信することです。このループはr.sleep()を呼びだし、ループを通して要求された速度を維持するのに十分な時間スリープします。

rospy.sleep()も見つけるかもしれません。シミュレーションされた時間で同じように動く以外は、time.sleep() と似ています。(参照:Clock))

このループは、rospy.loginfo(str)も呼び出します。これは3つの役目を果たします。まず、スクリーンにメッセージを書き出し、ノードのログファイルに書き込み、rosoutに吐き出します。rosoutはデバッグするのに使い勝手がよいです。ノードの出力のコンソールを探さなくても、rqt_consoleを使えばメッセージを引き出せます。

std_msgs.msg.String はとてもシンプルなメッセージのタイプなので、より複雑なメッセージタイプがどのようなものか気になるかもしれません。一般的なルールの要約としては、"コンストラクタの引数は、.msgファイルの中と同じ順番にすること"となっています。何の引数も与えずに、領域を直接初期化することもできます。例えば以下のように:

msg = String()
msg.data = str

または、領域の一部を初期化して、残りはデフォルト値とすることができます。

String(data=str)

最後の数行が気になっているかもしれませんね:

  17     try:
  18         talker()
  19     except rospy.ROSInterruptException: pass

標準のPythonの __main__ チェックに加えて、これはrospy.ROSInterruptExceptionの例外を捕捉します。Ctrl-Cが押されるか、ノードが違った形で終了される時に、rospy.sleep()rospy.Rate.sleep()のメソッドによって例外が投げられます。この例外が引き起こされるのは、sleep()の後で間違ってコードを実行し続けないようにするためです。

さて、次はメッセージを受けとるノードを書く必要があります。

購読者のノードを書く

コード

  • listener.pyファイルをscriptsディレクトリにダウンロードしてください:

$ roscd beginner_tutorials/scripts/
$ wget https://raw.github.com/ros/ros_tutorials/indigo-devel/rospy_tutorials/001_talker_listener/listener.py

このファイルは以下のような内容です:

   1 #!/usr/bin/env python
   2 import rospy
   3 from std_msgs.msg import String
   4 
   5 def callback(data):
   6     rospy.loginfo(rospy.get_caller_id()+"I heard %s",data.data)
   7     
   8 def listener():
   9 
  10     # in ROS, nodes are unique named. If two nodes with the same
  11     # node are launched, the previous one is kicked off. The 
  12     # anonymous=True flag means that rospy will choose a unique
  13     # name for our 'listener' node so that multiple listeners can
  14     # run simultaenously.
  15     rospy.init_node('listener', anonymous=True)
  16 
  17     rospy.Subscriber("chatter", String, callback)
  18 
  19     # spin() simply keeps python from exiting until this node is stopped
  20     rospy.spin()
  21         
  22 if __name__ == '__main__':
  23     listener()

ノードを実行可能にすることを忘れないように:

$ chmod +x listener.py

コード解説

listener.pyのコードは、talker.pyに似ています。差分は、メッセージを購読するための新たなコールバックベースの仕組みを導入していることです。

  15     rospy.init_node('listener', anonymous=True)
  16 
  17     rospy.Subscriber("chatter", String, callback)
  18 
  19     # spin() simply keeps python from exiting until this node is stopped
  20     rospy.spin()

ここは、ノードが、std_msgs.msgs.Stringのタイプのchatter}}トピック}から購読することを宣言しています。新しいメッセージがトピックに到着するたびに、メッセージを第一引数として{{{callbackが起動されます。

また、rospy.init_node()の呼び出しを多少変更しています。anonymous=Trueのキーワード引数を追加しています。ROSはそれぞれのノードが固有の名前を持つこと要求します。もし同じ名前のノードが立ち上がると、古い方のノードを止めてしまいます。これで、誤動作しているノードを簡単にネットワークからはじき出すことができます。anonymous=True のフラグによって、rospy がノードが固有の名前を生成するので、複数のlistener.pyノードを容易に実行することができます。

最後の変更点は、ノードが終了するまでの間、rospy.spin()が単純に自ノード終了させないようにしています。roscppと違って、コールバックにはそれぞれのスレッドがあるので、rospy.spin()は購読者コールバック関数に影響しません。

ノードをビルドする

CMakeをビルドシステムとして採用しているので、Pythonノードの場合でも同じようにCMakeを使わなければなりません。これは、メッセージとサービスのための自動生成されるPythonコードを確実に作るためです。

我々は、ちょっとした利便性を得られるためMakefile利用しています。 roscreate-pkgは自動的に、Makefileをつくるので、編集する必要はありません。

ではmakeしてみましょう。

$ make

catkinのワークスペースへ移動して、catkin_makeしましょう:

$ cd ~/catkin_ws
$ catkin_make

これでシンプルな配信者と購読者を書くことが出来ました。次はシンプルなPublisherとSubscriberを実行してみるに進みましょう。


2019-10-12 12:41