Jump to content

[1.3] kOS Scriptable Autopilot System v1.1.3.0


erendrake

Recommended Posts

I've been banging a head against several brick walls for a few hours now, trying to get a reliable automatic staging script to work but I'm not getting anywhere because of what I think is incorrect numbers from KSP itself. Has anyone else noticed this?

My basic code is like this:


set throttleVal to 1.
lock throttle to throttleVal.

lock currentLiquidFuel to ship:liquidfuel.
set lastLiquidFuel to currentLiquidFuel.
set currentFuelFlow to 0.
set lastFuelFlow to 0.
set lastCheck to 0.

until 0 {
set now to time:seconds.
set currentFuelFlow to ((lastLiquidFuel - currentLiquidFuel) / throttleVal) / (now-lastCheck).

//.... do stuff

set lastFuelFlow to currentFuelFlow.
set lastLiquidFuel to currentLiquidFuel.
set lastCheck to now.

wait 0.1.
}

To my understanding currentFuelFlow should give me a reliable fuel flow, taking into account changes in throttle and fluctuations in loop duration. The number should be quite stable as long as all engines have fuel. It is not. Well it is most of the time but there are short and sudden fluctuations (around double the fuel flow for one or two cycles, then back to the average) every now and then.

The idea of the script is to stage when the fuel flow suddenly drops by more than a certain threshold but as long as I experience these glitches that is impossible since it will stage immediately after one of the glitches.

Note that the throttleVal doesn't change at the moment so it could be taken out but this is in preparation of ascend scenarios where the throttleVal will change.

Link to comment
Share on other sites

The idea of the script is to stage when the fuel flow suddenly drops by more than a certain threshold but as long as I experience these glitches that is impossible since it will stage immediately after one of the glitches.

Is that not your answer? Build a slightly more conservative trigger that needs the new value to be there for a loop or 5 to 10, so that you are sure this is permanent.

Link to comment
Share on other sites

Sure, that's the workaround.

I put this up in order to find out whether anyone else experienced these kind of glitches. kOS having the limited amount of memory that it has, I try to avoid workarounds wherever possible cause they eat up space and are yet-another source for bugs. :)

Link to comment
Share on other sites

put this up in order to find out whether anyone else experienced these kind of glitches. kOS having the limited amount of memory that it has, I try to avoid workarounds wherever possible cause they eat up space and are yet-another source for bugs. :)

Though it should probably be a feature and not an (accidental) bug, I feel that dealing with noise and the occasional strange reading is pretty much part of making a good control system. If only real life were so decent to provide picture perfect values.

But, like I said, this should be done in a controller fashion and not by accident , which seems to be the case here.

Edited by Camacha
Link to comment
Share on other sites

Heureka!

Turns out it was a bug on my end, happening because my currentLiquidFuel variable was locked to ship:liquidfuel. That caused the value to change between the currentFuelFlow calculation on top of the loop and the assignment to lastLiquidFuel at the end of the loop, introducing deviations if one cycle took much longer than the previous one.

New code still doesn't work but thats a time-resolution problem which should be easy enough to fix - after watching the match :)

Changes markeed in bold-underline.


set throttleVal to 1.
lock throttle to throttleVal.

[B][U]set [/U][/B]currentLiquidFuel to ship:liquidfuel.
set lastLiquidFuel to currentLiquidFuel.
set currentFuelFlow to 0.
set lastFuelFlow to 0.
set lastCheck to 0.

until 0 {
set now to time:seconds.
[B][U]set currentLiquidFuel to ship:liquidfuel.[/U][/B]
set currentFuelFlow to ((lastLiquidFuel - currentLiquidFuel) / throttleVal) / (now-lastCheck).

//.... do stuff

set lastFuelFlow to currentFuelFlow.
set lastLiquidFuel to currentLiquidFuel.
set lastCheck to now.

wait 0.1.
}

Link to comment
Share on other sites

Sure, that's the workaround.

I put this up in order to find out whether anyone else experienced these kind of glitches. kOS having the limited amount of memory that it has, I try to avoid workarounds wherever possible cause they eat up space and are yet-another source for bugs. :)

koS has plenty of memory. Did you mean disk space?

Link to comment
Share on other sites

[ stuff ]

I don't necessarily think this is related to the problem, but I think it's a really good idea to add a line as shown:


set throttleVal to 1.
lock throttle to throttleVal.

[B][U]set [/U][/B]currentLiquidFuel to ship:liquidfuel.
set lastLiquidFuel to currentLiquidFuel.
set currentFuelFlow to 0.
set lastFuelFlow to 0.
set lastCheck to 0.

