Jump to content

[1.3] kOS Scriptable Autopilot System v1.1.3.0


erendrake

Recommended Posts

6 hours ago, Chabadarl said:

http://ksp-kos.github.io/KOS_DOC/commands/files.html#copypath-frompath-topath

New file will be created at TOPATH, along with any parent directories if necessary. Its contents will be set to the contents of the file pointed to by FROMPATH.

 

Looked at that page, but missed info about bolded part and how TOPATH is interpreted by kOS. Thanks for pointing in right direction.

Anyhow, tried this in game:

copypath("0:/mun_land","").

And does exectly what I was asked for.

Btw. speaking of documentation I found small error, regarding nodes. On page http://ksp-kos.github.io/KOS_DOC/tutorials/exenode.html

is stated that command for picking up next maneuver node is this:

set nd to nextnode().

however that gives error. Proper command should be this:

SET MyNode to NEXTNODE.

Last one is from this page http://ksp-kos.github.io/KOS_DOC/structures/vessels/node.html#global:NEXTNODE

Probably lot's of changes were made within kOS, but tutorial examples were not updated.

That was not stoped me to create more/less multipurpose function to excecute maneuver node. This one should be in library file and executed from main script.

Spoiler

 


function ManeuverBurn {
	parameter nd.
	parameter ErrorMargin is 0.1. // acceptable error margin
	parameter output is "".
	
	local max_acc is ship:maxthrust/ship:mass. // current ship acceleration
	//set burn_duration to nd:deltav:mag/max_acc. // Calculating burn time
	local np is nd:deltav. // picking up point from node deltaV vector
	lock steering to np.

	set output to "Turning to maneuver.".
	hudtext(output,2,4,60,white,false).

	wait until nd:eta <= ((nd:deltav:mag/max_acc)/2 + 60). // waiting until node is close + 60s spare time
	// picking node direction if something changed
	set np to nd:deltav. // picking up point from node deltaV vector
	lock steering to np.

	set output to  "Node time + 60 reached.".
	hudtext(output,2,4,60,white,false).


	// prepare execution trough loop
	local VelGroundPID is PIDLOOP( 0.15, 0.05, 0.1, 0.0, 0.0 ).
	set VelGroundPID:MINOUTPUT to 0.
	set VelGroundPID:MAXOUTPUT to 1.
	VelGroundPID:RESET(). // reseting previous ITERM and ERRORSUM
	local myThrottle is 0. // ensure that is local

	wait until nd:eta <= ((nd:deltav:mag/max_acc)/2 + 1). // waiting again until is right time to execute

	set output to "Executing engine burn.".
	hudtext(output,2,4,60,white,false).


	// using PID to determine if we reached goal instead of complicated calculation
	local done is false.
	until done
	{
		set VelGroundPID:SETPOINT to 0.
		VelGroundPID:UPDATE(TIME:SECONDS, (-1)*nd:deltav:mag). // using vector scalar info for pid 
		set myThrottle to VelGroundPID:OUTPUT.
	
		set np to nd:deltav. // picking up point from node deltaV vector
		lock steering to np.
	
		// safety check, to ensure that ship is turned to desired direction
		// ship facing need to be inside 2 degree error margin from maneuver vector
		if round(VANG(SHIP:FACING:VECTOR, nd:deltav),10) < 2 {
			SET SHIP:CONTROL:PILOTMAINTHROTTLE TO myThrottle.
		}
		else
		{
			SET SHIP:CONTROL:PILOTMAINTHROTTLE TO 0.
		}.			
		wait 0. // wait for one timeframe
		if nd:deltav:mag < ErrorMargin {
			set done to true.
		}.
	}.
	SET SHIP:CONTROL:PILOTMAINTHROTTLE TO 0.
	unlock steering.
	SAS ON.
	set output to "Maneuver done.".
	hudtext(output,2,4,60,white,false).
}. // end of function

Throtlle PID could have some more optimization, timewarp stop command should be added before trottle up/turning ship and other small stuff.

Example of usage could be something like this:

set MyNode to nextnode.

set Moutput to "".
ManeuverBurn(MyNode,0.1,Moutput).
print Moutput.

Function does it's job, but feedback on terminal is not written as variable for output is primitive one, it is not of complex class with suffix. So that print command write only blank as it was set outside of funtction block. That behaviour is expected as described on this page: http://ksp-kos.github.io/KOS_DOC/language/user_functions.html#passing-by-value

I want to provide better feedback to user what is happening, to not get a feeling that script is stuck with something.
Currently I put text message on screen, but it is not so good if someone plan to use it trough telnet terminal, or trough kOS terminal in IVA, for example.

So instead of returning primitive, could be better that inside of ManeuverBurn function I add a call for some other function. for example something like this:

Spoiler

function ManeuverBurn {
	parameter nd.
	parameter ErrorMargin is 0.1. // acceptable error margin
	parameter display_block is function local_display{parameter output_something is "".}. // unsure if this is proper syntax
      // main code doing some stuff.
      display_block(output_stuff). // calling of display block on terminal
}.
  
function outside_display{
  parameter some_output is "".
  // display some data:
  print "Some common craft data " at (1,1).  
  print "kOS autopilot state: "+some_output at (1,2).  
}.

// function call example from main script:
set MyNode to nextnode.
ManeuverBurn(MyNode,0.1,outside_display()).

 

I know that instead of passing function as parameter, I could just simply create global function call for "display_block", but I want ManeuverBurn function to be in library, providing maximum reusage from various other scripts, as most probably display block will be different for various craft.

Somehow, I feel that is possible to do in kOS, but I can't find reliable example in documentation. Is it something like that even possible in kOS ?

Link to comment
Share on other sites

16 minutes ago, kcs123 said:

Somehow, I feel that is possible to do in kOS, but I can't find reliable example in documentation. Is it something like that even possible in kOS?

Delegates are perfectly legal parameters, and you may set the value to an anonymous function just like your example.  I prefer to use a named function however, just to keep everything clean.  If the function is a separate block, your parameter declaration is shorter and you can more easily format/comment the code:

// functions replacing DefaultManeuverDisplay in calls to ManeuverBurn should
// include a single parameter, and should display that parameter to the user
// as a sting by some means and/or formatting.
function DefaultManeuverDisplay {
	parameter str.
	// print message like: "T+30 - Hello World"
	print "T+" + round(missiontime) + " - " + str.
}

// setup the parameter to use a defined function, just to keep the code clean
function ManeuverBurn {
	parameter nd, ErrorMargin is 0.1, DisplayBlock is DefaultManeuverDisplay@.
	DisplayBlock:call("Node Burn Executing..."). // I prefer to explicitly call
	// execute the node...
	DisplayBlock:call("Node Burn Complete!").
}

function HudTextDisplay {
	parameter str.
	// display message via hudtext like: "Hello World"
	hudtext(str, 30, 3, 18, white, false).
}

ManeuverBurn(nextnode, 0.1, HudTextDisplay@).
Link to comment
Share on other sites

Thanks @hvacengi, that is exactly what I hoped it is possible. I know that I read about delegates in documentation, but I forgot that term "delegate" is related with that stuff I wanted to accomplish. Switching between several programming languages on daily basis and english not being native language does not help much. Still need to diggest large part of kOS syntax and quite nice set of "hidden" features that I didn't even know it is already included in kOS until I stumbled upon something that I need it.

 

Link to comment
Share on other sites

Alpha test of GUI ToolKit

I've put together a simple but powerful GUI system for kOS that allows you to make real on-screen GUIs like this:

He50UAz.png

Using code like this:

// Create a GUI window
LOCAL gui TO GUI(200,100).

// Add widgets to the GUI
LOCAL label TO gui:ADDLABEL("Hello world!").
SET label:ALIGN TO "CENTER".
SET label:VSTRETCH TO True. // Take up spare space.

LOCAL ok TO gui:ADDBUTTON("OK").

// Show the GUI.
gui:SHOW().

// Handle GUI widget interactions.
// Can safely wait and GUI will still be responsive.
UNTIL ok:PRESSED { PRINT("Waiting for GUI"). WAIT(0.1). }

// Hide when done (will also hide if power lost).
gui:HIDE().

I'm keen to add anything you might find missing before this becomes a candidate for inclusion in kOS proper, so if you'd like to try it out, here is a zip file of the current pre-release for KSP 1.2.1, plus the GUI.

https://github.com/WazWaz/KOS/releases/

The documentation is in GameData/kOS/html/structures/misc/gui.html in this package.

Obviously, only report problems with this release that relate to the GUI, and only complain to me. If you're on github, you can also discuss the branch here:

https://github.com/KSP-KOS/KOS/pull/1878

Enjoy! Post pics!

Edited by Waz
whitespace matters
Link to comment
Share on other sites

@Waz and @Steven Mading, I think it is quite cool addition for kOS. I already see multiple possible usage of it and I didn't even finished downloading. For example, I got my own setup for AGs on crafts that are "mandatory", like flap controls, engine toggle, solar panel toggle, cargo bay ... Leaving very few left to be used for kOS script. In cases that AG extended is not installed (for various reasons, not yet updated for current version of KSP, conflict with some other mods or user just find it to complex for usage).

I already rewriting my scripts to maximise usage on new features of delegates and passing parameters to functions and even whole programs. For example, my new script to launch rocket in orbit looks like this:

Spoiler

// Arguments for programm must be on top
parameter MyHeading is 90. // initial heading for orbit - influence starting inclination
parameter MyApoapsis is 120000. // Desired APOAPSIS of orbit
parameter ApETA is 27. // time before reaching Apoapsis when circularization burn start
clearscreen.
// load the functions I'm using:
//run once lib_PID. // "once" alows to execute libraray only one time
runoncepath("lib_navball").

// Declaration of PIDs for pitching and velocity
// Velocity change can't work with Solid Fuel Boosters

                            // Kp, Ki, Kd, min, max control  range vals. // Kp - most influence on initial overshoot value
set VelGroundPID to PIDLOOP( 0.15, 0.05, 0.1, 0.0, 1.0 ). // Throttle/Vertical velocity PID controller - some overshoot

// initial info on screen
print "Rocket Launch kOS autopilot". // Row 0.
print "--------------------------------------------".
print "Launching parameters:".
print "Heading = "+MyHeading.
print "Apoapsis = "+MyApoapsis.
print "                                            ".
print "     Stage once to start kOS autopilot      ".
print "     Press CTRL + C to terminate program    ".
print "--------------------------------------------".
print "Autopilot state:                            ". // Row 9.
print "Velocity:        (m/s)                      ". // Row 10.
print "Altitude:        (m)                        ". // Row 11.
print "                                            ". // Row 12.

// function that will display dynamic data on terminal
function DynamicDisplay{
  parameter output. // dynamic data - mandatory parameter
  parameter startCol is 17.
  parameter startRow is 9. // define where the block of text should be positioned

  print output at (startCol,startRow).
  print round(SHIP:AIRSPEED,2) + " "at (10,startRow+1).
  print round(SHIP:ALTITUDE,2) at (10,startRow+2).
}.

function AltitudePitch{
// Define pitching curve up to 10 km
// Goal is 45 degree at 10 km
    local Pitching is 83.
    if (SHIP:ALTITUDE > 1000) or (SHIP:AIRSPEED > 80){
        set Pitching to 77.
    }.
    if (SHIP:ALTITUDE > 2000) or (SHIP:AIRSPEED > 100){
        set Pitching to 75.
    }.
    if (SHIP:ALTITUDE > 3000){
        set Pitching to 72.
    }.
    if (SHIP:ALTITUDE > 4000){
        set Pitching to 70.
    }.
    if (SHIP:ALTITUDE > 5000){
        set Pitching to 68.
    }.
    if (SHIP:ALTITUDE > 6000){
        set Pitching to 65.
    }.
    if (SHIP:ALTITUDE > 7000){
        set Pitching to 60.
    }.
    if (SHIP:ALTITUDE > 8000){
        set Pitching to 60.
    }.
    if (SHIP:ALTITUDE > 15000){
        set Pitching to 55.
    }.
    if (SHIP:ALTITUDE > 20000){
        set Pitching to 50.
    }.
    if (SHIP:ALTITUDE > 25000){
        set Pitching to 45.
    }.
    if (SHIP:ALTITUDE > 30000){
        set Pitching to 40.
    }.
    if (SHIP:ALTITUDE > 35000){
        set Pitching to 35.
    }.
    if (SHIP:ALTITUDE > 40000){
        set Pitching to 30.
    }.
    if (SHIP:ALTITUDE > 45000){
        set Pitching to 25.
    }.
    if (SHIP:ALTITUDE > 50000){
        set Pitching to 20.
    }.
    if (SHIP:ALTITUDE > 55000){
        set Pitching to 15.
    }.
    if (SHIP:ALTITUDE > 60000){
        set Pitching to 10.
    }.
    if (SHIP:ALTITUDE > 65000){
        set Pitching to 10.
    }.
    DynamicDisplay("Turning to: "+Pitching).
    return Pitching.
}.


