Jump to content

[1.3] kOS Scriptable Autopilot System v1.1.3.0


erendrake

Recommended Posts

Made some tweaks, but I'm still getting the same dang error...

Boot.ks:

SET SHIP:CONTROL:PILOTMAINTHROTTLE TO 0.
LIGHTS OFF.
GEAR OFF.
BRAKES OFF.
SAS OFF.
RCS OFF.

FUNCTION NOTIFY
{
	PARAMETER message, priority.
	IF priority = "NOMINAL"
	{
		SET col TO GREEN.
	}
	ELSE IF priority = "ALERT"
	{
		SET col TO RGB(1,0.31,0). // international orange
	}
	ELSE IF priority = "WARNING"
	{
		SET col TO RED.
	}
	HUDTEXT("kOS: " + message, 1.5, 2, 30, col, FALSE).
}

FUNCTION ON_DRIVE
{
	PARAMETER filename, vol.
	
	SWITCH TO vol. LIST FILES in allFiles.
	FOR f IN allFiles
	{
		IF f:NAME = filename
		{
			SWITCH TO 1. RETURN TRUE.
		}
	}
	SWITCH TO 1. RETURN FALSE.
}

// First-pass at introducing artificial delay. ADDONS:RT:DELAY(SHIP) represents
// the line-of-site latency to KSC, as per RemoteTech
FUNCTION DELAY
{
	SET dTime TO ADDONS:RT:DELAY(SHIP) * 3.	// Total delay time
	SET accTime TO 0.						// Accumulated time

	UNTIL accTime >= dTime
	{
		SET start TO TIME:SECONDS.
		WAIT UNTIL (TIME:SECONDS - start) > (dTime - accTime) OR NOT ADDONS:RT:HASCONNECTION(SHIP).
		SET accTime TO accTime + TIME:SECONDS - start.
	}
}

// Get a file from KSC
FUNCTION DOWNLOAD
{
	PARAMETER filename.
	DELAY().
	IF ON_DRIVE(filename, 1)
	{
		DELETE filename.
	}
	IF ON_DRIVE(filename, 0)
	{
		COPY filename FROM 0.
	}
}

// Put a file on KSC
FUNCTION UPLOAD
{
	PARAMETER filename.
	DELAY().
	IF ON_DRIVE(filename, 0)
	{
		SWITCH TO 0. DELETE filename. SWITCH TO 1.
	}
	IF ON_DRIVE(filename, 1)
	{
		COPY filename TO 0.
	}
}

// Run a library, downloading it from KSC if necessary
FUNCTION REQUIRE
{
	PARAMETER filename.
	IF NOT ON_DRIVE(filename, 1)
	{
		DOWNLOAD(filename).
	}
	RENAME filename TO "tmp.exec.ks".
	RUN tmp.exec.ks.
	RENAME "tmp.exec.ks" TO filename.
}

// THE ACTUAL BOOTUP PROCESS
SET updateScript TO SHIP:NAME + ".update.ks".

// If we have a connection, see if there are new instructions. If so, download 
// and run them.
IF ADDONS:RT:HASCONNECTION(SHIP)
{
	IF ON_DRIVE(updateScript, 0)
	{
		DOWNLOAD(updateScript).
		SWITCH TO 0. DELETE updateScript. SWITCH TO 1.
		IF ON_DRIVE("update.ks", 1)
		{
			DELETE update.ks.
		}
		RENAME updateScript TO "update.ks".
		RUN update.ks.
		DELETE update.ks.
	}
}

// If a startup.ks file exists on the disk, run that.
SET bootScript TO SHIP:NAME + ".bootup.ks".
IF ON_DRIVE(bootScript, 0)
{
	DOWNLOAD(bootScript).
	RENAME bootScript TO "startup.ks".
	RUN startup.ks.
	IF ON_DRIVE("startup.ks", 1)
	{
		SWITCH TO 1. DELETE startup.ks.
	}
}
ELSE
{
	WAIT UNTIL ADDONS:RT:HASCONNECTION(SHIP).
	WAIT 10. // Avoid thrashing the CPU (when no startup.ks, but we have a
			// persistent connection, it will continually reboot)
	REBOOT.
}

 

Relay.bootup.ks:

DOWNLOAD(autoNavInit.ks).
DOWNLOAD(autoNavIterate.ks).
RUN autoNavInit(270).

 

AutoNavInit.ks:

PARAMETER goalHeading.
BRAKES ON.

NOTIFY("Starting navigation script...Done.", "NOMINAL").
WAIT 2.5.

NOTIFY("Downloading navigation instructions...Done.", "NOMINAL").
WAIT 2.5.

NOTIFY("Running iterative navigator...", "NOMINAL").
SWITCH TO 0. RUN autoNav(goalHeading).

 

AutoNav.ks:

// Until the goal has been reached, go through this process.

PARAMETER direct.
DRIVE_FORWARD().
DRIVE_BACK().
PARK().

// The loop... Functions are defined below
FUNCTION DRIVE_FORWARD
{
	UNTIL FALSE
	{
		POPULATE(direct).
		DECIDE_NEXT(options).
		NOTIFY("Selecting next waypoint.", "NOMINAL").
		WAIT 0.5.
		DRIVE_TO(nextPoint).
		STOP(). WAIT 5.
	
		IF NOT ADDONS:RT:HASCONNECTION(SHIP)
		{
			BREAK.
		}
	}
}

