Путь сборкиПродвинутыйНесколько выходных

Робот на ROS 2 находит маркер и подъезжает к нему

Робот находит маркер в другом конце помещения, определяет его положение относительно себя и подъезжает строго по нормали в виде реального графа узлов ROS 2.

Техническая схема: Робот на ROS 2 находит маркер и подъезжает к немуPOSE → STANDOFF → DOCK

Что вы создаёте

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

Все остальные сборки на сайте запускают одну программу на микроконтроллере. Эта — компьютер с колёсами, и это меняет суть проекта. Сложность теперь не в таймингах и проводке, а в том, чтобы понимать взаимное расположение объектов и поддерживать согласованность нескольких частей программного обеспечения, работающих одновременно.

Почему этому роботу нужен компьютер

Arduino не может этого сделать, и причина требует точности. Дело не в сырой скорости: кадр камеры занимает четверть мегабайта, для обнаружения ArUco нужна вещественная линейная алгебра, а всё это должно происходить, пока колёса ещё управляются с частотой 50 Hz. Это работа для операционной системы с реальной памятьью и реальным планированием.

Взамен вы получаете от этой Linux-машины возможность заглянуть внутрь работающего робота. Каждое сообщение между компонентами — это топик, на который можно подписаться с ноутбука. Когда робот проезжает мимо маркера, а не к нему, вы не добавляете отладочные сообщения и не перепрошиваете — вы выполняете ros2 topic echo для позы и в реальном времени видите, что она неверна.

Форма графа узлов

Пять задач, по одному узлу на каждую:

Узел Публикует Назначение
camera /image_raw, /camera_info Снимает кадры с шины CSI
aruco_detector TF camera_link → marker_7 Находит метку, вычисляет её позу
docking_controller /cmd_vel Определяет, куда ехать
diff_drive последовательный порт к Arduino Преобразует Twist в скорости колёс
odometry TF odom → base_link Интегрирует импульсы энкодеров

Именно интерфейсы делают структуру оправданной. Регулятор никогда не работает напрямую с камерой или двигателем — он принимает преобразование координат и выдаёт Twist. Это значит, что тем же роботом можно управлять с клавиатуры, проверять регулятор на тестовом преобразовании координат вообще без оборудования, а позже подключить навигационный стек, публикующий идентичный топик.

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

Список компонентов

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

Компонент Кол-во Примерная стоимость Примечания
Raspberry Pi 4, 4 GB 1 $55 4 GB — практический минимум для ROS 2 и зрения. 1 GB начинает подменять страницы и выходит из строя
Pi Camera Module 3 1 $25 Вариант Wide лучше подходит для навигации — 102° вместо 66°
microSD класса A2, 32 GB 1 $8 Или загрузка с USB SSD, что действительно быстрее
Радиатор или вентилятор 1 $5 Pi 4 снижает частоту при 80 °C, а перегрев приводит к пропуску кадров
Arduino Uno или Nano 1 $5 Энкодеры и управление двигателями — часть, работающая в реальном времени
двигатели N20 с энкодерами 2 $16
TB6612FNG 1 $3
шасси 2WD 1 $12 Место для Pi, стойки камеры и батареи
батарейный блок 1 $15 3S с импульсным регулятором 5 V на 3 A
Напечатанные маркеры ArUco — $0 Напечатайте, измерьте напечатанный размер и используйте измерение

Итого: примерно $145–175. Это самый дорогой проект на сайте с большим отрывом, и почти вся его стоимость приходится на Pi.

Питание — место, где эти роботы чаще всего выходят из строя, а поломка обходится дорого. Просадка питания во время записи на SD-карту повреждает весь системный образ. Используйте импульсный регулятор с запасом по мощности относительно потребления Pi, никогда не используйте общую шину с двигателями и проверяйте vcgencmd get_throttled — любое ненулевое значение означает недостаточное питание и скорое повреждение карты.