SAS on.
// ensurance that there will not be conflict with stock autopilot and we can still use "magic" rotation wheels
SET SASMODE TO "STABILITYASSIST".

wait until SHIP:MAXTHRUST > 0. // waiting idle until staged once for launch
// program will not continue down until staged
SAS off.
DynamicDisplay("Launch started").

// staging whenever ship is out of fuel
// "WHEN" command is trigger or event. Command inside brackets will run when condition is met
// "PRESERVE." command ensure that event will be triggered again when craft run out of fuel again
// kOS CPU is not aware of this until it reached for first time
when SHIP:MAXTHRUST = 0 then {
    STAGE.
    print "Staged".
    DynamicDisplay("Staged                 ").
    preserve.
}.

// Initial throttle and heading
SET SHIP:CONTROL:PILOTMAINTHROTTLE TO 1.
lock STEERING to HEADING(MyHeading,90). // works better than UP direction as UP tend to rotate

wait until SHIP:AIRSPEED > 70. // no stearing until proper velocity gained
set myPitch to AltitudePitch(). // first input from Pitching curve function
// Lock is needed only once, outside loop, steering will be changed whenever myPitch changes
lock STEERING to HEADING(MyHeading, myPitch).

until (ship:APOAPSIS > MyApoapsis-10000) {
    set myPitch to AltitudePitch().
    wait 1.
}.

// for last 10 km switching to PID controled throttle
set VelGroundPID:MINOUTPUT to 0.
set VelGroundPID:MAXOUTPUT to 1.
VelGroundPID:RESET(). // reseting previous ITERM and ERRORSUM
set VelGroundPID:SETPOINT to MyApoapsis.
            
until (ship:APOAPSIS > MyApoapsis) {
    set myPitch to AltitudePitch().
    VelGroundPID:UPDATE(TIME:SECONDS, ship:APOAPSIS).
    set myThrottle to VelGroundPID:OUTPUT.
    SET SHIP:CONTROL:PILOTMAINTHROTTLE TO myThrottle.
    wait 0.
}.
// Desired orbit is reached at this point

SET SHIP:CONTROL:PILOTMAINTHROTTLE TO 0.
lock STEERING to ship:PROGRADE. // orbital prograde - to minimise drag
print "Apoasis reached at "+round(SHIP:AIRSPEED,2)  + "(m/s) / "+round(SHIP:ALTITUDE,2)    + "(m)".
DynamicDisplay("Apoapsis reached").

// waiting until craft reach space
wait until (SHIP:ALTITUDE > 70000).
lock STEERING to HEADING(MyHeading,0). // align with horizont until AP reached
hudtext("Steering set to horizont ",2,4,60,white,false).
print "Point to horizont at "+round(SHIP:AIRSPEED,2)  + "(m/s) / "+round(SHIP:ALTITUDE,2)    + "(m)".
        
// reseting circularization PID
set VelGroundPID:MINOUTPUT to 0.
set VelGroundPID:MAXOUTPUT to 1.
VelGroundPID:RESET(). // reseting previous ITERM and ERRORSUM
print "Velocity PID reset".
        
// Starting maneuver slightly before reaching Ap
//wait until (SHIP:ALTITUDE > ship:APOAPSIS - 3000).
wait until (ETA:APOAPSIS <= ApETA). // waiting until 20 sec before Ap.
set kuniverse:TimeWarp:rate to 1. // set timewarp to 1X, just to be safe
        
SET SHIP:CONTROL:PILOTMAINTHROTTLE TO 1.
print "Maneuver started at "+round(SHIP:AIRSPEED,2)  + "(m/s) / "+round(SHIP:ALTITUDE,2)    + "(m)".
        
wait until (SHIP:ALTITUDE > ship:APOAPSIS - 500).
lock STEERING to ship:PROGRADE. // it is enough to have one single lock
        
print "PID burning for stable orbit".
        
until (ship:PERIAPSIS > 71000) {
    set VelGroundPID:SETPOINT to MyApoapsis-1000.
    VelGroundPID:UPDATE(TIME:SECONDS, ship:PERIAPSIS).
    set myThrottle to VelGroundPID:OUTPUT.
            
    // safety check, to ensure that ship is turned to desired direction
    // ship facing need to be inside 2 degree error margin from orbital prograde vector
    if round(VANG(SHIP:FACING:VECTOR, SHIP:VELOCITY:ORBIT),10) < 2 {
        SET SHIP:CONTROL:PILOTMAINTHROTTLE TO myThrottle.
    }
    else
    {
        SET SHIP:CONTROL:PILOTMAINTHROTTLE TO 0.
    }.            
    wait 0. // wait for one timeframe
}.
print "PID burning circular orbit".
// to maximise efficiency, allow burning only when craft is close to Apoapsis
// using lower time than the first orbital burn as we are much closer to goal
// turning to horizont instead of prograde, to prevent raising Apoapsis too much
set BurnAllowed to false.
lock STEERING to HEADING(MyHeading,0). // align with horizont
when(ETA:APOAPSIS <= ApETA/2 ) and (BurnAllowed=false) then {
    set BurnAllowed to true.
    DynamicDisplay("Fine Burning              ").
    set kuniverse:TimeWarp:rate to 1. // set timewarp to 1X, just to be safe
    preserve.
}.
when(ETA:APOAPSIS >= ApETA )  and (BurnAllowed=true) then {
    set BurnAllowed to false.
    DynamicDisplay("Wait for fine burning     ").
    preserve.
}.
        
