3 сентября 2012 года, прочитав на сайте Habrahabr новость о соревнованиях летающих роботов, мы поняли – вот оно, дождались! К тому моменту мы уже несколько месяцев думали о том, что пора переводить свой многолетний интерес к робототехнике в профессиональное русло, и искали для этого повод.
Поэтому вопросов об участии не возникало – начались обсуждения. Сразу же решили использовать готовый дрон, сосредоточившись на программном обеспечении. На первый взгляд, условия казались простыми, поэтому иллюзий, что мы сможем победить, не было – команд много, приз всего один. Решили, что будем использовать только камеру, продемонстрировав, таким образом, свою компетентность в области компьютерного зрения.
Забегая вперед, хочется отдельно отметить высокий уровень организации соревнований. Такого в России еще не было. Мы рады, что приняли участие в этом мероприятии и рады, что смогли победить.
Практически все датчики врут: лидар дорог, не видит объема и при этом слепнет в ясную погоду, сонары мешают друг другу и ловят непонятные отражения, ИК-дальномеры и Kinect работают лишь на близких расстояниях.
Полет по датчикам возможен только для узких, можно сказать, лабораторных задач. Кроме того, почти у всех существующих датчиков есть ограничения по радиусу действия.
Камера в этом плане универсальна. По весу и энергопотреблению она сравнима с сонарами, по скорости работы — с лидарами. По дальности и разрешению у камер нет конкурентов. Практически вся живая природа использует оптику, и почему бы и нам было не остановиться на этом решении. Конечно, для работы с камерой нужны эффективные алгоритмы, но именно этим мы и занимаемся в области своих профессиональных интересов.
Вначале для подготовки к соревнованиям свободного времени практически не было – все участники команды работали в разных местах. Встречались для обсуждений или в кафе, или у кого-нибудь дома. Так как у нас уже был опыт работы с наземными роботами, решили тренироваться на них. На Pololu 3Pi поставили камеру, модуль связи, на ватман налепили черную изоленту (позже приклеили полосы черной бумаги) в виде макета полигона, напечатали уменьшенные копии маркеров и начали писать алгоритмы.



Так незаметно подкралось время прохождения первой контрольной точки. По условиям соревнований, нам надо было прислать видеоролик-презентацию команды. Ролик решили снять на фоне Свято-Троицкой Сергиевой Лавры – главной достопримечательности Сергиева Посада. Собрались утром, перед работой (мы работали по-прежнему в разных местах). Температура: -20. Расцвет. Сугробы. С третьего дубля что-то сняли. Посмотрели – посмеялись, но переснимать не стали – решили порадовать и остальных.
Какова же была наша радость, когда мы получили от организаторов соревнования письмо, пусть и содержащее всего одну строчку: «Ваши материалы приняты!».
На этой контрольной точке организаторы выкладывали ролики по мере получения, и мы были в первой-второй десятке. Судя по всему, наш незамысловатый сюжет понравился другим участникам соревнований – пара команд в своих роликах явно нас пародировала.
Посмотрев все — а это более 8 часов! — ролики других участников, мы пришли к выводу, что многие не отдают себе отчета в сложности задачи и не имеют понимания, что и как они будут делать. Следующие контрольные точки это подтвердили – из 237 участников, прошедших КТ-1, после КТ-2 осталось 204 (для ее прохождения необходимо было просто прислать подтверждение, что участник продолжает участие в соревновании), а после третьей — всего 72 (тут уже надо было показать действующего и управляемого автоматически дрона).
Эксперименты с наземным роботом доказали принципиальную возможность выполнить задание только по камере, но необходимо было переходить к полетам.
На этом этапе мы уже располагали квадрокоптером Parrot Ar.Drone 2.0 и успели немного полетать им. Следующим шагом нам необходимо было заняться непосредственно выполнением полетного задания. Было очевидно, что если мы не будем распознавать кресты (маркеры взлета-посадки), на соревнованиях нам делать будет нечего.
Выбрав C# как основной язык разработки и вооружившись готовой библиотекой взаимодействия с Ar.Drone (написанной нашим соотечественником Русланом Баланухиным), мы приступили к разработке системы автоматического управления.
На первом этапе мы поставили перед собой задачу просто висеть над крестом. То есть дрон должен был взлететь, по нижней камере определить крест и зависнуть над его центром, противодействуя воздушным потокам, сносящим его в сторону.
Мы заказали у рекламщиков уменьшенные копии маркеров (диаметром 1 м). Положили один крест в центре комнаты 4х4 м. А дальше начались первые прозрения:
Все это было для нас как ушат холодной воды…
Отказавшись на этом этапе от выделения линий, мы начали распознавать кресты по контуру. Через пару недель «танцев с бубнами» мы добились точности распознавания на уровне 70-80% в любое время дня и при любом освещении, тем самым выполнив поставленную задачу – дрон взлетал и зависал над крестом. Уже на этом этапе мы поняли, что нельзя доверяться одному распознаванию – надо усреднять результат нескольких распознаваний.