Измеряйте напечатанные маркеры. Решение позы ArUco масштабируется прямо пропорционально размеру маркера, который вы задаёте. Маркер, напечатанный принтером в режиме «вписать в страницу» с масштабом 95%, даёт позы, ошибочные на 5% на любом расстоянии, и ничто в конвейере обработки об этом не сообщит.

Порядок сборки

1 — Запустите ROS 2 и проверьте сеть. Следуйте инструкции по установке ROS 2 на Raspberry Pi. Не переходите дальше, пока ros2 topic echo на ноутбуке не покажет топик, публикуемый роботом. Обнаружение устройств по Wi-Fi с наибольшей вероятностью отнимет вечер, и лучше сделать это сейчас, а не во время отладки зрения.

2 — Сделайте так, чтобы колёса выполняли Twist. Подключите Arduino, энкодеры и TB6612FNG и создайте мост cmd_vel. Этап: управление с клавиатуры с ноутбука приводит в действие настоящего робота. Откалибруйте расстояние между колёсами здесь — все последующие этапы наследуют его.

3 — Откалибруйте камеру. Правильно, с реальной мишенью, по калибровке камеры и позе ArUco. Нераскалиброванная камера создаёт позы, которые выглядят правдоподобно, но на краях кадра ошибаются на десятки процентов; это худший доступный вам режим отказа.

4 — Публикуйте маркер как преобразование. Не как пользовательское сообщение с x и y. Публикация camera_link → marker_7 в TF2 позволяет регулятору спросить «где находится маркер в base_link?», а ответ учитывает точное крепление камеры — включая её наклон, который у неё действительно есть.

5 — Подъезжайте к маркеру. Пропорциональный регулятор по азимуту: поверните к нему, едьте вперёд и останавливайтесь на заданном расстоянии. Это работает, но прибывает под углом, что и является поводом для следующего шага.

6 — Сближайтесь по нормали. Вместо рулевого управления по маркеру вычислите путевую точку на некотором расстоянии от лицевой стороны маркера по его нормали, подъедьте к ней и только затем едьте прямо. Это разница между тем, чтобы доехать до стыковочной станции, и выполнить стыковку. Именно здесь ориентация маркера — та часть позы, которая раньше не была нужна, — начинает иметь значение, и здесь вы столкнётесь с неоднозначностью позы.

7 — Оберните это в конечный автомат. Поиск, сближение, выравнивание, финальное приближение, завершение и переходы из каждого состояния при потере маркера. Конечные автоматы для поведения робота описывают структуру; конкретно этому роботу нужен тайм-аут потери маркера, возвращающий к поиску, а не продолжающий движение по последней известной позе.

Важные замечания по оборудованию

Установите камеру жёстко и выполните измерения. Каждая поза, которую вычисляет робот, задана относительно камеры, а TF2 преобразует её в позу относительно робота с помощью преобразования, которое вы объявляете от base_link к camera_link. Камера на гибком кронштейне превращает это объявленное преобразование в ложь, меняющуюся при ускорении.

Наклоните камеру вниз и укажите это. Камера, направленная на горизонт, теряет маркер именно тогда, когда робот приближается. Наклон на десять–пятнадцать градусов вниз сохраняет его в кадре во время финального сближения — и этот наклон входит в статическое преобразование, а не в подстроечный коэффициент регулятора.

Измеряйте маркер штангенциркулем. Масштаб позы прямо пропорционален размеру маркера, который вы сообщаете решателю. Печать с масштабом 96% из-за режима «вписать в страницу» делает каждое расстояние ошибочным на 4% — тихо и постоянно.

Питайте Pi отдельно от двигателей. Останавливающийся двигатель просаживает шину, и там, где Arduino безвредно перезагрузился бы, Pi повреждает файловую систему. Используйте отдельный регулятор или отдельный батарейный блок — здесь не место экономить на компоненте.

Держите ленту камеры подальше от проводов двигателей. Это неэкранированная высокоскоростная линия передачи данных. Шум от двигателей, попавший в неё, проявляется как повреждённые кадры, а те — как обнаружения, которые мерцают без видимой причины.

