Jump to content

My Adventures Using kOS – Interim Report (Gravity Turn) – Posted 10/03/15


BlkBltChemie

Recommended Posts

Current KSP/kOS Versions:

9/17/2015 - [KSP 1.0.4]

9/17/2015 - [kOS 0.17.3]

Overview:

As my username may suggest, my training is in Chemistry and the only programming experience I have goes back to about 8 years ago when I had to take two classes (C and C++) as an undergraduate for my B.S. Nevertheless, I have recently starting playing around a little bit using kOS in KSP version 1.0.4. Now, I should note that, up to this point, I have only ever played stock with occasional forays into Squad’s official mods – I have never used MechJeb or KER, and all of my flights since I joined back in v0.21 have been flown manually! So, at least for me, this should prove to be a . . . let’s go with interesting . . . adventure!

Goal and Format:

My purpose in posting this thread is to create a log of missions I have run using kOS. It will serve three roles: mission reporting, beginner’s tutorial, and a place for me to ask kOS gameplay questions.

Since the missions themselves will be fairly routine, at least starting out, there probably won’t be much writing or pictures for the report. So far, I have really liked using the PRINT command to display information on the kOS terminal so that will be the main picture and I may showcase a couple of in-flight shots. The bigger part of each report will be my commentary/analysis of the mission/code and areas where I might want to improve. As part of this, I will almost certainly include a couple of questions since I am still learning.

I will also include the full code and craft files for each of my missions – this is kind of the tutorial part of each post. Anyone who wants may copy the code and give it a try with no need to give me credit or anything like that. Now, as I am a complete novice at programming, it will probably not be the best in the world, but it will be functional. Any suggestions for optimization are more than welcome and would be most appreciated!

First Mission: Single-stage, liquid fueled rocket on a suborbital trajectory

Thanks in advance for reading and offering suggestions! I hope that at least someone will find these reports interesting and/or helpful!

Code and Craft File Dropbox - Both a .ks and .txt version of the code are included since the .ks cannot be viewed online and I want people to have an option other than directly downloading. All craft are designed using only stock parts plus the kOS Scriptable Control System (obviously); no other mods are used.

--------------

Mission Links

--------------

Mission 01

Mission 02

Interim Report A

Interim Report B

Interim Report C

Next Link

Edited by BlkBltChemie
Link to comment
Share on other sites

--------------------------------

Mission 01: Suborbital Test Probe

--------------------------------

Objective: Launch a single-stage, liquid-fueled rocket on a suborbital trajectory.

Report: Pretty straightforward mission to start off with. I have a Stayputnik probe core sitting on top of a LV-T30 engine. Programmed a fun little launch countdown based on the QuickStart tutorial provided in the kOS documentation. Locked the throttle to 40%, started gravity turn at 2 km, and increased by 5° every 2 km after that until the rocket reached 45° at 20 km. Then, changed to 10° every 5 km until horizontal at 40 km. On reaching space, I had the program detach the probe, extend its antennas (BEEP…BEEP…BEEP), and then print the ETA to apoapsis every 10 seconds. After reaching the apoapsis (~80km), the program printed the altitude every 10 seconds until reentry at which point the program ended and the probe was left to free-fall through the atmosphere into a glorious splash down.

Analysis: Lot of trial and error getting the code to work – from finding a good throttle level to setting up the gravity turn and making sure everything printed the way I wanted it to. I originally locked the steering to UP, but that caused the craft to rotate 180° immediately after launching so I changed it to lock to the heading (0,90) = North, up. I was also confused the first time the probe decoupled in space because it just tumbled away from its heading and I thought something was wrong with the code. I forgot the Stayputnik has no reaction wheels so it could not orient itself after detaching from the rocket.

O393Fm4.jpg

prUETTO.jpg

Overall, the program works for this specific ship, but I want to work on writing programs that may be more generally applicable to a variety of designs.

Room for Improvement:

  • Throttle locked to 40%. As the fuel is burned off the TWR increases so this was not a very efficient launch. Another side effect of this is that locked throttle is very specific to this particular craft and is unlikely to work with other designs. Need to look into a way to vary the throttle as a function of TWR.
  • Manually entered gravity turn. So the code for the gravity turn was over 60 lines (14 altitudes). The real problem though is that the code is essentially a step function not a smooth curve (see graph). Need to look into a way of optimizing the gravity turn code.

eo8hKeQ.jpg

Questions:

  • When you move the rocket to the pad, the throttle defaults to 50%. If you run the program, when it ends and unlocks the controls, the throttle reverts back to the default which can cause problems if you still have an engine attached. I pressed ‘X’ at the beginning of launch to avoid this which works ok, but is there another way to do it?
  • Is there a way to print the terminal output to a .txt file?

Code and Craft File: Mission 01

Next Mission: Two-stage, liquid fueled rocket to orbit

Edited by BlkBltChemie
Link to comment
Share on other sites

For the 50% default throttle problem, which IMO is one of the most annoying unwanted features SQUAD ever implemented - NOBODY wants it to work that way, do this:

During your script, execute this:


SET SHIP:CONTROL:PILOTMAINTHROTTLE TO 0.

At the start, and just before it ends.

It changes not what the script's throttle is, but what the pilot's remembered throttle is (the throttle it will shift back to when you quit the script).

The reason for also doing it again right before you finish the script is that if the player hit 'shift' or 'x' while not focussed on the window, it will have secretly moved the pilot throttle without showing any effect until the script ends.

Link to comment
Share on other sites

Fantastic! Thanks for the tip and explanation of how it works! I certainly agree - not sure what the motivation was behind setting the default throttle on launch to 50%.

They claimed it was so newbie users would still see something happen when they put a rocket on the pad and hit spacebar without knowing the other keybindings.

