Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- set k_autopilot2_version to "0.9.3".
- print "Kadin's autopilot2 V" + k_autopilot2_version:tostring.
- set debug to false.
- set slope_debug to true.
- ///
- /// set aoa to 72. lock steering to srfprograde * r(-aoa, 0,0)
- ///
- print "There are three versions of this code.".
- print "Unstable/development version, newest features, newest bugs: !runscript NHwvPAp3".
- print "Recent working version, seems like it is fairly stable: !runscript 0pgtewL5".
- print "Oldest version, least features but also fairly stable: !runscript dHtuDeGx".
- // 2021-09-05: completely re-wrote setup_runway and changed all references to variables matching regexp("^runway").
- // added variable flaps, while maintaining flaps on/off and toggle flaps.
- // you can do : set flaps to "full", "half" or "none".
- // you cat set flaps to 0.5.
- // BUT it only works when the flaps tag is "flaps:NUMBER" where number is the full scale deflection angle.
- // So if you want full flaps to be 23, then set the tag to "flaps:23".
- // added landing flare.
- // added aoa_limit_enable - stop craft from pitching beyond aoa limits.
- // - NOTE: the current aoa limit stuff is WRONG
- // - AoA has nothing to do with your angle to "up"... yet this is what I do.
- // - I know it is wrong, but i'll fix it later and it's better than nothing.
- // added function haoa() - hold angle of attack.
- // added SG Explorer and various other craft
- // latest change: added setup_runway function.
- //latest change: hl() for hold line.: hl(runway_west,runway_east).
- //latest change: blurb about version of the code.
- //latest change: added hg() for hold glideslope: hg(target_slope, ground_target, voffset, hoffset).
- set bank_change_rate to 3. // How fast we change between bank angles .
- set rudder_rate to 0.4. // How much rudder to kick in to help increase the turn rate.
- set default_bank_limit to 40. // This is how many degrees of bank for a turn if none are specified.
- set default_aoa_limit to 15. // aoa limit +/-
- set hud_message to "Want to have a go? Speak up in chat! I'm just testing code, and will happily stop and let you have a go!".
- set flare_factor to ship:mass/5.
- if ship:name:startswith("Mallard") {
- set vs to 65. // stall speed in level flight - complete guess.
- set vsr to 60. //normal stall speed.
- set vs0 to 40. //stall speed with flaps out
- set vto to 100. //take off speed
- set vfe to 65. //speed above which you would remove flaps.
- set vlo to 60. //speed below which you CAN extend/retract gear.
- set vc to 80. //cruise speed.
- set vt to 45. //threshold speed.
- set vtd to 40. //touchdown speed.
- set alt_radar_adj to 3.0433.
- set bank_limit to 40.
- //Setup small outboard aerosurfaces
- for p in ship:partsnamed("smallCtrlSrf") p:getmodule("ModuleControlSurface"):setfield("deploy",false).
- for p in ship:partsnamed("smallCtrlSrf") p:getmodule("ModuleControlSurface"):setfield("deploy direction",true).
- //max out authority limiter if we are able to.
- for p in ship:partsnamed("smallCtrlSrf") { local m is p:getmodule("ModuleControlSurface"). if m:hasfield("authority limiter") m:setfield("authority limiter",100). }.
- //Setup Large elevons.
- for p in ship:partsnamed("airlinerCtrlSrf") p:getmodule("ModuleControlSurface"):setfield("deploy",false).
- for p in ship:partsnamed("airlinerCtrlSrf") p:getmodule("ModuleControlSurface"):setfield("deploy direction",true).
- if exists("0:/Kadins_local_KSP.txt") { // in my own stock KSP, for some reason these elevons have deploy direction flipped.
- for p in ship:partsnamed("airlinerCtrlSrf") {
- if p:position:mag < 6 p:getmodule("ModuleControlSurface"):setfield("deploy direction",false).
- }
- }
- //max out authority limiter if we are able to.
- for p in ship:partsnamed("airlinerCtrlSrf") { local m is p:getmodule("ModuleControlSurface"). if m:hasfield("authority limiter") m:setfield("authority limiter",100). }.
- //set up tail fins
- for p in ship:partsnamed("tailfin") p:getmodule("ModuleControlSurface"):setfield("deploy",false).
- for p in ship:partsnamed("tailfin") p:getmodule("ModuleControlSurface"):setfield("deploy direction",false).
- //max out authority limiter if we are able to.
- for p in ship:partsnamed("tailfin") { local m is p:getmodule("ModuleControlSurface"). if m:hasfield("authority limiter") m:setfield("authority limiter",100). }.
- //use large elevons as flaps (with deploy angle to 100% of available authority).
- for p in ship:partsnamed("airlinerCtrlSrf") { local m is p:getmodule("ModuleControlSurface"). m:setfield("deploy angle", choose ( m:getfield("authority limiter") * 1.0) if m:hasfield("authority limiter") else m:getfield("deploy angle") ). }.
- for p in ship:partsnamed("airlinerCtrlSrf") set p:tag to "flaps:" + p:getmodule("ModuleControlSurface"):getfield("deploy angle").
- //for p in ship:partstaggedpattern("^flaps(:|$)") print "TAG = " + p:tag.
- //use tail fins as spoilers (with deploy angle to 80% of available authority)
- for p in ship:partsnamed("tailfin") { local m is p:getmodule("ModuleControlSurface"). m:setfield("deploy angle", choose ( m:getfield("authority limiter") * 0.8) if m:hasfield("authority limiter") else m:getfield("deploy angle") ). }.
- for p in ship:partsnamed("tailfin") set p:tag to "spoilers".
- // at one stage I was only using some of the large elevons for flaps...
- // p:position:mag < 6 is the inboard elevons
- // p:position:mag > 6 and < 8 is the middle elevons
- // p:position:mag > 8 is the outer large elevons.
- //setup airbrakes
- for p in ship:partsnamed("airbrake1") set p:tag to "airbrakes".
- for p in ship:partstagged("airbrakes") p:getmodule("ModuleAeroSurface"):setfield("deploy",false).
- //setup brakes
- for p in ship:partsnamed("GearMedium") p:getmodule("ModuleWheelBrakes"):setfield("brakes",75).
- for p in ship:partsnamed("SmallGearBay") p:getmodule("ModuleWheelBrakes"):setfield("brakes",25).
- //setup reversable jets
- for p in ship:partsnamed("JetEngine") set p:tag to "jets".
- } else if ship:name:startswith("Aeris 3A") {
- set alt_radar_adj to 1.410271525383.
- for p in ship:partsnamed("R8winglet") if p:position:mag < 4 p:getmodule("ModuleControlSurface"):setfield("deploy angle",10).
- for p in ship:partsnamed("R8winglet") if p:position:mag < 4 set p:tag to "flaps".
- for p in ship:partsnamed("elevon3") p:getmodule("ModuleControlSurface"):setfield("deploy angle",15).
- for p in ship:partsnamed("elevon3") set p:tag to "flaps".
- for p in ship:partsnamed("R8winglet") { if p:position:mag > 4 p:getmodule("ModuleControlSurface"):setfield("deploy angle",15). }
- for p in ship:partsnamed("R8winglet") if p:position:mag > 4 set p:tag to "spoilers".
- for p in ship:partsnamed("JetEngine") set p:tag to "jets".
- for p in ship:partsnamed("SmallGearBay") if p:position:mag > 2 p:getmodule("ModuleWheelBrakes"):setfield("brakes",25). else p:getmodule("ModuleWheelBrakes"):setfield("brakes",100).
- set bank_limit to 60.
- set vs to 32.
- set vsr to 32.
- set vs0 to 32.
- set vfe to 35.
- set vlo to 35.
- set vto to 75.
- set vc to 60.
- set vtd to 32.
- set vt to 35.
- } else if ship:name:startswith("Lockheed Jetstar") {
- set alt_radar_adj to 1.6479332447952.
- for p in ship:partsnamed("SmallGearBay") if p:position:mag < 2 p:getmodule("ModuleWheelBrakes"):setfield("brakes",100). else p:getmodule("ModuleWheelBrakes"):setfield("brakes",25).
- set bank_limit to 50.
- set vs to 60.
- set vsr to 60.
- set vs0 to 60.
- set vfe to 65.
- set vlo to 65.
- set vto to 100.
- set vc to 80.
- set vtd to 60.
- set vt to 60.
- set vrot to 60.
- } else if ship:name:startswith("Reusable Moons Rocketship") {
- set bank_limit to 30.
- set alt_radar_adj to 4.58227.
- // can glide (constant airspeed) at about a -28 pitch down orientation.
- for p in ship:partsnamedpattern("gear") if p:position:mag < 7 p:getmodule("ModuleWheelBrakes"):setfield("brakes",200).
- // the shuttle rudder defaults to deploy angle 37.5 deg. but it only has an authority limiter of 9.75 deg.
- // so I'm assuming you will lose control authority if you deploy the tail fins as a speed brake.
- // also they both have deploy direction set to false... which I think will mean they don't activate opposite directions???
- // mpore experimentation is required.
- for p in ship:partsnamed("wingShuttleRudder") set p:tag to "spoilers".
- set vs to 75.
- set vsr to 75.
- set vs0 to 75.
- set vfe to 100.
- set vlo to 100.
- set vto to 150.
- set vc to 125.
- set vtd to 80.
- set vt to 90.
- } else if ship:name:startswith("SG Rescue 2") {
- //AG1 = rapier engine
- //ag2 = toggle rapier mode
- //ag3 = airbrakes.
- //ag5 = cargobay
- //ag7,9,10 do drill stuff.
- // enable nuclear engines with: list engines in es. for e in es if e:name:contains("nuc") e:activate
- //show engine mode for rapiers: list engines in es. for e in es if e:multimode print e:mode
- //All engines on: list engines in es. for e in es e:activate
- //use execute_node_old for any multi egine craft with some engines on or off or jet engines in space etc...
- //extend antenna: for a in ship:modulesnamed("ModuleDeployableAntenna") a:DoAction("extend antenna", true)
- set alt_radar_adj to 6.
- set vs to 120.
- set vsr to 120.
- set vs0 to 120.
- set vfe to 120.
- set vlo to 120.
- set vto to 120.
- set vc to 120.
- set vtd to 120.
- set vt to 120.
- } else if ship:name:startswith("roach") {
- set alt_radar_adj to 1.90005767345428.
- // vertical stabilizers only have authority limiter = 15 so 10 for spoilers is about the most you can use safely.
- for p in ship:partsnamed("R8winglet") if p:position:mag > 3.3 p:getmodule("ModuleControlSurface"):setfield("deploy angle",10).
- for p in ship:partsnamed("R8winglet") if p:position:mag > 3.3 set p:tag to "spoilers".
- for p in ship:partsnamed("SmallGearBay") if p:position:mag < 1.2 p:getmodule("ModuleWheelBrakes"):setfield("brakes",25).
- set vs to 30.
- set vsr to 30.
- set vs0 to 30.
- set vfe to 60.
- set vlo to 60.
- set vto to 60.
- set vc to 100.
- set vtd to 30.
- set vt to 35.
- //set apid:KP to 0.2.
- //set apid:KI to 0.1.
- //set apid:KD to 0.2.
- //top speed around 876 at 2500m.
- } else if ship:name:startswith("SG Explorer") {
- set alt_radar_adj to 3.75.
- //for p in ship:partsnamed("SmallGearBay") p:getmodule("ModuleWheelBrakes"):setfield("brakes",0).
- for p in ship:partsnamed("airbrake1") set p:tag to "airbrakes".
- set sus to ship:modulesnamed("ModuleWheelSuspension").
- for w in sus { if w:hasevent("spring/damper: auto") w:doevent("spring/damper: auto").}.
- for w in sus { w:setfield("spring strength",2). w:setfield("damper strength",2).}.
- set sus to ship:modulesnamed("ModuleWheelBase").
- for w in sus { if w:hasevent("friction control: auto") w:doevent("friction control: auto").}.
- for w in sus { w:setfield("friction control",1).}.
- for m in ship:modulesnamed("ModuleWheelBrakes") m:setfield("brakes",200).
- set vs to 90.
- set vsr to 90.
- set vs0 to 90.
- set vfe to 120.
- set vlo to 120.
- set vto to 100. // rotate at 90? 95?
- set vc to 150.
- set vtd to 95.
- set vt to 100.
- set STEERINGMANAGER:MAXSTOPPINGTIME to 20.
- set steeringmanager:rollpid:kd to 1.
- set bank_change_rate to 1.
- set steeringmanager:rollpid:ki to 0.1. set steeringmanager:rollpid:kd to 0.2. set steeringmanager:rollpid:kp to 0.4.
- } else {
- set vs to 100.
- set vsr to 100.
- set vs0 to 100.
- set vfe to 120.
- set vlo to 120.
- set vto to 120.
- set vc to 150.
- set vtd to 95.
- set vt to 100.
- set alt_radar_adj to 5.
- }
- // anomoly scanner.
- //set as to addons:scansat:getanomalies(body). for anomaly in as print anomaly:name:padright(20) + anomaly:geoposition
- // flying a heading near the pole:
- //lock srfheading to body:geopositionof(srfprograde:vector:normalized):heading
- // lock x to srfheading + turnrate.
- // stall speed increases at high bank angles. Keep this updated so we can refer to this increased stall speed.
- lock bank_stall_angle to arccos(vs^2/max(vs,airspeed)^2).
- set control_revthrust to true.
- set revthrust to false.
- on revthrust {
- for p in ship:partstagged("jets") {
- local m is p:getmodule("ModuleAnimateGeneric").
- if revthrust and m:hasevent("reverse thr" + "ust") m:doevent("reverse thr" + "ust").
- else if m:hasevent("forward thr" + "ust") m:doevent("forward thr" + "ust").
- }
- return control_revthrust.
- }
- //on flaps {
- // for p in ship:partstagged("flaps") p:getmodule("ModuleControlSurface"):setfield("deploy",flaps).
- // if flaps set vs to vs0.
- // else set vs to vsr.
- // return true.
- //}
- // allow flaps to be set to other values.
- set control_flaps to true.
- set flaps to 0.
- on flaps {
- if flaps:istype("Boolean") {
- if flaps set flaps to 1.
- else set flaps to 0.
- }
- if flaps:istype("String") {
- if list("On","All","Full"):find(flaps:trim) > -1 set flaps to 1.
- else if list("Off","None",""):find(flaps:trim) > -1 set flaps to 0.
- else if flaps:trim = "Half" set flaps to 0.5.
- else set flaps to 1.
- }
- if flaps:istype("Scalar") {
- if flaps > 1 set flaps to 1.
- if flaps < 0 set flaps to 0.
- for p in ship:partstaggedpattern("^flaps(:|$)") {
- if flaps > 0 {
- local tag_parts is p:tag:split(":").
- if tag_parts:length > 1 {
- //tonumber(0) means if the flaps setting is bad, we will effectively have NO flaps
- p:getmodule("ModuleControlSurface"):setfield("deploy angle",tag_parts[1]:tonumber(0) * flaps).
- p:getmodule("ModuleControlSurface"):setfield("deploy",true).
- } else {
- //if the tag is just "flaps" then they are either on (any value above 0) or off (value is 0).
- if flaps < 1 set flaps to 1.
- p:getmodule("ModuleControlSurface"):setfield("deploy",true).
- }
- } else {
- p:getmodule("ModuleControlSurface"):setfield("deploy",flaps).
- }
- }
- //vsr is the normal stall speed. vs0 is stall speed with full flaps.
- //we will make a linear approximation of stall speed between vs0 and vsr proportional to flaps.
- //TODO: this is saying stall speed changes based on what flap setting we WANT
- // it should be stall speed changes based on what the flaps are actually SET to.
- // i.e. we should check "deploy" and "deploy angle" compared to the tag "flaps:".
- // if "flap:###" tag was bad, and we are deploying flaps to 0, then we shoudl NOT be reducing stall speed!!!!
- set vs to vsr - (vsr - vs0) * flaps.
- //if flaps set vs to vs0.
- //else set vs to vsr.
- } else {
- print char(7) + "ERROR: unrecognised variable type " + flaps:typename + "for variable: flaps".
- }
- return control_flaps.
- }
- //merge airbrakes into spoilers for the moment.
- set control_spoilers to true.
- set spoilers to false.
- on spoilers {
- for p in ship:partstagged("spoilers") p:getmodule("ModuleControlSurface"):setfield("deploy",spoilers).
- for p in ship:partstagged("airbrakes") p:getmodule("ModuleAeroSurface"):setfield("deploy",spoilers).
- return control_spoilers.
- }
- //set airbrakes to false.
- //set control_airbrakes to true.
- //on airbrakes {
- // for p in ship:partstagged("airbrakes") p:getmodule("ModuleAeroSurface"):setfield("deploy",airbrakes).
- // return control_airbrakes.
- //}.
- on lights {
- set flaps to lights.
- return true.
- }
- function alt_radar {
- if defined alt_radar_adj return alt:radar - alt_radar_adj.
- else return alt:radar.
- }
- //compass heading of our current direction of travel. (compass travel).
- function ct {
- if airspeed < 0.1 {
- return body:geopositionof(ship:facing:vector:normalized):heading.
- } else {
- return body:geopositionof(srfprograde:vector:normalized):heading.
- }
- }
- //compass heading of the direction we are facing. (compass facing).
- function cf {
- return body:geopositionof(ship:facing:vector:normalized):heading.
- }
- // return the angle between two compass headings (second defaults to the direction we are travelling).
- // -ve means you need to subtract from the current direction of travel to get to the first headings.
- // +ve means you need to turn right (i.e.add to the current direction of travel).
- function ang {
- parameter a.
- parameter b is ct().
- //extra 720 added for a bit more resiliency against supplied angles like "-370 degrees" etc.
- return mod(720 + a-b + 180 + 360,360) - 180.
- }.
- // Use set to change these values. locking steering and THEN doing more locks on the steering variables /seems/ to cause issues.
- set x to cf().
- if alt_radar() > 10 set x to ct().
- set p to 10.
- set b to 0.
- lock steering to heading(x,p,b).
- set pitch_mode to "fixed". // used to know when we are switching from hv() to ha() so we can do a pid:reset().
- set hdg to x.
- set hdg_mode to "fixed".
- set pitch_info to p:tostring + " degrees".
- set heading_info to x:tostring + " degrees".
- set tpid to pidloop(0.5,0.01,0.1,0,1). //used for holding speed
- set vpid to pidloop(1,0.1,0.2,-45,45). //used for holding_vertical_speeed
- set apid to pidloop(0.5,0.02,0.4,-15,45). //used for holding altitude
- set rpid to pidloop(0.5,0.02,0.5,-10,60). //used for flying NOE
- set lpid to pidloop(0.2,0.02,0.05,-5,5). //used for following a line
- set gpid to pidloop(1,0.2,0.2,-45,45). // used for gliding to maintain speed using pitch.
- set spid to pidloop(1,0.2,0.2,-45,45). // use for slipping.
- set gpid:setpoint to vs + 20.
- set using_wheelsteer to false.
- set turn_dir to 0.
- set turn_force_dir to 45.
- set m_per_deg to (2 * constant():pi * body:radius) / 360.
- // return the reciprocal runway name, if it does not looke like a runway name, or there is no reciprocal, then return "".
- function recip {
- parameter r_str.
- if r_str:istype("String") {
- if r_str:matchespattern(" \d\d$") {
- local r_number is (r_str:substring(r_str:length-2,2)):tonumber.
- local r_name is r_str:substring(0,r_str:length -2).
- set r_number to mod(r_number + 18,36).
- if r_number = 0 set r_number to 36.
- if r_number < 10 set r_name to r_name + "0".
- set r_name to r_name + r_number:tostring.
- if places:haskey(r_name) return(r_name).
- else return "".
- } else {
- return "".
- }
- } else {
- return "".
- }
- }.
- set json_filename to "0:/json/" + body:name + ".json".
- if exists(json_filename) {
- set places to readjson(json_filename).
- } else if exists("0:/json/places.json") {
- set places to readjson("0:/json/places.json").
- } else {
- set places to lexicon().
- // assume we are an airplane and on the end of the runway pointing at the far end. pretty big guesses!
- local rw_num is floor(cf()/10):tostring.
- until rw_num:length >= 2 {
- set rw_num to "0" + rw_num.
- }
- places:add("Guess " + rw_num,ship:geoposition).
- set rw_num to mod(floor(cf()/10) + 18,36).
- if rw_num = 0 set rw_num to 36.
- if rw_num < 10 set r_name to r_name:string + "0".
- places:add("Guess " + rw_num, body:geopositionof(ship:geoposition:position + ship:facing:forevector * 2400)).
- }
- set runway to lexicon("enabled",false).
- set default_runway_final to 2000.
- set default_runway_touchdown to 150.
- set default_runway_turn to 1000.
- set default_runway_glideslope to 4.
- //setup_runway("KSC 27",lexicon("final",5000)).
- //setup_runway("KSC 09",lexicon("touchdown",250)).
- //setup_runway("KSC 09",lexicon("turn",1250)).
- //setup_runway("KSC 09",lexicon("slope",20)).
- //setup_runway(lexicon("start",places["KSC VAB Pad 1"],"end",places["KSC VAB Pad 2"]),lexicon("touchdown",-15)).
- function setup_runway {
- parameter rw.
- parameter opts is lexicon().
- local new_runway is lexicon("enabled",true).
- if rw:istype("String") and rw = "" {
- print char(7) + "WARNING: no runway specified".
- return 0.
- } else if rw:istype("String") and places:haskey(rw) and places:haskey(recip(rw)) {
- set new_runway["name"] to rw.
- set new_runway["start"] to places[rw].
- set new_runway["end"] to places[recip(rw)].
- } else if rw:istype("Lexicon") and rw:haskey("start") and rw:haskey("end") and rw["start"]:istype("GeoCoordinates") and rw["end"]:istype("GeoCoordinates") {
- set new_runway["start"] to rw["start"].
- set new_runway["end"] to rw["end"].
- local numbers is floor(remote_heading(new_runway["start"],new_runway["end"])/10):tostring.
- if numbers = "0" set numbers to "36".
- if numbers:length = 1 set numbers to "0" + numbers.
- set new_runway["name"] to "Lat:" + round(new_runway["start"]:lat,3) +",Lng:" + round(new_runway["end"]:lng,3) + " " + numbers.
- } else {
- print char(7) + "ERROR: runway incorrectly specified".
- return 0.
- }
- set new_runway["normalized"] to ( new_runway["end"]:position - new_runway["start"]:position ):normalized.
- set new_runway["touchdown"] to body:geopositionof(new_runway["start"]:position + new_runway["normalized"] * (choose opts["touchdown"] if opts:haskey("touchdown") else default_runway_touchdown)).
- set new_runway["final"] to body:geopositionof(new_runway["normalized"] * -(choose opts["final"] if opts:haskey("final") else default_runway_final) + new_runway["start"]:position).
- set new_runway["slope"] to (choose opts["slope"] if opts:haskey("slope") else default_runway_glideslope).
- set new_runway["right"] to body:geopositionof(
- (new_runway["normalized"] * -(choose opts["final"] if opts:haskey("final") else default_runway_final)) +
- (vcrs(up:vector,new_runway["normalized"]):normalized*(choose opts["turn"] if opts:haskey("turn") else default_runway_turn)) + new_runway["start"]:position
- ).
- set new_runway["left"] to body:geopositionof(
- ( new_runway["normalized"] * -(choose opts["final"] if opts:haskey("final") else default_runway_final)) +
- (vcrs(new_runway["normalized"],up:vector):normalized*(choose opts["turn"] if opts:haskey("turn") else default_runway_turn)) + new_runway["start"]:position
- ).
- set runway to new_runway.
- return 1.
- }
- function find_closest_runway {
- local closest_runway is "".
- local closest_distance is -1.
- for rw_name in places:keys {
- if rw_name:matchespattern(" \d\d$") {
- if recip(rw_name) <> "" {
- local dist is body:radius * constant:degtorad * vang(places[rw_name]:position - body:position, ship:position - body:position).
- if closest_distance = -1 or dist < closest_distance {
- set closest_runway to rw_name.
- set closest_distance to dist.
- }
- }
- }
- }
- return closest_runway.
- }
- if (setup_runway(find_closest_runway())) {
- if (ship:status = "landed" or ship:status = "prelaunch") and runway["start"]:distance < 250 and groundspeed < 15 {
- set hdg to runway["end"]:heading.
- //set x to runway["end"]:heading.
- }
- } else {
- set runway to lexicon("enabled",false).
- }
- //Replying to @kadin955: is there an easy way to get the angle between the line to the start of the runway, and the line of the runway , using vectory thingies ?
- //9:09Moderator9-Month Subscriber0zin: you see that "rw" vector at the start there? just vang(vxcl(up:vector,p1:position), rw)
- //lock rw to vxcl(up:vector,p2:position-p1:position):normalized.
- //given two points, work out the heading from the first to the second.
- function remote_heading {
- parameter loc_from.
- parameter loc_to.
- local d_lat is loc_to:lat - loc_from:lat.
- local d_lng is loc_to:lng - loc_from:lng.
- if d_lng > 0 return 90 - arctan(d_lat/d_lng).
- else if d_lng < 0 return 270 - arctan(d_lat/d_lng).
- else if d_lng = 0 {
- if d_lat > 0 return 0.
- else if d_lat < 0 return 180.
- else return 0.
- }
- }.
- // truncate num so that it is between min and max (inclusive). optionally, do a call back to say you did something.
- function constrain {
- parameter num.
- parameter min is -1.
- parameter max is 1.
- parameter action is "".
- if num < min {
- if not (action = "") action(num,min).
- return(min).
- } else if num > max {
- if not (action = "") action(num,max).
- return(max).
- } else {
- return num.
- }
- }
- set steeringmanager:pitchtorquefactor to 0.2.
- set steeringmanager:yawtorquefactor to 0.5.
- set steeringmanager:rollcontrolanglerange to 180.
- steeringmanager:resetpids().
- // default_bank_limit is how steep to turn if the pilot does not specify...
- // bank_limit is how steep to turn (pilot can change this value but it defaults to default_bank_limit).
- set bank_limit to default_bank_limit.
- set bank_fudge_factor to 3. // we try to bank this many degrees for every degree of heading we want to change.
- // other constraints will stop us banking that exact ammount, this will have more
- // effect at very small changes in heading angle. heading angle change of 1 deg = 3deg bank.
- set current_rudder to 0.
- //safetey features.
- set dynamic_brakes_enable to false. // when ground handling, apply/release brakes to help maintain target speeds <= 15.
- set electric_throttle_enable to false. // kick in the throttle if ship:electric charge gets too low.
- set wing_leveler_enable to true. // when lower than 40m off the ground, level the wings.
- // this gives better climb rates, and might mean avoiding touch a wingtip on the ground.
- set auto_spoilers_enable to true. // set if you want spoilers to auto operate while holding a slope with hg().
- set overspeed_spoilers_enable to false. // set if you want spoilers to deploy just based on over speed,
- set auto_gear_enable to true. // TODO: need an indicator like DBE, but... we alreayd have a gear indicator can we merge?
- set auto_wheelsteer_enable to true.
- set aoa_limit_enable to true. //Limit pitch AoA to +/- default_aoa_limit from current direction of travel.
- // 1 minute timer
- on floor(time:seconds / 60) {
- if hud_message <> "" {
- hudtext(hud_message, 15, 2, 25, purple, false).
- }
- return true.
- }
- // terrain following radar - lookahead to see what the terrain is like - and peek out to the sides a bit too.
- //Try to predict where we are heading by looking at how fast our direction of travel is changing.
- set tft_prev_hdg to ct().
- set tft_prev_time to time:seconds.
- // hold a 2d array of vectors to draw.
- set tfr_vecdraws to list().
- set tfr_lookahead to 3. // how many seconds ahead should the tfr radar look.
- function tfr {
- parameter lookahead is 3.
- local max_ht is ship:geoposition:terrainheight.
- local alpha is ang(tft_prev_hdg,ct()) * 50 * groundspeed *(time:seconds - tft_prev_time ).
- set tft_prev_time to time:seconds.
- set tft_prev_hdg to ct().
- from { local dt is 1. } until dt > lookahead step { set dt to dt + 1. } do {
- from { local base_rot is -5. } until base_rot > 5 step { set base_rot to base_rot +5. } do {
- local actual_rot is base_rot - alpha * dt.
- //local th is body:geopositionof(vxcl(ship:up,velocity:surface * dt * r(actual_rot,0,0))):terrainheight.
- local th is body:geopositionof(vxcl(up:vector,velocity:surface) * dt * r(actual_rot,0,0)):terrainheight.
- //local th is body:geopositionof(positionat(ship,time:seconds + dt )*r(actual_rot,0,0)):terrainheight.
- if dt -1 >= tfr_vecdraws:length {
- print "add row = " + (dt -1).
- tfr_vecdraws:add(list()).
- }
- if base_rot/5 + 1 >= tfr_vecdraws[dt -1]:length {
- print "add index = " + (dt -1) + "," + (base_rot/5 + 1).
- tfr_vecdraws[dt-1]:add( vecdraw(v(0,0,0),v(0,0,0),yellow,"",1,true)).
- }
- if th > max_ht {
- set max_ht to th.
- set tfr_vecdraws[dt -1][base_rot/5 +1]:color to red.
- } else {
- set tfr_vecdraws[dt -1][base_rot/5 +1]:color to yellow.
- }
- //set tfr_vecdraws[dt -1][base_rot /5 + 1]:vec to vxcl(ship:up,velocity:surface * dt * r(0,0,actual_rot)).
- set tfr_vecdraws[dt -1][base_rot /5 + 1]:vec to vxcl(up:vector,velocity:surface) * dt * r(0,0,actual_rot).
- tfr_vecdraws[dt -1][base_rot/5 +1]:show.
- }
- }
- return max_ht .
- }.
- print "DEBUG: setting up the gui".
- set the_gui to gui(300).
- set gui_fields to lexicon().
- {
- // hide some local veriables that can be thrown away.
- gui_fields:add("gui",the_gui).
- local vl is the_gui:addvlayout().
- local hl1 is vl:addhlayout().
- hl1:addlabel("Throttle:").
- gui_fields:add("speed",hl1:addtextfield(tpid:setpoint:tostring)).
- hl1:addlabel("m/s").
- gui_fields:add("stall",hl1:addlabel("<color=black>Stall</color>")).
- local hl2 is vl:addhlayout().
- hl2:addlabel("Pitch:").
- gui_fields:add("pitch_mode",hl2:addtextfield(pitch_mode)).
- set gui_fields["pitch_mode"]:style:fontsize to 10.
- gui_fields:add("pitch_info",hl2:addtextfield(p:tostring)).
- set gui_fields["pitch_info"]:STYLE:HSTRETCH TO True.
- set gui_fields["pitch_info"]:STYLE:FONTSIZE TO 10.
- local hl3 is vl:addhlayout().
- hl3:addlabel("Heading:").
- gui_fields:add("heading_mode",hl3:addtextfield(hdg_mode)).
- set gui_fields["heading_mode"]:style:fontsize to 10.
- gui_fields:add("heading_info",hl3:addtextfield(hdg:tostring)).
- set gui_fields["heading_info"]:STYLE:HSTRETCH TO True.
- set gui_fields["heading_info"]:STYLE:FONTSIZE TO 10.
- local hl4 is vl:addhlayout().
- hl4:addlabel("Bank Ang:").
- gui_fields:add("bank",hl4:addtextfield(b:tostring)).
- local lab is hl4:addlabel("Limit:").
- set lab:style:align to "RIGHT".
- gui_fields:add("bank_limit",hl4:addtextfield(bank_limit:tostring)).
- local hl5 is vl:addhlayout().
- gui_fields:add("brakes", hl5:addlabel((choose "<color=green>Brakes</color>" if brakes else "<color=black>Brakes</color>"))).
- gui_fields:add("gear", hl5:addlabel((choose "<color=green>Gear</color>" if gear else "<color=black>Gear</color>"))).
- gui_fields:add("flaps", hl5:addlabel((choose "<color=green>Flaps</color>" if flaps else "<color=black>Flaps</color>"))).
- gui_fields:add("spoilers", hl5:addlabel( (choose "<color=green>Spoilers</color>" if spoilers else "<color=black>Spoilers</color>"))).
- local hl6 is vl:addhlayout().
- gui_fields:add("revthrust",hl6:addlabel( (choose "<color=green>Reverse</color>" if revthrust else "<color=black>Reverse</color>"))).
- gui_fields:add("electric_throttle",hl6:addlabel( (choose "<color=green>ETE</color>" if electric_throttle_enable else "<color=black>ETE</color>"))).
- gui_fields:add("dynamic_brakes",hl6:addlabel( (choose "<color=green>DBE</color>" if dynamic_brakes_enable else "<color=black>DBE</color>"))).
- gui_fields:add("wing_leveler",hl6:addlabel( (choose "<color=green>WLE</color>" if wing_leveler_enable else "<color=black>WLE</color>"))).
- set the_gui:x to -100.
- set the_gui:y to 100.
- the_gui:show().
- }
- print "DEBUG: gui created.".
- set main_loop_timestamp to 0.
- set main_loop_updates_per_second to 0.
- set debug_main_loop_updates to false.
- // 1 second timer
- on time:second {
- if debug_main_loop_updates print "Main loop updates per second: " + main_loop_updates_per_second.
- //Gear at least does not mess with stallspeeds in KSP (I think!? If so it does not have much effect).
- if auto_gear_enable and alt_radar() < 80 and verticalspeed < 0 if not gear gear on.
- if gui_fields["gui"]:visible {
- local blink is false.
- if mod(time:second,2) = 0 set blink to true.
- set gui_fields["speed"]:text to tpid:setpoint:tostring.
- if ship:status <> "LANDED" and (airspeed <= vs or b >= bank_stall_angle) set gui_fields["stall"]:text to "<color=" + (choose "red" if blink else "yellow") + ">Stall</color>".
- else set gui_fields["stall"]:text to "<color=black>Stall</color>".
- set gui_fields["pitch_mode"]:text to pitch_mode.
- set gui_fields["pitch_info"]:text to pitch_info.
- set gui_fields["heading_mode"]:text to hdg_mode.
- set gui_fields["heading_info"]:text to heading_info.
- //set gui_fields["bank"]:text to round(abs(90 - vang(ship:facing:starvector,up:vector)),1):tostring + " deg".
- set gui_fields["bank"]:text to round(vang(vcrs(up:vector,vxcl(up:vector,ship:facing:forevector):normalized):normalized,ship:facing:starvector),1):tostring + " deg".
- set gui_fields["bank_limit"]:text to bank_limit:tostring + " deg".
- if brakes set gui_fields["brakes"]:text to "<color=green>Brakes</color>".
- else set gui_fields["brakes"]:text to "<color=black>Brakes</color>".
- if gear {
- if defined vlo and airspeed > vlo set gui_fields["gear"]:text to "<color=" + (choose "red" if blink else "yellow") + ">Gear</color>".
- else set gui_fields["gear"]:text to "<color=green>Gear</color>".
- } else {
- set gui_fields["gear"]:text to "<color=black>Gear</color>".
- }
- if flaps {
- if defined vfe and airspeed > vfe set gui_fields["flaps"]:text to "<color=" + (choose "red" if blink else "yellow") + ">Flaps</color>".
- else set gui_fields["flaps"]:text to "<color=green>Flaps</color>".
- } else {
- set gui_fields["flaps"]:text to "<color=black>Flaps</color>".
- }
- if spoilers set gui_fields["spoilers"]:text to "<color=green>Spoilers</color>".
- else set gui_fields["spoilers"]:text to "<color=black>Spoilers</color>".
- if revthrust set gui_fields["revthrust"]:text to "<color=green>Reverse</color>".
- else set gui_fields["revthrust"]:text to "<color=black>Reverse</color>".
- if electric_throttle_enable set gui_fields["electric_throttle"]:text to "<color=green>ETE</color>".
- else set gui_fields["electric_throttle"]:text to "<color=black>ETE</color>".
- if dynamic_brakes_enable set gui_fields["dynamic_brakes"]:text to "<color=green>DBE</color>".
- else set gui_fields["dynamic_brakes"]:text to "<color=black>DBE</color>".
- if wing_leveler_enable set gui_fields["wing_leveler"]:text to "<color=green>WLE</color>".
- else set gui_fields["wing_leveler"]:text to "<color=black>WLE</color>".
- }
- if main_loop_timestamp > 0 and main_loop_timestamp +5 < time:seconds {
- print "MAIN LOOP IS DEAD".
- }.
- return true.
- }.
- set circle_radius to 1250.
- set slip_bank_angle to -20.
- set runway_heading to 0.
- set pitch_aoa to 0.
- set side_slip to false.
- set side_slip_enable to false.
- //set runway_vecdraw to vecdraw(v(0,0,0),v(0,0,0),yellow,"",1,true,0.2,true,false).
- //set touchdown_vecdraw to vecdraw(v(0,0,0),v(0,0,0),yellow,"",1,true,0.2,false,false).
- //set touchdown_vecdraw:pointy to false.
- //set glideslope_vecdraw to vecdraw(v(0,0,0),v(0,0,0),green,"",1,true,0.2,false,false).
- //set glideslope_vecdraw:pointy to false.
- // set previous to v(0,0,0).
- // for i in range(0,trajectory:length) {
- // set trajectory[i]:start to previous:vec.
- // set trajectory[i]:vec to angleaxis( (i+0.5) * turn_rate,up:vector) * (my_horizon_forward:normalized * chord_length).
- // set previous to previous:vec + trajectory[i]:vec.
- // }
- set draw_the_runway to false.
- //slope_correction_factor is how aggressively to try to correct slope errors.
- //at 0.8, the new slope we want to fly is taking us to the correct height, (1-0.8) = 20% of the way to the target point.
- //at 0.5 we are trying to get to the correct height by the time we are half way to the target point.
- set slope_correction_factor to 0.75.
- // Fast timer
- when true then {
- // get these calculations out of the main loop... if you want to change them call setup_runway() !
- //if defined(runway) and runway["enabled"] {
- // set runway_normalized to ( runway_end:position - runway_start:position ):normalized.
- // set runway_touchdown to body:geopositionof(runway_start:position + runway_normalized * runway_touchdown_distance).
- // set runway_final to body:geopositionof(runway_normalized * -runway_final_distance + runway_start:position).
- //}
- if draw_the_runway {
- if runway["enabled"] {
- set runway_vecdraw:start to runway["start"]:position + up:vector * 3.
- set runway_vecdraw:vec to runway["end"]:position - runway["start"]:position - up:vector * runway["start"]:terrainheight + up:vector * runway["end"]:terrainheight.
- set touchdown_vecdraw:start to runway["touchdown"]:position + runway["normalized"] * 25 * angleaxis(-90,up:vector) + up:vector * 3.
- set touchdown_vecdraw:vec to runway["normalized"] * 50 *angleaxis(90,up:vector).
- set glideslope_vecdraw:start to runway["touchdown"]:position.
- set glideslope_vecdraw:vec to vxcl(up:vector,runway["normalized"]):normalized * angleaxis(180+runway["slope"] , touchdown_vecdraw:vec) * ((runway["final"]:position - runway["start"]:position):mag / cos(runway["slope"] )).
- if not(runway_vecdraw:show) or not(touchdown_vecdraw:show) or not(glideslope_vecdraw:show) {
- set runway_vecdraw:show to true.
- set touchdown_vecdraw:show to true.
- set glideslope_vecdraw:show to true.
- }
- }
- } else {
- //set runway_vecdraw:show to false.
- //set touchdown_vecdraw:show to false.
- //set glideslope_vecdraw:show to false.
- }
- set main_loop_updates_per_second to 1/(time:seconds - main_loop_timestamp).
- set main_loop_timestamp to time:seconds.
- if pitch_mode = "vert" {
- // pilot has asked to try to maintain climb/sink rate
- if aoa_limit_enable {
- local curr_pitch is 90 - vang(up:vector,ship:velocity:surface).
- set vpid:minoutput to curr_pitch - default_aoa_limit.
- set vpid:maxoutput to curr_pitch + default_aoa_limit.
- } else {
- set vpid:minoutput to -45.
- set vpid:maxoutput to 45.
- }
- set p to vpid:update(time:seconds,verticalspeed).
- } else if pitch_mode = "aoa" {
- //maintain an angle of attack.
- set p to 90 - vang(up:vector,ship:velocity:surface) + pitch_aoa.
- } else if pitch_mode = "glide" {
- of aoa_limit_enable {
- local curr_pitch is 90 - vang(up:vector,ship:velocity:surface).
- set gpid:minoutput to curr_pitch - default_aoa_limit.
- set gpid:maxoutput to curr_pitch + default_aoa_limit.
- } else {
- set gpid:minoutput to -45.
- set gpid:maxoutput to 45.
- }
- set p to -gpid:update(time:seconds,airspeed).
- } else if pitch_mode = "alt" {
- // pilot has asked to try to maintain altitude
- if aoa_limit_enable {
- local curr_pitch is 90 - vang(up:vector,ship:velocity:surface).
- set apid:minoutput to curr_pitch - default_aoa_limit.
- set apid:maxoutput to curr_pitch + default_aoa_limit.
- } else {
- set apid:minoutput to -15.
- set apid:maxoutput to 45.
- }
- set p to apid:update(time:seconds,altitude).
- } else if pitch_mode = "radar" {
- // pilot has ask to to fly NOE
- //my current thinking is to NOT follow aoa limits, since in KSP we have reaction wheels to easily enable stall recover
- //and landing gear in KSP has the ability to absorb huge impacts, and getting the gear into position is more important
- //than avoiding the stall if you are that close to the ground.
- set p to rpid:update(time:seconds,altitude - tfr(tfr_lookahead)).
- } else if pitch_mode = "slope" {
- if aoa_limit_enable {
- local curr_pitch is 90 - vang(up:vector,ship:velocity:surface).
- set vpid:minoutput to curr_pitch - default_aoa_limit.
- set vpid:maxoutput to curr_pitch + default_aoa_limit.
- } else {
- set vpid:minoutput to -45.
- set vpid:maxoutput to 45.
- }
- if runway["final"]:altitudeposition(altitude):mag <1000 and airspeed > (vc + vt)/2 hs((vc + vt)/2).
- if runway["start"]:altitudeposition(altitude):mag < 1000 and airspeed > vt hs(vt).
- if runway["start"]:altitudeposition(altitude):mag < 100 or runway["touchdown"]:altitudeposition(altitude):mag < 100 and airspeed > vtd hs(vtd).
- if alt_radar < ship:mass * -verticalspeed / flare_factor {
- print "DEBUG: Flaring!".
- set pitch_mode to "flare".
- set p to p + 3.
- flaps off.
- spoilers on.
- if debug print "flare" + char(7).
- } else {
- if debug print "A_R= " + round(alt_radar,1) + " VS=" + round(verticalspeed,1) + " TRIGGER=" + round(ship:mass * -verticalspeed / flare_factor,1).
- local actual_dist is (slope_target:position - ship:geoposition:position):mag + slope_distance_adj.
- //Trying new calculation to get the horizontal distance to touchdown target.
- local actual_dist is slope_target:altitudeposition(altitude):mag + slope_distance_adj.
- local actual_vert is altitude - slope_target:terrainheight - slope_height_adj.
- if actual_dist = 0 {
- print "DEBUG: divide by zero due to actual_dist = 0".
- }
- local actual_slope is arctan(actual_vert / actual_dist).
- local new_dist is actual_dist * (1 - slope_correction_factor).
- local new_vert is altitude - slope_target:terrainheight - slope_height_adj - ( actual_dist * tan(runway["slope"] )*slope_correction_factor).
- if airspeed = 0 {
- print "DEBUG: divide by zero due to airspeed = 0".
- }
- set vpid:setpoint to ((-new_vert)/ (new_dist / airspeed)).
- set p to vpid:update(time:seconds,verticalspeed).
- if new_dist = 0 {
- print "DEBUG: divide by zero due to new_dist = 0".
- }
- if slope_debug print "SL TGT: " + round(runway["slope"] ,1) + " ACT: " + round(actual_slope,1) + " NEW: " + round(arctan(new_vert/new_dist),1) + " VS TG=" + round(vpid:setpoint,1).
- if tpid:setpoint * 1.1 < airspeed {
- if overspeed_spoilers_enable spoilers on.
- } else if tpid:setpoint * 1.05 < airspeed and actual_slope > runway["slope"] {
- if auto_spoilers_enable spoilers on.
- } else {
- if (overspeed_spoilers_enable or auto_spoilers_enable) spoilers off.
- }.
- if side_slip_enable {
- if tpid:setpoint * 1.1 < airspeed and (actual_slope + 2) > runway["slope"] and alt_radar > 200 set side_slip to true.
- else set side_slip to false.
- }
- }
- } else if pitch_mode = "flare" {
- set pitch_info to "landing flare".
- if ship:status = "landed" {
- if flaps flaps off.
- if not spoilers spoilers on.
- set pitch_info to round(p,1) + " deg".
- set gui_fields["pitch_info"]:text to pitch_info.
- hs(0).
- hp(0).
- set pitch_mode to "landed".
- if debug print "landed".
- }
- //if verticalspeed > -0.25 set p to p -1.
- //if verticalspeed < -0.75 set p to p + 1.
- if tpid:setpoint > vtd hs(vtd).
- //set vpid:setpoint to -alt_radar /10.
- set pitch_info to round(p,1) + " degrees".
- } else if pitch_mode = "landed" {
- set pitch_info to "landed".
- print "DEBUG: not applying brakes in the main loop".
- //if not brakes brakes on.
- if groundspeed < 0.1 {
- hp(0).
- }
- } // else pitch_mode = "fixed" => just leave the pitch alone.
- if hdg_mode = "circle" {
- //TODO: support circle_target:istype("Vessel")...
- if circle_target:altitudeposition(altitude):mag > circle_radius {
- local alpha is arcsin( circle_radius / circle_target:altitudeposition(altitude):mag ).
- set hdg to circle_target:heading + (choose alpha if circle_dir = -1 else -alpha).
- } else {
- set hdg to circle_target:heading + 92 * -circle_dir.
- }
- } else if hdg_mode = "target" {
- if hdg_target:altitudeposition(altitude):mag < (2 * groundspeed) and not(hdg_target:istype("Vessel")) {
- // if we get "close", just keep flying that heading TODO: this should be more rigorous shouldn't it?
- //unless it is a vessel... then we just keep heading towards it.
- set hdg_mode to "heading".
- set heading_info to round(hdg,1):tostring + " degrees".
- } else {
- set hdg to hdg_target:heading.
- }
- } else if hdg_mode = "lineup" {
- // try a multi-stage linup method
- set runway_heading to remote_heading(runway["start"],runway["end"]).
- if runway["touchdown"]:altitudeposition(altitude):mag < 150 {
- // just fly the runway heading now. Perhaps we are doing a touch-n-go or a go-around.
- set hdg to runway["end"]:heading.
- set hdg_mode to "fixed".
- } else if runway["start"]:altitudeposition(altitude):mag < 300 or abs(ang(runway["start"]:heading,ct())) > 90 {
- //continue lineup but now target runway["touchdown"].
- set hdg to (mod(360 + runway["touchdown"]:heading + ang(runway["touchdown"]:heading,runway_heading) ,360)).
- } else if runway["final"]:altitudeposition(altitude):mag < 600 or abs(ang(runway["final"]:heading,ct())) > 90 {
- //continue lineup but now target runway["start"].
- set hdg to (mod(360 + runway["start"]:heading + ang(runway["start"]:heading,runway_heading) ,360)).
- } else {
- // aim to lineup before runway["final"]
- set hdg to (mod(360 + runway["final"]:heading + ang(runway["final"]:heading,runway_heading) ,360)).
- }
- }
- if side_slip {
- set old_b to b.
- if alt_radar < 50 {
- set side_slip_enable to false.
- set side_slip to false.
- }
- if alt_radar < 100 {
- set b to constrain(slip_bank_angle/2,old_b -3, old_b + 3).
- } else {
- set b to constrain(slip_bank_angle,old_b -3, old_b + 3).
- }
- set x to ct() + spid:update(time:seconds,ang(hdg,ct())).
- } else
- if hdg_mode = "fixed" or hdg_mode = "target" or hdg_mode = "circle" or hdg_mode = "lineup" {
- if ship:status = "PRELAUNCH" or ship:status = "LANDED" {
- set b to 0.
- set x to hdg.
- //still on the ground - try to steer, but as speed increases do a LOT less wheelsteering.
- if auto_wheelsteer_enable {
- if abs(ang(hdg,cf())) < 1 {
- set ship:control:wheelsteer to 0.
- set using_wheelsteer to false.
- } else {
- set using_wheelsteer to true.
- set ship:control:wheelsteer to constrain(
- constrain(
- -ang(hdg,cf())/10,
- -100/(groundspeed+1)^2,
- 100/(groundspeed+1)^2
- ),
- -1,
- 1
- ).
- }.
- }.
- // we might be using throttle to maintain ship:electriccharge... so using brakes on the ground could be really important.
- if dynamic_brakes_enable {
- if tpid:setpoint < 0.1 {
- brakes on.
- } else {
- if groundspeed > tpid:setpoint * 1.1 brakes on.
- if groundspeed < tpid:setpoint brakes off.
- }
- }
- } else {
- //in the air
- //if brakes brakes off.
- if using_wheelsteer {
- set ship:control:wheelsteer to 0.
- set using_wheelsteer to false.
- }.
- local bank_dir is 0.
- if hdg_mode = "circle" {
- set bank_dir to circle_dir.
- set turn_force_dir to 90.
- }
- if hdg_mode = "fixed" set bank_dir to turn_dir.
- // force a turn in a particular direction if the angle is over turn_force_dir degrees.
- // otherwise turn which ever way is smaller.
- if abs(ang(hdg,ct())) < turn_force_dir set bank_dir to 0.
- local hdg_error is ang(hdg,ct()).
- // force us to turn the other way by faking how much we need to turn :-/
- if bank_dir = -1 and hdg_error > 0 {
- set hdg_error to hdg_error - 180.
- } else if bank_dir = 1 and hdg_error < 0 {
- set hdg_error to hdg_error + 180.
- }
- // don't bank so much you stall,
- // don't exceed normal bank limits,
- // don't change bank too rapidly,
- set b to constrain(
- -hdg_error * bank_fudge_factor,
- max(-bank_stall_angle,max(-bank_limit,b - bank_change_rate)),
- min(bank_stall_angle,min(bank_limit,b + bank_change_rate))
- ).
- set target_rudder to rudder_rate * -b.
- if wing_leveler_enable {
- // don't bank steeply close to the ground.
- set b to constrain(b,-alt_radar(), alt_radar()).
- }
- set current_rudder to constrain(target_rudder,current_rudder -1, current_rudder + 1).
- set x to mod(720 + ct() + current_rudder,360).
- }
- }
- return true.
- }
- // move the runway to left (-ve) or right (+ve), x meters.
- function rs {
- parameter dist is 0.
- print char(7)+"ERROR: rs() is unavailable.".
- return.
- local offset is runway_normalized * dist * angleaxis(90,up:vector).
- set runway_start to body:geopositionof( runway_start:position + offset).
- set runway_end to body:geopositionof(runway_end:position + offset).
- }
- //move the runway d meters further away. (closer if d is negative).
- function rd {
- parameter dist is 0.
- print char(7)+"ERROR: rd() is unavailable.".
- return.
- local offset is runway_normalized * dist.
- set runway_start to body:geopositionof( runway_start:position + offset).
- set runway_end to body:geopositionof(runway_end:position + offset).
- }
- //rotate the runway thru angle rot_angle around the starting point.
- function ra {
- parameter rot_angle is 0.
- print char(7)+"ERROR: ra() is unavailable.".
- return.
- set runway_end to body:geopositionof(
- runway_start:position + (runway_end:position - runway_start:position) * angleaxis(rot_angle,up:vector)
- ).
- }
- function rf {
- local temp is runway_end.
- print char(7)+"ERROR: rf() is unavailable.".
- return.
- set runway_end to runway_start.
- set runway_start to temp.
- }
- // begin decending at slope "slope", once we are, work out where we will land, and create a "runway" there.
- function land_here {
- parameter slope is 4.
- hv(sin(slope) * airspeed).
- }
- set valid_dirs to list("left","right","either").
- // try to hold a circle - if not landmark to reference is given, circle the current location.
- //if "either" direction is given (or no direction given) then a direction has to be determined here.
- function circle {
- parameter ctgt is ship:geoposition.
- parameter radius is 1000.
- parameter dir is "either".
- if not (ctgt:hassuffix("distance") and ctgt:hassuffix("heading")) and not places:haskey(ctgt) {
- print char(7) + "ERROR: cannot circle - unrecognised target".
- return.
- }
- if valid_dirs:find(dir) = -1 {
- print char(7) + "ERROR: cannot circle - unrecognised direction".
- return.
- }
- if places:haskey(ctgt) {
- set heading_info to ctgt + " radius=" + round(circle_radius) + "m ".
- set ctgt to places[ctgt].
- } else {
- set heading_info to "LAT:" + round(ctgt:lat,3) + " LNG:" + round(ctgt:lng,3).
- }
- set hdg_mode to "circle".
- set circle_target to ctgt.
- set circle_radius to radius.
- if dir = "either" {
- if circle_target:altitudeposition(altitude):mag > circle_radius {
- set circle_dir to (choose 1 if ang(circle_target:heading,ct()) > 0 else -1).
- } else {
- set circle_dir to (choose 1 if abs(ang(circle_target:heading -90 ,ct())) < 90 else -1).
- }
- } else {
- set circle_dir to (choose -1 if dir = "left" else 1 ).
- }
- set heading_info to heading_info + (choose "left" if circle_dir < 0 else "right").
- }.
- // provide target heading, a direction to force a turn in, and a limit of how far off a heading must be before forced dir will be used.
- // i.e. if the current heading is 45, the new target heading is 50 and the force_dir is left, and force_angle is 10 we will turn right.
- // be careful setting small force angles, any perturbation of the heading could result in complete 360degree turns.
- set force_dirs to list("closest","left","right").
- function tt {
- parameter ttgt.
- parameter force_dir is "closest".
- parameter force_angle is 45.
- if force_dirs:find(force_dir) = -1 {
- print char(7) + "ERROR: " + force_dir + " is not a recognised direction".
- } else {
- set turn_force_dir to force_angle.
- if force_dir = "closest" or abs(ang(ttgt,ct())) < force_angle {
- set hdg_mode to "fixed".
- set hdg to ttgt.
- set turn_dir to 0.
- } else if force_dir = "left" {
- set hdg_mode to "fixed".
- set hdg to ttgt.
- set turn_dir to -1.
- } else if force_dir = "right" {
- set hdg_mode to "fixed".
- set hdg to ttgt.
- set turn_dir to 1.
- }
- set heading_info to hdg:tostring + " deg".
- }
- return true.
- }.
- //pilot is requesting to fly to a particular location.
- function goto {
- parameter where.
- if where:istype("String") and places:haskey(where) {
- set hdg_mode to "target".
- set hdg_target to places[where].
- set heading_info to where.
- } else if where:istype("GeoCoordinates") {
- set hdg_mode to "target".
- set hdg_target to where.
- set heading_info to "LAT:" + round(where:lat,3) + " LNG:" + round(where:lng,3).
- } else if where:istype("Vessel") {
- set heading_info to "TGT:" + where:name.
- set hdg_mode to "target".
- set hdg_target to where.
- } else {
- print "Sorry, I don't know where " + where + " is.".
- }
- return true.
- }.
- // pilot is requesting to fly NOE at a certain height off the ground.
- function hr {
- parameter rtgt.
- if pitch_mode <> "radar" {
- rpid:reset().
- set pitch_mode to "radar".
- }
- set rpid:setpoint to rtgt.
- set pitch_info to "NOE " + round(rtgt,1) + " m".
- return true.
- }.
- //pilot is requesting to hold a particular speed - if we are using throttle to maintain electric charge,
- //then when electriccharge is low, kick in enough throttle to maintain some charge!
- //in the air electric_throttle_enable might not be noticed, but on the ground a small change in throttle could
- //easily cause problems... so might be a good idea to also set dynamic_brakes_enable to true to prevent overspeeds.
- function hs {
- parameter stgt is 0.
- if stgt = "" {
- unlock throttle.
- } else {
- set tpid:setpoint to stgt.
- lock throttle to max(tpid:update(time:seconds,airspeed),choose 100 - ship:electriccharge if electric_throttle_enable else 0).
- }
- return true.
- }.
- //pilot has requested to hold a particular pitch
- function hp {
- parameter ptgt.
- set pitch_mode to "fixed".
- set p to ptgt.
- set pitch_info to round(ptgt,1) + " deg".
- return true.
- }
- //pilot is requesting to hold a particular climb/sink rate
- function hv {
- parameter vtgt.
- if pitch_mode <> "vert" and pitch_mode <> "slope" {
- vpid:reset().
- }
- set pitch_mode to "vert".
- set vpid:setpoint to vtgt.
- if vtgt < 0 {
- set pitch_info to "Descend " + round(vtgt,1) + " m/s".
- } else if vtgt > 0 {
- set pitch_info to "Climb " + round(vtgt,1) + " m/s".
- } else {
- set pitch_info to "Level Flight".
- }.
- return true.
- }.
- //hold glideslope.
- function hg {
- parameter slope is default_glideslope.
- parameter gstgt is (choose runway["touchdown"] if runway["enabled"] else "").
- parameter ht is 0.
- parameter dist is 0.
- set runway["slope"] to slope.
- set slope_target to gstgt.
- set slope_height_adj to ht.
- set slope_distance_adj to dist.
- if pitch_mode <> "vert" and pitch_mode <> "slope" {
- vpid:reset().
- }
- //main flight loop will calculate the vertspd to fly and set p accordingly.
- set pitch_mode to "slope".
- set pitch_info to round(slope,1) + " deg slope".
- return true.
- }
- function hl {
- parameter rw_name.
- parameter the_final_distance is default_runway_final.
- parameter the_touchdown_distance is default_runway_touchdown.
- parameter the_turn_radius is default_runway_turn.
- local opts is lexicon("final",the_final_distance,"touchdown",the_touchdown_distance,"turn",the_turn_radius).
- if rw_name:istype("String") and places:haskey(rw_name) and places:haskey(recip(rw_name)) {
- setup_runway(rw_name,opts).
- set heading_info to "Runway " + runway["name"].
- set hdg_mode to "lineup".
- } else if rw_name:istype("List") and rw_name:length = 2 and rw_name[0]:istype("GeoCoordinates") and rw_name[1]:istype("GeoCoordinates") {
- setup_runway(lexicon("start",rw_name[0],"end",rw_name[1]), opts).
- set heading_info to "Runway " + runway["name"].
- set hdg_mode to "lineup".
- } else {
- print char(7) + "ERROR: runway incorrectly specified".
- }
- }
- function make_runway {
- parameter slope is 3.
- print char(7) + "ERROR: make_runway is not available.".
- return.
- local sink is sin(slope) * airspeed.
- local rw_start is ship:geoposition.
- local projected_alt is altitude.
- until projected_alt < rw_start:terrainheight {
- set rw_start to body:geopositionof(rw_start:position + vxcl(up:vector,ship:velocity:surface)).
- set projected_alt to projected_alt - sink.
- }.
- set rw_end to body:geopositionof(rw_start:position + rw_start:position:normalized * 2400).
- setup_runway(lexicon("start",rw_start,"end",rw_end),lexicon("slope",slope)).
- set draw_the_runway to true.
- }
- //pilot is requesting to hold a particular altitude.
- function ha {
- parameter atgt.
- if pitch_mode <> "alt" {
- apid:reset().
- set pitch_mode to "alt".
- }
- set apid:setpoint to atgt.
- set pitch_info to "" + round(atgt,1) + " m".
- }.
- function haoa {
- parameter tgt.
- set pitch_mode to "aoa".
- set pitch_aoa to tgt.
- set pitch_info to "" + round(tgt,1) + " deg".
- }
- function hm {
- parameter spd is vs.
- set gpid:setpoint to spd.
- if pitch_mode <> "glide" gpid:reset().
- set pitch_mode to "glide".
- set pitch_info to "Speed: " + spd.
- }
- function takeoff_and_land {
- set bank_limit to 30.
- stage.
- brakes off.
- hs(100).
- hv(10).
- set flaps to 0.5.
- tt(runway["end"]:heading).
- when altitude > 100 then hv(9).
- when altitude > 120 then hv(8).
- when altitude > 160 then hv(7).
- when altitude > 200 then hv(6).
- when altitude > 240 then hv(5).
- when altitude > 280 then hv(4).
- when altitude > 310 then hv(3).
- when altitude > 330 then hv(2).
- when altitude > 340 then hv(1).
- when altitude > 345 then ha(350).
- when alt:radar > 25 then gear off.
- when airspeed > 60 then flaps off.
- when airspeed > 75 then {
- tt(275).
- when abs(ang(ct(),275)) < 10 and abs(ang(ct(),runway["start"]:heading)) > 135 then {
- hl(runway["name"]).
- hg(4,runway["touchdown"]).
- when runway["start"]:distance < 2000 then {
- flaps on.
- hs(vt + 10).
- }
- when runway["start"]:distance < 500 then hs(vt).
- when runway["touchdown"]:distance < 250 then hs(vtd).
- on ship:status {
- revthrust on.
- hs(1000).
- flaps off.
- spoilers on.
- when groundspeed < 10 then {
- revthrust off.
- hs(0).
- // ready to taxi
- wait 5.
- brakes on.
- }.
- }.
- }.
- }.
- }.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement