Интеллектуальная система планирования и оптимизации групповых беспилотных авиационных работ для БВС АО «Геоскан»
Разработано для компании АО «Геоскан» в рамках хакатона «Лидеры Цифровой Трансформации 2026».
- Обзор продукта и назначение
- Ключевые фичи и возможности
- Архитектура решения
- Последовательный математический алгоритм
- Сильные стороны и конкурентные преимущества
- Проблемы в процессе разработки и их решения
- Инструкция по развертыванию и запуску (Local & Docker)
- Инструкция по автоматизированному тестированию
- Чек-лист ручного тестирования (Manual QA)
- Продакшн инфраструктура и ссылки
GEOSCAN FleetCommander AI — это программный комплекс корпоративного уровня для автоматизированного планирования, координации и оптимизации аэрофотосъемочных (АФС) и лазерных сканирующих миссий для гетерогенного флота БВС «Геоскан».
- Геоскан 201 — БВС самолетного типа дальнего действия для сверхбольших площадей (размах 2.2 м, крейсерская скорость 21 м/с, время полета до 180 мин, радиус виража 85 м).
- Геоскан 701 — флагманский самолет повышенной автономности для площадной и линейной аэрофотосъемки.
- Геоскан 801 — промышленный мультироторный комплекс высокой грузоподъемности для детальной инспекции и лидаров.
- Геоскан 401 — среднеразмерный мультиротор для геодезических работ и точного земледелия.
- Геоскан 101 — легкий самолет быстрого развертывания.
- Геоскан Gemini — компактный квадрокоптер для оперативного картографирования.
- Sony RX1RM2 (42.4 Мп, фокус 35 мм, полнокадровая геодезическая съемка)
- Sony A6000 (24.3 Мп, фокус 20 мм, APS-C)
- Sony ILX-LR1 (61.0 Мп, сверхвысокое разрешение)
- Лидар AGM-MS3 (лазерное сканирование высокой плотности)
- Мультиспектральная камера RedEdge-P (агромониторинг и NDVI)
- Интерактивная Web-GIS консоль: темная тема с акцентами в стиле Flight Control Center, плавная картография Leaflet, отображение полигонов, зон и рельефных препятствий.
- Поддержка кастомных полигонов: возможность нарисовать произвольный полигон любой формы или загрузить участок из базы (613 кадастровых и лесоустроительных участков).
- Метеомодель и ветроучет: интерактивный селектор ветра (скорость и азимут), корректная индикация навигационного и метеорологического направления.
- 4D-симулятор миссии: интерактивный плеер со шкалой времени (Time Scrubbing), синхронной визуализацией параллельного полета бортов, реалистичным курсовым углом (Heading) и скоростью.
- Реалистичная аварийная траектория: генерация экстренного схода на площадку посадки с соблюдением радиуса виража, плавной глиссады снижения и обхода препятствий.
- Двойной критерий оптимизации:
- Минимизация общего времени (Makespan) — максимальное распараллеливание флота для завершения всей задачи в кратчайший срок.
- Минимизация суммарного налета (Total Flight Time) — экономия ресурса двигателей и аккумуляторов.
- Кроссплатформенный промышленный экспорт:
- QGroundControl
.plan— готовый полетный план с WGS84-координатами, скоростями, высотами и безопасными параметрами. - KML — трехмерные траектории для Google Earth.
- GeoJSON — векторные слои для интеграции с внешними корпоративными ГИС.
- Поддержка одиночной выгрузки и ZIP-архива для группового вылета флота.
- QGroundControl
Решение построено по принципам модульной микросервисной архитектуры с четким разделением слоев:
graph TD
Client[Web-клиент: Leaflet + Vanilla JS] -->|HTTPS / REST API| Nginx[Nginx Reverse Proxy + SSL Let's Encrypt]
Nginx -->|Reverse Proxy :8000| FastAPI[FastAPI Backend Core]
subgraph Backend Core
FastAPI --> Router[API Routers: parcels, airspace, plan-mission, export]
Router --> DataLoader[DataLoader: KML Parser & R-Tree Spatial Index]
Router --> Photogrammetry[Photogrammetry Engine: GSD & Altitude Calculator]
Router --> WindModel[Aerodynamic Wind Vector Triangle Engine]
Router --> Planner[Multi-UAV Path Planner & Fleet Optimizer]
Planner --> Dubins[Dubins Aircraft Kinematics Generator]
Planner --> SafetyValidator[4D Safety & Airspace Zone Validator]
Router --> Exporter[Exporters: QGC .plan, KML, GeoJSON, ZIP]
end
DataLoader --> DataFiles[(Data: 613 Parcels, 341 Zones, 8363 Obstacles)]
-
backend/models.py: Pydantic-модели валидации данных, каталоги ТТХ БВС и полезных нагрузок. -
backend/data_loader.py: высокопроизводительная загрузка KML геометрий, парсер вертикальных эшелонов зон и пространственный индексR-Tree(Shapely STRtree). -
backend/photogrammetry.py: фотограмметрические зависимости (GSD, фокусное расстояние, физический размер пикселя, расчет базы фотографирования$B_x$ и ширины захвата$D_{\text{swath}}$ ). -
backend/wind_math.py: расчет путевой скорости, угла сноса (Crab angle) и поправки энергопотребления от встречно-бокового ветра. -
backend/path_planner.py: ядро алгоритма — нарезка галсов (Boustrophedon), кинематические траектории, динамический срез площади под батарею, многобортовое расписание. -
backend/exporters.py: сериализаторы в стандартные форматы беспилотной авиации.
Весь процесс планирования выполняется строго детерминированно в 9 математических этапов:
По заданному требуемому разрешению на местности (
Исходные координаты полигона pyproj. Это обеспечивает нулевые искажения метрических расстояний при нарезке галсов и расчете площадей.
Вектор ветра
- Полигон поворачивается на угол
$-\alpha$ , приводя галсы к параллели с осью абсцисс. - Проводится семейство секущих прямых с шагом
$D_{\text{swath}}$ . - Вычисляется пересечение прямых с полигоном (
$\text{LineString} \cap \text{Polygon}$ ). При наличии внутренних вырезов (no-fly zones, озера, запретные объекты) линия корректно фрагментируется на валидные отрезки. - Концы отрезков возвращаются обратным поворотом на
$+\alpha$ .
- Для
$N \le 9$ проходов: запускается точное динамическое программирование (Held-Karp algorithm) для задачи TSP с фиксированными концами, находящее абсолютно кратчайший маршрут обхода. - Для
$N > 9$ : применяется жадный алгоритм ближайшего соседа с локальной оптимизацией 2-Opt.
Для самолетов (Геоскан 201 / 701) соединение концов двух соседних галсов под прямым или острым углом физически невозможно.
Минимальный радиус виража определяется предельно допустимым углом крена
Если в миссии задействовано несколько БВС с разным уровнем заряда аккумулятора
- Каждый борт получает допустимый энергетический лимит дальности
$L_i = V_{\text{air}} \cdot T_{\text{max}} \cdot \frac{B_i - B_{\text{reserve}}}{100}$ . - Вместо дисквалификации борта с пониженным зарядом (например, 40%) система производит пропорциональный геометрический срез площади полигона.
- БВС с 40% батареи закрывает ровно ту часть галсов, на которую гарантированно хватает энергии с запасом 20% на возвращение к базе, а оставшуюся часть забирает полностью заряженный напарник.
В точке симуляции отказа:
- Вычисляется текущий вектор скорости и пространственная ориентация БВС.
- По касательной к текущей траектории без недопустимых скачков перегрузки строится дуга выхода в направлении назначенной точки аварийной посадки (или взлетно-посадочной полосы).
- Высота плавно снижается по безопасной глиссаде с учетом высоты препятствий под траекторией снижения.
Каждый построенный сегмент маршрута проходит проверку через R-Tree индекс:
- Препятствия: проверка пересечения с цилиндрическим буфером безопасности
$R_{\text{buf}} = 50\text{ м}$ и высотой препятствия$H_{\text{obs}} + 25\text{ м}$ . - Зоны ограничений: проверка попадания в запретные зоны только в том случае, если диапазон высот зоны
$[H_{\min}, H_{\max}]$ пересекается с эшелоном полета БВС (высотные коридоры FL150+ выше 5000 м автоматически пропускают низколетящий дрон).
| Параметр / Характеристика | Типовые решения конкурентов | GEOSCAN FleetCommander AI |
|---|---|---|
| Кинематика самолета | «Угловатые» развороты по 90°/180°, срезаемые автопилотом | Честные гладкие дуги Дубинса ( |
| Учет ветра | Статический либо отсутствует | Навигационный треугольник скоростей, угол сноса и расчет путевой скорости |
| Учет батареи | Жесткая отбраковка борта при заряде < 60% | Динамический срез площади под доступную емкость аккумулятора |
| Ограничения высот | Слепая блокировка любым полигоном ограничений | 4D-фильтр высот (эшелоны 5-29 км не блокируют полет на 100 м) |
| Оптимизация | Жадный выбор | Двойной критерий (Makespan vs Total Flight Time) + точный DP |
| Экспорт | Только GeoJSON или текст | QGroundControl .plan (WGS84, MAVLink), KML, GeoJSON, ZIP |
| Симуляция | Статическая картинка | Полноценный 4D-плеер с таймлайном, динамическим курсом и скоростью |
- Проблема: Запретная зона UUR215 имеет высотный коридор от FL150 (4 570 м) до FL290 (8 840 м). Исходный парсер считал любое 2D-пересечение с полигоном нарушением, из-за чего дроны, летящие на высоте 100 м над землей, блокировались системой.
- Решение: Реализован строгий вертикальный клиренс в функции
_is_altitude_clear(). Если нижняя граница зоны выше высоты полета дрона более чем на 50 метров, зона признается безопасной для пролета снизу.
- Проблема: При нарезке галсов стандартный переход между соседними проходами давал отрезки под углом 90° и 180°, что на скорости 21 м/с приводит к срыву потока или резкому уходу автопилота с траектории.
- Решение: Интегрирован генератор кривых Дубинса, динамически рассчитывающий точки сопряжения окружностей радиусом 85 м и прямых отрезков сглаживания.
- Проблема: Ранее аварийный сход отображался условной прямой линией в центр полигона.
- Решение: Разработан полноценный расчет аварийной траектории: сход с галса по касательной к текущему вектору, кинематический разворот в створ посадочной площадки и расчет времени снижения.
- Проблема: При установке батареи в 40% алгоритм минимизации времени вообще исключал борт из задачи, перекладывая всю работу на один дрон.
- Решение: Введен алгоритм динамического разделения площади (Dynamic Area Partitioning). Дрону с 40% батареи выделяется ровно столько галсов, сколько он успевает покрыть с учетом резерва энергии на возврат к базе.
- Проблема: Текст направления ветра («Северный») расходился со стрелкой на компасе, так как в метеорологии указывается направление, откуда дует ветер, а в навигации — вектор, куда он дует.
-
Решение: Разделены метеорологический азимут (
$\psi_{\text{meteo}}$ ) и вектор перемещения воздушной массы ($\psi_{\text{nav}} = \psi_{\text{meteo}} \pm 180^\circ$ ).
- Проблема: Браузер Chrome на GitHub Pages блокировал запросы к API с ошибкой
Multiple CORS header 'Access-Control-Allow-Origin', так как Nginx и FastAPI одновременно добавляли этот заголовок. - Решение: Из конфигурации Nginx удалена ручная директива
add_header, а обработка CORS и OPTIONS preflight полностью передана нативномуCORSMiddlewareв FastAPI.
# Клонирование репозитория
git clone https://github.com/whatrushki/drone.git
cd drone
# Сборка и запуск контейнера в фоне
docker compose up -d --build
# Проверка статуса контейнера и healthcheck
docker compose ps
docker compose logs -f# Сборка образа
docker build -t geoscan-fleet-commander .
# Запуск контейнера
docker run -d -p 8000:8000 --name geoscan_app geoscan-fleet-commander
# Проверка работоспособности
curl http://localhost:8000/api/healthПриложение доступно:
- Веб-интерфейс: http://localhost:8000
- Интерактивная документация Swagger: http://localhost:8000/docs
- Python 3.10 – 3.13
- Операционная система: Windows, Linux или macOS
# 1. Создание и активация виртуального окружения
python -m venv venv
# Windows (PowerShell):
.\venv\Scripts\Activate.ps1
# Linux / macOS:
source venv/bin/activate
# 2. Установка зависимостей
pip install --upgrade pip
pip install -r requirements.txt
# 3. Запуск сервера
python run.pyПроект покрыт полным набором модульных и интеграционных тестов с использованием фреймворка pytest.
# Запуск полного набора тестов с подробным выводом
pytest -v
# Запуск с измерением времени выполнения
pytest -v --durations=5-
test_airspace_endpoint_returns_valid_geojson_geometry: проверка валидности структуры зон ограничений по спецификации GeoJSON RFC 7946. -
test_allowed_area_rejects_route_outside_boundary: жесткая отбраковка маршрутов, выходящих за границу разрешенного района полетов. -
test_battery_level_and_emergency_diversion: корректность расчета точки невозврата и построения аварийного маршрута. -
test_fixed_wing_turns_and_emergency_path_smoothness: валидация радиусов виражей кривых Дубинса ($R \ge 85$ м) для самолета Геоскан 201. -
test_group_export_contains_every_drone_plan: проверка целостности экспорта ZIP-архива для группы БВС. -
test_headwind_can_make_a_leg_infeasible: проверка физической невозможности полета при встречном ветре, превышающем$V_{\text{air}}$ . -
test_high_altitude_zone_not_blocking_low_drone: валидация того, что зоны эшелонов FL150+ (5-29 км) не блокируют полет БВС на высоте 80-120 м. -
test_low_battery_drone_utilization_in_makespan: подтверждение того, что дрон с 40% батареи задействуется на пропорциональной части площади. -
test_objectives_compare_complete_routes: проверка корректности разделения критериев Makespan и Total Flight Time. -
test_parcel_index_returns_matching_feature_and_area: корректность геометрии и метрической площади участков по индексу. -
test_qgc_export_params_has_no_null: валидация формата QGroundControl.plan(отсутствиеnull-значений в параметрах MAVLink миссии). -
test_reported_distance_matches_exported_route: равенство заявленной дистанции в API и физической длины экспортируемой полилинии. -
test_same_drone_sensor_jobs_are_sequential: проверка невозможности наложения во времени миссий одного физического борта. -
test_search_compares_available_bases: автоматический выбор наилучшей стартовой площадки из доступных кандидатов. -
test_single_plan_exports_parse: валидность синтаксиса и парсинга одиночных полетных заданий. -
test_small_parcel_has_no_server_crash: стабильность алгоритма на ультрамалых полигонах (отсутствие деления на 0). -
test_small_swath_tour_matches_exhaustive_search: совпадение эвристического обхода с полным перебором на малом числе галсов. -
test_time_limit_is_hard_constraint: строгое соблюдение лимита времени выполнения миссии. -
test_unsafe_obstacle_is_rejected: гарантированная отбраковка траекторий, пересекающих буфер опасного препятствия.
| № | Действие тестировщика | Ожидаемый результат | Статус |
|---|---|---|---|
| 1 | Открыть https://whatrushki.github.io/drone/ | Зеленый индикатор в шапке: «API: Онлайн», карта отцентрирована на полигонах | PASS |
| 2 | Ввести в строке поиска участок FID 2 (или выбрать из выпадающего списка) |
Карта плавно центрируется на полигоне, подсвечивая его границы бирюзовым цветом | PASS |
| 3 | Нажать кнопку инструмента рисования «Свой полигон» и нарисовать область | Создается пользовательский полигон, обновляется расчетная площадь в гектарах | PASS |
| 4 | Кликнуть по карте для установки основной базы (Home) и запасной посадки | На карте появляются маркеры База 1 и Аварийная площадка |
PASS |
| 5 | Выбрать БВС «Геоскан 201» (самолет), сенсор Sony RX1RM2, GSD = 5 см/пикс | В блоке фотограмметрии мгновенно отображается расчетная высота (175 м) и ширина захвата | PASS |
| 6 | Установить скорость ветра 6 м/с и направление 45° | Стрелка на компасе указывает вектор, отображается метеорологическое направление | PASS |
| 7 | Нажать «Сформировать задание» (Критерий: Минимизация времени) | Строятся съемочные галсы со сглаженными виражами Дубинса, выводятся карточки статистики | PASS |
| 8 | Запустить 4D-плеер симуляции кнопкой Play | Маркер БВС синхронно перемещается по галсам, плавно меняя курсовой угол при разворотах | PASS |
| 9 | Нажать кнопку «Аварийный сход» в окне плеера | БВС плавно сходит с галса по касательной и совершает посадку на аварийную площадку | PASS |
| 10 | Нажать «Экспорт QGC (.plan)» | Браузер скачивает валидный файл .plan, готовый к импорту в QGroundControl |
PASS |
- 🚀 Фронтенд на GitHub Pages: https://whatrushki.github.io/drone/
- ⚡ Продакшн API Backend (Cloud VPS Ubuntu 24.04): https://84.201.161.204.sslip.io
- 📖 Интерактивная Swagger спецификация OpenAPI: https://84.201.161.204.sslip.io/docs
- 🛡️ SSL/TLS: Let's Encrypt доверенный сертификат с автопродлением
- 📦 Репозиторий проекта: https://github.com/whatrushki/drone.git