KerboScript в примерах и задачах. Часть 1. Выход на орбиту

Kerbal Space Program » Гайды

После того, как в предыдущей части мы смогли запулить зонд за пределы атмосферы, искупать Джеба в океане, пришло время перейти к следующему этапу освоения космоса и выйти на орбиту.

Использованные моды:


При ручном управлении вывод ракеты на орбиту состоит из четырёх основных этапов:
  1. Вертикальный подъём
  2. Разворот по тангажу (gravity turn)
  3. Построение апоцентра
  4. Скругление орбиты


Те же этапы сохраняются и с выводом при помощи kOS. Напишем, что делается на этих этапах.
1. Вертикальный подъём
Летим вертикально вверх, пока не достигли высоты начала разворота

2. Разворот по тангажу
Держим курс на восток, плавно меняем тангаж с 90 до 0 градусов.
Стараемся, чтобы нос не уходил далеко от вектора скорости.

3. Построение апоцентра
В горизонтальном полёте не отключаем тягу до тех пор, 
пока не достигли желаемой высоты апоцентра.
По достижении нужной высоты апоцентра вырубаем тягу.

4. Скругление орбиты
В апоцентре или недалеко от него делаем прожиг в направлении орбитальной скорости,
пока орбита не скруглится

5*. 
Запускаем новые ступени по необходимости


Эти этапы будем оформлять в виде функций. Функция задаётся следующим синтаксисом:
 function HelloName {
  parameter Name is "World".
  print "Hello, " + Name + "!".
}

Здесь задана функция с именем HelloName, которая имеет один аргумент и печатает его, присоединив впереди "Hello, " и в конце восклицание. В данном случае, аргумент функции необязателен, его значение по умолчанию "World".
Примеры использования:
HelloName("Kerbin"). // выведет "Hello, Kerbin!"
HelloName(). // выведет "Hello, World!"

Теперь напишем функции для контроля ориентации ракеты на всех этапах выхода на орбиту. Для начала идём по простейшему пути - взлетаем строго на восток, орбита получается экваториальная.

1. С вертикальным взлётом всё просто
function VertAscent {
  lock steering to heading(90,90).
}

2. Разворот по тангажу - самый сложный вопрос. Тут нужно соблюсти тонкий баланс между потерями на борьбу с силой тяжести и трением об атмосферу. Поэтому летим вверх до 15 км, потом ставим тангаж на 45. Я сам при ручном выводе до тангажа 45 градусов руководствовался величиной скорости, дальше - высотой апоцентра. Поэтому для скрипта выбрал ту же стратегию.
function GravityTurn {
  parameter vstart. // скорость, при которой начинается разворот
  parameter AP45. // апоцентр при тангаже 45 градусов
  parameter APstop is 60000. // апоцентр, по достижении которого ракета ложится горизонтально
  parameter v45 is 500. // скорость, при которой угол тангажа должен быть 45 градусов
  
  local vsm to velocity:surface:mag. // величина скорости относительно поверхности
  local pitch to 0.
  if ( vsm < v45 ) {
    set pitch to 90 - arctan( (vsm - vstart)/(v45 - vstart) ). // линейно менять тангаж от скорости оказалось плохо, по арктангенсу довольно неплохо получается
  }
  else {
    set pitch to max(0, (apoapsis - APstop) / (AP45 - APstop) ). // линейно меняем тангаж, на APstop укладываем ракету горизонтально
  }
  lock steering to heading( 90, pitch ).
  // возложим на kOS функции Kerbal Engineer
  print "Apoapsis: " + round( apoapsis/1000, 2 ) + " km    " at (0,30).
  print "Periapsis: " + round( periapsis/1000, 2 ) + " km    " at (0,31).
  print " Altitude: " + round( altitude/1000, 2 ) + " km    " at (24,30).
  print " Pitch: " + round( pitch ) + " deg  " at (24,31).
}

Переменные здесь вводятся ключевым словом local - это означает, что область видимости этих переменных ограничивается тем блоком кода, где они заданы. Это делается потому, что во внешней программе уже могут быть определены переменные с тем же именем, которые мы не хотим случайно поменять. Если же инициализировать переменную через set, то по умолчанию она инициализируется как глобальная, что в итоге может привести к интересным побочным эффектам. Аргументы функции по умолчанию рассматриваются как локальные имена.
Заметим, что функция держит нужное направление не только во время разворота, но и держит ракету горизонтально после него.
3. Отключить двигатель, когда апоцентр достиг нужного значения - опять просто.
function ShutdownAfterMaxAP {
  parameter APmax is body:atm:height + 10000. // по умолчанию считаем, что хотим подняться на 10 км выше атмосферы
  if apoapsis > APmax { lock throttle to 0. }
}