FUNCTION DRIVE_BACK
{
	UNTIL FALSE
	{
		POPULATE(360 - direct).
		DECIDE_NEXT(options).
		NOTIFY("Selecting next waypoint", "NOMINAL").
		WAIT 0.5.
		DRIVE_TO(nextPoint).
		STOP(). WAIT 5.
		
		IF ADDONS:RT:HASCONNECTION(SHIP)
		{
			BREAK.
		}
	}
}

FUNCTION THERE_YET
{
	PARAMETER point.
	
	IF point:DISTANCE < 10
	{
		RETURN TRUE.
	}
	ELSE
	{
		RETURN FALSE.
	}
}

FUNCTION POPULATE
{
	PARAMETER hdg.
	
	SET offset_90 TO SIN(hdg) * ((360 * 100) / (BODY:RADIUS * 2 * CONSTANT:PI)). // duh
	SET offset_675 TO offset_90 * SIN(67.5). // 67.5 deg.
	SET offset_45 TO offset_90 * SIN(45). // 45 deg.
	SET offset_225 TO offset_90 * SIN(22.5). // 22.5 deg.
	
	SET op_A TO LATLNG(SHIP:GEOPOSITION:LAT + offset_225, SHIP:GEOPOSITION:LNG - offset_675).
	SET op_B TO LATLNG(SHIP:GEOPOSITION:LAT + offset_45, SHIP:GEOPOSITION:LNG - offset_45).
	SET op_C TO LATLNG(SHIP:GEOPOSITION:LAT + offset_90, SHIP:GEOPOSITION:LNG).
	SET op_D TO LATLNG(SHIP:GEOPOSITION:LAT + offset_45, SHIP:GEOPOSITION:LNG + offset_45).
	SET op_E TO LATLNG(SHIP:GEOPOSITION:LAT + offset_225, SHIP:GEOPOSITION:LNG + offset_675).
	
	SET options TO LIST
	(
		op_A, op_B, op_C, op_D, op_E
	).
	
	RETURN options.
}

FUNCTION SLOPE_IS_SAFE
{
	PARAMETER option.
	SET here TO SHIP:GEOPOSITION.
	SET there TO option.
	SET slope TO ABS(ARCTAN2(there:TERRAINHEIGHT - here:TERRAINHEIGHT, lookAhead)).
	IF slope < 10
	{
		RETURN TRUE.
	}
	ELSE
	{
		RETURN FALSE.
	}
}

FUNCTION DECIDE_NEXT
{
	PARAMETER options.
	SET startPos TO 0.
	UNTIL startPos > options:LENGTH - 1
	{
		SET o TO options[startPos].
		IF SLOPE_IS_SAFE(o)
		{
			SET nextPoint TO o.
			RETURN nextPoint.
			BREAK.
		}
		ELSE
		{
			SET startPos TO startPos + 1.
		}
	}
}

FUNCTION DRIVE_TO
{
	PARAMETER point.
	
	BRAKES OFF.
	SET spd TO 1. // Really stinkin' slow, but safe.

	// Throttle control variables
	SET throttlePID TO PIDLOOP(0.15, 0.05, 0.1, -1.0, 1.0).
	SET throttlePID:SETPOINT TO spd.

	// Steering control variables
	SET steerPID TO PIDLOOP(0.15, 0.05, 0.1, -1.0, 1.0).
	SET steerPID:SETPOINT TO point:HEADING.
	
	CLEARSCREEN.
	
	SET thrott TO 0.
	SET steerVal TO 0.
	
	UNTIL THERE_YET(point)
	{
		SET thrott TO throttlePID:UPDATE(TIME:SECONDS, SHIP:GROUNDSPEED).
		SET steerVal TO steerPID:UPDATE(TIME:SECONDS, SHIP:HEADING).
		
		LOCK WHEELTHROTTLE TO thrott.
		LOCK WHEELSTEER TO steerVal.
		
		PRINT "Current Location: " + ROUND(SHIP:GEOPOSITION:LAT,3) + ", " + ROUND(SHIP:GEOPOSITION:LNG,3) at (0,3).
		PRINT "Next waypoint: " + ROUND(point:LAT,3) + ", " + ROUND(point:LNG, 3) AT (0,4).
		PRINT "Throttle: " + ROUND(thrott, 3) AT (0,9).
		PRINT "Steering:    " + ROUND(steerVal,3) AT (0,10).
		
		WAIT 0.01.
	}
	STOP().
}

FUNCTION STOP
{
	IF GROUNDSPEED > 0.5
	{
		LOCK WHEELTHROTTLE TO -0.5.
	}
	ELSE
	{
		UNLOCK WHEELTHROTTLE.
		IF NOT BRAKES
		{
			BRAKES ON.
		}
	}
	UNLOCK ALL. NOTIFY("Arrived!", "NOMINAL").
}

FUNCTION PARK
{
	STOP().
	LIGHTS ON.
	FOR someAntenna IN SHIP:PARTSNAMED("RTLongAntenna2")
	{
		someAntenna:GETMODULE("ModuleRTAntenna"):DOEVENT("activate").
	}
}

