Глава 3. Основы ROS
1. Цель занятия и обзор плана
На этом занятии мы разберемся:
-
что такое ROS2;
-
что представляют собой основные понятия ROS2: node, topic, publisher, subscriber, namespace, тип topic;
-
как запустить базовый пример;
-
разберём консольные инструменты;
-
познакомимся с понятием remaping;
-
поработаем в симуляторе.
2. Теоретический материал
2.1. Что такое ROS?
ROS (Robot Operating System) — это открытая программная платформа, которая помогает инженерам и программистам создавать, тестировать и управлять роботами.
Хотя в названии есть словосочетание “операционная система”, на самом деле ROS — это не самостоятельная ОС, а набор инструментов, библиотек и стандартов, упрощающих создание сложных робототехнических систем.
На текущий момент ROS является самым популярным фреймворком для применения в робототехнике. Только в России ROS широко используют следующие компании:
-
Сбер, организатор крупнейшей в России конференции по ROS - "ROS meetup";
-
Яндекс использует глубоко переработанную ROS внутри своих роботов-курьеров и робомобилей;
-
Starline широко использует ROS в своих робомобилях;
-
В российской подводной робототехнике ROS использует фирма "Океанос", "РМК", "Трионикс", а также наше СКБ.
С большим количеством роботов можно ознакомиться на сайте https://robots.ros.org/.
2.2. Почему мы используем ROS?
-
ROS задаёт рамку разработки ПО, поощряющую написание кода так, чтобы его было легко использовать повторно;
-
как следствие предыдущего пункта, для ROS легко найти готовые модули для решения стандартных задач (навигация, взаимодействие с манипуляторами, взаимодействие с стандартными устройствами)
-
в связи с популярностью ROS, на многие вопросы по работе с системой легко найти ответы в интернете либо же найти специалистов, которые смогут помочь с вашей проблемой
-
ROS "из коробки" поддерживает распределённую работу по сети. Так, не составит большого труда обеспечить исполнение части программного обеспечения на роботе, а части - на связанном с ним по сети компьютере. В рамках эксперимента, мы смогли без особых проблем управлять "Водомеркой", находящейся в Санкт-Петербурге из Петропавлоска-Камчатского.
Во всём курсе под ROS мы подразумеваем именно версию ROS2. Она достаточно сильно отличается от версии ROS1, которая на сегодняшний день всё больше выходит из употребления.
2.3. Примеры популярных компонентов ROS
-
MoveIt — управление движением манипуляторов;
-
TF — отслеживание координатных систем;
-
Navigation — планирование маршрутов и движение робота;
2.4. Основные концепции ROS: ноды
Одной из двух ключевых концепций ROS является нода (node). Само слово node переводится как "узел", имея в виду узел сети обмена данными, но на курсе мы не будем использовать перевод, а будем называть эту сущность "нода".
В первом приближении нода представляет собой просто программу, написанную на языке Python или C++ (штатно ROS поддерживает только эти языки).
Отличия от простой программы заключаются в том, что программа для робота с точки зрения ROS - это набор нод, взаимодействующих между собой, обмениваясь сообщениями.
Это достаточно старая концепция в программировании - разделение программы на модули, взаимодействующие относительно небольшим количеством способов с другими модулями, и не раскрывающая своё внутреннее устройство (свою реализацию).
В математике такого рода сущности называют "черным ящиком" - вы знаете что нужно подать на вход чёрного ящика чтобы получить нужный вам результат, но вы не знаете (или не хотите знать) как этот результат получить.
Пусть концепция "чёрного ящика" может показаться странной, однако вы уже наверняка с ней знакомы, если вы использовали на калькуляторе кнопку вычисления квадратного корня. Вы наверняка знаете, какой результат вы получите от операции извлечения квадратного корня, однако подавляющее большинство читающих не знают как вычислить квадратный корень без помощи калькулятора или компьютера.
Более того, ограничение способов общения с модулем даёт вам заметные преимущества. Вообразим, что в вашем программном обеспечении модуль вычисления квадратного корня работает очень медленно. С точки зрения ROS - вы просто меняете ноду, которая вычисляет квадратный корень, не трогая остальное программное обеспечение.
Предложенный пример достаточно умозрителен, но вот более реальный пример: вы хотите узнать факт наличия на изображении, получаемом с USB-камеры QR-кода и если он есть, то вас интересует значение, которое он содержит. Конечно, вы бы могли разработать весь код самостоятельно, но было бы это эффективно с точки зрения затрат времени и качества кода?
Очевидно, что задача работы с USB-камерами была решена до вас и решена хорошо. От того, что вы напишете ещё одну реализацию, мир не станет лучше. Правильнее взять готовый модуль, получить от него изображение, передать его в другой готовый модуль, который умеет выделять на изображении QR-код, и выдавать далее его значение.
Задача разработчика — не переизобретать в тысячный раз велосипеды, а добавлять нечто новое, основываясь на уже реализованных разработках. Как говорил Исаак Ньютон "Если я и смог посмотреть дальше других, то только потому что стоял на плечах гигантов".
Обычно, в этом месте некоторое количество студентов курса высказывают желание написать весь код самостоятельно, не опираясь на готовые библиотеки. Традиционно рекомендуем им начать с добычи кварца для того, чтобы изготовить самостоятельно процессор для компьютера а также с добычи медной руды, чтобы изготовить провода для компьютера.
Стоит понимать, что иногда доступные реализации задач действительно по той или иной причине не устраивают нас, и тогда необходимо написать код самостоятельно. Мы абсолютно не против такого подхода, а лишь настоятельно рекомендуем проверить обоснованность такого решения и напоминаем что недостаток "код написан не мной" является слабым обоснованием.
2.5. Основные концепции ROS: топики и сообщения
Итак, мы примерно поняли что такое нода (если вы не разобрались до конца - не переживайте, у вас будет время попрактиковаться и разобраться). Однако для того, чтобы система заработала, кроме нод нужен способ обмена данными между нодами.
В ROS основным способом обмена данными между нодами являются топики (topic) - этот термин мы также не будем переводить.
Топик - это именованный, типизированный канал, куда ноды могут отправлять (publish) сообщения, а также ноды могут быть подписаны (subscribe) на топики.
Важно отметить, что ноды отправляют сообщения не другим нодам, а именно в топик. Также ноды получают сообщения не от конкретной ноды, а из топика. Это позволяет ещё сильнее уменьшить связанность нод между собой, уменьшить требования о раскрытии внутренней структуры нод и, в итоге, это приводит к тому что ноды легче объединять в сеть, даже не занимаясь непосредственно программированием (в рамках практического занятия мы попробуем это сделать).
Теперь рассмотрим ту часть определения, где упоминается что топики являются типизированными. Это означает, что данные внутри топиков имеют определенный тип и для топика он всегда один, отправка сообщений разного типа в топики приведёт к ошибкам.
Наконец, мы многократно говорили, что ноды в ROS обмениваются данным, но что из себя представляют эти самые данные?
2.6. Типы данных, передаваемых в топиках
Передача данных в топиках является основой взаимодействия узлов в ROS, поэтому важно понимать, какие типы сообщений могут использоваться. В ROS 2 применяется строго определённая система типов: каждый топик публикует сообщения фиксированного формата, описанного в файлах с расширением .msg. Базовые типы данных включают простые числовые и логические значения:
-
целые числа различных диапазонов (
int8,uint8,int16,uint16,int32,uint32,int64,uint64); -
числа с плавающей точкой (
float32,float64); -
булевы значения;
-
строки;
-
время (
uint32); -
длительность (
uint32); -
массивы этих элементов. Эти типы позволяют описывать простые сигналы, такие как скорость, состояние датчика, уровень заряда или значения параметров управления.
Помимо примитивных типов ROS поддерживает составные структуры данных. Они представляют собой сообщения, состоящие из нескольких полей, каждое из которых тоже является типом ROS. Примером может служить пакет geometry_msgs/Twist (с ним мы будем работать в практической части занятия).
Важно отметить, что пользователь не ограничен только стандартными типами: в ROS можно самостоятельно создавать собственные форматы сообщений. Для этого достаточно определить структуру в файле .msg, указать нужные поля и задать зависимости в пакете. После сборки такие пользовательские сообщения становятся доступными для публикации и подписки так же, как встроенные типы. Это даёт разработчику гибкость в создании тех форматов данных, которые наиболее точно описывают работу конкретного робота или алгоритма.
Далее разберём устройство сообщения geometry_msgs/Twist.msg.
Сообщение geometry_msgs/Twist.msg
Сообщение geometry_msgs/Twist.msg используется в ROS для передачи информации о скоростях робота и является одним из самых часто применяемых типов данных в мобильной робототехнике. Оно описывает состояние движения через две величины: линейную скорость и угловую скорость.
geometry_msgs/Twist.msg
# This expresses velocity in free space broken into its linear and angular parts.
Vector3 linear
Vector3 angular
Обе составные части представлены типом Vector3, который содержит три координаты x, y и z. Таким образом, структура Twist.msg включает два поля: Vector3 linear и Vector3 angular, каждое из которых задаёт скорость вдоль соответствующих осей.
geometry_msgs/Twist.msg
# This represents a vector in free space.
# It is only meant to represent a direction. Therefore, it does not
# make sense to apply a translation to it (e.g., when applying a
# generic rigid transformation to a Vector3, tf2 will only apply the
# rotation). If you want your data to be translatable too, use the
# geometry_msgs/Point message instead.
float64 x
float64 y
float64 z
Такое устройство сообщения выбрано не случайно. Линейная и угловая скорости являются универсальным способом описания движения практически любого робота, независимо от его конструкции: колёсного, гусеничного, шагового или плавающего. Разделение на два вектора позволяет единообразно передавать движение в трёхмерном пространстве, даже если конкретный робот использует только часть этих компонент. Например, наземные мобильные платформы обычно управляют скоростями linear.x и angular.z, а остальные компоненты остаются равными нулю. Благодаря этому Twist стал универсальным интерфейсом: один и тот же тип сообщения подходит для симуляторов, реальных контроллеров, алгоритмов навигации и систем планирования движения. Такой подход упрощает взаимодействие разных пакетов и обеспечивает совместимость программ в рамках всей ROS-экосистемы.
2.7. Заключение
Основная концепция ROS - это набор модулей, взаимодействующих между собой при помощи обмена сообщениями. Это очень старая и важная концепция в мире IT, ещё в 1967 году один из отцов современного программирования работал над аналогичной концепцией:
"Я представлял объекты как биологические клетки и/или отдельные компьютеры в сети, способные общаться только при помощи сообщений". Алан Кей (по материалам https://habr.com/ru/articles/946868/)
Данная концепция значительно расширяет возможности повторного переиспользования кода и отладки программ.
3. Практическое занятие
3.1. Установка ROS
На курсе мы будем работать с версией ROS Jazzy. Установка выполняется по инструкции:
Для установки на ПК используйте версию desktop а для одноплатного компьютера (например на катамаран) - версию base.
После установки выполните команду:
$ echo source "/opt/ros/jazzy/setup.bash" >> ~/.bashrc
$ source ~/.bashrc
Эта команда используется для того, чтобы автоматически подключать окружение ROS 2 при каждом открытии нового терминала. Файл setup.bash, находящийся в каталоге установленного дистрибутива ROS, добавляет в систему необходимые переменные среды: пути к пакетам, библиотекам, инструментам командной строки и настройкам ROS_DOMAIN_ID. Если выполнить команду source вручную, окружение будет активно только в текущем окне терминала, и после его закрытия настройки исчезнут. Добавление строки source /opt/ros/jazzy/setup.bash в файл ~/.bashrc делает подключение постоянным: при каждом запуске терминала оболочка автоматически загружает окружение ROS, и все команды (ros2 run, ros2 topic, ros2 node) становятся доступными без дополнительных действий. Это упрощает работу учащихся и снижает вероятность ошибок, связанных с забытым подключением среды.
3.2. Запуск примера с turtlesim
Turtlesim — это простой учебный симулятор, входящий в состав ROS 2 и предназначенный для первых упражнений по работе с нодами, топиками и управлением роботом. Он представляет собой двумерную среду, в которой «черепашка» двигается по экрану, реагируя на команды скорости. Благодаря минималистичному устройству turtlesim позволяет быстро увидеть, как данные, опубликованные одной нодой, влияют на поведение другой, и тем самым наглядно демонстрирует принципы архитектуры ROS.
Для работы с turtlesim необходимо запустить две разные ноды, каждая в своём терминале. Команда
ros2 run turtlesim turtlesim_node
запускает сам симулятор — это нода, которая отображает черепашку и принимает команды движения через соответствующий топик. В другом терминале запускается команда
ros2 run turtlesim turtle_teleop_key
которая открывает ноду управления с клавиатуры. Она считывает нажатия клавиш и публикует сообщения о скоростях черепашки. Разделение на два процесса важно, потому что ноды ROS работают независимо, а обмен данными между ними происходит через топики. Такое упражнение позволяет учащимся на практике увидеть взаимодействие нод, публикующих и принимающих сообщения.
Рисунок 1. Терминал для управления черепахой
|
Рисунок 2. Пример работы turtlesim
|
3.3. Изучаем консольные утилиты ROS
После запуска симулятора turtlesim и ноды управления с клавиатуры можно использовать консольные утилиты ROS 2, чтобы изучить, какие ноды активны, какие топики существуют и какие сообщения передаются между компонентами. Такие инструменты помогают понять внутреннюю структуру работающей системы и увидеть, как ноды взаимодействуют друг с другом в реальном времени.
Команда ros2 node list
Позволяет получить список всех запущенных нод. В нашем случае вы увидите примерно следующее:
$ ros2 node list
/turtlesim
/teleop_turtle
Эти имена подтверждают, что в системе работают две ноды — симулятор и управление с клавиатуры.
Команда ros2 topic list
Выводит перечень всех активных топиков. Среди них можно увидеть:
$ ros2 topic list
/parameter_events
/rosout
/turtle1/cmd_vel
/turtle1/color_sensor
/turtle1/pose
Топик /turtle1/cmd_vel является ключевым: именно в него публикуются команды скорости, которые затем воспринимаются симулятором.
Чтобы узнать, какие сообщения ожидает и публикует конкретный топик, используется команда
ros2 topic info /turtle1/cmd_vel
Типичный вывод будет следующим:
$ ros2 topic info /turtle1/cmd_vel
Type: geometry_msgs/msg/Twist
Publisher count: 1
Subscription count: 1
Это показывает, что топик использует сообщение типа Twist, что одна нода публикует данные (teleop), а другая — подписана на них (turtlesim).
Наконец, команда ros2 topic echo /turtle1/cmd_vel выводит сами сообщения, которые передаются в топике. При нажатии клавиш управления вы увидите обновляющиеся строки вида:
linear:
x: 1.0
y: 0.0
z: 0.0
angular:
x: 0.0
y: 0.0
z: 1.0
Эти данные отражают текущие команды линейной и угловой скорости черепашки. Таким образом, консольные утилиты позволяют подробно исследовать взаимодействие нод и увидеть передачу сообщений внутри ROS-приложения.
3.4. Визуализация структуры системы: rqt_graph
После знакомства с консольными утилитами, такими как ros2 node list, ros2 topic list и ros2 topic echo, важно показать учащимся инструмент, который позволяет увидеть архитектуру работающей системы в наглядной графической форме. Такой инструмент — rqt_graph. Он отображает ноды, топики и направления передачи данных в виде схемы, что помогает понять структуру ROS-приложения быстрее, чем вручную анализировать списки и выводы в терминале. В учебных примерах этот инструмент особенно полезен, поскольку позволяет сразу увидеть, какие ноды взаимодействуют друг с другом, какие топики активны и как распределяются сообщения в системе.
Запуск rqt_graph выполняется командой в консоли:
$ rqt_graph
После её выполнения откроется окно с графическим представлением текущей ROS-сети. Если в системе запущены ноды turtlesim и teleop_turtle, то схема будет включать минимум три элемента: ноду /teleop_turtle, ноду /turtlesim и топик /turtle1/cmd_vel. На графе будет видно, что /teleop_turtle публикует команды скорости в этот топик, а /turtlesim подписывается на него. Также могут отображаться дополнительные служебные топики, такие как /parameter_events или /rosout, появляющиеся автоматически при работе ROS 2.
Использование rqt_graph помогает увидеть взаимосвязи между компонентами, убедиться, что сообщения доходят до нужных нод, и в целом лучше понять архитектуру системы. Это делает инструмент важной частью начального обучения работе с ROS, дополняя консольные утилиты визуальными средствами анализа.
3.5. Настраиваем ноды без программирования: remapping
Одно из важных преимуществ ROS заключается в том, что систему можно настраивать и собирать из готовых нод даже без написания собственного кода. Механизм remapping позволяет переназначать имена топиков, нод и сервисов прямо при запуске программы, что даёт возможность объединять разные компоненты в рабочую систему, не изменяя исходный код и не создавая новых пакетов. Благодаря этому разработчик может «сконструировать» поведение робота из готовых элементов: одна нода генерирует команды, другая принимает их, а связь между ними задаётся через параметры запуска. Такой подход особенно полезен учащимся, потому что позволяет начать экспериментировать с функциональностью робота сразу, не ожидая написания и сборки программ.
Хорошим примером является управление turtlesim при помощи джойстика. Для этого используются две готовые ноды: joy_node, которая считывает состояние игрового контроллера, и teleop_node из пакета teleop_twist_joy, которая преобразует движения джойстика в сообщения типа Twist. Для начала необходимо установить пакет поддержки джойстика, если он ещё не установлен. Это делается командой:
$ sudo apt install ros-jazzy-joy ros-jazzy-teleop-twist-joy
После установки можно запустить чтение данных джойстика:
$ ros2 run joy joy_node --ros-args -p dev:="/dev/input/js0"
Эта нода публикует состояние всех осей и кнопок в топик /joy. О том, что такое --ros-args -p dev:="/dev/input/js0" мы поговорим позднее.
В другом терминале запустим:
$ ros2 run teleop_twist_joy teleop_node
Давайте посмотрим на вывод rqt_graph:
Мы видим, что нода teleop_twist_joy не соединена с нодой turtlesim, а инспекция ноды в терминале покажет, что хотя топик с нужным типом данных есть, но называется он иначе:
$ ros2 node info /teleop_twist_joy_node
/teleop_twist_joy_node
Subscribers:
/joy: sensor_msgs/msg/Joy
/parameter_events: rcl_interfaces/msg/ParameterEvent
Publishers:
/cmd_vel: geometry_msgs/msg/Twist
/parameter_events: rcl_interfaces/msg/ParameterEvent
/rosout: rcl_interfaces/msg/Log
Вывод идёт в топик /cmd_vel, вместо нужного нам /turtle1/cmd_vel. Изменим это без программирования. Остановим ноду, и запустим её с параметром
Затем в другом терминале запускается нода управления:
$ ros2 run teleop_twist_joy teleop_node --ros-args --remap cmd_vel:=/turtle1/cmd_vel
Здесь используется remapping: --remap cmd_vel:=/turtle1/cmd_vel
Он переназначает стандартный выходной топик cmd_vel на тот, который понимает turtlesim, то есть /turtle1/cmd_vel. Без такой перенастройки нода teleop_twist_joy публиковала бы сообщения в другой топик, и симулятор не получал бы команд.
Теперь rqt_graph показывает правильную картину:
Для повышения удобства работы ещё сильнее изменим настройки ноды:
$ ros2 run teleop_twist_joy teleop_node --ros-args \
--remap cmd_vel:=/turtle1/cmd_vel \
-p axis_linear.x:=4 -p axis_angular.yaw:=3 \
-p scale_linear.x:=1.0 -p scale_angular.yaw:=1.0 \
-p require_enable_button:=false
Остальные параметры управляют тем, как именно интерпретируются оси джойстика. Параметр axis_linear.x:=4 указывает, что линейная скорость робота берётся из оси номер 4 контроллера, а axis_angular.yaw:=3 задаёт ось номер 3 как источник угловой скорости. Значения scale_linear.x и scale_angular.yaw определяют коэффициенты масштабирования: они ограничивают диапазон скоростей, чтобы движение оставалось плавным и предсказуемым. Например, уменьшив scale_linear.x, можно сделать движение медленнее, что полезно при обучении. И, наконец, команда -p require_enable_button:=false снимает требования нажатия кнопки разблокировки для управления.
4. Работа с катамараном/симулятором
4.1. Установка симулятора
Необходимо скачать нужную версию симулятора (windows или linux). Для Linux мы рекомендуем работать в папке ~/ros2/sim-lin.
https://sdb.smtu.ru/nextcloud/s/dX2Dw6kR62kKW95 |
Для версии Linux необходимо разрешить запуск файла симулятора:
$ sudo chmod +x WS_SIM_UBUNTU.x86_64
После этого запуска программу WS_SIM_UBUNTU.x86_64 можно запускать или из терминала или из GUI.
4.2. Общие сведения о симуляторе
Для соединения с ROS2 используется ROS TCP Connector для отправки/получения сообщений из ROS и пакет визуализаций для добавления визуализаций входящих и исходящих сообщений в Unity сцене.
Меню
На изображении показан главный экран приложения. Ниже размещены три основные кнопки:
-
«Выбрать сцену» — переход к выбору сцен;
-
«Настройки» — открытие параметров приложения;
-
«Выйти» — завершение работы программы.
Выбор сцены
На данный момент, доступны четыре варианта окружений:
-
«Пустой бассейн»
-
«Сбор датасета»
-
«Соревнование»
-
«Aruco маркеры».
Выбор любого из вариантов открывает соответствующую сцену симуляции.
Настройка IP
В центральной области размещено поле для ввода ROS IP-адреса, предназначенное для указания адреса узла ROS TCP Endpoint.
4.3. Установка и запуск ноды для отправки команд из ROS в симулятор
Клонируем в папку ~/ros2 репозитория:
https://sdb.smtu.ru/gitlab/marinerobotics/ros-usv-teleop |
Далее необходимо перейти в пакет ros2 cpp modbus
и установить зависимости, которые представлены в README
https://sdb.smtu.ru/gitlab/robotics/ros2_cpp_modbus_driver |
Обратите внимание: При сборке может возникнуть проблема с драйверами v4l-ctl. Исправить данную ошибку можно установив v4l-utils:
$ sudo apt install v4l-utils
После этого перейдите в папку и скомпилируйте ноду:
$ cd ~/ros2/ros-usv-teleop/usv_ws
$ colcon build
Результат правильного выполнения команды выглядит примерно так:
$ colcon build
Starting >>> movement_usv
Starting >>> ros_tcp_endpoint
...
---
Finished <<< ros_tcp_endpoint [1.95s]
Summary: 2 packages finished [2.16s]
1 package had stderr output: ros_tcp_endpoint
Далее, аналогично ROS мы рекомендуем сохранить команду в файл .bashrc (см. раздел про установку ROS, чтобы вспомнить зачем).
$ echo "source ~/ros2/ros-usv-teleop/usv_ws/install/setup.bash" >> ~/.bashrc
$ source ~/.bashrc
Внимание: если вы склонировали код в другую папку, скорректируйте путь к файлу.
После этого можно запускать ноду, которая должна быть запущена в течение всего времени работы с симулятором:
$ ros2 launch movement_usv main.launch.py is_sim:=true
Параметр is_sim:=true отвечает за запуск ROS TCP Connector. Без данного параметра будет запускаться версия для управления аппаратом в реальности.
$ ros2 launch movement_usv main.launch.py
4.4. remapping стандартных инструментов для работы с катамараном/симулятором
Управление с клавиатуры
ros2 run turtlesim turtle_teleop_key \
--ros-args -r /turtle1/cmd_vel:=/ws/twist_pilot
5. Домашнее задание
-
Установить пакет mouse_teleop (ros-jazzy-mouse-teleop);
-
установить пакет twist_stamper (ros-jazzy-twist-stamper);
-
настроить управление turtlesim и катамараном в симуляторе, при помощи мыши;
-
склонировать репозиторий 3 https://sdb.smtu.ru/gitlab/marinerobotics/lesson-03;
-
в файле lesson_03.sh указать список команд, которые нужно ввести в различных консолях, для выполнения домашнего задания;
-
код нужно отправлять в ветку, которую вы создадите сами и назовете по вашей фамилии;
-
-
после загрузки кода необходимо выполнить merge request.
6. Дополнительные материалы
Установка ROS2 https://docs.ros.org/en/jazzy/Installation/Ubuntu-Install-Debs.html |
https://docs.ros.org/en/jazzy/Installation/Ubuntu-Install-Debs.html |
Официальная справка https://docs.ros.org/en/jazzy/Tutorials/Beginner-CLI-Tools.html |
https://docs.ros.org/en/jazzy/Tutorials/Beginner-CLI-Tools.html |
Телеграм-канал российского сообщества ROS https://t.me/rosrussia |
https://t.me/rosrussia |