Топики и модель publish/subscribe

Топики — основной способ обмена данными в ROS; разбираем, как устроена модель publish/subscribe.

Топик (topic) — именованный канал, в который одни узлы публикуют сообщения, а другие на них подписываются. Это асинхронная связь «многие-ко-многим».

Зачем нужны топики

Топики — это «трубы данных» робота. Лидар измеряет расстояния 10 раз в секунду и публикует их в топик /scan. Ему всё равно, кто слушает: построитель карты, модуль объезда препятствий, логгер — может слушать любой из них или сразу все. Издатель и подписчики не знают друг о друге и не ждут друг друга: лидар продолжает публиковать, даже если подписчиков ноль. Это и есть асинхронность.

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

Многие-ко-многим

У одного топика может быть несколько издателей и несколько подписчиков одновременно. Например, в топик /cmd_vel могут писать и автономный планировщик, и узел джойстика (ручное управление) — а слушает их один base_controller.

  издатели                топик            подписчики
  +----------+                            +-----------------+
  | lidar    |---+                    +--->| map_builder    |
  +----------+   |     +---------+    |   +-----------------+
                 +--->|  /scan  |----+
                       +---------+    |   +-----------------+
                                      +--->| obstacle_avoid |
                                          +-----------------+

Осмотр топиков с консоли

Семейство команд ros2 topic позволяет исследовать живые топики, не написав ни строчки кода — это главный инструмент отладки.

# Все активные топики
ros2 topic list

# Печатать сообщения топика в реальном времени
ros2 topic echo /scan

# Частота публикации
ros2 topic hz /scan

# Тип сообщения и число издателей/подписчиков
ros2 topic info /scan

Вывод (ros2 topic list):

/scan
/odom
/cmd_vel
/tf
/rosout

Публикация из терминала

Можно даже опубликовать сообщение вручную — удобно, чтобы проверить, как робот реагирует на команду, без написания узла:

ros2 topic pub /cmd_vel geometry_msgs/msg/Twist \
  "{linear: {x: 0.2}, angular: {z: 0.0}}"

Как работает под капотом

За топиками стоит DDS. Когда узел создаёт издателя для /scan, DDS объявляет об этом по сети (discovery). Подписчики того же топика находят издателя и устанавливают прямое соединение. Дальше сообщения идут напрямую от издателя к подписчикам, минуя какой-либо центр. Важно: издатель и подписчик должны совпадать не только по имени топика, но и по типу сообщения и по совместимым политикам QoS — иначе связь не установится.

Частые ошибки

  • Опечатка в имени топика. /scan и /Scan — разные топики; подписчик ничего не получит.
  • Разные типы сообщений. Издатель шлёт LaserScan, подписчик ждёт PointCloud — связи не будет.
  • Несовместимый QoS. Частая причина «топик есть в list, а echo молчит» — расхождение политик надёжности.

Итоги

  • Топик — именованный канал; издатели публикуют, подписчики получают.
  • Связь асинхронная и многие-ко-многим; стороны не знают друг о друге.
  • ros2 topic list/echo/hz/info — главные инструменты отладки.
  • Для связи нужны совпадение имени, типа сообщения и совместимый QoS.
Проверьте себя
1. Что такое топик в ROS?
AФайл конфигурации
BИменованный канал для обмена сообщениями по модели publish/subscribe
CЦентральный сервер
DТип робота
2. Сколько издателей и подписчиков может быть у топика?
AРовно один издатель и один подписчик
BМного издателей и много подписчиков (многие-ко-многим)
CТолько подписчики
DНе больше двух всего
3. Зачем нужна команда ros2 topic echo /scan?
AУдалить топик
BПечатать приходящие в топик сообщения в реальном времени
CСоздать новый узел
DИзменить тип сообщения