Введение
Моя первая статья на Хабре, не судите строго, надеюсь содержание будет как минимум интересным!
По профессии я программист, занимаюсь мобильными разработками, но меня всегда тянуло к "железу". Приятно творить магию с помощью кода, но еще приятнее когда результатом твоих трудов является некоторое конечное устройство.
Не так давно, ко мне в руки, попала модель радиоуправляемого катера Avanti от производителя Thunder Tiger, сердцем которого является мощный бесколлекторный двигатель Ripper OBL 29/19 с водяным охлаждением. Производитель обещает скорость до 60 км/ч! Быстро наигравшись, как в далеком детстве, полез смотреть на начинку игрушки.
Устройство предельно простое для любого, кто сталкивался с RC моделями:
трансивер на 2,4 ГГц
блок управления двигателем (регулятор оборотов)
сервомашинка для управления рулем
отсек для LiPo аккумулятора
Первое, что пришло в голову: подключить вместо трансивера - микрокомпьютер Raspberry Pi. Пусть катер получит зачатки интеллекта и самостоятельно отправится в плавание!
Катер весьма точно ориентировался по GPS, ворочал рулем и уверенно проходил контрольные точки. Видео обзор по результатам заплыва можно посмотреть в ролике.
Все получилось, если бы не...
Водоросли и прочий мусор! Катер собирает всю растительность на винт, путается в сетях и таранит любой предмет на своем пути. Было бы здорово, чтобы он не только плавал по координатам, но и уворачивался от препятствий.
В робототехнике часто используют ультразвуковые датчики сближения (в более продвинутых системах - LiDAR). А как быть если препятствие находится прямо в воде и не может быть обнаружено сонаром?
Многие видели, как алгоритмы компьютерного зрения определяют и классифицируют визуальные объекты в реальном времени. Для этого нужны значительные по объему базы данных классификаторов и немалая производительность. А что если мы заранее не знаем, что встретим на своем пути? Если объект будет произвольной формы, цвета и размера?
Вот тут у нас палка проплыла, чудом не повредив корпус катера, а следом водная растительность которая легко запутает винт и руль.
Робото-мировозрение
Для Raspberry Pi существует отличная библиотека OpenCV с огромным набором функций. Мне казалось, что должно существовать готовое решения обнаружения абстрактного препятствия и сопровождение его в реальном времени. И вроде времени я потратил немало, но готовых решений не нашел. Значит будем решать задачу самостоятельно. За образец я взял видео с GoPro установленной на катере во время тестового заплыва по координатам. Не забывайте, на тот момент дрон был еще "незрячий".
Для определения препятствий уместно использовать алгоритм edges, предварительно убрав цветность.
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray, 100, 300)
Теперь сведем полученный результат и исходное изображение.
Уже хорошо, но нужно определить вектор движения и границы "опасных" объектов, чтобы отдавать команды на руль беспилотника.
Отслеживая каждый последующий фрейм, мы можем найти смещение объекта и определить вектор движения относительно положения катера. Причем неважно движется препятствие или катер, мы всегда будем получать вектор по которому происходит сближение с потенциально опасным препятствием.
Вроде уже все здорово и можно доработать скрипт управления судном, если бы не одно жирное НО: такие идеальные условия бывают очень редко. За все время запусков такое случились только один раз.
А вот как выглядит обычный выход на воду:
Этот "шалтай-балтай" совсем не похож на эталонный заплыв "в ванной"...
Возникает закономерная задача стабилизации видео. И тут я упираюсь в проблему ограничения производительности Raspberry Pi. Алгоритмы обработки изображений требуют ресурсов, а запаса у меня уже нет. Поэтому, я решил сделать "финт ушами" и вместо полноценной стабилизации попробовать детектировать линию горизонта и стабилизировать картинку по ней. В дальнейшем, я могу брать углы крена с гироскопа катера и заменить программную стабилизацию на аппаратную, только положение горизонта будет определять не визуальная картинка, а гироскоп.
Что дальше...
Когда я взялся за решение проблемы обхода препятствий, то не знал, что мне предстоит решить сразу несколько задач:
Стабилизация изображения
Обнаружение абстрактных препятствий
"Трекинг" обнаруженных препятствий
Буду рад прочитать ваши комментарии. Обязательно напишите, если хотите увидеть продолжение статей про беспилотный катер.
Комментарии (43)
Meklon
06.01.2022 12:52+1Нашёл статью, которая может быть актуальна.
www.sciencedirect.com/science/article/pii/S1350449519300465tolianT Автор
06.01.2022 13:09Спасибо. Нормальная такая статья. Тоже обратите внимание, с чб изображением работают.
Само по себе определение препятствий у меня уже работает. Отдельно был вопрос оптимизации, алгоритм должен быть шустрым.
Тоже читал разные статьи. Вот по определению линии горизонта только 3-4 солидных таких же видел. На практике они не сработали. При одном ракурсе камеры есть горизонт, на другом уже не видит.
Meklon
06.01.2022 15:49Горизонт лучше всё-таки копеечным акселерометром отслеживать. Возможно даже тремя для возможности выбраковки сбойного датчика, если от этого существенно зависит безопасность функционирования.
tolianT Автор
06.01.2022 21:11Все верно, именно так и будет.
Но пока катер стоит "на приколе" нужно с чем-то работать. Пока горизонт получаю из визуальной картинки. Кстати, это отдельная интересная задачка. Все найденные мной алгоритмы, лажали с определением. :/ не хочу хвастаться, у меня уверенно определяет горизонт даже в условиях водных брызг и частичной видимости.
tur007
06.01.2022 14:53+1Спасибо, очень интересно. Нельзя ли посмотреть исходный код?
tolianT Автор
06.01.2022 21:21Спасибо за поддержку! :)
Вас интересует код детектирования препятствий, стабилизации видео или как происходит трекинг обнаруженных объектов?
Все это часть одного проекта беспилотного катера. Код планирую публиковать когда проведу испытания на "открытой воде" и буду уверен, что все работает как надо.
tur007
06.01.2022 21:30Вам спасибо;) Конечно, хотелось бы увидеть весь код, но трекинг препятствий, наверное, наиболее интересен. С удовольствием посмотрел бы и черновик кода, не стесняйтесь:)
Un_ka
06.01.2022 19:28Про производительность:
Какое расширение видео использовали?
Какую модель Raspberry pi?
Если собирали библиотеку сами, то можно было при сборке включить использование openMP — библиотеку распараллеливания.
Попробуйте написать на C++. Там использование функций и классов openCV почти такое же, но есть возможность скомпилировать с максимальной оптимизацией.
tolianT Автор
06.01.2022 21:24Видео у меня пока - это фрагменты записи с GoPro в формате mp4
Малинка: Raspberry Pi 4 Model B с 4 Гб
За подсказки благодарю! :)
usa_habro_user
07.01.2022 00:44Очень любопытная разработка, и интересная статья! Хотелось бы узнать немного о том, как вы тестировали свой код управления на воде: ведь такая игрушка баксов под $500, думаю, стоит, если что - жалко потерять. Видимо, есть и обычная "моторка" под боком, на всякий случай?
Касательно же детектирования препятствий при помощи RPi, то, мне кажется, что на RPi не получится: не та производительность, да и алгоритмы нужны уж больно хитрые. Притом, полузатопленное бревно или водоросли под самой поверхностью и человеческий глаз далеко не всегда сможет своевременно заметить, да еще и на таких скоростях.
Думаю, что более надежным решением будут чисто "аппаратные" модификации: винт посадить в импеллер и/или окружить сеткой - скорость, конечно, упадет, но, полагаю, незначительно. А для обнаружения препятствий по ходу - использовать простой контактный датчик, усилие на который передается через длинный (1 - 1.5 м) и легкий углепластиковый штырь-"щуп", вынесенный на нос лодки, и подключенный к программируемой логике, или просто к самому RPi. Думаю, для начала и одного хватит - для экстренной остановки в случае препятствия. Если к нему добавить пружину, то можно будет подбирать чувствительность подобного "emergency stop" (ну, чтобы не реагировал на мелкие ветки). Опять-таки, если использовать тонкий, но прочный материал, то сопротивления он практически не добавит, зато надежность будет высокой.
tolianT Автор
07.01.2022 16:57Благодарю! Не думал, что такая специфичная область заинтересует столько людей. Хотя вот меня затянула чуть больше чем полностью. :)
Если интересно, именно по запуску катера, можете посмотреть мой же видео отчет: https://m.youtube.com/watch?v=5ZUPO3FEQQ0
Это не реклама, канал без монетизации, чисто любительский. В конце видео есть подбивка: около 300$ весь проект. При том, что вы можете снять Raspberry Pi и у вас снова будет та же самая игрушка из магазина.
Тоже были сомнения, получится ли детектировать препятствия. Но... пока получается. :) Raspberry Pi 4 достаточно мощный девайс, а библиотека OpenCV неплохо оптимизирована.
Но в любом случае, или все получится, или провалится. И я напишу по какой причине не получилось. :)
usa_habro_user
08.01.2022 07:13Не люблю, если честно, видеблоги, предпочитаю прочесть, но посмотрел, спасибо. Ну, а область DIY не такая уж специфичная; вдобавок, несущийся по волнам катер намного интереснее набивших оскомину радиуправляемых машинок, которые тут "всплывают" с досадной регулярностью. Плюс - такая challanging задача, real time распознавание на такой скорости, да еще и на "малинке".
Моими советами, кстати, не пренебрегайте: они просты в реализации, и вполне могут служить дополнением к продвинутой системе распознавания препятствий.
P.S. Подкину вам еще идейку (если, конечно, вы - рыбак, и в вашем озере водятся щуки и окуни): прикрепите к корме короткую удочку с сенсором натяжения (tension sensor), а к ней на леске блесну-"попплер". Как RPi обнаружит, что натяжение сильно возрастет, нужно резко увеличить обороты ненадолго (подсечка), а потом автоматически буксировать добычу к берегу ;)
tolianT Автор
08.01.2022 10:23+1Солидарен с вами, читать удобнее. Так уж получилось, что сначала это была просто rc игрушка, потом подключил raspberry только из любопытства: разобраться с управлением. Камеру поставил, опять же из любопытства, посмотреть "глазами" капитана этого судна. :) дальше решил научиться монтировать видео, чтобы оставить его себе на память.
Писать статью про запуск катера с raspberry мне показалось неуместным, именно потому, что, как вы пишите, роботомашинки набили всем оскомину. Полностью поддерживаю.
А вот детектирование абстрактных объектов на пути и их отслеживание, та тема по которой мало материала или вообще отсутствует. И так появилась эта дебютная статья. Вдруг в этом сезоне получится реализовать задумку и не потерять катер.
Советами не пренебрегаю, за все идеи читателям благодарен! Значит не зря писал. А все комментарии мотивируют довести дело до конца, появилась ответственность перед вами.
71rmn
07.01.2022 12:33+1Есть подозрение что ИИ не нужен. Ведь задача обходить ВСЕ препятствия, а не определить какие из них опасные.
По идее достаточно отделить «шум» на поверхности воды и трекать его.
Интересно как в итоге вы решите задачу.tolianT Автор
07.01.2022 16:36Вы все верно поняли.
Я не использую нейронные сети для определения объекта. В воде может быть что угодно, хоть коряга похожая на лысого лешего. Задача не столкнуться с ним, а деликатно обойти и вернуться на маршрут. Спасибо, что внимательно прочитали. :)
kulikovDenis
07.01.2022 15:46В список задач нужно еще один пункт добавить, коррекцию сферических искажений. а то горизонт дугой изгибается, рано или поздно этот фактор начнет критически влияеть на результат.
Вот попалась статья, наглядно показывает о чем речь.
https://habr.com/ru/post/341160/tolianT Автор
07.01.2022 16:38Это видео с GoPro. Она в широком формате даёт эффект "рыбьего глаза". Пока не уверен мешает он мне или можно пренебречь. Скоро узнаем, надеюсь!
MShevchenko
07.01.2022 15:59+1Горизонт я бы искал с помощью преобразования Хафа. По факту гироскопы дают дрейф. Результаты с них можно объединить.
Для всего что ниже горизонта можно сделать нормализацию. Возможно нелинейную.
Определение мусора. Пробегаемся граф-сегментатором. Например таким
https://www.cc.gatech.edu/cpl/projects/videosegmentation/
Граф-сегментаторы очень хорошо реагируют на трешхолд.
Пробуем определить вектор движения сегмента и его размер. Или используем более сложные ии классификаторы.
Что бы не гонять классификатор на каждом фрейме используем оптимизацию на подобее описаной в моем патенте https://patents.google.com/patent/US9002056B2 но с учётом того что мы движемся в 3D пространстве.
Если не хватает производительности, смело уменьшайте разрешение для тяжёлых участков. Вплоть до 320х240. На такой скорости фреймрейт важне.
tolianT Автор
07.01.2022 16:45+1Спасибо. Дайте время изучить.
Пока могу сказать по предварительным результатам:
1. фрейм рейт действительно важен
2. камеру необходимо поднять выше над корпусом судна, чтобы раньше замечать препятствия и отстроиться от волн( в плоскости горизонта они мешают сильнее, чем если смотрим на волную поверхность сверху).
Классификаторов у меня нет, я ищу абстрактные препятствия. Просто любой объект, больше некоторого предела "опасности" что ли...
DmitriiR
08.01.2022 06:51+1В камере за оббъективом должен стоять ИК фильтр.
Можно его снять (если он не на метрице конечно) и открыть совсем иные картинки.
Кстати было Красим беззеркалку в инфракрасный цвет / Хабр (habr.com)
Meklon
Я вижу тут очень неприятную фундаментальную проблему. Большинство препятствий вроде водорослей и пакетов имеют те же HSL характеристики цвета, что и вода. Условно, пучок водорослей особо не отличается ничем от зеленоватой воды.
По сути, у нас два пути — пытаться выделить объект в Lightness канале или в Hue. Второй даст неплохой эффект для пакетов и всякого яркого мусора. А вот с зеленоватыми корягами непонятно что делать.
В инфракрасном спектре не пробовал смотреть? Может быть существенная разница в поглощении поверхностью, что даст нужный контраст.
vba
Наверное эта проблема может быть решена в купе с использованием мини эхолота.
tolianT Автор
Думал об этом, но увидит ли эхолот пакет на поверхности воды? На данном этапе актуально обнаружить видимые глазу препятствия. Скрытые препятствия это уже отдельная тема.
vba
Да, пакет на поверхности, не факт, но мне кажется, если подкрутить чувствительность, то заросли травы должны быть видны при колебании воды. А как дела обстоят с использованием лазерного луча или ультразвука на поверхности воды?
tolianT Автор
"Островок" растительности хорошо различим визуально, по опыту испытаний могу сказать.
Лазерные и ультразвуковые дальномеры первое что пришло мне в голову, я же не собирался влазить во все эти проблемы технического зрения. Но не забывайте, мы на воде, а катер постоянно раскачивает на волнах. Ультразвук и лазер будут отражаться от волн на воде.
cepera_ang
От нейронок никуда не деться рано или поздно, а чтобы работали на распбери — воткнуть какой-нибудь мовидиус.
tolianT Автор
Вы не забывайте, что вопрос автономности тоже важен для дрона. У нас только одной проблемы нет в случае с беспилотным катером - отвод тепла. :)
cepera_ang
Neural Compute Stick 2 — полтора ватта, вряд ли это значимый процент от того, что движок потребляет. А учитывая, что распбери сама может жрать до 15 ватт, то глядишь снизив на неё загрузку после переноса на акселератор, ещё и меньше общий пакет окажется :)
tolianT Автор
Спасибо! Изучу сей девайс.
praeivis
Полтора вата, но цена 100$ - для таких проектов дороговато.
cepera_ang
А распбери сколько стоит? :)
tolianT Автор
RaspberryPi 4 model B брал за 40$ на али. Но это было до ванханалии с ценами.
cepera_ang
Плюс флешка, плюс корпус какой-никакой, плюс питание, та же сотня и набежит :) А с учётом вакханалии вообще боюсь смотреть.
А мовидиус на маузере 79 долларов. То есть я не что-то такое заоблачное предложил :)
tolianT Автор
Нет, не заоблачно.
Если он может взять на себя задачу по обнаружению препятствий, то смысл есть.
Я даже думал вторую малинку воткнуть при необходимости.
tolianT Автор
Возможно, вас могло ввести в заблуждение видео с камеры GoPro. Она установлена слишком низко, на самом корпусе катера. Я планирую подключить камеру к самой Raspberry Pi и установить значительно выше, что "отодвинет" горизонт и даст возможность замечать препятствия намного раньше, а заодно уменьшить число помех от водяных капель.
Мне нравится ваша идея задействовать инфракрасный спектр, что может быть особенно полезно в сумерках. Пока же, хочу обнаруживать препятствия в видимом диапазоне: если препятствие видит человек, то должен увидеть катер.
Отдельно спасибо за ваш развернутый комментарий на мою первую статью!
Meklon
Можно попробовать использовать узкополосный инфракрасный фильтр, который отсекает видимый спектр. Сюда же добавить мощный инфракрасный прожектор в импульсном режиме.
В итоге, камера в видимом спектре и камера в ИК, которая дёргает кадры с низким фреймрейтом синхронно со вспышками прожектора. Это даст экономию энергии.
tolianT Автор
Согласен, что это расширет возможности по обнаружению препятствий. Дальность правда будет ограничена: объекты за сотни метров от катера он не добьет.
И задачи по обработке кадров, детектирования препятствий и трекинга так же остаются у нас актуальными.
DMITRY20210921
А может быть над катером будет летать дрон. Он будет лучше видеть панораму. Разведчик.
tolianT Автор
Конечно, крупные препятствия он увидит раньше. Но сразу снижается автономность, отказоустойчивость всего комплекса в сумме, чувствительность к погодным условиям(дождь, ветер)...
На катер можно поставить солнечные панели, с квадракоптером это проблема.
Катер может отплывать на значительные расстояния: десятки километров. Квадрокоптер привязан к оператору и дальности приёма сигнала.
У меня есть ссылка на видео в начале статьи, снимал ракурсы с квадрика как раз. У катера был значительный запас хода, а квадрик уже терял сигнал.