4. Чтобы закруглить орбиту, потребуется немного математики.
Предположим, мы находимся на эллиптической орбите на высоте h < HAp. Для перехода на круговую орбиту на той же высоте, нужно нашу текущую скорость V превратить в скорость круговой орбиты Vcirc (рис. 1).
Как скруглить орбиту

Рисунок 1. Схема перехода с эллиптической орбиты на круговую.

Скорость на круговой орбите известна - она направлена по нормали к поверхности в плоскости орбиты, а величина её равна
KerboScript в примерах и задачах. Часть 1. Выход на орбиту

Здесь RKerbin - это вектор из начала координат (в kOS, как помним, центр вселенной - это наш корабль) к центру Кербина. Нужное приращение ΔV равно разности Vcirc - V. Таким образом, если делать прожиг, постоянно направляя нос ракеты на вектор оставшейся скорости до круговой, то орбита будет в итоге скруглена (если хватит топлива). Реализуем это в коде:
function circularize {
  local th to 0. // в этой переменной будет необходимый уровень тяги
  local Vcircdir to vxcl( up:vector, velocity:orbit ):normalized. // направление круговой скорости такое же, как у горизонтальной компоненты орбитальной скорости
  local Vcircmag to sqrt(body:mu / body:position:mag). // mu - это гравитационный параметр планеты, произведение массы на гравитационную постоянную
  local Vcirc to Vcircmag*Vcircdir.
  local deltav to Vcirc - velocity:orbit.
  
  // начинаем прожиг, поворачивая ракету постоянно в сторону маневра
  lock steering to lookdirup( deltav, up:vector).
  wait until vang( facing:vector, deltav ) < 1. // убеждаемся, что прожиг начинается в нужной ориентации
  lock throttle to th.
  until deltav:mag < 0.05 {
    set Vcircdir to vxcl( up:vector, velocity:orbit ):normalized.
    set Vcircmag to sqrt(body:mu / body:position:mag).
    set Vcirc to Vcircmag*Vcircdir.
    set deltav to Vcirc - velocity:orbit.
    if vang( facing:vector, deltav ) > 5 { 
      set th to 0. // если сильно не туда смотрим, надо глушить двигатель
    }
    else {
      set th to min( 1, deltav:mag * ship:mass / ship:availablethrust ). // снижаем тягу, если приращение скорости нужно небольшое
    }
    wait 0.1.
  }
  set th to 0.
  set ship:control:pilotmainthrottle to 0.
  unlock throttle.
}

Теперь напишем программу, которая объединяет всё это в скрипт вывода.
function gettoorbit {
  parameter Horb to body:atm:height + 10000.
  parameter GTstart to 1000. // высота начала разворота
  parameter GTendAP to 60000. // заканчиваем разворот, когда апоцентр на этой высоте
  // запомним, как ракета стоит на столе, в этом положении взлетаем
  lock throttle to 1.
  local initialpos to ship:facing.
  lock steering to initialpos.
  startnextstage().
  until altitude > GTstart {
    VertAscent().
    if ship:availablethrust = 0 startnextstage().
    wait 0.01.
  }
  
  // запомним параметры для функции гравиразворота:
  local GTStartSpd to velocity:surface:mag. // при какой скорости начали разворот
  local Apo45 to apoapsis. // какой апоцентр был при тангаже 45 градусов
  local lock pitch to 90 - vang( up:vector, velocity:surface ). // переменная с тем же именем, что и в другой функции
  // т.к. объявлена локально, конфликта имён возникать не должно
  until altitude > body:atm:height {
    if pitch >= 45 { set Apo45 to apoapsis. } // перестанет обновляться после тангажа 45 градусов - то, что требуется
    GravityTurn(GTStartSpd,Apo45,GTendAP).
    ShutdownAfterMaxAP(Horb).
    startnextstage().
    wait 0.01.
  }
  // ждём, пока не подобрались к апоцентру
  until altitude > Horb - 500 {
    lock steering to prograde.
    wait 0.01.
  }
  // скругляем (функция внутри не проверяет, хватит ли на это топлива - должен быть запас!)
  circularize().
  print "We are in orbit: " + round(apoapsis,2) + "x" + round(periapsis,2) + " km. Releasing the payload. ".
  
  lock steering to prograde.
  stage.
  wait 1.
  stage.
}