На этой картинке красный кружок – центр креста, а желтый – проекция центра дрона.
В это время (за месяц до третьей контрольной точки) нас пригласили принять участие в Весенних Соревнованиях Роботов, организованных Питерским Физико-Математическим Лицеем №239. Одной из дисциплин на них были соревнования летающих роботов по регламенту RobotChallenge «Воздушные гонки».
Такой хороший шанс получить дополнительный опыт полетов и пообщаться с другими пилотами мы не могли упустить. Но времени на подготовку не было, пришлось импровизировать.
Цель соревнований — пролететь как можно больше правильных восьмерок за 10 минут. Согласно регламенту, в качестве помощи в навигации на полу была начерчена пунктирная линия. После некоторых раздумий мы решили использовать наш опыт висения над крестом. Только вместо координаты центра креста передавать в модуль управления дроном верхнюю видимую точку пунктира. В результате, дрон, как мул за морковкой, пытался зависнуть над этой точкой, а мы подсовывали ему следующую.
У нас было всего четыре часа времени на отладку на реальном полигоне накануне соревнований, но решение оказалось не только изящным, но и плодотворным – мы налетали пять кругов, получив приз за второе место.
На этих соревнованиях нас ждал очередной сюрприз – проблемы со связью. Из отведенных 10 минут на попытку мы больше половины времени потратили на установление связи с дроном — он терял ее в процессе полета, сбивался с маршрута. Приходилось его останавливать и начинать выполнение задания заново. В процессе общения с другими участниками выяснилось, что это стандартная проблема дронов Parrot.
Ролик, снятый на этих соревнованиях, мы использовали для прохождения КТ-3.
Вернувшись домой, мы приступили к следующему этапу – полетам между маркерами. После питерских соревнований стало ясно, что необходимо как можно больше летать на реальные расстояния в реальных условиях.
Мы договорились об использовании школьного спортзала на время летних каникул. Напечатали кресты в натуральную величину и опять были удивлены – по нижней камере определить большой крест невозможно, целиком его в нижнюю камеру просто не видно.
В очередной раз пришлось менять концепцию — мы вернулись к определению крестов по линиям. Алгоритм был следующим – сначала получаем все линии, потом начинаем объединять рваные и фильтровать их по контрастности, местоположению (кресты на потолке и стенах нам не нужны), отсекая все лишнее. После этого находим перекрестия и уже по ним пытаемся понять, похоже ли это на настоящие маркеры. То есть фильтруем, фильтруем и еще раз фильтруем. Это ужасно прожорливо по ресурсам, но зато достаточно надежно.
Исходное изображение:

Найденные линии:

Фильтр по контрастности:

Объединяем рваные линии:

Все пересечения:

Фильтр не похожих на крест:

Результат:

Пришло время последней контрольной точки. По условиям соревнований, мы обязаны были пройти ее на полигоне организатора.
На пробный полет мы записались одними из первых. По приезде в КРОК нас ждал очередной сюрприз – к проблемам со связью добавился ветер. Наш дрон банально сдувало, а алгоритма противодействия порывам ветра у нас на тот момент не было. В результате, из двадцати попыток нам удалось выполнить задание КТ-4 только три раза. Спасибо организаторам, что они зачли нам эту попытку. Мы прошли КТ-4 первыми.
В попытках настроить алгоритм противодействия ветру мы в очередной раз столкнулись с проблемой связи. Проводя испытания на улице в ветреную погоду, мы чуть не разбили наш дрон, потеряв связь с ним.
Надо было что-то делать. Как мы уже знали, плохая связь — это общая проблема дронов Parrot. Поэтому мы воспользовались уже найденным до нас способом ее решения — установкой внешней антенны. Внешняя антенна и роутер позволили нам считать вопрос связи закрытым. Как позже выяснилось, многие команды с этой проблемой столкнулись только на соревнованиях.
За три нед��ли до финала организаторы окончательно утвердили полигон. Всем участникам давалась возможность дважды посетить его для настройки алгоритмов.
После первого посещения уже готового полигона у нас сложилось ощущение, что мы не выполним задание. У нас возникло три проблемы:
Попытка пролететь по лабиринту на ручном управлении по камере привела к столкновению со стеной и крушению. Вторая попытка привела к такому же результату.
Все, что мы сделали в первый приезд, – поснимали полигон в разное время — когда солнце было за облаками и не давало лишних теней и, наоборот – при ярком солнце и контрастных тенях.
За оставшуюся неделю мы доработали определение коридора, использовав подход «vanishing point».
Приехав во второй раз, за три дня до соревнований, нам удалось автоматически пролететь коридор в одну сторону, однако проблема посадки и взлета оставалась нерешенной.
У нас оставалось два дня. При этом было непонятно, как повторить условия порывистого ветра, чтобы выяснить, победили ли мы его?
В качестве способа борьбы с ветром мы использовали активное противодействие внешним воздействиям при посадке – стараясь удерживать углы крена, тангажа и рысканья. А взлет решили делать винтом – одновременно набирая высоту и разворачиваясь.
Отлаживали в спортзале, создавая порывы ветра с помощью листа ДВП. Выглядело все это довольно комично.
23-го августа в 21:30, вернувшись из спортзала, мы подняли бокалы за то, что достойно прошли все этапы соревнования – теперь мы знали, что выполним задание. Точнее, что мы имеем хороший шанс его выполнить — Его Величество Случай никто не отменял.
Мы научились летать в коридоре, не сталкиваясь со стенами. Мы хорошо распознавали кресты в любую погоду. Оба креста (думаю, участники меня поймут). Проблемы связи и ветра также были решены.
Единственное, что мы не успели – это автоматический выбор направления маршрута. Для определения поворотов мы использовали правило правой/левой руки, которое переключали после каждой посадки. И это чуть не сыграло с нами злую шутку.
Уперевшись в стенку препятствия на обратном пути при выполнении полета, мы развернулись по правилу правой руки и полетели на уже посещенный маркер. После посадки мы переключились на левую руку. Долетев до последнего поворота, опять развернулись и снова полетели обратно. И только после третьей посадки опять включилось правило правой руки, и мы благополучно вернулись.
Мы понимали, что 6 мин 45 с, полученные нами в первой попытке, — проигрышное время — достаточно кому-либо просто выполнить задание. При этом правило правой/левой руки мы отменить не могли, и была вероятность, что дрон опять собьется и начнет кружить. Тогда на второй попытке мы решили «лететь на все деньги» и подняли скорость дрона в полтора раза. Но, к сожалению, забыли изменить параметр снижения скорости, зависящий от расстояния до препятствия, и не успели вовремя затормозить, окончательно остановившись об стену.
Для нас действительно было неожиданным, что больше никто не сможет пройти дистанцию. Полтора дня мы ждали, что вот-вот кто-то пролетит быстрее нас (у дрона организаторов было лучшее время, но они участвовали в соревнованиях вне зачета), и мы сможем уже расслабиться и отдохнуть, искренне желая успеха другим участникам. Но удача была капризна, и в этот раз она оказалась на нашей стороне.
Ниже запись полета со стороны дрона. Скорость распознавания была неравномерной, поэтому время на ролике не совпадает с реальностью.
Поэтому вопросов об участии не возникало – начались обсуждения. Сразу же решили использовать готовый дрон, сосредоточившись на программном обеспечении. На первый взгляд, условия казались простыми, поэтому иллюзий, что мы сможем победить, не было – команд много, приз всего один. Решили, что будем использовать только камеру, продемонстрировав, таким образом, свою компетентность в области компьютерного зрения.
Забегая вперед, хочется отдельно отметить высокий уровень организации соревнований. Такого в России еще не было. Мы рады, что приняли участие в этом мероприятии и рады, что смогли победить.
Почему камера?
Практически все датчики врут: лидар дорог, не видит объема и при этом слепнет в ясную погоду, сонары мешают друг другу и ловят непонятные отражения, ИК-дальномеры и Kinect работают лишь на близких расстояниях.
Полет по датчикам возможен только для узких, можно сказать, лабораторных задач. Кроме того, почти у всех существующих датчиков есть ограничения по радиусу действия.
Камера в этом плане универсальна. По весу и энергопотреблению она сравнима с сонарами, по скорости работы — с лидарами. По дальности и разрешению у камер нет конкурентов. Практически вся живая природа использует оптику, и почему бы и нам было не остановиться на этом решении. Конечно, для работы с камерой нужны эффективные алгоритмы, но именно этим мы и занимаемся в области своих профессиональных интересов.
Рожденные ползать
Вначале для подготовки к соревнованиям свободного времени практически не было – все участники команды работали в разных местах. Встречались для обсуждений или в кафе, или у кого-нибудь дома. Так как у нас уже был опыт работы с наземными роботами, решили тренироваться на них. На Pololu 3Pi поставили камеру, модуль связи, на ватман налепили черную изоленту (позже приклеили полосы черной бумаги) в виде макета полигона, напечатали уменьшенные копии маркеров и начали писать алгоритмы.



