Введение
Моя первая статья на Хабре, не судите строго, надеюсь содержание будет как минимум интересным!
По профессии я программист, занимаюсь мобильными разработками, но меня всегда тянуло к "железу". Приятно творить магию с помощью кода, но еще приятнее когда результатом твоих трудов является некоторое конечное устройство.
Не так давно, ко мне в руки, попала модель радиоуправляемого катера Avanti от производителя Thunder Tiger, сердцем которого является мощный бесколлекторный двигатель Ripper OBL 29/19 с водяным охлаждением. Производитель обещает скорость до 60 км/ч! Быстро наигравшись, как в далеком детстве, полез смотреть на начинку игрушки.
![Thunder Tiger Avanti Thunder Tiger Avanti](https://habrastorage.org/getpro/habr/upload_files/51c/7c4/5a6/51c7c45a6570ae46f666e5eeb456115e.jpeg)
Устройство предельно простое для любого, кто сталкивался с RC моделями:
трансивер на 2,4 ГГц
блок управления двигателем (регулятор оборотов)
сервомашинка для управления рулем
отсек для LiPo аккумулятора
Первое, что пришло в голову: подключить вместо трансивера - микрокомпьютер Raspberry Pi. Пусть катер получит зачатки интеллекта и самостоятельно отправится в плавание!
![Вот что получилось. Хорошо, что Raspberry Pi не занимает много места. Вот что получилось. Хорошо, что Raspberry Pi не занимает много места.](https://habrastorage.org/getpro/habr/upload_files/fd3/fa5/e62/fd3fa5e6253686f561a0e7852b70ebaf.png)
Катер весьма точно ориентировался по GPS, ворочал рулем и уверенно проходил контрольные точки. Видео обзор по результатам заплыва можно посмотреть в ролике.
Все получилось, если бы не...
Водоросли и прочий мусор! Катер собирает всю растительность на винт, путается в сетях и таранит любой предмет на своем пути. Было бы здорово, чтобы он не только плавал по координатам, но и уворачивался от препятствий.
В робототехнике часто используют ультразвуковые датчики сближения (в более продвинутых системах - LiDAR). А как быть если препятствие находится прямо в воде и не может быть обнаружено сонаром?
Многие видели, как алгоритмы компьютерного зрения определяют и классифицируют визуальные объекты в реальном времени. Для этого нужны значительные по объему базы данных классификаторов и немалая производительность. А что если мы заранее не знаем, что встретим на своем пути? Если объект будет произвольной формы, цвета и размера?
Вот тут у нас палка проплыла, чудом не повредив корпус катера, а следом водная растительность которая легко запутает винт и руль.
Робото-мировозрение
Для Raspberry Pi существует отличная библиотека OpenCV с огромным набором функций. Мне казалось, что должно существовать готовое решения обнаружения абстрактного препятствия и сопровождение его в реальном времени. И вроде времени я потратил немало, но готовых решений не нашел. Значит будем решать задачу самостоятельно. За образец я взял видео с GoPro установленной на катере во время тестового заплыва по координатам. Не забывайте, на тот момент дрон был еще "незрячий".
Для определения препятствий уместно использовать алгоритм edges, предварительно убрав цветность.
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray, 100, 300)
![Вот так алгоритм детектирует палку на воде Вот так алгоритм детектирует палку на воде](https://habrastorage.org/getpro/habr/upload_files/14d/f33/ba5/14df33ba5bdff45736b6807986e189c3.png)
![А вот небольшие пучки водорослей А вот небольшие пучки водорослей](https://habrastorage.org/getpro/habr/upload_files/9ed/330/1bc/9ed3301bcdbf3f09de2a33cd4da6a03c.png)
Теперь сведем полученный результат и исходное изображение.
Уже хорошо, но нужно определить вектор движения и границы "опасных" объектов, чтобы отдавать команды на руль беспилотника.
Отслеживая каждый последующий фрейм, мы можем найти смещение объекта и определить вектор движения относительно положения катера. Причем неважно движется препятствие или катер, мы всегда будем получать вектор по которому происходит сближение с потенциально опасным препятствием.
Вроде уже все здорово и можно доработать скрипт управления судном, если бы не одно жирное НО: такие идеальные условия бывают очень редко. За все время запусков такое случились только один раз.
А вот как выглядит обычный выход на воду:
Этот "шалтай-балтай" совсем не похож на эталонный заплыв "в ванной"...
Возникает закономерная задача стабилизации видео. И тут я упираюсь в проблему ограничения производительности Raspberry Pi. Алгоритмы обработки изображений требуют ресурсов, а запаса у меня уже нет. Поэтому, я решил сделать "финт ушами" и вместо полноценной стабилизации попробовать детектировать линию горизонта и стабилизировать картинку по ней. В дальнейшем, я могу брать углы крена с гироскопа катера и заменить программную стабилизацию на аппаратную, только положение горизонта будет определять не визуальная картинка, а гироскоп.
Что дальше...
Когда я взялся за решение проблемы обхода препятствий, то не знал, что мне предстоит решить сразу несколько задач:
Стабилизация изображения
Обнаружение абстрактных препятствий
"Трекинг" обнаруженных препятствий
Буду рад прочитать ваши комментарии. Обязательно напишите, если хотите увидеть продолжение статей про беспилотный катер.