Пришло время протестировать предлагаемый метод вывода.
Для этого я сделал простой крафт:
Тестовый крафт для вывода на орбиту

Рисунок 2. Аппарат для тестирования вывода на орбиту.

Все функции нужно скопировать в файл (пусть будет KSPutnik.ks), который поместить в папку Ships/Script. После определения всех функций не забыть написать
gettoorbit().

для запуска собственно полёта. На стартовом столе открываем kOS терминал, пишем
copypath("0:/KSPutnik.ks","KSPutnik.ks").
runpath("KSPutnik.ks").

Наслаждаемся мультиком.
В полёте

Рисунок 3. Разворот надо бы сделать чуть менее агрессивным.

К сожалению, в конце антенны спутника оказываются свёрнутыми. Чтобы это исправить, после сброса обтекателя надо добавить следующий код:

  set alist to ship:partsnamed("longAntenna").
  for an in alist {
    set d to an:getmodule("ModuleRTAntenna").
    d:doevent("activate").
  }

Первая строчка создаёт список всех частей аппарата с заданным именем (имя можно посмотреть в ЦВС по ПКМ на часть - "Change Name Tag"). Далее проходим циклом по всем антеннам и раскрываем их. Сам я пока эту чёрную магию не совсем понимаю, интересующиеся могут почитать официальное руководство.

С обновлённой циклограммой запуска спутник выходит на орбиту, разворачивает антенны и отделяется от носителя и работает как ретранслятор для последующих запусков. Сброшенная ступень остаётся космическим мусором. Спутник в этом тоже к ней присоединится когда у него закончится электричество.

Итак, теперь написан достаточно универсальный скрипт для вывода спутника на экваториальную орбиту. В следующей части - простейшее орбитальное маневрирование и развёртывание группировки спутников-ретрансляторов.

Крафт и скрипт вывода (переименовать .ks.txt в .ks):
KerboScript в примерах и задачах. Часть 3. Предсказание орбиты. Летим на Муну.
5 апр 2017 в 21:21, Гайды
KerboScript в примерах и задачах. Часть 2. Простейшие орбитальные манёвры
26 мар 2017 в 21:56, Гайды
  1. Soul

    Soul @Павел Гладилов 25 марта 2017 23:17

    А файлы/листинги примеров будут?

    1. Pand5461

      Pand5461 25 марта 2017 23:19 Автор

      Под спойлером в самом конце.

      1. Soul

        Soul @Павел Гладилов 25 марта 2017 23:24

        Цитата: Pand5461
        Под спойлером в самом конце.

        Спасибо за ответ, сразу не увидел, пардон.

  2. Nexsius

    Nexsius @Сергей 27 апреля 2017 15:12

    Хм. Я видимо совсем неудачник... Скачал крафт и скрипт, а оно не летает...
    Стартовать стартует, но в последствии начинает переворачиваться и крутиться :( что я делаю не так?

{login}
  • bowtiesmilelaughingblushsmileyrelaxedsmirk
    heart_eyeskissing_heartkissing_closed_eyesflushedrelievedsatisfiedgrin
    winkstuck_out_tongue_winking_eyestuck_out_tongue_closed_eyesgrinningkissingstuck_out_tonguesleeping
    worriedfrowninganguishedopen_mouthgrimacingconfusedhushed
    expressionlessunamusedsweat_smilesweatdisappointed_relievedwearypensive
    disappointedconfoundedfearfulcold_sweatperseverecrysob
    joyastonishedscreamtired_faceangryragetriumph
    sleepyyummasksunglassesdizzy_faceimpsmiling_imp
    neutral_faceno_mouthinnocent
Последние сообщения с форума
  • Автор
    Тема в разделе: В ангаре у Боба
    Просмотров: 7401
    Ответов: 55
  • Автор
    Тема в разделе: Технические вопросы
    Просмотров: 24643
    Ответов: 68
  • Автор
    Тема в разделе: Моды
    Просмотров: 1539
    Ответов: 2
  • Автор
    Тема в разделе: В ангаре у Боба
    Просмотров: 207225
    Ответов: 1484
  • Автор
    Тема в разделе: Игровой процесс
    Просмотров: 1832
    Ответов: 1
    Все сообщения..
    Полный список последних сообщений
    Loading...

    Нашли ошибку?
    Вы можете сообщить об этом администрации.
    Выделив текст нажмите Ctrl+Alt