01. Бот-маршрутник: ищет термики по вариометру и летит маршрут (FR-34a)
Цель: headless-бот, который летит маршрут N км на реальном рельефе локации, находя термики только по вариометру (как пилот), и пишет статистику полёта в JSON — основа измерения проходимости.
Контекст: scripts/atmosphere/atmosphere.gd (API), scripts/flight/flight_model.gd (step(dt, input, air_fn, ground_fn)),
scripts/flight/flight_telemetry.gd, tests/flight/flight_sim.gd (образец обвязки), tests/terrain/test_locations.gd
(как грузить Terrain.new() headless), docs/research/thermals.md §1–2.
Владения: tests/atmosphere/xc/ (новые: xc_pilot.gd, xc_run.gd, xc_run.tscn), tools/atmosphere/xc_run.sh.
Чужой код (FlightModel, Terrain, scripts/game/autopilot.gd) — только через API, не править.
Шаги:
xc_run.tscn -- --location=ongudai --weather=medium --seed=1 --wind=15,270 --km=30 --out=<json>: грузит Terrain, Atmosphere (configure,set_ground(height_at, thermal_source_strength_at, surface_at),focus= бот), FlightModel крылаsport; старт в воздухе над стартом локации на +300 м AGL; шаг 1/60 с.XcPilot.drive(telemetry, dt) -> ControlInput— честный бот (FR-22): видит только вариометр (усреднение 1–2 с), высоту, AGL, курс, позицию, путевую скорость.thermals_nearНЕ использовать. Режимы:- переход: курс на поворотную точку (прямая по умолчанию), скорость по МакКриди от ожидаемого набора;
- вход: усреднённый вариометр > порог (≈ +0,5 м/с сверх собственного снижения) → вираж 35–40° в сторону, где был подъём (асимметрия крена от FR-8 — подсказка);
- центровка: правило Райхмана (сильнее → положе, слабее → круче / смещать круг к максимуму);
- выход: средний набор за круг < порога МакКриди, или до кромки < 150 м под крупным облаком (FR-14b, «близко не подходят»);
- ниже 300 м AGL — режим «спасения» (берёт любой подъём); коснулся земли → вынужденная посадка, конец.
- Опционально флаг
--clouds: бот видит облака (центры видимых облаков из CloudModel), выбирает цель перехода под растущим облаком в секторе ±30° от курса — как пилот читает небо. - Метрики в JSON: пройдено км, время, средняя путевая, доля времени в кружении, число термиков, средний набор в
термике (по кругам), распределение набора (гистограмма 0,5 м/с), среднее снижение на переходах, эффективное
качество переходов, макс. вариометр, время с вариометром ≥ +7, время в облаке (
cloud_density_at> 0,3), доля найденных термиков без облака, причина конца (цель / посадка / лимит времени).
Критерий приёмки (измеримо):
- Синтетика (плоская земля, статичные термики 3 м/с R=100 м сеткой через 2 км вдоль курса, без ветра, фон −0,5): бот проходит 30 км без посадки в 5/5 сидах; находит ≥ 90 % термиков, чей центр ≤ 150 м от линии курса; средний набор в термике ≥ 65 % от (ядро − снижение крыла на вираже).
- Без термиков бот пролетает дистанцию ≈ высота × качество ±15 % (проверка переходов и учёта снижения).
- Детерминизм: один сид → одинаковый JSON. Прогон 30 км ≤ 60 с CPU.
- Юнит-тест
tests/atmosphere/test_xc_bot.gd(синтетика, короткая 10 км) — в общем прогоне ≤ 10 с.
Зависимости: после агента atmosphere; Terrain headless (есть). Модель: opus. Размер: M.