Пример работы Издателя и Подписчика, часть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 в соседних терминалах.

Также у нас получилось, что если остановим публикацию имени, то публикация приветствия продолжит работать, так как это независимые части программы.

results matching ""

    No results matching ""