Skip to content

Latest commit

 

History

History
266 lines (167 loc) · 19.2 KB

manual.mkd

File metadata and controls

266 lines (167 loc) · 19.2 KB

Manual

Meet Bob Kerman

Although Bob might not be such a superstar as Jebediah, he's a very good astronaut. While Jeb is trashing about with rockets willy nilly, Bob likes to plan things in advance; be prepared; know exactly when and where to burn to get things done efficiently. Bill suggested using the autopilot, but Bob is oldschool, Bob wants to figure stuff out for himself. Bob brought along his trusty Kerbulator, which he will program himself!

This manual will follow Bob as he creates a function that will circularize his current orbit. Along the way we will go over all the different features of Kerbulator.

Bob is flying... in space!

Bob is inside a spacecraft orbiting his home planet Kerbin. He is in an elliptical orbit, as the map view shows:

Bob's orbit

He would like to calculate at which time to turn on his engines and how much Δv he should burn to circularize his orbit.

Starting Kerbulator

Bob notices, when he's flying, the Kerbulator button (+ - × ÷ in a square) in the upper right hand corner of the screen. Therefore he knows his Kerbulator was installed properly. He presses this button and window appears with a list of all the available functions. As this is his first time running Kerbulator, the list is empty. Bob wouldn't have it any other way. He will program his own mathematical equations into the thing. Encouragingly, there are two buttons at the bottom of this list: New function and New maneuver. Both buttons will create new functions, although the New function button will create an empty function and the New maneuver button will create a function that already has a bit of programming code: the code required to be able to place a maneuver node using the function. Bob dives in and creates his first function.

Writing functions

Functions are the bread and butter of Kerbulator. A function is a piece of programming code that performs a calculation to produce some result, called the output. Often, a function not only has an output, but also an input. Sometimes a function has multiple inputs and sometimes even multiple outputs! If we want to do any computation with Kerbulator, we have to create a function to do it in. Then, we write a little piece of programming code (that looks a lot like math) to perform the calculation we want.

Bob wants to start simple by calculating 1+1. He clicks the New function button, which opens an editor window. There are some buttons there. The delete button (trashcan icon) will delete the function. The save button (disk icon) will save the function to disk, so you can access it later. The run button (triangle in circle icon) will execute the function and actually do the computation. There is also a sort of keyboard at the bottom which helps Bob enter greek and mathematical symbols as his keyboard does not have keys for those. That leaves a textfield containing the name of the function (currently unnamed) and a big text area where Bob can write the actual programming code.

Bob writes into the big text area:

x = 1 + 1

and stares at its beautiful simplicity.

Some nomenclature