Как выглядит хороший результат

Показатель Типичное значение на Pi 4
Захват камеры при 640×480 30 fps
Обнаружение ArUco, 640×480 25–30 fps, с использованием 40–60% одного ядра
Обнаружение ArUco, 1920×1080 5–8 fps — и каждый кадр устарел
Дальность обнаружения маркера (маркер 100 mm, 640×480) 1.5–2.5 m
Точность позы при 1 m ±2–5 cm по положению, ±3–5° по ориентации
Общая задержка от изображения до решения 60–120 ms
Контур управления двигателями, на Arduino 100–200 Hz
Задержка топика ROS 2, от Pi к Arduino по последовательному порту 5–15 ms

Две строки несут в себе весь смысл проекта.

Разрешение не бесплатно, а более высокое часто хуже. Переход от 640×480 к 1080p увеличивает обработку в 4–6× примерно ради увеличения дальности обнаружения в 1.7× раза. Если вам не нужно видеть маркер издалека, меньший кадр даёт более быстрый и свежий ответ, а свежесть в контуре управления важнее точности.

Строка задержки объясняет, почему существует разделение на два мозга. При 0.3 m/s задержка зрения в 100 ms — это 3 cm пути; при повороте со скоростью 90°/s — это 9° поворота. Каждое измерение зрения описывает, где робот был. Если замкнуть быстрый контур непосредственно на нём, он будет колебаться. Рабочая структура — та, которую использует этот робот: Arduino выполняет быстрый контур по энкодерам, а зрение медленно корректирует его — точно та же схема, что при слиянии GPS с одометрией на роботе для прохождения маршрутных точек, и по той же причине.

Скользящий затвор, если робот движется во время съёмки

Стандартные модули камеры Pi имеют скользящий затвор: строки экспонируются одна за другой, поэтому верхняя часть кадра снимается на несколько миллисекунд раньше нижней. В неподвижном состоянии это незаметно. При повороте со скоростью 90°/s четыре угла маркера ArUco снимаются при четырёх разных ориентациях робота, и вычисленная по ним поза неверна так, что калибровка не может это исправить.

Если робот должен выполнять зрение во время движения, именно для этого предназначен модуль Global Shutter. Если он может позволить себе остановиться, посмотреть, а затем двигаться, более дешёвый модуль вполне подойдёт — останавливаться, чтобы посмотреть, является допустимым проектным решением, а не обходным путём.

Когда что-то идёт не так

Симптом Обычно
Ноутбук не видит топики Многоадресная передача заблокирована точкой доступа или не совпадает ROS_DOMAIN_ID
Маркер обнаружен, робот не движется Twist публикуется подписчику TwistStamped
Расстояние постоянно отличается на несколько процентов Неверный размер маркера или принтер масштабировал страницу
Поза сильно дрожит на дальности Маркер слишком мал в кадре — приблизьтесь или напечатайте больше
Нормаль маркера скачет туда-сюда Неоднозначность позы — приближайтесь не по оси или используйте доску ChArUco
Робот прибывает рядом с маркером, но криво Управляет по маркеру, а не по его нормали
Перелетает при финальном сближении Управляет по позе возрастом 50–100 ms — замедлитесь в конце
Продолжает движение после выхода маркера из кадра В конечном автомате нет тайм-аута потери маркера

Распределение в этой таблице стоит заметить до начала работы: почти ничего из этого не относится к компьютерному зрению. Это сетевые взаимодействия, кадры, единицы и управление — именно этому учит создание робота на ROS 2, поэтому основы ROS 2 уделяют время паттернам обмена и системам координат, а не OpenCV.

Если это слишком сложный шаг, робот для прохождения лабиринта обучает построению карты и планированию на микроконтроллере без Linux, а робот с управлением по телефону рассматривает часть этой задачи, связанную с тем, что «команды поступают по сети», за небольшую долю деталей.

Дорожная карта проекта

