Jump to content

[1.3] kOS Scriptable Autopilot System v1.1.3.0


erendrake

Recommended Posts

Ok... so... I may have accidentally broken kOS. I think the 3600x1800 array may be partially responsible:blush:. (just a quick note to Steve and Erendrake I am not asking for a fix it's just a horrifyingly inefficient script & thank-you for the awesome mod).

I don't know if this works yet (the script is still running) and there is still some bits that need adding. Also I have already started working on a re-write of it.

Anyway here it is:

A kOS version of Dijkstra's path-finding algorithm:). It is intended to produce a way-point list that will take a rover to its target destination avoiding water and rough terrain.

Note: if you try to run this i suggest wacking the IPU up to 2000 and leaving it running over night. It is a very brute force approach and the current settings have the equatorial vertices spaced around 1km(they get denser nearer the polls) and samples the terrain every 5m along its projected route.

EDIT: changed settings after leaving it running over night ksp was using ~20Gb or Ram and had slowed down masively as it was running in swap.:rolleyes:

EDIT2: This now runs!!! The sample rate is low(ish) and the cost for change in terrain height needs balancing but it runs:D.

The main script.


clearscreen.
set slat to ship:latitude. //start lat.
set slng to ship:longitude. //start lng.
if slng < 0 {
set slng to (slng+360).
}.

set flat to -90. //finish lat.
set flng to 0. //finish lng.
if flng < 0 {
set flng to (flng+360).
}.

if body = kerbin or body = eve or body = laythe {
set water to 1.
}
else {
set water to 0.
}.

Set dx to 1.
set dy to 1.
set samplerate to 100.
set slopefactor to 1.
set traversefactor to 1. //not yet used

//=====Vertex info list=======
// 0 - geolocation.
// 1 - checked connections.
// 2 - grid pos x
// 3 - grid pos y
// 4 - vertex cost.
// 5 - x of previous vertex in shortest path.
// 6 - y of previous vertex in shortest path.


//====Set up grid sphere======= This will be replaced with a cube projection when i get round to it.
set grid to list(). //x coordinate on grid
set x to 0.
set y to -90.
until x = 360 {
grid:add(list()). //y coordiante on grid
until y > 90-dy {
set y to round(y+dy,1). //rounding to remove floating point error that creeps in (dont know how it gets there)
grid[grid:length-1]:add(list()). //vertex info
grid[grid:length-1][grid[grid:length-1]:length-1]:add(latlng(y,x)).
grid[grid:length-1][grid[grid:length-1]:length-1]:add(0).
grid[grid:length-1][grid[grid:length-1]:length-1]:add((grid:length-1)).
grid[grid:length-1][grid[grid:length-1]:length-1]:add((grid[grid:length-1]:length-1)).
}.
set y to -90.
set x to x + dx.
}.
Print "Grid setup complete.".
//==============================

//=====Set up start/finish======
set start to list().
start:add(latlng(slat,slng)).
start:add(0).
start:add(-1).
start:add(-1).

set finish to list().
finish:add(latlng(flat,flng)).
finish:add(0).
finish:add(-2).
finish:add(-2).
finish:add(0).
//==============================

//==Set up neighbors / visited==
set neighbors to list().
set visited to list().
//visited:add(start).
visited:add(finish).
if finish[0]:lat < (dy - 90) {
set pos to 0.
until pos >= grid:length-1 {
neighbors:add(grid[pos][0]).
set pos to pos +1.
}.
}
else if finish[0]:lat > (90 - dy) {
set pos to 0.
until pos >= grid:length -1 {
neighbors:add(grid[pos:index][grid[pos]:length - 1]).
set pos to pos +1.
}.
}
else {
set x to floor(finish[0]:lng)/dx.
set y to (floor(finish[0]:lat)+90) / dy.
neighbors:add(grid[x][y]).
neighbors:add(grid[x+1][y]).
neighbors:add(grid[x+1][y+1]).
neighbors:add(grid[x][y+1]).
}.
neighbors:add(start).
//==============================

//======Pathfinding=============
set activeVertex to finish.

until activeVertex = start {
Print "Checking vertex at" +activeVertex[0].

//calculate weighting.
for vertex in neighbors {
if vertex[0]:terrainheight < 0 and water = 1 {
set vertex[1] to 8.
}
else {
set cost to 0.
set swimming to false.
run gs_distance(activevertex[0],vertex[0],body:radius).
set gsdist to result.
print "Distance to "+vertex[0]+" is "+gsdist.
// log "Distance to "+vertex[0]+" is "+gsdist to debug.
set floorgsdist to floor(gsdist/samplerate).
set count to 0.
set p1 to activevertex[0].
until count >= floorgsdist or swimming = true {
run gs_bearing(p1,vertex[0]).
set gsbear to result.
run gs_destination(p1,gsbear,samplerate,body:radius).
set p2 to result.
if p2:terrainheight < 0 {
set swimming to true.
print "Can't cross water at "+p2.
}
else {
set cost to cost + samplerate + (slopefactor*abs(p1:terrainheight-p2:terrainheight)/samplerate).
}.
set p1 to p2.
set count to count + 1.
}.
if swimming = false {
run gs_distance(p1,vertex[0],body:radius).
set gsdist to result.
set cost to cost + gsdist + (slopefactor*abs(p1:terrainheight-vertex[0]:terrainheight)/gsdist).
if vertex:length < 5 {
set vertex[1] to vertex[1]+1.
vertex:add(activevertex[4]+cost).
vertex:add(activevertex[2]).
vertex:add(activevertex[3]).
visited:add(vertex).

}
else if activevertex[4]+cost < vertex[4] {
set vertex[1] to vertex[1]+1.
set vertex[4] to activevertex[4]+cost.
set vertex[5] to activevertex[2].
set vertex[6] to activevertex[3].
}
else {
set vertex[1] to vertex[1]+1.
}.
}
else {
set vertex[1] to vertex[1]+1.
}.
if vertex[2] = -1 {
set start to vertex.
}
else {
set x to vertex[2].
set y to vertex[3].
set grid[x][y] to vertex.
}.
}.
}.
print "remove active vertex from visited list".
set pos to 0.
until pos = visited:length {
// print "checking visited["+pos+"]".
if visited[pos] = activevertex {
visited:remove(pos).
set pos to visited:length-1.
}.
set pos to pos+1.
}.

print "select new active vertex".
set activevertex to visited[0].
for vertex in visited {
if vertex[4] < activevertex[4] {
set activevertex to vertex.
}.
}.
if activevertex = start {}
else {

print "create new neighbors list".
set neighbors to list().
neighbors:add(start).
set nx to -1.
until nx > 1 {
set ny to -1.
until ny > 1 {
set vx to activevertex[2]+nx.
if vx < 0 {
set vx to grid:length-1.
}
else if vx > grid:length-1 {
set vx to 0.
}.
set vy to activevertex[3]+ny.
if vy < 0 or vy > grid[activevertex[2]]:length-1 {
set vy to activevertex[3].
if vx < grid:length / 2 {
set vx to vx + (grid:length / 2).
}
else {
set vx to vx - (grid:length / 2).
}.
}.
if grid[vx][vy][1] < 8 {
neighbors:add(grid[vx][vy]).
}.
set ny to ny + 1.
}.
set nx to nx + 1.
}.
print "remove active vertex from neighbors".
set pos to 0.
until pos = neighbors:length {
// print "checking neighbors["+pos+"]".
if neighbors[pos] = activevertex {
neighbors:remove(pos).
set pos to neighbors:length-1.
}.
set pos to pos+1.
}.
}.
}.
print "rout calculated".
//==============================

//=====Save waypoint list=======
set rout to list().
set activevertex to start.
Until activevertex = finish {
if activevertex[5] = -2 {
set activevertex to finish.
}
else {
set activevertex to grid[activevertex[5]][activevertex[6]].
}.
rout:add(activevertex[0]).
}.
Log rout to waypoints.
//any angle smoothing pass
//==============================


//====Driving===================

Dependancys - these are useful for other stuff too.


// Name this "gs_bearing.ks"
// This will give you the bearing (at point 1) for the great circle path from point 1 to point 2.
declare parameter p1,p2.
set result to arctan2(sin(p2:lng-p1:lng)*cos(p2:lat),cos(p1:lat)*sin(p2:lat)-sin(p1:lat)*cos(p2:lat)*cos(p2:lng-p1:lng)).


// Name this "gs_distance.ks"
// This will give you the great circle distance between point 1 and 2.
declare parameter p1, p2, radius. //(point1,point2,radius(planet/moon)).
set resultA to sin((p1:lat-p2:lat)/2)^2 + cos(p1:lat)*cos(p2:lat)*sin((p1:lng-p2:lng)/2)^2.
set result to radius*constant():PI*arctan2(sqrt(resultA),sqrt(1-resultA))/90.


// Name this "gs_destination.ks"
// This will give you a destination given a start point, the distance you travel and the initial bearing (assuming you are traveling along a great circle path)
declare parameter p1, b, d, radius. //(start point,bearing,distance,radius(planet/moon)).
set resultA to (d*180)/(radius*constant():pi).
set resultB to arcsin(sin(p1:lat)*cos(resultA)+cos(p1:lat)*sin(resultA)*cos().
set resultC to p1:lng+arctan2(sin(*sin(resultA)*cos(p1:lat),cos(resultA)-sin(p1:lat)*sin(resultB)).
set result to latlng(resultB,resultC).

Edited by TDW
Code change
Link to comment
Share on other sites

Tried using both 0.16.0 and 0.16.2 in KSP 0.90 and in the VAB there is no option to open terminal. The kOS button on the toolbar only states "No loaded CPUs found"

I can open the terminal once the vehicle is launched.

Am I missing something here? Any known conflicts with other mods? Dependencies?

Suggestions will be appreciated.

Link to comment
Share on other sites

Tried using both 0.16.0 and 0.16.2 in KSP 0.90 and in the VAB there is no option to open terminal. The kOS button on the toolbar only states "No loaded CPUs found"

I can open the terminal once the vehicle is launched.

That's the way the mod behaves. Time is sort of 'stuck' in the editor, which would make many of the things the mod does be very messy and screwed up (like reading your velocity when the clock isn't going). Rather than try to make exception cases around all of that, the mod is just disabled on parts that are still in the editor and not fully "real" yet.

Link to comment
Share on other sites

Hi !

I'm building a new KSP install and I just discovered this mod so I wanted to give it a try.

I built a rocket with the core scripting module on it, and launched it. But the "Open terminal" button never showed up.

Right now I have those mods installed:

* Stage Recovery 1.5.3

* Flight Manager for Reusable Stages 0.3.02

* B9 Aerospace R5.2.8

* Kerbal Alarm Clock 3.2.3.0

* Kerbal Engineer Redux 0.6.2.12

* kOS: Scriptable Autopilot System 0.16.2 (tried with 0.16.0 for the same result)

* KW Rocketry 2.6d2

* Ferram Aerospace Reseasrch 0.14.6

The game is the last update Steam downloaded.

Any help ?

Link to comment
Share on other sites

Hi !

I'm building a new KSP install and I just discovered this mod so I wanted to give it a try.

I built a rocket with the core scripting module on it, and launched it. But the "Open terminal" button never showed up.

Right now I have those mods installed:

* Stage Recovery 1.5.3

* Flight Manager for Reusable Stages 0.3.02

* B9 Aerospace R5.2.8

* Kerbal Alarm Clock 3.2.3.0

* Kerbal Engineer Redux 0.6.2.12

* kOS: Scriptable Autopilot System 0.16.2 (tried with 0.16.0 for the same result)

* KW Rocketry 2.6d2

* Ferram Aerospace Reseasrch 0.14.6

The game is the last update Steam downloaded.

Any help ?

Can you show a screenshot with the part menu open? And scan the output log for the word "kOS" and see if there's any exception messages.

Link to comment
Share on other sites

1425799851-scs-vab.png

1425799845-scs-on-flight.png

(Yes, I clicked on it AFTER I pressed space)

And about the log:

Load(Assembly): kOS/Plugins/ICSharpCode.SharpZipLibAssemblyLoader: Loading assembly at C:\Program Files (x86)\Steam\SteamApps\common\Kerbal Space Program\GameData\kOS\Plugins\ICSharpCode.SharpZipLib.dll

Load(Assembly): kOS/Plugins/kOS

AssemblyLoader: Loading assembly at C:\Program Files (x86)\Steam\SteamApps\common\Kerbal Space Program\GameData\kOS\Plugins\kOS.dll

AssemblyLoader: KSPAssembly 'kOS' V0.16

Load(Assembly): kOS/Plugins/kOS.Safe

AssemblyLoader: Loading assembly at C:\Program Files (x86)\Steam\SteamApps\common\Kerbal Space Program\GameData\kOS\Plugins\kOS.Safe.dll

Non platform assembly: C:\Program Files (x86)\Steam\SteamApps\common\Kerbal Space Program\GameData\kOS\Plugins\ICSharpCode.SharpZipLib.dll (this message is harmless)

Non platform assembly: C:\Program Files (x86)\Steam\SteamApps\common\Kerbal Space Program\GameData\kOS\Plugins\kOS.dll (this message is harmless)

Non platform assembly: C:\Program Files (x86)\Steam\SteamApps\common\Kerbal Space Program\GameData\kOS\Plugins\kOS.Safe.dll (this message is harmless)

AssemblyLoader: Exception loading 'kOS': System.Reflection.ReflectionTypeLoadException: The classes in the module cannot be loaded.

System.TypeLoadException: Could not load type 'kOS.Suffixed.WaypointValue' from assembly 'kOS, Version=0.16.2.0, Culture=neutral, PublicKeyToken=null'.

Load(Texture): kOS/Flags/kOS-Logo

Load(Texture): kOS/GFX/FontFinder

Load(Texture): kOS/GFX/font_sml

Load(Texture): kOS/GFX/launcher-button

Load(Texture): kOS/GFX/monitor_launch

Load(Texture): kOS/GFX/monitor_minimal

Load(Texture): kOS/GFX/network-zigzag

Load(Texture): kOS/GFX/resize-button

Load(Texture): kOS/GFX/terminal-icon-closed-telnet

Load(Texture): kOS/GFX/terminal-icon-closed

Load(Texture): kOS/GFX/terminal-icon-open-telnet

Load(Texture): kOS/GFX/terminal-icon-open

Load(Texture): kOS/Parts/kOSMachine0m/KR-2042_uv_layout_1_d_NRM

Load(Texture): kOS/Parts/kOSMachine0m/KR-2042_uv_layout_1_EMIS

Load(Texture): kOS/Parts/kOSMachine0m/KR-2042_uv_layout_d

Load(Texture): kOS/Parts/kOSMachine1m/model000

Load(Texture): kOS/Parts/kOSMachine1m/model001

Load(Texture): Squad/Parts/FuelTank/fuelTankOscarB/model000

Load(Texture): Squad/Parts/FuelTank/fuelTankOscarB/model001

Load(Model): kOS/Parts/kOSMachine0m/model

Load(Model): kOS/Parts/kOSMachine1m/model

Load(Model): Squad/Parts/FuelTank/fuelTankOscarB/model

Config(@PART

[*]:FOR[kOS]) kOS/kOS-module-manager/@PART

[*]:FOR[kOS]

Config(PART) kOS/Parts/kOSMachine0m/part/kOSMachine0m

Config(PART) kOS/Parts/kOSMachine1m/part/kOSMachine1m

Config(PART) Squad/Parts/FuelTank/fuelTankOscarB/fuelTankOscarB/miniFuelTank

Cannot find a PartModule of typename 'KOSNameTag'

Cannot find a PartModule of typename 'KOSNameTag'

Cannot find a PartModule of typename 'KOSNameTag'

Cannot find a PartModule of typename 'KOSNameTag'

Cannot find a PartModule of typename 'KOSNameTag'

[...]

Cannot find a PartModule of typename 'KOSNameTag'

Cannot find a PartModule of typename 'KOSNameTag'

Cannot find a PartModule of typename 'KOSNameTag'

Cannot find a PartModule of typename 'KOSNameTag'

Cannot find a PartModule of typename 'KOSNameTag'

PartLoader: Compiling Part 'kOS/Parts/kOSMachine0m/part/kOSMachine0m'

Cannot find a PartModule of typename 'kOSProcessor'

Cannot find a PartModule of typename 'KOSNameTag'

PartLoader: Compiling Part 'kOS/Parts/kOSMachine1m/part/kOSMachine1m'

Cannot find a PartModule of typename 'kOSProcessor'

Cannot find a PartModule of typename 'KOSNameTag'

Cannot find a PartModule of typename 'KOSNameTag'

Cannot find a PartModule of typename 'KOSNameTag'

Cannot find a PartModule of typename 'KOSNameTag'

Cannot find a PartModule of typename 'KOSNameTag'

[...]

Cannot find a PartModule of typename 'KOSNameTag'

Cannot find a PartModule of typename 'KOSNameTag'

Cannot find a PartModule of typename 'KOSNameTag'

Cannot find a PartModule of typename 'KOSNameTag'

Cannot find a PartModule of typename 'KOSNameTag'

PartLoader: Compiling Part 'Squad/Parts/FuelTank/fuelTankOscarB/fuelTankOscarB/miniFuelTank'

Cannot find a PartModule of typename 'KOSNameTag'

Cannot find a PartModule of typename 'KOSNameTag'

Cannot find a PartModule of typename 'KOSNameTag'

Cannot find a PartModule of typename 'KOSNameTag'

Cannot find a PartModule of typename 'KOSNameTag'

[...]

Cannot find a PartModule of typename 'KOSNameTag'

Cannot find a PartModule of typename 'KOSNameTag'

Cannot find a PartModule of typename 'KOSNameTag'

Cannot find a PartModule of typename 'KOSNameTag'

Cannot find a PartModule of typename 'KOSNameTag'

kOSMachine1m(Clone) added to ship - part count: 2

kOSMachine1m(Clone) added to ship - part count: 12

[kOSMachine1m]: Activated

Link to comment
Share on other sites

Ok, got it working...

For the other ones getting the same problem as me: Try on a new install WITHOUT 64bit installed.

I was playing the 32bits game, but I had the 64bit version installed in the same folder, sounds like it was my problem.

Anyway, thank you for your help.

Now I'm gonna try this awesome looking mod :)

Edited by Squall124
Link to comment
Share on other sites

Hi

Does anyone have a kOS script / can think of a method to create (using kOS) a cubed sphere array in ksp?

for those that haven't seen one before a cubed sphere looks like this:

cubed-sphere-grid.jpg

The intention would be to have an array for each face containing the lat-long of each vertex (point where the lines cross) for use in a pathfinding script.

Link to comment
Share on other sites

The intention would be to have an array for each face containing the lat-long of each vertex (point where the lines cross) for use in a pathfinding script.

Is there some reason the algorithm depends on data being pre-stored before it starts? Is there a reason it can't calculate altitude at a given location on the fly when it examines it?

I mean, the probability that the optimal path ends up going all the way around the other side of the world seems pretty remote to me, so why pay the expense of calculating the height map for all those locations the algorithm is unlikely to need to visit?

Link to comment
Share on other sites

Is there some reason the algorithm depends on data being pre-stored before it starts? Is there a reason it can't calculate altitude at a given location on the fly when it examines it?

Edit: the algorithm as it stands does not create a hight map for the entire planet at the start that is calculated on the fly as you suggest, what it does need though is a list of all valid positions on the globe as setting them up on the fly without overlap is trickier.

at the moment the algorithm only pre-stores a list of each vertex containing:

[0] - its latlng() position

[1] - the number of checked connections (initially set to 0)

[2]/[3] - its x/y position on the grid (used for moving it in and out of working lists)

Initially the pre-storing of the data was to overcome the issues with having to backfill the array when going round an obstacle eg. not being able to add data at grid[5][7] when grid[5][4] had not added to the grid. The reason behind arranging the points on a grid this way was that it made finding neighbouring vertices quick as they were the ones surrounding you on the grid, instead of having the program search the entire list to find veracities within a set range. Also if the veracities are created on the fly extra checking needs to be done to avoid adding new ones within a set distance of pre-existing ones.

The future plan for the script is to have it split up into 2 parts with the initial part creating an array/list containing all the vertices and the cost between them and their neighbours (possibly with some any-angle edges thrown in), it would then export this to a file that could be run in the future to load the whole thing back up, without doing any calculation, and then do path-finding on that without ever having to do the cost calculations for that body again.

One advantage of the cubed sphere(other than more uniform distribution) is that it would be that it is fairly simple to set up so it only loads the other faces when they are needed.

Edited by TDW
Link to comment
Share on other sites

Is there a reason the algorithm fails when using a simple cylindrical projection? (Does it end up distorting the path under a false notion of how far apart the points are when closer to the poles?) Maybe the algorithm could be altered to weight the cost of moving to a neighboring vertex based on what latitude it's at. On a cylindrical projection, the farther from the equator you are, the less it costs to move one hop east or west to the next vertex. If that weighting could be added in to the algorithm, you might not need a cubed sphere.

Link to comment
Share on other sites

The algorithm "works" at the moment it's just not very efficient. The cubed sphere should cut down the number of vertices by 1/3 and speed up route calculation around the poles.

The weighting is already calculated based on the great circle distance between the two points along with a terrain modifier calculated by sampling along that path.

Couple of other optimisations that I intend to try are changing the visited list to a sorted list and adding an A* weighting. But I have those sorted (at least in my head). A way of converting between lat-long possitions and cubed sphere positions is what I'm having trouble working out.

It was mostly just a vague hope that someone here had created one before and could supply / suggest a pseudocode algorithm I could use as a starting point.

Link to comment
Share on other sites

Hello again! I've finally finished tutorial #3 featuring rovers. With this script running on a rover the vehicle will automatically reduce steering input the faster it's going, use cruise control, and have a lock steering to heading function. This makes it much more difficult to accidentally flip over. I hope you enjoy it, and if you have any questions please let me know!

Download the exmple code here: https://gist.github.com/KK4TEE/5966971602973c24107f

The control scheme is as follows:


W: Increase target speed
S: Decrease target speed
Brakes: Reset cruise control to 0 and come to a stop.
AG1: Toggle Autopilot
AG2: Set autopilot target to current heading
AG3: Adjust target heading by -0.5 degrees
AG4: Adjust target heading by +0.5 degrees
AG5: Decrease target heading until pressed again
AG6: Increase target heading until pressed again
AG10: End Program

Link to comment
Share on other sites

Yeah, tried a new dropbox app for picture sharing. I think it sucks.

Nice part! I've also written MM config for KAL-9000 part, but yours look more fitting.

Link to comment
Share on other sites

working on an update to my RCS Thrust Controller (latest release is out yay!) to take advantage of the new part modules.

Anyone know if there's a way to get the kN for an RCS thruster? I can't find one. They aren't considered engines.

Also, is there a way to check for a null Declare Parameter? As in allowing people to type run rcsthrustcontroller(0.25). if they want to define a thrust value or just run rcsthrustcontroller. if they want to use tweakable thrust settings.

Any update on RemoteTech integration? Mainly getting signal delay.

Also is there a way to quit out of a program without shutting down the console?

Edited by Gaiiden
Link to comment
Share on other sites

I'd like to be able to launch manually, all the while having a kOS script running while I'm in manual control, and under certain conditions the script overrides the pilot control, killing the throttle, but also leave the throttle down after the script has exited. Is this even possible?

It seems that simply calling

SET SHIP:CONTROL:MAINTHROTTLE TO 0

can't manage that.

Link to comment
Share on other sites

Also is there a way to quit out of a program without shutting down the console?

Control-C in terminal window should terminate running script

- - - Updated - - -

I'd like to be able to launch manually, all the while having a kOS script running while I'm in manual control, and under certain conditions the script overrides the pilot control, killing the throttle, but also leave the throttle down after the script has exited. Is this even possible?

It seems that simply calling

SET SHIP:CONTROL:MAINTHROTTLE TO 0

can't manage that.

Well, it is actually possible if our script does not lock throttle or steering. You can run a script like this on the launchpad


wait until alt:radar > 50000.
print "Cuting throttle".
set ship:control:mainthrottle to 0.

The script will not interfere with your manual controls until the wait condition triggers

Link to comment
Share on other sites

SO this is basically MechJeb, except for the act that you have to tediously program the thing yourself, and the commands you give it are precise and exact, with no flexibility?

...

I like it. I REALLY like it.

Link to comment
Share on other sites

So... what replaced heading(pitch,roll,yaw)? - It still produces a R()otation, but if you try to use it it gives a cast error?

SET Pitch to 90.

SET Roll to -90.

SET Yaw TO 0.

LOCK STEERING TO HEADING(Pitch, Yaw, Roll).

Now gives "cannot cast from source type to destination type. (Cannot show kOS Error Location - error might really be internal. See kOS devs.)"

Link to comment
Share on other sites

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