Не хватало записей в конкурс настольных роботов незадолго до закрытия окна регистрации на RoboGames 2023. Чтобы убедиться, что конкурс состоится, я ввел робота. Потом мне пришлось построить один.
Что такое настольный робот?
Tablebot живет на столе. Конкурс состоит из трех «этапов»:
- Этап I. Соберите робота, который ходит от одного конца стола к другому и обратно.
- Этап II: Попросите робота столкнуть блок с выступа стола.
- Фаза III: Попросите робота втолкнуть блок в коробку из-под обуви, установленную в конце стола.
Также есть неофициальная Фаза IV — упасть со стола и выжить. Я не пробовал эту фазу.
Большинство настольных роботов довольно просты — пара гидролокаторов или ИК-датчиков, и они как бы бродят по столешнице в надежде завершить различные этапы. Мой настольный робот совершенно другой — и это окупилось, поскольку робот выиграл золотую медаль на RoboGames 2023.
Сборка роботов
Весь робот построен из напечатанных на 3D-принтере деталей и случайных вещей, которые у меня были под рукой.
У меня какое-то время был один из этих лидаров LD-06 за 99 долларов, и я решил, что это отличный проект для его использования. Я использовал сервопривод Dynamixel AX-12, чтобы наклонить лазер, чтобы найти стол, куб или цель.
Весь код работает на STM32, на моей специальной плате Etherbotix, которая была разработана для моего Робот Максвелла несколько лет назад. В роботе используется дифференциальный привод с редукторными двигателями 30:1 12 В, которые были приобретены у Lynxmotion в 2008 году и на протяжении многих лет использовались в различных пожарных роботах.
В качестве датчиков обрыва используется набор небольших цифровых ИК-датчиков Sharp. Их можно перемещать вверх или вниз для калибровки различных поверхностей стола с помощью пары регулировочных винтов. Хотя датчики очень точны и останавливают робота, они не видят достаточно далеко вперед при движении на полной скорости, поэтому я также использую лазер, чтобы определить, когда приближается край стола.
Программное обеспечение фазы 1
Фаза 1 довольно прямолинейна и в основном основана на одометрическом счислении:
- Лазер направлен вниз в поисках стола. Это делается путем проецирования сканирования на 3D-точки и фильтрации всего, что не находится перед роботом примерно на высоте стола. Когда стол исчезает (количество точек становится слишком низким), мы уменьшаем максимальную скорость до значения, безопасного для обнаружения датчиками обрыва.
- Пока лазерные датчики ищут конец стола, робот движется вперед, а простая петля обратной связи удерживает робота в центре стола с помощью одометрии.
- Когда в конечном итоге срабатывают датчики обрыва, робот останавливается, отступает на 15 сантиметров, а затем поворачивается на 180 градусов — все это с использованием одометрии с абсолютным счислением.
- Затем максимальная скорость сбрасывается, и мы улетаем на другой конец стола с тем же поведением.
Программное обеспечение фазы 2
Движения фазы 2 в основном такие же, как и фазы 1 — мы движемся вперед, оставаясь в центре с помощью одометрии. Скорость немного ниже, чем в Фазе 1, потому что лазер тоже ищет блок:
- Лазерное сканирование проецируется в 3D, и мы отфильтровываем любые точки, которые являются частью таблицы, в зависимости от высоты. Эти оставшиеся точки затем группируются, и кластеры анализируются по размеру.
- Если кластер является хорошим кандидатом на блок, робот поворачивается к блоку (используя, как вы уже догадались, точный расчет по одометрии).
- Затем робот движется к блоку, используя простой контур управления, чтобы удерживать курс.
- Как только блок достигнут, робот едет прямо, пока не сработает датчик обрыва.
- В этот момент робот останавливает колесо со стороны сработавшего датчика обрыва и очень медленно двигает другое колесо вперед, чтобы мы выровняли переднюю часть робота с краем стола, гарантируя, что блок будет отодвинут от стола. .
Программное обеспечение фазы 3
Заключительный этап самый сложный, но не намного. Как и на предыдущих этапах, робот перемещается по столу в поисках блока:
- В отличие от фазы 2, робот фактически приближается к позе сразу за блоком.
- Как только эта поза будет достигнута, робот наклоняет лазер обратно на уровень и находит цель.
- Затем робот поворачивается к цели так же, как сначала поворачивался к блоку.
- Затем робот приближается к цели, используя тот же простой контур управления, и в процессе толкает блок к цели.
Все программное обеспечение для моего Tablebot доступно на Гитхаб.
Робоигры видео
Джим Динунцио, член Клуба самодельной робототехники, снял видео во время реального соревнования в Robogames, чтобы вы могли увидеть выигрышную серию заездов:
Визуализация
Чтобы упростить разработку, я также написал графический интерфейс Python, который отображает таблицу, след одометра робота, данные лазера и обнаруженные цели и кубы.
Веселье с математикой
Попутно я столкнулся с ошибкой в библиотеке DSP ARM CMSIS. я использовал arm_sin_cos_f32()
функция для вычисления моей одометрии:
arm_sin_cos_f32(system_state.pose_th * 57.2958f, &sin_th, &cos_th);
system_state.pose_x += cos_th * d;
system_state.pose_y += sin_th * d;
system_state.pose_th = angle_wrap(system_state.pose_th + dth);
Эта функция принимает угол (в градусах!) и возвращает синус и косинус угла, используя справочную таблицу и некоторую интересную интерполяцию. При визуализации пути робота я заметил, что одометрия робота время от времени прыгала в сторону и назад, что не имело смысла.
Дальнейшее исследование показало, что для очень малых отрицательных углов arm_sin_cos_f32
возвращал огромные значения. Я углубился в код и обнаружил, что существует несколько разных версий:
- Версия из моей старой библиотеки STM32 имела эту конкретную проблему с очень маленькими отрицательными числами. Та же ошибка все еще присутствовала в официальном CMSIS-DSP на учетной записи руки.
- Версия в текущей библиотеке STM32 имела исправление для этого места, но это исправление сломало функцию для всего квадранта!
Проблема оказалась довольно простой:
- В коде используется таблица поиска из 512 элементов.
- Для данного угла он должен интерполировать между предыдущей и следующей записью в таблице.
- Если ваш угол упал между 511-й записью и следующей (которая будет 0-й записью из-за циклического перехода), тогда вы использовали случайное значение в следующем слоте памяти для интерполяции между (и для вычисления интерполяции). В какой-то момент это привело к тому, что sin(-1/512) вернул возмутительные значения вроде 30.
После исправления этой ошибки одометр работал безупречно. Как оказалось, у меня была такая же функция/ошибка в каком-то рабочем коде управления бесколлекторным двигателем.
Робоигры завершаются
Как здорово, что RoboGames вернулись! Этот маленький робот больше не появится, но я начинаю работать над роботом RoboMagellan на следующий год.
Майкл Фергюсон