until 0 {
set now to time:seconds.
[B][U]set currentLiquidFuel to ship:liquidfuel.[/U][/B]
set currentFuelFlow to ((lastLiquidFuel - currentLiquidFuel) / throttleVal) / (now-lastCheck).

//.... do stuff

wait 0.00001. // <------ NEWLY ADDED LINE.
set lastFuelFlow to currentFuelFlow.
set lastLiquidFuel to currentLiquidFuel.
set lastCheck to now.

wait 0.1. // <---- Maybe reduce this to something very small like 0.0001
}

This is because of some features of how kOS works that I've just found over the last few weeks that is awaiting documentation (I wrote the document, but it's not publishable until some other things about the next release are worked out because of other unrelated changes in the documentation that might not still be true anymore once the release is finalized.).

Anyway that feature is this: kOS executes a certain number of underlying CPU instructions per physics tick of the KSP universe. (The exact number can be found by using PRINT CONFIG:IPU.) Keep in mind that the number of underlying instructions per line of code is not a 1:1 match. There are generally about 1-5 instructions per expression term - ish. Anyway the important thing is that the entire physical universe, including the clock time, the amount of consumables left (ship:liquidfuel), the position, the velocity, etc, is utterly frozen during the running of those statements. If you SET VAR TO TIME:SECONDS, then SET VAR2 TO SHIP:LIQUIDFUEL, then SET VAR3 TO SHIP:VELOCITY:ORBIT, and all those commands just happen to occur in the same KSP physics tick, then they represent a correct snapshot of that one instant in time, BUT, if the end of a physics tick happens to occur right in the middle of them, then the later statements are taking measurements from a different physics tick than the previous ones, i.e, like so:

Imagine this scenario:


some code here.

// <-- A new physcs tick happens to start here.

some more code here.

some more code here.

set var1 to time:seconds.
// <-- The physics tick happens to end here.
// <-- A new physics tick starts here.
set var2 to ship:liquidfuel.
set var3 to ship:velocity:orbit.

If that occurs, then var1 is referring to a clock time that is a whole physics tick earlier than the time the var2 and var3 measurements were taken. For a program like you're trying to make that could throw off your results by quite a bit. In fact, exactly by doubling and halving factors, as it makes timeslice measurements exactly twice as long, or half as long, as expected.

So the fix is that when you want to take samples of several measurements of the universe that were meant to refer to a single snapshot in time rather than being taken from a mix of two different snapshots in time, you have to do something that guarantees the physics tick won't end in the midst of taking those samples. And the way to do it is to force kOS to pause a moment and wait for the start of the next physics tick immediately before starting into the section of code where you take all the measurements. That way you know it will get through all the measurements in one go before the next border between physics ticks.

And the WAIT statement does that because no matter what the WAIT condition is, no matter how small the WAIT time is, it's guaranteed to put the program to sleep until the next physics tick at least, where it wakes up and checks the wait condition to see if it's time to continue executing. (Effectively this means its actually impossible for WAIT to wait for a period of time less than one physics tick. If your physics ticks are occuring once every 1/10th of a second, then a WAIT 0.05 and a WAIT 0.00001 are effectively identical.)

Saying WAIT 0.00001 is a way of saying "wait for the next physics tick rather than 0.00001 seconds, since there's no way your KSP is running with physics ticks smaller than 0.00001 seconds."

Link to comment
Share on other sites

I can't comment on the glitches, but a different way to do a staging program is to list all engines, then check each engine to see if it has flamed-out, if an engine has flamed-out, then stage, if not, don't.

Link to comment
Share on other sites

I can't comment on the glitches, but a different way to do a staging program is to list all engines, then check each engine to see if it has flamed-out, if an engine has flamed-out, then stage, if not, don't.

This is a lot more reliable. Back in kOS 0.9, I wrote an asparagus staging logic for the Duna mission that had to do all the calculations about fuel consumption rate and it had a lot of sensitive problems. That was before you could query for flameout of engines. Now that you can, it's much more reliable to just do that.

Link to comment
Share on other sites

Hmmm I might check that, thanks a lot :).

In the meantime I got the fuel-consumption based script to run reliably though. "Reliably" meaning it runs without error on 4 different staging setups (single->single, double->single, four->double->single, asparagus) running each setup a couple of times, even with alterating throttle settings.

In case anyone is interested:


// fuel flow test bed
declare parameter ffMaxStages, ffThres.
set tickSize to 0.1.

set throttleVal to 1.
lock throttle to throttleVal.
stage.

set currLF to ship:liquidfuel. set lastLF to currLF.
set ffStaged to 0. set ffStageT to 0.
set currFF to 0. set lastFF to 0.
set lastFFChk to 0. set now to time:seconds.