Can someone help me find my mistake(s)?

Link to comment
Share on other sites

35 minutes ago, MAFman said:

Can someone help me find my mistake(s)?

Sorry, I don't have much time on disposal to inspect every line of code, neither to try it in KSP. At first sight, everything looks OK, but oviously it is not, otherwise you would not ask for help.
Only thing I can is to give you tip for selfhelp.

Put some additional lines of near suspicious part of code. Just print some info, either on screen or log file that could give you a clue is something work as intended or not. Similar to those "notify" lines like you already have in code.

Without modern debuger and code insight info too see each value in variable it is pretty much only way to find logic errors or exact spot what is problematic line of code. You will need that kind of experience anyhow if you encounter in real life problematic situatons with some piece of software that is pretty much closed black box. Not only for game purposes in kOS, but other programming areas too.

Link to comment
Share on other sites

Quote

[LOG 19:11:11.259] System.Collections.Generic.KeyNotFoundException: The given key was not present in the dictionary.
  at System.Collections.Generic.Dictionary`2[System.String,System.Int32].get_Item (System.String key) [0x00000] in <filename unknown>:0 
  at kOS.Safe.Compilation.ProgramBuilder.ReplaceLabels 

 

When you get this error (key was not present in the dictionary) and you get it being done by ProgramBuilder.ReplaceLabels() as shown here, there's a good chance it's not your fault and it's a bug in how things are being loaded into the VM by kOS.  We've done a lot of overhauling in that area in recent developer work so I can't tell if this problem would still exist in the next release or not unless I can re-run exactly everything you're doing in exactly the way you have been running it.

That would mean, starting from the same saved game, running the same program, the same way, on the same craft.   Some of what your program is doing looks like it's dependent on having a craft that is exactly like it expects it to be, with the same parts on it.  (Which is why I'm reluctant to give it a test.  It's a lot of set up work for a problem that for all I know might already be fixed.)

The code change under the hood that may or may not have already fixed this in the development version is this one:

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

The old way the RUN command was implemented before that had some odd failure cases where it would crash the ProgramBuilder.ReplaceLabels method.

If you aren't in a position to be able to compile the kOS C# code yourself, I could try to give you a temporary ZIP file you can try to use to re-install kOS and it would give you the development version as-is (possible problems and all), and it might let you test if you still have this problem or not.  I'm a bit reluctant to do this, though, as I don't think we're that far away from having a more official proper release anyway, and spending time on this problem would detract from getting that release out, which might fix it anyway.

 

 

Link to comment
Share on other sites

9 hours ago, Steven Mading said:

When you get this error (key was not present in the dictionary) and you get it being done by ProgramBuilder.ReplaceLabels() as shown here, there's a good chance it's not your fault and it's a bug in how things are being loaded into the VM by kOS.  We've done a lot of overhauling in that area in recent developer work so I can't tell if this problem would still exist in the next release or not unless I can re-run exactly everything you're doing in exactly the way you have been running it.

That would mean, starting from the same saved game, running the same program, the same way, on the same craft.   Some of what your program is doing looks like it's dependent on having a craft that is exactly like it expects it to be, with the same parts on it.  (Which is why I'm reluctant to give it a test.  It's a lot of set up work for a problem that for all I know might already be fixed.)

The code change under the hood that may or may not have already fixed this in the development version is this one:

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

The old way the RUN command was implemented before that had some odd failure cases where it would crash the ProgramBuilder.ReplaceLabels method.

If you aren't in a position to be able to compile the kOS C# code yourself, I could try to give you a temporary ZIP file you can try to use to re-install kOS and it would give you the development version as-is (possible problems and all), and it might let you test if you still have this problem or not.  I'm a bit reluctant to do this, though, as I don't think we're that far away from having a more official proper release anyway, and spending time on this problem would detract from getting that release out, which might fix it anyway.

 

 

I'd be super excited for a new patch version! :D I think I'll wait until the official release.

9 hours ago, Steven Mading said:

When you get this error (key was not present in the dictionary) and you get it being done by ProgramBuilder.ReplaceLabels() as shown here, there's a good chance it's not your fault and it's a bug in how things are being loaded into the VM by kOS.  We've done a lot of overhauling in that area in recent developer work so I can't tell if this problem would still exist in the next release or not unless I can re-run exactly everything you're doing in exactly the way you have been running it.

That would mean, starting from the same saved game, running the same program, the same way, on the same craft.   Some of what your program is doing looks like it's dependent on having a craft that is exactly like it expects it to be, with the same parts on it.  (Which is why I'm reluctant to give it a test.  It's a lot of set up work for a problem that for all I know might already be fixed.)

The code change under the hood that may or may not have already fixed this in the development version is this one:

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

The old way the RUN command was implemented before that had some odd failure cases where it would crash the ProgramBuilder.ReplaceLabels method.

If you aren't in a position to be able to compile the kOS C# code yourself, I could try to give you a temporary ZIP file you can try to use to re-install kOS and it would give you the development version as-is (possible problems and all), and it might let you test if you still have this problem or not.  I'm a bit reluctant to do this, though, as I don't think we're that far away from having a more official proper release anyway, and spending time on this problem would detract from getting that release out, which might fix it anyway.

 

 

I can send you my save game and rover.craft if you want to try it. I'm also using RemoteTech and the RT Communotron 32, which is the only non-stock part on the rover.

Link to comment
Share on other sites

On 7/4/2016 at 1:51 PM, Steven Mading said:

When you get this error (key was not present in the dictionary) and you get it being done by ProgramBuilder.ReplaceLabels() as shown here, there's a good chance it's not your fault and it's a bug in how things are being loaded into the VM by kOS.  We've done a lot of overhauling in that area in recent developer work so I can't tell if this problem would still exist in the next release or not unless I can re-run exactly everything you're doing in exactly the way you have been running it.

That would mean, starting from the same saved game, running the same program, the same way, on the same craft.   Some of what your program is doing looks like it's dependent on having a craft that is exactly like it expects it to be, with the same parts on it.  (Which is why I'm reluctant to give it a test.  It's a lot of set up work for a problem that for all I know might already be fixed.)

The code change under the hood that may or may not have already fixed this in the development version is this one:

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

The old way the RUN command was implemented before that had some odd failure cases where it would crash the ProgramBuilder.ReplaceLabels method.

If you aren't in a position to be able to compile the kOS C# code yourself, I could try to give you a temporary ZIP file you can try to use to re-install kOS and it would give you the development version as-is (possible problems and all), and it might let you test if you still have this problem or not.  I'm a bit reluctant to do this, though, as I don't think we're that far away from having a more official proper release anyway, and spending time on this problem would detract from getting that release out, which might fix it anyway.

 

 

What folder in GitHub is the Program-Builder in?

Link to comment
Share on other sites

Found it! Also found the log line where the error happened...

Apparently, it tried to get a key from System.Collections.Generic.Dictionary`2 and it didn't find it. What is the difference between Dictionary and Dictionary`2?

