Пример совместной независимой работы
На предыдущем уроке мы создали пример в котором Подписчик и Издатель работают совместно. А именно, Подписчик вызывает Издателя. На этом уроке мы попрактикуемся создавать примеры, в которых Подписчик и Издатель будут действовать независимо.
Давайте разберемся в чем принципиальная разница зависимой и независимой работы. В примере предыдущего урока Подписчик вызвал метод greeter.sayHello и передавал ей данные, которые он получал из топика /name. Функция greeter.sayHello в свою очередь форматировала полученные от Подписчика данные и передавала их в Издатель для публикации в топик /greeting. Как вы видите вся логика программы увязана с получением данных в топике/name. Т.е. если данные в этот топик не поступают, то и функция greeter.sayHello не вызывается и Издатель не публикует ничего в топик /greeting.
Теперь, давайте создадим программу, которая будет принимать данные из одного топика, и сохранять эти данные в некую переменную, чтобы другие методы нашей программы могли этими данными пользоваться. Давайте слегка модифицируем пример из прошлого урока. Мы так-же будем получать в топик /name данные типа String с именем человека, и возвращать приветствие в виде Hello, Имя в топик /greeting . Однако сейчас сохранять данные "Имя" мы будем в переменную класса, а публиковать приветствие будем используя это "Имя" но в другом цикле.
Файл lesson6/string_pubsub_async.py
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
import rospy
from std_msgs.msg import String
class GreetingWorker(object):
def __init__(self):
self.pub = rospy.Publisher('/greeting', String, queue_size=10)
self.sub = rospy.Subscriber('/name', String, self.cbName)
self.rate = rospy.Rate(1)
self.name = ""
self.run()
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()
self.rate.sleep()
if __name__ == '__main__':
rospy.init_node('greeting_indep_node')
rospy.loginfo('Start Greeting Node')
greeter = GreetingWorker()
rospy.spin()
В этом примере мы создали класс GreetingWorker который выполняет обработку получения данных в топик /name с последующей публикацией в топик /greeting. Обратите внимание, что мы сначала инициализировали Подписчика, а потом указали одну из функций класса cbName() как callback функцию этого Подписчика. cbName получает данные из Подписчика и сохраняет их в переменную name экземпляра класса.
В методе конструктора класса __init__ мы создали объект pub в котором инициализировали объект Издатель. В функции pubGreet мы публикуем данные взятые из переменной self.name передавая их в качестве аргумента в self.pub.publish ().
Запустим наш скрипт.
python3 lesson6/string_pubsub_async.py
Откроем вывод топика /greeting
rostopic echo /greeting
Отправим тестовые данные в топик /name
rostopic pub /name std_msgs/String "Robot" -r10
В терминале вывода топика /greeting мы увидим что данные начали публиковаться
Hello, Robot
Hello, Robot
Hello, Robot
Обратите внимание, что данные публикуются из терминала в топик /name с частотой 10 герц, а публикуются нашим скриптом в топик /greetings с частотой rospy.Rate(1) - один герц. Это наглядно видно если вы посмотрите с какой частотой идут публикации в топик /name и /greetings открыв rostopic echo name и rostopic echo greetings в соседних терминалах.
Мы написали и разобрали пример python программы которая подписывается на данные, обрабатывает их и публикует их в другой топик и делает это в независимом режиме. Большинство программ в ROS, функционируют по аналогичному принципу. Весь вопрос в сложности обработки этих данных.
Пример взаимодействия Подписчика и Издателя с сохранением состояния: https://youtu.be/YmQJgBIiSSs