But what's dumb about that is that you still need to know SOME keybindings to know to hit spacebar in the first place, so it's not like it's gaining you anything.

Link to comment
Share on other sites

Hum, your "gravity turn" function looks somewhat iffy due to the stepwise nature ( also , forcing pitch ensures you're not actually doing a gravity turn: you only do a gravity turn when you let gravity turn your rocket ;) ) and if you used it in a more flexible rocket, if can lead to laggy response, or worse, ressonating oscilations. Also, it might get you in hot water in the 1.x atmo , where sudden changes in pitch during ascent can lead to disastrous results. How about getting a if-else cycle ensuring that the prograde is never too far away of the velocity vector?

Also in the throttle department , you might want to consider to look on keeping a stable TWR. Locked throttle can give you issues when going trans-sonic in the 1.x atmo ( aka rocket flipping upside down ).

P.S Other Chemist around ? Yay ;) Atleast they taught you C, instead of Matlab ;)

Link to comment
Share on other sites

( also, forcing pitch ensures you're not actually doing a gravity turn: you only do a gravity turn when you let gravity turn your rocket ;) )

Good point and very true! So yeah in 1.0.0 I had no trouble manually pitching over about 5-10 degrees at 50 m/s, turning off SAS and letting my rocket fly itself to orbit with throttle adjustments. Not so much in 1.0.2/1.0.4. I've had to use SAS more again and input a lot more manual control authority. I'm not sure if it is something to do with drag being increased (as I recall) in 1.0.2.

You were also spot on, with the step function. The prograde marker generally lagged about 5-10 degrees behind the pitch angle. The gravity turn is definitely something I want to work on. A lot of examples I've looked over are using a variety of different loops: mostly if-else if. I really want to try to tie it to throttle instead of altitude/pitch angle as that will resolve both problems in one go - the gravity turn and the TWR issues - and make the code more generally applicable instead of just working for this craft.

P.S Other Chemist around ? Yay ;) Atleast they taught you C, instead of Matlab ;)

Yep, I think there are a few of us here! All science majors had to take one computer science class at my undergrad and since I was a double major of Chemistry and Math, I had to take a second one for the Math. The most fun was the final where we had to use a pseudo-random number generator to code paper-rock-scissors and be able to "play" against the computer. I think one of my calculus classes used Matlab and another one used Maple. Never really liked either. For PChem we used Mathematica which was by far my favorite.

Link to comment
Share on other sites

-------------------------------

Mission 02: Orbital Test Probe

-------------------------------

Objective: Launch a two-stage, liquid-fueled rocket to deploy a probe in a stable orbit.

Report: I made a couple modifications to the craft used in the previous mission by adding a second stage with an LV-909 engine. I also remembered to add a reaction wheel to keep the Stayputnik probe oriented after I decouple it. The launch was pretty much the same (although I did add the line of code from Steven Mading to sort out the default throttle issue). The first stage was decoupled at 32 km. Orbital insertion was started 8 seconds before apoapsis at full throttle and gave a final orbit of 81 km x 85 km. Finally I had the probe timewarp until its electric charge was expended (the probe doesn’t have any solar panels) – did not quite make a full orbit.

Faorjb8.jpg

yh2xD5h.jpg

Analysis: Because I really wanted to try to achieve orbit, I used the same launch code I had programmed for the previous mission instead of working on any optimizations. I had a lot of trouble getting the conditional statements right for staging (see below). The circularization code required a lot of trial and error and I’m not really happy with how it ended up. My first try was to lock heading to prograde and burn 5 seconds before apoapsis, but that gave me a highly elliptic orbit and I ran out of fuel before the periapsis was high enough. I played around with when I started the burn – various times between 5 adn 15 seconds before apoapsis – and ultimately settled on 8 sec which gave a fairly circular orbit. This isn’t a very good solution, in my opinion, since it will only work for this craft and required a lot of trial and error. (I really want to get to the point of making my code more generally applicable to different designs and knowing it will work at launch instead of relying on trial and error.)

Room for Improvement:

  • Since I used more or less the same code as for the suborbital mission, and as r_rolo1 commented above, there is definitely room for improvement in the (not really a) gravity turn sequence. The plan is to try to use an if-else if loop to vary the throttle while keeping a constant TWR after an initial pitch over once speed is greater than 50 m/s.
  • Specifically for this mission I want to work on the code for staging and circularization (see below). What I used worked, but like I said above only for this ship.

Questions:

  • So...staging. I know there are some issues if the decoupler and engine are in the same stage – you can’t use STAGE:LIQUIDFUEL<0.1 because KSP for some reason adds the fuel that is in the next stage up. (I did try with them in the same stage as well as in separate stages; neither worked.) It will work with STAGE:LIQUIDFUEL < 90.1 (for this craft), but I went with SHIP:LIQUIDFUEL instead just because. I tried using LIST ENGINES to check for FLAMEOUT – not sure if I wrote the code incorrectly or what but I just could not get that to work. (I also could not get an IF loop to work and ended up using WAIT UNTIL, which is really unreliable.) Any suggestions? (Related, when do I need to use PRESERVE?)
  • Next, what is the best way to circularize such that Ap and Pe have minimal deviation? There are several variables – when you start the burn, how much thrust you use, and where you aim. When I manually burn in my stock save, I start aiming below the horizon (before Ap), move to prograde at the apoapsis, and then continue above the horizon (after Ap). Is there a way to write a code for this (or another option for precision circularization)?
  • Finally, is there a good way to code something like “warp ahead this many complete orbits?â€Â

Code and Craft File: Mission 02

Next Mission: Optimization! (This one will probably be a little while in the making since it will take some more research and lots of testing on my part.)

Edited by BlkBltChemie
Link to comment
Share on other sites

Good work so far ;) Now let me try to help to the extent of my knowledge of kOS ( admitedly not very extensive )

