# [1.3] kOS Scriptable Autopilot System v1.1.3.0

## Recommended Posts

There is a way to get a combined value for drag and lift.

You use:

total force = mass * acceleration

total force = engine thrust + force due to gravity + lift&drag

this gives

lift&drag = mass * (acceleration - gravity) - thrust

This is actually an approximation and is only valid when mass is constant. The actual definition is ÃŽÂ£F = dp/dt. In a situation with varying mass such as a rocket, dp/dt = m(dv/dt) + (dm/dt)v.

Thus ÃŽÂ£F = (instantaneous mass)(acceleration) + (mass flow rate)(instantaneous velocity) = (engine thrust) + (instantaneous mass)(gravity) + (lift) + (drag).

Thus (Lift) + (Drag) = (instantaneous mass)(acceleration) + (mass flow rate)(velocity) - (engine thrust) - (instantaneous mass)(Gravity).

One can assume lift to be 0, since rockets are typically fly without wings and with no sideslip angle to generate body lift.

Thus (Drag) = (instantaneous mass)(acceleration) + (mass flow rate)(velocity) - (engine thrust) - (instantaneous mass)(Gravity).

And Thus (Drag) = (instantaneous mass)(acceleration - gravity) - (engine thrust) + (mass flow rate)(velocity).

(Bolded values are vectors, just for my own bookkeeping. Might also be helpful for anyone who needs to calculate vector drag.)

Thankfully, since the aero update, mass flow rate through an engine is constant for any given throttle value, so that simplifies things a little bit. Mass flow rate = (Thrust)/(Specific Impulse)(g), where g = 9.802m/s^2 always. The ratio of thrust to specific impulse is constant, so you can just plug in the sea level thrust and ISP numbers to calculate this. Or the vaccum numbers, those will work too. Thus to calculate this, we get something like:

`ISP = <someValue> //You'll need to specify this yourself unless you want to grab engines from the list() function and pull the ISP from that. (Hint: it's easier to just plug this one in.)mDot is vessel:maxthrustat(1)/(ISP*9.802) //Note that thrust used is sea level thrust. Use corresponding ISP value.function drag{    local drag is ship:mass*(ship:acc:mag - ship:grav:mag/9.802) - vessel:maxthrustat(vessel:pres) + mDot*ship:velocity:mag. //Drag calculated is scalar and not vector since drag /should/ always be oriented opposite ship:up. If you need vector drag you can do that yourself.    return drag.}`

And you can call the drag() function as needed.

And to answer your question Qigon; yes, thrust is technically a vector, though it is usually convenient to treat it like a scalar since it is (almost) always pointing through the center of mass of the rocket.

Edited by VFB1210

##### Share on other sites

I've been having a lot of fun writing my own launch script for this plugin

My goal has been to be able to write a script that works for all rockets of all shapes and sizes without having to input different numbers to the code. I want to be able to just run the launch program and go.

Everything works well. I even managed to get it to detect solid fuel boosters and stage accordingly (see script below). Full disclosure, this is heavily based off of the first tutorial script on the KOS documentation site as well as a few other scripts I found on the web.

My problem is that no matter what I try I can't figure out how to get the script to recognise if the ship has any liquid fuelled boosters. I thought I could write something to work out when the first stage lost some thrust but I could not get it to work. Bearing in mind I would have liked to make this a one size fits all script

Cheers.

//My First Launch Script

//Initialise variables.

set targetApoapsis to 100000.

set targetPeriapsis to 100000.

set TVAL to 1.0.

set stageLF to 0.

set stageLFBoost to 0.

set actionInt to 0.

set messageInt to 0.

if SHIP:SOLIDFUEL > 1000 {

set stageSF to 1.

}

else {

set stageSF to 0.

}

if ship:altitude > 70000 { //Abort script if run in orbit/out of atmo.

set runMode to 10.

}

//Prep ship for launch.

clearScreen.

wait 1.

print "Launch sequence initialised, beginning systems check...".

print " ".

wait 1.5.

SAS on.

wait 1.5.

SAS off.

print "Guidance - GO.".

print " ".

wait 1.5.

lock throttle to 0.0.

