Jump to content

[1.3] kOS Scriptable Autopilot System v1.1.3.0


erendrake

Recommended Posts

6 hours ago, Steven Mading said:

I'm still confused.  What does the steering have to do with the staging?  Are you saying it fails to know where to steer once you stage part of the ship away?

Cooked steering stops working if I stage with AGX, but it's OK if I use the Stage command.. see code below - CAPITALISED comments section.

 

I set up the staging order and.or AGX numbers, manually in the VAB

With AGX mod installed I would use the Toggle(AGxxx) to effect staging and engine ignition - but I would then loose COOKED control and the rocket wanders off somewhere else.

With the Stage command.. COOKED control remains in control and the rockets ends up in the right place.

Now I'm trying to get around the Stage command and use DOACTIONS instead as the upper stage engine have to be switched on/off regularly to obtain orbit and transfers.

 

//============================================================================
//								STAGE-1 FLIGHT
//============================================================================
Function Stage1
{
Local b_Busy1 is TRUE.
Local BTrot is TRUE.

	Set ShipUp_Va to 0.
	Screen_Stage1().
	Set myStage to 1.
	LOCK Steering to HEADING(ShipHeading,ShipPitch).

	When SHIP:ALTITUDE > 200 THEN
	{
		Set ShipHeading to 90.
	}
	UNTIL b_Busy1 = FALSE
	{
		Stg123_APOTime().					// Aposapsis average times and alarms.
		Stg1_DeterminePitch().					// Crude pitch control method.
		Stg12_PitchAngleControl().				// Finer pitch control.
		MThrottle1(0.27).					// RD701 minimum Throttle.
		Set ShipUp_Vb to ShipUp_Va.
		Set ShipUp_Va to SHIP:AIRSPEED.
		If ShipUp_Va < ShipUp_Vb				// Fuel runs out when previous Velocity
		{							// is greater than current Velocity.
			IF Ship_Alt > 500				// Delay to prevent false staging.
			{
				Stage.					// THIS WORKS COOKED CONTROL (Drop stage fairings)
//				Toggle(AG248).				// THIS DOESN'T WORK 
				Lock THROTTLE to 1.			// Max throttle to keep engine on
				Stage.					// THIS WORKS COOKED CONTROL (Activate engine)
//				Toggle(AG247).				// THIS DOESN'T WORK 
				Set b_Busy1 to FALSE.			// Set stage exit flag.
			}
		}
		ELSE
		{
			Print Ship_Alt AT (22,4).
			Print ShipPitch AT (22,6).
			Print ALT:APOAPSIS AT (22,8).
			Print ApoT_AVG AT (22,10).
			Print ShipHeading AT (22,13).
			Print D_ApoTime AT (22,17).
		}
	}
}

 

Edt:

Added video. On the first launch AGXs are used, and as you can see the rocket loses it.

On the second launch All I've done is replace the AGX statements with a Stage command... and it works perfectly.

The problem come comes at the stage where I have switch high pressure engines on/off to achieve orbits and transfers.. Stage'ing will not work here :wink:

 

Edited by ColKlonk2
video added
Link to comment
Share on other sites

 

6 hours ago, Steven Mading said:

set foo to waypoint("Sector B4-X Alpha"). // For example.

print foo:geoposition.

Thanks.

4 minutes ago, maculator said:

Hi I got a small question:

Is it better to do:


if stage:solidfuel < 1 and savestage < 3 { --STUFF--

or:


if stage:solidfuel < 1 {
	if savestage < 3 { --STUFF--

?

It depends of if you want to check situation. when stage:solidfuel<1, but savesage >=3 .

Link to comment
Share on other sites

@Sebra I use it to stage a simple tourist-gee-knockout rocket.

savestage is a number I'm using to prevent the script from staging through everything.

I just "want" (need) to save some EC and try to make my script as triggerlight as possible.

So since I'm not a programer and therefore have no clue I thoguht in solution 1 it'll check for solidfuel and savestage the whole time while in solution 2 it'll only keep track of solidfuel and if I run out it'll check for savestage aswell.

 

I don't know if you get what I mean, I certainly wouldn't so here is the small script (like I said I wanted to use as less loops as possible to keep it leightweigt):

Spoiler

clearscreen.
print "savestage = 1.".
set savestage to 1.
lock steering to heading (0,90).
stage.
print "set exit to 0.".
set exit to 0.


until exit = 3 {

	if exit = 0 {
		if alt:radar < 70000 {
			lock steering to up.
			wait 0.005.
			if savestage = 3 {
				set kuniverse:timewarp:mode to "physics".
				wait 0.5.
				print "warping.".
				set warp to 4.
				wait 0.5.
				print "set exit to 1.".
				set exit to 1.
			}
		}
	}

	else if exit = 1 {
		wait until alt:radar > 70000.
		set warp to 0.
		wait 0.5.
		lock steering to up + R(0,-90,0).
		print "waiting.".
		wait 5.
		print "knocking out a tourist.".
		stage.
		wait until stage:solidfuel < 1.
		stage.
		set kuniverse:timewarp:mode to "rails".
		wait 3.
		print "warping. - again".
		set warp to 4.
		print "set exit to 2.".
		set exit to 2.
	}

	else if exit = 2 {
		wait until alt:radar < 70000.
		set warp to 0.
		wait 0.5.
		lock steering to retrograde.
		set kuniverse:timewarp:mode to "physics".
		wait 0.5.
		print "warping. - once more...".
		set warp to 4.
		wait until alt:radar < 1200.
		set warp to 0.
		wait 0.5.
		wait until alt:radar < 950.
		set warp to 4.
		wait until alt:radar < 100.
		set warp to 0.
		wait 1.
		print "set exit to 3.".
		set exit to 3.
	}

	if stage:solidfuel < 1 and savestage < 3 {
		stage.
		set savestage to savestage + 1.
		print "stage. - new savestage is now " + savestage.
		wait 1.
	}

	wait 0.004.

}

print "end of tour - prepare for touchdown!".

 

It works like a charm althou it took me quite a while to bring it to this point. So now I'm looking for ways to improve it.

Link to comment
Share on other sites

Cheats?

I unlocked the parts, constructed the rocket and worked my unskilled ass off to get a script together. Those missions fund my scientiffic ones down on kerbin and are repetive and tedious - just right for KOS.

This is not the place to discuss ones opinion on cheating. I just wanted some help because I'm a noob. Simple question, simple answer, thankfull noob.

Will it check both parameters if they're seperated with an "and" or is it better to put in a second "if" for the second parameter"?

I'm curious about some knowledge about KOS.

Edited by maculator
reasons
Link to comment
Share on other sites

1 minute ago, Sebra said:

You use warp and even change warpmodes. Isn`t it a cheat?

IMHO best place to knockout a tourist is the launchpad. Just add more busters. (c)Kerbal way.

why is doing something with KOS that you can do in game at any point considered cheating?

Link to comment
Share on other sites

17 minutes ago, TheRagingIrishman said:

why is doing something with KOS that you can do in game at any point considered cheating?

I count physics warp as kind of cheat. "Set kuniverse:timewarp:mode to "rails" " I do not even understand fully. But of course you can do anything you want.

13 minutes ago, maculator said:

kerbal who payed for a suborbital knockout in space

Did not see such perverse yet.

Btw I want to see that ship. :wink:

Edit: Your scripting style was fun to decipher. :D

Edited by Sebra
Link to comment
Share on other sites

The ship matching the script:

Spoiler

Aj5YKTO.png

~6k Funds. Mission yields 16500 each launch and I recover some 1k-2k. Upper stage is used to knock them out. The ascent profile is: straight up to 70kmi and then fire the last stage flat.

"physics" is the one you can do inside the atmosphere/under acceleration. "rails" is the one outside a tmosphere wich goes really fast.

I thought my "style" was clear to read :/ since batteries are funds I went for a simple as possible script, that approach also suited my skills quite well.

Link to comment
Share on other sites

1 hour ago, maculator said:


Will it check both parameters if they're seperated with an "and" or is it better to put in a second "if" for the second parameter"?

I'm curious about some knowledge about KOS.

The concept of not checking further parts of an expression once we definitely know the overall result is called short-circuiting. kOS does this:

http://ksp-kos.github.io/KOS_DOC/language/features.html#short-circuiting-booleans

This means it is useful to order checks within expressions, so that simple checks are done first that can prevent something complicated being checked unnecessarily. It can also be used as a safety measure, to avoid doing something potentially crashy (though this is less obvious to someone reading the code, so it's not necessarily best practice). The two comparisons in your example are both on the simple end. I'd just go for whatever seems more readable to being with, though I'd later viciously reduce it in size to the minimum possible as I am always running out of hard disk space until the KAL-9000 is available.

Link to comment
Share on other sites

13 hours ago, ColKlonk2 said:

Cooked steering stops working if I stage with AGX, but it's OK if I use the Stage command.. see code below - CAPITALISED comments section.

Well, there's a few places where the kOS code is watching for the sort of events that split a vessel in two, and it tries to recalculate the ship's properties after the splitting is done.  I suppose it's possible that whatever AGX is doing to fire off the decoupler is causing those checks to get bypassed so kOS still thinks the "gone" parts of the vessel are there affecting its moment of inertia and torque properties.  (In this case the gone parts of "the rocket" would be the launch clamps, which I think have weird physics properties to make them immobile (i.e. enormous fake mass ,etc).)

I'm not the one who normally touches that part of the code but I'll pass it along.

Do you get the same bug if you decouple the launch clamps by using DOEVENT or DOACTION instead of AGX?

 

Link to comment
Share on other sites

I am interested in writing a couple scripts, but I'm having a hard time following the way things execute.  I am a C++ programmer with alot of experience in Java and C#.  One of the most fundamental things is that each piece of code executes in order and each instruction is run only once barring any loops or function calls.  I just can't follow how the scripts are executing, I've read through much of the documentation at this point and I haven't seen anything that explains what I'm looking for. 

Link to comment
Share on other sites

4 hours ago, eberkain said:

I am interested in writing a couple scripts, but I'm having a hard time following the way things execute.  I am a C++ programmer with alot of experience in Java and C#.  One of the most fundamental things is that each piece of code executes in order and each instruction is run only once barring any loops or function calls.  I just can't follow how the scripts are executing, I've read through much of the documentation at this point and I haven't seen anything that explains what I'm looking for. 

Unless you use until or for loops, it execute commands in sequence until end of file is reached.

Exceptions from that rule are functions and triggers. Function only need to be declared once in code. I'm kind of old school programmer, so i like to have all global variables and function declared on top of file. Then after that some initialization code following by one endless loop that ends only on certain action group triggered or only trough CTRL+C.

WHEN and ON command is a bit trickier to understand. In C++ or C# world better term would be "event". Meaning, once you wrote that block of command, it is executed when certain condition is met. If you use preserve keyword inside when block, it means that same part of code will be executed again if same conditions are met.

However, when part of code must be executed in sequence at least once, to be active, before you start loop for your main program.
 

I hope that above make some sense, english is not my native language, so I don't know if it is explained properly.

Link to comment
Share on other sites

8 hours ago, eberkain said:

I am interested in writing a couple scripts, but I'm having a hard time following the way things execute.  I am a C++ programmer with alot of experience in Java and C#.  One of the most fundamental things is that each piece of code executes in order and each instruction is run only once barring any loops or function calls.  I just can't follow how the scripts are executing, I've read through much of the documentation at this point and I haven't seen anything that explains what I'm looking for. 

In general things should execute in sequence just like C++. The best way to help you is if you post simple code examples of the things that seem not to make sense.

I usually debug my scripts with lots of tracecode. Either one-time as a new line in the terminal, or updated every frame at some fixed location (note to self: finally clean up those scripts so I can give them a thread in the forum)
https://github.com/pellinor0/kOS-MissionFramework/blob/master/Script/libatmo.ks#L145#L149

Link to comment
Share on other sites

On 4/3/2017 at 9:05 PM, ColKlonk2 said:

Well that's just it.. 

 

OK problem solved thus far... the KOS documentation needs to be more explicit and many working examples thrown in.. but when you have the time.:D

Anyway here's a working example of my problem that I've had..

Clearscreen.
Global P is "".
Global MOD is "".
Global PM is "".

FOR P IN SHIP:PARTS 
{
	LOG ("***** " + P:NAME + " *****") TO MODLIST.
	LOG (" ") TO MODLIST.

	FOR MOD IN P:MODULES
	{
		//********************************************************************
		// A SIMPLE BUT VITAL MISSING PIECE OF INFO IN THE KOS DOCUMENTATION
		//
		// THE 'MOD' VARIABLE DEFAULTS TO THE MOD NAME SO DON'T USE 'MOD:NAME'
		//      (You WILL throw your rockets out the window :) :) )
		//*******************************************************************
		SET PM TO P:GETMODULE(MOD).

		LOG("-------------------------------------- " + MOD) TO MODLIST.
		LOG(" ") TO MODLIST.

		LOG("--------------- ALLFIELDS") TO MODLIST.
		LOG PM:ALLFIELDS TO MODLIST.
		LOG(" ") TO MODLIST.

		LOG("----------------ALLEVENTS") TO MODLIST.
		LOG PM:ALLEVENTS  TO MODLIST.
		LOG(" ") TO MODLIST.

		LOG("---------------ALLACTIONS") TO MODLIST.
		LOG PM:ALLACTIONS TO MODLIST.
		LOG(" ") TO MODLIST.
	}
}

Results in a long list.. (1 part of 88)

***** LR87LH2Vac *****
 
-------------------------------------- ModuleEnginesRF
 
--------------- ALLFIELDS
LIST of 9 items:

[0] = "(get-only) ignitions remaining, is Int32"

[1] = "(get-only) propellant, is String"

[2] = "(get-only) current throttle, is Single"

[3] = "(get-only) eng. internal temp, is String"

[4] = "(get-only) fuel flow, is Single"

[5] = "(get-only) thrust, is Single"

[6] = "(get-only) specific impulse, is Single"

[7] = "(get-only) status, is String"

[8] = "(settable) thrust limiter, is Single"
 
----------------ALLEVENTS
LIST of 1 items:

[0] = "(callable) activate engine, is KSPEvent"
 
---------------ALLACTIONS
LIST of 3 items:

[0] = "(callable) toggle engine, is KSPAction"

[1] = "(callable) shutdown engine, is KSPAction"

[2] = "(callable) activate engine, is KSPAction"
 
-------------------------------------- ModuleJettison
 
--------------- ALLFIELDS
LIST of 0 items:


 
----------------ALLEVENTS
LIST of 0 items:


 
---------------ALLACTIONS
LIST of 1 items:

[0] = "(callable) jettison shroud, is KSPAction"
 
-------------------------------------- ModuleGimbal
 
--------------- ALLFIELDS
LIST of 2 items:

[0] = "(settable) gimbal, is Boolean"

[1] = "(settable) gimbal limit, is Single"
 
----------------ALLEVENTS
LIST of 1 items:

[0] = "(callable) show actuation toggles, is KSPEvent"
 
---------------ALLACTIONS
LIST of 6 items:

[0] = "(callable) toggle gimbal, is KSPAction"

[1] = "(callable) lock gimbal, is KSPAction"

[2] = "(callable) free gimbal, is KSPAction"

[3] = "(callable) toggle gimbal pitch, is KSPAction"

[4] = "(callable) toggle gimbal yaw, is KSPAction"

[5] = "(callable) toggle gimbal roll, is KSPAction"
 
-------------------------------------- ModuleAnimateHeat
 
--------------- ALLFIELDS
LIST of 0 items:


 
----------------ALLEVENTS
LIST of 0 items:


 
---------------ALLACTIONS
LIST of 0 items:


 
-------------------------------------- ModuleSurfaceFX
 
--------------- ALLFIELDS
LIST of 0 items:


 
----------------ALLEVENTS
LIST of 0 items:


 
---------------ALLACTIONS
LIST of 0 items:


 
-------------------------------------- ModuleTestSubject
 
--------------- ALLFIELDS
LIST of 0 items:


 
----------------ALLEVENTS
LIST of 0 items:


 
---------------ALLACTIONS
LIST of 0 items:


 
-------------------------------------- ModuleAGX
 
--------------- ALLFIELDS
LIST of 0 items:


 
----------------ALLEVENTS
LIST of 0 items:


 
---------------ALLACTIONS
LIST of 0 items:


 
-------------------------------------- EngineGroupModule
 
--------------- ALLFIELDS
LIST of 1 items:

[0] = "(get-only) engine group id is , is String"
 
----------------ALLEVENTS
LIST of 0 items:


 
---------------ALLACTIONS
LIST of 0 items:


 
-------------------------------------- EngineLightEffect
 
--------------- ALLFIELDS
LIST of 0 items:


 
----------------ALLEVENTS
LIST of 0 items:


 
---------------ALLACTIONS
LIST of 0 items:


 
-------------------------------------- KOSNameTag
 
--------------- ALLFIELDS
LIST of 1 items:

[0] = "(get-only) name tag, is String"
 
----------------ALLEVENTS
LIST of 1 items:

[0] = "(callable) change name tag, is KSPEvent"
 
---------------ALLACTIONS
LIST of 0 items:


 
-------------------------------------- ModuleEngineConfigs
 
--------------- ALLFIELDS
LIST of 0 items:


 
----------------ALLEVENTS
LIST of 0 items:


 
---------------ALLACTIONS
LIST of 0 items:


 
-------------------------------------- ModuleAeroReentry
 
--------------- ALLFIELDS
LIST of 0 items:


 
----------------ALLEVENTS
LIST of 0 items:


 
---------------ALLACTIONS
LIST of 0 items:

 

Edited by ColKlonk2
Link to comment
Share on other sites

22 hours ago, ColKlonk2 said:

//********************************************************************
// A SIMPLE BUT VITAL MISSING PIECE OF INFO IN THE KOS DOCUMENTATION
//
// THE 'MOD' VARIABLE DEFAULTS TO THE MOD NAME SO DON'T USE 'MOD:NAME'
// (You WILL throw your rockets out the window :) :) )
//*******************************************************************
SET PM TO P:GETMODULE(MOD).

 

Can you provide an example of what this line of code (and the previous line where the "MOD" variable was being populated in the first place) looked like in previous versions of your work before you corrected it?  (or multiple examples if you made several different not-working attempts before you got it working). I'm not sure I understand what your comment is referring to, but seeing what your previous attempts had been may help me to understand where the docs may have misled you (and thus where they need to be edited).

Edit: Okay now I see.  The MODULES suffix of a part is returning a list of strings - just the names, and not the modules themselves, but this wasn't clear.

Well, this kind of sucks because if it just returns names it should have been called "MODULENAMES" - that's our bad, but if we change it now we'd be likely to break existing scripts that already expect MODULES to return strings.

Note, there's a reason we don't have one that returns the modules themselves.  Although that would look cleaner and more organized, the problem is that there's a bit of overhead in creating a PartModuleFields object for your script to use, so we really don't want to build a list of all of them if we're not certain you'll be using them all.

(i.e. it would be horribly wasteful if MODULES was actually a list of all the PartModuleFields and then you did:

P:MODULES[0]:GETFIELD("Enabled").

for example.  You'd only be using the zero-th one, but we would have constructed all of the other ones too in order to create the list.

 

 

Edited by Steven Mading
Link to comment
Share on other sites

I only went through all the parts and modules to see what it would bring up,as one would need to know the Fieldnames before I can use them

One can just filter out the part/module of interest and use that in code - I'll be doing this now now :D

From what I can see the modules are just an Object Structure (we are dealing with OOP anyway) and the Module Name is the first element/string of the object structure.

SET PM TO P:GETMODULE(MOD).

.. just returns a pointer to the structure, which also happens to be the Name pointer.

 

Just my thinking.. but no need to change it in the compiler, maybe some other time if necessary.

 

Edited by ColKlonk2
Link to comment
Share on other sites

On 4/3/2017 at 9:56 AM, kcs123 said:

I'm kind of old school programmer, so i like to have all global variables and function declared on top of file. Then after that some initialization code following by one endless loop that ends only on certain action group triggered or only trough CTRL+C.

So, once in a loop, there is no way to send new commands to the program?

Link to comment
Share on other sites

6 hours ago, eberkain said:

So, once in a loop, there is no way to send new commands to the program?

That's not correct. If one is treating one file as one script without any declaration of functions, the script will eventually lock one out of the terminal. If one is implementing a userinput, the script can surely check the state each cycle. If one is inputting new commands while a script is running, those inputs are getting queued up and executed after the actual program has ended (like in any other PL where "run mycode.extension" will just do that). Loops are also like in any other PL, one can make them run in the backround or keep the script from executing further until a certain condition is met. One can even run a whole program nested inside an until-loop by the use of delegates. Check out http://ksp-kos.github.io/KOS_DOC/language/flow.html and http://ksp-kos.github.io/KOS_DOC/language/delegates.html for more info.

Edited by Meltdown
Link to comment
Share on other sites

Does anybody know how to make this work?:

Spoiler

function printhud {
	parameter message.
	
	hudtext(message, 5, 2, 20, green, false).
}

function hasfile {
	parameter name.
	parameter volume.
	
	switch to volume. list files in filecheck.
	for file in filecheck {
		if file:name = name {
			switch to 1.
			return true.
		} else {
		switch to 1.
		return false.
		}
	}
}
if hasfile("test.ks", 0) { printhud("test.ks exists on 0:/"). wait 5.} //doesn't print anything :/

printhud("we made it to the end of test.ks!").

 

The 2 functions seem to work, the programm runs until the end and confirms it's done. But I cant get it to tell me wether hasfile() is true or false :/

Link to comment
Share on other sites

18 minutes ago, maculator said:

Does anybody know how to make this work?:

  Reveal hidden contents


function printhud {
	parameter message.
	
	hudtext(message, 5, 2, 20, green, false).
}

function hasfile {
	parameter name.
	parameter volume.
	
	switch to volume. list files in filecheck.
	for file in filecheck {
		if file:name = name {
			switch to 1.
			return true.
		} else {
		switch to 1.
		return false.
		}
	}
}
if hasfile("test.ks", 0) { printhud("test.ks exists on 0:/"). wait 5.} //doesn't print anything :/

printhud("we made it to the end of test.ks!").

 

The 2 functions seem to work, the programm runs until the end and confirms it's done. But I cant get it to tell me wether hasfile() is true or false :/

You're only comparing the desired filename to the first file in the list, then immediately returning true or false depending on whether that file is the one you were after or not (so it's probably always returning false). 

Move the bit that sets the volume to 1 and returns false outside of the for loop, so it is only executed if you've looped through every file and didn't find what you want.

Alternatively, the EXISTS(file_path) function exists so that you don't have to loop through the files yourself.

Link to comment
Share on other sites

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