Привет Хабр! Я работаю RnD-художником в минском центре разработки Wargaming. А в свободное время даю волю своей инженерной фантазии. В этой статье я хочу поделиться своим опытом домашнего марсоходостроения.
Началось все с того, что захотелось почувствовать, каково управлять марсоходом, находящимся за десятки световых минут. Доступа к настоящему роверу, конечно же, нет, поэтому построил свой. Главным условием, которое я был намерен соблюсти – симуляция временного лага в управлении. Усилий потрачено масса, но нужный результат был достигнут.
Не буду подробно останавливаться на своих изысканиях, а сразу опишу финальную конструкцию. Если будет интересно, почему я пришел к этим решениям и комплектующим (или сможете предложить варианты лучше), то милости прошу в комментарии.
Hardware
Перво-наперво была приобретена платформа — радиоуправляемый танк Abrams M1A2, содержимое которого (за исключением двигателей) было беспощадно выпотрошено:
Далее, я приступил к поиску источника питания. К сожалению, Плутоний-238 для самодельного РИТЭГа найти не удалось, поэтому пришлось использовать альтернативный вариант. Достойной заменой стала батарея из 16 аккумуляторов NCR18650B (3400 мА) с контроллером заряда/разряда. Расчетная емкость — 27 А/ч при напряжении 7,2 В:
Мозгом ровера стал Raspberry Pi 2. Шлейфом (удлиненным и армированным скотчем) к нему подключена камера без IR фильтра, с инфракрасной подсветкой:
Подсветка потребляет достаточно много энергии, поэтому включается лишь во время съемки при уровне освещения ниже установленного порога. Также только на время замера включается и оптический дальномер. Включение и отключение происходит при помощи 40-амперных мосфетов (других ключей в запасе не нашлось), управляемых микроконтроллером Atmega328 с минимальной обвязкой. К этому же контроллеру подключен дальномер и фоторезистор. Для последнего я подобрал функцию аппроксимации под промышленный люксметр, взятый на работе (там мы его используем для валидации освещения). Также я использовал бесконтактный датчик температуры MLX90614. Вся эта обвязка была собрана на макетной плате и прикручена к серводвигателям вращения головы. К Raspberry головной модуль подключен всего четырьмя проводами — питание и шина I2C.
Для управления сервоприводами я использовал специализированный I2C-контроллер PCA9685 на 16 ШИМ выходов. Сначала попробовал Arduino, но библиотека для сервоприводов там реализована программно. Из-за этого возникали спонтанные рывки и подергивания во время работы контроллера с I2C. Как-то раз ровер даже начал молотить камерой о стол. После замены Arduino на PCA9685 все движения стали ровными
Для управления двигателями я использовал немного доработанный Dual Channel H-Bridge Motor Shield.
По умолчанию для управления требуется семь линий, две из которых ШИМ. Я выбросил входную логику, подключившись к входам драйверов на прямую. Получилось пять управляющих линий. Но теперь стало необходимо, чтобы четыре из них управлялись через ШИМ. Пытался использовать оставшиеся линии PCA9685, но оказалось, что частота ШИМ на всех каналах должны быть одна, а 50 герц для управления серводвигателями мне никак не подходили. У Raspberry всего один полноценный ШИМ, а связываться с программными не хотелось. В результате я решил использовать дополнительный контроллер, который заодно измеряет напряжение батареи. В итоге получился I2C моторшилд:
Дополнительно я установил энкодеры от мышек с прорезинеными колесами от них же, которые отслеживают скорость и дистанцию при движении. Энкодеры подключены к малинке через RC-фильтры и вызывают прерывания в обработчике при срабатывании. Применение простых фильтров почти убрало дребезг контактов, а оставшиеся случайные срабатывания элементарно отсекались в коде. Скорость меряется по временным промежутка между прерываниями, и усредняется по нескольким замерам.
Для питания ровера используется два понижающих стабилизатора — отдельно для Raspberry и электроники, и отдельно для сервоприводов. Внутренности марсохода выглядят так:
Датчики влажности и давления, а также GPS, я вынес на «броню». GPS подключен к нативному последовательному порту Raspberry. В итоге у меня получился вот такой «зоопарк» I2C-устройств:
Изначально в качестве центра управления трудился Arduino c радиомодулем, подключенным к PC. Но решение было не совсем аутентичным, поэтому я заменил его на еще один Raspberry Pi 2, управляемый по SSH. Заодно это позволило управлять ровером не из дома (если вы понимаете, о чем я). Обмен данными с ровером идет через модули nrf24L01 PA.
Итоговое фото марсохода:
Software
Для работы с железом я собрал и установил библиотеки BCM2835, WiringPi, NRF24 и OpenCV. По поводу последней были большие опасения, но на удивление, все прошло гладко. Хоть на сборку и ушло более трех часов. OpenCV понадобился для исправления сильного искажения камеры (для этого откалибровал камеру), для отрисовки GUI поверх снимков и создания примитивной панорамы:
С библиотеками для I2C-датчиков пришлось повозиться. В итоге я понял, что каждый датчик предпочитает свою частоту шины. Большую часть кода датчиков пришлось переписать под библиотеку BCM2835 — тут частоту шины можно регулировать. Не обошлось без казусов. Оказалось, что магнитомер девятиосевого гироскопа —отдельный девайс со своим адресом. При его программном подключении на общую шину он почему-то вырубал датчик влажности, хотя они и имели разные адреса. Поэтому магнитометр программно подключается к шине только перед замером.
Обновлять данные акселерометра для фильтра MadgwickAHRS нужно с равными промежутками времени, поэтому его код я вынес в отдельный поток. Во избежание конфликтов доступа к шине добавил мьютекс для I2C. Кстати, MadgwickAHRS очень удобная штука — скармливаем ему сырые данные, а на выходе получаем готовый отфильтрованный кватернион поворота ровера в пространстве. Чтобы данные сильно не плыли, необходим откалиброванный гироскоп. Также он позволяет получать крен и тангаж марсохода и осуществлять поворот на заданный угол.
Для реализации настраиваемой задержки радиомодуля я использовал очереди из структур (32 байта пакета и метка времени), а также два отдельных потока. Один непосредственно общается с радиомодулем, а второй занимается управлением данными. Опять же есть мьютексы для защиты от конфликтов. Протокол обмена прост до безобразия — принять/отправить строку или файл. Благодаря этому можно передать роверу скомпилированную программу из центра управления — в итоге пригодилось для правки багов уже во время миссии.
Двигателями управляю посредством ПИД-регуляторов, с учетом данных от энкодеров. На настройку коэффициентов регуляторов потратил несколько дней, снимая десятки и даже сотни графиков и подстраивая параметры. Но в итоге добился плавной и четкой работы.
Были некоторые проблемы с потерей данных на шине I2C между малиной и микроконтроллерами. Решилось использованием контрольных сумм.
Написал парсер для модуля GPS, благо протокол NMEA 0183 не отличается сложностью. Парсер работает в отдельном потоке и посимвольно обрабатывает входящую информацию.
Научил марсоход делать тепловые карты, используя mlx90614 (тот же вид с балкона):
Миссия 1: тест в домашних условиях
Изначально я планировал выехать загород и запустить марсоход в сельской местности. Но из-за неблагоприятных погодных условий (снежный покров в полметра), было решено произвести запуск прямо в квартире.
Итак, ровер был активирован перед уходом на работу. Я удаленно связался с центром управления и успешно установил связь с марсоходом. Задержку сигнала установил на две минуты. Вскоре получил первую панораму (кликабельно):
Внезапно обнаружился баг в коде — ровер не ждал окончания команд движения. Пришлось править, собирать и отправлять ему пофикшенную прошивку. И вот ровер отправляется навстречу неизвестности:
Но всплыла очередная проблема — внезапно начала портиться приходящая по радиоканалу информация. Пример (тут отключена проверка на контрольную сумму, иначе файлы не были бы приняты):
Быстрый разбор показал, что виновата шина SPI в центре управления. Снизив ее частоту вдвое, проблему удалось решить. Заодно я снизил частоту шины для ровера и залил ему новую прошивку.
Итак, миссия продолжилась. Первый тепловой скан:
В целом удаленно управлять ровером со значительной задержкой оказалось очень увлекательно. Вот только скорость продвижения невысока. Например, заехав в кладовку, ровер целый час пытался оттуда выбраться. Как потом стало ясно — я не рассчитал расстояние и зацепился головным модулем за шланг пылесоса:
Когда в центре управления отказал радиомодуль, миссию пришлось свернуть, т.к. на уровне ПО решить проблему не удалось (подвели разъемы).
Весна близко! Поэтому планирую в ближайшее время пофиксить все баги и отправить марсоход на улицу.
Если вы можете поделиться полезным опытом или просто хотите задать вопросы — пишите комментарии.
Все исходники тут github.com/DIMOSUS/Rover
Комментарии (17)
zabbius
01.03.2016 16:38+2Привет, коллега (https://habrahabr.ru/post/244407/)!
А чем не понравился тот же ServoBlaster на RPi? У меня оно 5 серво-каналов без проблем держит.
В каком виде видео гонится на пульт? Насколько большие лаги при ручном управлении?DIMOSUS
01.03.2016 16:48Привет! Хотел его использовать, но по хорошему нужно согласование уровней 3.3v/5.0v. Хотя возможно и так будет работать. Под рукой оказался подходящий модуль, захотелось его опробовать.
Одна картинка передается секунд 15. Больше 500 килобит выжать из модулей не смог. Но учитывая исскуственный лаг в две минуты это вообще не проблема. Wi-Fi использовать посчитал не спортивным.zabbius
01.03.2016 17:51Для стандартных сервоприводов и модельных регуляторов напряжения все ок. ServoBlaster дает импульсы от 1 до 2 мс каждые 20 мс (диапазон импульса может быть чуть шире, настраивается). А амплитуда импульсов как раз должна быть равна питанию сервы, то есть 5-6 В. Получается точный аналог сигнала с обычного приемника для RC моделей.
Насчет картинки, если нету FPV, то как эта штука управляется? Сама ездит или просто вслепую?DIMOSUS
01.03.2016 18:36Даю команду сделать снимок или панораму. Жду несколько минут. По снимку прикидываю, куда поехать. Даю команду что-то сделать. Снова несколько минут жду снимок.
В этом вся суть проекта.zabbius
01.03.2016 18:37А команда — это что-то вроде метр прямо, поворот 30 градусов, еще полметра прямо?
Не думали прикрутить туда до кучи USB веб камеру для низкокачественного, но быстрого видео (MJPEG у нее аппаратный)?DIMOSUS
01.03.2016 18:49Да, именно так и управляется.
Имеющаяся камера подключена на аппаратный порт малины, так что она будет лучше любой USB. Просто цели делать FPV не стояло :)zabbius
01.03.2016 19:05Что цели не было я понял, просто, насколько я помню, аппаратная камера выдает yuv, который довольно таки прилично весит, а жать в JPEG программно на RPi так себе идея, процессор откровенно слабоват.
Кстати, а как отмеряется тот самый метр, который вперед и т.п.? Если обработка пробуксовок и неоднородной поверхности (одной гусеницей на ковре)?DIMOSUS
01.03.2016 19:39Пока реализовано только слежение за пройденным растоянием каждой гусеницы. Не сложно будет доработать учет акселерометра. Но для квартиры пока не понадобилось.
MaxAlekseev
01.03.2016 18:41Можно подробнее написать про видеоканал, с помощью чего осуществляется стриминг и где на видео накладывается телеметрия?
DIMOSUS
01.03.2016 18:53Стриминга как такового нет. По команде ровер делает фото, с помощью OpenCV рисует поверх его телеметрию и по радиоканалу (nrf24L01) пересылает файл центру управления.
drobzik
03.03.2016 15:56А можете рассказать чуть подробнее, как вы строите теплокарты?
DIMOSUS
03.03.2016 16:42+2По аналогии с https://geektimes.ru/post/257850/ только тут всем управляет Raspberry.
У робота имеется однопиксельный бесконтактный датчик температуры в головном модуле. Сервоприводы построчно перемещают датчик. На сканирование уходит порядка минуты.
leremin
Как гироскоп получит крен и тангаж? Нет, можно, конечно. Но теоретически. Обычно они акселерометрами меряются. Гироскопы в этом плане грубее на порядки.
DIMOSUS
Для краткости назвал модуль гироскопом, но конечно имел в виду гироскоп/акселерометр/магнитометр.
dittohead
Акселерометр кажущуюся скорость по осям мерит, а вот гироскоп как раз крен, рысканье и тангаж и мерит.
leremin
Смотря, как считать. Можно взять три акселерометра и расположить их ортогонально, то по проекциям на вертикаль и горизонталь очень легко определить крен и тангаж. Гироскопами тоже можно, но грубее будет. С рысканьем — да, нельзя. Но это если нужны мгновенные значения, если нужна траектория, то без гироскопов не обойтись. А вообще тема слишком обширна.