Also, shouldn't the code try to access just System.Collections.Generic.Dictionary?

Why is it saying AddObjectParts(IEnumerable`1 parts)[0x00000] in <filename unknown>:0 ? Especially the <filename unknown>? I'm guessing it should be "in <autonav>:0" or something.

[LOG 13:51:15.203] kOS: FunctionCopy: Volume: 1 Direction: to Filename: autonav.ks
[LOG 13:51:15.728] kOS: At autonavinit.ks on 1, line 17
RUN autoNav(direct).
^
Called from startup.ks on 1, line 20
RUN autoNavInit(270).
^
Called from boot.ks on 1, line 139
			RUN startup.ks.
   ^
Called from boot.ks on 1, line 153
			RUN startup.ks.
   ^
Called from sys:boot, line 1
(Can't show source line)
^

[LOG 13:51:15.730] System.Collections.Generic.KeyNotFoundException: The given key was not present in the dictionary.
  at System.Collections.Generic.Dictionary`2[System.String,System.Int32].get_Item (System.String key) [0x00000] in <filename unknown>:0 
  at kOS.Safe.Compilation.ProgramBuilder.ReplaceLabels (System.Collections.Generic.List`1 program) [0x00000] in <filename unknown>:0 
  at kOS.Safe.Compilation.ProgramBuilder.BuildProgram () [0x00000] in <filename unknown>:0 
  at kOS.Safe.Execution.ProgramContext.AddObjectParts (IEnumerable`1 parts) [0x00000] in <filename unknown>:0 
  at kOS.Function.FunctionLoad.Execute (kOS.SharedObjects shared) [0x00000] in <filename unknown>:0 
  at kOS.Function.FunctionManager.CallFunction (System.String functionName) [0x00000] in <filename unknown>:0 
  at kOS.Safe.Execution.CPU.CallBuiltinFunction (System.String functionName) [0x00000] in <filename unknown>:0 
  at kOS.Safe.Compilation.OpcodeCall.StaticExecute (ICpu cpu, Boolean direct, System.Object destination, Boolean calledFromKOSDelegateCall) [0x00000] in <filename unknown>:0 
  at kOS.Safe.Compilation.OpcodeCall.Execute (ICpu cpu) [0x00000] in <filename unknown>:0 
  at kOS.Safe.Execution.CPU.ExecuteInstruction (IProgramContext context, Boolean doProfiling) [0x00000] in <filename unknown>:0 
[LOG 13:51:15.735] Code Fragment
File                 Line:Col IP   label   opcode operand
====                 ====:=== ==== ================================  
1/startup.ks           20:17  0740 @0736   push 270 
1/startup.ks           20:17  0741 @0737   call 674 
1/startup.ks           20:17  0742 @0738   pop 
                        0:0   0743         push 0 
                        0:0   0744         return 0 deep 
1/autonavinit.ks       17:1   0745 @0739   push $program-autonav* 
1/autonavinit.ks       17:1   0746 @0740   exists 
1/autonavinit.ks       17:1   0747 @0741   br.false +4 
1/autonavinit.ks       17:1   0748 @0742   br.false +11 
1/autonavinit.ks       17:1   0749 @0743   push 0 
1/autonavinit.ks       17:1   0750 @0744   return 0 deep 
1/autonavinit.ks       17:1   0751 @0745   pop 
1/autonavinit.ks       17:1   0752 @0746   push $program-autonav* 
1/autonavinit.ks       17:1   0753 @0747   push _KOSArgMarker_ 
1/autonavinit.ks       17:1   0754 @0748   push autonav 
1/autonavinit.ks       17:1   0755 @0749   push null 
1/autonavinit.ks       17:1   0756 @0750   call load() <<--INSTRUCTION POINTER--
1/autonavinit.ks       17:1   0757 @0751   pop 
1/autonavinit.ks       17:1   0758 @0752   store 
1/autonavinit.ks       17:1   0759 @0753   call $program-autonav* 
1/autonavinit.ks       17:1   0760 @0754   pop 
1/autonavinit.ks       17:1   0761 @0755   push 0 
1/autonavinit.ks       17:1   0762 @0756   return 0 deep 
1/autonavinit.ks        1:11  0763 @0757   push direct 
1/autonavinit.ks        1:11  0764 @0758   swap 
1/autonavinit.ks        1:11  0765 @0759   storelocal 
1/autonavinit.ks        1:11  0766 @0760   argbottom 
1/autonavinit.ks        2:1   0767 @0761   push $brakes 
1/autonavinit.ks        2:8   0768 @0762   push True 
1/autonavinit.ks        2:8   0769 @0763   store 
1/autonavinit.ks        3:1   0770 @0764   push _KOSArgMarker_ 
1/autonavinit.ks        3:11  0771 @0765   push 1 
1/autonavinit.ks        3:11  0772 @0766   call switch() 

 

FOUND IT! In the function ReplaceLabels(), there's a variable

var labels = new Dictionary<string, int>();

It's complaining because the string parameter is missing. Looking further down the code, there's an if statement that is not being met, and it doesn't have an "else":

private void ReplaceLabels(List<Opcode> program)
        {            
            var labels = new Dictionary<string, int>();

            // get the index of every label
            for (int index = 0; index < program.Count; index++)
            {
                if (program[index].Label != string.Empty)
                {
                    if (labels.ContainsKey(program[index].Label))
                    {
                        if (program[index].Label.EndsWith("-default"))
                            continue;
                        // This is one of those "should never happen" errors that if it happens
                        // it means kOS devs screwed up - so dump the partially relabeled program
                        // to the log just to help in diagnosing the bug report that may happen:
                        //
                        Utilities.SafeHouse.Logger.LogError("=====Relabeled Program so far is: =========");
                        Utilities.SafeHouse.Logger.LogError(Utilities.Debug.GetCodeFragment(program));

                        throw new Exceptions.KOSCompileException(LineCol.Unknown(), string.Format(
                            "ProgramBuilder.ReplaceLabels: Cannot add label {0}, label already exists.  Opcode: {1}", program[index].Label, program[index].ToString()));
                    }
                    labels.Add(program[index].Label, index);
                }
}

You should have an "else" condition to "if (program[index].Label != string.Empty) { //stuff}" as well as "if(labels.containsKey(program[index].Label)){//More stuff}

Lesson: If you have an IF(), always follow it with ELSE().

Edited by MAFman
Link to comment
Share on other sites

On 7/3/2016 at 8:17 PM, MAFman said:

Ok, here's the log file... I finally found it... (at least the part with the kOS error.)

Well, I found the problem.  I don't know why it's true, but `unlock all` doesn't appear to do anything, but it screws up function declaration.  It literally compiles as a `NOP` opcode, which is essentially "don't do anything, just move to the next instruction".  I'm pretty sure it was supposed to go away at the same time as `unset all`.  That being said, it is still documented as working.  If you simply exit the program, there is no need to make this call anyways, since all flight controls automatically unlock upon returning to the terminal.

Basically, remove the one reference to `unlock all.` from inside the `stop` function, and you should compile.  Oh, and never use it again! :P We'll have to update the docs, and kill it once and for all.

Link to comment
Share on other sites

Odd, your post some how crossed mine... even though I refreshed before posting.  Anyways, I'll respond to your comments, but my above post still applies.

4 hours ago, MAFman said:

Found it! Also found the log line where the error happened...

Apparently, it tried to get a key from System.Collections.Generic.Dictionary`2 and it didn't find it. What is the difference between Dictionary and Dictionary`2?

Also, shouldn't the code try to access just System.Collections.Generic.Dictionary?

Why is it saying AddObjectParts(IEnumerable`1 parts)[0x00000] in <filename unknown>:0 ? Especially the <filename unknown>? I'm guessing it should be "in <autonav>:0" or something.

This is a result of the use of Generics.  Essentially C# does some fancy things to dynamically create the type definition for the dictionary based on the Type data that was passed to it.  So our code accesses a `Dictionary<string, int>` which the compiler then defines as `System.Collections.Generic.Dictionary`2`

4 hours ago, MAFman said:

FOUND IT! In the function ReplaceLabels(), there's a variable

[...]

It's complaining because the string parameter is missing. Looking further down the code, there's an if statement that is not being met, and it doesn't have an "else":

 

Actually, I added some debugging statements and this is not the section of code that throws the error.  The applicable code is here: https://github.com/KSP-KOS/KOS/blob/develop/src/kOS.Safe/Compilation/ProgramBuilder.cs#L235 You'll notice that the code section you cited is actually protected by checking for an empty string before using it as a key, and it checks the dictionary to make sure it contains the key before attempting to use it.  The line I cited has no such protection, and can only be triggered in very rare circumstances (like using `unlock all.` with functions).  I almost added a better error message here about 6 months back, but got busy working on other things including fixing another bug that was causing this same message.

4 hours ago, MAFman said:

You should have an "else" condition to "if (program[index].Label != string.Empty) { //stuff}" as well as "if(labels.containsKey(program[index].Label)){//More stuff}

Lesson: If you have an IF(), always follow it with ELSE().

Since this if condition isn't the problem, an else won't fix it.  More importantly, an if statement does not always need an else.  In our particular instance, we have an implicit else: "if this condition is true, continue to the next loop." which will skip the section of code that follows "throw an error".  Because "continue" skips the rest of the loop, it's the same as saying "if this condition is true, continue to the next loop, else throw an error".  And there are plenty of practical times where no else condition is required at all.  "create a new variable x equal to 1, if the current time is after noon, set x equal to 2" is perfectly valid.

I wanted to take a moment to point this out specifically because kOS tends to attract, and focus on, new programmers.  I don't want to have a bunch of people now think that they absolutely need an else for every if.  I'm gonna find a whole lot of user scripts that read `if true { doSomething(). } else { doNothing() }`.  I appreciate that you were walking through our code, and thought you found the error, but speaking in general absolutes can often be taken out of context and confuse others.

Link to comment
Share on other sites

Twitch devs show kOS v1.0.0 UTC time 2016-07-08 21:00 (Friday)

Stream Channel: https://www.twitch.tv/dunbaratu

With kOS v1.0.0 coming up Real Soon Now (tm), we decided to do a stream on Twitch of new things, with an eye toward Q&A about it.  Come along and see what important things are changing and have a chance to ask about it.

We intend this to be timed very close to the release of kOS v1.0.0.  The release might go out just a few hours before, or just a few hours after, the stream itself.  In any case the release is expected to be roughly co-incident with the stream.  

Unlike the release, for the stream we figured it was more important to announce a predictable time ahead of time (thus this message) because it's live interaction.  With the actual release, well, it comes out whenever we happen to have gotten all the last pieces in place (changelogs, documentation updates, etc).

This is in no way a binding promise to get the release out at the expected time!!  Who knows what might be found in those last few hours of work before it goes out.  It could be something that is a showstopper.  We'd LIKE to get it out at the same time as the stream.  We don't PROMISE to do so however.

The stream will be broadcast here: https://www.twitch.tv/dunbaratu
And include at least 2 of the devs on microphone:

  • Dunbaratu (Also known as Steven Mading here on the forums, AKA "me")
  • Hvacengi

The duration is unknown.  It depends on questions and interaction.

 

Edited by Steven Mading
Just removed the math entirely. The title says 21:00 UTC, that should be enough.
Link to comment
Share on other sites

13 minutes ago, Steven Mading said:

For reference, 21:00 UTC-5 Friday is:

  •     - Berlin: 11pm
  •     - UK: 10pm
  •     - New York: 6pm
  •     - Los Angeles: 3pm
  •     - Sydney: Saturday 8pm

Something’s off with at least the American times listed: 2100 UTC can’t be 1800 NYC, as that’s only a three-hour difference.  Currently NYC is UTC-0400 (and it’s UTC-0500 in winter), so if this really is happening 2100 UTC tomorrow, it will be at 5pm New York time.  LA is similarly off, more likely 2pm than 3pm.  Not sure about the rest.

Link to comment
Share on other sites

2 minutes ago, meyerweb said:

Something’s off with at least the American times listed: 2100 UTC can’t be 1800 NYC, as that’s only a three-hour difference.  Currently NYC is UTC-0400 (and it’s UTC-0500 in winter), so if this really is happening 2100 UTC tomorrow, it will be at 5pm New York time.  LA is similarly off, more likely 2pm than 3pm.  Not sure about the rest.

The indicated time was UTC-5, not UTC.

That said, if the actual time zone is Eastern Daylight Time (Eastern Standard Time is UTC-5), the US times are correct as listed and the other timezones are possibly off.  If EDT isn't the origin time zone, then we'll have to wait for @Steven Madingto correct us

 

Link to comment
Share on other sites

1 minute ago, dewin said:

The indicated time was UTC-5, not UTC.

That said, if the actual time zone is Eastern Daylight Time (Eastern Standard Time is UTC-5), the US times are correct as listed and the other timezones are possibly off.  If EDT isn't the origin time zone, then we'll have to wait for @Steven Madingto correct us

 

No, that doesn’t work either.  2100 UTC-5 would be 10pm NYC time, because UTC-5 is currently the US Central time zone, one hour behind NYC.  Even if they meant the Eastern US time zone under DST, as it presently is, 2100 is still 9pm, not 5pm.  Further, the top-of-post time given is 2100 UTC, not 2100 UTC-5.

Link to comment
Share on other sites

I might not be able watch live stream, but I would appretiate if you cover some of stuff in it:

  • Dmagic science part support
  • IR part sequencer support (with respect to latest available changes in IR mod)
  • gamebalance changes - power consuption vs IPU, earler/later kOS parts
  • reintroduction of LaserDist mod, some folks might be even forget that it exist, it can be combined with IR parts if possible
  • fine tune PID for built in STEER command (not to be confused with custom PIDloop and raw pilot input)

Besides that, whatever is new/changed from last version of kOS. Also, Steven always have some nice math methods to show how things were done, like how slope is calculated that more falls into general math category, rather than kOS programming itself. Some of things I never learned trough formal education and for some there is never real life purpose for using it until there is need for it in KSP.

A link for recorded stream will be appreciated too, don't be discouraged if there was not many watchers on live stream, plenty of kOS users are scatered trough various time zones.

Link to comment
Share on other sites

One of the new kOS features is proper support for external addons, in that other addons can now add structures that you can access from your kOS scripts.  This means that rather than waiting for kOS to provide support for a mod, it is now possible for a mod to provide support for kOS (or a third mod that supports both).

I'm actually working on a mod that takes advantage of this, with the primary goal of talking between kOS and KRPC.  (Though it will probably include communication between kOS Processors as a freebie, and that portion doesn't require KRPC). 

Link to comment
Share on other sites

2 minutes ago, dewin said:

will probably include communication between kOS Processors as a freebie

Inter-processor and inter-vessel communication is included as part of this next release.  I'm sorry that I haven't had any opportunity yet to look at your mod and see if I have any useful comments or pointers, but I do mean to do that soon.  I also have a sample addon prepared that I intend to make available so that other modders can see the recommended workflow.  I just need to add a simple reflection interface so that people won't have to dig through the really complicated IR or RT addons to understand how to use reflection to access an api.

18 minutes ago, kcs123 said:

I might not be able watch live stream, but I would appretiate if you cover some of stuff in it:

Most of those items are not specific to v1.0.0.  While we're happy to discuss them, the new features will be the main focus of the stream.  If we don't have few enough questions that we can kind of pick a direction, we'll definitely keep that list in mind though.  If we don't get to it, Stephen tries to stream regularly so ping us with a reminder and I'm sure that he can find a way to fit it into one of his other streams.

59 minutes ago, meyerweb said:

Something’s off with at least the American times listed: 2100 UTC can’t be 1800 NYC, as that’s only a three-hour difference.  Currently NYC is UTC-0400 (and it’s UTC-0500 in winter), so if this really is happening 2100 UTC tomorrow, it will be at 5pm New York time.  LA is similarly off, more likely 2pm than 3pm.  Not sure about the rest.

I'm scheduled for 5PM (17:00) EDT (UTC-4, local time for me), 4PM (16:00) CDT (UTC-5, local to Stephen), 9PM (21:00) UTC.  Feel free to extrapolate the other time zones from that.  I'll ping him in chat to update it.

Link to comment
Share on other sites

2 hours ago, meyerweb said:

Something’s off with at least the American times listed: 2100 UTC can’t be 1800 NYC, as that’s only a three-hour difference.  Currently NYC is UTC-0400 (and it’s UTC-0500 in winter), so if this really is happening 2100 UTC tomorrow, it will be at 5pm New York time.  LA is similarly off, more likely 2pm than 3pm.  Not sure about the rest.

What's off is that I originally typed in my time in my local time zone as 16:00 UTC-5, then decided it was better to just post the UTC time, so I converted it to 21:00 for UTC, but then neglected to change the label from "UTC-5" to just "UTC".

Add to that the fact when I composed the message yesterday and saved it as draft, I was planning on a different start time and when I changed the start time to the one I went with in the end, I didn't edit all the cities' times to match that edit.  In the end it was an inconsistent mess.

What I meant was this:

I live in UTC-5, my local time is going to be 16:00 when I stream.  That will be 21:00 in UTC+0.

I've edited and corrected the post now.  Thanks for catching it.

 

Edited by Steven Mading
Link to comment
Share on other sites

1 hour ago, kcs123 said:

there is never real life purpose for using it until there is need for it in KSP.

A link for recorded stream will be appreciated too, don't be discouraged if there was not many watchers on live stream, plenty of kOS users are scatered trough various time zones.

For this reason I plan to not have the background music I usually have when I stream.  I want the recorded video to be un-muted for people who have to watch it later.

 

Link to comment
Share on other sites

1 hour ago, hvacengi said:

Inter-processor and inter-vessel communication is included as part of this next release.  I'm sorry that I haven't had any opportunity yet to look at your mod and see if I have any useful comments or pointers, but I do mean to do that soon.

Heh, looking through my mod probably won't find much at this point anyways as it's not really at a functional level yet

It'll be interesting to look at your inter-(processor,vessel) communication bits though; it might change how I approach the kRPC bridge -- particularly if I can just treat kRPC clients as a 'virtual' vessel of sorts rather than everything else that I'm doing.  Some key differences I'm seeing poking at the github docs:

  • I'm using a different mechanism for serialization than kOS's inbuilt one, so there are different restrictions on what constitutes a valid message.  (Notable: Mine uses something like {"type": "vessel", "data": "vesselguid"} as its mechanism for representing everything except primitives, and can properly handle things like a particular list being referenced in multiple places (or referencing itself).  The output is generally more compact than kOS's format)
  • Parts are serializable in my implementation.
  • I don't implement actual message queues to keep things simple and avoid 'leaked' messages in the case of a kRPC client never checking for them.  Instead, a given processor has at most one inbound and one outbound message and mechanisms for atomically setting either field.  A given processor can both "send" (setting its outbound message) and "send to" (setting another processor's inbound message), the two are separate queues.  The kRPC side has no inbound/outbound message -- it communicates by examining the outbound field of other processors or setting their inbound fields.
  • RT is ignored completely, but this is true for kRPC in general.  In-game-wise, this can be explained as kRPC being additional processing power on the same vessel -- though one could totally "cheat" at remotetech with this (kOS from one ship -> kRPC -> kOS to ship far away/out of communications range with no latency).

Now that I think about it more, I might just stash my current code somewhere and start from sort-of-scratch using the kOS API, focusing solely on the kRPC bridge (which was my original intent).  I knew that inter-vessel/processor communication was on the kOS roadmap but had no idea it was going to be in this release.

Oh, one convenience feature I'm seeing missing from the current kOS implementation: My implementation had a notion of a message ID or count of received/sent messages or whatnot -- mainly so that messages can be processed in the background(ish) by doing something like:

ON something:messagerxcount { // changes every time we receive a new message.
   handleMessage();
}

The only way I see to do that in the current implementation is to do ON messagequeue:length, but there's a lot of complexities in that particular case.  (Also, a count of "packets" tx/rx would be neat anyways).

Though now I almost wonder if a future version of kOS should have a proper event system.  As I understand ON, it's examining an output every update and firing when it changes -- as opposed to a more passive "sleep until I'm awoken, event X wakes me up" system.

Link to comment
Share on other sites

Looking for some help as I am trying to write some ascent and plane-change scripts. What I want is for the craft to burn until the apoapsis is located directly above the equator. I have been doing some basic research, but I am brand new to KoS and computer language in general and having some tough times. Here is what I have been trying:

 

//First I tried the general POSITIONAT(SHIP, APOAPSIS), but then saw a negative return on the Y, 
//so I tried to minus the SHIP:BODY:POSITION to get a good  value, but then realized the Y value it returned was not a readout of the latitude
//I then tried this, but again, to no avail

SET varname TO POSITIONAT(SHIP, APOAPSIS) - SHIP:BODY:POSITION.

WAIT UNTIL varname:Y < 1000.
LOCK THROTTLE TO .2. 

WAIT UNTIL varname:Y < 100.
LOCK THROTTLE TO 0.

Does anyone know a better way of telling KoS what my future latitude will be at Apoapsis? (while burning)

Link to comment
Share on other sites

12 minutes ago, seamus2849 said:

Does anyone know a better way of telling KoS what my future latitude will be at Apoapsis? (while burning)

Since KSP doesn't have axial tilt, latitude is (IIRC):

ARCSIN(position:y / position:mag)

where position is your relative position to the planet.  (If the magnitude of your position somehow is 0, latitude is technically undefined and you have bigger problems.)

Latitude for a given true anomaly value is:

ARCSIN(SIN(trueanomaly + argumentofperiapsis) * SIN(inclination))

True anomaly at periapsis is 0, at apoapsis is 180.  Thus, you can do ARCSIN(SIN(180 + argumentofperiapsis) * SIN(inclination)) to get latitude at apoapsis without even needing to use POSITIONAT.

Edited by dewin
Link to comment
Share on other sites

37 minutes ago, dewin said:

Since KSP doesn't have axial tilt, latitude is (IIRC):

ARCSIN(position:y / position:mag)

where position is your relative position to the planet.  (If the magnitude of your position somehow is 0, latitude is technically undefined and you have bigger problems.)

Latitude for a given true anomaly value is:

ARCSIN(SIN(trueanomaly + argumentofperiapsis) * SIN(inclination))

True anomaly at periapsis is 0, at apoapsis is 180.  Thus, you can do ARCSIN(SIN(180 + argumentofperiapsis) * SIN(inclination)) to get latitude at apoapsis without even needing to use POSITIONAT.

Thanks for the quick post and great math! 

I plugged that in and the 

Quote

ARCSIN(SIN(trueanomaly + argumentofperiapsis) * SIN(inclination))

does provide a reading of my vessel current latitude, but I have to add "ship:orbit:" in front of the argumentofperiapsis and inclination in order to get a readout. Am I doing it wrong still?

Link to comment
Share on other sites

Nope!  I was using descriptive variables, not quite actual kOS code, and completely meant it as "replace this value with your current (or desired) true anomaly, this value with your argument of periapsis, etc.)

You may want to use ship:obt:trueanomaly and ship:obt:inclination for consistency, or just use obt:* in all 3 cases (the 'ship:' is optional).

Also, two months ago I didn't know any of the math either.  I'm particularly proud of the latitude-at-anomaly function though -- other orbital formulae I found or derived from well-known published equations/etc somewhere, but I managed to figure out latitude entirely on my own.

It's deprecated and undocumented, but some of my stuff is here -- mostly focused on orbital math.  (lib_obt has the newest versions after i dropped the "create my own representation of an orbit" bits) https://github.com/dewiniaid/ksp-kos-scripts/commits/master

 

 

Link to comment
Share on other sites

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