Трое из ларца
Так незаметно подкралось время прохождения первой контрольной точки. По условиям соревнований, нам надо было прислать видеоролик-презентацию команды. Ролик решили снять на фоне Свято-Троицкой Сергиевой Лавры – главной достопримечательности Сергиева Посада. Собрались утром, перед работой (мы работали по-прежнему в разных местах). Температура: -20. Расцвет. Сугробы. С третьего дубля что-то сняли. Посмотрели – посмеялись, но переснимать не стали – решили порадовать и остальных.
Какова же была наша радость, когда мы получили от организаторов соревнования письмо, пусть и содержащее всего одну строчку: «Ваши материалы приняты!».
На этой контрольной точке организаторы выкладывали ролики по мере получения, и мы были в первой-второй десятке. Судя по всему, наш незамысловатый сюжет понравился другим участникам соревнований – пара команд в своих роликах явно нас пародировала.
Посмотрев все — а это более 8 часов! — ролики других участников, мы пришли к выводу, что многие не отдают себе отчета в сложности задачи и не имеют понимания, что и как они будут делать. Следующие контрольные точки это подтвердили – из 237 участников, прошедших КТ-1, после КТ-2 осталось 204 (для ее прохождения необходимо было просто прислать подтверждение, что участник продолжает участие в соревновании), а после третьей — всего 72 (тут уже надо было показать действующего и управляемого автоматически дрона).
Эксперименты с наземным роботом доказали принципиальную возможность выполнить задание только по камере, но необходимо было переходить к полетам.
Как удивителен мир
На этом этапе мы уже располагали квадрокоптером Parrot Ar.Drone 2.0 и успели немного полетать им. Следующим шагом нам необходимо было заняться непосредственно выполнением полетного задания. Было очевидно, что если мы не будем распознавать кресты (маркеры взлета-посадки), на соревнованиях нам делать будет нечего.
Выбрав C# как основной язык разработки и вооружившись готовой библиотекой взаимодействия с Ar.Drone (написанной нашим соотечественником Русланом Баланухиным), мы приступили к разработке системы автоматического управления.
На первом этапе мы поставили перед собой задачу просто висеть над крестом. То есть дрон должен был взлететь, по нижней камере определить крест и зависнуть над его центром, противодействуя воздушным потокам, сносящим его в сторону.
Мы заказали у рекламщиков уменьшенные копии маркеров (диаметром 1 м). Положили один крест в центре комнаты 4х4 м. А дальше начались первые прозрения:
- Оказывается, крестов-то вокруг нас много!
- Оказывается, белое и черное — понятия относительные!
- Оказывается, стандартные алгоритмы выделения линий OpenCV находят линии даже там, где мы и подумать не могли!
- Оказывается, с камеры приходят битые кадры!
Все это было для нас как ушат холодной воды…
Отказавшись на этом этапе от выделения линий, мы начали распознавать кресты по контуру. Через пару недель «танцев с бубнами» мы добились точности распознавания на уровне 70-80% в любое время дня и при любом освещении, тем самым выполнив поставленную задачу – дрон взлетал и зависал над крестом. Уже на этом этапе мы поняли, что нельзя доверяться одному распознаванию – надо усреднять результат нескольких распознаваний.