Путь сборки

Следуйте по дереву технологий от деталей к работающему роботу. Каждый узел открывается, когда выполнены его предварительные условия, а ваш прогресс сохраняется на этом устройстве.

0 / 19 выполнено

100%
Учебный путь

Основы ROS 2

Траектория обучения

Открыть путь
Учебный путь

Управление двигателями

Траектория обучения

Открыть путь
Сборка

Управляйте им с ноутбука

Сборка

Сборка

Сближайтесь по нормали

Сборка

Цель

Стабильно стыкуйтесь с маркером

Цель

Компоненты

Руководства на этом пути

Часто задаваемые вопросы

Почему для этого использовать ROS 2, а не один скрипт Python?

Для этого робота одного скрипта было бы достаточно, и он был бы короче. Но он не пережил бы вторую функцию. Как только цикл камеры, цикл привода и логика принятия решений должны работать с разными частотами и продолжать работу при зависании одного из них, один скрипт превращается в задачу планирования, которую приходится решать самостоятельно. ROS 2 даёт разделение процессов, формат обмена между частями и — то, что сразу заметно, — возможность из ноутбука просматривать любой топик во время работы робота. Этот проект стоит реализовать, потому что он учит этой структуре на задаче, достаточно небольшой, чтобы её ещё можно было понять.

Нужны ли мне одновременно Arduino и Raspberry Pi?

Строго говоря, не обязательно, но с ним робот будет значительно лучше. На Pi работает Linux, а значит цикл двигателя планируется вместе со всем остальным и иногда будет задерживаться на миллисекунды. Для зрения это незаметно, а для ПИД-регулятора (PID) колеса — смертельно. Разделение робота — Pi для восприятия и решений, микроконтроллер для контуров, которые не должны иметь дрожания, — является стандартной архитектурой, и ROS 2 также поощряет именно её.

Почему маркер ArUco, а не обнаружение реального объекта?

Потому что маркер даёт полную 6-DOF-позу по одному кадру без обучающих данных и без неоднозначности в том, какой объект найден. Обнаружение стула примерно говорит, где находится стул; обнаружение метки ArUco сообщает её положение и ориентацию в метрах, что на самом деле нужно регулятору. Это также честная отправная точка — реальные станции стыковки, складские роботы и площадки посадки дронов используют маркеры-ориентиры по той же причине.

Почему ориентация маркера скачет туда-сюда?

Это неоднозначность позы, свойство геометрии, а не ошибка в коде. Плоский квадрат при почти фронтальном просмотре имеет две ориентации в 3D, которые проецируются почти на одни и те же пиксели, поэтому даже небольшой шум переключает решатель между ними. Расстояние остаётся стабильным, а вычисленная нормаль скачет. Используйте физически больший маркер, приближайтесь с небольшим боковым смещением, где два решения расходятся, или переходите к доске ChArUco или нескольким маркерам на станции стыковки — всё это даёт решателю дополнительные геометрические данные, которые помогают различить эти два варианта.

Насколько точна стыковка?

С откалиброванной камерой и маркером, измеренным с точностью до миллиметра, реалистична погрешность в один-два сантиметра при расстоянии стыковки в полметра. Преобладают не те ошибки, которых ожидают: неверно заданный размер маркера пропорционально масштабирует каждую оценку расстояния, а задержка конвейера обработки камеры означает, что поза, по которой вы управляете, описывает положение маркера 50–100 мс назад. Замедление на последних 30 cm пути устраняет большую часть второй проблемы бесплатно.

Можно ли выполнить этот проект на Raspberry Pi Zero?

Для этого проекта — нет, не с комфортом. Zero 2 W может запускать ROS 2 и декодировать видеопоток камеры, но поверх этого оставлять ресурсы для ArUco-детектирования на приемлемой частоте кадров, а сборка рабочего пространства на нём мучительна. Используйте Pi 4 с 4 GB или Pi 5. Zero — хорошая плата для робота, чей Pi только передаёт команды.