print "LF Booster - GO.".

print " ".

if stageSF = 1 {

wait 1.5.

print "SF Booster - GO.".

print " ".

}

wait 1.5.

GEAR off.

print "Landing - GO.".

print " ".

wait 1.5.

lights on.

print "Recovery - GO.".

print " ".

wait 2.

print "We are GO for launch.".

print " ".

wait 3.

clearScreen.

print "T minus 10 seconds.".

print " ".

FROM {local countdown is 10.} UNTIL countdown = 3 STEP {SET countdown to countdown -1.} DO {PRINT "- " + countdown.

wait 1. //Pauses the script here for 1 second

}

print "- 3".

print " ".

PRINT "Engine Ignition Sequence.".

print " ".

WAIT 1.

PRINT "- 2".

LOCK THROTTLE TO TVAL. //1.0 is the max, 0.0 is idle.

WAIT 1.

PRINT "- 1".

print " ".

WAIT 1. //Give throttle time to adjust.

STAGE.

WAIT 1.5.

PRINT "Lift-off!".

print " ".

set runMode to 1.

set mecoInt to 0.

until runMode = 0 {

if runMode = 1 AND ship:altitude >= 500 { //Initial ascent & roll program.

print "Beginning roll program.".

print " ".

set runMode to 2.

}

else if runMode = 2 { //start of gravity turn

if SHIP:ALTITUDE >= 1500 {

print "Beginning gravity turn.".

print " ".

set runMode to 3.

}

}

else if runMode = 3 {

set targetPitch to max(5, 90 * (1 - SHIP:ALTITUDE / 42000)).

if SHIP:ALTITUDE >= 5000 AND stageLF = 0 {

set TVAL to max(0.75, 1 * (1 - SHIP:ALTITUDE / 60000)).

}

if SHIP:ALTITUDE > 20000 AND stageLF = 0 {

set TVAL to 0.75.

}

if SHIP:ALTITUDE > 32000 AND actionInt = 0 {

AG1 on.

print "Tower check!".

print " ".

set actionInt to 1.

}

if SHIP:APOAPSIS >= targetApoapsis {

set runMode to 4.

}

}

else if runMode = 4 {

set TVAL to 0.

if (SHIP:ALTITUDE > 70100) AND (ETA:APOAPSIS > 60) AND (VERTICALSPEED > 0) {

if WARP = 0 {

unlock steering.

SAS on.

wait 1.5.

set WARPMODE to "RAILS".

wait 0.5.

set WARP to 3.

set messageInt to 1.

if messageInt = 1 {

print "Warping to apoapsis.".

print " ".

set messageInt to 0.

}

}

}

else if ETA:APOAPSIS < 60 {

set WARP to 0.

SAS off.

wait 0.5.

set runMode to 5.

}

}

else if runMode = 5 {

if (ETA:APOAPSIS < 5) OR (VERTICALSPEED < 0) {

set TVAL to 1.

if messageInt = 2 {

print "Beginning CIRC manoeuvre.".

print " ".

}

}

if (SHIP:PERIAPSIS > targetPeriapsis) OR (SHIP:PERIAPSIS > targetApoapsis * 0.95) {

set TVAL to 0.

set runMode to 10.

}

}

else if runMode = 10 {

set TVAL to 0.

SAS on.

unlock steering.

wait 2.

clearScreen.

print "Orbit complete, systems released, manual control restored.".

print " ".

set runMode to 0.

}

//Staging & Throttle control.

if stage:kerosene < 1.0 AND stageLF = 0 {

wait 0.5.

stage.

print "First stage separation confirmed.".

print " ".

set TVAL to 1.

wait 2.5.

stage.

set stageLF to 1.

print "Second stage ignition.".

print " ".

}

if stage:SOLIDFUEL < 1.0 and stageSF = 1 {

wait 0.5.

stage.

print "Solid booster separation confirmed.".

print " ".

set stageSF to 2.

}

if TVAL = 0 AND mecoInt = 0 {

PRINT "M.E.C.O.".

print " ".

set mecoInt to 1.

}

if TVAL > 0 AND mecoInt = 1 {

set mecoInt to 0.

}

set finalTVAL to TVAL.

lock throttle to finalTVAL.

//wait 0.1.

}