Questions:

  • So...staging. I know there are some issues if the decoupler and engine are in the same stage – you can’t use STAGE:LIQUIDFUEL<0.1 because KSP for some reason adds the fuel that is in the next stage up. (I did try with them in the same stage as well as in separate stages; neither worked.) It will work with STAGE:LIQUIDFUEL < 90.1 (for this craft), but I went with SHIP:LIQUIDFUEL instead just because. I tried using LIST ENGINES to check for FLAMEOUT – not sure if I wrote the code incorrectly or what but I just could not get that to work. (I also could not get an IF loop to work and ended up using WAIT UNTIL, which is really unreliable.) Any suggestions? (Related, when do I need to use PRESERVE?)

Well, I really not sure on this one, but I think ( take this with a pint of salt ) that checking for Liquid fuel avaliability is a bad idea, due to the change Squad did on liquid fuel routing in 1.0 ( basically, jet engines will act like RCS engines and check for LF in all the ship, regardless of passing through parts that don't allow for fuel flow, so maybe kOS is being fooled by that ). Maybe checking for other consumable would work better ? ;)

  • Next, what is the best way to circularize such that Ap and Pe have minimal deviation? There are several variables – when you start the burn, how much thrust you use, and where you aim. When I manually burn in my stock save, I start aiming below the horizon (before Ap), move to prograde at the apoapsis, and then continue above the horizon (after Ap). Is there a way to write a code for this (or another option for precision circularization)?

Well, circularization is the first big hurdle on using kOS, simply because a good general method for it requires you to juggle around with orbital mechanics and not just code.

Let's divide the issue in some parts:

a) As you know, the time you need to burn to any manouver depends both of the dV you need and of both the Isp of the engine at the time ( I'm assuming just one engine , for sanity sake at this point. Also note that Isp of engines can change with exterior atmo pressure. Beware ) and the rate the engine burns fuel. Isp and fuel burn rate are engine parameters that IIRC can be called by kOS on demand ( or, in worst case scenario, from the wiki ), and if you also know the dV needed, you can use the bread and butter of rocket equations, the Tsiolkovsky rocket equation to know how much mass you need to burn, and as consequence, the time needed to burn it.

B) Now, how to know the dV needed? Remember that, before anything else, dV is a change of velocity, and, specifically in this case, the diference in velocity needed in Apoapsis before and after circularization ( since the velocity in both cases would be colinear and in the same direction before and after circularization, it is just a diference in the module of the velocity before and after ). You can get the velocities you need by the liberal use of the Vis-viva equation ( remember, the semi-major axis of a orbit is (Ap+Pe)/2 if you measure both Ap and Pe from the center of the planet you are orbiting. Say, a Ap of 70 km around Kerbin as displayed in game is actually 600+70 = 670 Km from the center of Kerbin .Also, while the mass of the planets is not given directly in game, you can get G.M on kOS via calling "Mu" IIRC ;) )

So in somewhat pseudo code:

1) You call the Ap and Pe of the current orbit ( it might be a good idea to check if you are out of the atmosphere before doing this BTW ;) ), calculate the semi-major axis of your current orbit and using that you calculate the speed you will have in your current Ap using the Vis-Viva equation

2) You do the same for a circular orbit with the distance between the center of the planet and your current Ap ( remember that in a circular orbit the semi-major axis is equal to the radius by definition ;) ) using the same equation

3) Use 1) and 2) to calculate the dV needed for the circularization manouver ( basically the speed you will have in a circular orbit minus the speed you will have in your current Ap if you don't burn. Also, in this point you might want to check for the signal here because that will tell you if you need to burn prograde or retrograde ( because you might want to circularize from a orbit higher than the current one ;) ) )

4) Get the engine Isp and fuel burn rate of your engine ( I assume you can get both via calling partmodules IIRC. Again take this with a pint of salt )

5) Using the Isp from 4) and the dV from 3), use the Tsiolkovsky rocket equation to get m0/m1 from that equation ( the mass the ship had at start of burn divided by the mass the ship will have at end of burn to get the desired dV out ) and , from there, m0-m1 ( aka change of mass )

6) From 5) and the fuel burn rate you got in 4) , calculate the time you need to burn the fuel you need to burn , aka the burn time you wanted to know :D ( P.S I'm assuming 100% throttle. If not, you need to make the apropriate corrections :D )

Yup, it is hard work. But well, rocket science didn't got it's fame of being hard work for nothing :P

  • Finally, is there a good way to code something like “warp ahead this many complete orbits?â€Â

Again, orbital mechanics to the rescue :D

You can calculate the orbital period if you know G.M ( aka "Mu" ) of the body you're orbiting and the semimajor axis of your orbit ( I assume you read the above answer ;) ) via the use of the Kepler third law ( some pointers on this ). If you know the orbital period, “warp ahead this many complete orbits†becomes "warp ahead for this number of orbital periods" or, in other words " Warp to n*"orbital period" after this moment"

Edited by r_rolo1
Minor corrections
Link to comment
Share on other sites

Good work so far ;) Now let me try to help to the extent of my knowledge of kOS ( admitedly not very extensive )

Thanks! Definitely a pretty steep learning curve, but I'm having fun! And the help is definitely appreciated!

