С момента последней статьи прошел почти год. Спасибо читателям за комментарии, они здорово помогли, отдельная благодарность @Meklonза идею с фильтрами и в целом за участие в дискуссии. Сама эта идея за весь период времени из головы благополучно вылетела, но видимо не совсем. :) Об этом чуть позже.
Произошло немало событий, времени на мое хобби с автономным катером нашлось откровенно мало. :/
Но идея обнаружения абстрактных препятствий не давала мне покоя. Постоянно казалось, что до результата рукой подать.
Аппаратная часть.
Цены уползли вверх и теперь я не могу позволить легкомысленно утопить аппаратуру катера. Как я рассуждал раньше: "Ну что там Raspberry Pi и несколько датчиков. Всегда можно взять новую "малинку", восстановить образ из бэкапа и продолжить испытания."
Сейчас же ситуация обратная. Если потеряю катер со всей электроникой, то дальше решать задачу, скорее всего, смогу только теоретически, на листочке в клеточку.
Поэтому, я спроектировал и распечатал на 3d принтере новый герметичный корпус с аккумуляторным отсеком.
![Герметичный бокс для электронной начинки. Герметичный бокс для электронной начинки.](https://habrastorage.org/getpro/habr/upload_files/0bb/7ac/8fe/0bb7ac8fedd92f3011be57f988dafd84.jpeg)
Штатный бокс демонтировал, в него уже ничего не помещается. Заодно обслужил вал гребного винта. Все новые технологические отверстия тщательно загерметизировал.
![Начало сборки новой конфигурации катера. Начало сборки новой конфигурации катера.](https://habrastorage.org/getpro/habr/upload_files/37a/327/8ff/37a3278ff18572fd6596516879b459f7.png)
Трудно не заметить - на катере появилась камера на мачте. Этому есть объяснение: чем выше точка обзора, тем раньше мы сможем увидеть препятствие, а значит у нас будет больше времени для принятия решения. Другими словами - мы отодвигаем границу "видимого горизонта".
![Картинка из Википедии. Картинка из Википедии.](https://habrastorage.org/getpro/habr/upload_files/2ee/5d2/f0a/2ee5d2f0a877af65fbbaa6fb9f553a1e.png)
После сборки получаем новую компоновку:
![Катер с новой компоновкой. Катер с новой компоновкой.](https://habrastorage.org/getpro/habr/upload_files/ea4/d9a/431/ea4d9a4312bd9a7453d76fdaf964bd45.jpg)
Но плотная компоновка тут же подкинула проблему с охлаждением. В замкнутом пространстве микрокомпьютер и регулятор оборотов двигателя превращают крышку отсека в утюг.
Чтобы снизить температуру, необходимо повысить производительность водяного охлаждения, оно тут предусмотрено штатно. Проектирую и печатаю новый водозаборник который будет крепиться на дейдвудную трубку вала.
![Сравните размеры штатного водозаборника и нового пластикового. Сравните размеры штатного водозаборника и нового пластикового.](https://habrastorage.org/getpro/habr/upload_files/e3c/82d/b27/e3c82db27714b01d3194f8d477f15247.jpeg)
Программная часть - самое простое! ...или нет?
Уже потираю руки - аппаратура надежно защищена, алгоритм давно придуман и проверен!
Меня напрягало пользоваться окошком терминала для запуска программы автопилота и контроля параметров беспилотника. А раз добавили камеру - логично набросать веб-интерфейс, чтобы следить за испытаниями в реальном времени.
![Слева - было, справа - стало. Слева - было, справа - стало.](https://habrastorage.org/getpro/habr/upload_files/39a/eee/434/39aeee4348272f0cb3792632b78ed5c7.jpg)
Включаем, понеслось...
Это просто ад какой-то!
Абсолютно неожиданно: в воде, в хорошую погоду, могут отражаться облака, деревья или любые другие объекты над водой. А еще, алгоритм поиска граней неплохо обнаруживает рябь и волны на поверхности. Все это накладывается друг на друга и превращается в одно хаотичное пятно. Алгоритм адаптивный, при увеличении числа помех я понижаю порог чувствительности и катер просто перестает видеть материальные препятствия на пути.
Вот тут я знатно подвис, я ставил себе задачу обнаружения препятствий и планировал отправить автономный катер в большое путешествие, но не смог даже отплыть от берега - вся зеркальная поверхность воды превратилась в сплошные препятствия!
Вывод: ничего не получилось! ...или нет?
Я продел немалую работу: спроектировал и собрал техничку, провел тюнинг игрушечного катера, допилил ПО и все для того, чтобы столкнуться с фундаментальной проблемой - отражения на воде.
Для алгоритма нет никакой разницы какие данные он получает с камеры, он тем и отличается от интеллекта человека, что ему все равно какой объект находится в воде: пакет или облако, отражение дерева или утонувшее бревно, птица в небе или водоросль в толще воды... Что, напомню, совсем не похоже на заплыв в идеальных условиях:
![Так я видел работу автопилота изначально. Так я видел работу автопилота изначально.](https://habrastorage.org/getpro/habr/upload_files/d4d/f13/8e3/d4df138e36a650f21e6f88576a4ae848.jpg)
Ну не получилось и не получилось, не может отличить и что ж теперь? В лепешку расшибиться?! Зато я весело провел время!
На этом могла бы закончиться статья про Epic Fail в обнаружении препятствий с помощью камеры, если бы я сел ее писать сразу после полученных результатов. Но рука не поднялась. Я просто убрал катер на дальнюю полку и забыл на некоторое время.
Но осознание неудачи не давало покоя, нет-нет, да появлялась мысль: а вдруг есть другие варианты решения задачи. И когда ощущение фиаско притупилось, я понемногу стал возвращаться к обдумыванию той самой задачи, как же обнаружить (чтоб их!!!) абстрактные препятствия, не прибегая к ресурсоемким нейорсетям.
С чистого листа.
Немного отдохнув, я решил отказаться от идеи искать объекты по граням. Скорее всего для моей задачи это тупик. Нужны были новые идеи и я стал разбираться в различных методах фильтрации изображений. Опыт подсказывал, что задача не решается из-за отсутствия необходимых знаний. Почитав и поразмыслив, в голову пришла идея применить некоторые полезные фильтры, которые могли бы подтолкнуть к правильному решению.
Интуитивно, я понимал, что отражения на воде имеют какие-то особенности, которые могут позволить отфильтровать их из общего окружения.
У меня уже накопилось достаточно видеоматериала с испытаний, чтобы эмпирически попытаться получить удовлетворительный результат.
Во время изысканий, настоящим откровением стал "фильтр Собеля". Метод находит градиент каждого пикселя (или заданной области пикселей). Причем направление градиента можно выбирать. Нашел я его во время опытов и только потом узнал, что он используется как простейший метод нахождения края объекта.
![Пример фильтра Собеля из Википедии Пример фильтра Собеля из Википедии](https://habrastorage.org/getpro/habr/upload_files/609/650/df4/609650df40f1f109f4eb7a66bd337811.png)
В моем случае этот фильтр дает поляризационный эффект. Обратите внимание, что отражение облаков и рябь на воде эффективно отфильтровываются, а небольшой лист на воде светится яркой точкой. Повышаем контрастность и данные с камеры превращаются в подобие радара который "видит" материальные объекты на нашем пути.
Сравнение старого и нового метода обнаружения препятствий:
Данный метод показал хорошие результаты и в более сложных условиях. Там где алгоритм Canny Edges попросту сходит с ума и видит практически непрерывное препятствие, фильтр Собеля успешно отстраивается от большинства помех.
![Canny Edges слева, Sobel справа Canny Edges слева, Sobel справа](https://habrastorage.org/getpro/habr/upload_files/dfe/6d7/967/dfe6d7967388fb232b0a7839b4f1cf4c.jpg)
А как на практике?
На практике остается посчитать весовые коэффициенты для набора возможных траекторий и встроить новый метод в программу пилотирования катера.
Погонял автопилот на других видео и убедился, что алгоритм отлично справляется с нашей задачей.
"Пока суть да дело - лето пролетело."
Лезть в холодную р.Волгу уже не так охота как при +30°, а значит снова придется ждать лета! Остается надеяться, что сюрпризов больше не будет и я смогу представить вам полный обзор самостоятельного путешествия катера с автопилотом и компьютерным зрением на Raspberry Pi.
Спасибо, что прочитали статью!