##### Share on other sites

@VFB1210

Was not sure if ksp took into account mass loss during a physics tick or just assumed constant mass during a tick (for optimization as it was doing the calculation so frequently). I always seem to lose out (dV wise) under phys-warp, I assumed this was because i was carrying the mass for longer.

If it doesn't then assuming this as this is being done live (hopefully during a single physics tick) then mass is constant, otherwise yes you are right it could do with taking it into account.

On the subject of the lift always being 0. I was planing to provide a combined vector (or a list of the 2) as the result so that people using it for planes (or vessels with significant body lift) would not have to run 2 separate (but almost identical) functions for the vectors, since the calculation only differs in the final stage.

Edit:

My problem is that no matter what I try I can't figure out how to get the script to recognise if the ship has any liquid fuelled boosters.

There are a number of ways to do it.

You can look at stage:liquidfuel in the same way that you are using stage:solidfuel . but this wont work for asparagus staging.

You can also look at drops in maxthrust. (this means that an engine has shut down) so

`//at the start of the script.set old_maxthrust to 0.// staging logicIf round(ship:maxthrust,2) > old_maxthrust {           // The rounding is done to prevent accidental staging due to floating point errors / tiny differences in maxthrust set old_maxthrust to round(ship:maxthrust,2).} else if round(ship:maxthrust,2) < old_maxthrust{ stage. wait 0.1. set old_maxthrust to round(ship:maxthrust,2).}.`

One advantage of this is that it does not need to differentiate between liquid or solid engines and it works for asparagus staiging. In the above form it requires the engines to be in the same stage as the decouplers, this can be changed but the code becomes more complex.

One major thing this cant handle is drop tanks (eg the big orange tank on the space shuttle).

An older method I used for this was to repeatedly re-list the engines and check for flame-outs but that has the same disadvantages as the maxthrust method and requires constant refreshing of a list.

If you need to handle drop tanks. it is possible to have kOS navigate the part tree and look at the state of fuel tanks on the other side of decouplers, activating the decoupler if all the fuel is gone.

Edit 3: (someone else post please so I donÃ¢â‚¬â„¢t have to keep doing this with edits)

Drag calculated is scalar and not vector since drag /should/ always be oriented opposite ship:up.

Drag would always be opposite the direction of travel (prograde) if you calculate it using ship:facing then it would show less drag when pancaking :-P

Edited by TDW

##### Share on other sites

^The only issue I see with that is that it would be extremely difficult to calculate lift from wings. Body lift is easy enough, as it is essentially just the component of drag working opposite the direction of gravity.

In fact, looking back at the code now, getting vector drag is literally as simple as dropping the :mag tags and multiplying the thrust by the unit vector along ship:up. For some reason I decided it would be more complicated than that and got lazy.

`ISP is <someValue> //You'll need to specify this yourself unless you want to grab engines from the list() function and pull the ISP from that. (Hint: it's easier to just plug this one in.)mDot is vessel:maxthrustat(1)/(ISP*9.802) //Note that thrust used is sea level thrust. Use corresponding ISP value.function drag{    local drag is ship:mass*(ship:acc - ship:grav/9.802) - vessel:maxthrustat(vessel:pres)*ship:up + mDot*ship:velocity.    return drag.}function bodyLift{    local localUp is -kerbin:position:normalized. //Kerbin:position returns a vector from the ship to the center of Kerbin, constituting the local "down" direction. Opposite of this is the local "up." Key here is that it points in the exact opposite direction of gravity.    local bodyLift is vdot(drag(),localUp). //Calculate component of of drag working against gravity-aka body lift.    return localUp*bodyLift. //Project onto localUp.}`

Of course, this wouldn't quite work in a situation where the body is generating significant amounts of lift via the bernoulli effect, but it should be at least somewhat useful.

##### Share on other sites

@VFB1210

Ok I think i am missing something here. I have:

`ÃŽÂ£F = F[SUB]1[/SUB] + F[SUB]2[/SUB] + F[SUB]3[/SUB]ÃŽÂ£F = M * a + (dm/dt)vWhere:F[SUB]1 [/SUB]= ThrustF[SUB]2[/SUB] = force due to gravity = M * grav + (dm/dt)v[SUB]vertical[/SUB] // don't the changing mass apply to the force due to gravity too.F[SUB]3[/SUB] = Drag and liftRearranged to:F[SUB]3[/SUB] = M * a + (dm/dt)v - F[SUB]1[/SUB] - M * grav - (dm/dt)v[SUB]vertical  [/SUB]|  (dm/dt)v - (dm/dt)v[SUB]vertical[/SUB] = (dm/dt)v[SUB]horizontal[/SUB]F[SUB]3[/SUB] = M(a-grav) + (dm/dt)v[SUB]horizontal[/SUB] - F[SUB]1[/SUB]`

In code this gives

`function lift_drag { local M is ship:mass. local a is ship:sensors:acc. local grav is -(body:mu/(body:radius+ship:altitude)^2)*up:vector. // negavive magnitude to up vector is down. local thrust is 0.     // calculated by queriying the engines local fuel_flow is 0.// calculated by queriying the engines local eng_list is list(). list engines in eng_list. for eng in eng_list {  set thrust to thrust+eng:thrust.  set fuel_flow to fuel_flow + eng:fuelflow. }. local resultant is M * ( a - grav ) + fuel_flow * ship:vleocity:surface - thrust * ship:facing:vector. return resultant.}.`

but I am getting some odd reasults

Edited by TDW

##### Share on other sites

What exactly are odd results? I haven't had a chance to play with either of our scripts myself.

##### Share on other sites

I was getting readings for drag in space, that turned out to be due to the rocket flexing and the accelerometer being on the command pod (distant from the COM).

But i have also been getting long periods of time (not just blips caused by staging engines) where the drag is reading as pulling the rocket upwards.

##### Share on other sites

How strange. I'll have to look over the math once again and do a couple of test flights once I get home from work. Also, if I'm not mistaken, the ship:acceleration tag is actually a thing in kOS, so you should be able to use that rather than relying on an accelerometer.

Edit: A very preliminary guess without having the chance to look anything over would be that there may be a unit mismatch somewhere, an overlooked conversion factor or something.

Edited by VFB1210

##### Share on other sites
A very preliminary guess without having the chance to look anything over would be that there may be a unit mismatch somewhere, an overlooked conversion factor or something.

That was my initial thought too but it would have to be on something very small at constant speed (or there are 2 mismatched units that cancel) as i took a plane out and flew it up to max speed. It gave the same value for drag (in kN) as the engine thrust (kN) when at level flight and constant speed.

##### Share on other sites

If you are flying level at a constant speed, the net force on the plane should be zero, and drag should be equal to thrust. That makes sense. Similarly, thrust will be greater than drag when speeding up, and less than drag when slowing down.

##### Share on other sites

Does KOS control ships in the background?

The reason I ask is because I would like to automate ore trips from minmus to orbit.

##### Share on other sites

I've seen other people do it, (e.g. F9 flyback booster) but I could never get it to work, and the ship has to be within physics range. So an ore ship to Minmus would probably be out of the qurstion.

##### Share on other sites

That's what I figured but thought I would ask.

##### Share on other sites

Hi. I start to study kOS.

I try to use kOS_0.17.3 with KSP_1.0.4 at Windows7x64, but I meet some problem.

Tigger Commands, like WHEN/THEN and ON. They don't work.

But other commands seems to work well.

For explame, I code:

set a to 1.

until FALSE {

set a to a+1.

print "normal".}

when a>5 then{

print "TIGGER".}

I only get "normal" without "TIGGER".

I even copy sample code from http://ksp-kos.github.io/KOS_DOC/ and RUN it.

But it still didn't work.

Chould you tell me what shall I do?

##### Share on other sites

There are a number of ways to do it.

You can look at stage:liquidfuel in the same way that you are using stage:solidfuel . but this wont work for asparagus staging.

You can also look at drops in maxthrust. (this means that an engine has shut down) so

