Jump to content

[1.3] kOS Scriptable Autopilot System v1.1.3.0


erendrake

Recommended Posts

I don't know about anything else but a roll program will be very difficult to create for all contingencies. Afterall rockets all behave differently.

Basically you should be able to spec your current orientation, and simply add or subtract 180 from the roll component. What's more difficult is making sure the program knows when you've achieved your orientation. It has something to do with the dot product of both vectors, but I've never done anything like that.

Also yes, you need to turn SAS off before performing maneuvers and turn it back on before the end of the program.

Edited by Cpt. Kipard
Link to comment
Share on other sites

Lastly was [ heading(x,y) ] deprecated? It doesn't throw any errors, it seems to be ignored; now I must use [ heading x by y] to get a response from the controls.

I had the exact opposite experience. [ heading x by y ] was deprecated and I had to change to [ heading(x,y) ].

Link to comment
Share on other sites

Thank you all for addressing some of my issues.

I'll keep rolling how I have been.

That's very odd about the HEADING.

Here are some other points I had:

This is probably the most important for me to address right now as I need that extra layer of info to fly from IVA properly.

I saw in a video but cannot find it again, where you can continuously echo variables on the screen? This is important as I am doing more and more flights IN cockpit and finding the features lacking. My Apoapsis, Periapsis and ETA to Apoapsis would be nice to know at all times.

Also

Have my tests been conclusive? Am I right in that you cant change rotation/bearing with SAS on? It seems so, so now I turn it off before all maneuvers and back on after that code completes.

It's great to get feedback from you all. I hope I'm not a bother. I've googled my butt off, but some of the documentation seems it's for older versions.

Be well all!

Link to comment
Share on other sites

Very sorry to bother you all. I am loving this mod, so much so that I didn't sleep last night. I have a few questions.

I saw in a video but cannot find it again, where you can continuously echo variables on the screen? This is important as I am doing more and more flights IN cockpit and finding the features lacking. My Apoapsis, Periapsis and ETA to Apoapsis would be nice to know at all times.

If I understand your question correctly I assume you mean have a line of text that is continously updating? so it's not scrolling?

If that's the case look into positioning. I THINK it was something like

[s]print "altitude:" + altitude (0,2).[/s]

It's actually

print "altitude: " + altitude at (0,2).

For more information check out the kOS wiki (community opperated) list of commands at http://kos.wikia.com/wiki/List_of_all_Commands

I've had plenty of bugs where they are called out in the console, but the wrong line is displayed.

Yeah, I've had that before. It's been a while since I've messed with KSP but I think it had to deal with something not being terminated correctly. A missing "full stop", or a missing quote or bracket.

And as far as SAS goes, I always forget to turn it off when using kOS, so I try to remember to turn sas off before or after a lock heading command, and then at the end of the program turn it back on. Seems to do the trick most of the time.

Edited by Sma
Link to comment
Share on other sites

print "altitude: " + altitude at (0,2).

This is better:

print "altitude: " + round(altitude,0) + "  " at (0,2).

The reason for rounding is that altitude is a floating point number and you could get a display like 1234.5667781.

The reason for adding [ + " " ] after the altitude is to handle the case where the altitude might become small enough to lose a digit. You want to wipe out the characters after the altitude so that if you go from this:

altitude: 10000

to this:

altitude: 9999

The extra "0" leftover from the '10000' gets wiped out. Otherwise you'll end up with the "9999" looking like this:

altitude: 99990

Link to comment
Share on other sites

This is such a useful thing I just found buried in the github code, and it was in the documentation but it sneaked past me without a major announcement and I didn't see it.


set dir to Up + R(20,0,0).
set unitV to dir:vector.

That suffix ":vector" is what I'm talking about. It converts the direction into a unit vector pointing in that direction.

To see how happy I am to find out that this exists, remember that this is the kosscript code I had to use when I had to build the rotation matrix manually without the help of the Unity engine's matrix operations:


declare parameter tfDir.

// Rotation angles for rotation matrix:
set tfA to tfDir:yaw.
set tfCosA to cos(tfA).
set tfSinA to sin(tfA).

set tfB to tfDir:pitch.
set tfCosB to cos(tfB).
set tfSinB to sin(tfB).

set tfC to tfDir:roll.
set tfCosC to cos(tfC).
set tfSinC to sin(tfC).

set tf11 to tfCosA*tfCosC + tfSinA*tfSinB*tfSinC .
set tf21 to tfCosC*tfSinA*tfSinB - tfCosA*tfSinC .
set tf31 to tfCosB*tfSinA .
set tf12 to tfCosB*tfSinC .
set tf22 to tfCosB*tfCosC .
set tf32 to 0-tfSinB .
set tf13 to tfCosA*tfSinB*tfSinC - tfCosC*tfSinA .
set tf23 to tfSinA*tfSinC + tfCosA*tfCosC*tfSinB .
set tf33 to tfCosA*tfCosB .
set tfV to V( 0,0,1 ).

