Jump to content

MAFman

Members
  • Posts

    328
  • Joined

  • Last visited

Everything posted by MAFman

  1. I found a potential bug in kOS, where I try to create a maneuver node from a list of four values, and it returns the error "Cannot iterate on an object of type kOS.Safe.Encapsulation.ScalarIntValue. What's going on?
  2. I can get the orbital period of the current orbit and the transfer directly from the game. What I need help with is how to calculate what longitude I need to start the burn at.
  3. How do I calculate the surface longitude where I start my transfer burn to geostationary altitude, given the surface longitude where I want my satellite to end up, my current altitude and orbital period, and my current longitude? I'm trying to write a kOS program that puts a satellite into a precise-ish slot in geostationary orbit. My probe is powered by a single ion engine and has a wet mass of 1.726 tonnes.
  4. I'm trying to revive someone else's kOS code for rover pathfinding using A*, but their code is so messy I can't make heads or tails of it. Can someone help me? The Reddit post featuring the code is here:
  5. I'm trying to write a general one size fits all launch script based around Powered Explicit Guidance, but the math is way over my head, and I'm not quite patient enough to write all those formulas... Can someone help me develop this? I want the final product to be able to pilot a ship from the launch pad to an orbit defined by apoapsis. periapsis, inclination, longitude of ascending node, and argument of periapsis, with the first two being the only mandatory arguments. I am using a heavily modified (mostly trimmed) variant of Seth Persigehl's launch script for the in-atmospheric flight, including open loop pitch control and open loop heading control. PEG will kick in once the second stage starts, and the rocket's engine will not shutdown or throttle significantly until cutoff - the rocket will make orbit in one long burn.
  6. Is there a way to edit BV so that it drives my rover while I have it active, not just when I'm looking at it from the tracking station? Currently, when I tell it to go somewhere, and switch to the 'roving' rover, it just sits there with controls locked...Also, I found the pathfinding doesn't actually mark any of the tiles as unwalkable, leading to the rover going over mountains and through the ocean...
  7. PizzaOverHead, if you're still having issues with gimbal lock comma I would suggest using quaternions. While more complicated, as they make full use of the imaginary number syste, using quaternions instead of Euler angles almost completely eliminates gimbal lock. Can you share the Github link? I want to see if I can help.
  8. I was thinking of pulling a heightmap directly from the game and using A* to search through it, using the brightness per pixel (height) and the change in altitude over the change in coordinates as a heuristic, as well as arbitrarily assigning infinite cost to points in the ocean. Currently, I have the HeightMapExtractor mod working on pulling a 32K heightmap (which it's been working on for the last two days...).
  9. KerbalMaps is up again!!! http://www.kerbalmaps.com/ Say, does anyone have ideas how I could use KerbalMaps to navigate a rover autonomously with an A* search? I'd need the data to be accurate to within 10 meters so the rover can avoid cliffs and the ocean...
  10. I'm trying to make a tool that takes two geocoordinates as input and spits out the shortest and safest path between the two (as a queue of points from the end to the start) kinda like GPS routing. How do I do that?
  11. Turns out the culprit WAS RemoteTech...I wonder if I could download the source code, make some changes, and push it to the master branch...
  12. IDK whether this counts as a bug report or just a help-me, but I've been having an issue lately with the escape and mapview keys. Whenever I hit "escape" to pause the game, it doesn't pause, but instead completely freezes the camera and locks all controls. When I enter Task Manager, everything looks absolutely normal. Something similar happens when I try to go to the map, but in addition to locking everything up, it also completely breaks the map and ship view, replacing the camera with a weird, Jello-like blob that vaguely resembles Kerbin - and I can't cancel the map view unless I hit Ctrl-Alt-Delete and click "End Task" on the KSP process... I found a possible solution. In the KSP.log file, I found that RemoteTech2 was absolutely spamming the crap out of everything with "I'm connected - no wait, I'm not...no wait...etc..." messages. Is there a method to disable this?
  13. Is there a way to just hack-unlock all the levels?
  14. Sorry if I'm necro-posting, but I'm working on a rover navigation / SLAM library. Does my code make sense? BTW, lib_circle_nav is from KSLib. @lazyglobal off. import("lib_circle_nav"). // lib_a_star.ks finds the shortest path from a start node to a target node. // Due to the nature of the algorithm, it will also avoid hills and cliffs. // Define what a node is first. function worldNode{ parameter gridX, gridY. // Example: worldNode(5, 10) gives me a point 5 grid marks to the right of the ship, and 10 marks forward. local d is 2 * planet:radius. local c is constant:pi * d. local offset is (50 * 360) / c. // The nodes are 50 meters apart. local nodeX is offset * gridX. local nodeY is offset * gridY. local there is circle_destination(circle_destination(offset, 90, body:radius), offset, 0, body:radius). return lex("X", nodeX, "Y", nodeY, "alt", there:terrainheight, "gCost", gCost(), "hCost", hCost(), "fCost", (gCost() + hCost())). } // Then create the grid. function grid local _height is 10. local _width is 19. local spacing is 50. local startPoint is ship:geoposition. // Center the grid on the ship local _grid is list(). for {local i is (-_height / 2).}{until i >= (_height / 2)}do{ for{local j is (-_width / 2).}{until j >= (_width / 2)}do{ _grid:add(worldNode(i, j)). } } return _grid. } function endNode{ parameter grid. for n in grid{ // Pick the node on the far side of the grid with the lowest line-of-sight slope to the current node. } } function gCost{ parameter start is worldNode(0, 0), thisNode. // 3D Pythagoras: Distance^2 = deltaX^2 + deltaY^2 + deltaZ^2. return sqrt((thisNode["X"] - start["X"])^2 + (thisNode["X"] - start["X"])^2 + (thisNode["alt"] - start["alt"])^2). } function hCost{ parameter thisNode, end. // 3D Pythagoras: Distance^2 = deltaX^2 + deltaY^2 + deltaZ^2. return sqrt((thisNode["X"] - end["X"])^2 + (thisNode["X"] - end["X"])^2 + (thisNode["alt"] - end["alt"])^2). } function fCost{ parameter start is worldNode(0, 0), thisNode, endNode. return gCost(thisNode) + hCost(thisNode, end). } // The actual pathfinding algorithm function pathfinding{ parameter endNode, grid is localGrid() startNode is worldNode(0, 0). local openList is list(). local closedList is list(). local path is list(). return path. } function driveTo{ parameter point. }
  15. WOOHOO!! XD So, would I need infernal robotics to make lidar units that I've seen on robots such as the Neato?
  16. Is it possible to use this mod for, for example, LIDAR or SLAM-based navigation?
  17. Is it possible or feasible to use this as a crude LIDAR syste for, example, SLAM / navigation?
  18. // Ground navigation library import("lib_enum.ks"). import("lib_circle_nav.ks"). function aStarSearch{ // Will include multiple sub-functions parameter hdg. // Runs all at once, returning a path. global costS is 10. global costD is 14. createGrid(). set startPoint to startPoint(). set currentPoint to grid[startPoint:index]. set path to list(). until reachedGoal(){ // Set the current point as the parent set parentPoint to currentPoint. local childPoints is list(). // Assign eight child points from the existing grid: // 1 | 2 | 3 // ----+---------------+----- // 4 | (parent) | 5 // ----+---------------+----- // 6 | 7 | 8 // Calculate the g-, h-, and f-costs for each child for c in childPoints { gCost(c, parentPoint). hCost(c). fCost(c). } // Set the point with the lowest f-cost as the parent and add it to the path path:add(lowestFCostPoint()). set currentPoint to lowestFCostPoint(). // Rinse and repeat } return path. } function lowestFCostPoint { return . // The point whose fCost is the minimum of all points } function createGrid{ global startPoint is currentPoint(). global spacing is 25. // 25 meters apart local _height is 64. // 64 points vertically local _width is 64 // 64 points horizontally local start is 0 local iterationNum_x is 0. local iterationNum_y is 0. // Total points: 4,096 // Total height and width: 1,600 m (approx. 1 mile - total coincidence!) // Total grid area: 2,560,000 sq. m. (about 1 square mile) set grid to list(). until iterationNum_y >= _height{ until iterationNum_x >= _width{ // work on the rows first grid:add(point((start * iterationNum_x), (start * iterationNum_y), startPoint)). set iterationNum_x to iterationNum + 1. // Start a new column } grid:add(point((start * iterationNum_x), (start * iterationNum_y), startPoint)). set iterationNum_y to iterationNum_y + 1. // Start a new row } return grid. // Hopefully kOS has enough memory! (I hope my COMPUTER has enough memory!) } function reachedGoal{ parameter endPoint is endPoint(), currentPoint is currentPoint(). if currentPoint["fCost"] = 0{ return true. }else{ return false. } } function currentPoint{ // Runs every loop local here is ship:geoposition. local currentPoint is point(here:lat, here:lng). return currentpoint. } function endpoint{ local endPoint is point(). // Figures out which point is on the opposite side of the grid, with the lowest slope of points surrounding it // Runs at the same time as startpoint(). local endPoint["x"] is _width - startPoint["x"]. local endPoint["y"] is _height - startPoint["y"]. return endPoint. } function fCost{ parameter point. set point["fCost"] to point["gCost"] + point["hCost"]. } function gCost{ parameter point, start is startPoint(). set point["gCost"] to cost(start, point). } function hCost{ parameter point, end is endPoint(). set point["hCost"] to cost(point, end). } function cost{ parameter p1, p2. // From the point class local deltaX is p2["x"] - p1["x"]. local deltaY is p2["y"] - p1["y"]. local costX is deltaX * costS. local costY is deltaY * costS. local isDiagonal is false. if (deltaX and deltaY) <> 0 set isDiagonal to true. // If the point is directly diagonal, draw a diagonal line between the points // and return the length of that line times costD. local deltaDiag is round(sqrt(deltaX^2 + deltaY^2)). local costDiag is deltaDiag * costD. if isDiagonal{ return costDiag. } // Otherwise, return the sum of costX and costY else return (costX + costY). } function point{ // Poor-man's class // Points are initialized as offset relative to the point (0,0) on the planet parameter dX is 0, dY is 0, reference is latlng(0,0). local _x is (360 * dX) / (body:radius * 2 * constant:pi). local _y is (360 * dY) / (body:radius * 2 * constant:pi). local location is latlng(_x + reference:lat, _y + reference:lng). // *shrug* local _z is location:terrainheight. return lex("x", _x, "y", _y, "z", _z, "gCost", 0, "hCost", 0, "fCost", 0). } I have no idea what I'm doing...
  19. 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?
  20. 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.
  21. Ok! I did find a one-size-fits-all satellite launching script!
  22. 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.
  23. 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"). } } } }
  24. 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().
×
×
  • Create New...