`//at the start of the script.set old_maxthrust to 0.// staging logicIf round(ship:maxthrust,2) > old_maxthrust {           // The rounding is done to prevent accidental staging due to floating point errors / tiny differences in maxthrust set old_maxthrust to round(ship:maxthrust,2).} else if round(ship:maxthrust,2) < old_maxthrust{ stage. wait 0.1. set old_maxthrust to round(ship:maxthrust,2).}.`

One advantage of this is that it does not need to differentiate between liquid or solid engines and it works for asparagus staiging. In the above form it requires the engines to be in the same stage as the decouplers, this can be changed but the code becomes more complex.

One major thing this cant handle is drop tanks (eg the big orange tank on the space shuttle).

An older method I used for this was to repeatedly re-list the engines and check for flame-outs but that has the same disadvantages as the maxthrust method and requires constant refreshing of a list.

If you need to handle drop tanks. it is possible to have kOS navigate the part tree and look at the state of fuel tanks on the other side of decouplers, activating the decoupler if all the fuel is gone.

Thanks! worked like a charm. that method is definitely going to come in handy.

Edited by Snillum101

##### Share on other sites
Tigger Commands, like WHEN/THEN and ON. They don't work.

But other commands seems to work well.

For explame, I code:

set a to 1.

until FALSE {

set a to a+1.

print "normal".}

when a>5 then{

print "TIGGER".}

I only get "normal" without "TIGGER".

I even copy sample code from http://ksp-kos.github.io/KOS_DOC/ and RUN it.

But it still didn't work.

Chould you tell me what shall I do?

kOS runs the code from top to bottom. Until false { } is an infinite loop as such the trigger is never created as in your script it would do that after completing the loop.

Move the when trigger above the loop and it should work

##### Share on other sites
kOS runs the code from top to bottom. Until false { } is an infinite loop as such the trigger is never created as in your script it would do that after completing the loop.

Move the when trigger above the loop and it should work

To add to this: triggers don't actually get turned on until they're mentioned in the code.

`set x to 1.print "one".wait 1.print "two".wait 1.when x = 1 then {  print "x is one". }print "three".wait 1.`

Will print something like this:

`onetwox is onex is onex is onex is onex is onex is onex is onex is onex is onex is onex is onex is onex is onex is onex is onex is onex is onex is onex is onex is onex is onethreex is onex is onex is onex is onex is onex is onex is onex is onex is onex is onex is onex is onex is onex is onex is onex is onex is onex is onex is one`

The trigger that prints 'x is one' doesn't really become active until the point in the program where it was mentioned.

##### Share on other sites

I finally decided to fix a time for my first episode of twitch kOS demos and stop putting it off.

TIME IS GIVEN IN TIMEZONE UTC-5 (US CDT, UTC-6, +1 for Daylight Savings). Please adjust accordingly for your location.

• twitch channel to watch: http://www.twitch.tv/dunbaratu/
• start time: UTC-5 (US CDT: UTC-6 + 1 for daylight savings): 7PM on Tuesday night, 14 July 2015
• duration: between 2 and 3 hours, depending on how fast we go thought it*

Be gentle. I've not done twitch much before.