set tfUnit to V(
tf11*tfV:x + tf21*tfV:y + tf31*tfV:z ,
tf12*tfV:x + tf22*tfV:y + tf32*tfV:z ,
tf13*tfV:x + tf23*tfV:y + tf33*tfV:z ) .

THAT, is now replaced with this one line:


set tfUnit to tfDir:vector.

Normally in most cases I dislike when the kOS mod does all the work for you, but in this case I like it because it doesn't feel like "cheating" when real navigation computers would have the ability to perform vector rotations with a transformation matrix as a very low level operation buried down in the hardware. Even the Apollo computer had that. (sort of. It ran on a very RISC set of only about 12 instruction opcodes, which then had a set of middleware instructions layered on top of them to preset a virtual machine language to the rest of the system that had more than those 12 opcodes. The matrix and vector operations were in that middleware pseudo-ML layer.)

Edited by Steven Mading
Link to comment
Share on other sites

Could someone help me with some maths?

I've been developing a node execution script, an I've got it pretty close to what I want, but there's still one thing that makes it perform poorly with very short burns or interbody burns. I'm almost positive it's down to the fact that the throttle can't be maxed instantaneously. There's a split second delay while it throttles up and down. Id like to try something but I'm not sure how to implement it.

TntZNgc.png

A. This is how the burn is performed right now. The green line is the function that controls the acceleration. It's timed based on maxthrust and throttle is locked to a mass/startmass ratio to keep acceleration constant. Burn time here is (T1 * 2 + T2)

B. With a quick calculus refresher I remembered that the blue area under a function (integral) here represents delta-v so I simply changed the geometry while keeping the area the same. I want to determine T1 arbitrarily and throttle up according to function B. Question is: How do I do that? Ideally I'd like to have a multiplier that's >0 and <1, which I could ramp up over T1*2, and then down again over the same amount of time.

Please help. This has been bothering me for a really long time.

This is such a useful thing I just found buried in the github code

What have you used that for?

Edited by Cpt. Kipard
Link to comment
Share on other sites

Please help. This has been bothering me for a really long time.

The biggest problem you're going to run into with any attempt to calculate this is that you literally cannot detect the duration of time that your sloped sections of the graph take. Nothing you query from kOS will tell you "this is where the real throttle is at the moment, rather than the throttle setting it's seeking toward." So you can't tell how long it took to get from zero to 100% from inside the code. The instant you set the throttle to 1, kOS will *claim* it really is at 1 right away when you query it, whether it really has gotten there yet or not.

Here's how I usually deal with it: I don't do what you're trying to do. Predicting the burn time ahead of time and then unconditionally telling it to burn for that long seems a very fragile algorithm to follow given that the numbers in KSP aren't 100% accurate. Instead I look for a way to query the expected ending condition (burn until WHAT is true? Until the orbit is circular? Until the encounter is at its minimum periapsis?, etc.), and then I make that check be the thing that actually causes the burn to end, utterly ignoring the predicted burn time. I only use the predicted burn time for some fuzzy heuristics, never for a thing I have to "trust" it for.

