Разбираемся в MAVLink. Часть 1 |
||
МЕНЮ Искусственный интеллект Поиск Регистрация на сайте Помощь проекту ТЕМЫ Новости ИИ Искусственный интеллект Разработка ИИГолосовой помощник Городские сумасшедшие ИИ в медицине ИИ проекты Искусственные нейросети Слежка за людьми Угроза ИИ ИИ теория Внедрение ИИКомпьютерные науки Машинное обуч. (Ошибки) Машинное обучение Машинный перевод Реализация ИИ Реализация нейросетей Создание беспилотных авто Трезво про ИИ Философия ИИ Big data Работа разума и сознаниеМодель мозгаРобототехника, БПЛАТрансгуманизмОбработка текстаТеория эволюцииДополненная реальностьЖелезоКиберугрозыНаучный мирИТ индустрияРазработка ПОТеория информацииМатематикаЦифровая экономика
Генетические алгоритмы Капсульные нейросети Основы нейронных сетей Распознавание лиц Распознавание образов Распознавание речи Техническое зрение Чат-боты Авторизация |
2016-10-11 23:10
Для обмена данными многие современные дроны, собираемые энтузиастами, коммерческие или даже промышленные, используют протокол MAVLink. Я бы хотел поделиться своим опытом работы с этим протоколом в этой, а может и в последующих статьях.
MAVLink или Micro Air Vehicle Link - это протокол информационного взаимодействия с дронами или малыми беспилотными аппаратами (летающими, плавающими, ползающими и т.д), далее по тексту называемых MAV (Micro Air Vehicle). MAVLink распространяется под LGPL лицензией в виде модуля для python (есть удобная обёртка DroneKit) и генератора header-only С/C++ библиотеки. Есть так же репозитории уже сгенерированных библиотек для MAVLink версии v1 (этой мы и будем пользоваться) и версии v2. Протокол описывает информационное взаимодействие между системами, такими как MAV и GCS(Ground control station) - станция наземного управления, а так же их составными частями - компонентами. Базовой сущностью MAVLink является пакет, имеющий следующий формат: Первый байт пакета (STX) - это символ начала сообщения: 0xFD для версии v2.0, 0xFE для версии v1.0, 0x55 для версии v0.9. LEN - длинна полезной нагрузки (сообщения). SEQ - содержит счётчик пакета (0-255), который поможет нам выявить потерю сообщения. SYS (System ID) - идентификатор отправляющий системы, а COMP (Component ID) - идентификатор отправляющего компонента. MSG (Message ID) - тип сообщения, от него зависит, какие данные будут лежать в полезной нагрузки пакета. PAYLOAD - полезная нагрузка пакета, сообщение, размером от 0 до 255 байт. Два последних байта пакета - CKA и CKB, нижний и верхний байт, соответственно, содержат контрольную сумму пакета. Библиотека MAVLink позволяет кодировать и раскодировать пакеты согласно протоколу, но она не регламентирует, какими аппаратными и программными средствами данные будет отправлены - это могут быть TCP/UDP сообщения, обмен через последовательный порт, да что угодно, что обеспечивает двухсторонний обмен. Библиотека обрабатывает входные данные побайтово, добавляя их в буфер и сама собирает из них пакет. Каждая система или компонент, может одновременно обмениваться данными по разным источникам, тогда для каждого источника назначается специальный идентификатор, называемый channel (канал). MAVLink содержит буфер на каждый канал. Получаем heartbeat с борта Перейдём от теории к практике и попробуем написать ООП-обёртку поверх MAVLink. Ниже, я буду приводить примеры кода на C++ с использованием Qt. Я выбрал этот инструмент, во-первых, потому, что в будущем планирую визуализировать некоторые параметры MAVLink с использованием Qt Quick и Qt Location, а во-вторых, многие решения я подсмотрел в проекте qgroundcontrol, так же написанного на Qt. Для начала, введём абстракцию над каналом связи, пусть это будет класс AbstractLink, в его интерфейсе определим функциональность, позволяющую нам получать и отправлять данные в виде QByteArray. Наследники этого класса, UdpLink и SerialLink, обеспечат нам передачу данных по сети и через последовательный порт. Интерфейс класса AbstractLink
Прямую работу с протоколом MAVLink инкапсулируем в класс MavLinkCommunicator. В его обязанности будет входить получение данных по каналам связи и декодирование их в пакеты mavlink_message_t, а так же отправка сообщений по каналам связи. Так как, для каждого канала связи MAVLink содержит свой буфер, мы введём словарь указателя на канал связи к идентификатору канала. Интерфейс класса MavLinkCommunicator
Рассмотрим, как осуществляется сборка пакета из потока данных. Как было сказано выше, MAVLink читает входящий поток данных побайтово, для этого используется функция mavlink_parse_char, которая возвращает данные сообщения или NULL, если сообщение не может быть получено, сохраняя полученный символ во внутренний буфер. MAVLink содержит буфер для каждого канала. Такой подход позволяет передавать данные с последовательного порта напрямую в функцию разбора пакета MAVLink, лишая пользователя библиотеки удовольствия вручную собирать сообщения из потока. Метод сборки пакета класса MavLinkCommunicator
Для получения полезных данных одной только сборки пакета мало. Необходимо получить из пакета сообщение, извлечь полезную нагрузку согласно идентификатору msgid. MAVLink имеет набор встроенных типов, под каждый msgid (тип сообщения) и функции получения этих сообщений из пакета. Введём ещё один абстрактный тип - AbstractHandler, в интерфейсе этого класса определим чисто виртуальный слот processMessage для обработки сообщения, полученного от MavLinkCommunicator'а. Наследники класса AbstractHandler будут решать, могут ли они обработать то или иное сообщение и, по-возможности, обрабатывать. К примеру, мы хотим обрабатывать сообщения типа heartbeat. Этот самый базовый пакет, в котором система говорит, что она существуют, и что оно такое. Стоит заметить, что heartbeat - это единственный тип пакета, который MAVLink обязывает к использованию. Введём обработчик сообщений этого типа - HeartbeatHandler. Реализация метода processMessage класса HeartbeatHandler
Теперь, если мы настроем классы и установим правильно связь, то сможем получать heartbeat сообщения от полётного контроллера. Я воспользуюсь парой радио модемов и Raspberry Pi с шилдом NAVIO2, на котором запущен автопилот APM. Теоретически, это должно работать с любым автопилотом, поддерживающим текущую версию MAVLink, но если у Вас нет ничего под рукой, чуть дальше будет пример с имитатором автопилота. код функции main
Запускаем программу, включаем автопилот и через несколько секунд должно побежать:
Отправляем свой heartbeat По задумке, каждая система должна отправлять heartbeat, следовательно, и наша тоже. Начнём с реализации функции отправки пакета класса MavLinkCommunicator. Функция mavlink_msg_to_send_buffer записывает пакет message в буфер для отправки. Предполагается, что на этом этапе все поля пакета, включая длину и контрольную сумму, заполнены корректно. Метод отправки пакета класса MavLinkCommunicator
Теперь, когда у нас есть функция отправки пакета, нам остаётся сформировать сообщение и записать его в пакет. Поручим эту задачу уже существующему классу HeartbeatHandler, а в интерфейс AbstractHandler добавим сигнал отправки сообщения. Функция mavlink_msg_heartbeat_encode записывает сообщение heartbeat в пакет, подобные функции есть для всех встроенных сообщений. Обращу внимание читателя, что в mavlink предусмотрены и дополнительные функции, например mavlink_msg_heartbeat_pack позволяет записать сообщение heartbeat в mavlink_message_t без явного создания объекта типа mavlink_heartbeat_t, а mavlink_msg_heartbeat_send сразу отправляет данные, при наличии определённой функции отправки. Подробнее, как работать с этими функциями, можно ознакомиться по ссылке. Дополнительное окончание _chan (к примеру mavlink_msg_heartbeat_pack_chan) указывает по какому каналу сообщение будет отправлено. Код события timerEvent класса HeartbeatHandler
Отправлять heartbeat мы будем по таймеру с частотой 1 Гц. Если поставить отладочный вывод в методе отправки данных канала связи data.toHex(), увидим наши сообщения, согласно приведённой в начале статьи картинке. Каждый такт счётчик должен увеличиваться, а контрольная сумма соответственно меняться.
Для того, чтобы проверить работает ли наш heartbeat, создадим две цели сборки: gcs - имитатор станции наземного управления и uav - имитатор беспилотника. код функции main gcs
код функции main uav
Результатом должен стать двухсторонний обмен пакетами heartbeat. При желании можно экспериментировать дальше: добавить ещё одну систему или канал связи. Полный исходный код этого примера можно найти на гитхабе. Надеюсь, было интересно, хоть первая часть и вышла довольно простой. В следующей статье я постараюсь рассказать про другие типы сообщений и что интересного с ними можно делать. Благодарю за внимание! Интересные ссылки: Официальный сайт MAVLink Сайт проекта Dronecode Туториал на английском с сайта DIY Drones Источник: habrahabr.ru Комментарии: |
|