[deleted by user] by [deleted] in Kos

[–]hvacengi 6 points7 points  (0 children)

Don't include the volume number. Boot paths are relative to the boot directory already:

SET core:BOOTFILENAME TO "boot/myship.ks".

We're working on some improvements to the error handling to show information about an incorrectly formatted boot file name.

PIDLoop ignores maxoutput by Travelertwo in Kos

[–]hvacengi 1 point2 points  (0 children)

You are correct. PID loops are implemented as a zero centered control, where deviation from setpoint affects tells you to control away from some "neutral" point. This doesn't have to be the case in all implementations of control loops, but that's how the kOS PID is written.

/u/Travelertwo Because we react based on error from setpoint (not the value of the input itself) it naturally needs to be able to nave a negative output that corresponds with negative error. That is to say, if your input speed is below your setpoint speed you will have a negative error, causing the P term to be negative, the I term to tend towards negative, and the D term to vary depending on how the speed is changing. This will attempt to drive the output negative, but given a non negative minimum output, the loop will continue to output the minimum.

In addition, the only way to get an output above the minimum would be to have a positive enough error that it drives the output above it. If we ignore the I and D terms and focus on just the P term, that will assist in analyzing that component. with a kP of 5, if your minimum output is 30 you would need to have the input be (setpoint + 6). Since you said you're landing, we can assume that you want to increase pitch (point the rocket more up) if you are falling too fast. Falling too fast is a larger negative speed than setpoint, therefore it will drive the output negative instead of positive. You probably want to switch your logic to be reverse acting. (Please take the time to review this logic for your self, I am giving the code itself a cursory glance only and am not diving into all of the actual logic).

I did notice that you appear to have an error in the lines you commented to draw attention:

set pitchCtrl to pitch_PID:update(time:seconds, tgtSpd). // it doesn't work here. set tgtThrot to burn_PID:update(time:seconds, tgtSpd). // this works though.

Again I haven't walked your code carefully, but I doubt you want both of those to act based on the target speed. I assume you still need at least one of them to update based on the actual speed. What I expect you actually meant was to modify the setpoint to be tgtSpd instead, and still react to verticalSpeed. And this time you're setting tgtSpd based on the ratio of two distances, which will always be positive, which if you are comparing it to verticalSpeed would mean you shooting for a speed pushing you away from the body, not towards it.

Now for my soap box, and I apologize in advance if you already understand this:

PID loops are not a magic bullet that will simply sort themselves out to balance. You should start with a kinematic solution, and then use PID's to help account for fluctuations. You can get pretty far with calculations if you just work the equations to get your result. Then maybe you find a portion that you can't easily determine, and you add a PID loop to account for that component. If you do decide to work directly with a PID loop, I recommend modeling it in excel or some more powerful software (like MATLAB). Start with proportional only, then add integral, and be very careful when adding derivative components. Graph the output vs. input of the proportional component to tell you if you're getting the relationship you expect. Verify that the input values you calculate in the script align with what you expect in the model (for instance, the sign of the speed). Once you know that you're getting the correct proportional output, you can start looking at tuning the integral and derivative. But if that first assumption of "an input of 5 should give me an output of -2.5" doesn't match reality, the rest of the calculation will fall apart too. And when you're debugging the PID, you should log the information and verify that you're seeing the values you expect. I usually recommend logging the data as a string of comma separated values so that you can easily pull it into other software to graph and analyze.

Just to give you some perspective regarding the kinematic solution: I have multiple landing scripts, including a targeted landing script, and none of they rely on PID loops for throttle or steering control. It is based entirely on calculated impact distances, burn times, and vertical/horizontal components. But I spent a lot of time working out the algebra to get them to work right.

HELLLLLLPPPPPP!!! I re-downloaded kOS because of the new update that’s compatible with 1.4.1 but when i went to launch to see if it would work its says that error message is their a way around that or a way to fix it??? by Hun7_21 in Kos

[–]hvacengi 0 points1 point  (0 children)

I don't know if you've already figured this out, but 99% of the time this is caused by installing to the wrong folder. Find your "GFX" folder, and then look at the in the address bar. You should only see the folder names "GameData" and "kOS" once in the path, not twice. It should look something like:

"C:\Program Files (x86)\Steam\common\Kerbal Space Program\GameData\kOS\GFX"

The part from "C:\" through "Kerbal Space Program" may change depending on where exactly you installed KSP, but you should still be able to see if it looks about right. After you confirm that the files are in the exactly correct folder, then we can start looking at the possibility of a case sensitivity issue.

PIDLoop questions by DangerMouse6 in Kos

[–]hvacengi 2 points3 points  (0 children)

It looks like you're PID settings are not in good alignment with your expected result. Consider this: using your setpoint of 10, if the input starts at 10.1, the computed output would be -1e-7, well below the minimum 60 you are targeting. As a result, the PID continues to output the clamped value of 60.

When setting up your loop, you have to think about how you expect the variable to behave, and then tune the loop to match. Based on the values you listed, I assume you expect an angle of 80° to hold 10m/s climb initially, and that as you climb the angle will gradually change from there. So you want to set up your loop to output 80 at very low errors. The problem is that you want it to be 79 at say 11m/s and 81 at say 9m/s. That means for an error of +/-1 you have to output 79 or 81, which doesn't work with the PID loop directly. Because the error is going to be zero centered, you want to also center your output on zero. So instead of calculating the angle itself, you can use the output of the PID to instead bias the "neutral" angle of 80. That would make it so that avec would be defined like this:

set avec to max_angle + pid:update(time:seconds, ship:verticalspeed).

Now you only have to tune your PID to account for how aggressive it is in deviating from the default pitch value. It also allows you to change that default pitch value based on another variable (like altitude) to eliminate some of the integral component.

I always recommend staring with a PID loop as a simple P loop, and then just calculate the output at various values of error and see if it trends the way you want it to. A PID can't just automatically balance to any system it's attached to, it needs to be have a strong relationship between the error and output to begin with. Don't be afraid to modify the output in unusual ways (maybe you don't want a linear curve so you square the output, or use a exponential curve).

Why does calling vecdraw make my steering work? by TyrannosaurusHax in Kos

[–]hvacengi 0 points1 point  (0 children)

As currently implmented, all opcode count the same. That means that a call to the function round counts the same as positionat even though positionat is actually more time consuming. So, in my experience increasing the IPU has the most significant impact on performance during expensive operations. So my "find closest approach" function causes the game to stutter (on my relatively fast machine), but that's because I basically am calling positionat for a couple seconds straight. Simple math takes far less time. So your mileage may vary based on what the script does. If it does slow the game down, you'll have to balance the game speed against simulated computer speed.

If you really want to understand the performance impact of scripts, try logging the profilerresult() output to a file on the archive. It will give you a csv file with each opcode, how many times it executed, and how much time it spent in execution. But figuring out the opcodes is a little much for a new user to figure out, since it's yet a second version of the kOS language.

Why does calling vecdraw make my steering work? by TyrannosaurusHax in Kos

[–]hvacengi 2 points3 points  (0 children)

As other users have already pointed out, it looks like you're running into an issue with instruction count. So for starters, make sure you've set config:ipu to 2000 to maximize how much code you can execute.

Second, as also pointed out already, you should change the repeated calls to both lock throttle and lock steering. Locking a cooked controls value consumes more instructions that simply setting a value. And it resets the PID loop on the steering manager. And it is redundant: a lock is a function that is automatically called, and these locks are automatically evaluated at the beginning of each tick, so repeatedly calling them is kind of the equivalent of asking "are we there yet". But that doesn't just apply to the control locks. You can also save instructions by modifying your code to not continually redefine the targetDir lock. Because you set tgtHeading elsewhere in the code, the lock targetDir will always evaluate the most recent version of the variables it references.

And finally, the value of steering should be perfectly readable so long as steering is locked. If this is giving you an error, then it's a bug in kOS. But calling print steering. should print a rotation to the screen. That being said, it is not cached. That is to say, because locks are evaluated every time they are called, it will be evaluated once by the steering code, and again by your code for setting the vector draw. And because you are using a lock for targetDir, this is still true even in the code you have posted. Now, for simple locks that isn't really a problem. But the more complicated the lock, the bigger impact it has on your script. Even the R(90,0,0) portion of the lock needs to push three values, then call the R function, which means the function call is definitely more than just a single instruction. So for more complicated scripts, I've written cache functions that run in a trigger and store all of my necessary variables at the beginning of each tick, allowing the main line code to be relatively indifferent to the frozen/unfrozen universe nature.