The letter x is a variable: a little piece of computer memory that can hold a number (or list as we'll see later). The = sign means that x is going to be assigned a new value. The rest is called an 'expression'. An expression is a piece of math that yields a result, in this case the sum of 1 and 1. The + sign is called an 'operator' and Kerbulator has a lot of them to do perform lot of different mathematical operations. They are all listed in the 'Operators' section of the language reference. The entire line together is called a 'statement'.

Naming and saving functions

Bob feels that unnamed is not the proper name for such a beautiful formula and flips to the section 'Identifiers' of the language reference. He notes that functions (and variables for that matter) can have any name, as long as this name doesn't contain any forbidden characters, which are: spaces and any of # + - / ÷ * × · ^ √ % : = ( ) [ ] { } ⌊ ⌋ ⌈ ⌉ | because they have a special meaning in the Kerbulator programming language. Also, they cannot start with a dot and also cannot start with a number. They may contain dots and numbers, just not as the first character of the name. Bob names his function simple_sum and saves it. He notices that the function simple_sum is now available in the function list on the left. When he clicks the function name some info is given about the function.

Running functions

Bob hits the run button (a triangle inside a circle) next to the simple_sum function in the main window. He could also have pressed the run button in the editor for the same effect. A new window appears (called the run window) and behold: it shows x=2, which is the correct answer. He can choose to run the function again by pressing the run button in either the run window, editor window or main window. Bob is pleased to find out the function always reliably produces x=2, whichever run button was pressed.

A more complicated function

Bob gets out a piece of paper en draws on it the following:

v = sqrt( M*G * (2/r - 2 / (Pe+Ap)) )

This is the formula that describes the speed of an object in orbit of a planet. The variables in the formula mean:

Variable Meaning
M Mass of the planet in kilograms
G The gravitational constant: 6.67384 × 10^(-11)
r Distance (in meters) from the object in orbit to the center of the planet
r_min Distance (in meters) from the center of the planet to the periapsis of the orbit
r_max Distance (in meters) from the center of the planet to the apoapsis of the orbit

Bob presses the New function button, names the function current_velocity and, after glancing at his instruments, types the following:

M = 5.2915793E22
G = 6.673834E-11
R = 600E3
r = R + 2940E3
r_min = R + 309216
r_max = R + 4823113

v = √( M*G * (2/r - 2 / (r_min + r_max)) )

This function begins by initializing a whole bunch of variables to different values. Note that Kerbulator supports scientific notation, which simplifies writing down very big and very small numbers. Next, the variables are used to compute the current speed v of Bob's craft. He presses the run button and sees that the speed calculated by Kerbulator is exactly the speed indicated by his instruments. Bob is very smart and of course his formula is correct. Bob notices however that it would be nice to attach some notes to his function, explaining what all those variables mean. Whenever you type a # mark, this mark and anything following it is completely ignored by Kerbulator up to the end of the line. Bob changes his current_velocity function to the following:

M = 5.2915793E22    # Mass of Kerbin
G = 6.673834E-11    # Gravitational constant
R = 600E3           # Radius of Kerbin (distance from center of planet to sea level)
r = R + 2940E3      # I'm flying at 2940 km above Kerbin sea level
r_min = R + 309216  # My periapsis is 309.216 km above Kerbin sea level
r_max = R + 4823113 # My apoapsis is 4823113 km above Kerbin sea level

# Formula describing the speed of an object orbiting a planet
v = √( M*G * (2/r - 2 / (r_min + r_max)) )

It is starting to look pretty. By the way, every line of the function is a 'statement'. A statement always assigns the result of an expression to a variable. A statement containing just the expression 1 + 1 by itself would be invalid, for example, as would something like = 1 + 1.

Using globals

Bob is annoyed that he has to look at his instruments and type in numbers every time he wishes to use the current_velocity function. Luckily, Kerbulator strives to make all the numbers visible in KSP available to the programmer. It does so by defining a long list of 'globals': variables that are predefined by Kerbulator and available in every function. After taking a look at the complete list of globals, Bob modifies his function:

M = Parent.M      # Mass of the parent body we're orbiting
# G is already defined by Kerbulator, hooray!
R = Parent.R      # Radius of the parent body we're orbiting
r = R + Craft.Alt # My current altitude
r_min = R + Craft.Pe # My periapsis
r_max = R + Craft.Ap # My apoapsis

# Formula describing the speed of an object orbiting a planet
v = √( M*G * (2/r - 2 / (r_min + r_max)) )

Bob can now run his function and everytime he does, the function will give his current velocity with great precision.

Specifying inputs and outputs

Although being able to calculate his current velocity greatly pleases Bob, he's not done yet. He makes another drawing on his piece of paper:

plan for circularization of orbit

This is Bob's plan: he's going to burn at apoapsis in order to circularize his orbit. This answers the question when he should burn: whenever he reaches apoapsis (a value given by the KSP map interface and therefore also accessible as a global in Kerbulator). Now to answer how much Δv to burn for when he reaches apoapsis. The answer is: the difference between however fast Bob's going when he reaches apoapsis and how fast he should be going were he in a circular orbit. This involves calculating the speed of two different orbits. Of course, Bob could write two different functions for each of them, but he finds it much more pleasing to write a single function that can calculate the speed of an object in any orbit. For this, he's going to use two features called 'function inputs' and 'function outputs'. He clicks the New function button once more, names the function orbital_velocity and types:

in: Pe "Periapsis of the orbit"
in: Ap "Apoapsis of the orbit"
in: Alt "Current altitude"
out: v "Current velocity of object" 

M = Parent.M   # Mass of the parent body we're orbiting
# G is already defined by Kerbulator, hooray!
R = Parent.R   # Radius of the parent body we're orbiting

r_min = R + Pe # Height of periapsis measured from planet center
r_max = R + Ap # Height of apoapsis measured from planet center
r = R + Alt    # Current altitude measured from planet center

# Formula describing the speed of an object orbiting a planet
v = √( M*G * (2/r - 2 / (Pe + Ap + 2*R)) )

Inputs are values that are not defined in the function itself and are not globals given by Kerbulator, but have to be supplied when running the function. Outputs are values the function produces. When you don't define any outputs, the last statement of the function will be taken as implicit output. Functions can have multiple inputs and outputs. First, all of the inputs are described: each on its own line in the form of in: <identifier> "<description>", then all of the outputs are described: again each on its own line and in the form of out: <identifier> "<description>". The "<description>" parts are optional, although useful to document your functions. Inputs must always be described first and then the outputs and then all of the statements of the function. For example, this is wrong:

out: c
in: a
c = √(a^2 + b^2)
in: b

Bob is excited about his multi-purpose orbital_velocity function and wants to try it out. Pressing the run button opens the run window, which now presents some text boxes to enter the input variables to the function. Other than simple numbers, you can type expressions in these boxes, including globals. Bob enters Parent.R + Craft.Pe in the box labeled Pe, Parent.R + Craft.Ap in the box labeled Ap and Parent.R + Craft.Alt in the box labeled Alt. Satisfied that the function works properly, Bob is ready to chain multiple functions together.

Calling functions from functions

By calling the orbital_velocity function from inside another function, Bob can complete his computation. He creates a new function called circularize and writes:

out: Δv "Amount of Δv to burn for"
out: Δt "Time at which to initiate burn (0 means right now)"

# Calculate our velocity when we reach apoapsis
v1 = orbital_velocity(Craft.Pe, Craft.Ap, Craft.Ap)

# Calculate how fast we should be going were we in a circular orbit
v2 = orbital_velocity(Craft.Ap, Craft.Ap, Craft.Ap)

# Calculate Δv required to circularize our orbit
Δv = v2 - v1

# Burn at apoapsis. Kerbulator has a global for this.
Δt = Craft.TimeToAp

He saves his function and presses the Run button. Behold! Kerbulator faithfully spits out a Δv and Δt value: the two outputs he had defined. Note that the other variables are discarded, never to be heard from again outside of their function. With these values Bob is able to circularize his orbit! Lets take a look at the 'function calls' that Bob has just made. He 'calls' the function orbital_velocity two times, each time with slightly different inputs. To call a function you usually write <function name>(input1, input2, ...). This form will work every time, but take a look at the other ways to call a function in the language reference. Also, take a look at the build-in functions that Kerbulator provides for you. The ability to call functions that call functions that call functions, etc., gives Kerbulator the ability to do very complex computations.

Creating maneuver nodes

Bob is just about to create a maneuver node manually when he realizes that Kerbulator has the ability to create it for him. However, he needs to make a small change to his code. In the same manner as he defined the inputs and outputs, Bob can define maneuvers at the top of the function by writing maneuver: <identifier> "<description>". When Kerbulator is asked to create a node based on the result of a function, it runs the function and then takes a look at which variables are flagged as describing maneuvers. A maneuver variable needs to be a list of four values in the form of: [Δv_p, Δv_n, Δv_r, Δt], where the values mean:

Value Description
Δv_p Change in velocity in the prograde direction (straight ahead)
Δv_n Change in velocity in the normal direction (up)
Δv_r Change in velocity in the radial direction (away from the planet)
Δt Time at which to perform the burn (where 0 means right now)

All these values may be negative, except for value 4 (Δt); creating nodes in the past really confuses KSP so Kerbulator will not do it. Also, not all of these have to be defined by the function.

For Bob's function to be able to create a maneuver nodes, he first declares the maneuver variable at the top and assigns a list to the variable at the bottom:

out: Δv "Amount of Δv to burn for"
out: Δt "Time at which to initiate burn (0 means right now)"
maneuver: circularize "Maneuver to perform the circularization burn"

# Calculate our velocity when we reach apoapsis
v1 = orbital_velocity(Craft.Pe, Craft.Ap, Craft.Ap)

# Calculate how fast we should be going were we in a circular orbit
v2 = orbital_velocity(Craft.Ap, Craft.Ap, Craft.Ap)

# Calculate Δv required to circularize our orbit
Δv = v2 - v1

# Burn at apoapsis. Kerbulator has a global for this.
Δt = Craft.TimeToAp

# Information to create a maneuver node.
circularize = [Δv, 0, 0, Δt]

Now Bob can press the node button (maneuver node icon) in the run window in order to create the node. Happy flying Bob!

Calling functions with multiple outputs

What if Bob ever wants to call his circularize function from inside another function? He could write:

Δv, Δt = circularize()

Notice that there are multiple variable names on the left side of the = symbol. The outputs of the function are returned as a 'list'. This list is 'unpacked' into the variables you specify on the left hand side. Lets take a closer look at lists:

Lists

A list is a sequence of 'elements', where an element is usually a number, but can also be a list itself. Here are some examples of how to denote lists:

x = [1,2,3]         # Assign a list of three elements 1,2 and 3 to a variable
x = [1+1, 2+2, 3+3] # A list of three elements, 2, 4 and 6
x = [a,b]           # A list containing the values of 'a' and 'b'
x = [1]             # A list containing only one value

x = [[1,2,3], [4,5,6]]  # A list containing two lists
x = [1, [4,5,6]]        # A list containing a number and a list

a = [1,2,3]
vec1_num_elements = len(a) # Number of elements in a list (3 in this case)
x,y,z = a                  # Use value unpacking to access the individual members of a list

For all the cool things you can do with lists, take a look at what the language reference has to say about them. For example, you can do vector math:

vec1 = [1, 2, 1] # Some vector
vec2 = [2, 2, 2] # Some other vector

vec1_magnitude = |vec1|  # Magnitude of a vector

vec3 = dot(vec1, vec2) # Dot product between two vectors 
vec3 = cross(vec1, vec2) # Cross product between two vectors 

mat1 = [[1, 2, 3], [4, 5, 6]] # A matrix
mat2 = dot(mat1, mat1) # Dot product between two matrices

Writing functions in your own editor

Bob likes the little editor inside KSP, because it gives quick access to Greek and math symbols to make his formulae look pretty. However, when writing very long functions, you may want to use some other editor. Kerbulator stores its functions in a folder on your disk. The location depends on your KSP installation:

{KSP folder}/PluginData/Kerbulator

Everytime you switch from KSP to some other window, Kerbulator makes sure the files on your disk are up to date. Then, when returning to the KSP window, Kerbulator reloads the functions from disk. Any editing you've done on those files (and any new files you've created) will be picked up by Kerbulator. Functions are text files in UTF-8 encoding with the extention .math.

Legacy save folder location

If you were using Kerbulator 0.32 or earlier, you must manually move your functions file to the new save folder location. This legacy location depends on your operative system:

Platform Location
Windows C:/Users/{username}/AppData/LocalLow/Squad/Kerbal Space Program/Kerbulator
OSX /Users/{username}/Library/Caches/unity.Squad.Kerbal Space Program/Kerbulator
Linux /home/{username}/.config/unity3d/Squad/Kerbal Space Program/Kerbulator

Using the numeric solver

In orbital mechanics, lots of problems crop up where no analytical solution is possible. One such example is the calculation of the true anomaly of an object. Kerbulator ships with an algorithm to approximate a solution in this case (see also the language reference). It is invoked like this:

x: x + 5 = 10

which will try to find a value for x so that the equation holds.

Creating alarms

If Bob brings his trusty Kerbal Alarm Clock, he can use Kerbulator to set an alarm, based on some calculation. This works similarly to creating maneuver nodes, by writing alarm: <identifier> "<description>". Alarm outputs are given at global game time. By using the UT global value, relative times are also usable like so:

someAlarm = UT + Δt

Name Description
Δt Alarm will be set Δt seconds from now
UT A global value returning the current time in global game time