Well, I really not sure on this one, but I think ( take this with a pint of salt ) that checking for Liquid fuel avaliability is a bad idea, due to the change Squad did on liquid fuel routing in 1.0 ( basically, jet engines will act like RCS engines and check for LF in all the ship, regardless of passing through parts that don't allow for fuel flow, so maybe kOS is being fooled by that ). Maybe checking for other consumable would work better ? ;)

Great idea! I had completely forgotten about the fuel routing change. I ran a test for oxidizer yesterday, but it ran into the same problems, unfortunately. I need to look at some more recent examples for a good approach to auto-staging.

Well, circularization is the first big hurdle on using kOS, simply because a good general method for it requires you to juggle around with orbital mechanics and not just code.

Aha, I was wondering when the rocket science would come into play! Thanks for the excellent explanation and general overview - I'll give this a few more read-throughs, take a look at some examples, and then give it a shot!

You can calculate the orbital period if you know G.M ( aka "Mu" ) of the body you're orbiting and the semimajor axis of your orbit ( I assume you read the above answer ;) ) via the use of the Kepler third law ( some pointers on this ). If you know the orbital period, “warp ahead this many complete orbits†becomes "warp ahead for this number of orbital periods" or, in other words " Warp to n*"orbital period" after this moment"

I've been delving some more into the kOS documentation and it looks like there is actually a command to call for the orbital period so this should be pretty easy! (I just didn't know where to start.)

Thanks again for the great suggestions and explanations! I think I should be able to sort out circularization and orbiting now and have looked at quite a few examples for gravity turns. Now if only I can smooth out the staging...

Link to comment
Share on other sites

In general most people seem to circularize with some variant of getting periapsis and apoapsis altitudes within a tolerance of each other, but that's frought with error - if you take too long to burn, it can be the case that it's actually impossible to do this and the script fails to realize that you've already done the best you possibly can and it's time to stop trying.

This very simple bit of code does circularization sort of okay:


// Number of seconds you want to start the burn before of the apoapsis.
// There's precise ways to measure this, involving the Tchaikovsky rocket equation,
// but for a first go, just hardcode it depending on your ship design:
set apoapsis_lead_time to 5.

lock steering to prograde.
lock throttle to 0.
wait until eta:apoapsis < apoapsis_lead_time.

// Thrusts until the apoapsis and periapsis have started to swap positions with each other,
// i.e the ship is in the half of the orbit that is closer to Pe than it is to Ap:
lock throttle to 1.
wait until ship:obt:trueanomaly < 90 or ship:obt:trueanomaly > 270.
lock throttle to 0.

print "That's as good as it gets. I should now be halfway between apo and peri.".

Link to comment
Share on other sites

For staging, it might be worthwhile to explore using the acceleration of the rocket. You don't want to look for 0gs (particularly if you're still in atmo) but perhaps a reduction in G by some amount (maybe average the prior frames 15-10 against 5-current frame to help avoid physics issues). You might also want to couple this to another metric (if you have no exposed solar panels or rtgs and your engines in a stage have alternators, maybe look for a drain in electric charge to signal when the engines cut off) as a backup.

Link to comment
Share on other sites

In general most people seem to circularize with some variant of getting periapsis and apoapsis altitudes within a tolerance of each other, but that's frought with error - if you take too long to burn, it can be the case that it's actually impossible to do this and the script fails to realize that you've already done the best you possibly can and it's time to stop trying.

This very simple bit of code does circularization sort of okay:

Thanks! I can see how taking an iterative approach to a set tolerance can cause the code to blow up. I really appreciate the comments explaining what the example code is doing. I understand how "trueanomaly" specifies the angle before/after Pe when I looked through some of the kOS documentation after reading this post. I'm a little confused though as to the "obt" part of the call. Is that just shorthand for "orbit?"

That also sounds like a useful way to warp to a specific point in the orbit. You could set trueanomaly to the desired value and use an until loop to warp there, correct?

For staging, it might be worthwhile to explore using the acceleration of the rocket. You don't want to look for 0gs (particularly if you're still in atmo) but perhaps a reduction in G by some amount (maybe average the prior frames 15-10 against 5-current frame to help avoid physics issues). You might also want to couple this to another metric (if you have no exposed solar panels or rtgs and your engines in a stage have alternators, maybe look for a drain in electric charge to signal when the engines cut off) as a backup.

This actually sounds pretty similar to some examples I have seen that rely on a change in the maxthrust, particularly for asparagus staging.

I've been working on my staging script the last couple evenings. I think I almost have it so I will post an interim report a little later after some more testing tonight.

Link to comment
Share on other sites

---------------------------

Interim Report A: Staging

---------------------------

The last few evenings, I have been working on optimizing the staging code I used in Mission 02. In that program, I used:

[spoiler=]

WAIT UNTIL SHIP:LIQUIDFUEL < 90.1.

PRINT " ".
PRINT "...Stage 1 exhausted, activating Stage 2.".
LOCK THROTTLE TO 0.0.
WAIT 0.5.
STAGE.
PRINT "...Stage 1 separation complete.".
WAIT 0.5.
LOCK THROTTLE TO 0.6.
WAIT 0.5.
STAGE.
PRINT "...2nd stage ignition successful!".
PRINT " ".

Since the WAIT UNTIL command is a sequential design, it could potentially be disastrous if placed in the wrong part of the overall code. This drastically limits its applicability to different designs. From the kOS documentation on design patterns, two alternatives are setting up loops either for condition checking (IF/ELSE) or for triggers (WHEN/THEN). I have seen several examples using both types of loops for autostaging based on parameters like fuel level, change in maxthrust, and engine status.

I generally like to separate my decoupler and engine activation into two stages with a small time delay between. Since you can’t WAIT in a WHEN/THEN loop, I focused on using an IF loop to check for conditions. Fuel levels are occasionally unreliable for STAGE:RESOURCE (sometimes KSP and consequently kOS adds the fuel of the next stage), so I really wanted to use engine status.

As I said in the Mission 02 post, I actually tried using a check for engine flameout, but couldn’t get it to work. The (partial) code was:

[spoiler=]

