-
Posts
334 -
Joined
-
Last visited
Content Type
Profiles
Forums
Developer Articles
KSP2 Release Notes
Everything posted by MAFman
-
It is installed on my desktop. I didn't think of running it as an administrator, though. I'll try that. What does the flag "RTLEnterCriticalSection" mean, BTW?
-
I usually run the 64- bit player, and I always get a crash-to-desktop within 5 minutes of starting the game. Attached below is a screenshot of the Visual Studio debug window explaining the error. Hopefully you understand it better than me... Error Image This happens no matter what I am doing in-game, or even if I'm doing anything at all.
-
How do I make a rover drive itself intelligently?
MAFman replied to MAFman's topic in KSP1 Mods Discussions
Ok! I did find a one-size-fits-all satellite launching script! -
How do I make a rover drive itself intelligently?
MAFman replied to MAFman's topic in KSP1 Mods Discussions
The goal of the rovers is to be a passive relay for the RemoteTech signal. Also, hmmm...can I get the biome of a LATLNG()? Maybe I can do that, and if the biome of an option is "Water", it'll skip that option. -
How do I make a rover drive itself intelligently?
MAFman replied to MAFman's topic in KSP1 Mods Discussions
Improvement? I didn't change the other scripts; just the way I iterate over the lists. PARAMETER direct. SWITCH TO 1. DELETE startup.ks. UNTIL NOT ADDONS:RT:HASCONNECTION(SHIP) { POPULATE(direct). SEARCH(options). DRIVE_TO(nextPoint). } UNTIL ADDONS:RT:HASCONNECTION(SHIP) { POPULATE(direct + 180). SEARCH(options). DRIVE_TO(nextPoint). } FUNCTION POPULATE { PARAMETER whichWay. SET here TO SHIP:GEOPOSITION. SET offSet TO (360 * 100) / (2 * CONSTANT:PI * BODY:RADIUS). SET preOptions TO LIST // An arc 270 degrees wide, 100m in radius ( LATLNG(here:LAT + offset, here:LNG), // forward LATLNG(here:LAT + (SIN(22.5) * offset), here:LNG + (COS(22.5) * offset)), // 22.5 deg. left LATLNG(here:LAT + (SIN(22.5) * offset), here:LNG - (COS(22.5) * offset)), // 22.5 deg. right LATLNG(here:LAT + (SIN(45) * offset), here:LNG + (COS(45) * offset)), // 45 deg. left LATLNG(here:LAT + (SIN(45) * offset), here:LNG - (COS(45) * offset)), // 45 deg. right LATLNG(here:LAT + (SIN(57.5) * offset), here:LNG + (COS(57.5) * offset)), // 57.5 deg. left LATLNG(here:LAT + (SIN(57.5) * offset), here:LNG - (COS(57.5) * offset)), // 57.5 deg. right LATLNG(here:LAT + (SIN(90) * offset), here:LNG + (COS(90) * offset)), // 90 deg. left LATLNG(here:LAT + (SIN(90) * offset), here:LNG - (COS(90) * offset)), // 90 deg. right LATLNG(here:LAT + (SIN(112.5) * offset), here:LNG + (COS(112.5) * offset)), // 112.5 deg. left LATLNG(here:LAT + (SIN(112.5) * offset), here:LNG - (COS(112.5) * offset)), // 112.5 deg. right LATLNG(here:LAT + (SIN(135) * offset), here:LNG + (COS(135) * offset)), // 135 deg. left LATLNG(here:LAT + (SIN(135) * offset), here:LNG - (COS(135) * offset)) // 135 deg. right ). // Now rotate the whole thing until it aligns with "whichWay" SET options TO LIST(). FOR o IN preOptions { // Do some matrix magic options:ADD(LATLNG((o:LAT * SIN(whichWay)) - (o:LNG * COS(whichWay)), (o:LAT * COS(whichWay)) + (o:LNG * SIN(whichWay)))). } RETURN options. } FUNCTION SEARCH { PARAMETER options. SET sortedBySlope TO LIST(). SET start TO 0. UNTIL start > options:LENGTH { SET here TO SHIP:GEOPOSITION. SET there TO options[start]. SET frac TO (here:TERRAINHEIGHT - there:TERRAINHEIGHT) / 100. SET slope_a TO ABS(ARCTAN(frac)). SET there_last TO options[start - 1]. // The option before this one IF there_last:INDEX > 0 { SET frac_b TO (here:TERRAINHEIGHT - there_last:TERRAINHEIGHT) / 100. SET slope_b TO ABS(ARCTAN(frac_b)). IF slope_a < slope_b // If the current slope is less than the last slope, { sortedBySlope:INSERT(0, there). // Put it into the list at the zero-th position } ELSE // If the current slope is greater than the last slope, { sortedBySlope:INSERT(0, there_last). // Put the last slope into the list at the zero-th position } SET start TO start + 1. } ELSE { SET start TO start + 1. } } SET sortedByAngle TO LIST(). SET start TO 0. UNTIL start > sortedBySlope:LENGTH - 1 { // Sort the options again, this time by angle between the point and the direction SET currentPoint TO sortedBySlope[startAgain]. SET lastPoint TO sortedBySlope[startAgain - 1]. // The option before this one IF currentPoint:INDEX > 0 { SET theta TO ABS(whichWay - currentPoint:HEADING). SET last_theta TO ABS(whichWay - lastPoint:HEADING). IF theta < last_theta { sortedByAngle:INSERT(0, currentPoint). } ELSE { sortedByAngle:INSERT(0, lastPoint). } } SET start TO startAgain + 1. } // Run through both lists, and if there is a match, // i.e. there is a point whose corresponding point // in the other list is at the same index, // set the next waypoint to the match SET ind TO 0. UNTIL ind > options:LENGTH { SET a TO sortedBySlope[ind]. SET b TO sortedByAngle[ind]. IF a = b { SET nextPoint TO sortedBySlope[ind]. RETURN nextPoint. } ELSE { SET ind TO ind + 1. } } SET nextPoint TO sortedBySlope[0]. // If none of the conditions are true, just go with the point with the lowest slope... RETURN nextPoint. } FUNCTION DRIVE_TO { PARAMETER point. SET steerPID TO PIDLOOP(). SET throttlePID TO PIDLOOP(). SET steerPID:SETPOINT TO point:HEADING. SET throttlePID:SETPOINT TO 2.5. UNTIL point:DISTANCE < 10 { SET WHEELTHROTTLE TO throttlePID:UPDATE(TIME:SECONDS, GROUNDSPEED). SET WHEELSTEER TO steerPID:UPDATE(TIME:SECONDS, SHIP:HEADING). } STOP(). } FUNCTION STOP { SET WHEELSTEER TO 0. SET WHEELTHROTTLE TO 0. IF NOT BRAKES { BRAKES ON. } WAIT UNTIL GROUNDSPEED < 0.1. AG1 OFF. NOTIFY("Arrived!", "NOMINAL"). // Turn the cherry light off and tell us we've arrived } FUNCTION PARK { STOP(). // Activate all non-dipole antennas, and deactivate all dipoles FOR p IN SHIP:PARTS { SET mods TO p:MODULES. FOR m IN mods { IF m:NAME = "ModuleRTAntenna" AND p:NAME <> "RTShortAntenna1" { m:DOEVENT("activate"). } ELSE IF m:NAME = "ModuleRTAntenna" AND p:NAME = "RTShortAntenna1" { m:DOEVENT("deactivate"). } } } } -
How do I make a rover drive itself intelligently?
MAFman replied to MAFman's topic in KSP1 Mods Discussions
I modified my script...AGAIN... but now it's throwing an error... Boot: // First, set the ship to a known configuration. SET SHIP:CONTROL:PILOTMAINTHROTTLE TO 0. LIGHTS OFF. GEAR OFF. FOR p IN SHIP:PARTS { IF p:TITLE = "RoveMax Model M1" OR p:TITLE = "RoveMax Model S2" OR p:TITLE = "RoveMax Model XL3" OR p:TITLE = "TR-2L Ruggedized Vehicular Wheel" { SET SHIP:TYPE TO "rover". } } IF SHIP:TYPE = "rover" { BRAKES ON. WHEN SHIP:SENSORS:LIGHT < 0.75 THEN { LIGHTS ON. PRESERVE. } WHEN SHIP:SENSORS:LIGHT > 0.75 THEN { LIGHTS OFF. PRESERVE. } FOR p IN SHIP:PARTS { IF p:NAME = "fuelCell" OR p:NAME = "fuelCellArray" { p:GETMODULE("ModuleResourceConverter"):DOACTION("Start Fuel Cell", TRUE). } } } ELSE { 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((255/255), (114/255), 0). // Safety orange } ELSE IF priority = "WARNING" { SET col TO RED. } HUDTEXT("kOS: " + message, 2, 2, 30, col, FALSE). } FUNCTION ON_DRIVE { PARAMETER n, vol. SWITCH TO vol. LIST FILES IN allFiles. FOR f IN allFiles { IF f:NAME = n { SWITCH TO 1. RETURN TRUE. } } SWITCH TO 1. RETURN FALSE. } FUNCTION DELAY { SET dTime TO ADDONS:RT:DELAY(SHIP). 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 f. DELAY(). IF ON_DRIVE(f, 1) { DELETE f. } IF ON_DRIVE(f, 0) { SWITCH TO 0. COPY f TO 1. SWITCH TO 1. } } // Put a file on KSC FUNCTION UPLOAD { PARAMETER f. DELAY(). IF ON_DRIVE(f, 0) { SWITCH TO 0. DELETE f. SWITCH TO 1. } IF ON_DRIVE(f, 1) { COPY f TO 0. } } // Run a library, downloading it from KSC if necessary FUNCTION REQUIRE { PARAMETER lib. IF NOT ON_DRIVE(lib, 1) { DOWNLOAD(lib). } RENAME lib TO "new_library.ks". RUN new_library. RENAME "new_library.ks" TO lib. } // 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) // If the update script exists on the archive, download and run it. { IF ON_DRIVE("update.ks", 1) // If an old file exists on the archive { NOTIFY("An old update file already exists. Deleting old file...", "ALERT"). WAIT 5. DELETE update.ks. } DOWNLOAD(updateScript). SWITCH TO 0. DELETE updateScript. SWITCH TO 1. // Whichever situation is true, we now have an up-to-date file NOTIFY("Update file found! Executing...", "NOMINAL"). WAIT 5. RENAME updateScript TO "update.ks". RUN update.ks. DELETE update.ks. } ELSE // We don't have an update script, so do nothing. { NOTIFY("No update file found. Either you haven't created one or one is not necessary.", "ALERT"). } // If a startup.ks file exists on the disk, run that. SET bootScript TO SHIP:NAME + ".startup.ks". IF ON_DRIVE(bootScript, 1) { SWITCH TO 1. DELETE bootScript. // If we already have an old startup file, delete it. IF ON_DRIVE(startup.ks, 1) { SWITCH TO 1. DELETE startup.ks. } IF ON_DRIVE(bootScript, 0) { DOWNLOAD(bootScript). RENAME bootScript TO "startup.ks". RUN startup.ks. } ELSE { NOTIFY("Startup failed! Instructions not found.", "WARNING"). WAIT 5. REBOOT. } } ELSE IF ON_DRIVE(bootScript, 0) { IF NOT ON_DRIVE(bootScript, 1) { DOWNLOAD(bootScript). RENAME bootScript TO "startup.ks". RUN startup.ks. DELETE startup.ks. } ELSE { DELETE bootScript. DOWNLOAD(bootScript). RENAME bootScript TO "startup.ks". RUN startup.ks. DELETE startup.ks. } } } ELSE { WAIT UNTIL ADDONS:RT:HASCONNECTION(SHIP). // Avoid thrashing the CPU (when no startup.ks, but we have a persistent connection, it will continually reboot) WAIT 5. REBOOT. } Startup: // Relay rover startup file // Lists the number of active "relay" rovers // and bases its navigation software on that. SWITCH TO 1. DELETE boot.ks. // Download the appropriate libraries DOWNLOAD(autoNav.ks). // List the active relays LIST TARGETS IN allVessels. SET relays TO LIST(). FOR t IN allVessels { IF t:NAME = "Relay" AND t:TYPE = "rover" { relays:ADD(t). } } // Decide which direction to go IF relays:LENGTH = 0 { RUN autonav(270). } ELSE { SET iterationNum TO relays:LENGTH + 1. IF iterationNum = 1 { RUN autonav(0). } ELSE IF iterationNum = 2 { RUN autonav(270). } ELSE IF iterationNum = 3 { RUN autonav(180). } ELSE { SET iterationNum TO MOD(iterationNum, 3) + 1. // It can be 1, 2, or 3. No more, no less. } } Autonav: PARAMETER direct. SWITCH TO 1. DELETE startup.ks. UNTIL NOT ADDONS:RT:HASCONNECTION(SHIP) { POPULATE(direct). SEARCH(options). DRIVE_TO(nextPoint). } UNTIL ADDONS:RT:HASCONNECTION(SHIP) { POPULATE(direct + 180). SEARCH(options). DRIVE_TO(nextPoint). } FUNCTION POPULATE { PARAMETER whichWay. SET here TO SHIP:GEOPOSITION. SET offSet TO (360 * 100) / (2 * CONSTANT:PI * BODY:RADIUS). SET preOptions TO LIST // An arc 270 degrees wide, 100m in radius ( LATLNG(here:LAT + offset, here:LNG), // forward LATLNG(here:LAT + (SIN(22.5) * offset), here:LNG + (COS(22.5) * offset)), // 22.5 deg. left LATLNG(here:LAT + (SIN(22.5) * offset), here:LNG - (COS(22.5) * offset)), // 22.5 deg. right LATLNG(here:LAT + (SIN(45) * offset), here:LNG + (COS(45) * offset)), // 45 deg. left LATLNG(here:LAT + (SIN(45) * offset), here:LNG - (COS(45) * offset)), // 45 deg. right LATLNG(here:LAT + (SIN(57.5) * offset), here:LNG + (COS(57.5) * offset)), // 57.5 deg. left LATLNG(here:LAT + (SIN(57.5) * offset), here:LNG - (COS(57.5) * offset)), // 57.5 deg. right LATLNG(here:LAT + (SIN(90) * offset), here:LNG + (COS(90) * offset)), // 90 deg. left LATLNG(here:LAT + (SIN(90) * offset), here:LNG - (COS(90) * offset)), // 90 deg. right LATLNG(here:LAT + (SIN(112.5) * offset), here:LNG + (COS(112.5) * offset)), // 112.5 deg. left LATLNG(here:LAT + (SIN(112.5) * offset), here:LNG - (COS(112.5) * offset)), // 112.5 deg. right LATLNG(here:LAT + (SIN(135) * offset), here:LNG + (COS(135) * offset)), // 135 deg. left LATLNG(here:LAT + (SIN(135) * offset), here:LNG - (COS(135) * offset)) // 135 deg. right ). // Now rotate the whole thing until it aligns with "whichWay" SET options TO LIST(). FOR o IN preOptions { // Do some matrix magic options:ADD(LATLNG((o:LAT * SIN(whichWay)) - (o:LNG * COS(whichWay)), (o:LAT * COS(whichWay)) + (o:LNG * SIN(whichWay)))). } RETURN options. } FUNCTION SEARCH { PARAMETER options. SET sortedBySlope TO LIST(). FOR o IN options { // Sort the options by slope, with lowest first. SET here TO SHIP:GEOPOSITION. SET there TO o. SET frac TO (here:TERRAINHEIGHT - there:TERRAINHEIGHT) / 100. SET slope_a TO ABS(ARCTAN(frac)). SET there_last TO . // The option before this one SET frac_b TO (here:TERRAINHEIGHT - there_last:TERRAINHEIGHT) / 100. SET slope_b TO ABS(ARCTAN(frac_b)). IF slope_a < slope_b // If the current slope is less than the last slope, { sortedBySlope:INSERT(0, there). // Put it into the list at the zero-th position } ELSE // If the current slope is greater than the last slope, { sortedBySlope:INSERT(0, there_last). // Put the last slope into the list at the zero-th position } } SET sortedByAngle TO LIST(). FOR s IN sortedBySlope { // Sort the options again, this time by angle between the point and the direction SET currentPoint TO s. SET lastPoint TO . // The option before this one SET theta TO ABS(whichWay - currentPoint:HEADING). SET last_theta TO ABS(whichWay - lastPoint:HEADING). IF theta < last_theta { sortedByAngle:INSERT(0, currentPoint). } ELSE { sortedByAngle:INSERT(0, lastPoint). } } // Now run through both lists, and pick the first point whose index is the same in both // If the above condition cannot be met, pick the first point on sortedBySlope(). // Magic! :D // I really hope this works... FOR this IN sortedBySlope { SET that TO sortedByAngle[this:INDEX]. IF this:INDEX = that:INDEX { SET nextPoint TO sortedBySlope[this:INDEX]. RETURN nextPoint. } } SET nextPoint TO sortedBySlope[0]. RETURN nextPoint. } FUNCTION DRIVE_TO { PARAMETER point. SET steerPID TO PIDLOOP(). SET throttlePID TO PIDLOOP(). SET steerPID:SETPOINT TO point:HEADING. SET throttlePID:SETPOINT TO 2.5. UNTIL point:DISTANCE < 10 { SET WHEELTHROTTLE TO throttlePID:UPDATE(TIME:SECONDS, GROUNDSPEED). SET WHEELSTEER TO steerPID:UPDATE(TIME:SECONDS, SHIP:HEADING). } STOP(). } FUNCTION STOP { SET WHEELSTEER TO 0. SET WHEELTHROTTLE TO 0. IF NOT BRAKES { BRAKES ON. } WAIT UNTIL GROUNDSPEED < 0.1. AG1 OFF. NOTIFY("Arrived!", "NOMINAL"). // Turn the cherry light off and tell us we've arrived } FUNCTION PARK { STOP(). // Activate all non-dipole antennas, and deactivate all dipoles FOR p IN SHIP:PARTS { SET mods TO p:MODULES. FOR m IN mods { IF m:NAME = "ModuleRTAntenna" AND p:NAME <> "RTShortAntenna1" { m:DOEVENT("activate"). } ELSE IF m:NAME = "ModuleRTAntenna" AND p:NAME = "RTShortAntenna1" { m:DOEVENT("deactivate"). } } } } It's saying I can't get the index of a LATLNG, although I'm trying to get the index of a list value, which just so happens to be a LATLNG(). -
How do I make a rover drive itself intelligently?
MAFman replied to MAFman's topic in KSP1 Mods Discussions
I modified my script a bit, and now it seems to insist on driving into the ocean, or crashing... Halp! How do I get it to select the point from a list with the minimum slope and angle between itself and the desired heading? -
[1.3] kOS Scriptable Autopilot System v1.1.3.0
MAFman replied to erendrake's topic in KSP1 Mod Releases
Hmmm... *more derps later...* // First, set the ship to a known configuration. SET SHIP:CONTROL:PILOTMAINTHROTTLE TO 0. LIGHTS OFF. GEAR OFF. IF SHIP:NAME = "Relay" { SET SHIP:TYPE TO "rover". } IF SHIP:TYPE = "rover" { BRAKES ON. } ELSE { 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(255, 79, 0). // International orange } ELSE IF priority = "WARNING" { SET col TO RED. } HUDTEXT("kOS: " + message, 2, 2, 30, col, FALSE). } FUNCTION ON_DRIVE { PARAMETER n, vol. SWITCH TO vol. LIST FILES IN allFiles. FOR f IN allFiles { IF f:NAME = n { SWITCH TO 1. RETURN TRUE. } } SWITCH TO 1. RETURN FALSE. } FUNCTION DELAY { SET ksc TO LATLNG(-0.131331503391266, -74.594841003418). SET dTime TO ksc:DISTANCE / 299792458. // 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 f. DELAY(). IF ON_DRIVE(f, 1) { DELETE f. } IF ON_DRIVE(f, 0) { SWITCH TO 0. COPY f TO 1. SWITCH TO 1. } } // Put a file on KSC FUNCTION UPLOAD { PARAMETER f. DELAY(). IF ON_DRIVE(f, 0) { SWITCH TO 0. DELETE f. SWITCH TO 1. } IF ON_DRIVE(f, 1) { COPY f TO 0. } } // Run a library, downloading it from KSC if necessary FUNCTION REQUIRE { PARAMETER lib. IF NOT ON_DRIVE(lib, 1) { DOWNLOAD(lib). } RENAME lib TO "new_library.ks". RUN new_library. RENAME "new_library.ks" TO lib. } // 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) // If the update script exists on the archive, download and run it. { IF ON_DRIVE("update.ks", 1) // If an old file exists on the archive { NOTIFY("An old update file already exists. Deleting old file...", "ALERT"). WAIT 5. DELETE update.ks. } DOWNLOAD(updateScript). SWITCH TO 0. DELETE updateScript. SWITCH TO 1. // Whichever situation is true, we now have an up-to-date file NOTIFY("Update file found! Executing...", "NOMINAL"). WAIT 5. RENAME updateScript TO "update.ks". RUN update.ks. DELETE update.ks. } ELSE // We don't have an update script, so do nothing. { NOTIFY("No update file found. Either you haven't created one or one is not necessary.", "ALERT"). } // If a startup.ks file exists on the disk, run that. SET bootScript TO SHIP:NAME + ".startup.ks". IF ON_DRIVE(bootScript, 1) { SWITCH TO 1. DELETE bootScript. // If we already have an old startup file, delete it. IF ON_DRIVE(startup.ks, 1) { SWITCH TO 1. DELETE startup.ks. } IF ON_DRIVE(bootScript, 0) { DOWNLOAD(bootScript). RENAME bootScript TO "startup.ks". RUN startup.ks. } ELSE { NOTIFY("Startup failed! Instructions not found.", "WARNING"). WAIT 5. REBOOT. } } ELSE IF ON_DRIVE(bootScript, 0) { IF NOT ON_DRIVE(bootScript, 1) { DOWNLOAD(bootScript). RENAME bootScript TO "startup.ks". RUN startup.ks. DELETE startup.ks. } ELSE { DELETE bootScript. DOWNLOAD(bootScript). RENAME bootScript TO "startup.ks". RUN startup.ks. DELETE startup.ks. } } } ELSE { WAIT UNTIL ADDONS:RT:HASCONNECTION(SHIP). WAIT 5. // Avoid thrashing the CPU (when no startup.ks, but we have a // persistent connection, it will continually reboot) REBOOT. } // Relay rover startup file // Lists the number of active "relay" rovers // and bases its navigation software on that. // Download the appropriate libraries DOWNLOAD(autoNav.ks). // List the active relays LIST TARGETS IN allVessels. SET relays TO LIST(). FOR t IN allVessels { IF t:NAME = "Relay" { relays:ADD(t). } } SET iterationNum TO relays:LENGTH + 1. // Because computers count from 0 IF relays:LENGTH = 0 { SET iterationNum TO 2. } IF iterationNum = 1 { RUN autoNav(0). // Go north } ELSE IF iterationNum = 2 { RUN autoNav(270). // Go west } ELSE IF iterationNum = 3 { RUN autoNav(180). // Go south } ELSE IF iterationNum > 3 // Make it only 1, 2, or 3 { SET iterationNum TO CEILING(MOD(iterationNum, 3)). } ELSE // If we get something weird, just give up. { NOTIFY("Huh...something's gone wrong...", "WARNING"). BRAKES ON. } PARAMETER direct. SWITCH TO 1. DELETE startup.ks. // Do some garbage collection // The loop... Functions are defined below IF ADDONS:RT:HASCONNECTION(SHIP) { UNTIL FALSE { POPULATE(direct). DECIDE_NEXT(options). NOTIFY("Selecting next waypoint.", "NOMINAL"). WAIT 0.5. NOTIFY("Driving to next waypoint", "NOMINAL"). DRIVE_TO(nextPoint). STOP(). WAIT 5. IF NOT ADDONS:RT:HASCONNECTION(SHIP) { BREAK. } } } ELSE { UNTIL FALSE { POPULATE(360 - direct). DECIDE_NEXT(options). NOTIFY("Selecting next waypoint", "NOMINAL"). WAIT 0.5. NOTIFY("Driving to next waypoint", "NOMINAL"). IF nextPoint:DISTANCE > 10 { DRIVE_TO(nextPoint). } STOP(). WAIT 5. IF ADDONS:RT:HASCONNECTION(SHIP) { BREAK. } } } PARK(). SHUTDOWN. FUNCTION POPULATE { PARAMETER hdg. SET offset_90 TO SIN(hdg) * ((360 * 1000) / (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 lat_here TO SHIP:GEOPOSITION:LAT. SET lon_here TO SHIP:GEOPOSITION:LNG. SET op_A TO LATLNG((lat_here + offset_225), (lon_here - offset_675)). // 67.5 deg. left SET op_B TO LATLNG((lat_here + offset_45), (lon_here - offset_45)). // 45 deg. left SET op_C TO LATLNG((lat_here + offset_90), lon_here). // Straight at the heading SET op_D TO LATLNG((lat_here + offset_45), (lon_here + offset_45)). // 45 deg. right SET op_E TO LATLNG((lat_here + offset_225), (lon_here + offset_675)). // 67.5 deg. right 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, 100)). IF slope < 15 { 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 5. // Really stinkin' slow, but safe. // Throttle control variables SET throttlePID TO PIDLOOP(0.5, 0.1, 0.1, -1.0, 1.0). SET throttlePID:SETPOINT TO spd. // Steering control variables SET steerPID TO PIDLOOP((1/360), 0.0001, 0.2, -1.0, 1.0). SET steerPID:SETPOINT TO point:HEADING. CLEARSCREEN. SET thrott TO 0. SET steer TO 0. UNTIL FALSE { IF point:DISTANCE > 10 { SET thrott TO throttlePID:UPDATE(TIME:SECONDS, SHIP:GROUNDSPEED). SET steer TO steerPID:UPDATE(TIME:SECONDS, SHIP:BEARING). LOCK WHEELTHROTTLE TO thrott. SET SHIP:CONTROL:WHEELSTEER TO steer. PRINT " " AT (0,3). PRINT "Current Location: " + ROUND(SHIP:GEOPOSITION:LAT,3) + ", " + ROUND(SHIP:GEOPOSITION:LNG,3) at (0,3). PRINT " " AT (0,4). PRINT "Next waypoint: " + ROUND(point:LAT,3) + ", " + ROUND(point:LNG, 3) AT (0,4). PRINT " " AT (0,9). PRINT "Throttle: " + ROUND(thrott, 3) AT (0,9). PRINT " " AT (0,10). PRINT "Steering: " + ROUND(steer,3) AT (0,10). WAIT 0.01. } ELSE { STOP(). BREAK. } } } FUNCTION STOP { SET WHEELSTEER TO 0. UNLOCK WHEELTHROTTLE. IF NOT BRAKES { BRAKES ON. } UNLOCK WHEELSTEERING. NOTIFY("Arrived!", "NOMINAL"). } FUNCTION PARK { STOP(). LIST PARTS. FOR p IN PARTS { p:GETMODULE("ModuleAnimateGeneric"):DOEVENT("Extend"). p:GETMODULE("ModuleLight"):DOEVENT("Lights on"). } } -
How do I make a rover drive itself intelligently?
MAFman replied to MAFman's topic in KSP1 Mods Discussions
Is there a way to implement the a* search algorithm in kOS, perhaps using kerbalmaps.com? If so, how would I adapt the algorithm to say, "keep navigating until you run out of connection, then navigate backwards until you gain connection."? -
How do I make a rover drive itself intelligently?
MAFman replied to MAFman's topic in KSP1 Mods Discussions
I'm looking for a script that runs on bootup and sets my RemoteTech network up automagically, i.e. without me actually doing anything except hitting launch. The first rover would start at KSC, then drive west until it ran out of connection, then drive east until it had connection again. Every subsequent rover would follow suit, only driving west until the hit ocean, then north until ocean, then south until ocean, you get the idea. -
Given that the spot is oblong like a shadow, is it the shadow of one of Jool's moons?
-
How do I make a rover drive itself intelligently?
MAFman replied to MAFman's topic in KSP1 Mods Discussions
KOS does have information for the ship's position, as well as all kinds of math functions. Also, what exactly is bearing? -
I know I've posted A LOT on this, but I'm getting really frustrated. I want to make a rover using kOS drive in a certain general direction until it can no longer connect to KSC with RemoteTech, then drive the other way until it connects again. I want to do all this while actively avoiding slopes greater than (+ -)10°. How do i do this?
-
[1.3] kOS Scriptable Autopilot System v1.1.3.0
MAFman replied to erendrake's topic in KSP1 Mod Releases
Are there any obvious errors in my code that I missed? The rover is just saying that it's driving, but it "arrives" instantly, and never actually does anything. Boot file: // First, set the ship to a known configuration. SET SHIP:CONTROL:PILOTMAINTHROTTLE TO 0. LIGHTS OFF. GEAR OFF. IF SHIP:NAME = "Relay" { SET SHIP:TYPE TO "rover". } IF SHIP:TYPE = "rover" { BRAKES ON. } ELSE { 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((251/255),(66/255),(0/255)). // Bright orange } ELSE IF priority = "WARNING" { SET col TO RED. } HUDTEXT("kOS: " + message, 2, 2, 30, col, FALSE). } FUNCTION ON_DRIVE { PARAMETER n, vol. SWITCH TO vol. LIST FILES IN allFiles. FOR f IN allFiles { IF f:NAME = n { SWITCH TO 1. RETURN TRUE. } } SWITCH TO 1. RETURN FALSE. } FUNCTION DELAY { SET ksc TO LATLNG(-0.131331503391266, -74.594841003418). SET dTime TO ksc:DISTANCE / 299792458. // 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 f. DELAY(). IF ON_DRIVE(f, 1) { DELETE f. } IF ON_DRIVE(f, 0) { SWITCH TO 0. COPY f TO 1. SWITCH TO 1. } } // Put a file on KSC FUNCTION UPLOAD { PARAMETER f. DELAY(). IF ON_DRIVE(f, 0) { SWITCH TO 0. DELETE f. SWITCH TO 1. } IF ON_DRIVE(f, 1) { COPY f TO 0. } } // Run a library, downloading it from KSC if necessary FUNCTION REQUIRE { PARAMETER lib. IF NOT ON_DRIVE(lib, 1) { DOWNLOAD(lib). } RENAME lib TO "new_library.ks". RUN new_library. RENAME "new_library.ks" TO lib. } // 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) // If the update script exists on the archive, download and run it. { IF ON_DRIVE("update.ks", 1) // If an old file exists on the archive { NOTIFY("An old update file already exists. Deleting old file...", "ALERT"). WAIT 5. DELETE update.ks. } DOWNLOAD(updateScript). SWITCH TO 0. DELETE updateScript. SWITCH TO 1. // Whichever situation is true, we now have an up-to-date file NOTIFY("Update file found! Executing...", "NOMINAL"). WAIT 5. RENAME updateScript TO "update.ks". RUN update.ks. DELETE update.ks. } ELSE // We don't have an update script, so do nothing. { NOTIFY("No update file found. Either you haven't created one or one is not necessary.", "ALERT"). } // If a startup.ks file exists on the disk, run that. SET bootScript TO SHIP:NAME + ".startup.ks". IF ON_DRIVE(bootScript, 1) { SWITCH TO 1. DELETE bootScript. // If we already have an old startup file, delete it. IF ON_DRIVE(startup.ks, 1) { SWITCH TO 1. DELETE startup.ks. } IF ON_DRIVE(bootScript, 0) { DOWNLOAD(bootScript). RENAME bootScript TO "startup.ks". RUN startup.ks. } ELSE { NOTIFY("Startup failed! Instructions not found.", "WARNING"). WAIT 5. REBOOT. } } ELSE IF ON_DRIVE(bootScript, 0) { IF NOT ON_DRIVE(bootScript, 1) { DOWNLOAD(bootScript). RENAME bootScript TO "startup.ks". RUN startup.ks. DELETE startup.ks. } ELSE { DELETE bootScript. DOWNLOAD(bootScript). RENAME bootScript TO "startup.ks". RUN startup.ks. DELETE startup.ks. } } } ELSE { WAIT UNTIL ADDONS:RT:HASCONNECTION(SHIP). WAIT 5. // Avoid thrashing the CPU (when no startup.ks, but we have a // persistent connection, it will continually reboot) REBOOT. } Startup file: // Relay rover startup file // Lists the number of active "relay" rovers // and bases its navigation software on that. // Download the appropriate libraries DOWNLOAD(autoNav.ks). // List the active relays LIST TARGETS IN allVessels. SET relays TO LIST(). FOR t IN allVessels { IF t:NAME = "Relay" { relays:ADD(t). } } SET iterationNum TO relays:LENGTH + 1. // Because computers count from 0 IF iterationNum = 1 { RUN autoNav(0). // Go north } ELSE IF iterationNum = 2 { RUN autoNav(270). // Go west } ELSE IF iterationNum = 3 { RUN autoNav(180). // Go south, so we don't drive into the ocean } ELSE IF iterationNum = 4 { RUN autoNav(270). } ELSE IF iterationNum > 4 // Make it only 1, 2, 3, or 4 { SET iterationNum TO CEILING(MOD(iterationNum, 4)). } ELSE // If we get something weird, just give up. { NOTIFY("Huh...something's gone wrong...", "WARNING"). BRAKES ON. } DELETE startup.ks. // Do some garbage collection Navigation file: PARAMETER direct. SWITCH TO 1. DELETE startup. // The loop... Functions are defined below IF ADDONS:RT:HASCONNECTION(SHIP) { UNTIL FALSE { POPULATE(direct). DECIDE_NEXT(options). NOTIFY("Selecting next waypoint.", "NOMINAL"). WAIT 0.5. NOTIFY("Driving to next waypoint", "NOMINAL"). DRIVE_TO(nextPoint). STOP(). WAIT 5. IF NOT ADDONS:RT:HASCONNECTION(SHIP) { BREAK. } } } ELSE { UNTIL FALSE { POPULATE(360 - direct). DECIDE_NEXT(options). NOTIFY("Selecting next waypoint", "NOMINAL"). WAIT 0.5. NOTIFY("Driving to next waypoint", "NOMINAL"). IF nextPoint:DISTANCE > 10 { DRIVE_TO(nextPoint). } STOP(). WAIT 5. IF ADDONS:RT:HASCONNECTION(SHIP) { BREAK. } } } PARK(). FUNCTION POPULATE { PARAMETER hdg. SET offset_90 TO SIN(hdg) * ((360 * 1000) / (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 lat_here TO SHIP:GEOPOSITION:LAT. SET lon_here TO SHIP:GEOPOSITION:LNG. SET op_A TO LATLNG((lat_here + offset_225), (lon_here - offset_675)). SET op_B TO LATLNG((lat_here + offset_45), (lon_here - offset_45)). SET op_C TO LATLNG((lat_here + offset_90), lon_here). SET op_D TO LATLNG((lat_here + offset_45), (lon_here + offset_45)). SET op_E TO LATLNG((lat_here + offset_225), (lon_here + 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, 100)). IF slope < 15 { 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 FALSE { IF point:DISTANCE > 10 { 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. } ELSE { STOP(). BREAK. } } } FUNCTION STOP { SET WHEELSTEER TO 0. UNLOCK WHEELTHROTTLE. IF NOT BRAKES { BRAKES ON. } UNLOCK WHEELSTEERING. NOTIFY("Arrived!", "NOMINAL"). } FUNCTION PARK { STOP(). LIST PARTS. FOR p IN PARTS { p:GETMODULE("ModuleAnimateGeneric"):DOEVENT("Extend"). p:GETMODULE("ModuleLight"):DOEVENT("Lights on"). } SWITCH TO 1. DELETE autoNav. } -
For using a PIDLOOP() to control the steering and throttle, what settings for kP, kI, and kD are recommended?
-
I definitely could make a ton of use out of this, and perhaps I can edit this to actually work with my algorithm.
-
[1.3] kOS Scriptable Autopilot System v1.1.3.0
MAFman replied to erendrake's topic in KSP1 Mod Releases
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(). -
[1.3] kOS Scriptable Autopilot System v1.1.3.0
MAFman replied to erendrake's topic in KSP1 Mod Releases
What folder in GitHub is the Program-Builder in? -
[1.3] kOS Scriptable Autopilot System v1.1.3.0
MAFman replied to erendrake's topic in KSP1 Mod Releases
I'd be super excited for a new patch version! I think I'll wait until the official release. 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. -
[1.3] kOS Scriptable Autopilot System v1.1.3.0
MAFman replied to erendrake's topic in KSP1 Mod Releases
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)? -
[1.3] kOS Scriptable Autopilot System v1.1.3.0
MAFman replied to erendrake's topic in KSP1 Mod Releases
Ok, here's the log file... I finally found it... (at least the part with the kOS error.) [LOG 19:10:59.261] kOS: FlightCtrlParam: Enabled: throttle False => False [LOG 19:10:59.261] kOS: FlightCtrlParam: Enabled: steering False => False [LOG 19:10:59.262] kOS: FlightCtrlParam: Enabled: wheelthrottle False => False [LOG 19:10:59.263] kOS: FlightCtrlParam: Enabled: wheelsteering False => False [LOG 19:10:59.263] kOS: FlightControl Unbinding [LOG 19:10:59.264] kOS: FlightControl Unbound [LOG 19:10:59.265] kOS: Pushing context staring with: File Line:Col IP label opcode operand [LOG 19:10:59.266] kOS: Saving and removing 9 pointers [LOG 19:10:59.271] kOS: FlightControlManager.AddTo 45e59b2a-16bb-4de8-9909-bd98dd240abb [LOG 19:10:59.271] kOS: FlightCtrlParam: Enabled: throttle False => False [LOG 19:10:59.272] kOS: FlightCtrlParam: Enabled: steering False => False [LOG 19:10:59.273] kOS: FlightCtrlParam: Enabled: wheelthrottle False => False [LOG 19:10:59.274] kOS: FlightCtrlParam: Enabled: wheelsteering False => False [LOG 19:10:59.276] kOS: Pushing context staring with: File Line:Col IP label opcode operand [LOG 19:10:59.276] kOS: Saving and removing 0 pointers [LOG 19:10:59.545] kOS: FlightControl Binding [LOG 19:10:59.546] kOS: FlightControl Bound [LOG 19:10:59.579] kOS: FunctionCopy: Volume: 0 Direction: from Filename: startup.ks [LOG 19:10:59.591] kOS: FunctionCopy: Volume: 0 Direction: from Filename: autonavinit.ks [LOG 19:10:59.602] kOS: FunctionCopy: Volume: 0 Direction: from Filename: autonaviterate.ks [LOG 19:10:59.953] Updating vessel voxel for Relay [LOG 19:11:00.182] Std dev for smoothing: 3 voxel total vol: 40.614487677163 filled vol: 3.44612579691208 [LOG 19:11:01.574] Updating vessel voxel for Relay [LOG 19:11:01.797] Std dev for smoothing: 3 voxel total vol: 40.614487677163 filled vol: 3.44612579691208 [LOG 19:11:03.243] Updating vessel voxel for Relay [LOG 19:11:03.418] Std dev for smoothing: 3 voxel total vol: 40.614487677163 filled vol: 3.44612579691208 [LOG 19:11:11.258] kOS: At autonavinit.ks on 1, line 10 RUN autoNavIterate(goalHeading). ^ Called from startup.ks on 1, line 3 RUN autoNavInit(270). ^ Called from boot.ks on archive, line 124 RUN startup.ks. ^ Called from sys:boot, line 1 (Can't show source line) ^ [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 (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 19:11:11.265] Code Fragment File Line:Col IP label opcode operand ==== ====:=== ==== ================================ 1/startup.ks 3:17 0556 @0552 push 270 1/startup.ks 3:17 0557 @0553 call 526 1/startup.ks 3:17 0558 @0554 pop 0:0 0559 push 0 0:0 0560 return 0 deep 1/autonavinit.ks 10:1 0561 @0555 push $program-autonaviterate* 1/autonavinit.ks 10:1 0562 @0556 exists 1/autonavinit.ks 10:1 0563 @0557 br.false +4 1/autonavinit.ks 10:1 0564 @0558 br.false +11 1/autonavinit.ks 10:1 0565 @0559 push 0 1/autonavinit.ks 10:1 0566 @0560 return 0 deep 1/autonavinit.ks 10:1 0567 @0561 pop 1/autonavinit.ks 10:1 0568 @0562 push $program-autonaviterate* 1/autonavinit.ks 10:1 0569 @0563 push _KOSArgMarker_ 1/autonavinit.ks 10:1 0570 @0564 push autonaviterate 1/autonavinit.ks 10:1 0571 @0565 push null 1/autonavinit.ks 10:1 0572 @0566 call load() <<--INSTRUCTION POINTER-- 1/autonavinit.ks 10:1 0573 @0567 pop 1/autonavinit.ks 10:1 0574 @0568 store 1/autonavinit.ks 10:1 0575 @0569 call $program-autonaviterate* 1/autonavinit.ks 10:1 0576 @0570 pop 1/autonavinit.ks 10:1 0577 @0571 push 0 1/autonavinit.ks 10:1 0578 @0572 return 0 deep 1/autonavinit.ks 1:11 0579 @0573 push goalheading 1/autonavinit.ks 1:11 0580 @0574 swap 1/autonavinit.ks 1:11 0581 @0575 storelocal 1/autonavinit.ks 1:11 0582 @0576 argbottom 1/autonavinit.ks 3:7 0583 @0577 push _KOSArgMarker_ 1/autonavinit.ks 3:8 0584 @0578 push Starting navigation script...Done. 1/autonavinit.ks 3:46 0585 @0579 push NOMINAL 1/autonavinit.ks 3:46 0586 @0580 call $notify* 1/autonavinit.ks 3:46 0587 @0581 pop 1/autonavinit.ks 4:6 0588 @0582 push 5 [LOG 19:11:11.273] kOS: Stack dump: stackPointer = 10 018 SubroutineContext: {CameFromInstPtr 23, TriggerPointer -1} (type: SubroutineContext) 017 SubroutineContext: {CameFromInstPtr 16, TriggerPointer -1} (type: SubroutineContext) 016 kOS.Safe.Execution.VariableScope (type: VariableScope) ScopeId=22, ParentScopeId=0, ParentSkipLevels=1 IsClosure=False 015 SubroutineContext: {CameFromInstPtr 502, TriggerPointer -1} (type: SubroutineContext) 014 SubroutineContext: {CameFromInstPtr 375, TriggerPointer -1} (type: SubroutineContext) 013 SubroutineContext: {CameFromInstPtr 558, TriggerPointer -1} (type: SubroutineContext) 012 SubroutineContext: {CameFromInstPtr 541, TriggerPointer -1} (type: SubroutineContext) 011 SubroutineContext: {CameFromInstPtr 607, TriggerPointer -1} (type: SubroutineContext) 010 SP-> $program-autonaviterate* (type: String) 009 270 (type: Scalar) 008 _KOSArgMarker_ (type: KOSArgMarkerType) 007 _KOSArgMarker_ (type: KOSArgMarkerType) 006 _KOSArgMarker_ (type: KOSArgMarkerType) 005 _KOSArgMarker_ (type: KOSArgMarkerType) 004 _KOSArgMarker_ (type: KOSArgMarkerType) 003 _KOSArgMarker_ (type: KOSArgMarkerType) 002 _KOSArgMarker_ (type: KOSArgMarkerType) 001 _KOSArgMarker_ (type: KOSArgMarkerType) 000 0 (type: Scalar) [LOG 19:11:11.277] kOS: Popping context 2 [LOG 19:11:11.278] kOS: Removed Context File Line:Col IP label opcode operand -
[1.3] kOS Scriptable Autopilot System v1.1.3.0
MAFman replied to erendrake's topic in KSP1 Mod Releases
I totally redid the algorithm. However, I'm still getting that "not in dictionary" error. What am I doing wrong? AutoNavInit.ks: PARAMETER goalHeading. // Navigation variables SET lookAhead TO 10. // Waypoint options will be plotted this far out in all directions SET acceptableSlope TO 10. // The new waypoint can have this much relative slope and still be good 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, 5, 2, 30, col, FALSE). } NOTIFY("Starting navigation script...Done.", "NOMINAL"). WAIT 5. NOTIFY("Downloading navigation instructions...Done.", "NOMINAL"). WAIT 5. NOTIFY("Running iterative navigator...", "NOMINAL"). RUN autoNavIterate(goalHeading). AutoNavIterate.ks: // Until the goal has been reached, go through this process. PARAMETER direct. // The loop... Functions are defined below IF ADDONS:RT:HASCONNECTION(SHIP) { 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. } } } ELSE { 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. } } } PARK(). 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 * lookAhead) / (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 < acceptableSlope { 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(). LIST PARTS. FOR p IN PARTS { p:GETMODULE("ModuleAnimateGeneric"):DOEVENT("Extend"). p:GETMODULE("ModuleLight"):DOEVENT("Lights on"). } } -
[1.3] kOS Scriptable Autopilot System v1.1.3.0
MAFman replied to erendrake's topic in KSP1 Mod Releases
Hmmm... Ok, now the driving works, but the navigation is behaving badly. It appears to want to drive straight south... How do I say, "Ok, go to the local radio horizon at this heading."? -
[1.3] kOS Scriptable Autopilot System v1.1.3.0
MAFman replied to erendrake's topic in KSP1 Mod Releases
It no longer complains when I try the command RUN autonav(1000,270), but now it just does nothing at all. PARAMETER goalDistance, goalHeading. // Navigation variables SET lookAhead TO 100. // Waypoint options will be plotted this far out in all directions SET acceptableSlope TO 15. // The new waypoint can have this much relative slope and still be good SET acceptableBearingDiff TO 60. // The new waypoint can be this far off the goal and still be good // Initialize the navigation by setting a geo-point goal SET startPosition TO LATLNG(SHIP:GEOPOSITION:LAT, SHIP:GEOPOSITION:LNG). SET goalOffset TO (360 * goalDistance) / (BODY:RADIUS * 2 * CONSTANT:PI). SET goalLatOff TO goalOffset * SIN(goalHeading). SET goalLonOff TO goalOffset * COS(goalHeading). SET goal TO LATLNG(startPosition:LAT + goalLatOff, startPosition:LNG + goalLonOff). RUN autoNavIterate(goal).