Введение

Моя первая статья на Хабре, не судите строго, надеюсь содержание будет как минимум интересным!

По профессии я программист, занимаюсь мобильными разработками, но меня всегда тянуло к "железу". Приятно творить магию с помощью кода, но еще приятнее когда результатом твоих трудов является некоторое конечное устройство.

Не так давно, ко мне в руки, попала модель радиоуправляемого катера Avanti от производителя Thunder Tiger, сердцем которого является мощный бесколлекторный двигатель Ripper OBL 29/19 с водяным охлаждением. Производитель обещает скорость до 60 км/ч! Быстро наигравшись, как в далеком детстве, полез смотреть на начинку игрушки.

Thunder Tiger Avanti
Thunder Tiger Avanti

Устройство предельно простое для любого, кто сталкивался с RC моделями:

  • трансивер на 2,4 ГГц

  • блок управления двигателем (регулятор оборотов)

  • сервомашинка для управления рулем

  • отсек для LiPo аккумулятора

Первое, что пришло в голову: подключить вместо трансивера - микрокомпьютер Raspberry Pi. Пусть катер получит зачатки интеллекта и самостоятельно отправится в плавание!

Вот что получилось. Хорошо, что Raspberry Pi не занимает много места.
Вот что получилось. Хорошо, что 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)


  1. Meklon
    06.01.2022 10:50
    +2

    Я вижу тут очень неприятную фундаментальную проблему. Большинство препятствий вроде водорослей и пакетов имеют те же HSL характеристики цвета, что и вода. Условно, пучок водорослей особо не отличается ничем от зеленоватой воды.

    По сути, у нас два пути — пытаться выделить объект в Lightness канале или в Hue. Второй даст неплохой эффект для пакетов и всякого яркого мусора. А вот с зеленоватыми корягами непонятно что делать.

    В инфракрасном спектре не пробовал смотреть? Может быть существенная разница в поглощении поверхностью, что даст нужный контраст.


    1. vba
      06.01.2022 11:43
      -1

      Наверное эта проблема может быть решена в купе с использованием мини эхолота.


      1. tolianT Автор
        06.01.2022 12:36

        Думал об этом, но увидит ли эхолот пакет на поверхности воды? На данном этапе актуально обнаружить видимые глазу препятствия. Скрытые препятствия это уже отдельная тема.


        1. vba
          06.01.2022 12:58

          Да, пакет на поверхности, не факт, но мне кажется, если подкрутить чувствительность, то заросли травы должны быть видны при колебании воды. А как дела обстоят с использованием лазерного луча или ультразвука на поверхности воды?


          1. tolianT Автор
            06.01.2022 13:04

            "Островок" растительности хорошо различим визуально, по опыту испытаний могу сказать.

            Лазерные и ультразвуковые дальномеры первое что пришло мне в голову, я же не собирался влазить во все эти проблемы технического зрения. Но не забывайте, мы на воде, а катер постоянно раскачивает на волнах. Ультразвук и лазер будут отражаться от волн на воде.


    1. cepera_ang
      06.01.2022 12:26

      От нейронок никуда не деться рано или поздно, а чтобы работали на распбери — воткнуть какой-нибудь мовидиус.


      1. tolianT Автор
        06.01.2022 12:56

        Вы не забывайте, что вопрос автономности тоже важен для дрона. У нас только одной проблемы нет в случае с беспилотным катером - отвод тепла. :)


        1. cepera_ang
          06.01.2022 13:50
          +1

          Neural Compute Stick 2 — полтора ватта, вряд ли это значимый процент от того, что движок потребляет. А учитывая, что распбери сама может жрать до 15 ватт, то глядишь снизив на неё загрузку после переноса на акселератор, ещё и меньше общий пакет окажется :)


          1. tolianT Автор
            06.01.2022 21:36

            Спасибо! Изучу сей девайс.


          1. praeivis
            07.01.2022 11:57

            Полтора вата, но цена 100$ - для таких проектов дороговато.


            1. cepera_ang
              07.01.2022 12:11

              А распбери сколько стоит? :)


              1. tolianT Автор
                07.01.2022 16:33

                RaspberryPi 4 model B брал за 40$ на али. Но это было до ванханалии с ценами.


                1. cepera_ang
                  07.01.2022 16:37

                  Плюс флешка, плюс корпус какой-никакой, плюс питание, та же сотня и набежит :) А с учётом вакханалии вообще боюсь смотреть.


                  А мовидиус на маузере 79 долларов. То есть я не что-то такое заоблачное предложил :)


                  1. tolianT Автор
                    07.01.2022 20:40

                    Нет, не заоблачно.

                    Если он может взять на себя задачу по обнаружению препятствий, то смысл есть.

                    Я даже думал вторую малинку воткнуть при необходимости.


    1. tolianT Автор
      06.01.2022 12:33

      Возможно, вас могло ввести в заблуждение видео с камеры GoPro. Она установлена слишком низко, на самом корпусе катера. Я планирую подключить камеру к самой Raspberry Pi и установить значительно выше, что "отодвинет" горизонт и даст возможность замечать препятствия намного раньше, а заодно уменьшить число помех от водяных капель.

      Мне нравится ваша идея задействовать инфракрасный спектр, что может быть особенно полезно в сумерках. Пока же, хочу обнаруживать препятствия в видимом диапазоне: если препятствие видит человек, то должен увидеть катер.

      Отдельно спасибо за ваш развернутый комментарий на мою первую статью!


      1. Meklon
        06.01.2022 12:48

        Можно попробовать использовать узкополосный инфракрасный фильтр, который отсекает видимый спектр. Сюда же добавить мощный инфракрасный прожектор в импульсном режиме.

        В итоге, камера в видимом спектре и камера в ИК, которая дёргает кадры с низким фреймрейтом синхронно со вспышками прожектора. Это даст экономию энергии.


        1. tolianT Автор
          06.01.2022 12:54

          Согласен, что это расширет возможности по обнаружению препятствий. Дальность правда будет ограничена: объекты за сотни метров от катера он не добьет.

          И задачи по обработке кадров, детектирования препятствий и трекинга так же остаются у нас актуальными.


      1. DMITRY20210921
        09.01.2022 09:13

        А может быть над катером будет летать дрон. Он будет лучше видеть панораму. Разведчик.


        1. tolianT Автор
          09.01.2022 09:21

          Конечно, крупные препятствия он увидит раньше. Но сразу снижается автономность, отказоустойчивость всего комплекса в сумме, чувствительность к погодным условиям(дождь, ветер)...

          На катер можно поставить солнечные панели, с квадракоптером это проблема.

          Катер может отплывать на значительные расстояния: десятки километров. Квадрокоптер привязан к оператору и дальности приёма сигнала.

          У меня есть ссылка на видео в начале статьи, снимал ракурсы с квадрика как раз. У катера был значительный запас хода, а квадрик уже терял сигнал.


  1. RubliovG
    06.01.2022 10:50
    +3

    Безумно интересно узнать о дальнейших развития этого проекта.


    1. tolianT Автор
      06.01.2022 12:39

      Спасибо вам за поддержку. Мне самому интересно посмотреть к чему это приведет, потому как времени потрачено немало и бросать это уже неспортивно.


  1. Meklon
    06.01.2022 12:52
    +1

    Нашёл статью, которая может быть актуальна.
    www.sciencedirect.com/science/article/pii/S1350449519300465

    image


    1. tolianT Автор
      06.01.2022 13:09

      Спасибо. Нормальная такая статья. Тоже обратите внимание, с чб изображением работают.

      Само по себе определение препятствий у меня уже работает. Отдельно был вопрос оптимизации, алгоритм должен быть шустрым.

      Тоже читал разные статьи. Вот по определению линии горизонта только 3-4 солидных таких же видел. На практике они не сработали. При одном ракурсе камеры есть горизонт, на другом уже не видит.


      1. Meklon
        06.01.2022 15:49

        Горизонт лучше всё-таки копеечным акселерометром отслеживать. Возможно даже тремя для возможности выбраковки сбойного датчика, если от этого существенно зависит безопасность функционирования.


        1. tolianT Автор
          06.01.2022 21:11

          Все верно, именно так и будет.

          Но пока катер стоит "на приколе" нужно с чем-то работать. Пока горизонт получаю из визуальной картинки. Кстати, это отдельная интересная задачка. Все найденные мной алгоритмы, лажали с определением. :/ не хочу хвастаться, у меня уверенно определяет горизонт даже в условиях водных брызг и частичной видимости.


  1. tur007
    06.01.2022 14:53
    +1

    Спасибо, очень интересно. Нельзя ли посмотреть исходный код?


    1. tolianT Автор
      06.01.2022 21:21

      Спасибо за поддержку! :)

      Вас интересует код детектирования препятствий, стабилизации видео или как происходит трекинг обнаруженных объектов?

      Все это часть одного проекта беспилотного катера. Код планирую публиковать когда проведу испытания на "открытой воде" и буду уверен, что все работает как надо.


      1. tur007
        06.01.2022 21:30

        Вам спасибо;) Конечно, хотелось бы увидеть весь код, но трекинг препятствий, наверное, наиболее интересен. С удовольствием посмотрел бы и черновик кода, не стесняйтесь:)


  1. Un_ka
    06.01.2022 19:28

    Про производительность:

    Какое расширение видео использовали?

    Какую модель Raspberry pi?

    Если собирали библиотеку сами, то можно было при сборке включить использование openMP — библиотеку распараллеливания.

    Попробуйте написать на C++. Там использование функций и классов openCV почти такое же, но есть возможность скомпилировать с максимальной оптимизацией.


    1. tolianT Автор
      06.01.2022 21:24

      Видео у меня пока - это фрагменты записи с GoPro в формате mp4

      Малинка: Raspberry Pi 4 Model B с 4 Гб

      За подсказки благодарю! :)


  1. usa_habro_user
    07.01.2022 00:44

    Очень любопытная разработка, и интересная статья! Хотелось бы узнать немного о том, как вы тестировали свой код управления на воде: ведь такая игрушка баксов под $500, думаю, стоит, если что - жалко потерять. Видимо, есть и обычная "моторка" под боком, на всякий случай?

    Касательно же детектирования препятствий при помощи RPi, то, мне кажется, что на RPi не получится: не та производительность, да и алгоритмы нужны уж больно хитрые. Притом, полузатопленное бревно или водоросли под самой поверхностью и человеческий глаз далеко не всегда сможет своевременно заметить, да еще и на таких скоростях.

    Думаю, что более надежным решением будут чисто "аппаратные" модификации: винт посадить в импеллер и/или окружить сеткой - скорость, конечно, упадет, но, полагаю, незначительно. А для обнаружения препятствий по ходу - использовать простой контактный датчик, усилие на который передается через длинный (1 - 1.5 м) и легкий углепластиковый штырь-"щуп", вынесенный на нос лодки, и подключенный к программируемой логике, или просто к самому RPi. Думаю, для начала и одного хватит - для экстренной остановки в случае препятствия. Если к нему добавить пружину, то можно будет подбирать чувствительность подобного "emergency stop" (ну, чтобы не реагировал на мелкие ветки). Опять-таки, если использовать тонкий, но прочный материал, то сопротивления он практически не добавит, зато надежность будет высокой.


    1. tolianT Автор
      07.01.2022 16:57

      Благодарю! Не думал, что такая специфичная область заинтересует столько людей. Хотя вот меня затянула чуть больше чем полностью. :)

      Если интересно, именно по запуску катера, можете посмотреть мой же видео отчет: https://m.youtube.com/watch?v=5ZUPO3FEQQ0

      Это не реклама, канал без монетизации, чисто любительский. В конце видео есть подбивка: около 300$ весь проект. При том, что вы можете снять Raspberry Pi и у вас снова будет та же самая игрушка из магазина.

      Тоже были сомнения, получится ли детектировать препятствия. Но... пока получается. :) Raspberry Pi 4 достаточно мощный девайс, а библиотека OpenCV неплохо оптимизирована.

      Но в любом случае, или все получится, или провалится. И я напишу по какой причине не получилось. :)


      1. usa_habro_user
        08.01.2022 07:13

        Не люблю, если честно, видеблоги, предпочитаю прочесть, но посмотрел, спасибо. Ну, а область DIY не такая уж специфичная; вдобавок, несущийся по волнам катер намного интереснее набивших оскомину радиуправляемых машинок, которые тут "всплывают" с досадной регулярностью. Плюс - такая challanging задача, real time распознавание на такой скорости, да еще и на "малинке".

        Моими советами, кстати, не пренебрегайте: они просты в реализации, и вполне могут служить дополнением к продвинутой системе распознавания препятствий.

        P.S. Подкину вам еще идейку (если, конечно, вы - рыбак, и в вашем озере водятся щуки и окуни): прикрепите к корме короткую удочку с сенсором натяжения (tension sensor), а к ней на леске блесну-"попплер". Как RPi обнаружит, что натяжение сильно возрастет, нужно резко увеличить обороты ненадолго (подсечка), а потом автоматически буксировать добычу к берегу ;)


        1. tolianT Автор
          08.01.2022 10:23
          +1

          Солидарен с вами, читать удобнее. Так уж получилось, что сначала это была просто rc игрушка, потом подключил raspberry только из любопытства: разобраться с управлением. Камеру поставил, опять же из любопытства, посмотреть "глазами" капитана этого судна. :) дальше решил научиться монтировать видео, чтобы оставить его себе на память.

          Писать статью про запуск катера с raspberry мне показалось неуместным, именно потому, что, как вы пишите, роботомашинки набили всем оскомину. Полностью поддерживаю.

          А вот детектирование абстрактных объектов на пути и их отслеживание, та тема по которой мало материала или вообще отсутствует. И так появилась эта дебютная статья. Вдруг в этом сезоне получится реализовать задумку и не потерять катер.

          Советами не пренебрегаю, за все идеи читателям благодарен! Значит не зря писал. А все комментарии мотивируют довести дело до конца, появилась ответственность перед вами.


  1. 71rmn
    07.01.2022 12:33
    +1

    Есть подозрение что ИИ не нужен. Ведь задача обходить ВСЕ препятствия, а не определить какие из них опасные.
    По идее достаточно отделить «шум» на поверхности воды и трекать его.
    Интересно как в итоге вы решите задачу.


    1. tolianT Автор
      07.01.2022 16:36

      Вы все верно поняли.

      Я не использую нейронные сети для определения объекта. В воде может быть что угодно, хоть коряга похожая на лысого лешего. Задача не столкнуться с ним, а деликатно обойти и вернуться на маршрут. Спасибо, что внимательно прочитали. :)


  1. kulikovDenis
    07.01.2022 15:46

    В список задач нужно еще один пункт добавить, коррекцию сферических искажений. а то горизонт дугой изгибается, рано или поздно этот фактор начнет критически влияеть на результат.
    Вот попалась статья, наглядно показывает о чем речь.
    https://habr.com/ru/post/341160/


    1. tolianT Автор
      07.01.2022 16:38

      Это видео с GoPro. Она в широком формате даёт эффект "рыбьего глаза". Пока не уверен мешает он мне или можно пренебречь. Скоро узнаем, надеюсь!


  1. MShevchenko
    07.01.2022 15:59
    +1

    Горизонт я бы искал с помощью преобразования Хафа. По факту гироскопы дают дрейф. Результаты с них можно объединить.

    Для всего что ниже горизонта можно сделать нормализацию. Возможно нелинейную.

    Определение мусора. Пробегаемся граф-сегментатором. Например таким

    https://www.cc.gatech.edu/cpl/projects/videosegmentation/

    Граф-сегментаторы очень хорошо реагируют на трешхолд.

    Пробуем определить вектор движения сегмента и его размер. Или используем более сложные ии классификаторы.

    Что бы не гонять классификатор на каждом фрейме используем оптимизацию на подобее описаной в моем патенте https://patents.google.com/patent/US9002056B2 но с учётом того что мы движемся в 3D пространстве.

    Если не хватает производительности, смело уменьшайте разрешение для тяжёлых участков. Вплоть до 320х240. На такой скорости фреймрейт важне.


    1. tolianT Автор
      07.01.2022 16:45
      +1

      Спасибо. Дайте время изучить.

      Пока могу сказать по предварительным результатам:

      1. фрейм рейт действительно важен

      2. камеру необходимо поднять выше над корпусом судна, чтобы раньше замечать препятствия и отстроиться от волн( в плоскости горизонта они мешают сильнее, чем если смотрим на волную поверхность сверху).

      1. Классификаторов у меня нет, я ищу абстрактные препятствия. Просто любой объект, больше некоторого предела "опасности" что ли...


  1. DmitriiR
    08.01.2022 06:51
    +1

    В камере за оббъективом должен стоять ИК фильтр.

    Можно его снять (если он не на метрице конечно) и открыть совсем иные картинки.

    Кстати было Красим беззеркалку в инфракрасный цвет / Хабр (habr.com)


    1. tolianT Автор
      08.01.2022 10:29

      Спасибо за идею!

      В первой версии будет стоять самая обычная камера для raspberry pi:

      Не совсем понял как за объективом поставить? Или с такой не получится?


      1. DmitriiR
        08.01.2022 17:04

        Фильтр между объективом и матрицей.

        Поковыряйте.. )