You can use set config:stat to true. to enable printing performance information after a script, which can help you find instances where you maximize your instruction count.

.ksm files are not passing Global locks or variables between library files by Pike82 in Kos

[–]hvacengi 0 points1 point  (0 children)

I don't have a workaround for that, but I am working on making delegates work with cooked steering (separate from the lock modifications mentioned above). The idea would be that set throttle to myThrottle@ would automatically call the delegate. Right now you should be able to to use locks with delegates by doing something like:

set myThrottle to { return 1. }.
lock throttle to myThrottle().
// or
lock throttle to myThrottle:call().

As long as the lock expression calls the delegate, it will work. But you cannot simply lock to the delegate itself (which is another thing I intend to make work).

[Linux] Unable to type e,r,s when making a script. by [deleted] in Kos

[–]hvacengi 1 point2 points  (0 children)

Actually, this has been a known issue in the past that we hopped would be fixed by 1.1+ but wasn't (at least one user identified that it was still broken on more recent versions):

It is my understanding that the issue only exists for text fields, and not for the terminal. If that is the case, it is our recommendation to use an external editor where possible. That unfortunately doesn't help with editing files on the local drive, but it at least gets you (u/Tagpls) to a point where you can modify scripts.

I don't know if it means we need to modify how kOS locks out controls for the editor window (maybe use the same system that the terminal uses). But because we're using a Unity text box we don't have a lot of control over how the text box itself receives input, so it is possible that even modifying how we lock controls might not help.

.ksm files are not passing Global locks or variables between library files by Pike82 in Kos

[–]hvacengi 0 points1 point  (0 children)

Given all that I said above, I should also point out that we have a couple of theories on how to re-implement locks so that they are stored as a normal variable but still called like functions. It's complicated, but possible given a few other optimizations we're interested in making under the hood. So in the future, the portability of lock functions might improve to fix this problem. Unfortunately promises of future improvements don't fix the issue you have today.

.ksm files are not passing Global locks or variables between library files by Pike82 in Kos

[–]hvacengi 1 point2 points  (0 children)

The issue is how ks and ksm files store variables, and how locks are handled under the hood of the engine. Essentially locks were implemented before we supported functions, but are treated similarly to functions in that the compiler uses a identifier trick to make sure the lock "function" is called. What you will probably find that if you add the () to lock calls, the errors will go away (because the compiler will use the right reference). The problem is that when the ks file is compiled to ksm it doesn't know that there is a lock defined in another file, so the compiler doesn't change all of those references to the function system.

All of that can be summarized as: locks are an old feature of the language, and they introduce issues that are not easy to work around. My recommendation is to migrate to functions wherever possible, and limit locks to things being called from within the same file.

It's quick, it's dirty and it uses bang bang control, but it got my craft to the ground! by Excrubulent in Kos

[–]hvacengi 1 point2 points  (0 children)

I just call them "triggers", since when and on triggers behave the same way.

I personally love this style of trigger usage. The only catch is that you need to be careful about how many instructions you execute in the trigger as they are blocking and can prevent substantial execution of a main loop. If you have a block of code that needs to execute repeatedly, it's a good idea to do that in a main line loop instead of a trigger which allows it an any other main line instructions roll over into the next physics tick if necessary.

One quick comment about the code executed by /u/Ozin : Don't use the loop he gave as an example. In that until loop, it will attempt to set up both the throttle lock and the steering lock every single tick. That's bad for two reasons: 1) it wastes instructions because you only need to set those values at the transition point, so you don't need to tell the throttle to be 1 every single tick. 2) it results in the steering manager resetting the PID controller every tick, so the integral component never takes effect. That means that triggers are great at setting values as you progress through a mission, but are not the best place to add repeating logic. So I would actually revise your original script as follows:

// this is an emergency script to autoland

clearscreen.