Subject: Rescue a stranded orbiting Kerbal with kOS. (Like the career mode mission, but demo'ed in sandbox for debugging reasons.).

Sub-steps: Focus on inclination matching and rendezvous prediction. Less focus on the initial ascent and final re-entry. (Those topics are often covered well by others. I may start from already being in orbit.)

Format: I am already solving the problem in my own code ahead of time, but intend to re-type it all in and explain as the stream goes on. You can stop me as I do so if you need a thing explained better, or have a better idea. The stream will be a mixture of code typing and crude hand-drawn math formula derivation, and running the code.

##### Share on other sites
I finally decided to fix a time for my first episode of twitch kOS demos and stop putting it off.

• twitch channel to watch: http://www.twitch.tv/dunbaratu/
• start time: UTC-6: 7PM on Tuesday night, 14 July 2015
• duration: between 2 and 3 hours, depending on how fast we go thought it*

Be gentle. I've not done twitch much before.

Subject: Rescue a stranded orbiting Kerbal with kOS. (Like the career mode mission, but demo'ed in sandbox for debugging reasons.).

Sub-steps: Focus on inclination matching and rendezvous prediction. Less focus on the initial ascent and final re-entry. (Those topics are often covered well by others. I may start from already being in orbit.)

Format: I am already solving the problem in my own code ahead of time, but intend to re-type it all in and explain as the stream goes on. You can stop me as I do so if you need a thing explained better, or have a better idea. The stream will be a mixture of code typing and crude hand-drawn math formula derivation, and running the code.

Just double check that you have pressed "record" button.

For us who can't watch live channel due to time zone difference. Thanks.

##### Share on other sites

See what happens when you program it like that telescope,,,

I'm curious to why the SHIP:SURFACESPEED and SHIP:VERTICALSPEED are the same here, as the documentation says different ?

CLEARSCREEN.

PRINT "H-SPEED:" + SHIP:SURFACESPEED.

PRINT "V-SPEED:" + SHIP:VERTICALSPEED.

##### Share on other sites

Clarified timezone info on stream feed announcement. My timezone is listed as UTC-6 on most websites, but they failed to mention it's UTC-5 during daylight savings.

##### Share on other sites
See what happens when you program it like that telescope,,,

http://i.imgur.com/DWAztJM.jpg

I'm curious to why the SHIP:SURFACESPEED and SHIP:VERTICALSPEED are the same here, as the documentation says different ?

http://i.imgur.com/wOBtz0x.jpg

They are very slightly different there - the closeness makes sense. At the moment of your screencap, you are basically pointed (and moving) straight up - so your surface speed is [mostly] your vertical speed - your horizontal velocity component is almost 0.

##### Share on other sites

Thus ÃŽÂ£F = (instantaneous mass)(acceleration) + (mass flow rate)(instantaneous velocity) = (engine thrust) + (instantaneous mass)(gravity) + (lift) + (drag).

....

where g = 9.802m/s^2 always.

...

And to answer your question Qigon; yes, thrust is technically a vector, though it is usually convenient to treat it like a scalar since it is (almost) always pointing through the center of mass of the rocket.

Nice piece of math here, thanks for the step by step.

I never could imagine that mass flow would play here, but hey this is rocket science, where anything can happen in equations. Out of curiosity, what values did you get while flying?

Silly question, doesn't g decrease with distance? or is it too small a difference?

About thrust, my concern is whether kos thrust is a vector. Because of gimballing. From the too of my head, there's no engine with more than3 degrees in stock, no idea in other mods.

^The only issue I see with that is that it would be extremely difficult to calculate lift from wings. Body lift is easy enough, as it is essentially just the component of drag working opposite the direction of gravity.

Would it make sense to compute lift as the component along vessel:top and real drag as the component along surface velocity? That way you'll be more accurate in Aero breaking and high g turns.

I'm too slow to keep up with you guys on this. Taking advantage of the momentum and steering the question in another direction, would you guys agree that terminal velocity is reached when the magnitude of drag equals mass times g, if we apply the above formulas?

##### Share on other sites

Wow~~ These triggers are more useful than I thought. Thx!

- - - Updated - - -

Thanks for your reply! In the past, I thought triggers start to work at the beginning of program. So its position can be anywhere. But it's wrong! Now I realize triggers can do more than I thought~

##### Share on other sites
They are very slightly different there - the closeness makes sense. At the moment of your screencap, you are basically pointed (and moving) straight up - so your surface speed is [mostly] your vertical speed - your horizontal velocity component is almost 0.

According to this.. that speed is not right - the horizontal speed should be close to Zero from the start, relative to the SOI body (Earth), and should remain close to zero until the rocket pitches over from the vertical.

The two speeds are almost identical up to a few x1000m ?

Vessel:SURFACESPEED[TABLE=class: docutils field-list]

[TR=class: field-odd field]

[TH=class: field-name]Type:[/TH]

[TD=class: field-body]scalar (m/s)[/TD]

[/TR]

[TR=class: field-even field]

[TH=class: field-name]Access:[/TH]

[TD=class: field-body]Get only[/TD]

[/TR]

[/TABLE]

How fast the ship is moving in the plane horizontal to the SOI bodyÃ¢â‚¬â„¢s sea level surface.

Edited by ColKlonk