LIST ENGINES IN MyList.
FOR eng IN MyList
{
IF eng:flameout
{

[INDENT] .
.
.
}
[/INDENT]


I defined the parameter to check but forgot to state what condition I want it to check – ENG:FLAMEOUT can be true or false. After much trial and error I finally have a staging code I am pretty happy with based on when the engine cuts out:

[spoiler=]

LIST ENGINES IN MyList.

UNTIL STAGE:NUMBER = 0
{
FOR eng IN MyList
{
IF eng:flameout = true
{
PRINT "Decoupling Stage " + stage:number.
PRINT " ".
STAGE.
WAIT 1.
STAGE.
PRINT "Stage " + stage:number + " activated!".
LIST ENGINES IN MyList.
WAIT 1.
}

}
}

(Note: Right now, I am only working with a single, central stack – if I use boosters or asparagus staging, I’m sure I will need to adjust this.)

In addition to actually setting the ENG:FLAMEOUT check condition, it took me a while to figure out that I needed to relist the engines after staging within the loop. (I thought I remembered reading somewhere that the engine was automatically removed from the list after being decoupled?) If it is not included in the IF loop, the program uses the original list and will continue to stage since ENG:FLAMEOUT is still true for the decoupled engine. I am actually kind of proud about how I did the troubleshooting to discover that by printing ENG:IGNITION and ENG:FLAMEOUT each loop (not included in the above code).

I’m not entirely sure about the condition I have for the UNTIL loop. Let’s consider two cases: Case 1 = a satellite that decouples without an engine (i.e. Stage 0 is just a decoupler). Case 2 = a Mun lander (i.e. Stage 0 is a decoupler + engine).

t2K9sj4.jpg

If the second engine cuts out in Case 1, it automatically decouples the satellite, which is something I don’t really want – I would rather do that on my own. I can simply change to:

[spoiler=]

UNTIL STAGE:NUMBER = 1
{
.
.
.
}

This works but isn’t general enough for any design, but only changing 1 character isn’t too bad. I also tried testing for when the ship is out of fuel:

[spoiler=]

UNTIL SHIP:LIQUIDFUEL < 0.1
{
.
.
.
}

This does not automatically detach the satellite and works for both the probe and Mun lander cases! However, if the ship never runs out of fuel (leftover fuel after achieving orbit/landing) the loop will never end. (I suppose this is also true for the IF loop as the engine would never flameout either.) So with either UNTIL condition, I need to go back and add a BREAK condition to exit the loop.

  • For the BREAK condition (landed/in orbit), my instinct is saying that it needs to be part of the UNTIL loop (not the IF or FOR loops), right?
  • In Case 1 for the satellite, I may want to stay in the loop until I finish orbital maneuvers…is it ok to just let a small loop keep running indefinitely?
    • If, later in the code, I manually decouple the satellite after finalizing the orbit, will the loop automatically end since it the longer has engines attached or will it throw an error?
    • If an error, is there a way to say IF MyList = empty {break.}? (Sorry for the pseudo-code.)

    [*]At this point, I am not sure which (if either) condition for the UNTIL loop is better?

-----------------------

UPDATE (9/23/2015):

-----------------------

I just discovered that if I move LIST ENGINES IN MyList into the UNTIL loop, that I do not have to relist the engines as part of the IF loop!

[spoiler=]

UNTIL STAGE:NUMBER = 0
{
LIST ENGINES IN MyList.
FOR eng IN MyList
{
IF eng:flameout
{
PRINT "Decoupling Stage " + stage:number.
PRINT " ".
STAGE.
WAIT 1.
STAGE.
PRINT "Stage " + stage:number + " activated!".
WAIT 1.
}

}
IF SHIP:APOAPSIS > 200000
{
BREAK.
}
}

And I was also right - the BREAK condition worked in the parent UNTIL loop!

Edited by BlkBltChemie
Link to comment
Share on other sites

small hint:

This:


IF eng:flameout = true
{

is redundant because all Boolean values work that way without the '= true' tacked on, as follows:


IF eng:flameout
{

eng:flameout already *is* a boolean expression by itself, because it's a boolean variable that can be false or true, just like an expression with '=' can be false or true.

In fact, depending on what you're doing, it's usually a good habit to avoid any boolean expression where you're doing "= true" or "= false", for this reason: It works fine when using a type that is restricted to only being allowed to be two enumerated values: 0 which is aliased to "false", or 1 which is aliased to "true", like a Boolean tries to be, but given that you can make a Boolean interpretation of any integer value, doing "= true" gets wonky results when the value in question is, say neither a 0 nor a 1, but say a 2. By the rules of Boolean logic, anything that is not zero is true, so a 2 should be a true value. But the check "foo = true", if foo was 2, would yield a false, which is wrong.

Granted, this isn't a problem when you put the burden on the language to restrict the values to only being capable of being 0 or 1 and nothing else, but as a general programming practice, it's best to avoid it so it doesn't mess you up when you come across more low level languages that don't do this coercion and really treat all boolean expressions as integers (like C or C++ for example).

Plus it just looks weird to redundantly say "= true" when that's what the Boolean value already meant by itself.

Link to comment
Share on other sites

Thanks for the tip! I had originally tried using if "eng:flameout" in Mission 02, but it did not work which is why I added "= true" here. I just ran a test without "= true" and this new script worked just fine. Unfortunately I don't have a copy of the older code that did not work so there must have been something else wrong. I wonder...I don't think I put the "if" loop inside an "until" loop so maybe it was just checking once and then done since it was false. Anyway, it works now so thanks!

Next up: I almost have throttle control worked out and will probably do another interim report for that as well.

Edited by BlkBltChemie
Link to comment
Share on other sites

------------------------------------

Interim Report B: Throttle Control

------------------------------------

The next step, after having worked out a better method for staging, is to start improving launch efficiency by controlling the throttle. Working on this was kind of fun for me as a chemist, because I never really delved that deeply into physics or orbital mechanics. The basic idea is to control the throttle by keeping a constant thrust-to-weight ratio.

TWR = thrust/(mass*gravity) -> thrust = TWR*(mass*gravity)

A few things to keep in mind:

  • Ship mass changes as fuel is burned
    • TWR increases (mass decreases)

    [*]Gravitational acceleration changes with altitude

    • TWR increases (gravity decreases)

    [*]Post KSP 1.0, engine thrust changes with altitude

    • TWR increases (thrust increases, usually)

    [*]In a gravity turn, not all of the thrust is used to counter gravity so the TWR is defined by the effective thrust. (I will not get into this for current report and will save it for next time.)

    • TWR decreases (more thrust is horizontal so less fights gravity)

To do this, I need to loop calculations of mass, gravity, and thrust. At 100% throttle, the thrust = max thrust of the engine so if I have a target TWR in mind, I calculate the thrust needed (above) and the ratio of thrust/max thrust gives me the throttle setting I need. The math and resulting code are below:

Universal Law of Gravitation: F = G(m1m2)/r2

When one body is much larger: g = -GM/r2È“ (vector)

Standard Gravitational Parameter: μ = GM

r = radius + altitude

Magnitude of g = μ/(radius + altitude)2

We can either use this formula at each altitude or we can use: gh=g0 (r/(r+h))2


LIST ENGINES IN MyLIST.

FOR eng IN MyList
{
SET tmax to eng:maxthrust.
}

UNTIL SHIP:LIQUIDFUEL < 0.1
{
IF SHIP:VERTICALSPEED > 50
{
SET g to KERBIN:MU / ((KERBIN:RADIUS + SHIP:ALTITUDE)*(KERBIN:RADIUS + SHIP:ALTITUDE)).
SET t to 2*(SHIP:MASS*g). //Change 2 to desired TWR
LOCK THROTTLE TO t/tmax.
SET twr to t/(SHIP:MASS*g).
PRINT "maxthrust = " + round(tmax) + ", thrust = " + round(t) + ", TWR = " + round(twr,2) + ", Throttle = " + round(throttle,2).
PRINT " ".
}
}
WAIT 5.

The big question, for me anyway was will this work for different designs, and the answer is yes!

U7rCp7l.jpg

Ok, so where I had the most trouble was tying in my code for staging - the problem was that when I staged, the maxthrust was reported as 0 so throttle = t/tmax was trying to divide by 0 which doesn’t work so I went back to relisting the engines after I staged. I have something that finally works but feedback here would definitely be great (particularly if there is an alternative to using the two FOR loops), because it does not seem very optimal to me, but then again, I’m still pretty new at this.


LIST ENGINES IN MyLIST.

UNTIL SHIP:LIQUIDFUEL < 0.1
{
FOR eng IN MyList
{
IF eng:flameout
{
PRINT "Decoupling Stage " + stage:number.
PRINT " ".
STAGE.
WAIT 1.
STAGE.
LIST ENGINES IN MyLIST.
PRINT "Stage " + stage:number + " activated!".
PRINT " ".
WAIT 1.
}
}
FOR eng IN MyLIST
{
SET tmax to eng:maxthrust.
PRINT eng:name + ", " + round(eng:maxthrust).
PRINT " ".
}

IF SHIP:VERTICALSPEED > 50
{
SET g to KERBIN:MU / ((KERBIN:RADIUS + SHIP:ALTITUDE)*(KERBIN:RADIUS + SHIP:ALTITUDE)).
SET t to 2*(SHIP:MASS*g). //Change 2 to desired TWR
LOCK THROTTLE TO t/tmax.
SET twr to t/(SHIP:MASS*g).
PRINT "maxthrust = " + round(tmax) + ", thrust = " + round(t) + ", TWR = " + round(twr,2) + ", Throttle = " + round(throttle,2).
PRINT " ".
WAIT 1.
}
}

WAIT 5.

Next up: Gravity turn! (I’m hoping to do a true gravity turn where I do an initial pitch over and then unlock the steering and let gravity and throttle control do the rest. I’m really curious to see how well the code I’ve written here works especially after I modify it to account for the effective thrust.)

Edited by BlkBltChemie
Link to comment
Share on other sites

Good job so far. I also agree that the two For loops do not seem optimal, but I really don't see at a glance how could you do better. OTOH , why that particular limit on the vertical speed to the TWR adjustement ? I understand the idea behind ( basically, it is just saying that you want some velocity between you and the ground before starting messing with the throttle ), but magic numbers are evil ;) and you want this piece of code to work in all of your takeoffs, no matter in what planet. For a example, 50m/s is more than the escape velocity of Gilly and more than 1/4 of the one of Pol :D I know, work in progress, like all the staging occuring when you have no fuel at all ( not optimal if you want to have chutes working :P ), just pointing out stuff you need to take care in the future.

Just another point I wanted to remind you about thrust: It does not change with altitude, it changes with presssure. Better said, Isp changes with pressure and the math can get wicked at that point if you want to be rigourous. It would probably be better to just ask the engine what is their thrust at the moment than to try to calculate it while in atmo, especially if we are talking about jet engines, or worse, dual mode engines ( in game ATM it is just the RAPIER ).

Anyway, I foresee liberal use of the Tsiolkovsky rocket equation in your near future. Brace yourself :D

Link to comment
Share on other sites

why that particular limit on the vertical speed to the TWR adjustement ? I understand the idea behind ( basically, it is just saying that you want some velocity between you and the ground before starting messing with the throttle ), but magic numbers are evil ;) and you want this piece of code to work in all of your takeoffs, no matter in what planet. For a example, 50m/s is more than the escape velocity of Gilly and more than 1/4 of the one of Pol :D

Ah, great question! 50 m/s is when I start my gravity turn on Kerbin. I was thinking ahead to my next optimization step. It is actually going well so far - still in need of some polishing though. (Preview: I have set up a TWR 2 launch until I get to 50 m/s then drop the TWR to 1.5 as I start the gravity turn and begin taking into account pitch angle. At least for the craft I'm currently testing, with steering unlocked after an initial 5 degree pitch over it hits 45 degrees right at 20,000 m.) Also, I am not planning on using this particular code for takeoff from every celestial - mainly because I call the planet's mu, radius, etc to calculate g.

I know, work in progress, like all the staging occuring when you have no fuel at all ( not optimal if you want to have chutes working :P ), just pointing out stuff you need to take care in the future.

Sorry, not sure I followed this - the staging stops when the ship is out of fuel. I see the no fuel at all primarily as a limitation for potential refuelling missions - I don't want to stage if I have a tanker ready to rendezvous and refuel. As for parachutes (and fairings for that matter), I'm leaning more towards using action groups.

Just another point I wanted to remind you about thrust: It does not change with altitude, it changes with presssure. Better said, Isp changes with pressure and the math can get wicked at that point if you want to be rigourous. It would probably be better to just ask the engine what is their thrust at the moment than to try to calculate it while in atmo, especially if we are talking about jet engines, or worse, dual mode engines ( in game ATM it is just the RAPIER ).

I may not be reading this correctly, but I think I am having the engine tell me its thrust (well max thrust) at a given altitude/pressure. The thrust I'm calculating is the thrust I need to obtain my target TWR. But like I said, maybe I am misreading/misunderstanding something here.

Link to comment
Share on other sites

--------------------------------

Interim Report C – Gravity Turn

--------------------------------

Things are really starting to come together in the launch optimization process and I finally have a code that I (mostly) like for a true gravity turn! This also incorporates the staging and throttle control from the previous interim reports. In Missions 01 and 02, I used a sequence of WHEN/THEN triggers to turn over x degrees at y altitude; however, with the 1.0 aerodynamics, I wanted to use a true gravity turn without locking steering.

The basic profile is to launch with steering locked vertically – I use (0,90) to keep the launch orientation, then (90,90) to rotate once it clears the launch clamps. At 50 m/s, I lock the steering to (90,85), allow a few seconds to stabilize, and then unlock steering for the rest of the flight.

[spoiler=]

CLEARSCREEN.

//Setup

SET SHIP:CONTROL:PILOTMAINTHROTTLE TO 0. //Thanks to Steven Mading on the KSP forum for this override of the default 50% throttle on launch
SET twr to 1.6. //Change as needed depending on vessel design
LIST ENGINES IN MyList.

PRINT "All systems go for launch!".
PRINT " ".
WAIT 2.

SET runmode to 1.

//Flight Control

UNTIL runmode = 0 //Runmode format based on code found at https://gist.github.com/KK4TEE/c41b4fb789a01cef6122
{
FOR eng IN MyList
{
IF eng:flameout
{
LOCK THROTTLE TO 0.
LOCK STEERING TO SHIP:FACING. //May not be needed depending on craft design
PRINT "Decoupling Stage " + stage:number.
PRINT " ".
STAGE.
WAIT 1.

STAGE.
LIST ENGINES in MyList.
PRINT "Stage " + stage:number + " activated!".
PRINT " ".

UNLOCK STEERING.
}
}

IF runmode = 1 //Launch Sequence
{
STAGE.
FOR eng IN MyList
{
SET tmax to eng:maxthrust.
}
SET g to KERBIN:MU / ((KERBIN:RADIUS + SHIP:ALTITUDE)*(KERBIN:RADIUS + SHIP:ALTITUDE)).
SET t to twr*(SHIP:MASS*g).
LOCK THROTTLE TO t/tmax.
LOCK STEERING TO HEADING(0, 90).
PRINT "Main engine ignition!".
PRINT " ".
WAIT 2.

STAGE.
PRINT "Launch clamps disengaged!".
PRINT "WE HAVE LIFTOFF!!!".
PRINT " ".
WAIT 2.
LOCK STEERING TO HEADING(90, 90). //Potentially add a wait here for large vessels with less control authority (SAS/RCS)

SET runmode to 2.
}

ELSE IF runmode = 2 //Gravity turn
{
IF SHIP:VERTICALSPEED > 50 //Change as needed depending on vessel design
{
LOCK STEERING TO HEADING(90, 85).
PRINT "Commencing gravity turn.".
PRINT " ".
WAIT 3.

UNLOCK STEERING.

SET runmode to 3.
}
}

ELSE IF runmode = 3 //Throttle control
{
FOR eng IN MyList
{
IF eng:ignition AND NOT eng:flameout //Need this because stowed/flameout give maxthrust = 0
{
SET tmax to eng:maxthrust.
}
}
SET g to KERBIN:MU / ((KERBIN:RADIUS + SHIP:ALTITUDE)*(KERBIN:RADIUS + SHIP:ALTITUDE)).
SET p to VECTORANGLE(ship:facing:vector, ship:up:vector). //90-p = angle above horizon, p = angle from straight up; Formula from https://github.com/KSP-KOS/KOS/issues/664
SET teff to twr*(SHIP:MASS*g).
SET t to teff / COS(p).
LOCK THROTTLE TO t/tmax.
//Change as needed depending on vessel design (or omit??)
WHEN SHIP:ALTITUDE > 12000 THEN //11.5 km -> 0.1 atm
{
SET twr to 1.3.
}
WHEN SHIP:ALTITUDE > 24000 THEN //23 km -> 0.01 atm
{
SET twr to 1.0.
}

IF SHIP:APOAPSIS > 100000
{
LOCK THROTTLE TO 0.
LOCK STEERING TO PROGRADE.
PRINT "Suborbital trajectory achieved.".
PRINT "Current AP: " + round(SHIP:APOAPSIS).
PRINT " ".

SET runmode to 0.
}
}
}

SET SHIP:CONTROL:PILOTMAINTHROTTLE TO 0.
WAIT UNTIL SHIP:ALTITUDE > 70000.

Challenge 1 was adjusting the throttle control because as the rocket pitches over, not all of the thrust goes to counteracting gravity. The effective thrust then, can be calculated by thrust(eff) = thrust * cosine(pitch angle). The real challenge was calling the pitch angle because SHIP: PITCH returns something else because of the original kOS design. Fortunately, I found a command that computes the angle between the SHIP:FACING and SHIP:UP vectors, which corresponds to the pitch from vertical. So with thrust(eff) = twr*(mass*g), where g is a function of altitude, and thrust = thrust(eff)/cos(angle), I can still adjust the throttle by thrust/maxthrust. Now it is a function of both altitude and angle. (Essentially, it throttles down with increasing altitude and up with increasing angle.)

I’m not sure if I like this but I included a couple triggers to change the desired twr at 12 km and 24 km which correspond to 1/10 and 1/100 sea level pressure. It does give a shallower trajectory once leaving the thickest part of the atmosphere and also avoids temperature indicators appearing. I’m still experimenting with this part of the code.

Challenge 2 was dealing with staging which gave me a lot of trouble – (a) when an engine is stowed or out of fuel, it returns a maxthrust of 0 meaning I was trying to divide by 0 for throttle = thrust/maxthrust which breaks the code. This was easy to fix by adding an if loop to only set tmax to maxthrust if the engine had been activated and was not flameout. (B) Harder to fix was the rocket flipping out during staging. I locked throttle to 0 during staging so it wasn’t trying to use the last throttle from the launch stage. I also played around with a temporary steering lock and then unlocking again after the engine ignited. Unfortunately, without fins on the upper stage, the craft always flipped out. After adding fins, I actually didn’t have to add the temporary steering lock for the 1.25 m design. If locked to SHIP: PROGRADE, the craft actually started flipping again, but SHIP:FACING or SHIP:HEADING kept the upper stage on course. For the 2.5 m design, I did have to lock the steering, and SHIP:FACING worked best. The images below using SHIP:FACING for both designs.

Ao6CrIs.jpgI think it is interesting how different the final trajectories are in map mode as well as when different events occurred. I may still need some more optimizations to improve the general applicability.

Another big change was changing to a runmode format to separate the steps of the mission. I adapted the basic outline from a

and the corresponding code.

Next Up: Optimizing orbital circularization using some suggestions given previously. I’m really looking forward to comparing the efficiency of the launch to the Mission 02 code. Since this will return to an ordinary mission report, I’ve uploaded the code and craft files from the interim reports to Dropbox. (I have a separate save for the optimization testing from my standard missions - to explain any inconsistencies with file naming.)

Code and Craft Files: Interim A-C

Edited by BlkBltChemie
Link to comment
Share on other sites

Sorry, not sure I followed this - the staging stops when the ship is out of fuel. I see the no fuel at all primarily as a limitation for potential refuelling missions - I don't want to stage if I have a tanker ready to rendezvous and refuel. As for parachutes (and fairings for that matter), I'm leaning more towards using action groups.

What I'm saying is that normally you don't want to stage all up in quick sucession until you burn all your fuel. Say, in most launches you'll hit suborbital flight still quite low in the atmo ( say, 30ish Km ) and you'll need to cut out engines until you reach Apoapsis ... it is very rare the launch where you burn all the thing in one go. Same OFC for fairings deployment ( you only want to do that high in atmo ) or the chutes, but those are easly action grouped as you said, so it is a minor concern.

I may not be reading this correctly, but I think I am having the engine tell me its thrust (well max thrust) at a given altitude/pressure. The thrust I'm calculating is the thrust I need to obtain my target TWR. But like I said, maybe I am misreading/misunderstanding something here.

Ok, this one is my fault. I was actually saying you were doing it the best way, but also saying that if you really wanted, you could do the whole math based on the change of Isp with pressure, the change of pressure with altitude and your exact flight plan .... and in case of airbreathing engines in atmo mode, you also have to consider the speed of the ship ... in other words, the issue can get quite mathy ( and I strongly advice you to not go that way :D ).

Now, onto the Report :D

Link to comment
Share on other sites

The issues you're having with staging , if I'm reading your rocket and your programming correctly( I might not ), might be because you're staging when the ship velocity is close of the speed of sound. In 1.x there is a huge spike in drag in the transsonic region and staging at that velocity ( in fact even keeping prograge if the ship top is convoluted enough ) ) can be hugely problematic if the top of your ship is draggy enough. There are three ways of dealing with that: giving your ship more control authority ( like you did ), reduce drag ( mostly fairings usage ) or to make that the separation occurs at a time the ship is not suffering so much drag. The last one can be done by either increasing or decreasing speed at separation if you don't want to change the ship, but increasing it might send you to too much steep launch profile, so IMHO it would probably be better to reduce the speed ( or alternatively reduce the TWR at launch a little so that the separation occurs a little later and higher : less air=less drag= less issues ).

That said, I don't think you need to avoid the thermal gauges too much. In fact, due to the fact that KSP was forced to make their parts to heat up a lot more than RL because otherwise there would be no reentry heat to speak off ( Kerbin typical low orbit orbital speeds are just a little above Mach 9, so if realistical heating was up, you would most likely not see any heating at all until you got above Kerbin escape velocity ), thermal gauges light up too soon on launches and if you go by them, your launch will cost a couple hundreds of m/s in dV. My rule of thumb is that if I don't see reds, there is no issue :D

On the code proper ... it looks good enough. I would add some sanity checks at certain points ( say, the typical 45ish degrees at 10 km high ) just to see if stuff is not going down the drain. Redundancy, is key :D

Link to comment
Share on other sites

This thread is quite old. Please consider starting a new thread rather than reviving this one.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...