geoscan — бизнес-описание сервиса¶
Этот раздел объясняет что делает geoscan, какую боль снимает и кому читать дальше. Заказчик и жюри найдут здесь постановку задачи 5 ЛЦТ и отличие двух критериев оптимизации с живыми числами. Новый разработчик — границы продукта и связь UI → API → планировщик. Оператор — краткий маршрут по экранам и честный список того, что уже работает, а что нет. Детали запуска и диагностики — в 07-operate; алгоритм галсов и энергии — в 05-domain.
Постановка и глоссарий: 00-brief/01-tz.md (../../00-brief/01-tz.md), 03-glossary.md.
Симулятор полётов (отдельный продукт в simulate/) — раздел
simulate/docs/91-doc/01-business/README.md
(в worktree doc-gs-business файла пока нет; код и сценарии — в каталоге simulate/ репозитория).
Какую задачу решает сервис¶
До geoscan распределение ПАФС (площадной аэрофотосъёмки) между несколькими БВС обычно делают вручную в Geoscan Planner / Mission Planner: оператор рисует полигон, получает сетку галсов, сам решает, сколько бортов вывести и кто какую полосу летит. При двух ВПП, БПЗ, ветре и разном GSD ошибка в одном числе превращается в недосъём, лишний налёт или срыв окна работ.
geoscan — веб-сервис планирования и распределения беспилотных авиационных работ (задача 5 ЛЦТ, отраслевой партнёр ГК «Геоскан»). На входе: полигон съёмки, парк бортов, площадки, тип съёмки, ЛАФС/ПАФС-параметры качества, границы разрешённого воздушного пространства, бесполётные зоны, ветер. На выходе: полётное задание (ПЗ) на каждый задействованный борт — маршрут по галсам с высотой, скоростью, фазами полёта — в KML / GeoJSON (и других форматах экспорта, см. код экспортёра).
Оптимизация поддерживает минимум два критерия из ТЗ (docs/task5/00-brief/01-tz.md:40-41):
| Критерий в коде | Смысл для заказчика |
|---|---|
makespan |
Время выполнения работ — когда вернулся последний борт (минимум «календарного» простоя бригады) |
total_flight_time |
Суммарный налёт — сумма лётного времени всех бортов (износ, энергия, стоимость часа) |
Дополнительно в UI есть режим pareto с весом λ
(src/frontend/apps/planner/src/screens/ScenarioScreen.tsx:385-396).
mindmap
root((geoscan))
Вход
Полигон задачи ПАФС
GSD и тип съёмки
Парк БВС и ВПП
ЛАФС allowed / БПЗ no_fly
Ветер weather
Ядро
Галсы и покрытие
Назначение бортам
Энергия и вылеты
Обход БПЗ в перелётах
Выход
План metrics
ПЗ по бортам
KML GeoJSON
Контроль
Валидатор G1-G6
Отчёт в UI
Вывод: geoscan закрывает mCPP — multi-robot coverage path planning: одна область, несколько БВС, ограничения из ТЗ, два явных KPI для выбора стратегии бригады.
Границы системы и внешние акторы¶
Публичная точка входа — gateway (REST /api/..., OpenAPI /docs); домены planner и
validator вызываются по gRPC (docs/task5/50-stack/05-service-architecture.md:29-33).
Фронтенд — монорепозиторий src/frontend/ (shell + remote-приложения), маршруты в
src/frontend/apps/shell/src/App.tsx:31-38.
flowchart TB
subgraph actors [Вне системы]
OP[Оператор / планировщик полётов]
JURY[Жюри / заказчик]
AP[Автопилот / QGC]
end
subgraph geoscan [geoscan tailnet geoscan.ff]
UI[Браузер shell + planner + validator]
GW[gateway HTTP :3000]
PL[planner gRPC]
VAL[validator gRPC]
PG[(Postgres сценарии и jobs)]
end
subgraph out [Артефакты]
KML[KML GeoJSON PLAN]
RPT[Отчёт валидатора]
end
OP --> UI
JURY --> UI
UI --> GW
GW --> PL
GW --> VAL
GW --> PG
PL --> GW
VAL --> GW
GW --> KML
UI --> RPT
KML --> AP
Вывод: geoscan не заменяет диспетчера ЕС ОрВД, не подаёт план в СППИ и не управляет бортом в полёте — только готовит ПЗ и метрики качества.
Кто пользователь и что он делает¶
Роли выведены из реализованных экранов и API, а не из org-chart.
| Актор | Цель | Где в продукте |
|---|---|---|
| Оператор съёмки | Собрать сценарий, выбрать критерий, получить маршруты и выгрузить в автопилот | «Сценарии» → «Область съёмки и парк» → «Воздушное пространство и БПЗ» → «План полётов» → «Экспорт и импорт» (src/frontend/apps/shell/src/LeftRail.tsx:24-32) |
| Инженер / методист | Проверить, что план формально допустим (покрытие, NFZ, энергия) | «Отчёт валидатора», «Парето» |
| Разработчик / интегратор | Встроить расчёт в свой контур | POST /api/plans, CLI python -m planner (src/backend/planner/planner/cli/__main__.py:81-92) |
| Жюри / заказчик | Убедиться, что на демо-сценарии видны метрики и два критерия | Демо s01–s10, KPI и сравнение с baseline на «План полётов» (src/frontend/apps/planner/src/screens/PlanScreen.tsx:73-74,98,114-121) |
journey
title Оператор: от сценария до KML
section Старт
Выбрать демо или импорт JSON: 4: OP
Открыть карту сценария: 5: OP
section Настройка
Задать GSD и критерий: 4: OP
Проверить БПЗ и allowed: 3: OP
section Расчёт
Нажать Рассчитать план: 5: OP
Сравнить makespan с бейзлайном: 4: OP
section Сдача
Открыть отчёт валидатора: 3: OP
Скачать KML по борту: 5: OP
Вывод: один человек может пройти весь путь в браузере; формальный контроль качества вынесен в
отдельный экран валидатора — это сознательное следование принципу «валидатор раньше продукта»
(docs/task5/70-plan/01-validator-first.md).
Вход и выход в терминах заказчика¶
Вход (документ сценария JSON)¶
| Поле сценария | Что означает для заказчика | Пример в коде |
|---|---|---|
launch_sites[] |
ВПП — откуда стартуют роторы/катапульта | s03-multi-sites.json:8-26 — «ВПП запад» и «ВПП восток» |
fleet[] |
Какие БВС доступны, домашняя площадка, нагрузка | s03-multi-sites.json:30-51 — три geoscan_gemini |
tasks[] |
Полигон ПАФС, тип съёмки, GSD | s03-multi-sites.json:54-73 — rgb, GSD 3 см |
airspace.allowed |
Внешняя оболочка разрешённого ВП | s03-multi-sites.json:76-88 |
airspace.no_fly |
БПЗ (exclusion) | s02-nfz.json (отдельный демо-сценарий) |
landing_sites[] |
Резервные площадки посадки (несимметричный финиш) | Во всех s01–s10 сейчас [] — поле есть в схеме, практика не показана |
weather |
Ветер для путевой скорости и лимитов борта | s03-multi-sites.json:92-96 |
objective |
Критерий, резерв энергии, режим ЛЗП, буфер от запреток | s03-multi-sites.json:98-103 |
Пять типов съёмки объявлены в контракте (src/backend/shared-py/geoscan_contracts/enums.py:8-13);
не все представлены в каждом демо-JSON
(см. R-IN-4 в 04-requirements-checklist.md (../../00-brief/04-requirements-checklist.md)).
Выход (документ плана)¶
| Артефакт | Содержание | Где в коде |
|---|---|---|
metrics |
makespan, суммарный налёт, доля покрытия, нарушения NFZ/energy/… | plan.schema.json; экран «План» |
missions[] |
ПЗ на каждый борт: вылеты (sorties), фазы (survey, transit, …) |
s03-multi-sites.plan.json:34+ |
| Экспорт | KML, GeoJSON, QGC .plan, waypoints |
src/backend/planner/planner/export/__init__.py:17-24 |
На экране «План» оператор видит карту галсов по цветам бортов, гантт вылетов и сравнение
оптимизированного makespan с наивным равным делением
(src/frontend/apps/planner/src/screens/PlanScreen.tsx:73-74,114-121).
Два критерия оптимизации: когда какой выбирать¶
| Вопрос | Выбирайте makespan («Время работ») |
Выбирайте total_flight_time («Налёт») |
|---|---|---|
| Что минимизируем | Время до возврата последнего борта | Сумму лётных часов всех бортов |
| Типичная ситуация | Срочная съёмка, дорогой простой бригады на земле | Длинная кампания, лимит моточасов / АКБ, износ парка |
| Цена компромисса | Чаще больше суммарный налёт — параллелим работу | Чаще дольше makespan — меньше бортов в воздухе одновременно |
Переключатель в UI: src/frontend/apps/planner/src/screens/ScenarioScreen.tsx:375-383.
В CLI — флаг --objective (src/backend/planner/planner/cli/__main__.py:83-87).
Живые числа: сценарий s03-multi-sites¶
Сценарий: полоса ~3×1 км, 3 борта geoscan_gemini, 2 ВПП на противоположных сторонах
(scenarios/s03-multi-sites.json:3-51). Команды выполнены 17.09.2026 в worktree docs2/gs-business,
каталог src/backend, --seed 42:
cd src/backend
uv run python -m planner run --scenario scenarios/s03-multi-sites.json --objective makespan --seed 42 --out /tmp/s03-makespan.json
uv run python -m planner run --scenario scenarios/s03-multi-sites.json --objective total_flight_time --seed 42 --out /tmp/s03-total.json
Фрагмент фактического вывода (скрипт на json.load после двух прогонов; метрики — из
plan["metrics"], статус решателя — из plan["solver"]["status"], не из metrics):
=== makespan ===
makespan_s: 781.3
total_flight_time_s: 2300.9
coverage_frac: 0.9999490222920405
uavs_used: 3
sorties_total: 3
solver.status: feasible
=== total_flight_time ===
makespan_s: 1064.7
total_flight_time_s: 2095.9
coverage_frac: 0.9999490222920405
uavs_used: 2
sorties_total: 2
solver.status: feasible
| Метрика | makespan |
total_flight_time |
Разница |
|---|---|---|---|
| Makespan (мин:сек) | 13:01 (781 с) | 17:45 (1065 с) | −283 с (−27 %) у режима «время работ» |
| Суммарный налёт | 38:21 (2301 с) | 34:56 (2096 с) | −205 с (−9 %) у режима «налёт» |
| Бортов задействовано | 3 | 2 | режим налёта экономит борт |
| Вылетов | 3 | 2 |
Валидатор на обоих планах: ВЕРДИКТ: план допущен (те же файлы, python -m validator check …).
quadrantChart
title Компромисс на s03-multi-sites seed 42
x-axis Дольше makespan --> Короче makespan
y-axis Больше суммарный налёт --> Меньше суммарный налёт
quadrant-1 Баланс с упором на срок
quadrant-2 Идеал по обеим осям
quadrant-3 Дорого по обоим KPI
quadrant-4 Упор на экономию налёта
makespan: [0.72, 0.35]
total_flight_time: [0.45, 0.55]
Точки на диаграмме нормированы для наглядности (0…1 внутри квадранта); абсолютные секунды — в таблице выше. Вывод: критерии дают разные планы; «быстрее закончить бригаду» и «меньше налетать в сумме» — не одно и то же.
Как считается план (сквозной поток)¶
sequenceDiagram
participant U as Оператор UI
participant G as gateway
participant P as planner
participant V as validator
U->>G: POST /api/plans сценарий + criterion
G-->>U: 202 Accepted Location /api/plans/id
U->>G: GET /api/plans/id/events SSE
G->>P: gRPC Plan
P-->>G: Plan + metrics
G-->>U: progress → completed
U->>G: GET /api/plans/id/export?fmt=kml
G-->>U: файл KML
U->>G: POST validate или экран validator
G->>V: gRPC Validate
V-->>U: G1…G6 отчёт
stateDiagram-v2
[*] --> queued: POST /api/plans
queued --> running: dispatcher
running --> done: planner OK
running --> error: Infeasible / сбой
done --> [*]: metrics + export
error --> [*]
Статусы job в gateway: queued → running → done | error
(src/backend/gateway/src/plans/postgres-plans.repository.ts:81,162-191,266-287).
Чего сервис сознательно не делает¶
Кратко; развёрнуто — 95-manual/03-limitations.md.
| Не входит в продукт | Почему |
|---|---|
| Полётное управление и телеметрия в реальном времени | Только планирование ПЗ, не GCS в полёте |
| Юридическая проверка зон и подача в СППИ | Статическая геометрия сценария, без интеграции с ЕС ОрВД |
| LiDAR / геофизика «из коробки» на всех бортах | В каталоге нет полной связки носитель↔нагрузка для всех типов |
| Автономный выбор резервной площадки посадки | landing_sites читаются, посадка в планировщике привязана к home (см. вердикт R-IN-7 ниже) |
| Симуляция исполнения плана | Это продукт simulate/, не geoscan |
Что работает и что нет (честно)¶
Вердикт приёмки в репозитории¶
Файл docs/task5/96-acceptance/00-verdict.md отсутствует на ветке docs2/gs-business
(git show HEAD:… → fatal). Эталонная приёмка лежит на ветке accept/geoscan-final
(дата 16.09.2026): итог «готовность частичная», блокеры Б-1…Б-5 в
96-acceptance/01-blockers.md той же ветки.
Ниже — перепроверка на текущем коде (17.09.2026). Утверждения без повторного прогона помечены как «по вердикту 16.09».
| Тема | Вердикт 16.09 | Сейчас на docs2/gs-business |
|---|---|---|
| Б-1: валидатор не допускает планы | FAIL G3-04 на s01 | Исправлено в проверке: s01 → ВЕРДИКТ: план допущен |
| Б-2: s02 заход в БПЗ | FAIL, violations.nfz > 0 |
Исправлено в проверке: s02 → nfz: 0.0, валидатор допускает; в pipeline есть route_avoiding_nfz (src/backend/planner/planner/pipeline.py:212,316) |
| Б-3: s04 пустой план | 0 missions | Не пустой: 1 mission, makespan ≈ 31681 с (~8,8 ч) — план тяжёлый, но не нулевой |
| Б-4: total_flight_time хуже makespan по налёту | налёт 3453 с vs 2301 с | Исправлено: total 2096 с < makespan 2301 с (таблица s03 выше) |
| R-IN-1: произвольная ВПП в UI | инструмент place-site не обработан |
По-прежнему: тип place-site только в src/frontend/packages/domain/src/store.ts:30, в UI не используется |
| R-IN-7: резервные площадки | не реализовано | По-прежнему: нет демо с непустыми landing_sites |
| R-PLT-2: фронт в docker/k3s | заглушка gateway | По k3s: деплой gateway/planner/validator (k3s/geoscan/), фронт отдельной сборкой — см. 07-operate |
| R-SUB-7: презентация | нет в git | Без изменений |
Что можно показать жюри уже сейчас¶
| Возможность | Доказательство |
|---|---|
| Демо-сценарии s01–s10 в репозитории | из корня репозитория: ls src/backend/scenarios/ — 10 JSON |
| Два критерия + метрики | Прогон s03 выше; UI Segmented «Время работ» / «Налёт» |
| KML / GeoJSON | planner export (src/backend/planner/planner/cli/__main__.py:99-105) |
| Сквозной REST | tests/integration/test_gateway_api.py (см. 96-status/00-final-status.md) |
| Формальный отчёт | Экран validator, правила G1–G6 |
Известные ограничения (не исчезли)¶
- Правки сценария в UI не всегда уходят на backend без сохранения через API (см. трассировку в
93-review/). - Browser E2E в CI ограничен (typecheck/build).
- Документ
95-manual/03-limitations.mdдатирован 16.09 — сверять с кодом перед защитой.
Соседние разделы документации¶
| Раздел | Путь |
|---|---|
| Сценарии использования | 02-usecases |
| Путь по интерфейсу | 03-userflow — на доработке · черновик: руководство пользователя |
| Архитектура | 04-architecture |
| Домен: галсы, ветер, энергия | 05-domain |
| API и форматы | 06-api — на доработке · черновик: публичный API |
| Установка и эксплуатация | 07-operate |
Быстрые ссылки для разработчика¶
# План + метрики (из корня backend)
cd src/backend
uv run python -m planner run --scenario scenarios/s03-multi-sites.json --objective makespan --out /tmp/plan.json
# Формальная проверка
uv run python -m validator check --scenario scenarios/s03-multi-sites.json --plan /tmp/plan.json
# Экспорт KML одного борта
uv run python -m planner export --plan /tmp/plan.json --scenario scenarios/s03-multi-sites.json --fmt kml --uav gemini-01 --out /tmp/gemini-01.kml
Критерии в контракте: src/backend/shared-py/geoscan_contracts/enums.py:32-35.