Jump to content

MechJeb Autom8 Scripts Megathread


r4m0n

Recommended Posts

If your file extensions are hidden by default, then you should now have a filename.lua.txt

Either disable hiding of common file extensions or try right clicking the file and selecting "properties", you should then see the whole file name plus the extension and be able to change it.

Also, .lua is a text file in a sense, the code is in a human readable form, just formatted so the lua interpreter can read it, see here for details.

Link to comment
Share on other sites

Based on further experimentation, here's additional information on the vector based mechjeb.attitudeTo, for those planning to terrify their kerbals during more complex orbital manuevers with Mechjeb's Autom8:


mechjeb.attitudeTo({x,0,0},"ORBIT")
?Where x < 0, NML+
?Where x > 0, NML-
mechjeb.attitudeTo({0,x,0},"ORBIT")
?Where x < 0, RAD- (to body)
?Where x > 0, RAD+ (Away from body)
mechjeb.attitudeTo({0,0,x},"ORBIT")
Where x < 0, RETROGRADE
Where x > 0, DIRECT (PROGRADE)

mechjeb.attitudeTo({x,0,0},"INERTIAL")
?Where x < 0, ??
?Where x > 0, ??
mechjeb.attitudeTo({0,x,0},"INERTIAL")
?Where x < 0, ??
?Where x > 0, ??
mechjeb.attitudeTo({0,0,x},"INERTIAL")
Where x < 0, ??
Where x > 0, ??

Link to comment
Share on other sites

Are all the functions required to automatically rendezvous with another craft available?

Off the top of my head, you'd need a way to do the following:

- [launch or get into] a (preferably) lower orbit, preferably in the same plane, but if not...

- Align planes (matching both LAN and inclination)

- Align lines of apsides (make apoapsis and periapsis line up correctly)

- Catch up (get the craft close enough, preferably < 1 km)

- Transfer to target's orbit (aka match velocity aka insertion burn)