Also, I usually come up with a way for that end-condition check to "notice" when the condition is getting near but not there yet, so I can slow the throttle down gently and therefore not overshoot the end condition. For example, when circularizing the orbit, I start slowing the throttle down as the eccentricity gets closer to 0.0, and then cut the throttle off when the craft gets closer to periapsis than apoapsis altitude (meaning the craft has rotated them around to the point where there's no point in burning any further from the current location).

What have you used that for?

A number of uses so far, where I used my longhand version of it, that I can now go through and replace with the shorter version.

The mod gives you "north" and "up", but only in the form of Directions, not in the form of vectors. If I had them in the form of vectors then I can get my own axes rotated relative to the surface, and thus make calculations in that surface-relative coordinate system that's so much better to deal with for the last steps of landing. So I used that code to get the "up" unit vector from the "up" R() rotation, and the "north" unit vector from the "north" R() rotation. Once I had those two then I could get the east vector by taking the cross product of the north and up vectors. (And I used to have to do the cross product in longhand too, but that now has a function VCRS(A,B) for it.)

Another place where having it is handy is in transforming the direction to a target into a vector to the target that can be multiplied, scaled, and combined with other vectors to help in writing docking scripts (which I'm just starting now but first I'm looking at some problems in the actual mod code).

Edited by Steven Mading
Link to comment
Share on other sites

This is better:

print "altitude: " + round(altitude,0) + "  " at (0,2).

The reason for rounding is that altitude is a floating point number and you could get a display like 1234.5667781.

The reason for adding [ + " " ] after the altitude is to handle the case where the altitude might become small enough to lose a digit. You want to wipe out the characters after the altitude so that if you go from this:

altitude: 10000

to this:

altitude: 9999

The extra "0" leftover from the '10000' gets wiped out. Otherwise you'll end up with the "9999" looking like this:

altitude: 99990

Ahh yes, forgot about those. Actually I looked up one of my old codes and I also converted it to km instead of meters.


print "Kerbosyncronous KommSat Launcher " at (0,0).
print "--------------------------------------------------" at (0,1).
print "| Apoapsis: | Periapsis: | Altitude: " at (0,2).
print "--------------------------------------------------" at (0,3).
print "| " + round(apoapsis/1000,2) + "km" at (0,4).
print "| " + round(periapsis/1000,2) + "km" at (15,4).
print "| " + round(altitude/1000,2) + "km" at (34,4).
print "|" at (49,2).
print "|" at (49,4).
print "--------------------------------------------------" at (0,5).

For some reason I had the other pipes added in later on in the program lol

Link to comment
Share on other sites

@Steven Mading: Beware that the VECTOR suffix doesn't necessarily work with all rotations, only with those that were (internally) created using a vector. (In your old script you are calculating a bunch of stuff that is later multiplied by zero, so the script could be simpler).

@Cpt. Kipard: Check the node execution script I posted here. It reduces the throttle so the burn takes at least 1s and that allows the script to time it more precisely, and also has a throttle up delay to start the burn a little early (determined experimentally, may be different for you).

Link to comment
Share on other sites

@Steven Mading: Beware that the VECTOR suffix doesn't necessarily work with all rotations, only with those that were (internally) created using a vector. (In your old script you are calculating a bunch of stuff that is later multiplied by zero, so the script could be simpler).

Would you object if it was adapted so that it does work regardless of whether it was internally made with a vector or not? Because the meaning of the R(..,..,..) format you get from the built-in rotations IS in fact to assume the starting direction (pitch, yaw, and roll all being zero) prior to any of the rotations is the Z axis. So you can always treat it like it was crated from the unit vector V(0,0,1).

All rotations in fact start from the presumption that you began with a known initial direction, otherwise they don't mean anything.

"I'm steering in a direction that is 20 degrees to the left".

"uh… 20 degrees to the left of WHAT?"

Without a well defined meaning of that "WHAT", you can't steer toward that direction because it's not defined what it is. Experimentally, I found out that in kOS, the "WHAT" is always the Z axis.

In other words, I don't understand how kOS can make use of a Rotation like R(… ,…., …) to steer by if there exist rotations that don't have a default presumed starting direction.

Link to comment
Share on other sites

Thanks Steven and marianoapp, but those solutions don't really suit my play style.

Does kOS have a function that limits it's output to some maximum or minimum?

Yes, MAX and MIN.

Actually my script is very similar to the solution you proposed, with the difference that the throttle ramp-up area is left to the game's own throttle up delay. The burn is then executed a little short and after it finishes a throttle ramp-down is performed proportional to the node's remaining dV (or orbit eccentricity, as Steven suggested).

If you want to control the ramp-up rate you could use a lock that returns the throttle as a function of time, but bear in mind that the code won't necessarily be executed in exact intervals and that could introduce some errors.

Link to comment
Share on other sites

Cpt Kipard: If you really do want to use the timed burn style, then you need to force the ramp-up and ramp-down times to be predictable so you can calculate the triangular parts of your graph. What matters isn't that it has to be super fast, but that it has to be KNOWN so you can perform your calculations.

Here's an idea of how to ramp it up predictably. Let's say that you've decided upon a 2 second ramp-up time and a 2-second ramp down time, and doing the calculation that way you've come to the conclusion that with those timings you'd need a burn that looks like this:

Ramp up from 0.0 to 1.0 in 2 seconds.

Then burn steady at 1.0 for 10 seconds.

Then ramp down from 1.0 to 0.0 in 2 seconds.

(I'm leaving it to you to work out the math for how to decide that that's the burn you need, but lets say for the sake of the example that you've already determined that those are the timings you want) You could implement that like so:

This would mean that you want a slope at the beginning of the graph of 1/2 (2 seconds to get from 0.0 to 1.0)., and at the end of the graph a slope of -1/2 (2 seconds to get from 1.0 to 0.0). You can make a triangular graph that does that with this formula:

1: throttle = 3.5 - abs( (t-7)/2 )

(Note the number 7 is derived from "it's half of 14", which is the total duration of the ramp up, steady burn, and ramp down parts of the graph (2+10+2).)

(Note the number 3.5 is derived from "it's the midpoint time, multiplied by the slope: 7*(1/2)". That makes it be the max height of the triangle.)

(and the divide by 2 is because you want a slope of 1/2 in this example).

Then the middle steady part of the burn is described by this formula:

2: throttle = 1.0 [ a constant ]

Graphing the two of them you get this: (the brown line is formula 1, and the blue line is formula 2).

4ftg7ii.png

If you take the minimum of those two, you get this graph:

3: throttle = min( 1.0, 3.5 - abs( (t-7)/2 ) )

u6a21Yn.png

That's the graph you want the burn to do.

This is the code that would accomplish that burn:


set rampSlope to 0.5. // Assume this is fixed no matter what.

// I leave it as an exercise for you to work out how you'd come up with this next number, given
// the rampSlope.

set steadyTime to 10.0.

// Total time, 14 in this case:
set tTotal to 2/rampSlope + steadyTime.

set tHalf to tTotal/2.
set triangleTop to tHalf * rampSlope.

set tZero to time:seconds.

// Now, the entire throttle burn envelope can be controlled with this one expression:

lock throttle to max( 0, max( 1, triangleTop - abs( (t-tHalf )*rampSlope ) ) ).

The max(0, ….) part is there so that when the expression goes negative, the throttle stays at zero.

Edited by Steven Mading
Link to comment
Share on other sites

(In your old script you are calculating a bunch of stuff that is later multiplied by zero, so the script could be simpler).

True, but the reason it looks like that is that I didn't know at first what the internal starting point of the rotation was and I had to determine it experimentally by tweaking the script again and again until it worked. Until I knew which way around it was it was easier to leave the entire transformation matrix populated fully even for the zero terms, otherwise I'd have to re-type it every time I tried a different starting point (because that causes different terms to zero out.)

Link to comment
Share on other sites

Thanks both of you that's exactly what I wanted. :D

Next step. Error correction.

Let's say the node is executed in this way but there's e.g. 1m/s left in the node, would kOS recognise that remainder correctly if I ran the node script again?

Edit:

I've tested it and it looks like the remainder is completely ignored by kOS. Is this normal behaviour? Maybe that's something that should be fixed.

Edited by Cpt. Kipard
Link to comment
Share on other sites

The remaining deltaV displayed for a node gets a bit wonky near 0. It would probably not be the best idea to try and get it down to 0.

Cheers

Hans

Yes. Even flying manually I never get it all the way to zero. It seems to get down close to zero and then start going back up again. I suspect this is because the aim would have to be 100% accurate for it to get to zero. It's probably calculating the difference between your current velocity and the intended end velocity, and I say "velocity" rather than "speed" quite deliberately here because I mean the vector, not the scalar. The direction matters not just the magnitude. So let's say for example that you set up a maneuver node that was meant to achieve a delta-V of 100 m/s in a particular direction, but you were burning 2 degrees off from the planned direction. Then after adding 100 m/s of delta-V you still aren't at the intended velocity. You're 2 degrees off from the intended velocity. Your maneuver node at this point would tell you that your current velocity is still 100*sin(2 deg) away from the intended velocity, or 3.49 m/s. But that's the closest it gets as your velocity passes just missing the intended mark and starts going farther past it.

The only way to get it to exactly 0 is for the aim to be literally exact and perfect, which is utterly impossible due to floating point math precision anyway, not to mention that the steering algorithm will have a little bit of wobble in it. It will just get near zero without reaching it.

Suggested fix: In a loop continually compare the node's current delta V magnitude to the node's delta-V magnitude that you had on the previous loop iteration. This will let you detect if it's getting smaller (current is less than previous). Instead of burning until delta-V magnitude is zero, burn until the delta-V magnitude starts getting larger instead of getting smaller.

Edited by Steven Mading
Link to comment
Share on other sites

Once you get close to the node, it's generally better to check the thing you were trying to accomplish in the first place, for example, if you create a node to circularize at apoapsis, cut the engines when your periapsis gets within X of your starting apoapsis.

Link to comment
Share on other sites

Once you get close to the node, it's generally better to check the thing you were trying to accomplish in the first place, for example, if you create a node to circularize at apoapsis, cut the engines when your periapsis gets within X of your starting apoapsis.

I agree in principle, but not with that specific example. That can be a dangerous check that fails to stop the burn.

It has two problems:

1: If X is too small, you can blow past X faster than the script responds and then when periapsis and apoapsis swap positions continued burning won't make the gap smaller, but larger.

2: If It takes too long to execute the burn so that you aren't precise enough in executing it centered on apoapsis, then its possible to never get apoapsis and periapsis within X, and yet its still time to stop burning because continued burning won't make it any better. The check I prefer is to stop the burn when you've rotated periapsis to within 90 degrees of your current position - to stop the burn as the apoapsis and periapsis are starting to swap positions and you're halfway between then. To see how to calculate that, google the phrase "True Anomaly".

Link to comment
Share on other sites

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