На этой картинке красный кружок – центр креста, а желтый – проекция центра дрона.
Морковка для дрона
В это время (за месяц до третьей контрольной точки) нас пригласили принять участие в Весенних Соревнованиях Роботов, организованных Питерским Физико-Математическим Лицеем №239. Одной из дисциплин на них были соревнования летающих роботов по регламенту RobotChallenge «Воздушные гонки».
Такой хороший шанс получить дополнительный опыт полетов и пообщаться с другими пилотами мы не могли упустить. Но времени на подготовку не было, пришлось импровизировать.
Цель соревнований — пролететь как можно больше правильных восьмерок за 10 минут. Согласно регламенту, в качестве помощи в навигации на полу была начерчена пунктирная линия. После некоторых раздумий мы решили использовать наш опыт висения над крестом. Только вместо координаты центра креста передавать в модуль управления дроном верхнюю видимую точку пунктира. В результате, дрон, как мул за морковкой, пытался зависнуть над этой точкой, а мы подсовывали ему следующую.
У нас было всего четыре часа времени на отладку на реальном полигоне накануне соревнований, но решение оказалось не только изящным, но и плодотворным – мы налетали пять кругов, получив приз за второе место.
На этих соревнованиях нас ждал очередной сюрприз – проблемы со связью. Из отведенных 10 минут на попытку мы больше половины времени потратили на установление связи с дроном — он терял ее в процессе полета, сбивался с маршрута. Приходилось его останавливать и начинать выполнение задания заново. В процессе общения с другими участниками выяснилось, что это стандартная проблема дронов Parrot.
Ролик, снятый на этих соревнованиях, мы использовали для прохождения КТ-3.
Фильтруй, и все получится
Вернувшись домой, мы приступили к следующему этапу – полетам между маркерами. После питерских соревнований стало ясно, что необходимо как можно больше летать на реальные расстояния в реальных условиях.
Мы договорились об использовании школьного спортзала на время летних каникул. Напечатали кресты в натуральную величину и опять были удивлены – по нижней камере определить большой крест невозможно, целиком его в нижнюю камеру просто не видно.
В очередной раз пришлось менять концепцию — мы вернулись к определению крестов по линиям. Алгоритм был следующим – сначала получаем все линии, потом начинаем объединять рваные и фильтровать их по контрастности, местоположению (кресты на потолке и стенах нам не нужны), отсекая все лишнее. После этого находим перекрестия и уже по ним пытаемся понять, похоже ли это на настоящие маркеры. То есть фильтруем, фильтруем и еще раз фильтруем. Это ужасно прожорливо по ресурсам, но зато достаточно надежно.
Исходное изображение:

Найденные линии:

Фильтр по контрастности:

Объединяем рваные линии:

Все пересечения:

Фильтр не похожих на крест:

Результат:

Взять почту, телефон, телеграф
Пришло время последней контрольной точки. По условиям соревнований, мы обязаны были пройти ее на полигоне организатора.
На пробный полет мы записались одними из первых. По приезде в КРОК нас ждал очередной сюрприз – к проблемам со связью добавился ветер. Наш дрон банально сдувало, а алгоритма противодействия порывам ветра у нас на тот момент не было. В результате, из двадцати попыток нам удалось выполнить задание КТ-4 только три раза. Спасибо организаторам, что они зачли нам эту попытку. Мы прошли КТ-4 первыми.
В попытках настроить алгоритм противодействия ветру мы в очередной раз столкнулись с проблемой связи. Проводя испытания на улице в ветреную погоду, мы чуть не разбили наш дрон, потеряв связь с ним.
Надо было что-то делать. Как мы уже знали, плохая связь — это общая проблема дронов Parrot. Поэтому мы воспользовались уже найденным до нас способом ее решения — установкой внешней антенны. Внешняя антенна и роутер позволили нам считать вопрос связи закрытым. Как позже выяснилось, многие команды с этой проблемой столкнулись только на соревнованиях.
За три нед��ли до финала организаторы окончательно утвердили полигон. Всем участникам давалась возможность дважды посетить его для настройки алгоритмов.
Опахало для шашлыка
После первого посещения уже готового полигона у нас сложилось ощущение, что мы не выполним задание. У нас возникло три проблемы:
- Определение коридора. Разделительная перегородка была организована с использованием строительных блоков, которые вносили помехи в наш алгоритм определения стенок.
- Посадка в условиях ветра. Операцию посадки мы выполняли, можно сказать, с закрытыми глазами: мы находим крест, выцеливаем его и выполняем посадку (подлетаем на два-три метра и садимся). Однако любой порыв ветра сносит нас в сторону от площадки.
- Взлет и разворот в условиях ветра. Эту операцию мы тоже делали «на автомате» — в результате нас могло бросить ветром на стену (почему-то мы считали, что касаться стен запрещено условиями соревнований).
Попытка пролететь по лабиринту на ручном управлении по камере привела к столкновению со стеной и крушению. Вторая попытка привела к такому же результату.
Все, что мы сделали в первый приезд, – поснимали полигон в разное время — когда солнце было за облаками и не давало лишних теней и, наоборот – при ярком солнце и контрастных тенях.
За оставшуюся неделю мы доработали определение коридора, использовав подход «vanishing point».
Приехав во второй раз, за три дня до соревнований, нам удалось автоматически пролететь коридор в одну сторону, однако проблема посадки и взлета оставалась нерешенной.
У нас оставалось два дня. При этом было непонятно, как повторить условия порывистого ветра, чтобы выяснить, победили ли мы его?
В качестве способа борьбы с ветром мы использовали активное противодействие внешним воздействиям при посадке – стараясь удерживать углы крена, тангажа и рысканья. А взлет решили делать винтом – одновременно набирая высоту и разворачиваясь.
Отлаживали в спортзале, создавая порывы ветра с помощью листа ДВП. Выглядело все это довольно комично.
Я пью до дна...
23-го августа в 21:30, вернувшись из спортзала, мы подняли бокалы за то, что достойно прошли все этапы соревнования – теперь мы знали, что выполним задание. Точнее, что мы имеем хороший шанс его выполнить — Его Величество Случай никто не отменял.
Мы научились летать в коридоре, не сталкиваясь со стенами. Мы хорошо распознавали кресты в любую погоду. Оба креста (думаю, участники меня поймут). Проблемы связи и ветра также были решены.
Единственное, что мы не успели – это автоматический выбор направления маршрута. Для определения поворотов мы использовали правило правой/левой руки, которое переключали после каждой посадки. И это чуть не сыграло с нами злую шутку.
Ёжик в тумане
Уперевшись в стенку препятствия на обратном пути при выполнении полета, мы развернулись по правилу правой руки и полетели на уже посещенный маркер. После посадки мы переключились на левую руку. Долетев до последнего поворота, опять развернулись и снова полетели обратно. И только после третьей посадки опять включилось правило правой руки, и мы благополучно вернулись.
Мы понимали, что 6 мин 45 с, полученные нами в первой попытке, — проигрышное время — достаточно кому-либо просто выполнить задание. При этом правило правой/левой руки мы отменить не могли, и была вероятность, что дрон опять собьется и начнет кружить. Тогда на второй попытке мы решили «лететь на все деньги» и подняли скорость дрона в полтора раза. Но, к сожалению, забыли изменить параметр снижения скорости, зависящий от расстояния до препятствия, и не успели вовремя затормозить, окончательно остановившись об стену.
Для нас действительно было неожиданным, что больше никто не сможет пройти дистанцию. Полтора дня мы ждали, что вот-вот кто-то пролетит быстрее нас (у дрона организаторов было лучшее время, но они участвовали в соревнованиях вне зачета), и мы сможем уже расслабиться и отдохнуть, искренне желая успеха другим участникам. Но удача была капризна, и в этот раз она оказалась на нашей стороне.
Ниже запись полета со стороны дрона. Скорость распознавания была неравномерной, поэтому время на ролике не совпадает с реальностью.