I imagine the hard parts would be aligning planes and lining up the apsides (since I haven't noticed any mechjeb functions that do those automatically yet), but I don't know if those functions actually exist yet.

Edited by Peewee
figured out post #121, removed mention of manual param input
Link to comment
Share on other sites

Hm, I don't understand how mechjeb's Autom8 lua thing actually works. Is there a way to use "FindAn(orbit, tgttorbit)" (in OrbitExtensions.cs when looking through the source) in a lua script, or would I have to do the math myself?

Derp, figured out previous problem. Sorry for anyone trying to follow my problems, but make sure you have a target selected before trying to use 'mechjeb.core.targetVessel'.

Also, the varying interfaces for mechjeb.core.target* and vessel.* are driving me nuts.

example:

mechjeb.core.targetVessel.orbit.inclination

vs

vessel.orbitInclination

Also, put a space between while and ( due to LuaSharp being buggy.

Edited by Peewee
Adding an also every time I get stuck learning lua and figure it out
Link to comment
Share on other sites

Do not despair! It appears that

mechjeb.core.targetVessel

mechjeb.core.targetBody

mechjeb.core.part.vessel

.orbit

.referenceBody

local Orbits = script.call("Planetarium.Orbits")

Orbits.

are all direct interfaces to the KSP mod system, while

vessel.

is an abstraction layer/interface/wrapper that the Mechjeb team wrote for the Autom8 module. Thus, there is choice inherent in the system - choose the Autom8 abstraction, which is more limited but which is, I suspect, more likely to remain consistent version to version, or choose the more direct KSP interface, which is fuller featured, but more likely to change (and, apparently, nearly completely undocumented as far as I can tell - I'm adding what I find to the SimpleKSPOrbitalOperations.lua file, and to this thread).

Also, what was the answer to FindAn(orbit, tgttorbit) - can you post sample code, please, so we can all learn more?

Link to comment
Share on other sites

As far as I can tell, you have to do the math yourself.

From OrbitExtensions.cs:

        /// <summary>
/// Finds the coordinates of a state vector.
/// </summary>
/// <returns>
/// Double[] {lattitude, longitude}
/// </returns>
/// <param name='vinput'>
/// State vector
/// </param>
public static double[] LatLonofVector(Vector3d vinput)
{
//get the geocentric latitude and longitude of a orbital element vector
double rad = Math.PI/180;
double c1 = vinput.x;
double c2 = vinput.y;
double c3 = vinput.z;
double lon = 0;

double lat = Math.Atan(c3/Math.Pow((c1*c1) + (c2*c2), .5))/rad;
if (c1 < 0)
{
lon = (Math.Atan(c2/c1)/rad) + 90;
}
else
{
lon = (Math.Atan(c2/c1)/rad) + 270;
}
var coord = new[] {lat, lon};
return coord;
}
/// <summary>
/// Orbit foo, this finds the nodes of two orbits
/// </summary>
/// <returns>
/// The true anomaly of the ascending node(descing node is 180degrees off)
/// </returns>
/// <param name='orbit'>
/// Orbit.
/// </param>
/// <param name='tgtorbit'>
/// Target Orbit
/// </param>
public static double FindAN(Orbit orbit, Orbit tgtorbit)
{
double rad = Math.PI/180;
double Lan1 = orbit.LAN;
double inc1 = orbit.inclination;
double Lan2 = tgtorbit.LAN;
double inc2 = tgtorbit.inclination;

//see braeunig.us/space... cross product of two orbital planes gives the node location
var a = new Vector3d(Math.Sin(inc1*rad)*Math.Cos(Lan1*rad), Math.Sin(inc1*rad)*Math.Sin(Lan1*rad),
Math.Cos(inc1*rad));
var b = new Vector3d(Math.Sin(inc2*rad)*Math.Cos(Lan2*rad), Math.Sin(inc2*rad)*Math.Sin(Lan2*rad),
Math.Cos(inc2*rad));
var c = new Vector3d(0, 0, 0);
c = Vector3d.Cross(a, ;
var coord = new double[] {0, 0};
coord = LatLonofVector(c); //get the coordinates lat/lon of the ascending node
double lat = coord[0];
double lon = coord[1];

//go look at the diagrams at braeunig.us/space
double α = lon - Lan1; //its all greek to me
if (α < 0) α += 360;
double λ = Math.Atan(Math.Tan(α*rad)/Math.Cos(inc1*rad))/rad;
double x = 180 + (λ - orbit.argumentOfPeriapsis);
if (x > 360) return 360 - x;
else return x;
}

My current (completely untested) lua port:


-- takes (vector{x,y,z}) (?), returns coordinates{lat, lon}
function LatLonofVector(vinput)
-- get the geocentric latitude and longitude of a orbital element vector
rads = math.pi/180
local c1 = vinput[1]
local c2 = vinput[2]
local c3 = vinput[3]
local lon = 0

local lat = math.atan(c3/math.sqrt((c1*c1) + (c2*c2)))/rads;
if (c1 < 0) then
lon = (math.atan(c2/c1)/rads) + 90;
else
lon = (math.atan(c2/c1)/rads) + 270;
end
local coord = {lat, lon}
return coord;
end
--takes (vessel, mechjeb.core.targetVessel), returns true anomaly of ascending node
function FindAN(subj, tgt)
rads = math.pi/180
local Lan1 = subj.orbitLAN
local inc1 = subj.orbitInclination
local Lan2 = tgt.orbit.LAN
local inc2 = tgt.orbit.inclination
-- see braeunig.us/space... cross product of two orbital planes gives the node location
local a = {math.sin(inc1*rads)*math.cos(Lan1*rads), math.sin(inc1*rads)*math.sin(Lan1*rads), math.cos(inc1*rads)}
local b = {math.sin(inc2*rads)*math.cos(Lan2*rads), math.sin(inc2*rads)*math.sin(Lan2*rads), math.cos(inc2*rads)}
local c = {0, 0, 0}
c = VectorCross(a, --easy enough to define yourself
local coord = {0,0,0}
coord = LatLonofVector(c) --get the coordinates lat/lon of the ascending node
local lat = coord[1]
local lon = coord[2]

-- go look at the diagrams at braeunig.us/space
local d = lon - Lan1; -- its all greek to me
if (d < 0) then
d = d + 360
end
local e = math.atan(math.tan(d*rads)/math.cos(inc1*rads))/rads
local x = 180 + (e - subj.orbitArgumentOfPeriapsis)
if (x > 360) then
return 360 - x
else
return x
end
end


Yesterday, I decided to split off most of the math into a different script for calculating true/mean/eccentric anomalies, from a table of orbital parameters. That should make it easier to keep up to date; should just need to update the way the getParameters(ship) function works when KSP/MechJebLib updates and everything breaks. :)

Link to comment
Share on other sites

Alright, 319 lines in (including whitespace and comments) and I >think< I have a ship that matches planes with its target. More testing/debugging is required though. I found some interesting time equations at http://braeunig.us/space/ , and I think this script could be (on paper anyway) capable of making a combined transfer/minor plane change burn to intercept with the target, then simply kill relative velocity to synchronize orbits, but that's not very likely in the first version.

Link to comment
Share on other sites

Excellent work, Peewee - you're definitely ahead of me for this area; I'll catch up at some point, though I have a lot of other functions to write first.

For everyone that's interested, below is a newer lua/Autom8 function from my SimpleKSPOrbitalMechanics script that will print out a large portion of the information available to us from any of the Orbit classes (the vessel.orbit* references still exist, but if you like, you can replace vessel.orbit with <your orbital object>, which I'm going to do myself for my report* function, because then you can use it for your own vessel (as this does), or any target vessel or body, or even a specific body or vessel not being targetted.

Grand Lander, the basic steps in simply using Autom8 are easy. If you want to see basic vessel control, the FlyMeToTheMun script from the first page of this thread is an excellent, simple starting point. Start KSP, and get a Mun lander with Mechjeb ready on the launchpad.

Either copy and paste the contents of that script into the Autom8 window's bottom text bar, or save it in %KSP%\PluginData\mumechlib as "FlyMeToTheMun.lua" and then type in that same bottom Autom8 text bar:


require "FlyMeToTheMun"

Then type in that bottom Autom8 text bar:


FlyMeToTheMun(30,30)

And read through the "print()" statements in the script as it runs; you can then start to figure out the code controlling your rocket.

If you want something more detailed and to learn more about lua, some of the other scripts in this thread are better - you can start with SimpleOrbitalMechanics for pure Autom8 math, or SimpleOrbitalOperations for pure operational use (Molniya style orbits, for example). That's post #53 in this thread (http://kerbalspaceprogram.com/forum/showthread.php/16503-MechJeb-Autom8-Scripts-Megathread?p=238962&viewfull=1#post238962)


function printSkomKSPCurrentOrbitalElements()
-- returns nothing.
--[[ Ex.
printSkomKSPCurrentOrbitalElements()
]]
print("name string " .. mechjeb.core.part.vessel.name)
print("orbitApA meters " .. vessel.orbitApA)
print("orbitApR meters " .. mechjeb.core.part.orbit.ApR)
print("orbitPeA meters " .. vessel.orbitPeA)
print("orbitPeR meters " .. mechjeb.core.part.orbit.PeR)
print("orbitPeriod seconds " .. vessel.orbitPeriod)
print("orbitTimeToAp seconds " .. vessel.orbitTimeToAp)
print("orbitTimeToPe seconds " .. vessel.orbitTimeToPe)
print("orbitLAN (RA/Long of Ascending Node) degrees " .. vessel.orbitLAN)
print("LAN degrees " .. mechjeb.core.part.orbit.LAN)
print("orbitArgumentOfPeriapsis (APe) degrees " .. vessel.orbitArgumentOfPeriapsis)
print("orbitLongitudeOfPeriapsis (LPe) degrees " .. calcSomLpeFromLanApe(vessel.orbitLAN, vessel.orbitArgumentOfPeriapsis))
print("orbitInclination degrees " .. vessel.orbitInclination)
print("orbitEccentricity (e) " .. vessel.orbitEccentricity)
print("orbitSemiMajorAxis (a) meters " .. vessel.orbitSemiMajorAxis)
print("meanAnomaly radians 0 to 2pi " .. mechjeb.core.part.vessel.orbit.meanAnomaly)
print("meanAnomalyAtEpoch radians (KSP 0.16 BUGGED == meanAnomaly) 0 to 2pi " .. mechjeb.core.part.vessel.orbit.meanAnomalyAtEpoch)
print("epoch seconds " .. mechjeb.core.part.orbit.epoch)
print("time seconds " .. vessel.time)
print("StartUT seconds " .. mechjeb.core.part.orbit.StartUT)
print("GetUniversalTime seconds " .. script.call("Planetarium.GetUniversalTime"))
print("trueAnomaly degrees 0 to 360 " .. mechjeb.core.part.orbit.trueAnomaly)
print("eccentricAnomaly radians 0 to 2pi " .. mechjeb.core.part.orbit.eccentricAnomaly)
print("pos[1] position vector ?x? ?? " .. mechjeb.core.part.orbit.pos[1])
print("pos[2] position vector ?x? ?? " .. mechjeb.core.part.orbit.pos[2])
print("pos[3] position vector ?x? ?? " .. mechjeb.core.part.orbit.pos[3])
print("vel[1] velocity vector ?x? ?? " .. mechjeb.core.part.orbit.vel[1])
print("vel[2] velocity vector ?x? ?? " .. mechjeb.core.part.orbit.vel[2])
print("vel[3] velocity vector ?x? ?? " .. mechjeb.core.part.orbit.vel[3])
print("semiMinorAxis meters " .. mechjeb.core.part.vessel.orbit.semiMinorAxis)
print("semiLatusRectum meters " .. mechjeb.core.part.vessel.orbit.semiLatusRectum)
print("speedOrbital m/s " .. vessel.speedOrbital)
print("orbitalSpeed ?? not the same as vessel.speedOrbital " .. mechjeb.core.part.orbit.orbitalSpeed)
print("orbitalEnergy " .. mechjeb.core.part.orbit.orbitalEnergy)
print("speedSurface m/s " .. vessel.speedSurface)
print("speedVertical m/s " .. vessel.speedVertical)
print("speedHorizontal m/s " .. vessel.speedHorizontal)
print("vesselHeading degrees " .. vessel.vesselHeading)
print("vesselPitch degrees " .. vessel.vesselPitch)
print("vesselRoll degrees " .. vessel.vesselRoll)
print("altitudeASL meters " .. vessel.altitudeASL)
print("altitudeTrue meters " .. vessel.altitudeTrue)
print("altitudeBottom meters " .. vessel.altitudeBottom)
print("core altitude meters " .. mechjeb.core.part.vessel.altitude)
print("latitude degrees " .. vessel.latitude)
print("longitude degrees " .. vessel.longitude)
print("vessel orbit radius meters " .. vessel.radius)
print("core orbit radius meters " .. mechjeb.core.part.orbit.radius)
print("localg m/s " .. vessel.localg)
print("atmosphericDensity " .. vessel.atmosphericDensity)
print("ObT ?? " .. mechjeb.core.part.vessel.orbit.ObT)
print("ObTAtEpoch ?? " .. mechjeb.core.part.vessel.orbit.ObTAtEpoch)
print("SEVp ?? " .. mechjeb.core.part.orbit.SEVp)
print("SEVs ?? " .. mechjeb.core.part.orbit.SEVs)
print("fromE ?? " .. mechjeb.core.part.orbit.fromE)
print("fromV ?? " .. mechjeb.core.part.orbit.fromV)
print("E ?? " .. mechjeb.core.part.orbit.E)
print("V ?? " .. mechjeb.core.part.orbit.V)
print("toE ?? " .. mechjeb.core.part.orbit.toE)
print("toV ?? " .. mechjeb.core.part.orbit.toV)
print("UTappr ?? " .. mechjeb.core.part.orbit.UTappr)
print("UTsoi ?? " .. mechjeb.core.part.orbit.UTsoi)
print("referenceBody.name string " .. mechjeb.core.part.orbit.referenceBody.name)
if mechjeb.core.part.orbit.referenceBody.name == "Kerbin" then
print("referenceBody full name string KSP_Galaxy1_Kerbol_Kerbin")
elseif mechjeb.core.part.orbit.referenceBody.name == "Mun" then
print("referenceBody full name string KSP_Galaxy1_Kerbol_Kerbin_Mun")
elseif mechjeb.core.part.orbit.referenceBody.name == "Minmus" then
print("referenceBody full name string KSP_Galaxy1_Kerbol_Kerbin_Minmus")
elseif mechjeb.core.part.orbit.referenceBody.name == "Sun" then
print("referenceBody full name string KSP_Galaxy1_Kerbol")
end
print("ClAppr ?? only nonzero when closestEncounterBody ~= nil " .. mechjeb.core.part.orbit.ClAppr)
print("ClEctr1 ?? only nonzero when closestEncounterBody ~= nil " .. mechjeb.core.part.orbit.ClEctr1)
print("ClEctr2 ?? only nonzero when closestEncounterBody ~= nil " .. mechjeb.core.part.orbit.ClEctr2)
print("CrAppr ?? only nonzero when closestEncounterBody ~= nil " .. mechjeb.core.part.orbit.CrAppr)
print("EndUT " .. mechjeb.core.part.orbit.EndUT)
print("eccVec[1] eccentricity vector ?x? ?? " .. mechjeb.core.part.orbit.eccVec[1])
print("eccVec[2] eccentricity vector ?y? ?? " .. mechjeb.core.part.orbit.eccVec[2])
print("eccVec[3] eccentricity vector ?z? ?? " .. mechjeb.core.part.orbit.eccVec[3])
print("FEVp ?? " .. mechjeb.core.part.orbit.FEVp)
print("FEVs ?? " .. mechjeb.core.part.orbit.FEVs)
print("h[1] ?? " .. mechjeb.core.part.orbit.h[1])
print("h[2] ?? " .. mechjeb.core.part.orbit.h[2])
print("h[3] ?? " .. mechjeb.core.part.orbit.h[3])
print("mag ?? " .. mechjeb.core.part.orbit.mag)
if mechjeb.core.part.vessel.orbit.closestEncounterBody ~= nil then
print("closestEncounterBody.name " .. mechjeb.core.part.vessel.orbit.closestEncounterBody.name)
end
print("orbitPercent " .. mechjeb.core.part.orbit.orbitPercent)
if mechjeb.core.part.orbit.previousPatch ~= nil then
-- Orbit class
print("previousPatch.semiMajorAxis (a) meters " .. mechjeb.core.part.orbit.previousPatch.semiMajorAxis)
print("previousPatch.inclination degrees " .. mechjeb.core.part.orbit.previousPatch.inclination)
end
if mechjeb.core.part.orbit.nextPatch ~= nil then
-- Orbit class
print("nextPatch.semiMajorAxis (a) meters " .. mechjeb.core.part.orbit.nextPatch.semiMajorAxis)
print("nextPatch.inclination degrees " .. mechjeb.core.part.orbit.nextPatch.inclination)
end
print("nearestTT ?? " .. mechjeb.core.part.orbit.nearestTT)
print("nextTT ?? " .. mechjeb.core.part.orbit.nextTT)
print("objectType string " .. mechjeb.core.part.orbit.objectType)
print("sampleInterval ?? " .. mechjeb.core.part.orbit.sampleInterval)
print("timeToTransition1 ?? " .. mechjeb.core.part.orbit.timeToTransition1)
print("timeToTransition2 ?? " .. mechjeb.core.part.orbit.timeToTransition2)
-- ?? FUTURE ADD TimeSincePeriapsis, angular momentum,


end

Link to comment
Share on other sites

I've no experience with github. What do others think?

I've used SVN to a small extent; if a reference for basic check in/out, making copies, and doing so based on label name (not tip) in git is linked to, I'd be more than happy to use it as well as pastebin. I don't have any real preference between source control repositories - for a selection of individual scripts like these, with one or maybe two authors apiece, there's no compelling reason to choose one modern source control method over another.

I would say make sure there are Windows, Mac, and Linux instructions.

Link to comment
Share on other sites

How would I use the wait() command to wait until the ship is above/below a certain altitude, it doesn't seem to like anything I've tried.

What I've tried so far:

<code>

wait(altAbove1k)

...

function altAbove1k()

return vessel.altitudeASL > 1000

end

</code>

and

<code>

while vessel.altitudeASL < 1000 do

wait(1)

end

</code>

Both cause KSP to freeze and crash.

Is this a problem with 'vessel' or am I missing something?

Link to comment
Share on other sites

You need to run it in a coroutine. See kerbin2mun.lua in the OP for an example.

After thorough testing, I've determined that my FindAN() function doesn't work as expected.

If anyone has a working algorithm to get the true anomaly of the ascending node between two orbital planes, I'd be much obliged. :)

What I've got so far (significant portions ported over from MuMechLib):

-- TAKES: orbital position vector (3d vector)
-- RETURNS: geocentric latitude and longitude? (2d vector) at given orbital element vector
function LatLongofVector(vinput)
-- get the geocentric latitude and longitude of a orbital element vector
local rads = math.pi/180
local c1 = vinput[1]
local c2 = vinput[2]
local c3 = vinput[3]
local lat = math.atan(c3 / math.sqrt(c1*c1 + c2*c2))/rads
local long = math.atan2(c2, c1)/rads
if (c1 < 0) then
long = long + 90
elseif (c1 > 0) then
long = long + 270
end
local coord = {lat, long}
return coord;
end

-- TAKES: geocentric coordinates (latitude, longitude)
-- RETURNS: true anomaly (radians) when orbit is over coordinates
-- note: May or may not actually work right now...
function GetTrueAnomalyAtGeoCoordinates(orbitParams, coords)
local temp2 = math.deg(math.atan(math.tan(math.rad(coords[2]))/math.cos(math.rad(orbitParams.I))))
-- print("temp2: " .. temp2)
local truAnomaly = 180 + (temp2 - orbitParams.AoP)
if (truAnomaly > 360) then truAnomaly = truAnomaly - 360 end
return math.rad(truAnomaly)
end

-- TAKES: target orbital parameters
-- RETURNS: (radians) true anomaly of ascending node
-- note: does not work yet.
function FindAN(orbitParams, targetParams)
print("finding AN")
local vA = math.sin(math.rad(orbitParams.I))*math.cos(math.rad(orbitParams.LAN))
local vB = math.sin(math.rad(orbitParams.I))*math.sin(math.rad(orbitParams.LAN))
local vC = math.cos(math.rad(orbitParams.I))
local tA = math.sin(math.rad(targetParams.I))*math.cos(math.rad(targetParams.LAN))
local tB = math.sin(math.rad(targetParams.I))*math.sin(math.rad(targetParams.LAN))
local tC = math.cos(math.rad(targetParams.I))
-- vector3D.cross(v, t) inline here
local c = {}
c[1] = vB*tC - vC*tB
c[2] = vC*tA - vA*tC
c[3] = vA*tB - vB*tA
-- print("end vector stuff C")

local coordsA = LatLongofVector(c)
coordsA[2] = coordsA[2] - orbitParams.LAN --don't ask me.
if (coordsA[2] < 0) then
coordsA[2] = coordsA[2] + 360
end
print("AN coords?: ".. coordsA[1], coordsA[2])
-- Got latitude/longitude of node A
-- local latB = coordsA[1] * (-1)
-- local longB = coordsA[2] + 180
-- if (longB > 360) then
-- longB = longB - 360
-- end
-- local coordsB = {latB, longB}
-- Got latitude/longitude of node B
-- print("end coordinate stuff C")

local nodeA = GetTrueAnomalyAtGeoCoordinates(orbitParams, coordsA)
-- local nodeB = GetTrueAnomalyAtGeoCoordinates(orbitParams, coordsB)
-- print("end node stuff A")
-- TODO: figure out a way to distinguish ascending and descending nodes.
-- if (GetRadiusAtTruAnomaly(orbitParams, nodeA) > GetRadiusAtTruAnomaly(orbitParams, nodeB)) then
return nodeA
-- else
-- return nodeB
-- end
end

I also have true anomaly -> eccentric anomaly -> mean anomaly conversions.

Edited by Peewee
Link to comment
Share on other sites

To expand a little on Peewee's absolutely correct "run it in a coroutine" message (and do look at the example he provided!

Coroutines in lua are essentially a separate execution thread - they're a routine (function) that, in the simplest form, you tell to go off and start asynchronously, and it does whatever it wants while you continue to do whatever you want - you don't wait for it (much like starting a program in *nix with & afterwards - it runs in a separate process). So, if you want a constantly updated gauge or meter, a coroutine is great. If you want to have a light blink on and off forever, or based on something, a coroutine is great. If you want to interact with the code in the coroutine bidirectionally... not so simple.

Now, when you get your Autom8 lua window, whatever you do there is done _in the main game process_. So if you say "wait()", then the entire game waits. If you put the wait() in a coroutine, then that coroutine spawns a new process/thread, and that thread waits... but since you didn't wait for the coroutine, you don't see any wait.

Therefore, whatever you're waiting for needs to wait for the wait() (i.e. be synchronous with it, be in the same process/thread)... and to not stall out the game, that _entire package_ needs to be executed asynchronously with the game, i.e. in a coroutine.

So, we have:

function DoStuffDriver

stuff

wait()

stuff

end

function coDoStuff

..

end

And in the main Autom8 window, you'll call coDoStuff(), and you'll see the results of any print() statements, but you can't really control it anymore without a lot more work - you kick it off and let it run. If it goes wild, get out to the main Start Game screen and go back in.

Note that my SimpleSKPOrbitalOperations Isp finding coroutine is also an example, but less clear.

Link to comment
Share on other sites

Peewee, what license or licenses are you releasing your code under? If you're willing to go the user's choice of GPLv2, GPLv3, or CC-BY-SA 3.0 or a license compatible with all three of them (MIT, etc.), then I'd love to get my grubby little hands on your (working) code (particularly the anomaly conversions) to include in the SimpleOrbitalMechanics and related libraries with attribution to you as the original author. It'd save me some time writing abd documenting exactly the same mathematics, though since they're pure math, I'll need to write some assert() statements for the test harness.

dAkshEN3, you're in luck - I just finished the second of my major "waiting" general functions, and had to test it. I assume a test based on altitude would be of interest to you? :) That's the very last function below.

If anything's confusing (or wrong) please ask - this is the rough draft, copied from another function that waits for a set of two variables to quit changing too much per timeslice (i.e. wait until the pitch and heading settle down after a mechjeb.attitudeTo() call before firing engines), and I may well have some comments from the previous version in there. It's also a little chatty still, but that may help you visualize what's happening.


-- Original Work Copyright 2012, Nadrek, insofar as any elements that aren't obvious, trivial, or mathematics are concerned (none of which are copyrightable)
-- licensed under your choice of GPLv2, GPLv3, or Creative Commons Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0) http://www.gnu.org/licenses/gpl-2.0.html or http://www.gnu.org/licenses/gpl.html or http://creativecommons.org/licenses/by-sa/3.0/


function waitSkomForMinimumToPassFn1TmbtwnMnot(Function1, TimeBetween, MaxNumberOfTries)
-- added in v0.004
-- NOTE: Because this has wait() statements, it must be run synchronously with whatever uses the data it returns
-- NOTE: Because this has wait() statements, it must be run asynchronously with the main game and any control processes!
-- Function1 is a function that takes no arguments, and returns one numeric values that will be tested
-- to see if the return value is greater than or equal to the previous return value.
-- TimeBetween is the time in seconds between initial and final measurements for each test
-- MaxNumberOfTries is how many times we should wait for TimeBetween to elapse and test
-- This is so we don't get into an infinite loop with an ever increasing value
-- returns 0 if we timed out (got to MaxNumberOfTries without ever passing a minimum point
-- and 1 if we successfully ended up just past than the minimum.
-- For example, this is very useful to wait for some measurement to reach a minimum, i.e.
-- one use is to use this to wait until the Mean Anomaly, or the Longitude, or the Altitude is at its lowest.
-- Alternately, wait for math.abs(MeanAnomaly-2.3) to wait until the MA is just past 2.3
-- quit moving "too much", using that to determine when the vessel is indeed no longer oscillating too much.
-- Ex. USE WITHIN ANOTHER COROUTINE function!!!
-- waitSkomForMinimumToPassFn1TmbtwnMnot(reportSkomKSPLatitude, 30, 725)
-- Ex. see SimpleKSPOrbitalOperations, function ???
-- locals would be ideal; however, in one other test locals didn't update in the while loop, so uniquely named globals were used. This was as of SharpLua 1.1
globalFuncPrevi_waitSkomForMinimumToPassFn1TmbtwnMnot = 1
-- now for some _really_ stupid local/global kludges. local variables get a 1:1 replacement, but don't work in a prior while loop try.
-- global variables, however, get an index out of range exception on the timeout, but do work in the while loop.
local localFuncPrev1_waitSkomForMinimumToPassFn1TmbtwnMnot = Function1()
globalFuncPrev1_waitSkomForMinimumToPassFn1TmbtwnMnot = localFuncPrev1_waitSkomForMinimumToPassFn1TmbtwnMnot
-- First, wait a time unit after the initial "previous"
wait(TimeBetween)
-- now for some _really_ stupid local/global kludges. local variables get a 1:1 replacement, but don't work in a prior while loop try.
-- global variables, however, get an index out of range exception on the timeout, but do work in the while loop.
local localFuncCur1_waitSkomForMinimumToPassFn1TmbtwnMnot = Function1()
globalFuncCur1_waitSkomForMinimumToPassFn1TmbtwnMnot = localFuncCur1_waitSkomForMinimumToPassFn1TmbtwnMnot
-- Now we can enter our "checking" while loop.
-- If the return value is over our threshold and we aren't finished, let's keep waiting.
globalFuncDiff = (globalFuncCur1_waitSkomForMinimumToPassFn1TmbtwnMnot - globalFuncPrev1_waitSkomForMinimumToPassFn1TmbtwnMnot)
print(globalFuncDiff .. " loop " .. globalFuncPrevi_waitSkomForMinimumToPassFn1TmbtwnMnot)
-- The difference will be negative while the values are decreasing over time.
while (globalFuncDiff <= 0) and (globalFuncPrevi_waitSkomForMinimumToPassFn1TmbtwnMnot <= MaxNumberOfTries) do
-- the "Cur" we've currently got is now "Prev" - make it so.
globalFuncPrev1_waitSkomForMinimumToPassFn1TmbtwnMnot = globalFuncCur1_waitSkomForMinimumToPassFn1TmbtwnMnot
wait(TimeBetween)
-- Gather a new "Cur" with our kludgy local/global tricks.
local localFuncCur1_waitSkomForMinimumToPassFn1TmbtwnMnot = Function1()
globalFuncCur1_waitSkomForMinimumToPassFn1TmbtwnMnot = localFuncCur1_waitSkomForMinimumToPassFn1TmbtwnMnot
-- increment the loop counter so we can exit if it's taking too many tries.
globalFuncPrevi_waitSkomForMinimumToPassFn1TmbtwnMnot = globalFuncPrevi_waitSkomForMinimumToPassFn1TmbtwnMnot + 1
globalFuncDiff = (globalFuncCur1_waitSkomForMinimumToPassFn1TmbtwnMnot - globalFuncPrev1_waitSkomForMinimumToPassFn1TmbtwnMnot)
print(globalFuncDiff .. " loop " .. globalFuncPrevi_waitSkomForMinimumToPassFn1TmbtwnMnot)
end
if globalFuncPrevi_waitSkomForMinimumToPassFn1TmbtwnMnot >= MaxNumberOfTries then
print "Wait for minimum timed out"
return 0
else
print "Successful Minimum passage"
return 1
end
end


function testSkomKSPWaitForMinAltitudeDriver()
-- added in v0.004
-- purely a test function to verify that waitSkomForMinimumToPassFn1TmbtwnMnot works
-- and to demonstrate that functions can be created on the fly, as it were.
local Function1_testSkomKSPWaitForMinAltitudeDriver = function() return mechjeb.core.part.vessel.orbit.altitude end
local retval = waitSkomForMinimumToPassFn1TmbtwnMnot(Function1_testSkomKSPWaitForMinAltitudeDriver, 5, 20)
if retval == 0 then
print "Did not ever pass Periapsis (the minimum altitude)"
else
print("Either was already ascending, or just passed minimum altitude of " .. mechjeb.core.part.vessel.orbit.altitude .. " no more than 10 seconds before time " .. mechjeb.core.part.vessel.orbit.epoch)
end
end


function cotestSkomKSPWaitForMinAltitude()
-- added in v0.004
--[[ ex.
Warp to less than 100 seconds before periapsis, then run:
cotestSkomKSPWaitForMinAltitude()
]]

local coTest = coroutine.create(testSkomKSPWaitForMinAltitudeDriver)
coroutine.resume(coTest)
end

Note that in Mechjeb 1.9.1, there's still some synchronization errors with the wait() statement - if you get one, just re-run it. At this time, I don't know if they're correlated with number of wait()s or time spent wait()ing, but since r4m0n is aware of the issue already, I'm hoping Mechjeb 1.9.2 transparently resets the wait() when they happen, which would render further investigation from the lua side pointless.

Link to comment
Share on other sites

I'm using code from MuMechLib, so I'm obligated to release those parts under GPL. To keep everything tidy, I'm releasing it all under GPL.

Here's my script as-is. (still obviously a work in progress)

------NON-FUNCTIONAL CODE------

http://pastebin.com/uxCZJgjT

http://pastebin.com/X8qgZGdE

------FOR SCRIPT WRITERS ONLY------

------DON'T BOTHER DOWNLOADING IF YOU JUST WANT IT TO WORK------

Edited by Peewee
Link to comment
Share on other sites

It's fine if you're just checking out the code, but if you want to execute anything in-game, you'll need to get rid of the .txt on the end. Once again, it's a work in progress, and doesn't actually do anything useful yet. As it is now, Rendezvous() will just spam some debugging text to the console then throw an error about trying to do math on a nil value (AN is not currently returned because it was inaccurate). I'll edit that post before it causes any more confusion.

Link to comment
Share on other sites

Is it okay if the script is a .txt file?

If i donwload one of your scripts it is a text file.

-Blue

dofile("somefile.txt") should work if you want to keep the extension, but beware of mixing real text files with Lua code. :wink:

Link to comment
Share on other sites

Without seeming critical or troll(ish), the math is all very impressive, but it would be nice to see some actual .lua script files that we (the humble kerbalites) could use in Autom8, it would also be great to have a script library thread (which is what I thought this was) where scripts can be listed with a simple explanation of what they do.

Just my thoughts - not intended to offend anyone.

Link to comment
Share on other sites

Yes, that's what I'm working towards. The math has to be done before any simple 'run it and it just works' scripts can be made, and it just so happens that rendezvous scripts take a significant amount of annoyingly hard to debug math, which hasn't already been given to us by MuMechLib.

In the meantime, have a simple script I whipped up in an hour: http://pastebin.com/ZZ0VGU6N

It will take you on a quick spin around the Kerbin neighborhood and land. (Kerbin -> Mun -> Minmus -> Kerbin)

Link to comment
Share on other sites

Yes, that's what I'm working towards. The math has to be done before any simple 'run it and it just works' scripts can be made, and it just so happens that rendezvous scripts take a significant amount of annoyingly hard to debug math, which hasn't already been given to us by MuMechLib.

In the meantime, have a simple script I whipped up in an hour: http://pastebin.com/ZZ0VGU6N

It will take you on a quick spin around the Kerbin neighborhood and land. (Kerbin -> Mun -> Minmus -> Kerbin)

Thanks for this

Link to comment
Share on other sites

Without seeming critical or troll(ish), the math is all very impressive, but it would be nice to see some actual .lua script files that we (the humble kerbalites) could use in Autom8, it would also be great to have a script library thread (which is what I thought this was) where scripts can be listed with a simple explanation of what they do.

Just my thoughts - not intended to offend anyone.

As Peewee said, to do neat things, we have to work out the neat math first, and then code it, and then test it, and then go back to the math, and then change the design, and so on. The neat stuff isn't quite as trivial as it appears - it is, in fact, rocket science*. Once we have a really good, solid foundation, then all Autom8 using Kerbal engineers and scientists will have more building blocks to work with.

Also, don't sell yourself short - look at Peewee's tour script; I bet you can spend less than ten minutes, and modify it so that it goes on the tour in reverse order. You could also take FlyMeToTheMun, and alter it to be FlyMeToTheMinmus. All it takes is a little trial and error, and a few brave Kerbals.

*: Two body simplification thereof.

Link to comment
Share on other sites

Yes, that's what I'm working towards. The math has to be done before any simple 'run it and it just works' scripts can be made, and it just so happens that rendezvous scripts take a significant amount of annoyingly hard to debug math, which hasn't already been given to us by MuMechLib.

In the meantime, have a simple script I whipped up in an hour: http://pastebin.com/ZZ0VGU6N

It will take you on a quick spin around the Kerbin neighborhood and land. (Kerbin -> Mun -> Minmus -> Kerbin)

Umm I cant get this to work .. I'm typing ... dofile("tour")

and it says...

ParseException: Code has syntax errors:

Line 1, Col 1 'f': Failed to parse Name of VarName.

Line 1, Col 20 '(': Failed to parse '0'..

I've named the file tour.lua

and I've looked over the code but cant see anything that's obvious .........HELP lol

Edited by crusaderuk
Link to comment
Share on other sites

This thread is quite old. Please consider starting a new thread rather than reviving this one.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...