はじめに
最近少しずつROSを触り始めていて、Pythonでノードを実装するときに1つのノード内でpublisherとsubscriberを実装するにあたって困ったポイントがあったので紹介します。Pythonのクラスを使うことできれいにすることができました。
自分でパッケージが作れる程度のROSの知識と少しのオブジェクト指向の知識がある前提です。
実装例はこちら
やりたかったこと
このトピックのデータをsubscribeして、処理をして、あのトピックにpublishしたいな
ということがあると思います。調べ方が悪かったのか1つのノードで同時にsubscriberとpublisherを使うときはどうすればいいんだ、、、
と、かなりはまりました。
Pythonで実装するROSのPublisherとSubscriber
ROS.orgやよく紹介されているPublisherとSubscriberのチュートリアルでは以下のようになっていることが多いと思います。
Publisher(talkerとも)
rospy.Publisher
で トピック名とメッセージのタイプを指定して、pub.publish()
でpublish。
# rospyとメッセージのimport
import rospy
import std_msgs.msg import String
def talker():
pub = rospy.Publisher('chatter', String, queue_size=10)
rospy.init_node('talker', anonymous=True)
# 処理が続く
pub.publish(data)
if __name__ == '__main__':
try:
talker()
except rospy.ROSInterruptException: pass
Subscriber(listenerとも)
rospy.Subscriber
でトピック名、データの型の指定、そしてcallback関数を指定してsubscribe後の処理をcallback関数で行う、という形になっています。
# rospyとメッセージのimport
import rospy
from std_msgs.msg import String
def callback(data):
# subscribeのcallback関数
def listener():
rospy.init_node('listener', anonymous=True)
rospy.Subscriber("chatter", String, callback)
rospy.spin()
if __name__ == '__main__':
listener()
Publish と Subscribeを同時に1つのノードで行う
チュートリアルが終わって、PublishとSubscribeの仕組みなどは一応理解しました。
じゃあ新しいノードを作ってPublishとSubscribe同時にやろうかなー。と思い、実装してみると rospy.Subscriber
のcallback関数内でPublishすればいいのか、、?とコードをきれいにできずに悩みました。
その時にこの記事を見ていて、コードも拝見したところとてもきれいだったので参考にさせていただきました。
上記のチュートリアルではPythonのクラスを使っていませんでしたが、クラスを使うときれいに実装することができます。
__init__()
でPublisher, Subscriberを作成し、callback関数、Publishする関数という流れで処理をしていきます。
実行する際にはmainの部分でクラスを作成すれば完了です!
#! /usr/bin/env python
# -*- coding: utf-8 -*-
import rospy
from std_msgs.msg import String
import time
class testNode():
def __init__(self):
# Subscriberの作成
self.sub = rospy.Subscriber('topic name', String, self.callback)
# Publisherの作成
self.pub = rospy.Publisher('topic name', String, queue_size=1)
def callback(self, data):
# callback関数の処理をかく
self.publish(data)
def publish(self, data):
self.pub.publish(data)
def function(self, data):
# そのほかの処理もあったら書く
return data
if __name__ == '__main__':
rospy.init_node('test_node')
time.sleep(3.0)
node = testNode()
while not rospy.is_shutdown():
rospy.sleep(0.1)
おわりに
個人的にオブジェクト指向はとっかかりづらいと思っていましたが便利にきれいに書くことができました。
こんな感じでテンプレートを作ってくれている方もいますね!
"ros python publish subscribe 同じノード" とかの検索に欲しい情報なかったです。。。ROS初心者すぎるから自分が見当違いなことしているのですかね。なにかおかしかったら教えてください。
参考
ROSの機械学習用に、OpenPoseから関節角度をTopicで流すパッケージ作った
ROS講座31 python基礎
ROS のプログラムテンプレート
シンプルな配信者(Publisher)と購読者(Subscriber)を書く(Python)