until (ship:PERIAPSIS > MyApoapsis) or (ship:APOAPSIS > MyApoapsis + 20000 ) {
    // Circularize
    set VelGroundPID:SETPOINT to MyApoapsis.
    VelGroundPID:UPDATE(TIME:SECONDS, ship:PERIAPSIS).
    set myThrottle to VelGroundPID:OUTPUT.
            
    if (round(VANG(SHIP:FACING:VECTOR, SHIP:VELOCITY:ORBIT),10) < 2) and (BurnAllowed=true) {
        SET SHIP:CONTROL:PILOTMAINTHROTTLE TO myThrottle.
        DynamicDisplay("Burning allowed ETA: "+round(ETA:APOAPSIS,1)+"(s)").
    }
    else
    {
        SET SHIP:CONTROL:PILOTMAINTHROTTLE TO 0.
        DynamicDisplay("Burning baned ETA: "+round(ETA:APOAPSIS,1)+"(s)  ").
    }.            
    wait 0. // wait for one timeframe
}.
        
print "Finishing launch program ".
        
hudtext("Orbit established. ",2,4,60,white,false).
        
// stoping program sequence
SET SHIP:CONTROL:PILOTMAINTHROTTLE TO 0.
SAS on.
wait 0.
SET SASMODE TO "STABILITYASSIST".
UNLOCK all.
SET SHIP:CONTROL:NEUTRALIZE TO TRUE. // returning controls to pilot - pitch/yaw/roll
// ---

 

Probably not the best one around, can be tweaked lot more, but it I was tried to be more as beginers tutorial of possible command usage, for others to catch up more quickly with kOS syntax, tweak it and use it as starting point. Example of usage would be like this:

// from terminal
runpath("/rlaunch",90,120000).

// from other script
set RocketHeading to 75.
set RocketApoapsis to 80000.
runpath("/rlaunch",RocketHeading,RocketApoapsis).

As soon as I finish this post and download, first thing to try is to create a GUI around it, so heading and apoapsis can be chosen with buttons or slider. Plan to extend it with craft possible target list, for proper inclination, apoapsis and launch window.

Hovering scripts can take even more advantage of this, as it require even more AGs to toggle between various settings. Instead of AGs, objects on GUIs can be used.

Sorry for a bit long introduction, but it will be easier to understand following. I don't think that new GUI will made terminal or telnet terminal usage obsolete. Terminal still can be use to show one type of data, or it can show same data on both, terminal and GUI, it is up to user to figure out what is suitable for him.

There is one possible issue, if AGs are excluded and only GUI buttons are used to pass commands/values. To solve this, buttons have to be able to toggle trough script commands like this:

set button:PRESSED to true.

And one more thing, for telnet/terminal usage, it should be possible somehow to send some data to remote kOS CPU, remote CPU have to be able to accept that data and based on received info be able to "press" button, while the rest of program keep runing in loop, doing whatever it is designed to do on remote CPU.

Also, IIRC there was conversation about being possible to comunicate between kOS CPUs on different crafts. There is no info in documentation about it and I didn't have much time to search for available videos and reddit on that topic. Some small example for it would be good. Nothing fancy, for example recently I was having situation that I needded to do docking with another craft on dark side of planet. Quite difficult to figure out where docking port is. Some script example that is able to toggle lights on craft that is not under direct player control would be enough for it.

EDIT: disregard striked out thing, I found it in documentation at Communication page.
 


@Waz, small critics for plugin code. IIRC usage of "foreach" commands create garbage in unity - memory leaks and FPS slowdowns.
kOSprocessor.cs file have it at line #855

Quote

foreach (var w in shared.ManagedWindows) w.IsPowered = true;

There is probably more of it. Why exactly it is issue is mentioned trough devnotes before KSP 1.2.0 release. Sorry, I no longer recall details, I just know that it cause issue. Should be avoided whereever possible and replaced with old fashion "for" loop.

Other than that, I don't see a reason why it should not be merged with main release. Still have to test it and make some screenshots.
 

Maybe even create thread in craft exchange forum, just for script/craft examples and screenshots/videos to keep this thread clean for bug reports and similar.

Edited by kcs123
Link to comment
Share on other sites

1 hour ago, Drew Kerman said:

so something like this for text input is done via TextField ?

YtZr3iA.png

Just started to play with new GUI and found that is unclear how to access data that user wrote ?
In documentation it is stated that available suffixes are:

CHANGED Boolean Has the text been edited?
CONFIRMED Boolean

Is "TEXT" suffix available to get/set data ? For folks familiar with C# my be obvious, but for some noob that just started to learn programing might not be. I just throwing blind guess here, have yet to try it in game.

 

 

Link to comment
Share on other sites

42 minutes ago, Probus said:

Programmers programming a program that lets you program your guidance program. :) 

Having significant amount of fun while doing it. Jokes aside, KSP + kOS provide a significant feedback and visualisation of various problems and tasks that can be easy applied on real life problems that you need to solve. Keeping in mind that it is still just mathematical model and game, though. Forcing you to (re)learn of some math too. :)

Here is small script as possible example of usage. Found some small difference between documentation and actual usage:

Spoiler


// New feature of creating GUI's
set Info_Win to GUI(600,800). // (width,height)
set TitleLabel to Info_Win:ADDLABEL("GUI example").
set NestedBox to Info_Win:ADDHBOX. // new GUI box nested inside parent Info_Win
set NestedLabel to NestedBox:ADDLABEL("Some info inside nested box").
set NestedLabel2 to NestedBox:ADDLABEL("Open info.ks file in editor to see comments").
set NestedInputData to NestedBox:ADDTEXTFIELD("something"). // to write something inside
// triger to know that data is accepted - ENTER key pressed inside text input field
when NestedInputData:CONFIRMED then
{
    hudtext("Changes confirmed "+NestedInputData:text,2,4,60,white,false).
    preserve.
}.

