Пример работы Издателя и Подписчика, часть2
На предыдущем уроке мы создали пример, в котором Подписчик и Издатель работают совместно. А именно, Подписчик вызывает Издателя. На этом уроке мы попрактикуемся создавать примеры, в которых Подписчик и Издатель будут действовать независимо.
Давайте разберемся, в чем принципиальная разница зависимой и независимой работы. В примере предыдущего урока Подписчик вызвал метод greeter.sayHello и передавал ей данные, которые он получал из топика /name.Функция greeter.sayHello в свою очередь форматировала полученные от Подписчика данные и передавала их в Издатель для публикации в топик /greetings. Как вы видите, вся логика программы увязана с получением данных в топике/name. Т.е. если данные в этот топик не поступают, то и функция greeter.sayHello не вызывается и Издатель не публикует ничего в топик /greetings.
Теперь давайте создадим программу, которая будет принимать данные из одного топика и сохранять эти данные в некую переменную, чтобы другие методы нашей программы могли этими данными пользоваться когда они им понадобятся.
Слегка модифицируем пример из прошлого урока. Мы также будем получать в топик /name данные типа String с именем человека и возвращать приветствие в виде Hello, Имя в топик /greeting. Однако сейчас сохранять данные "Имя" мы будем в свойства класса, а публиковать приветствие будем, используя это "Имя", но в другом цикле.
Файл pubsub2.py
import rospy
from std_msgs.msg import String
class GreetingWorker(object):
def __init__(self):
rospy.loginfo('Start Greeting Node')
self.pub = rospy.Publisher('/greeting', String, queue_size=10)
self.sub = rospy.Subscriber('/name', String, self.cbName)
self.name = ""
def cbName(self, income_msg):
self.name = income_msg.data
def pubGreet(self):
self.pub.publish('Hello, {}'.format(self.name))
def run(self):
while not rospy.is_shutdown():
self.pubGreet()
rospy.sleep(1)
rospy.init_node('greeting_indep_node')
greeter = GreetingWorker()
greeter.run()
В этом примере мы создали класс GreetingWorker, который выполняет обработку получения данных в топик /name с последующей публикацией в топик /greeting.
Обратите внимание, что мы изменили callback функцию этого Подписчика. cbName получает данные из Подписчика и только сохраняет их в переменную name экземпляра класса. В прошлом примере мы сразу отправляли данные в топик.
def cbName(self, income_msg):
self.name = income_msg.data
Также у нас появился новый метод run()
def run(self):
while not rospy.is_shutdown():
self.pubGreet()
rospy.sleep(1)
В этом методе мы запускаем "бесконечный" цикл на публикацию данных с интервалом в одну секунду. При этом "получение" данных не останавливается, и метод cbName всегда вызывается как только получены данные в топике.
Запустим скрипт.
python pubsub2.py
Откроем вывод топика /greeting
rostopic echo /greeting
Отправим тестовые данные в топик /name
rostopic pub /name std_msgs/String "Robot" -r10
В консоли вывода топика /greeting мы увидим, что данные начали публиковаться
Hello, Robot
Hello, Robot
Hello, Robot
Обратите внимание, что мы публикуем данные из консоли в топик /name с частотой 10 герц, а выводятся данные с частотой один герц. Это наглядно видно, если посмотреть, с какой частотой идут публикации в топик /name и /greetings открыв rostopic echo name и rostopic echo greetings в соседних терминалах.
Также у нас получилось, что если остановим публикацию имени, то публикация приветствия продолжит работать, так как это независимые части программы.