Автор: Pand5461 Категория: Kerbal Space Program » Гайды

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

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

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


При ручном управлении вывод ракеты на орбиту состоит из четырёх основных этапов:
  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):

  1. 0
    Это Soul Soul - #10 0
    -9
    А файлы/листинги примеров будут?
    »
    Написано:
    Группа: Посетители, Публ/Комм: 0/33
     
    1. 9
      Это Pand5461 Pand5461 - #20 0
      +1
      Под спойлером в самом конце.
      »
      Написано:
      Группа: Модераторы, Публ/Комм: 13/77
      Мои kOS скрипты: https://github.com/pand5461/kOS
       
      1. 0
        Это Soul Soul - #30 0
        -9
        Цитата: Pand5461
        Под спойлером в самом конце.

        Спасибо за ответ, сразу не увидел, пардон.
        »
        Написано:
        Группа: Посетители, Публ/Комм: 0/33
         
  2. 0
    Это Nexsius Nexsius - #40 0
    0
    Хм. Я видимо совсем неудачник... Скачал крафт и скрипт, а оно не летает...
    Стартовать стартует, но в последствии начинает переворачиваться и крутиться :( что я делаю не так?
    »
    Написано:
    Группа: Посетители, Публ/Комм: 0/1
     
Информация
Посетители, находящиеся в группе Гости, не могут оставлять комментарии к данной публикации.
Чат
  • Опрос
  • Стримы
    Куда пойти, если сайт упал?
Последние комментарии
  • Lynx Lynx написал в
    JC-1 (SpacePlaza) (всего 17 комм.)
    Почитал я про нитрометан - разлагается с выделением температуры. В каком он там месте одновременно окислитель и восстановитель содержит непонятно, это не смесь, а чистое вещество.
  • Vovanm88 Vovanm88 написал в
    JC-1 (SpacePlaza) (всего 17 комм.)
    По вики правильно то, что и перекись и гидразин и нитрометан(и прочая) дичь - все монотопливо, оба monopropellant, а что такое monofuel - нипанятно, но судя по поисковой выдаче слово более применимо к нитрометану, и вообще используется в испаноязычных странах
  • Lynx Lynx написал в
    JC-1 (SpacePlaza) (всего 17 комм.)
    Нормальный гуманитарий и словарь нормальный напишет.
    Может правильно и так и так, лишь бы вещество ОДНО было?
    А еще может есть разница между monofuel и monopropellant?
  • Pand5461 Pand5461 написал в
    JC-1 (SpacePlaza) (всего 17 комм.)
    Таки если словарь пишут гуманитарии, то

    Definition of monopropellant
    : a rocket propellant containing both the fuel and the oxidizer in a single substance

    (https://www.merriam-webster.com/dictionary/monopropellant)
    Но я всё-таки в том лагере, что считает, что однокомпонентное топливо не "сгорает в самом себе", а разлагается с выделением тепла.
  • Vovanm88 Vovanm88 написал в
    JC-1 (SpacePlaza) (всего 17 комм.)
    ny partially nitrated alcohol esters are suitable for use as monopropellants. "Trimethylene glycol dinitrate" or 1,3-propanediol dinitrate is isomeric with PGDN, and produced as a fractional byproduct in all but the most exacting laboratory conditions; the marginally lower specific gravity (and thus energy density) of this compound argues against its use, but the minor differences in chemistry may prove useful in the future.[citation needed]

    The related "dinitrodiglycol", more properly termed diethylene glycol dinitrate in modern notation, was widely used in World War 2 Germany, both alone as a liquid monopropellant and colloidal with nitrocellulose as a solid propellant. The otherwise desirable characteristics of this compound; it is quite stable, easy to manufacture, and has a very high energy density; are marred by a high freeze point (-11.5 deg. C) and pronounced thermal expansion, both being problematic in spacecraft. "Dinitrochlorohydrin" and "tetranitrodiglycerin" are also likely candidates, though no current use is known. The polynitrates of long chain and aromatic hydrocarbons are invariably room temperature solids, but many are soluble in simple alcohols or ethers in high proportion, and may be useful in this state.


    вот хотя бы
  • Marschig Marschig написал в
    JC-1 (SpacePlaza) (всего 17 комм.)
    Не "наверное", а совершенно точно греет.
    The most common use of monopropellants is in low-impulse rocket motors, such as reaction control thrusters, the usual propellant being hydrazine which is generally decomposed by exposure to an iridium catalyst bed (the hydrazine is pre-heated to keep the reactant liquid). This decomposition produces the desired jet of hot gas and thus thrust.
Все комментарии
Обновления на форуме
103 Всего
1 Польз.
102 Гостей
Яндекс, Alexa, Google, doroppyyn2
Онлайн список
Новостей на страницу:
Наверх