Файл миссии выглядит так и содержит только цель:
RUNONCEPATH("0:/lib/mission.ks").
SET s TO m_defaults().
SET s["name"] TO "Спутник-2".
SET s["ap"] TO 7867078.
SET s["pe"] TO 3331362.
SET s["inc"] TO 20.1.
SET s["lan"] TO 250.8.
SET s["aop"] TO 29.6.
m_orbit(s).
Шестнадцать строк — и аппарат уходит на заданную орбиту сам. Здесь разобрано, что стоит за этой одной строкой m_orbit(s): в каком порядке идут фазы, какие решения принимаются на ходу и где смотреть, если пошло не так.
Общая последовательность
подготовка → окно узла → подъём → раскрытие → выбор схемы → прожиги → добор науки
| Фаза | Что происходит | Что печатает |
|---|---|---|
| Подготовка | IPU поднимается до 800, открывается лог, считается азимут |
=== имя · цель … · накл …° |
| Наука на столе | снимает показания приборов, ничего не передаёт | наука [на столе]: снято N |
| Окно узла | если задан lan — ждёт с перемоткой времени |
жду окно узла …°: N мин |
| Подъём | до апоцентра опорной, дальше по инерции из атмосферы | апоцентр … км |
| Раскрытие | панели и антенны, разрешаются выдвижные приборы | раскрыто: панели …, антенн N |
| Выведение | одна из двух схем, см. ниже | === разгон… или === скругление опорной |
| Итог | сверка «заказано / получилось», добор науки | === ИТОГ … / … км · накл …° |
Почему схемы две
Развилка одна и зависит от того, задан ли аргумент перицентра (aop).
Не задан — один прожиг. Из апоцентра подъёма даём импульс, поднимающий противоположную апсиду сразу до цели. Точка прожига становится перицентром. Это дешевле по топливу и быстрее: не нужно ни скругления, ни ожидания.
Задан — парковка и ожидание. Контракт требует, чтобы перицентр оказался в определённой точке витка. Тогда: скругляем опорную → считаем, когда аппарат придёт в нужную точку (u_utAtArgLat) → жжём именно там. Точка прожига становится перицентром, её угол от восходящего узла и есть требуемый аргумент.
Перицентр после этого поднимается отдельным прожигом — но только если он реально ниже цели больше чем на 2 км. Лишний манёвр не делается.
Что происходит при подъёме
Внутри a_run три участка:
- Вертикаль. Строго вверх до 60 м/с. Разворачиваться раньше опасно: скорость мала, рули не работают, аппарат валится.
- Гравитационный разворот. Курс задаётся расписанием тангажа по высоте, зажатым допуском угла атаки — 5° в плотном воздухе, 20° выше 25 км. Тяга ограничивается потолком перегрузки 2,3 до 22 км и потолком скоростного напора 0,32 атм.
- Дотягивание. Выше атмосферы ещё нет, но воздух уже грызёт апоцентр — короткие импульсы на 35% тяги держат его у цели.
Восстановление при заваливании. Если угол атаки превысил 14° в плотном воздухе, скрипт бросает расписание и разворачивает аппарат строго по потоку, а тягу снижает — но не ниже 0,45. Полностью убирать тягу нельзя: вместе с ней пропадает управление вектором двигателя, и ракета уже не выправляется. Как только угол упал ниже 4°, управление возвращается расписанию.
Аварийный триггер висит всё время подъёма: снижение быстрее 10 м/с в диапазоне 3–60 км означает, что мы падаем. Тяга глушится, a_run возвращает FALSE, m_orbit прекращает миссию и снимает управление.
Отделение ступеней
Топливо в ступени считать бесполезно: у твердотопливных и у сборок с общим баком счёт врёт. Признак другой — не осталось ни одного работающего двигателя:
IF STAGE:NUMBER = 0 { RETURN FALSE. }
IF NOT STAGE:READY { RETURN FALSE. }
RETURN s_liveEngines() = 0.
Работает и для ступеней без двигателей вовсе — обтекателей, переходников: они уходят вместе со следующей отсечкой. Мы пришли к этому после запуска, где скрипт не учёл одну промежуточную ступень и завис, ожидая тягу от отделённого блока.
Что писать в логи и как читать
Каждая миссия пишет mission.csv — строка каждые полсекунды:
t, alt, spd, q, aoa, az, inc, arglat, thr, ap, pe, mono, zone
Что смотреть, когда пошло не так:
| Симптом | Куда смотреть | Обычная причина |
|---|---|---|
| Перевернулась на подъёме | aoa и q |
угол атаки ушёл за допуск в плотном воздухе |
| Не хватило топлива | ap против t |
слишком крутое расписание: горизонтальной скорости мало, скругление дорогое |
| Наклонение мимо | az и inc |
азимут пуска: проверь U_AZ_BIAS |
| Узел мимо | строка калибровка узла в конце |
константа U_LAN_C для этого сейва другая |
| Наука не ушла | zone и счётчики в конце |
передавали в атмосфере либо все замеры дешевле 0,1 |
На экране во время полёта — две стрелки: зелёная «поток» (куда летим) и оранжевая «команда» (куда рулим). Расхождение между ними и есть угол атаки: видно глазом, без цифр.
Точки настройки
Менять поведение, не трогая код:
SET s["park"] TO 90000. // выше опорная — дольше подъём, дешевле разгон
SET s["hud"] TO FALSE. // без стрелок (например, при работе по telnet)
SET SCI_MIN_VALUE TO 0.5. // передавать только заметную науку
SET C_MONO_RESERVE TO 10. // беречь больше монотоплива
Параметры самого подъёма — через a_defaults(), если вызывать a_run напрямую: допуски угла атаки, потолки перегрузки и напора, высота границы плотного воздуха.
Порядок работы, который себя оправдал
- Собрать аппарат и вывести на стартовый стол — это делает игрок, скрипт постройкой не занимается.
- Прогнать проверку:
RUNPATH("0:/check/libcheck.ks").— ловит опечатки и занятые встроенные имена до пуска, а не на 20-й секунде. - Записать цель в файл миссии: апоцентр, перицентр, наклонение, при необходимости узел и аргумент перицентра.
- Запустить:
RUNPATH("0:/missions/имя.ks"). - Не трогать терминал. Любой ввод во время работы kOS считает попыткой прерывания и роняет программу. Смотреть можно, писать нельзя — в том числе по telnet.
- Прочитать итог: строка
=== ИТОГпоказывает полученное против заказанного. Контракты обычно дают допуск 10% по каждому параметру.
Дальний вылет: та же идея, дальше от дома
m_orbit(s) уводит на орбиту вокруг тела старта. ds_run(s) из lib/deepspace.ks — тот же принцип «файл миссии содержит только цель», но для перелёта к другому телу и обратно на несколько аппаратов сразу:
RUNONCEPATH("0:/lib/deepspace.ks").
SET s TO ds_defaults().
SET s["body"] TO MUN.
SET s["parkAlt"] TO 100000. // рабочая орбита — отсюда разводят спутники
SET s["mapAlt"] TO 0. // 0 = не подниматься, шина садится сама
SET s["landers"] TO LIST("sat-1", "sat-2", "sat-3", "sat-4").
SET s["selfLand"] TO TRUE. // после развода — деорбит и посадка шины
ds_run(s).
Внутри — та же последовательность, что при рандеву с аппаратом (Рандеву и стыковка), только целью выступает небесное тело: подгонка плоскости → окно перехода → прицельный перицентр у чужой сферы влияния (пробой знака, тот же приём, что у r_nodeMatchPlanes) → захват в перицентре (o_nodeCircularizeAtPeri — у гиперболы апоцентра нет, поэтому не тот узел, что при обычном скруглении). Дальше, если в spec заданы landers, — выпуск по очереди с интервалом в долю витка, чтобы фазы/наземные треки разошлись. landers — общее имя: под меткой может быть посадочный зонд, а может быть спутник созвездия, который остаётся на орбите, разница только в том, что дальше делает selfLand.
Что автоматика не решает сама: какой конкретно биом или орбитальную плоскость выбрать под каждую отделяемую нагрузку (разница по времени отделения — не гарантия, только шанс попасть в разные) и включение сканеров SCANsat — их модуль в библиотеке не сверен, переключаются с приборной панели руками. Если selfLand не задан — посадка каждой нагрузки-лендера отдельным шагом после переключения фокуса, l_run(s) из lib/land.ks: kOS не может вести аппарат, на который не переключен фокус, см. Управление флотом.
Если ведёшь полёт как ИИ-агент
Короткая версия для тех, кому дали доступ к терминалу:
- Игру запускает игрок. Твоё дело — подготовить скрипт, подключиться и наблюдать.
- Проверяй перед пуском, а не после:
libcheck.ksдешевле потерянной ракеты. - Читай, не вмешивайся.
kos.py --watch 60показывает экран, ничего не отправляя. - Диагностируй по логам, а не по ощущениям:
mission.csvрядом с игрой,KSP.logв корне. - Нашёл расхождение с этой статьёй — предложи правку. Как именно, написано в
AGENTS.md, который установщик кладёт рядом с игрой.
Что именно вызывать — kOS: справочник библиотеки kerbal.ru. Почему модули устроены так — kOS: библиотека модулей. Разбор реальных ошибок первых запусков — Скрипт вывода на орбиту: разбор ошибок.