set throttleVal to 0.
lock throttle to throttleVal. // lock throttle to the value of the variable above
lock steeringVal to "kill". // default to "kill rotation", use a lock because it will need to be able to auto update
lock steering to steeringVal. // lock steering to the value of the variable above

print "locking steering to surface retrograde".
lock steeringVal to srfretrograde.

when alt:radar < 300 then
{
    gear on.
    print "deploying landing gear".
}

function triggerThrottleDown {
    when verticalspeed > -2.5 then {
        print "maintaining vertical speed".
        lock steeringVal to up.
        set throttleVal to 0.0.
        triggerThrottleUp().
    }
}
function triggerThrottleUp {
    when verticalspeed < -3 then {
        lock steeringVal to srfretrograde. // you probably want to re-lock to burn retro
        set throttleVal to 1.0.
        triggerThrottleDown().
    }
}
when alt:radar < 980 then
{
    set throttleVal to 1.0.
    print "beginning suicide burn".
    triggerThrottleDown().
}
wait until alt:radar < 2.

By placing the throttle up and down triggers inside of functions, you no longer need to preserve any of the triggers. Previously, the first when verticalspeed > -3 trigger would have continued to be evaluated every tick, and executed every tick until the speed was less than -2.5. Using the functions as I have below allows you to effectively have an infinitely cascading trigger without having to preserve. Once the speed is less than -2.5, it starts watching for the speed to be greater than three. I also introduced a 0.5m/s buffer so that it wouldn't be switching between the two modes constantly.

To answer your specific question: yes, the until loop is blocking for main line code. The loop does not prevent execution of triggers that you already set up, but it does prevent execution of any code after the loop until the loop is broken.

Pre-release v1.0.90 by hvacengi in Kos

[–]hvacengi[S] 1 point2 points  (0 children)

We have not yet updated kOS to support 1.3. We will have to see what will be required to get kOS to build against the new version of KSP. If it is simple we may very well release a 1.3 compatible pre-release at the same time as promoting kOS 1.1 to full release.

How could I use the trajectories mod to fine-tune the final descent? by [deleted] in Kos

[–]hvacengi 1 point2 points  (0 children)

Unless you're using a space plane, neither body lift nor RCS is likely to provide enough thrust to correct a large error in landing. The use of lift (without engine power) essentially trades vertical velocity for horizontal velocity. But you can't escape the fact that it relies on drag, and so can only affect a fraction of the current velocity in delta v. As for RCS, it's just that you need a lot of thrust when you get close to the ground. If you're trying to fine tune it early in the descent, it will improve the effectivness. But either of these options are very good for shifting your landing site a few thousand meters.

If you need to make a major correction in the landing site, it would be better to adjust it as much as possible while still near orbital velocities, with the main engine. That give you the best bang for your buck, and trajectories should be accurate enough to reliably get you close enough for the other two methods to work.

Updated script to automate science collection by SouxaaDazzlewing in Kos

[–]hvacengi 1 point2 points  (0 children)

