DIY автономный дрон с управлением через интернет. Часть 2 про ПО
Это продолжение повествования об автономном дроне. В первой части говорилось про hardware, в этой речь пойдет про software. Для начала небольшой ликбез про взаимодействие оператора с коптером. Вот типичная схема у большинства самосборных дронов:
А вот схема у продвинутых дронов:
Так работают игрушечные дроны, которые управляются со смартфона:
Управлять дроном через интернет можно так (при наличии сим-карты со статическим IP-адресом):
Или так, если IP-адрес динамический:
Для надежности и резервирования каналов связи последний вариант можно развить до такого состояния:
Далее я буду описывать процесс настройки полетного контроллера Emlid Navio 2 и микрокомпьютера Raspberry Pi 3.
Но, с небольшими модификациями, эти настройки подойдут для любого полетного контроллера, с которым можно общаться по протоколу MAVLink в связке с любым компьютером на ОС семейства Linux.
Важно! Настройку необходимо делать с отключенным питанием на регуляторах оборотов, чтобы случайно не запустились двигатели.
ПО для управления дроном на ПК и планшетах
Для управления БПЛА используются специальные программы GCS (Ground Control Station). Далее по тексту я буду использовать эту аббревиатуру. Мне по душе пришлась QGroundControl, мультиплатформенная (Windows, Linux, MacOS, iOS, Android) GCS с открытым исходным кодом, которая стала частью проекта DroneCode. Но есть и альтернативы, бесплатные и коммерческие: APM Planner, MissionPlanner, UgCS, LibrePilot, OpenPilot, Tower (DroidPlanner) для Android, MAVPilot (iOS), SidePilot (iOS). А также консольная MAVProxy.
Установка образа ОС на SD-карту
Для нормальной работы автопилота крайне рекомендуется использовать «быстрые» SD-карты (класс 10). Медленные карты памяти не успевают сохранять логи автопилота даже на небольшой частоте, в результате чего они получаются кривыми или вообще не пишутся. Свидетельством этого может быть ошибка »No IO heartbeat», которую можно наблюдать в консоли MAVLink (как смотреть консоль MAVLink описано ниже). При покупке смотрите на возможность писать 4К видео: скорее всего это будет быстрая SD. К сожалению, я об этом узнал после падения дрона, когда нужно было проанализировать логи и узнать причину. Логи оказались нечитаемы для нескольких GCS. Причина отключения моторов в полете оказалась банальна: я забыл подправить в настройках значение минимального напряжения на аккумуляторе для срабатывания failsafe.
Итак, скачиваем готовый образ Raspbian Stretch с предустановленными Ardupilot и ROS от Emlid со страницы оригинальной инструкции. И пишем его на карту памяти с помощью Etcher или любой подобной программы.
Чтобы сразу после включения Raspberry соединялся с вашей WiFi сетью, необходимо отредактировать файл wpa_supplicant.conf в корне SD-карты. В нем должны быть такие строки:
network={
ssid="название_wifi_сети"
psk="пароль_wifi_сети"
}
Можно настроить и без WiFi, подключив одноплатник к роутеру Ethernet-кабелем. Теперь вынимаем SD-карту из ПК, вставляем ее в Raspberry и включаем питание. Через полминуты он должен появиться в админке роутера на странице подключенных устройств (хостнейм navio).
Обновление дистрибутива и установка необходимых пакетов
Открываем SSH-клиент и соединяемся с Raspberry (локальный IP-адрес navio вместо RASPBERRY_IP_ADDRESS):
ssh pi@RASPBERRY_IP_ADDRESS
Стандартный пароль: raspberry. В первую очередь необходимо расширить файловую систему ОС на весь объем SD-карты:
sudo raspi-config --expand-rootfs
и перегрузиться:
sudo reboot
После перезагрузки, соединяемся еще раз и обновляем дистрибутив:
sudo apt-get update && sudo apt-get dist-upgrade -y
Устанавливаем дополнительные пакеты:
sudo apt-get install autoconf automake libtool pkg-config libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libraspberrypi-dev gstreamer1.0-tools gstreamer1.0-plugins-good gstreamer1.0-plugins-bad
и компилируем обертку gst-rpicamsrc для gstreamer и родной камеры Raspicam:
git clone https://github.com/thaytan/gst-rpicamsrc.git rpicamsrc
cd rpicamsrc
chmod +x autogen.sh
./autogen.sh --prefix=/usr --libdir=/usr/lib/arm-linux-gnueabihf/
make
sudo make install
Проверим работает ли камера (создается видеофайл test.h264):
gst-launch-1.0 rpicamsrc bitrate=1000000 ! filesink location=test.h264
Если gstreamer запустился, подождите пару секунд, чтобы записалось видео. Прервать процесс можно клавишами Ctrl+C. Если видео есть, значит камера работает.
Настройка и запуск Ardupilot
Релизы новых версий Ardupilot немного запаздывают в сборке от Emlid. Если необходимый функционал доступен в самой последней версии, то установить ее из исходников можно по этой инструкции.
Разработчики Navio добавили в свою сборку простую и удобную утилиту Emlid tool для проверки датчиков и настройки Ardupilot. Сначала проверим, видит ли Raspberry контроллер Navio:
emlidtool info
Если в ответ на эту команду выдает что-то вроде:
Vendor: Emlid Limited
Product: Navio 2
Issue: Emlid 2018-06-05 831f3b08594f2da17dccae980a2e3659115ef71f
Kernel: 4.14.34-emlid-v7+
RCIO firmware: 0xcaec2284
значит видит. Проверим состояние датчиков (покажет список и состояние):
emlidtool test
и драйвера ШИМ-контроллера в ядре Linux:
cat /sys/kernel/rcio/status/alive
0 = не работает, 1 = работает.
Прошивка ШИМ-контроллера обновляется так:
sudo emlidtool rcio update
Теперь настроим Ardupilot:
sudo emlidtool ardupilot
В терминале откроется текстовый GUI с пошаговыми менюшками. Выбираем copter последней версии, тип arducopter, автозапуск при включении (On boot: enable), старт после настройки (Ardupilot: start).
Выходим через пункт меню Quit.
Проверим запустился ли Ardupilot:
sudo systemctl status arducopter
Обратите внимание, файл запуска в systemd называется arducopter, так как настроен был вариант copter.
Теперь нужно настроить Ardupilot так, чтобы он отправлял нам телеметрию. Для этого отредактируем файл конфигурации:
sudo nano /etc/default/arducopter
В нем должны быть такие строки:
TELEM1="-A udp:127.0.0.1:14550"
ARDUPILOT_OPTS="$TELEM1"
Сохраняем файл (Ctrl+X, затем Y) и перезапускаем Ardupilot:
sudo systemctl daemon-reload
sudo systemctl restart arducopter
Проверить состояние процесса Ardupilot можно такой командой:
sudo systemctl status arducopter
С такими настройками Ardupilot будет транслировать телеметрию (пакеты MAVLink) в локальный UDP-порт 14550. Далее, скрипт MAVProxy (описание ниже) будет забирать оттуда телеметрию и передавать в GCS или скрипт, а также отправлять в обратном направлении пакеты с командами.
Вместо локального адреса и порта можно записать IP-адрес ПК или планшета в локальной сети и пакеты будут транслироваться сразу туда.
Однако, такой подход оправдан, если данные телеметрии больше нигде не используются и у устройства с GCS статический IP адрес. Иначе каждый раз в настройках Ardupilot придется прописывать новый. Чтобы общаться с автопилотом по TCP могли одновременно несколько GCS с динамическими адресами и еще какие-нибудь скрипты на самом бортовом компьютере, удобнее использовать MAVProxy.
Этот скрипт (написан на Python) может получать пакеты MAVLink на локальный UDP-адрес и ретранслировать их на несколько локальных или удаленных IP-адресов как по UDP, так и по TCP. Пакеты передаются в обоих направлениях Ardupilot ⇔ GCS. Кроме того, MAVProxy представляет из себя полноценную GCS, но с текстовым интерфейсом.
MAVProxy
MAVProxy уже установлен в образе Navio. Его также можно установить и на ПК (Windows, Linux, MacOS) для дальнейшего общения с автопилотом в консольном режиме.
Убедившись, что Ardupilot работает, запустим на Raspberry скрипт MAVProxy такой командой:
mavproxy.py --master=udp:127.0.0.1:14550
Параметр --master=udp:127.0.0.1:14550 задает для скрипта источник данных. Это локальный UDP-порт, который был прописан в файле конфигурации Ardupilot. После запуска команды, MAVProxy соединиться с этим портом и выведет на экран сообщения автопилота, примерно как у меня:
pi@navio:~ $ mavproxy.py --master=udp:127.0.0.1:14550
Connect udp:127.0.0.1:14550 source_system=255
Failed to load module: No module named adsb. Use 'set moddebug 3' in the MAVProxy console to enable traceback
Log Directory:
Telemetry log: mav.tlog
Waiting for heartbeat from 127.0.0.1:14550
MAV> online system 1
STABILIZE> Mode STABILIZE
fence breach
GPS lock at 0 meters
APM: APM:Copter V3.5.5 (88a1ecdd)
APM: Frame: UNKNOWN
APM: PreArm: RC Roll not configured
APM: PreArm: Compass not calibrated
APM: PreArm: 3D Accel calibration needed
APM: PreArm: check firmware or FRAME_CLASS
APM: PreArm: Throttle below Failsafe
Так как автопилот еще не откалиброван и до конца не настроен, то об этом красноречиво говорят и сообщения. В этом режиме можно общаться с автопилотом посредством команд. Если бы дрон был полностью настроен, то вот такая последовательность двух команд привела бы к старту двигателей и взлету дрона на высоту 20 м:
arm throttle
takeoff 20
Не откалиброванный автопилот не полетит, а покажет сообщения с причинами, почему он этого сделать не сможет.
Установка связи с дроном в локальной сети
Остановим скрипт (Ctrl+C) и снова запустим его в таком виде:
mavproxy.py --master=udp:127.0.0.1:14550 --out=tcpin:0.0.0.0:5762
С дополнительным параметром --out=tcpin:0.0.0.0:5762 MAVProxy будет слушать порт 5762 на входящие TCP соединения от GCS. Как только GCS соединиться, пакеты с данными начнут перемещаться между дроном и GCS. Попробуем подключиться с ПК:
Если подключение удалось, то GCS покажет кучу сообщений с требованием откалибровать датчики и загрузит бортовые параметры с их текущими значениями:
Калибровка датчиков и настройка параметров автопилота
Калибровку автопилота можно сделать почти в любой GCS. В документации Ardupilot она описана во всех подробностях. Прежде всего устанавливаем тип рамы. У меня стандартная 4-х моторная компоновка, поэтому это Quad X.
Первый полет лучше все же сделать в ручном режиме. Подключаем и калибруем радиоуправление (приемник и передатчик).
Осталось откалибровать акселерометр и компас.
Для того, чтобы Ardupilot видел и учитывал данные с внешних датчиков, установим необходимые параметры:
Для PX4Flow (калибровка самого датчика и обновление прошивки)
FLOW_ENABLE = 1 (Enabled)
FLOW_ADDR = 0 (0 = вариант для стандартного адреса 0х42)
Для лазерного высотомера VL53L0X (инструкция)
RNGFND_TYPE = 16 (VL53L0X)
RNGFND_ORIENT = 25 (ориентация дальномера вниз)
RNGFND_ADDR = 41 (I2C-адрес в десятичном виде). Адрес датчика по-умолчанию 0x29, что в десятичном виде = 41.
RNGFND_SCALING = 1
RNGFND_MIN_CM = 5
RNGFND_MAX_CM = 120
RNGFND_GNDCLEAR = 15 (расстояние от датчика до поверхности, когда дрон стоит на земле)
Для IRLock (подробная инструкция, wiki IR-Lock)
PLND_ENABLED = 1
PLND_TYPE = 2
PLND_BUS = 1
Для сонара переднего обзора (инструкция)
RNGFND2_TYPE = 2 (MaxbotixI2C sonar)
RNGFND2_ORIENT = 0 (ориентация дальномера вперед)
RNGFND2_MAX_CM = 700 (макс дальность в сантиметрах)
Полный список параметров Ardupilot.
Теперь перезапускаем Ardupilot из меню GCS, снова соединяемся с бортом и открываем окошко MAVLink Inspector, чтобы увидеть данные с датчиков.
К сожалению, показания IR-Lock тут не видны, для анализа его работы придется взглянуть на бортовые логи. Как это сделать описано здесь.
Осталось настроить параметры безопасности и можно запускать дрон:
Как настроить гироподвес и управление основной камерой в деталях я напишу в одной из следующих статей, основные моменты изложены здесь.
Видеотрансляция
Проверим как работает видеотрансляция в сети WiFi. Такой командой можно запустить видео в TCP-порт на Raspberry с использованием родной утилиты raspivid для камеры Raspicam:
raspivid -t 0 -hf -fps 25 -w 640 -h 480 -o - | gst-launch-1.0 fdsrc ! h264parse ! rtph264pay config-interval=1 pt=96 ! gdppay ! tcpserversink host=0.0.0.0 port=5001
А вот такой командой делается тоже самое, только с использованием ранее скомпилированной обертки rpi-camsrc для gstreamer:
gst-launch-1.0 rpicamsrc sensor-mode=4 ! h264parse ! rtph264pay config-interval=1 pt=96 ! gdppay ! tcpserversink host=0.0.0.0 port=5001
В обоих случаях, трансляция в формате h264 доступна по IP-адресу Raspberry на порту 5001.
Посмотреть ее можно запустив на своем ПК такую команду (должен быть установлен gstreamer), вместо RPI_ADDRESS указываем адрес Raspberry в сети:
gst-launch-1.0 -v tcpclientsrc host=RPI_ADDRESS port=5001 ! gdpdepay ! rtph264depay ! avdec_h264 ! videoconvert ! autovideosink sync=false
В результате должно открыться окошко с видео.
Практически в любую GCS встроен видеоплеер, который может показывать RTSP-видеопоток. Чтобы сделать из Raspberry RTSP-сервер можно использовать консольный плеер VLC. Установка:
sudo apt-get install vlc
Видеотрансляция запускается так:
raspivid -o - -t 0 -n -w 320 -h 240 -fps 25 | cvlc -vvv stream:///dev/stdin --sout '#rtp{sdp=rtsp://:8554/live}' :demux=h264
Видео доступно по адресу (вместо RPI_ADDRESS, адрес Raspberry):
rtsp://RPI_ADDRESS:8554/live
Настройка GCS:
Адрес потока можно использовать для подключения нескольких плееров на разных устройствах, но, так как видеозахват и трансляция для Raspberry весьма трудоемкий процесс, то для нескольких потребителей видео лучше использовать внешний сервер (описание ниже).
Телеметрия через интернет
Чтобы GCS могла подключиться через интернет к дрону с динамическим IP-адресом, необходим промежуточный сервер со статическим IP, на котором будет запущен скрипт MAVProxy. Для этих целей я воспользовался арендой облачного сервера у одного из известных провайдеров. Для MAVProxy подойдет самая минимальная конфигурация, но так как у меня этот же сервер будет заниматься ретрансляцией видео, то я выбрал вариант с чуть большей памятью (одно ядро и 1Гб памяти, Ubuntu 18.04). Для минимальной задержки в прохождении данных между бортом и GCS, сервер должен располагаться в максимальной географической близости к дрону и GCS.
Устанавливаем MAVProxy на сервер. Сначала зависимости:
sudo apt-get install python-dev python-opencv python-wxgtk3.0 python-pip python-matplotlib python-pygame python-lxml python-yaml
а потом и сам скрипт через PIP:
sudo pip install MAVProxy
пропишем путь:
echo "export PATH=$PATH:$HOME/.local/bin" >> ~/.bashrc
и запустим скрипт с такими параметрами:
mavproxy.py --master=udp:0.0.0.0:15001 --out=tcpin:0.0.0.0:15002
MAVProxy слушает порт 15001 на входящие пакеты телеметрии от дрона по протоколу UDP, а порт 15002 на входящее TCP-соединение от GCS.
Запустим MAVProxy на Raspberry еще с одним параметром, чтобы телеметрия транслировалась еще и на сервер (вместо SERVER_IP адрес своего сервера):
mavproxy.py --master=udp:127.0.0.1:14550 --out=tcpin:0.0.0.0:5762 --out=udpout:SERVER_IP:15001
После старта скрипта на бортовом компьютере, в консоли сервера появятся сообщения от автопилота. Как уже говорилось выше, MAVProxy представляет из себя полноценную GCS с текстовым интерфейсом и в таком состоянии уже можно редактировать параметры и управлять дроном посредством команд в консоли сервера.
Подключим GCS на ПК или планшете к серверу. Настройки соединения такие же как и для локальной сети, только вместо IP-адреса Raspberry указываем адрес сервера и порт 15002.
Теперь можно подключить 4G USB-модем к Raspberry и оценить с какой задержкой реагирует авиагоризонт на экране.
Видео через интернет
Для ретрансляции видео установим на сервер VLC плеер:
sudo apt-get install vlc
После установки, запустим его как ретранслятор c UDP порта 5001 в RTSP канал SERVER_IP:8554/live:
cvlc -vvv udp://@:5001 --sout '#rtp{sdp=rtsp://:8554/live}' :demux=h264
На борту запустим видеотрансляцию с камеры на сервер по UDP (вместо SERVER_IP адрес сервера):
gst-launch-1.0 rpicamsrc bitrate=1000000 ! video/x-h264,width=640,height=480,framerate=25/1 ! h264parse ! udpsink host=SERVER_IP port=5001
Адрес потока теперь можно использовать как источник видео в настройках GCS или открыть в любом плеере, поддерживающим этот протокол.
Теперь можно спланировать маршрут полета и запустить дрон через интернет, предварительно его включив, например, с помощью помощника по телефону.
Очевидно, что из-за относительно большого времени путешествия видео и телеметрии по сети, такой способ вряд ли подойдет для FPV-полетов в ручном режиме между препятствиями.
Темы для последующих публикаций:
- Варианты автоматической зарядки дрона в своем скворечнике и на каком из них остановился я.
- Реализация web-based GCS с помощью MAVProxy, NodeJS, socket.io и медиасервера для управления несколькими дронами одновременно.
- Резервные каналы связи и системы спасения дронов
- Машинное зрение и лидары для избежания столкновения с препятствиями
Продолжение следует…