Правила и допущения расчёта¶
Как Аэрозвено на самом деле строит план: какие правила действуют на каждом шаге, какие числа зашиты в расчёт и что сознательно не моделируется. Все значения сверены с кодом текущего выпуска. Если значение — умолчание, которое можно поменять в сценарии, указано поле.
Режимы расчёта на публичном стенде
| Настройка | Значение на стенде | Что значит |
|---|---|---|
| Модель разворотов | arc |
самолётные борта разворачиваются по дуге, мультироторы — на месте |
| Поиск угла галсов | full, 8 процессов |
угол уточняется целыми планами, параллельно |
| Профиль взлёта и посадки | legacy |
взлёт 30 с и посадка 60 с в точке площадки; катапульта, парашют, разбег по полосе и глиссада не строятся |
| Цифровая модель рельефа | не подключена | запас над рельефом не проверяется, в плане — предупреждение TERRAIN_UNKNOWN |
Режимы переключаются настройками сервиса (PLANNER_TURN_MODEL, PLANNER_ANGLE_SEARCH,
PLANNER_ANGLE_WORKERS, PLANNER_PROFILE_MODEL, PLANNER_DEM_DIR); ниже описано поведение
кода во всех режимах.
Порядок расчёта¶
- Проверить сценарий по схеме и убедиться, что требуемый GSD достижим хотя бы одним бортом.
- Для каждого участка отобрать борта: подходящая нагрузка, допустимый ветер, заряд, температура.
- Рассчитать высоту съёмки из GSD и камеры, шаг галсов из перекрытий.
- Обрезать участок разрешённым пространством и бесполётными зонами на высоте съёмки.
- Выбрать угол галсов, построить галсы.
- Назначить галсы бортам по критерию и упорядочить обход.
- Нарезать работу на вылеты по запасу хода с резервом, проложить перелёты в обход зон.
- Посчитать метрики, учесть площадки и запасные АКБ, при запросе — развести борты.
- Уточнить угол галсов целыми планами и оставить лучший.
Схема конвейера — в Архитектуре.
Высота съёмки и GSD¶
Высота из GSD. Для камер (RGB, мультиспектр, ИК): H = GSD / k, где k — коэффициент нагрузки
из справочника, а если его нет — ширина матрицы / (фокусное расстояние × ширина кадра в пикселях).
Для камер со сменным объективом фокусное расстояние берётся из fleet[].focal_length_mm.
| Нагрузка | Высота при GSD 3 см |
|---|---|
| камера PF1B (Gemini) | ≈ 153 м |
| камера борта 201 | ≈ 233 м |
-
Лидар:
H = частота сканирования / (плотность точек × V × 2·tg(FOV/2)), V — крейсерская воздушная скорость. Геофизика: 50 м над землёй с ограничением пределами борта. -
Если расчётная высота ниже минимальной или выше максимальной для борта, борт исключается из участка (
ALTITUDE_BELOW_MIN,ALTITUDE_ABOVE_MAX,ALTITUDE_ASL_ABOVE_MAX) — высота не прижимается к пределу, чтобы не нарушить требуемый GSD. Если GSD недостижим ни одним бортом, расчёт отклоняется сGSD_UNREACHABLE. -
Высота выше 150 м — не отказ, а флаг и предупреждение
ALT_ABOVE_150M: для работ нужно разрешение на ИВП. Интерфейс предлагает ослабить GSD.
Покрытие и галсы¶
Отпечаток кадра: поперёк галса ширина матрицы × H / f, вдоль — высота матрицы × H / f
(длинная сторона матрицы — поперёк галса).
Шаг галсов: отпечаток поперёк × (1 − поперечное перекрытие); для лидара — ширина полосы
сканирования × (1 − перекрытие); для геофизики — quality.line_spacing_m. При боковом ветре шаг
уменьшается в cos β раз, где sin β = W⊥ / Vₐ — угол сноса (краба), чтобы перекрытие
сохранилось.
Интервал съёмки: отпечаток вдоль × (1 − продольное перекрытие) / путевая скорость.
Перекрытия по умолчанию (если в участке не заданы overlap_forward_frac / overlap_side_frac):
| Тип съёмки | Продольное | Поперечное |
|---|---|---|
| RGB | 70 % | 60 % |
| Мультиспектр | 80 % | 75 % |
| ИК | 80 % | 75 % |
| Лидар | — | 30 % |
Нарезка:
-
Участок =
area ∩ разрешённое пространство − (зоны + буфер)на высоте съёмки; куски меньше 1 м² отбрасываются. Вырезы в полигоне учитываются. -
Галсы параллельны, первый — на половине шага от края, направление чередуется «змейкой». Если участок уже половины шага — один галс посередине. Галс короче четверти шага не строится.
-
Добор покрытия: если полосы захвата покрывают меньше 99,5 % участка, добавляются короткие галсы (не короче 5 м), затем концы галсов выносятся за границу на 0,25 / 0,5 / 1 половины полосы — если это позволяют пространство и зоны.
-
Смешанный парк: борта группируются по шагу и высоте. Маленький участок (сторона меньше 6 шагов) целиком отдаётся одной группе с самым мелким шагом. Крупный режется на полосы поперёк галсов пропорционально производительности групп; группа берёт только то, до чего дотягивается (радиус — 70 % запаса хода туда и обратно), остаток — самой дальнобойной.
Угол галсов¶
Если в участке задан angle_deg, он используется как есть. Иначе угол выбирается в два шага.
1. Быстрая оценка. Для каждого угла оценивается время галсов с учётом ветра плюс время разворотов. При ≤ 4 участках перебирается каждый градус 0…179°, при большем числе — шаг 5° и уточнение по 1° в ±4° от лучшего. Выбирается минимум времени среди углов, у которых суммарная длина галсов не меньше 90 % максимальной.
2. Уточнение целыми планами. Быстрая оценка не видит подлёт к участку и нарезку на вылеты, поэтому после первого плана для каждого участка считаются полные планы по кандидатам угла:
| Правило | Значение |
|---|---|
| Кандидатов на участок | до 8: направления 4 самых длинных сторон, 2 направления «площадка → участок», 3 лучших угла быстрой оценки (разнесённых не меньше чем на 10°) |
| Соседи лучшего | ±5° |
| Совпадающие углы | ближе 0,25° считаются одним |
| Принять кандидата | план есть, нарушений не больше, покрытие не хуже более чем на 0,0005, выигрыш по критерию больше 0,1 % |
| Остановка по застою | 4 отклонённых кандидата подряд |
| Бюджет времени | уточнение — не больше 50 % лимита, весь расчёт — не больше 90 % лимита; не успели — ANGLE_SEARCH_TRUNCATED |
| Когда не уточняется | угол задан вручную; участков больше 4; в первом плане больше 400 галсов на участке; пересчёт после выбытия борта |
| Параллельность | кандидаты считаются пулом процессов (PLANNER_ANGLE_WORKERS, по умолчанию — по числу ядер, не больше 8); при сбое пула — последовательно |
Выбранный угол и таблица всех кандидатов с их критерием, покрытием и числом вылетов видны в «Протоколе решений» на экране плана.
Развороты¶
Режим задаёт objective.turn_mode: lzp — с выходом на ЛЗП (по умолчанию) или flyby —
пролётом.
Самолётные борты (201, Penguin B) разворачиваются по дуге — кратчайшей кривой Дубинса:
| Правило | Значение |
|---|---|
| Радиус | R = (V + W)² / (g · tg φ) плюс запас 5 %; ветер прибавляется целиком, g = 9,81 м/с² |
| Крен φ | 30° (допущение: в документации производителя не указан) |
| Пример | борт 201 (крейсерская 27,8 м/с) в штиль — ≈ 143 м; при ветре 5 м/с — ≈ 199 м |
| Выравнивание перед галсом | 4 с прямого полёта (в режиме lzp); у 201 ≈ 111 м |
| Время разворота | длина дуги / крейсерская воздушная скорость |
| Через сколько галсов разворачиваться | ceil(2R / шаг) — если шаг меньше диаметра, борт заходит на галс через один или несколько |
Мультироторы (Gemini, 801) разворачиваются на месте: 8 с в режиме lzp, 5 с — пролётом;
между галсами — прямая.
Развороты у зон и границы. Дуга не должна заходить в зону с буфером и за разрешённое
пространство. Порядок попыток: кратчайшая кривая → другие виды кривой → вынос разворота от торцов
шагом 50 м до 500 м → укорочение обоих галсов шагом 25 м до 300 м. Если остаток
галса короче четверти шага — галс выбрасывается (TRANSECT_TOO_SHORT); если разворот не
помещается — вылет завершается, галс уходит в следующий вылет (TURN_BLOCKED). Проверяются до 5
следующих галсов в очереди. Мультиротор не выносится и не укорачивается.
Вход на первый галс вылета и сход с последнего — по прямой перелёта, без дуги.
Перелёты, бесполётные зоны и граница пространства¶
| Правило | Значение |
|---|---|
| Буфер от зон | 25 м (objective.safety_buffer_m); при нарезке и прокладке берётся с запасом буфер × 1,02 + 0,5 м |
| Вертикальный запас | зона действует на высотах altitude_min − 50 м … altitude_max + 50 м (objective.zone_vertical_margin_m) |
| Обход стороной на любой высоте | objective.avoid_zones_laterally = true |
| Прокладка перелёта | кратчайший путь по графу видимости вокруг зон (вершины контура упрощены с допуском 10 м и отнесены на 5 м), в рамке ±5 км вокруг участков и площадок |
| Пути нет | прямая и предупреждение NFZ_DETOUR_NOT_FOUND |
| Площадка внутри зоны на высоте борта | вылет с неё невозможен (SITE_IN_NO_FLY_ZONE) |
| Часть участка вне разрешённого пространства | не снимается, покрытие считается от доступной части; предупреждение TASK_OUTSIDE_AIRSPACE при доле ≥ 0,1 % |
Граница разрешённого пространства на перелётах
Граница airspace.allowed вырезает площадь съёмки и проверяется у разворотов, но перелёты и
возвраты её не обходят — обход строится только вокруг зон. Если перелёт вышел за границу,
план получает нарушение airspace и статус «нерешаемо», а валидатор — G1-02. Помогает
площадка внутри пространства или граница пошире.
Время действия зон (valid_from, valid_to), вид зоны (zone_kind) и общий пол и потолок
пространства (floor_m, ceiling_m) в расчёте не используются: все зоны считаются
запретными постоянно.
Энергия, вылеты и оборот¶
Бюджет вылета: запас хода × (1 − резерв) × холодовой коэффициент.
| Составляющая | Значение |
|---|---|
| Резерв | 20 % (objective.energy_reserve) |
| Запас хода: борт 201 | 180 мин |
| Запас хода: Gemini, 801 | 40 мин |
| Запас хода: Penguin B (топливо) | бак 7,5 л / расход 0,375 л/ч = 20 ч |
| Холод (только АКБ, ниже 0 °C) | −1 % ёмкости на градус, но не меньше 50 % (weather.temperature_c); предупреждение BATTERY_COLD |
| Температура вне рабочего диапазона модели | борт исключается |
Заряд перед первым вылетом (fleet[].battery_left_frac) |
бюджет первого вылета × заряд; заряд не выше резерва — борт не участвует (UAV_LOW_CHARGE); не хватает на первый галс — борт заряжается перед первым вылетом |
Длительность вылета = взлёт + перелёт + галсы и развороты + возврат + заход + посадка. Галсы считаются с ветром, перелёт, возврат и заход — по крейсерской воздушной скорости без ветра.
Нарезка на вылеты: галс берётся в вылет, если после него хватает бюджета на возврат, заход и
посадку. Если первый галс вылета не помещается, он делится, когда помещается хотя бы 25 % его
длины; иначе галс остаётся нераспределённым (endurance_exceeded). Возврат — к ближайшей
подходящей площадке.
Где садиться между вылетами. Для каждого борта считаются два варианта — всегда «домой» и «на
ближайшую подходящую площадку» — и берётся лучший по критерию. Борт взлетает оттуда, где сел.
Резервная площадка (reserve: true) принимает только последнюю посадку.
Оборот между вылетами:
| Ситуация | Время на земле |
|---|---|
| Домашняя площадка | turnaround_time_min площадки (по умолчанию 10 мин) |
| Другая площадка с запасной АКБ этой модели | оборот площадки |
| Другая площадка без запасной АКБ | большее из оборота и времени зарядки (Gemini — 105 мин) |
| Топливный борт | большее из оборота и заправки (Penguin B — 15 мин) |
Запасные АКБ (spare_batteries) и места обслуживания (service_slots) учитываются после
раскладки: они только сдвигают вылеты по времени, если АКБ или места заняты. Каждые 50 запусков
борта выдаётся предупреждение о ТО (MAINTENANCE_DUE).
Ветер¶
- Ветер постоянный по району и высоте:
weather.wind_speed_msиwind_direction_deg(откуда дует). -
Путевая скорость:
Vg = √(Vₐ² − W⊥²) + W∥. Если поперечная составляющая не меньше воздушной скорости —CROSSWIND_EXCEEDS_AIRSPEED; если путевая скорость не положительна —HEADWIND_EXCEEDS_AIRSPEED. -
Время галса = половина длины по ветру + половина против ветра — направление пролёта конкретного галса на время не влияет.
-
Предел ветра: борт с
wind_maxменьше ветра сценария в расчёт не идёт. Борт 201 — 12 м/с; Gemini, 801, Penguin B — 10 м/с. -
Ветер учитывается в шаге галсов (снос), радиусе дуги, выборе курса полосы и в точке захода (с подветренной стороны).
- Если ветер в сценарии не задан (0 м/с), интерфейс может подставить прогноз Open-Meteo на высоте 120 м над землёй; источник подписан под значением.
Рельеф¶
Рельеф берётся из цифровой модели рельефа (сетка Copernicus GLO-30, модель поверхности — с лесом и постройками), с билинейной интерполяцией. Все высоты плана — над землёй (AGL).
| Правило | Значение |
|---|---|
| Галс | идёт на постоянной высоте над рельефом: точки излома — по упрощению профиля с допуском 10 м, выборка 30 м |
| Перелёт, возврат, заход (правило TER-06) | профиль проверяется шагом 10 м; если запас над рельефом меньше 50 м (с допуском 1 м), весь этап поднимается на недостающую величину |
| Глиссада (при расчётном профиле) | запас не меньше min(50 м, половина высоты глиссады), шаг 30 м; иначе APPROACH_TERRAIN |
| Нет данных рельефа | предупреждение TERRAIN_UNKNOWN; расчёт идёт без рельефа |
Валидатор независимо проверяет запас 50 м над рельефом по всему маршруту (G2-04). Развороты между галсами, взлёт и посадка по рельефу не поднимаются; время набора на поднятых этапах не учитывается.
Площадки, взлёт, посадка и полосы¶
Профиль legacy (на стенде). Взлёт — 30 с в точке площадки, посадка — 60 с. Заход — через две
точки с подветренной стороны в 200 м и 100 м от площадки на крейсерской скорости.
Расчётный профиль computed (включается настройкой сервиса):
| Тип | Взлёт | Посадка |
|---|---|---|
| Мультиротор | вертикальный набор с его скороподъёмностью | вертикальное снижение (801, Gemini — 3 м/с) |
| Борт 201 | с катапульты по курсу площадки (takeoff_heading_deg) или против ветра; если курс закрыт зоной — перебор ±5…±30° шагом 5°; весь сектор закрыт — TAKEOFF_SECTOR_BLOCKED |
на парашюте: спираль до 70 м, затем спуск 5 м/с; точка раскрытия смещена против ветра на снос |
| Penguin B | разбег по полосе, набор по курсу полосы | заход по глиссаде 3° на скорости 16,9 м/с, пробег 100 м |
Полоса (launch_sites[].runway): длина и курс считаются по торцам. Направление взлёта и
посадки — с большей встречной составляющей ветра; если заход закрыт зоной — обратное
(APPROACH_REVERSED) или отказ (APPROACH_BLOCKED). Если полоса домашней площадки короче
потребной для борта (у Penguin B — 45 м на взлёт и 150 м на посадку), борт в расчёт не идёт
(RUNWAY_TOO_SHORT) — эта проверка работает в любом профиле.
Площадки фильтруют борта по типу (suitable_for: multirotor, fixed_wing).
Разведение бортов¶
Поле separation запроса POST /api/plans: none (по умолчанию), time или altitude.
| Режим | Как работает |
|---|---|
| Поиск сближений (всегда) | два борта одновременно ближе 300 м по горизонтали и 50 м по высоте, выборка каждые 2 с, без взлёта и посадки → предупреждение UAV_ENCOUNTER |
time |
каждый следующий борт сдвигается целиком шагом 30 с до 30 мин, пока сближения не исчезнут (иначе — вариант с минимумом сближений) |
altitude |
k-й борт поднимает перелёт, возврат и заход на k × 50 м; съёмка остаётся на своей высоте; если выше потолка или в слое зоны — SEPARATION_ALTITUDE_UNAVAILABLE |
Назначение галсов и критерии¶
Критерий (objective.criterion) |
Что минимизируется | Как назначаются галсы |
|---|---|---|
makespan — время работ (по умолчанию) |
время до окончания работы последнего борта | эвристика балансировки: каждому галсу — самый «дешёвый» борт, затем переносы по одному галсу, пока уменьшается максимальная загрузка |
total_flight_time — суммарный налёт |
сумма длительностей всех вылетов | та же эвристика, но уменьшается сумма загрузок |
pareto |
взвешенная сумма времени работ и налёта с весом lambda_frac |
смешанно-целочисленная модель (OR-Tools) |
Для сравнения двух критериев используйте экран «Мультикритериальный анализ»: он строит фронт Парето между временем работ и суммарным налётом.
Порядок обхода галсов у борта: для самолётных — лучший из шаблонов («змейка», переходы через один и несколько галсов, зеркальные и обратные) и решения OR-Tools по длинам кривых Дубинса (до 150 галсов); для мультироторов — задача коммивояжёра в OR-Tools с двумя стартовыми стратегиями, каждый галс можно пройти в любом направлении.
makespan_s — максимум по бортам конца последнего вылета, включая обороты; total_flight_time_s —
сумма длительностей вылетов.
Точного решения задачи маршрутизации нет: планировщик — эвристика с локальным улучшением, гарантии оптимальности нет. Качество видно по сравнению с «наивным делением» на экране плана и по вариантам в «Протоколе решений».
Лимит времени расчёта и остановка¶
| Правило | Значение |
|---|---|
| Лимит по умолчанию | 300 с (режим «Точно» в интерфейсе; «Быстро» — 30 с) |
| Максимум | 1800 с (30 мин); больше — ошибка 400 |
| Командная строка планировщика | 30 с по умолчанию |
| Распределение времени | назначение и порядок галсов — до 60 % лимита; уточнение угла — до 50 %, весь расчёт — до 90 % |
| Дедлайн внутреннего вызова | лимит + 30 с |
«Остановить и взять лучший план» (POST /api/plans/{id}/stop). Остановка срабатывает на этапе
уточнения угла: расчёт возвращает лучший найденный к этому моменту план с предупреждением
STOPPED_BY_OPERATOR. Первый план остановка не прерывает — он досчитывается. Если уточнения угла нет
(угол задан, участков больше 4, пересчёт после выбытия борта), расчёт идёт до конца. Задание, ещё
стоящее в очереди, завершается без плана.
Воспроизводимость. Одинаковые сценарий, критерий, лимит и зерно (solver.seed, по умолчанию
42) дают одинаковый план.
Когда план считается нерешённым¶
План получает статус infeasible (и в интерфейсе — ошибку расчёта), если:
- покрытие меньше 99 %, или в каком-то участке не снято больше 10 000 м² (1 га);
- маршрут заходит в зону или за границу разрешённого пространства больше чем на 0,01 м.
Нераспределённые галсы попадают в unassigned[] с кодом причины (см.
Работа с файлами). Независимо от статуса планировщика план проверяет
валидатор: 39 проверок, допуск — только без нарушений и без проверок fail.
Что не моделируется¶
| Не учитывается | Следствие |
|---|---|
| Порывы ветра, изменение ветра с высотой, турбулентность | ветер постоянный; gust_ms сохраняется, но не влияет |
| Ветер на перелётах, возврате, заходе и в разворотах | их время — по воздушной скорости |
| Реальная энергетика (Вт·ч), зависимость расхода от скорости, ветра, набора высоты и висения | бюджет вылета — по паспортному времени полёта с резервом |
| Время набора на поднятых этапах (рельеф, разведение по высоте) | этап поднимается целиком, время не меняется |
| Время действия и вид зон, общий пол и потолок пространства | все зоны запретны постоянно |
| Обход границы разрешённого пространства на перелётах | выход за границу — нарушение, не обход |
available_from борта и временные окна участков в расчёте |
окна проверяет только валидатор (G5-05) |
| Боковой ветер на полосе | проверяет только валидатор (G5-11) |
| Коридорная съёмка (ЛАФС) | протяжённые объекты снимаются параллельными галсами |
| Подъём галсов над рельефом | галс идёт на постоянной высоте над землёй |
| Лидар и геофизика в серийном парке | в справочнике нет совместимых носителей; расчёт поддерживает эти типы для демо-нагрузок |
| Оптимальное решение задачи маршрутизации | эвристика, без гарантии оптимума |
| NOTAM, зоны из внешних систем, подача плана | зоны задаёт оператор; сервис только готовит полётные задания |
| Исполнение плана в полёте и телеметрия | Аэрозвено — планировщик, не наземная станция |
Какие поля сценария на что влияют¶
| Стадия | Поля |
|---|---|
| Высота, GSD, шаг, кадры | tasks[].survey_type, quality, overlap_forward_frac, overlap_side_frac; fleet[].model, payload, focal_length_mm, enabled; launch_sites[].elevation_m |
| Участок, зоны, граница | tasks[].area; airspace.allowed; airspace.no_fly[].geometry, altitude_min_m, altitude_max_m; objective.safety_buffer_m, zone_vertical_margin_m, avoid_zones_laterally |
| Угол галсов | tasks[].angle_deg; objective.criterion, lambda_frac; положения площадок |
| Развороты | objective.turn_mode; ветер |
| Энергия и вылеты | objective.energy_reserve; weather.temperature_c; fleet[].battery_left_frac, home; launch_sites[].turnaround_time_min, spare_batteries, service_slots, suitable_for; landing_sites[].reserve |
| Взлёт и посадка | launch_sites[].takeoff_heading_deg, runway (при расчётном профиле; длина полосы — всегда) |
| Назначение и порядок | objective.criterion, lambda_frac; solver.seed |
| Время | time_limit_s запроса или solver.time_limit_s; start_time (отметки времени вылетов) |
| Не влияют на план | weather.gust_ms, airspace.floor_m, ceiling_m, no_fly[].zone_kind, valid_from, valid_to, fleet[].available_from, tasks[].time_window |