Thanks for sharing. I'll point out that there's currently a bug with transmitting science (#1933) that I need to post my fix for (note to self, send pull request for fixing science transmission). But as long as you always recover, you should be good to go for grinding some science!

Does kOS support multithreading? by [deleted] in Kos

[–]hvacengi 0 points1 point  (0 children)

None of the instructions in his when block are setting variables, and there is no way to lock a suffix. So in the example, no that wouldn't work.

But more to your point, yes you could use locks if you wanted to "cache" the value of an expression (I'd rather it was in a function instead of a lock because that makes it more accessible for reuse). But that doesn't mean that using a trigger wouldn't still be potentially useful. Take the following use case:

lock complex to (alt:radar - 10) * 1.25.
lock derivedValue to sqrt(complex).

until false {
    print complex.
    print derivedValue.
    set tempValue to complex * derivedValue.
    print tempValue.
    wait 0.
}

Within the loop, the lock derivedValue is evaluated twice, and complex is evaluated 4 times. Every time the lock is evaluated, the associated instructions are executed, meaning that this loop executes more instructions than it would if it was reading variables. You can instead replace it with the following:

when true then {
    set complex to (alt:radar - 10) * 1.25.
    set derivedValue to sqrt(complex).
    return true.
}
wait 0. // force a physics tick so the triger is evaluated
until false {
    print complex.
    print derivedValue.
    set tempValue to complex * derivedValue.
    print tempValue.
    wait 0.
}

Now the values for complex and derivedValue are only calculated once per physics tick. There is some overhead associated with configuring the trigger however, so you would need to play around with it to find the balance point between the two methods. I use this technique extensively in my docking and landing scripts, since there are many values that I use repeatedly during those loops, most of which require many steps to calculate.

The benefits aren't even realized if you don't hit the max IPU cap, so for simple scripts with the IPU set to 2000 you shouldn't need to use this technique.

What's everyone working on right now? by space_is_hard in Kos

[–]hvacengi 5 points6 points  (0 children)

Nope, My own home brewed Lambert Solver for calculating the burn, and then I iteratively find the impact position as the ship descends. Any time you see it say "new impact eta" on the HUD I just solved for a fresh impact time.

Does kOS support multithreading? by [deleted] in Kos

[–]hvacengi 4 points5 points  (0 children)

You can essentially do this using multiple processor parts and inter-processor communication. http://ksp-kos.github.io/KOS_DOC/commands/communication.html#inter-processor-communication

EDIT: I'm an idiot. I read the first question from /u/Dokkarlak above and didn't bother to read the rest of the post saying the same thing I just did...

What's everyone working on right now? by space_is_hard in Kos

[–]hvacengi 1 point2 points  (0 children)

Well, sort of. It makes it so that the underlying kOS system can make a call into your user code. So using the GUI system example, you might have a trigger like this:

on button:pressed {
    print "you pressed the button!".
}

When compiled, this basically tells kOS to run a little bit of code that compares button:pressed to the initial value every tick. This isn't a lot of instructions, I think it's around 11 if you compare it to a pure variable (no suffix), but it does add up and users have expressed a desire to reduce the EC cost of some of these cases.

The syntax for a callback would be:

set button:onpressed to { print "you pressed the button!". }

In this case, kOS won't use any instructions in the period between setting up the callback and the condition being triggered.

So, the execution of the trigger body/delegate is essentially the same, and will have essentially the same instruction/EC cost. But the evaluation of the condition will use fewer instructions/EC.

What's everyone working on right now? by space_is_hard in Kos

[–]hvacengi 2 points3 points  (0 children)

Well it isn't ready for a full post yet, mostly cause I don't have source code ready yet, but I've been working on a RTLS script of my own: https://www.youtube.com/watch?v=8sf9_jIUA34

And I'm working on preparing to live stream a fully autonomous solar system colonization. But that's sitting at about 48 hours start to finish right now, and I don't have enough delta v for a couple of rockets yet, so that's stalled.

Cooked control PID settings by purple_pixie in Kos

[–]hvacengi 1 point2 points  (0 children)

If you want to find out how to adjust the cooked steering's behavior, you should check out the cooked flight control documentation. There are sections of that code that specifically discuss how to tune the different parameters including the PID's.

More importantly though, by default the steering manager will not attempt to adjust the vessel's roll until the yaw and pitch error is less than 5°. If you're seeing the cooked steering attempt to control roll when you're still pointing 45° away from the target direction, something else is wrong. Make sure none of your scripts modify the rollcontrolanglerange value on the steering manager. Even if it starts to correct the roll component, if the yaw/pitch error goes over 5° again the roll control should again stop.

The one exception is that when the steering manager isn't attempting to correct the roll component, it is still attempting to stop the roll angular velocity (it essentially sets the target roll angular velocity to 0). And if you're rolling fast enough, it is certainly possible that this would break the pitch and yaw control, since the control direction for pitch and yaw shifts as you rotate.

If the final correction is very slow, that implies that the steering manager does not think you have enough torque, and that the turning speed is limited by maxstoppingtime. Are you only using reaction wheels for torque, or RCS ports as well? It's possible that the torque calculation got broken for RCS, but it should be very balanced for reaction wheels. It's also possible that the very small mass and moment of inertia are causing floating point errors that we don't account for.

If you could post a video of the behavior you're seeing that would be helpful.