Узлы и граф вычислений
Узел — это базовая единица программы в ROS; из узлов складывается граф вычислений всего робота.
Узел (node) — это отдельная программа в ROS, отвечающая за одну задачу: опрос датчика, управление мотором, планирование маршрута. Множество узлов и связей между ними образуют граф вычислений.
Один узел — одна обязанность
Главный архитектурный принцип ROS: дроби систему на узлы по принципу единственной ответственности. У нашей мобильной платформы это может быть узел lidar_driver (читает лидар), узел camera_driver (читает камеру), узел localization (определяет, где робот), узел planner (строит маршрут) и узел motor_controller (крутит колёса). Каждый можно запустить, остановить, перезапустить и отладить отдельно. Упал планировщик — драйверы продолжают работать.
Узлы могут жить в разных процессах и даже на разных компьютерах. Например, тяжёлую обработку изображения вынесли на мощный ноутбук, а простое управление моторами оставили на Raspberry Pi внутри робота — для ROS это по-прежнему один граф.
Граф вычислений
Если нарисовать все узлы кружками, а связи между ними стрелками, получится граф вычислений — карта всей программной системы робота в данный момент. Это не статичная схема из документации, а живое отражение того, что реально запущено прямо сейчас.
+---------------+ /scan +----------------+
| lidar_driver | -------------> | localization |
+---------------+ +----------------+
|
/pose |
v
+---------------+ /cmd_vel +----------------+
| motor_control | <------------- | planner |
+---------------+ +----------------+
Инструменты интроспекции
ROS 2 даёт команды, чтобы заглянуть в живой граф. Они начинаются с ros2 node.
# Список всех запущенных узлов
ros2 node list
# Подробности про конкретный узел: что публикует, на что подписан
ros2 node info /localizationВывод (пример ros2 node list):
/lidar_driver /localization /planner /motor_control
Имена и пространства имён
У каждого узла есть имя, по которому его видно в графе. Имена можно группировать в пространства имён (namespaces) — это особенно важно, когда роботов несколько. Если два одинаковых робота запустить с пространствами имён /robot1 и /robot2, их узлы и топики не столкнутся: будет /robot1/lidar_driver и /robot2/lidar_driver.
Как работает под капотом
Когда узел стартует, библиотека клиента ROS (для Python это rclpy) инициализирует контекст, регистрирует узел в DDS и запускает цикл обработки событий — executor. Executor крутится в spin() и вызывает ваши обработчики (колбэки), когда приходят сообщения, запросы или срабатывают таймеры. Пока узел «спиннится», он живёт; как только spin прерывается — узел корректно отключается от графа.
Частые ошибки
- Запихивать всё в один узел. Теряется главное преимущество — независимость и отладка по частям.
- Дублировать имена узлов. Два узла с одинаковым именем в одном домене конфликтуют; используйте namespace.
- Забыть spin(). Без цикла обработки узел создан, но колбэки не вызываются — кажется, что «ничего не происходит».
Итоги
- Узел — программа с одной задачей; робот состоит из множества узлов.
- Граф вычислений — живая карта запущенных узлов и связей.
- Команды ros2 node list/info показывают, что реально работает.
- Namespaces разделяют узлы, когда роботов несколько.