Перейти к содержанию

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: queuedrunningdone | 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.