until 0 {
set now to time:seconds.
set currLF to ship:liquidfuel.
set currFF to ((lastLF-currLF)/throttleVal)/(now-lastFFChk).

if currFF<lastFF*ffThres AND now-1>ffStageT AND ffStaged<ffMaxStages {
// current fuel flow below threshold AND
// last time we staged is more than a second away AND
// we're still going through configured amount of stages
stage.
set ffStageT to now.
set ffStaged to ffStaged+1.
print "staging!" at (0, 3).
} else {
print " " at (0, 3).
}

log currLF + " " + lastLF + " " + throttleVal + " " + now + " " + lastFFChk + " " + currFF + " " + lastFF + " " + ffStaged + " " + ffMaxStages + " " + ffThres to fflog.

print "liquid fuel: " + round(currLF, 1) + " L " at (0, 0).
print "fuel flow: " + round(currFF, 1) + " L/s " at (0, 1). print "last flow : " + round(lastFF, 1) + " L/s " at(25, 1).

set lastFF to currFF.
set lastLF to currLF.
set lastFFChk to now.

wait tickSize.

}

Call with run fuelflow2(2, 0.7). if you have two stages to separate and you consider 70% fuel consumption as compared to earlier a safe indication for a stage being burned out.

Link to comment
Share on other sites

I can't comment on the glitches, but a different way to do a staging program is to list all engines, then check each engine to see if it has flamed-out, if an engine has flamed-out, then stage, if not, don't.

I just tried that approach... wow... that's much better. Definitely more reliable (although as I said I kinda got my approach to work) and also much shorter. I'm saving over 200 bytes with the flameout-based staging in my ascend script compared to my fuelflow-based staging.

Thanks a ton :D

Link to comment
Share on other sites

So, RemoteTech is back., and Starstrider said integration works. Do I need to wait for a new version, or will this version work?

the current pre-release is blocked by the remotetech integration, something changed with the new version of RT that brings KSP to its knees when you request your connection status. I have set aside tonight for hashing it out.

It might be an issue with RT but at this point we have changed so much that i cannot indemnify kOS either.

Edited by erendrake
Link to comment
Share on other sites

Quick question about NODE: can it be used to automatically execute maneuver nodes or "just" to set them up?

it is for setup and gives you useful vectors for executing the NODE but it cannot control the throttle.

Link to comment
Share on other sites

Quick question about NODE: can it be used to automatically execute maneuver nodes or "just" to set them up?

My mission toolkit here contains the exenode subprogram which does exactly what you are looking for.

Link to comment
Share on other sites

I've got another question:

Suppose I have two kOS modules on my craft somewhere. Lets call them A and B.

If run

set myvar to 0.
until 0 {
print myvar.
wait 1.
}.

on A, it will start printing 0 all over the screen and I can't do anything else until I kill the program with ctrl-c.

I can however close the terminal window and open a new one for B and do whatever I want. I can even read and write files (but not variables) to the currently occupied module A. All that is nice. I think it would be possible to have a bunch of modules running systems and have some master program tell them what to do by writing files to them and funky stuff like that.

Now what I wonder is:

Is there a way to get into the same situation (A is executing program, B is waiting for input) without closing the terminal window and manually opening a new one?

Can I run a program on B from A's prompt? Is it planned to be possible in the future or far future?

I'm not trying to do anything specific, I'm just curiously messing around :P

Link to comment
Share on other sites

Not sure if I understand your question correctly the_bT but you can absolutely run a program that's stored on B from the console of A.

If you do a list volumes. you get a list of all "harddrives". Now, important to keep in mind is that the harddirve of the console you have open at the moment is always volume 1. So console A lists itself as volume 1 and console B lists itself as volume 1 as well. That can be confusing at first, so keep that in mind (or use rename volume).

In your example, say you have a program called "runme" on the disk of console B. Open console A and type this:


switch to 2. // this is the disk from console B
run runme.
switch to 1. // return back to own disk.

Link to comment
Share on other sites


switch to 2. // this is the disk from console B
run runme.
switch to 1. // return back to own disk.

That's not what the_bT was asking for. That's "This computer runs a program that's stored on the other computer's drive."

what the_bT wanted was more like "This computer tells the other computer to run a program stored on it's drive."

(Also, I think it included a request for redirected output from the other computer to this computer's terminal.)

There's a beta feature in the works to run a program on another CPU. But the problem of displaying the output is still not addressed. Right now the only way to switch the terminal window is to close it and reopen it on the other CPU. I'd like to see some sort of tabbed buttons on the terminal to quickly swap which CPU the terminal is displaying for you.

Link to comment
Share on other sites

Guest
This topic is now closed to further replies.
×
×
  • Create New...