set Info_EmptySpace to Info_Win:ADDSPACING(20).
set Info_Checkbox to Info_Win:ADDCHECKBOX("CheckBox1",false). // CheckBox need two parameters, missing info in documentation for true/false
set Info_Slider to Info_Win:ADDHSLIDER(-1,1). // slider with min,max values
set ExampleButton to Info_Win:ADDBUTTON("Some value changer").

ON ExampleButton:PRESSED {
    print "Value from slider:  "+Info_Slider:VALUE.
    preserve.
}.

set Info_EmptySpace2 to Info_Win:ADDSPACING(40).
set CloseButton to Info_Win:ADDBUTTON("CLOSE").
Info_Win:SHOW().
wait until CloseButton:PRESSED.
info_win:hide().

 

Still have to put it in some more meaningful script.

 

Link to comment
Share on other sites

@kcs123 looks like you worked out the textfield :text attribute. Was the checkbox doc the only one I needed to fix? That foreach was fine (it's not executed every frame), but I found another one worth fixing.

I've spent some time porting my launch and node execution scripts to use the GUI, and I found a few things:

  • MARGIN - split in HMARGIN and VMARGIN
  • PADDING - split in HPADDING and VPADDING
  • Honour scoping so that UIs can be usefully made with locals, not just globals.
  • Add ADDHLAYOUT and ADDVLAYOUT - like HBOX/VBOX, but default to entirely no style or borders, just pure layout
  • A number of fixes, such as making LABEL honour HSTRETCH being set to false (and it will now default to false too)

I've updated the release zip file and edited the comment accordingly.

Link to comment
Share on other sites

@Waz, Checkbox is only thing I found so far, but I didn't advanced much. I want to re-write my hovering script to look more like a library, so I can more easy mess with user front end knowing that core funcionality work as intended.
Something that will create some fun over weekend, depending how much time I will have for KSP.

Thing that could possible be missing is default position for GUI, when first time is created. In center of screen is always craft that anyone want to watch trough flight. My personal "favorite" position for such GUI would be just right of default position of kOS terminal window. Or leave it as it is, but add option for default position when GUI is created for first time.

Something like this:

// Current command
set Info_Win to GUI(600,800). // (width,height)

// Proposed command
set Info_Win to GUI(600,800,400,400). // (width,height,Xposition,Yposition)

Position should be optional parameters for users who need them, using some default postion if data is not provided.
No special need to remember window position in some outside xml or config file, GUI will be recreated by user script each time craft is loaded in scene and boot script is executed.

Just poped on my mind to check out what will happen when I have such script on one craft. leave it in orbit with bootable script and GUI and then aproach with another craft with his own GUI too, will GUI's from both craft show ?
It will be fun to test this.

@hvacengi, I belive Wazs fork comes from your updated code for Blizzy's toolbar. Now it is possible to have kOS icon on stock toolbar, values from stock difficulty settings regarding kOS work properly now. I can even put kOS icon on Blizzy toolbar, but if I try to click on it to show kOS UI, it throw null object refernce error. When using stock toolbar, kOS UI shows properly.

IIRC, you are the person responsible for steering manager, right ? Awesome job on it, it works much better than I recall from last time I tried to use it. Much better than if I try my own PID for raw controls, have yet to try with pair of PID conrols for each raw axis, though.

Only small issue have with cooked steering, most noticable with rotation axis. Noticed with powered landing/suicide burn scripts. When you use command like this:

Spoiler

lock STEERING to Up + R(0,0,0). // craft can roll quickly trough decent as it don't know what NORTH is

lock STEERING to HEADING(MyHeading,90). // works much better, no violent rotation trough descent

// however in whole script there is transition where ship switch from retrogade vector to pure UP vector
// when craft ground speed is low enough I use something like this

set SteerAngle to round(VANG(SHIP:FACING:VECTOR,(-1)*SHIP:VELOCITY:SURFACE),2).
if SteerAngle < 10 {
	lock STEERING to ((-1) * SHIP:VELOCITY:SURFACE) + R(0,0,0).
}
else
{
	lock STEERING to HEADING(MyHeading,90).
}.

 

There is still some unwanted rotation when switching between two. Also in space, locking to maneuver vector also cause undesired rotation. Usage of monopropelant for RCS to rotate craft while rotation is not necessary at all.
Another thing that happened to me recently is that I use craft with simple fixed solar panels only on two sides of craft.
Steering manager locked craft in a way that neither was turned toward sun, resulting in power loss and probe left out of control. Yes, I know it is partly craft design flaw, but it will be avoided if steering manager didn't locked rotation axis.

So, my feature request is to add suffix on steering manager that will allow to exclude roll axis from locking. It would be even better if such option is available for all axis pitxh,yaw, roll. Default should stay like it is, steering manager does great job otherwise.

EDIT:

Above link for GUI alpha fork does not work, it is bette rto folloe from this link in case of future changes:

https://github.com/WazWaz/KOS/releases/

Edited by kcs123
Link to comment
Share on other sites

Just noticed another small issue with string to scalar conversion.
I tried this:

set Info_SteerToggle to Info_Win:ADDCHECKBOX("Autopilot steer toggle ",false).

ON Info_SteerToggle:PRESSED {
	if Info_SteerToggle:PRESSED = true{
		set MyHeading to NestedInputData:text.
		lock STEERING to HEADING(MyHeading,0). // This throws error. Scalar can't accept string as value.
	}
	else
	{
		unlock STEERING.
		SET SHIP:CONTROL:NEUTRALIZE TO TRUE. // returning controls to pilot - pitch/yaw/roll
	}.
	preserve.
}.

I'm aware that is possible to convert scalar to string trough suffix MyScalar:TOSTRING, but seems it is not possible other way around. Therefore is either, to add TONUMBER or TOSCALAR suffix for strings in whole kOS, or just put some additional checking in TEXTFIELD, if numbers are used for input to convert them in scalar.

Since that need to be done trough C# code, might be better idea to add suffix SCALARVALUE in structure of TEXTFIELD. Since kOS can't handle properly NaNs and can't have proper try-catch command, might be good to add additional suffix HASNUMBER with true/false.

Whenever user enter something in text field, trough C# you should try to convert it in float number with try-catch structure. If it is possible to convert input data to number, field SCALARVALUE is populated by that number and HASNUMBER is set to true. Othervise HASNUMBER is set to false and SCALARVALUE is set to "0".

Link to comment
Share on other sites

I was afraid that GUI's from multiple crafts in same physical area could be issue.

nBtLUpx.jpg

3 rovers placed nearby. Rover 01 and 03 have set boot script in SPH. Nothing fancy, just script that would show GUI with ship name on label.

For Rover 02 I have set boot script to none. On runway, I have manualy created boot directory and copied same script inside. Parked rover nearby and launched third one to check out everything and create screenshot.

Script on rover 02 was not executed and it is not possible to change bootscript from flight scene. Don't know if it is intended behaviour or not. I think it should be possible to choose whatever boot script is copied on internal arhive ships CPU, even in flight.

Example, why should be needed. Launch craft from launchpad and choose some orbit ascend script to be executed. Once in orbit, craft no longer need ascend script. So, I delete it and copy other scripts to manage maneuver nodes and landing on mun, for example. If I delete boot script instead to edit existing one, new desired script will not be executed next time I visit that craft in orbit.

Regarding GUI's, I think it will be better to limit showing GUI to craft under player focus/control only.
If other crafts nearby have their own GUI's it should be possible to hide/show their GUIs in similar manner as terminals from other crafts. Maybe to add "window" icon or similar next to terminal on kOS GUI from toolbar ?

Link to comment
Share on other sites

The boot script can be changed programmatically with core:bootfilename. The only time I've changed it in the past is to set up miners to restart themselves every morning.

Window position can be set with X and Y properties after creation. I guess they could be done via a 4-argument function, but I dislike effectively having default parameters that aren't at the end.

Also, I've reconsidered the use of scoping to control widget lifetime and I'm pretty sure it's wrong. I'll revert that in the next build.

Link to comment
Share on other sites

39 minutes ago, Waz said:

The boot script can be changed programmatically with core:bootfilename.

Thanks. I missed that info trough available documentation. I was searched in files I/O section, never poped on my mid to look at Core section of documentation.

47 minutes ago, Waz said:

Window position can be set with X and Y properties after creation. I guess they could be done via a 4-argument function, but I dislike effectively having default parameters that aren't at the end.

Well, I put in comment on side that defaults should be on the end

Quote

GUI(600,800,400,400). // (width,height,Xposition,Yposition)

No special need for that, but maybe to put that in "Hello GUI world" example ? Less question aked. Maybe someone else would also missed that in documentation like I am in the future.

Link to comment
Share on other sites

How would you feel about having the kOS-Invoked GUI widgets somehow positionally attached to the terminal window's position (like how the (admittedly a bit cruddy) in-game text editor does it?  What if the positions of the gui boxes were relative to the terminal edges?  (i.e. instead of saying "put at screen pos 500,600" you could say "put at terminal right-edge, with 'top gravity'"  ("gravity" being a concept used in some gui toolkits where you don't specify exact pixel position but instead allow it to "flow" where the position is relative to other things.  "top gravity" would mean "position the widget as high up as it will go until it hits the edge of another widget." (as opposed to positioning it as low as it will go, or as far left as it will go, etc.  You specify the gravity to tell the system how to position the widgets instead of specifying the exact position.  This is also useful in being modular.  If you run two different gui functions you developed separately they don't need to know about each other's positions - you just specify their layout flow and let the system position them so they don't get on top of each other.))

Then it would look like "these are some buttons and things on the control console".

 

=========

[The following was supposed to be a separate post because it's replying to a separate topic, but the forum software auto-merged it in that annoying way we're all familiar with.  Incidentally, this is why we prefer the subreddit for kOS to the KSP forums.  It allows more than one thread about kOS.  And there's enough variety of topics one might talk about with kOS that having to mash them all together into one is a bit unpleasant.]

 

1 hour ago, WeirdCulture said:

how I switch the telnet setting to IP v4? mine is listening on v6 only :(

kos_ipv6.png

Hmm.  The way this is done in the C# code is to just pick the "canonical" address of your computer that the API returns (which is presumably set to use the IPv6 address in your computer).  We never bothered implementing the ability to pick which address to use in cases where you have more than one to choose from.  Probably the solution would involve adding an interface to do so.  Are you on Github and can you make an issue for this at https://github.com/KSP-KOS/KOS/issues ?

Edited by Steven Mading
Link to comment
Share on other sites

41 minutes ago, Steven Mading said:

How would you feel about having the kOS-Invoked GUI widgets somehow positionally attached to the terminal window's position (like how the (admittedly a bit cruddy) in-game text editor does it?

Yes, that was my inital thoughts, for GUI to be attached ("glued") in similar way as text editor is at bottom of terminal. As said I think position on right edge of terminal would be suitable, for me, at least. Some other users may prefer some other part of screen.

Currently I considernig using terminal to show some craft data and GUI for controls (to replace AGs). Some other users might want to show GUI only and hide terminal window. How GUI will perform if terminal is hidden ? Should it replace terminal position more to the left of screen and when terminal window is shown again it will be glued to terminal again ?

Having option (GUI:SUFFIX) to choose behaviour will be good too. Maybe someone want to have more GUIs for different tasks on same craft. One GUI glued to terminal and other on some fixed position on right side of screen. Different people have different preferences, so having option to choose is always good.

Link to comment
Share on other sites

58 minutes ago, kcs123 said:

 How GUI will perform if terminal is hidden ? Should it replace terminal position more to the left of screen and when terminal window is shown again it will be glued to terminal again ?

That would be a problem we'd have to think about if we did that.  What I was thinking of was letting the script pick which edge to glue it to (left, top, bottom, etc), but then do we hide the gui when the terminal hides, or keep the gui and collapse the window to just a small enough rectangle to "hold" the guil's glued to it?

Link to comment
Share on other sites

2 hours ago, Steven Mading said:

That would be a problem we'd have to think about if we did that.  What I was thinking of was letting the script pick which edge to glue it to (left, top, bottom, etc), but then do we hide the gui when the terminal hides, or keep the gui and collapse the window to just a small enough rectangle to "hold" the guil's glued to it?

Maybe - if we can work out how to make both sensible. For me, the main way to use a GUI is in order to invoke tried-and-tested functionality - where the TermWindow is not used at all. Someone using a terminal doesn't generally want to go over to the mouse to click a button rather than just keep using the TTY (of course, it still needs a READLINE function of some sort), and similarly, someone using a GUI doesn't want to first have to open the TTY (itself a 2-3 click operation), then type a command, just to interact with a simple GUI.

Even if running a rarely-used GUI program from the TTY, the next thing the user is likely to do is close the TTY to free up screen space - should the anchored GUI then disappear?

To give an example of real-world use, I've added GUI to my "Launch to Orbit" script to allow entering target altitude and heading (previously done by editing a little parameters file or by kludge parsing the core "name tag" as if it was parameters). After reaching orbit, or upon reboot, the script then switches to just showing 3 small buttons: MEX, LND, LTO, respectively invoking my old maneuver executer, lander, and launch-to-orbit scripts. The MEX and LND scripts have only been trivially changed: adding support for a gui_cancel button that if defined aborts the command (like Ctrl-C did for them when standalone, but also resetting throttle, timewarp, etc.). As you can see, the GUI as I'm using it is a way to tie together a collection of mature TTY-based functionality.

A friend of mine has been using kOS ever since he got too addicted to RemoteTech's FlightComputer for executing nodes but then it wasn't ported to 1.2 for a while. All he ever does is boot into the launch-to-orbit script or manually "run mex.". I think this is a great way to get non-programmers to install kOS and eventually to think about looking under the hood. Some may doing all editing in Notepad (does anyone actually use the built-in editor?), and power-cycling the core to rerun their GUI, only ever opening the TTY if they need to see an error message when something goes wrong.

In all cases, the GUI-without-TTY and TTY-without-GUI are the primary use cases I see. Only when developing a GUI would the TTY commonly be open in parallel to a GUI.

@kcs123 - W,H,X,Y would be too confusing, I think. It's clear to just write GUI:X = 123. GUI:Y = 456, I think. I like the idea of X and Y somehow being "remembered" between invocations, but I can't think of a sensible way to do that without having some magic key for windows.

Link to comment
Share on other sites

@Waz

Well, even with GUI buttons I'd still use the TTY for readouts.  GUI invokes things, but the things run on the TTY. That's the use case you're saying doesn't exist.

You seem to be claiming that the TTY only exists for debugging during development.  That once a script is debugged nobody would ever want to look at the TTY anymore.  I don't agree.

I guess it could be done both ways maybe.  It's just that if I imagine multiple gui windows open, I'd like them glued together somehow and not all over the place separately.  I wouldn't enjoy having them disconnected from which CPU it was (which right now is tied to which terminal it is) and having to drag them around separately one at a time.

 

Edited by Steven Mading
Link to comment
Share on other sites

2 hours ago, Steven Mading said:

@Waz

Well, even with GUI buttons I'd still use the TTY for readouts.  GUI invokes things, but the things run on the TTY. That's the use case you're saying doesn't exist.

You seem to be claiming that the TTY only exists for debugging during development.  That once a script is debugged nobody would ever want to look at the TTY anymore.  I don't agree.

I guess it could be done both ways maybe.  It's just that if I imagine multiple gui windows open, I'd like them glued together somehow and not all over the place separately.  I wouldn't enjoy having them disconnected from which CPU it was (which right now is tied to which terminal it is) and having to drag them around separately one at a time.

 

I'm sure everyone is different. I was mostly explaining how I use it. Once I've developed a program, I try to tune all output to a minimum that can be logged with HUDTEXT.

I'm yet to investigate the multiple-CPUs scenario @kcs123 described. With the limitations KSP places on non-active vessels, I've never really made good use of multiple CPUs at once. Personally, if it was an issue, I'd just add a label with the ship:name and be done with it (having a label at the top also makes it clean to drag windows around), just as the TermWindow does.

guialpha3 - up on https://github.com/WazWaz/KOS/releases/

  • Add RADIOBUTTON, SCROLLBOX and POPUPMENU widgets.
  • Revert scope-based widget deletion.
  • Add explicit widget disposal (removal from parent).
  • Make top-level window auto-resize.
  • Fix blank transparent space window margins.

I think I'm done adding widgets now - these cover all the classics.

Note that the height parameter is now optional (docs not quite up-to-date), and windows resize automatically to fit content.

Edited by Waz
link
Link to comment
Share on other sites

5 hours ago, Waz said:

 

@kcs123 - W,H,X,Y would be too confusing, I think. It's clear to just write GUI:X = 123. GUI:Y = 456, I think. I like the idea of X and Y somehow being "remembered" between invocations, but I can't think of a sensible way to do that without having some magic key for windows.

It is OK to stay like it is. That fall better into KISS principle. Just hello world example in documentation can be updated, next commands after creation, to reposition of GUI to anyone personal liking. Having this in script solve a problem to remember default position, no need to store it's value anywhere outside. I just missed info how to do it when reading documentation for first time, some other new users might also oversight it, therefore I recommend to add command in tutorial example. That would be enough.

8 hours ago, Steven Mading said:

What I was thinking of was letting the script pick which edge to glue it to (left, top, bottom, etc), but then do we hide the gui when the terminal hides, or keep the gui and collapse the window to just a small enough rectangle to "hold" the guil's glued to it?

Yes, having property for GUI to choose edge where to glue is good enough. In my opinion GUI should stay after terminal hide and reposition itself to same position as terminal was. Once terminal is shown again, GUI will be glued again to terminal on chosen side (left,right,bottom, etc.).

5 hours ago, Waz said:

To give an example of real-world use, I've added GUI to my "Launch to Orbit" script to allow entering target altitude and heading (previously done by editing a little parameters file or by kludge parsing the core "name tag" as if it was parameters). After reaching orbit, or upon reboot, the script then switches to just showing 3 small buttons: MEX, LND, LTO, respectively invoking my old maneuver executer, lander, and launch-to-orbit scripts. .....

Yes I was thinking about similar usage here. Is there a example how to convert values from GUI to scalars ? Am I missed something obvious or GUI need to be upgraded for this ?

5 hours ago, Steven Mading said:

Well, even with GUI buttons I'd still use the TTY for readouts.  GUI invokes things, but the things run on the TTY. That's the use case you're saying doesn't exist.

You seem to be claiming that the TTY only exists for debugging during development.  That once a script is debugged nobody would ever want to look at the TTY anymore.  I don't agree.

But, like Steven, there certainly be scenario where I would like to keep both open, TTY and GUI, regardles if script debug is finished or not. There also be situations when I will only need GUI. I agree with Steven here, TTY should not be excluded.

6 hours ago, Waz said:

Some may doing all editing in Notepad (does anyone actually use the built-in editor?)

I use built in editor on occasions, to reach files copied in CPU core. Comment out or change primary script that will be executed next time I revisit same ship. You can't reach it with notepad. Notepad++ is prefered for archive 0.

3 hours ago, Waz said:

I'm yet to investigate the multiple-CPUs scenario @kcs123 described. With the limitations KSP places on non-active vessels, I've never really made good use of multiple CPUs at once. Personally, if it was an issue, I'd just add a label with the ship:name and be done with it (having a label at the top also makes it clean to drag windows around), just as the TermWindow does.

Well, consider assembling orbital station controled by kOS. You launch first segment in stable orbit. Then you need to dock another part of station in orbit, then another ... etc. There will be scenarios where you will be dock/undock multiple ships from stations trough resupply missions etc. Maybe we can solve both, multiple ship scenarios and GUI default positions.

 

Therefore GUI might be extended with following properties:

  • EDGETOGLUE (none,left,right,top)
  • NEEDTTY    (true,false)

With NEEDTTY set to true, if you have script like this:

LOCAL gui TO GUI(200,100).
set gui:EDGETOGLUE to RIGHT.
set NEEDTTY to true.
// Show the GUI.
gui:SHOW(). // GUI will not show unless TTY is shown

However, if someone close TTY, GUI should stay if it is shown. To hide GUI it still need button on GUI to close.
When TTY closes, GUI reposition to former TTY starting point.
When  TTY opens again, GUI is shown and glued to TTY again.
 

That would also solve multiship scenario, GUI will be shown only for craft I chosed to show, not everything at once.
It will cover user prefered scenario, how to use it, with, or without TTY. Only limitation is that on launch or changing scenes, user need to open TTY once and hide it if there is no need for TTY itself.

Don't know what are possibilities from code side, though, you are the ones doing all hard work, I just throw ideas and partly pseudocode.

Link to comment
Share on other sites

1 hour ago, kcs123 said:

... remember default position, no need to store it's value anywhere outside. I just missed info how to do it when reading documentation for first time, ...

... Is there a example how to convert values from GUI to scalars ? Am I missed something obvious or GUI need to be upgraded for this ?

... I would like to keep both open, TTY and GUI, regardless if script debug is finished or not. There also be situations when I will only need GUI. I agree with Steven here, TTY should not be excluded. ...

... That would also solve multiship scenario, GUI will be shown only for craft I chosed to show, not everything at once....

 

Sorry for the weird quoting. Forum editor is weird.

Storing small simple values isn't easy. kOS really needs a key-value datastore linked to the savefile. AFAIK, all you can do is write files, and then, only poorly. Maybe someone else can answer that link better. So having the program itself do this would be easy, if there was some kind of:

gui:x = STORAGE:GET("guix").
gui:= STORAGE:GET("guiy").

...

STORAGE:SET("guix",gui:x).
STORAGE:SET("guiy",gui:y).

Also, I have no idea how to convert strings to integers. I have an "atof()" function in by kOS function library, but I too suspect I'm missing something - seems like obvious functionality.

Certainly nothing is stopping you from having both open, the question is whether this is a big enough concern to implement this anchoring concept. To my mind, the TTY window has become bloated and ugly and full of all sorts of functionality that really belongs in the Settings, not the "primary" UI (not to mention ugly icons and poorly aligned gui elements), so the less I use the TTY the happier I am. YMMV.

I definitely need to look into multi-ship scenarios, but the GUI is not even one-per-TTY, so I can't see how it will be a problem, except the minor issue of having a LABEL identifying which ship the GUI is controlling.

Edited by Waz
Link to comment
Share on other sites

@Waz, sorry, english is not my native language, so I probably didn't explained my thoughts well enough.
No worries about storing position values somewhere outside, there is no special need for this. Ability to reposition GUI trough script command set GUI:x to something is good enough. It is up to user how he want to handle this. At least position:x,y is provided for that purpose.

That was not main point of my previous post. Biggest issue is how to convert string to number or scalar. Since it can't be done trough kOS scripts, it have to be handled trough core C# code. You missed this part:

Quote

Since that need to be done trough C# code, might be better idea to add suffix SCALARVALUE in structure of TEXTFIELD. Since kOS can't handle properly NaNs and can't have proper try-catch command, might be good to add additional suffix HASNUMBER with true/false.

Whenever user enter something in text field, trough C# you should try to convert it in float number with try-catch structure. If it is possible to convert input data to number, field SCALARVALUE is populated by that number and HASNUMBER is set to true. Othervise HASNUMBER is set to false and SCALARVALUE is set to "0".

In other words, TEXTFIELD widget should be extended with properties:

  • HASNUMBER (true,false) readonly value   - or HASSCALAR - whatever name you think fits better to kOS language
  • SCALAR  readonly value                            - if HASNUMBER is true it is filled with proper value, otherwise it holds "0"

I rarely do something in C++, C# so without looking trough C# help files consider following more as pseudocode.
In your C# code, where you handle TEXTFIELD objec, more specific values

CHANGED Boolean Has the text been edited?
CONFIRMED Boolean Has the user pressed Return in the field?

More apropriate place would be where CONFIRMED is handled in C# code to add something like this:

try
{
  textfield.SCALAR = StringToFloat(textfield.text); // Or whatever is proper command in C#
  textfield.HASNUMBER = true;
}
catch
{
  // In case that above throws exception for whatever reason
  // we know that in game TextField object can't have number so properties are set like this
  textfield.SCALAR = 0;
  textfield.HASNUMBER = false;
}.

By the way how sliders work in unity, they were not always precise enough, so there will always be need to enter some exact value trough script.

Sorry, don't know how to better explain this or where is exact place in your C# source code where should be applied.

Link to comment
Share on other sites

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