Advertisement
sumguytwitches

oddtest

Sep 9th, 2021 (edited)
93
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. set k_autopilot2_version to "0.9.3".
  2. print "Kadin's autopilot2 V" + k_autopilot2_version:tostring.
  3.  
  4.  
  5. set debug to false.
  6. set slope_debug to true.
  7.  
  8. ///
  9. /// set aoa to 72. lock steering to srfprograde * r(-aoa, 0,0)
  10. ///
  11.  
  12. print "There are three versions of this code.".
  13. print "Unstable/development version, newest features, newest bugs: !runscript NHwvPAp3".
  14. print "Recent working version, seems like it is fairly stable: !runscript 0pgtewL5".
  15. print "Oldest version, least features but also fairly stable: !runscript dHtuDeGx".
  16.  
  17. // 2021-09-05: completely re-wrote setup_runway and changed all references to variables matching regexp("^runway").
  18. // added variable flaps, while maintaining flaps on/off and toggle flaps.
  19. // you can do : set flaps to "full", "half" or "none".
  20. // you cat set flaps to 0.5.
  21. // BUT it only works when the flaps tag is "flaps:NUMBER" where number is the full scale deflection angle.
  22. // So if you want full flaps to be 23, then set the tag to "flaps:23".
  23. // added landing flare.
  24. // added aoa_limit_enable - stop craft from pitching beyond aoa limits.
  25. // - NOTE: the current aoa limit stuff is WRONG
  26. // - AoA has nothing to do with your angle to "up"... yet this is what I do.
  27. // - I know it is wrong, but i'll fix it later and it's better than nothing.
  28. // added function haoa() - hold angle of attack.
  29. // added SG Explorer and various other craft
  30. // latest change: added setup_runway function.
  31. //latest change: hl() for hold line.: hl(runway_west,runway_east).
  32. //latest change: blurb about version of the code.
  33. //latest change: added hg() for hold glideslope: hg(target_slope, ground_target, voffset, hoffset).
  34.  
  35. set bank_change_rate to 3. // How fast we change between bank angles .
  36. set rudder_rate to 0.4. // How much rudder to kick in to help increase the turn rate.
  37. set default_bank_limit to 40. // This is how many degrees of bank for a turn if none are specified.
  38. set default_aoa_limit to 15. // aoa limit +/-
  39. 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!".
  40.  
  41.  
  42. set flare_factor to ship:mass/5.
  43. if ship:name:startswith("Mallard") {
  44. set vs to 65. // stall speed in level flight - complete guess.
  45. set vsr to 60. //normal stall speed.
  46. set vs0 to 40. //stall speed with flaps out
  47. set vto to 100. //take off speed
  48. set vfe to 65. //speed above which you would remove flaps.
  49. set vlo to 60. //speed below which you CAN extend/retract gear.
  50. set vc to 80. //cruise speed.
  51. set vt to 45. //threshold speed.
  52. set vtd to 40. //touchdown speed.
  53. set alt_radar_adj to 3.0433.
  54.  
  55. set bank_limit to 40.
  56.  
  57. //Setup small outboard aerosurfaces
  58. for p in ship:partsnamed("smallCtrlSrf") p:getmodule("ModuleControlSurface"):setfield("deploy",false).
  59. for p in ship:partsnamed("smallCtrlSrf") p:getmodule("ModuleControlSurface"):setfield("deploy direction",true).
  60. //max out authority limiter if we are able to.
  61. for p in ship:partsnamed("smallCtrlSrf") { local m is p:getmodule("ModuleControlSurface"). if m:hasfield("authority limiter") m:setfield("authority limiter",100). }.
  62. //Setup Large elevons.
  63. for p in ship:partsnamed("airlinerCtrlSrf") p:getmodule("ModuleControlSurface"):setfield("deploy",false).
  64. for p in ship:partsnamed("airlinerCtrlSrf") p:getmodule("ModuleControlSurface"):setfield("deploy direction",true).
  65. if exists("0:/Kadins_local_KSP.txt") { // in my own stock KSP, for some reason these elevons have deploy direction flipped.
  66. for p in ship:partsnamed("airlinerCtrlSrf") {
  67. if p:position:mag < 6 p:getmodule("ModuleControlSurface"):setfield("deploy direction",false).
  68. }
  69. }
  70. //max out authority limiter if we are able to.
  71. for p in ship:partsnamed("airlinerCtrlSrf") { local m is p:getmodule("ModuleControlSurface"). if m:hasfield("authority limiter") m:setfield("authority limiter",100). }.
  72.  
  73. //set up tail fins
  74. for p in ship:partsnamed("tailfin") p:getmodule("ModuleControlSurface"):setfield("deploy",false).
  75. for p in ship:partsnamed("tailfin") p:getmodule("ModuleControlSurface"):setfield("deploy direction",false).
  76. //max out authority limiter if we are able to.
  77. for p in ship:partsnamed("tailfin") { local m is p:getmodule("ModuleControlSurface"). if m:hasfield("authority limiter") m:setfield("authority limiter",100). }.
  78.  
  79. //use large elevons as flaps (with deploy angle to 100% of available authority).
  80. 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") ). }.
  81. for p in ship:partsnamed("airlinerCtrlSrf") set p:tag to "flaps:" + p:getmodule("ModuleControlSurface"):getfield("deploy angle").
  82. //for p in ship:partstaggedpattern("^flaps(:|$)") print "TAG = " + p:tag.
  83.  
  84. //use tail fins as spoilers (with deploy angle to 80% of available authority)
  85. 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") ). }.
  86. for p in ship:partsnamed("tailfin") set p:tag to "spoilers".
  87.  
  88. // at one stage I was only using some of the large elevons for flaps...
  89. // p:position:mag < 6 is the inboard elevons
  90. // p:position:mag > 6 and < 8 is the middle elevons
  91. // p:position:mag > 8 is the outer large elevons.
  92.  
  93.  
  94. //setup airbrakes
  95. for p in ship:partsnamed("airbrake1") set p:tag to "airbrakes".
  96. for p in ship:partstagged("airbrakes") p:getmodule("ModuleAeroSurface"):setfield("deploy",false).
  97.  
  98. //setup brakes
  99. for p in ship:partsnamed("GearMedium") p:getmodule("ModuleWheelBrakes"):setfield("brakes",75).
  100. for p in ship:partsnamed("SmallGearBay") p:getmodule("ModuleWheelBrakes"):setfield("brakes",25).
  101.  
  102. //setup reversable jets
  103. for p in ship:partsnamed("JetEngine") set p:tag to "jets".
  104.  
  105. } else if ship:name:startswith("Aeris 3A") {
  106. set alt_radar_adj to 1.410271525383.
  107. for p in ship:partsnamed("R8winglet") if p:position:mag < 4 p:getmodule("ModuleControlSurface"):setfield("deploy angle",10).
  108. for p in ship:partsnamed("R8winglet") if p:position:mag < 4 set p:tag to "flaps".
  109. for p in ship:partsnamed("elevon3") p:getmodule("ModuleControlSurface"):setfield("deploy angle",15).
  110. for p in ship:partsnamed("elevon3") set p:tag to "flaps".
  111. for p in ship:partsnamed("R8winglet") { if p:position:mag > 4 p:getmodule("ModuleControlSurface"):setfield("deploy angle",15). }
  112. for p in ship:partsnamed("R8winglet") if p:position:mag > 4 set p:tag to "spoilers".
  113. for p in ship:partsnamed("JetEngine") set p:tag to "jets".
  114. for p in ship:partsnamed("SmallGearBay") if p:position:mag > 2 p:getmodule("ModuleWheelBrakes"):setfield("brakes",25). else p:getmodule("ModuleWheelBrakes"):setfield("brakes",100).
  115. set bank_limit to 60.
  116. set vs to 32.
  117. set vsr to 32.
  118. set vs0 to 32.
  119. set vfe to 35.
  120. set vlo to 35.
  121. set vto to 75.
  122. set vc to 60.
  123. set vtd to 32.
  124. set vt to 35.
  125. } else if ship:name:startswith("Lockheed Jetstar") {
  126. set alt_radar_adj to 1.6479332447952.
  127. for p in ship:partsnamed("SmallGearBay") if p:position:mag < 2 p:getmodule("ModuleWheelBrakes"):setfield("brakes",100). else p:getmodule("ModuleWheelBrakes"):setfield("brakes",25).
  128. set bank_limit to 50.
  129. set vs to 60.
  130. set vsr to 60.
  131. set vs0 to 60.
  132. set vfe to 65.
  133. set vlo to 65.
  134. set vto to 100.
  135. set vc to 80.
  136. set vtd to 60.
  137. set vt to 60.
  138. set vrot to 60.
  139. } else if ship:name:startswith("Reusable Moons Rocketship") {
  140. set bank_limit to 30.
  141. set alt_radar_adj to 4.58227.
  142. // can glide (constant airspeed) at about a -28 pitch down orientation.
  143. for p in ship:partsnamedpattern("gear") if p:position:mag < 7 p:getmodule("ModuleWheelBrakes"):setfield("brakes",200).
  144. // the shuttle rudder defaults to deploy angle 37.5 deg. but it only has an authority limiter of 9.75 deg.
  145. // so I'm assuming you will lose control authority if you deploy the tail fins as a speed brake.
  146. // also they both have deploy direction set to false... which I think will mean they don't activate opposite directions???
  147. // mpore experimentation is required.
  148. for p in ship:partsnamed("wingShuttleRudder") set p:tag to "spoilers".
  149. set vs to 75.
  150. set vsr to 75.
  151. set vs0 to 75.
  152. set vfe to 100.
  153. set vlo to 100.
  154. set vto to 150.
  155. set vc to 125.
  156. set vtd to 80.
  157. set vt to 90.
  158. } else if ship:name:startswith("SG Rescue 2") {
  159. //AG1 = rapier engine
  160. //ag2 = toggle rapier mode
  161. //ag3 = airbrakes.
  162. //ag5 = cargobay
  163. //ag7,9,10 do drill stuff.
  164. // enable nuclear engines with: list engines in es. for e in es if e:name:contains("nuc") e:activate
  165. //show engine mode for rapiers: list engines in es. for e in es if e:multimode print e:mode
  166. //All engines on: list engines in es. for e in es e:activate
  167. //use execute_node_old for any multi egine craft with some engines on or off or jet engines in space etc...
  168. //extend antenna: for a in ship:modulesnamed("ModuleDeployableAntenna") a:DoAction("extend antenna", true)
  169. set alt_radar_adj to 6.
  170. set vs to 120.
  171. set vsr to 120.
  172. set vs0 to 120.
  173. set vfe to 120.
  174. set vlo to 120.
  175. set vto to 120.
  176. set vc to 120.
  177. set vtd to 120.
  178. set vt to 120.
  179. } else if ship:name:startswith("roach") {
  180. set alt_radar_adj to 1.90005767345428.
  181. // vertical stabilizers only have authority limiter = 15 so 10 for spoilers is about the most you can use safely.
  182. for p in ship:partsnamed("R8winglet") if p:position:mag > 3.3 p:getmodule("ModuleControlSurface"):setfield("deploy angle",10).
  183. for p in ship:partsnamed("R8winglet") if p:position:mag > 3.3 set p:tag to "spoilers".
  184. for p in ship:partsnamed("SmallGearBay") if p:position:mag < 1.2 p:getmodule("ModuleWheelBrakes"):setfield("brakes",25).
  185. set vs to 30.
  186. set vsr to 30.
  187. set vs0 to 30.
  188. set vfe to 60.
  189. set vlo to 60.
  190. set vto to 60.
  191. set vc to 100.
  192. set vtd to 30.
  193. set vt to 35.
  194. //set apid:KP to 0.2.
  195. //set apid:KI to 0.1.
  196. //set apid:KD to 0.2.
  197. //top speed around 876 at 2500m.
  198. } else if ship:name:startswith("SG Explorer") {
  199. set alt_radar_adj to 3.75.
  200. //for p in ship:partsnamed("SmallGearBay") p:getmodule("ModuleWheelBrakes"):setfield("brakes",0).
  201. for p in ship:partsnamed("airbrake1") set p:tag to "airbrakes".
  202. set sus to ship:modulesnamed("ModuleWheelSuspension").
  203. for w in sus { if w:hasevent("spring/damper: auto") w:doevent("spring/damper: auto").}.
  204. for w in sus { w:setfield("spring strength",2). w:setfield("damper strength",2).}.
  205. set sus to ship:modulesnamed("ModuleWheelBase").
  206. for w in sus { if w:hasevent("friction control: auto") w:doevent("friction control: auto").}.
  207. for w in sus { w:setfield("friction control",1).}.
  208. for m in ship:modulesnamed("ModuleWheelBrakes") m:setfield("brakes",200).
  209. set vs to 90.
  210. set vsr to 90.
  211. set vs0 to 90.
  212. set vfe to 120.
  213. set vlo to 120.
  214. set vto to 100. // rotate at 90? 95?
  215. set vc to 150.
  216. set vtd to 95.
  217. set vt to 100.
  218. set STEERINGMANAGER:MAXSTOPPINGTIME to 20.
  219. set steeringmanager:rollpid:kd to 1.
  220. set bank_change_rate to 1.
  221. set steeringmanager:rollpid:ki to 0.1. set steeringmanager:rollpid:kd to 0.2. set steeringmanager:rollpid:kp to 0.4.
  222. } else {
  223. set vs to 100.
  224. set vsr to 100.
  225. set vs0 to 100.
  226. set vfe to 120.
  227. set vlo to 120.
  228. set vto to 120.
  229. set vc to 150.
  230. set vtd to 95.
  231. set vt to 100.
  232. set alt_radar_adj to 5.
  233. }
  234.  
  235.  
  236. // anomoly scanner.
  237. //set as to addons:scansat:getanomalies(body). for anomaly in as print anomaly:name:padright(20) + anomaly:geoposition
  238.  
  239.  
  240. // flying a heading near the pole:
  241. //lock srfheading to body:geopositionof(srfprograde:vector:normalized):heading
  242. // lock x to srfheading + turnrate.
  243.  
  244. // stall speed increases at high bank angles. Keep this updated so we can refer to this increased stall speed.
  245. lock bank_stall_angle to arccos(vs^2/max(vs,airspeed)^2).
  246.  
  247.  
  248. set control_revthrust to true.
  249. set revthrust to false.
  250. on revthrust {
  251. for p in ship:partstagged("jets") {
  252. local m is p:getmodule("ModuleAnimateGeneric").
  253. if revthrust and m:hasevent("reverse thr" + "ust") m:doevent("reverse thr" + "ust").
  254. else if m:hasevent("forward thr" + "ust") m:doevent("forward thr" + "ust").
  255. }
  256. return control_revthrust.
  257. }
  258.  
  259. //on flaps {
  260. // for p in ship:partstagged("flaps") p:getmodule("ModuleControlSurface"):setfield("deploy",flaps).
  261. // if flaps set vs to vs0.
  262. // else set vs to vsr.
  263. // return true.
  264. //}
  265.  
  266.  
  267. // allow flaps to be set to other values.
  268. set control_flaps to true.
  269. set flaps to 0.
  270. on flaps {
  271. if flaps:istype("Boolean") {
  272. if flaps set flaps to 1.
  273. else set flaps to 0.
  274. }
  275. if flaps:istype("String") {
  276. if list("On","All","Full"):find(flaps:trim) > -1 set flaps to 1.
  277. else if list("Off","None",""):find(flaps:trim) > -1 set flaps to 0.
  278. else if flaps:trim = "Half" set flaps to 0.5.
  279. else set flaps to 1.
  280. }
  281. if flaps:istype("Scalar") {
  282. if flaps > 1 set flaps to 1.
  283. if flaps < 0 set flaps to 0.
  284. for p in ship:partstaggedpattern("^flaps(:|$)") {
  285. if flaps > 0 {
  286. local tag_parts is p:tag:split(":").
  287. if tag_parts:length > 1 {
  288. //tonumber(0) means if the flaps setting is bad, we will effectively have NO flaps
  289. p:getmodule("ModuleControlSurface"):setfield("deploy angle",tag_parts[1]:tonumber(0) * flaps).
  290. p:getmodule("ModuleControlSurface"):setfield("deploy",true).
  291. } else {
  292. //if the tag is just "flaps" then they are either on (any value above 0) or off (value is 0).
  293. if flaps < 1 set flaps to 1.
  294. p:getmodule("ModuleControlSurface"):setfield("deploy",true).
  295. }
  296. } else {
  297. p:getmodule("ModuleControlSurface"):setfield("deploy",flaps).
  298. }
  299. }
  300. //vsr is the normal stall speed. vs0 is stall speed with full flaps.
  301. //we will make a linear approximation of stall speed between vs0 and vsr proportional to flaps.
  302. //TODO: this is saying stall speed changes based on what flap setting we WANT
  303. // it should be stall speed changes based on what the flaps are actually SET to.
  304. // i.e. we should check "deploy" and "deploy angle" compared to the tag "flaps:".
  305. // if "flap:###" tag was bad, and we are deploying flaps to 0, then we shoudl NOT be reducing stall speed!!!!
  306. set vs to vsr - (vsr - vs0) * flaps.
  307. //if flaps set vs to vs0.
  308. //else set vs to vsr.
  309. } else {
  310. print char(7) + "ERROR: unrecognised variable type " + flaps:typename + "for variable: flaps".
  311. }
  312. return control_flaps.
  313. }
  314.  
  315. //merge airbrakes into spoilers for the moment.
  316. set control_spoilers to true.
  317. set spoilers to false.
  318. on spoilers {
  319. for p in ship:partstagged("spoilers") p:getmodule("ModuleControlSurface"):setfield("deploy",spoilers).
  320. for p in ship:partstagged("airbrakes") p:getmodule("ModuleAeroSurface"):setfield("deploy",spoilers).
  321. return control_spoilers.
  322. }
  323.  
  324. //set airbrakes to false.
  325. //set control_airbrakes to true.
  326. //on airbrakes {
  327. // for p in ship:partstagged("airbrakes") p:getmodule("ModuleAeroSurface"):setfield("deploy",airbrakes).
  328. // return control_airbrakes.
  329. //}.
  330.  
  331. on lights {
  332. set flaps to lights.
  333. return true.
  334. }
  335.  
  336.  
  337. function alt_radar {
  338. if defined alt_radar_adj return alt:radar - alt_radar_adj.
  339. else return alt:radar.
  340. }
  341.  
  342. //compass heading of our current direction of travel. (compass travel).
  343. function ct {
  344. if airspeed < 0.1 {
  345. return body:geopositionof(ship:facing:vector:normalized):heading.
  346. } else {
  347. return body:geopositionof(srfprograde:vector:normalized):heading.
  348. }
  349. }
  350.  
  351. //compass heading of the direction we are facing. (compass facing).
  352. function cf {
  353. return body:geopositionof(ship:facing:vector:normalized):heading.
  354. }
  355.  
  356. // return the angle between two compass headings (second defaults to the direction we are travelling).
  357. // -ve means you need to subtract from the current direction of travel to get to the first headings.
  358. // +ve means you need to turn right (i.e.add to the current direction of travel).
  359. function ang {
  360. parameter a.
  361. parameter b is ct().
  362. //extra 720 added for a bit more resiliency against supplied angles like "-370 degrees" etc.
  363. return mod(720 + a-b + 180 + 360,360) - 180.
  364. }.
  365.  
  366. // Use set to change these values. locking steering and THEN doing more locks on the steering variables /seems/ to cause issues.
  367. set x to cf().
  368. if alt_radar() > 10 set x to ct().
  369. set p to 10.
  370. set b to 0.
  371. lock steering to heading(x,p,b).
  372. set pitch_mode to "fixed". // used to know when we are switching from hv() to ha() so we can do a pid:reset().
  373. set hdg to x.
  374. set hdg_mode to "fixed".
  375. set pitch_info to p:tostring + " degrees".
  376. set heading_info to x:tostring + " degrees".
  377.  
  378. set tpid to pidloop(0.5,0.01,0.1,0,1). //used for holding speed
  379. set vpid to pidloop(1,0.1,0.2,-45,45). //used for holding_vertical_speeed
  380. set apid to pidloop(0.5,0.02,0.4,-15,45). //used for holding altitude
  381. set rpid to pidloop(0.5,0.02,0.5,-10,60). //used for flying NOE
  382. set lpid to pidloop(0.2,0.02,0.05,-5,5). //used for following a line
  383. set gpid to pidloop(1,0.2,0.2,-45,45). // used for gliding to maintain speed using pitch.
  384. set spid to pidloop(1,0.2,0.2,-45,45). // use for slipping.
  385. set gpid:setpoint to vs + 20.
  386.  
  387. set using_wheelsteer to false.
  388. set turn_dir to 0.
  389. set turn_force_dir to 45.
  390. set m_per_deg to (2 * constant():pi * body:radius) / 360.
  391.  
  392. // return the reciprocal runway name, if it does not looke like a runway name, or there is no reciprocal, then return "".
  393. function recip {
  394. parameter r_str.
  395. if r_str:istype("String") {
  396. if r_str:matchespattern(" \d\d$") {
  397. local r_number is (r_str:substring(r_str:length-2,2)):tonumber.
  398. local r_name is r_str:substring(0,r_str:length -2).
  399. set r_number to mod(r_number + 18,36).
  400. if r_number = 0 set r_number to 36.
  401. if r_number < 10 set r_name to r_name + "0".
  402. set r_name to r_name + r_number:tostring.
  403. if places:haskey(r_name) return(r_name).
  404. else return "".
  405. } else {
  406. return "".
  407. }
  408. } else {
  409. return "".
  410. }
  411. }.
  412.  
  413. set json_filename to "0:/json/" + body:name + ".json".
  414. if exists(json_filename) {
  415. set places to readjson(json_filename).
  416. } else if exists("0:/json/places.json") {
  417. set places to readjson("0:/json/places.json").
  418. } else {
  419. set places to lexicon().
  420. // assume we are an airplane and on the end of the runway pointing at the far end. pretty big guesses!
  421. local rw_num is floor(cf()/10):tostring.
  422. until rw_num:length >= 2 {
  423. set rw_num to "0" + rw_num.
  424. }
  425. places:add("Guess " + rw_num,ship:geoposition).
  426. set rw_num to mod(floor(cf()/10) + 18,36).
  427. if rw_num = 0 set rw_num to 36.
  428. if rw_num < 10 set r_name to r_name:string + "0".
  429. places:add("Guess " + rw_num, body:geopositionof(ship:geoposition:position + ship:facing:forevector * 2400)).
  430. }
  431.  
  432. set runway to lexicon("enabled",false).
  433. set default_runway_final to 2000.
  434. set default_runway_touchdown to 150.
  435. set default_runway_turn to 1000.
  436. set default_runway_glideslope to 4.
  437.  
  438. //setup_runway("KSC 27",lexicon("final",5000)).
  439. //setup_runway("KSC 09",lexicon("touchdown",250)).
  440. //setup_runway("KSC 09",lexicon("turn",1250)).
  441. //setup_runway("KSC 09",lexicon("slope",20)).
  442. //setup_runway(lexicon("start",places["KSC VAB Pad 1"],"end",places["KSC VAB Pad 2"]),lexicon("touchdown",-15)).
  443. function setup_runway {
  444. parameter rw.
  445. parameter opts is lexicon().
  446.  
  447. local new_runway is lexicon("enabled",true).
  448. if rw:istype("String") and rw = "" {
  449. print char(7) + "WARNING: no runway specified".
  450. return 0.
  451. } else if rw:istype("String") and places:haskey(rw) and places:haskey(recip(rw)) {
  452. set new_runway["name"] to rw.
  453. set new_runway["start"] to places[rw].
  454. set new_runway["end"] to places[recip(rw)].
  455. } else if rw:istype("Lexicon") and rw:haskey("start") and rw:haskey("end") and rw["start"]:istype("GeoCoordinates") and rw["end"]:istype("GeoCoordinates") {
  456. set new_runway["start"] to rw["start"].
  457. set new_runway["end"] to rw["end"].
  458. local numbers is floor(remote_heading(new_runway["start"],new_runway["end"])/10):tostring.
  459. if numbers = "0" set numbers to "36".
  460. if numbers:length = 1 set numbers to "0" + numbers.
  461. set new_runway["name"] to "Lat:" + round(new_runway["start"]:lat,3) +",Lng:" + round(new_runway["end"]:lng,3) + " " + numbers.
  462. } else {
  463. print char(7) + "ERROR: runway incorrectly specified".
  464. return 0.
  465. }
  466. set new_runway["normalized"] to ( new_runway["end"]:position - new_runway["start"]:position ):normalized.
  467. 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)).
  468. 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).
  469. set new_runway["slope"] to (choose opts["slope"] if opts:haskey("slope") else default_runway_glideslope).
  470. set new_runway["right"] to body:geopositionof(
  471. (new_runway["normalized"] * -(choose opts["final"] if opts:haskey("final") else default_runway_final)) +
  472. (vcrs(up:vector,new_runway["normalized"]):normalized*(choose opts["turn"] if opts:haskey("turn") else default_runway_turn)) + new_runway["start"]:position
  473. ).
  474. set new_runway["left"] to body:geopositionof(
  475. ( new_runway["normalized"] * -(choose opts["final"] if opts:haskey("final") else default_runway_final)) +
  476. (vcrs(new_runway["normalized"],up:vector):normalized*(choose opts["turn"] if opts:haskey("turn") else default_runway_turn)) + new_runway["start"]:position
  477. ).
  478. set runway to new_runway.
  479. return 1.
  480. }
  481.  
  482.  
  483. function find_closest_runway {
  484. local closest_runway is "".
  485. local closest_distance is -1.
  486. for rw_name in places:keys {
  487. if rw_name:matchespattern(" \d\d$") {
  488. if recip(rw_name) <> "" {
  489. local dist is body:radius * constant:degtorad * vang(places[rw_name]:position - body:position, ship:position - body:position).
  490.  
  491. if closest_distance = -1 or dist < closest_distance {
  492. set closest_runway to rw_name.
  493. set closest_distance to dist.
  494. }
  495. }
  496. }
  497. }
  498. return closest_runway.
  499. }
  500.  
  501. if (setup_runway(find_closest_runway())) {
  502. if (ship:status = "landed" or ship:status = "prelaunch") and runway["start"]:distance < 250 and groundspeed < 15 {
  503. set hdg to runway["end"]:heading.
  504. //set x to runway["end"]:heading.
  505. }
  506. } else {
  507. set runway to lexicon("enabled",false).
  508. }
  509.  
  510.  
  511. //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 ?
  512.  
  513. //9:09Moderator9-Month Subscriber0zin: you see that "rw" vector at the start there? just vang(vxcl(up:vector,p1:position), rw)
  514. //lock rw to vxcl(up:vector,p2:position-p1:position):normalized.
  515.  
  516.  
  517. //given two points, work out the heading from the first to the second.
  518. function remote_heading {
  519. parameter loc_from.
  520. parameter loc_to.
  521.  
  522. local d_lat is loc_to:lat - loc_from:lat.
  523. local d_lng is loc_to:lng - loc_from:lng.
  524.  
  525. if d_lng > 0 return 90 - arctan(d_lat/d_lng).
  526. else if d_lng < 0 return 270 - arctan(d_lat/d_lng).
  527. else if d_lng = 0 {
  528. if d_lat > 0 return 0.
  529. else if d_lat < 0 return 180.
  530. else return 0.
  531. }
  532. }.
  533.  
  534.  
  535.  
  536. // truncate num so that it is between min and max (inclusive). optionally, do a call back to say you did something.
  537. function constrain {
  538. parameter num.
  539. parameter min is -1.
  540. parameter max is 1.
  541. parameter action is "".
  542. if num < min {
  543. if not (action = "") action(num,min).
  544. return(min).
  545. } else if num > max {
  546. if not (action = "") action(num,max).
  547. return(max).
  548. } else {
  549. return num.
  550. }
  551. }
  552.  
  553. set steeringmanager:pitchtorquefactor to 0.2.
  554. set steeringmanager:yawtorquefactor to 0.5.
  555. set steeringmanager:rollcontrolanglerange to 180.
  556. steeringmanager:resetpids().
  557.  
  558. // default_bank_limit is how steep to turn if the pilot does not specify...
  559. // bank_limit is how steep to turn (pilot can change this value but it defaults to default_bank_limit).
  560. set bank_limit to default_bank_limit.
  561.  
  562. set bank_fudge_factor to 3. // we try to bank this many degrees for every degree of heading we want to change.
  563. // other constraints will stop us banking that exact ammount, this will have more
  564. // effect at very small changes in heading angle. heading angle change of 1 deg = 3deg bank.
  565.  
  566. set current_rudder to 0.
  567.  
  568. //safetey features.
  569. set dynamic_brakes_enable to false. // when ground handling, apply/release brakes to help maintain target speeds <= 15.
  570. set electric_throttle_enable to false. // kick in the throttle if ship:electric charge gets too low.
  571. set wing_leveler_enable to true. // when lower than 40m off the ground, level the wings.
  572. // this gives better climb rates, and might mean avoiding touch a wingtip on the ground.
  573. set auto_spoilers_enable to true. // set if you want spoilers to auto operate while holding a slope with hg().
  574. set overspeed_spoilers_enable to false. // set if you want spoilers to deploy just based on over speed,
  575. set auto_gear_enable to true. // TODO: need an indicator like DBE, but... we alreayd have a gear indicator can we merge?
  576. set auto_wheelsteer_enable to true.
  577. set aoa_limit_enable to true. //Limit pitch AoA to +/- default_aoa_limit from current direction of travel.
  578.  
  579. // 1 minute timer
  580. on floor(time:seconds / 60) {
  581. if hud_message <> "" {
  582. hudtext(hud_message, 15, 2, 25, purple, false).
  583. }
  584. return true.
  585. }
  586.  
  587. // terrain following radar - lookahead to see what the terrain is like - and peek out to the sides a bit too.
  588. //Try to predict where we are heading by looking at how fast our direction of travel is changing.
  589. set tft_prev_hdg to ct().
  590. set tft_prev_time to time:seconds.
  591.  
  592. // hold a 2d array of vectors to draw.
  593. set tfr_vecdraws to list().
  594. set tfr_lookahead to 3. // how many seconds ahead should the tfr radar look.
  595.  
  596.  
  597. function tfr {
  598. parameter lookahead is 3.
  599. local max_ht is ship:geoposition:terrainheight.
  600. local alpha is ang(tft_prev_hdg,ct()) * 50 * groundspeed *(time:seconds - tft_prev_time ).
  601. set tft_prev_time to time:seconds.
  602. set tft_prev_hdg to ct().
  603. from { local dt is 1. } until dt > lookahead step { set dt to dt + 1. } do {
  604. from { local base_rot is -5. } until base_rot > 5 step { set base_rot to base_rot +5. } do {
  605. local actual_rot is base_rot - alpha * dt.
  606. //local th is body:geopositionof(vxcl(ship:up,velocity:surface * dt * r(actual_rot,0,0))):terrainheight.
  607. local th is body:geopositionof(vxcl(up:vector,velocity:surface) * dt * r(actual_rot,0,0)):terrainheight.
  608. //local th is body:geopositionof(positionat(ship,time:seconds + dt )*r(actual_rot,0,0)):terrainheight.
  609. if dt -1 >= tfr_vecdraws:length {
  610. print "add row = " + (dt -1).
  611. tfr_vecdraws:add(list()).
  612. }
  613. if base_rot/5 + 1 >= tfr_vecdraws[dt -1]:length {
  614. print "add index = " + (dt -1) + "," + (base_rot/5 + 1).
  615. tfr_vecdraws[dt-1]:add( vecdraw(v(0,0,0),v(0,0,0),yellow,"",1,true)).
  616. }
  617. if th > max_ht {
  618. set max_ht to th.
  619. set tfr_vecdraws[dt -1][base_rot/5 +1]:color to red.
  620. } else {
  621. set tfr_vecdraws[dt -1][base_rot/5 +1]:color to yellow.
  622. }
  623. //set tfr_vecdraws[dt -1][base_rot /5 + 1]:vec to vxcl(ship:up,velocity:surface * dt * r(0,0,actual_rot)).
  624. set tfr_vecdraws[dt -1][base_rot /5 + 1]:vec to vxcl(up:vector,velocity:surface) * dt * r(0,0,actual_rot).
  625. tfr_vecdraws[dt -1][base_rot/5 +1]:show.
  626. }
  627. }
  628. return max_ht .
  629. }.
  630.  
  631. print "DEBUG: setting up the gui".
  632. set the_gui to gui(300).
  633. set gui_fields to lexicon().
  634. {
  635. // hide some local veriables that can be thrown away.
  636. gui_fields:add("gui",the_gui).
  637. local vl is the_gui:addvlayout().
  638. local hl1 is vl:addhlayout().
  639. hl1:addlabel("Throttle:").
  640. gui_fields:add("speed",hl1:addtextfield(tpid:setpoint:tostring)).
  641. hl1:addlabel("m/s").
  642. gui_fields:add("stall",hl1:addlabel("<color=black>Stall</color>")).
  643. local hl2 is vl:addhlayout().
  644. hl2:addlabel("Pitch:").
  645. gui_fields:add("pitch_mode",hl2:addtextfield(pitch_mode)).
  646. set gui_fields["pitch_mode"]:style:fontsize to 10.
  647. gui_fields:add("pitch_info",hl2:addtextfield(p:tostring)).
  648. set gui_fields["pitch_info"]:STYLE:HSTRETCH TO True.
  649. set gui_fields["pitch_info"]:STYLE:FONTSIZE TO 10.
  650. local hl3 is vl:addhlayout().
  651. hl3:addlabel("Heading:").
  652. gui_fields:add("heading_mode",hl3:addtextfield(hdg_mode)).
  653. set gui_fields["heading_mode"]:style:fontsize to 10.
  654. gui_fields:add("heading_info",hl3:addtextfield(hdg:tostring)).
  655. set gui_fields["heading_info"]:STYLE:HSTRETCH TO True.
  656. set gui_fields["heading_info"]:STYLE:FONTSIZE TO 10.
  657. local hl4 is vl:addhlayout().
  658. hl4:addlabel("Bank Ang:").
  659. gui_fields:add("bank",hl4:addtextfield(b:tostring)).
  660. local lab is hl4:addlabel("Limit:").
  661. set lab:style:align to "RIGHT".
  662. gui_fields:add("bank_limit",hl4:addtextfield(bank_limit:tostring)).
  663. local hl5 is vl:addhlayout().
  664. gui_fields:add("brakes", hl5:addlabel((choose "<color=green>Brakes</color>" if brakes else "<color=black>Brakes</color>"))).
  665. gui_fields:add("gear", hl5:addlabel((choose "<color=green>Gear</color>" if gear else "<color=black>Gear</color>"))).
  666. gui_fields:add("flaps", hl5:addlabel((choose "<color=green>Flaps</color>" if flaps else "<color=black>Flaps</color>"))).
  667. gui_fields:add("spoilers", hl5:addlabel( (choose "<color=green>Spoilers</color>" if spoilers else "<color=black>Spoilers</color>"))).
  668. local hl6 is vl:addhlayout().
  669. gui_fields:add("revthrust",hl6:addlabel( (choose "<color=green>Reverse</color>" if revthrust else "<color=black>Reverse</color>"))).
  670. gui_fields:add("electric_throttle",hl6:addlabel( (choose "<color=green>ETE</color>" if electric_throttle_enable else "<color=black>ETE</color>"))).
  671. gui_fields:add("dynamic_brakes",hl6:addlabel( (choose "<color=green>DBE</color>" if dynamic_brakes_enable else "<color=black>DBE</color>"))).
  672. gui_fields:add("wing_leveler",hl6:addlabel( (choose "<color=green>WLE</color>" if wing_leveler_enable else "<color=black>WLE</color>"))).
  673. set the_gui:x to -100.
  674. set the_gui:y to 100.
  675. the_gui:show().
  676. }
  677. print "DEBUG: gui created.".
  678.  
  679. set main_loop_timestamp to 0.
  680. set main_loop_updates_per_second to 0.
  681. set debug_main_loop_updates to false.
  682.  
  683. // 1 second timer
  684. on time:second {
  685. if debug_main_loop_updates print "Main loop updates per second: " + main_loop_updates_per_second.
  686.  
  687. //Gear at least does not mess with stallspeeds in KSP (I think!? If so it does not have much effect).
  688. if auto_gear_enable and alt_radar() < 80 and verticalspeed < 0 if not gear gear on.
  689.  
  690. if gui_fields["gui"]:visible {
  691. local blink is false.
  692. if mod(time:second,2) = 0 set blink to true.
  693. set gui_fields["speed"]:text to tpid:setpoint:tostring.
  694. 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>".
  695. else set gui_fields["stall"]:text to "<color=black>Stall</color>".
  696. set gui_fields["pitch_mode"]:text to pitch_mode.
  697. set gui_fields["pitch_info"]:text to pitch_info.
  698. set gui_fields["heading_mode"]:text to hdg_mode.
  699. set gui_fields["heading_info"]:text to heading_info.
  700. //set gui_fields["bank"]:text to round(abs(90 - vang(ship:facing:starvector,up:vector)),1):tostring + " deg".
  701. 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".
  702. set gui_fields["bank_limit"]:text to bank_limit:tostring + " deg".
  703. if brakes set gui_fields["brakes"]:text to "<color=green>Brakes</color>".
  704. else set gui_fields["brakes"]:text to "<color=black>Brakes</color>".
  705. if gear {
  706. if defined vlo and airspeed > vlo set gui_fields["gear"]:text to "<color=" + (choose "red" if blink else "yellow") + ">Gear</color>".
  707. else set gui_fields["gear"]:text to "<color=green>Gear</color>".
  708. } else {
  709. set gui_fields["gear"]:text to "<color=black>Gear</color>".
  710. }
  711. if flaps {
  712. if defined vfe and airspeed > vfe set gui_fields["flaps"]:text to "<color=" + (choose "red" if blink else "yellow") + ">Flaps</color>".
  713. else set gui_fields["flaps"]:text to "<color=green>Flaps</color>".
  714. } else {
  715. set gui_fields["flaps"]:text to "<color=black>Flaps</color>".
  716. }
  717. if spoilers set gui_fields["spoilers"]:text to "<color=green>Spoilers</color>".
  718. else set gui_fields["spoilers"]:text to "<color=black>Spoilers</color>".
  719. if revthrust set gui_fields["revthrust"]:text to "<color=green>Reverse</color>".
  720. else set gui_fields["revthrust"]:text to "<color=black>Reverse</color>".
  721.  
  722. if electric_throttle_enable set gui_fields["electric_throttle"]:text to "<color=green>ETE</color>".
  723. else set gui_fields["electric_throttle"]:text to "<color=black>ETE</color>".
  724. if dynamic_brakes_enable set gui_fields["dynamic_brakes"]:text to "<color=green>DBE</color>".
  725. else set gui_fields["dynamic_brakes"]:text to "<color=black>DBE</color>".
  726. if wing_leveler_enable set gui_fields["wing_leveler"]:text to "<color=green>WLE</color>".
  727. else set gui_fields["wing_leveler"]:text to "<color=black>WLE</color>".
  728. }
  729.  
  730. if main_loop_timestamp > 0 and main_loop_timestamp +5 < time:seconds {
  731. print "MAIN LOOP IS DEAD".
  732. }.
  733. return true.
  734. }.
  735.  
  736. set circle_radius to 1250.
  737. set slip_bank_angle to -20.
  738. set runway_heading to 0.
  739. set pitch_aoa to 0.
  740. set side_slip to false.
  741. set side_slip_enable to false.
  742.  
  743. //set runway_vecdraw to vecdraw(v(0,0,0),v(0,0,0),yellow,"",1,true,0.2,true,false).
  744. //set touchdown_vecdraw to vecdraw(v(0,0,0),v(0,0,0),yellow,"",1,true,0.2,false,false).
  745. //set touchdown_vecdraw:pointy to false.
  746. //set glideslope_vecdraw to vecdraw(v(0,0,0),v(0,0,0),green,"",1,true,0.2,false,false).
  747. //set glideslope_vecdraw:pointy to false.
  748.  
  749. // set previous to v(0,0,0).
  750. // for i in range(0,trajectory:length) {
  751. // set trajectory[i]:start to previous:vec.
  752. // set trajectory[i]:vec to angleaxis( (i+0.5) * turn_rate,up:vector) * (my_horizon_forward:normalized * chord_length).
  753. // set previous to previous:vec + trajectory[i]:vec.
  754. // }
  755.  
  756.  
  757. set draw_the_runway to false.
  758.  
  759. //slope_correction_factor is how aggressively to try to correct slope errors.
  760. //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.
  761. //at 0.5 we are trying to get to the correct height by the time we are half way to the target point.
  762. set slope_correction_factor to 0.75.
  763.  
  764. // Fast timer
  765. when true then {
  766. // get these calculations out of the main loop... if you want to change them call setup_runway() !
  767. //if defined(runway) and runway["enabled"] {
  768. // set runway_normalized to ( runway_end:position - runway_start:position ):normalized.
  769. // set runway_touchdown to body:geopositionof(runway_start:position + runway_normalized * runway_touchdown_distance).
  770. // set runway_final to body:geopositionof(runway_normalized * -runway_final_distance + runway_start:position).
  771. //}
  772. if draw_the_runway {
  773. if runway["enabled"] {
  774. set runway_vecdraw:start to runway["start"]:position + up:vector * 3.
  775. set runway_vecdraw:vec to runway["end"]:position - runway["start"]:position - up:vector * runway["start"]:terrainheight + up:vector * runway["end"]:terrainheight.
  776. set touchdown_vecdraw:start to runway["touchdown"]:position + runway["normalized"] * 25 * angleaxis(-90,up:vector) + up:vector * 3.
  777. set touchdown_vecdraw:vec to runway["normalized"] * 50 *angleaxis(90,up:vector).
  778. set glideslope_vecdraw:start to runway["touchdown"]:position.
  779. 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"] )).
  780. if not(runway_vecdraw:show) or not(touchdown_vecdraw:show) or not(glideslope_vecdraw:show) {
  781. set runway_vecdraw:show to true.
  782. set touchdown_vecdraw:show to true.
  783. set glideslope_vecdraw:show to true.
  784. }
  785. }
  786. } else {
  787. //set runway_vecdraw:show to false.
  788. //set touchdown_vecdraw:show to false.
  789. //set glideslope_vecdraw:show to false.
  790. }
  791.  
  792. set main_loop_updates_per_second to 1/(time:seconds - main_loop_timestamp).
  793. set main_loop_timestamp to time:seconds.
  794. if pitch_mode = "vert" {
  795. // pilot has asked to try to maintain climb/sink rate
  796. if aoa_limit_enable {
  797. local curr_pitch is 90 - vang(up:vector,ship:velocity:surface).
  798. set vpid:minoutput to curr_pitch - default_aoa_limit.
  799. set vpid:maxoutput to curr_pitch + default_aoa_limit.
  800. } else {
  801. set vpid:minoutput to -45.
  802. set vpid:maxoutput to 45.
  803. }
  804. set p to vpid:update(time:seconds,verticalspeed).
  805. } else if pitch_mode = "aoa" {
  806. //maintain an angle of attack.
  807. set p to 90 - vang(up:vector,ship:velocity:surface) + pitch_aoa.
  808. } else if pitch_mode = "glide" {
  809. of aoa_limit_enable {
  810. local curr_pitch is 90 - vang(up:vector,ship:velocity:surface).
  811. set gpid:minoutput to curr_pitch - default_aoa_limit.
  812. set gpid:maxoutput to curr_pitch + default_aoa_limit.
  813. } else {
  814. set gpid:minoutput to -45.
  815. set gpid:maxoutput to 45.
  816. }
  817. set p to -gpid:update(time:seconds,airspeed).
  818. } else if pitch_mode = "alt" {
  819. // pilot has asked to try to maintain altitude
  820. if aoa_limit_enable {
  821. local curr_pitch is 90 - vang(up:vector,ship:velocity:surface).
  822. set apid:minoutput to curr_pitch - default_aoa_limit.
  823. set apid:maxoutput to curr_pitch + default_aoa_limit.
  824. } else {
  825. set apid:minoutput to -15.
  826. set apid:maxoutput to 45.
  827. }
  828. set p to apid:update(time:seconds,altitude).
  829. } else if pitch_mode = "radar" {
  830. // pilot has ask to to fly NOE
  831. //my current thinking is to NOT follow aoa limits, since in KSP we have reaction wheels to easily enable stall recover
  832. //and landing gear in KSP has the ability to absorb huge impacts, and getting the gear into position is more important
  833. //than avoiding the stall if you are that close to the ground.
  834. set p to rpid:update(time:seconds,altitude - tfr(tfr_lookahead)).
  835. } else if pitch_mode = "slope" {
  836. if aoa_limit_enable {
  837. local curr_pitch is 90 - vang(up:vector,ship:velocity:surface).
  838. set vpid:minoutput to curr_pitch - default_aoa_limit.
  839. set vpid:maxoutput to curr_pitch + default_aoa_limit.
  840. } else {
  841. set vpid:minoutput to -45.
  842. set vpid:maxoutput to 45.
  843. }
  844. if runway["final"]:altitudeposition(altitude):mag <1000 and airspeed > (vc + vt)/2 hs((vc + vt)/2).
  845. if runway["start"]:altitudeposition(altitude):mag < 1000 and airspeed > vt hs(vt).
  846. if runway["start"]:altitudeposition(altitude):mag < 100 or runway["touchdown"]:altitudeposition(altitude):mag < 100 and airspeed > vtd hs(vtd).
  847. if alt_radar < ship:mass * -verticalspeed / flare_factor {
  848. print "DEBUG: Flaring!".
  849. set pitch_mode to "flare".
  850. set p to p + 3.
  851. flaps off.
  852. spoilers on.
  853. if debug print "flare" + char(7).
  854. } else {
  855. if debug print "A_R= " + round(alt_radar,1) + " VS=" + round(verticalspeed,1) + " TRIGGER=" + round(ship:mass * -verticalspeed / flare_factor,1).
  856. local actual_dist is (slope_target:position - ship:geoposition:position):mag + slope_distance_adj.
  857. //Trying new calculation to get the horizontal distance to touchdown target.
  858. local actual_dist is slope_target:altitudeposition(altitude):mag + slope_distance_adj.
  859. local actual_vert is altitude - slope_target:terrainheight - slope_height_adj.
  860. if actual_dist = 0 {
  861. print "DEBUG: divide by zero due to actual_dist = 0".
  862. }
  863. local actual_slope is arctan(actual_vert / actual_dist).
  864. local new_dist is actual_dist * (1 - slope_correction_factor).
  865. local new_vert is altitude - slope_target:terrainheight - slope_height_adj - ( actual_dist * tan(runway["slope"] )*slope_correction_factor).
  866. if airspeed = 0 {
  867. print "DEBUG: divide by zero due to airspeed = 0".
  868. }
  869. set vpid:setpoint to ((-new_vert)/ (new_dist / airspeed)).
  870. set p to vpid:update(time:seconds,verticalspeed).
  871. if new_dist = 0 {
  872. print "DEBUG: divide by zero due to new_dist = 0".
  873. }
  874. 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).
  875. if tpid:setpoint * 1.1 < airspeed {
  876. if overspeed_spoilers_enable spoilers on.
  877. } else if tpid:setpoint * 1.05 < airspeed and actual_slope > runway["slope"] {
  878. if auto_spoilers_enable spoilers on.
  879. } else {
  880. if (overspeed_spoilers_enable or auto_spoilers_enable) spoilers off.
  881. }.
  882. if side_slip_enable {
  883. if tpid:setpoint * 1.1 < airspeed and (actual_slope + 2) > runway["slope"] and alt_radar > 200 set side_slip to true.
  884. else set side_slip to false.
  885. }
  886. }
  887. } else if pitch_mode = "flare" {
  888. set pitch_info to "landing flare".
  889. if ship:status = "landed" {
  890. if flaps flaps off.
  891. if not spoilers spoilers on.
  892. set pitch_info to round(p,1) + " deg".
  893. set gui_fields["pitch_info"]:text to pitch_info.
  894. hs(0).
  895. hp(0).
  896. set pitch_mode to "landed".
  897. if debug print "landed".
  898. }
  899. //if verticalspeed > -0.25 set p to p -1.
  900. //if verticalspeed < -0.75 set p to p + 1.
  901. if tpid:setpoint > vtd hs(vtd).
  902. //set vpid:setpoint to -alt_radar /10.
  903. set pitch_info to round(p,1) + " degrees".
  904. } else if pitch_mode = "landed" {
  905. set pitch_info to "landed".
  906. print "DEBUG: not applying brakes in the main loop".
  907. //if not brakes brakes on.
  908. if groundspeed < 0.1 {
  909. hp(0).
  910. }
  911. } // else pitch_mode = "fixed" => just leave the pitch alone.
  912. if hdg_mode = "circle" {
  913. //TODO: support circle_target:istype("Vessel")...
  914. if circle_target:altitudeposition(altitude):mag > circle_radius {
  915. local alpha is arcsin( circle_radius / circle_target:altitudeposition(altitude):mag ).
  916. set hdg to circle_target:heading + (choose alpha if circle_dir = -1 else -alpha).
  917. } else {
  918. set hdg to circle_target:heading + 92 * -circle_dir.
  919. }
  920. } else if hdg_mode = "target" {
  921. if hdg_target:altitudeposition(altitude):mag < (2 * groundspeed) and not(hdg_target:istype("Vessel")) {
  922. // if we get "close", just keep flying that heading TODO: this should be more rigorous shouldn't it?
  923. //unless it is a vessel... then we just keep heading towards it.
  924. set hdg_mode to "heading".
  925. set heading_info to round(hdg,1):tostring + " degrees".
  926. } else {
  927. set hdg to hdg_target:heading.
  928. }
  929. } else if hdg_mode = "lineup" {
  930. // try a multi-stage linup method
  931. set runway_heading to remote_heading(runway["start"],runway["end"]).
  932.  
  933. if runway["touchdown"]:altitudeposition(altitude):mag < 150 {
  934. // just fly the runway heading now. Perhaps we are doing a touch-n-go or a go-around.
  935. set hdg to runway["end"]:heading.
  936. set hdg_mode to "fixed".
  937. } else if runway["start"]:altitudeposition(altitude):mag < 300 or abs(ang(runway["start"]:heading,ct())) > 90 {
  938. //continue lineup but now target runway["touchdown"].
  939. set hdg to (mod(360 + runway["touchdown"]:heading + ang(runway["touchdown"]:heading,runway_heading) ,360)).
  940. } else if runway["final"]:altitudeposition(altitude):mag < 600 or abs(ang(runway["final"]:heading,ct())) > 90 {
  941. //continue lineup but now target runway["start"].
  942. set hdg to (mod(360 + runway["start"]:heading + ang(runway["start"]:heading,runway_heading) ,360)).
  943. } else {
  944. // aim to lineup before runway["final"]
  945. set hdg to (mod(360 + runway["final"]:heading + ang(runway["final"]:heading,runway_heading) ,360)).
  946. }
  947. }
  948. if side_slip {
  949. set old_b to b.
  950. if alt_radar < 50 {
  951. set side_slip_enable to false.
  952. set side_slip to false.
  953. }
  954. if alt_radar < 100 {
  955. set b to constrain(slip_bank_angle/2,old_b -3, old_b + 3).
  956. } else {
  957. set b to constrain(slip_bank_angle,old_b -3, old_b + 3).
  958. }
  959. set x to ct() + spid:update(time:seconds,ang(hdg,ct())).
  960. } else
  961. if hdg_mode = "fixed" or hdg_mode = "target" or hdg_mode = "circle" or hdg_mode = "lineup" {
  962. if ship:status = "PRELAUNCH" or ship:status = "LANDED" {
  963. set b to 0.
  964. set x to hdg.
  965. //still on the ground - try to steer, but as speed increases do a LOT less wheelsteering.
  966. if auto_wheelsteer_enable {
  967. if abs(ang(hdg,cf())) < 1 {
  968. set ship:control:wheelsteer to 0.
  969. set using_wheelsteer to false.
  970. } else {
  971. set using_wheelsteer to true.
  972. set ship:control:wheelsteer to constrain(
  973. constrain(
  974. -ang(hdg,cf())/10,
  975. -100/(groundspeed+1)^2,
  976. 100/(groundspeed+1)^2
  977. ),
  978. -1,
  979. 1
  980. ).
  981. }.
  982. }.
  983. // we might be using throttle to maintain ship:electriccharge... so using brakes on the ground could be really important.
  984. if dynamic_brakes_enable {
  985. if tpid:setpoint < 0.1 {
  986. brakes on.
  987. } else {
  988. if groundspeed > tpid:setpoint * 1.1 brakes on.
  989. if groundspeed < tpid:setpoint brakes off.
  990. }
  991. }
  992. } else {
  993. //in the air
  994. //if brakes brakes off.
  995. if using_wheelsteer {
  996. set ship:control:wheelsteer to 0.
  997. set using_wheelsteer to false.
  998. }.
  999. local bank_dir is 0.
  1000. if hdg_mode = "circle" {
  1001. set bank_dir to circle_dir.
  1002. set turn_force_dir to 90.
  1003. }
  1004. if hdg_mode = "fixed" set bank_dir to turn_dir.
  1005.  
  1006. // force a turn in a particular direction if the angle is over turn_force_dir degrees.
  1007. // otherwise turn which ever way is smaller.
  1008. if abs(ang(hdg,ct())) < turn_force_dir set bank_dir to 0.
  1009. local hdg_error is ang(hdg,ct()).
  1010. // force us to turn the other way by faking how much we need to turn :-/
  1011. if bank_dir = -1 and hdg_error > 0 {
  1012. set hdg_error to hdg_error - 180.
  1013. } else if bank_dir = 1 and hdg_error < 0 {
  1014. set hdg_error to hdg_error + 180.
  1015. }
  1016.  
  1017. // don't bank so much you stall,
  1018. // don't exceed normal bank limits,
  1019. // don't change bank too rapidly,
  1020. set b to constrain(
  1021. -hdg_error * bank_fudge_factor,
  1022. max(-bank_stall_angle,max(-bank_limit,b - bank_change_rate)),
  1023. min(bank_stall_angle,min(bank_limit,b + bank_change_rate))
  1024. ).
  1025. set target_rudder to rudder_rate * -b.
  1026. if wing_leveler_enable {
  1027. // don't bank steeply close to the ground.
  1028. set b to constrain(b,-alt_radar(), alt_radar()).
  1029. }
  1030. set current_rudder to constrain(target_rudder,current_rudder -1, current_rudder + 1).
  1031. set x to mod(720 + ct() + current_rudder,360).
  1032. }
  1033. }
  1034. return true.
  1035. }
  1036.  
  1037. // move the runway to left (-ve) or right (+ve), x meters.
  1038. function rs {
  1039. parameter dist is 0.
  1040. print char(7)+"ERROR: rs() is unavailable.".
  1041. return.
  1042. local offset is runway_normalized * dist * angleaxis(90,up:vector).
  1043. set runway_start to body:geopositionof( runway_start:position + offset).
  1044. set runway_end to body:geopositionof(runway_end:position + offset).
  1045. }
  1046. //move the runway d meters further away. (closer if d is negative).
  1047. function rd {
  1048. parameter dist is 0.
  1049. print char(7)+"ERROR: rd() is unavailable.".
  1050. return.
  1051. local offset is runway_normalized * dist.
  1052. set runway_start to body:geopositionof( runway_start:position + offset).
  1053. set runway_end to body:geopositionof(runway_end:position + offset).
  1054. }
  1055.  
  1056. //rotate the runway thru angle rot_angle around the starting point.
  1057. function ra {
  1058. parameter rot_angle is 0.
  1059. print char(7)+"ERROR: ra() is unavailable.".
  1060. return.
  1061. set runway_end to body:geopositionof(
  1062. runway_start:position + (runway_end:position - runway_start:position) * angleaxis(rot_angle,up:vector)
  1063. ).
  1064. }
  1065.  
  1066. function rf {
  1067. local temp is runway_end.
  1068. print char(7)+"ERROR: rf() is unavailable.".
  1069. return.
  1070. set runway_end to runway_start.
  1071. set runway_start to temp.
  1072. }
  1073.  
  1074. // begin decending at slope "slope", once we are, work out where we will land, and create a "runway" there.
  1075. function land_here {
  1076. parameter slope is 4.
  1077. hv(sin(slope) * airspeed).
  1078. }
  1079.  
  1080. set valid_dirs to list("left","right","either").
  1081. // try to hold a circle - if not landmark to reference is given, circle the current location.
  1082. //if "either" direction is given (or no direction given) then a direction has to be determined here.
  1083. function circle {
  1084. parameter ctgt is ship:geoposition.
  1085. parameter radius is 1000.
  1086. parameter dir is "either".
  1087. if not (ctgt:hassuffix("distance") and ctgt:hassuffix("heading")) and not places:haskey(ctgt) {
  1088. print char(7) + "ERROR: cannot circle - unrecognised target".
  1089. return.
  1090. }
  1091. if valid_dirs:find(dir) = -1 {
  1092. print char(7) + "ERROR: cannot circle - unrecognised direction".
  1093. return.
  1094. }
  1095. if places:haskey(ctgt) {
  1096. set heading_info to ctgt + " radius=" + round(circle_radius) + "m ".
  1097. set ctgt to places[ctgt].
  1098. } else {
  1099. set heading_info to "LAT:" + round(ctgt:lat,3) + " LNG:" + round(ctgt:lng,3).
  1100. }
  1101. set hdg_mode to "circle".
  1102. set circle_target to ctgt.
  1103. set circle_radius to radius.
  1104.  
  1105. if dir = "either" {
  1106. if circle_target:altitudeposition(altitude):mag > circle_radius {
  1107. set circle_dir to (choose 1 if ang(circle_target:heading,ct()) > 0 else -1).
  1108. } else {
  1109. set circle_dir to (choose 1 if abs(ang(circle_target:heading -90 ,ct())) < 90 else -1).
  1110. }
  1111. } else {
  1112. set circle_dir to (choose -1 if dir = "left" else 1 ).
  1113. }
  1114. set heading_info to heading_info + (choose "left" if circle_dir < 0 else "right").
  1115. }.
  1116.  
  1117.  
  1118. // 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.
  1119. // 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.
  1120. // be careful setting small force angles, any perturbation of the heading could result in complete 360degree turns.
  1121. set force_dirs to list("closest","left","right").
  1122. function tt {
  1123. parameter ttgt.
  1124. parameter force_dir is "closest".
  1125. parameter force_angle is 45.
  1126. if force_dirs:find(force_dir) = -1 {
  1127. print char(7) + "ERROR: " + force_dir + " is not a recognised direction".
  1128. } else {
  1129. set turn_force_dir to force_angle.
  1130. if force_dir = "closest" or abs(ang(ttgt,ct())) < force_angle {
  1131. set hdg_mode to "fixed".
  1132. set hdg to ttgt.
  1133. set turn_dir to 0.
  1134. } else if force_dir = "left" {
  1135. set hdg_mode to "fixed".
  1136. set hdg to ttgt.
  1137. set turn_dir to -1.
  1138. } else if force_dir = "right" {
  1139. set hdg_mode to "fixed".
  1140. set hdg to ttgt.
  1141. set turn_dir to 1.
  1142. }
  1143. set heading_info to hdg:tostring + " deg".
  1144. }
  1145. return true.
  1146. }.
  1147.  
  1148. //pilot is requesting to fly to a particular location.
  1149. function goto {
  1150. parameter where.
  1151. if where:istype("String") and places:haskey(where) {
  1152. set hdg_mode to "target".
  1153. set hdg_target to places[where].
  1154. set heading_info to where.
  1155. } else if where:istype("GeoCoordinates") {
  1156. set hdg_mode to "target".
  1157. set hdg_target to where.
  1158. set heading_info to "LAT:" + round(where:lat,3) + " LNG:" + round(where:lng,3).
  1159. } else if where:istype("Vessel") {
  1160. set heading_info to "TGT:" + where:name.
  1161. set hdg_mode to "target".
  1162. set hdg_target to where.
  1163. } else {
  1164. print "Sorry, I don't know where " + where + " is.".
  1165. }
  1166. return true.
  1167. }.
  1168.  
  1169. // pilot is requesting to fly NOE at a certain height off the ground.
  1170. function hr {
  1171. parameter rtgt.
  1172. if pitch_mode <> "radar" {
  1173. rpid:reset().
  1174. set pitch_mode to "radar".
  1175. }
  1176. set rpid:setpoint to rtgt.
  1177. set pitch_info to "NOE " + round(rtgt,1) + " m".
  1178. return true.
  1179. }.
  1180.  
  1181. //pilot is requesting to hold a particular speed - if we are using throttle to maintain electric charge,
  1182. //then when electriccharge is low, kick in enough throttle to maintain some charge!
  1183. //in the air electric_throttle_enable might not be noticed, but on the ground a small change in throttle could
  1184. //easily cause problems... so might be a good idea to also set dynamic_brakes_enable to true to prevent overspeeds.
  1185. function hs {
  1186. parameter stgt is 0.
  1187. if stgt = "" {
  1188. unlock throttle.
  1189. } else {
  1190. set tpid:setpoint to stgt.
  1191. lock throttle to max(tpid:update(time:seconds,airspeed),choose 100 - ship:electriccharge if electric_throttle_enable else 0).
  1192. }
  1193. return true.
  1194. }.
  1195.  
  1196. //pilot has requested to hold a particular pitch
  1197. function hp {
  1198. parameter ptgt.
  1199. set pitch_mode to "fixed".
  1200. set p to ptgt.
  1201. set pitch_info to round(ptgt,1) + " deg".
  1202. return true.
  1203. }
  1204.  
  1205. //pilot is requesting to hold a particular climb/sink rate
  1206. function hv {
  1207. parameter vtgt.
  1208. if pitch_mode <> "vert" and pitch_mode <> "slope" {
  1209. vpid:reset().
  1210. }
  1211. set pitch_mode to "vert".
  1212. set vpid:setpoint to vtgt.
  1213. if vtgt < 0 {
  1214. set pitch_info to "Descend " + round(vtgt,1) + " m/s".
  1215. } else if vtgt > 0 {
  1216. set pitch_info to "Climb " + round(vtgt,1) + " m/s".
  1217. } else {
  1218. set pitch_info to "Level Flight".
  1219. }.
  1220. return true.
  1221. }.
  1222.  
  1223. //hold glideslope.
  1224. function hg {
  1225. parameter slope is default_glideslope.
  1226. parameter gstgt is (choose runway["touchdown"] if runway["enabled"] else "").
  1227. parameter ht is 0.
  1228. parameter dist is 0.
  1229.  
  1230. set runway["slope"] to slope.
  1231. set slope_target to gstgt.
  1232. set slope_height_adj to ht.
  1233. set slope_distance_adj to dist.
  1234. if pitch_mode <> "vert" and pitch_mode <> "slope" {
  1235. vpid:reset().
  1236. }
  1237. //main flight loop will calculate the vertspd to fly and set p accordingly.
  1238. set pitch_mode to "slope".
  1239. set pitch_info to round(slope,1) + " deg slope".
  1240. return true.
  1241. }
  1242.  
  1243.  
  1244. function hl {
  1245. parameter rw_name.
  1246. parameter the_final_distance is default_runway_final.
  1247. parameter the_touchdown_distance is default_runway_touchdown.
  1248. parameter the_turn_radius is default_runway_turn.
  1249.  
  1250. local opts is lexicon("final",the_final_distance,"touchdown",the_touchdown_distance,"turn",the_turn_radius).
  1251.  
  1252. if rw_name:istype("String") and places:haskey(rw_name) and places:haskey(recip(rw_name)) {
  1253. setup_runway(rw_name,opts).
  1254. set heading_info to "Runway " + runway["name"].
  1255. set hdg_mode to "lineup".
  1256. } else if rw_name:istype("List") and rw_name:length = 2 and rw_name[0]:istype("GeoCoordinates") and rw_name[1]:istype("GeoCoordinates") {
  1257. setup_runway(lexicon("start",rw_name[0],"end",rw_name[1]), opts).
  1258. set heading_info to "Runway " + runway["name"].
  1259. set hdg_mode to "lineup".
  1260. } else {
  1261. print char(7) + "ERROR: runway incorrectly specified".
  1262. }
  1263. }
  1264.  
  1265. function make_runway {
  1266. parameter slope is 3.
  1267.  
  1268. print char(7) + "ERROR: make_runway is not available.".
  1269. return.
  1270.  
  1271. local sink is sin(slope) * airspeed.
  1272. local rw_start is ship:geoposition.
  1273. local projected_alt is altitude.
  1274. until projected_alt < rw_start:terrainheight {
  1275. set rw_start to body:geopositionof(rw_start:position + vxcl(up:vector,ship:velocity:surface)).
  1276. set projected_alt to projected_alt - sink.
  1277. }.
  1278. set rw_end to body:geopositionof(rw_start:position + rw_start:position:normalized * 2400).
  1279. setup_runway(lexicon("start",rw_start,"end",rw_end),lexicon("slope",slope)).
  1280. set draw_the_runway to true.
  1281. }
  1282.  
  1283.  
  1284. //pilot is requesting to hold a particular altitude.
  1285. function ha {
  1286. parameter atgt.
  1287. if pitch_mode <> "alt" {
  1288. apid:reset().
  1289. set pitch_mode to "alt".
  1290. }
  1291. set apid:setpoint to atgt.
  1292. set pitch_info to "" + round(atgt,1) + " m".
  1293. }.
  1294.  
  1295. function haoa {
  1296. parameter tgt.
  1297. set pitch_mode to "aoa".
  1298. set pitch_aoa to tgt.
  1299. set pitch_info to "" + round(tgt,1) + " deg".
  1300. }
  1301.  
  1302. function hm {
  1303. parameter spd is vs.
  1304. set gpid:setpoint to spd.
  1305. if pitch_mode <> "glide" gpid:reset().
  1306. set pitch_mode to "glide".
  1307. set pitch_info to "Speed: " + spd.
  1308. }
  1309.  
  1310. function takeoff_and_land {
  1311. set bank_limit to 30.
  1312. stage.
  1313. brakes off.
  1314. hs(100).
  1315. hv(10).
  1316. set flaps to 0.5.
  1317. tt(runway["end"]:heading).
  1318. when altitude > 100 then hv(9).
  1319. when altitude > 120 then hv(8).
  1320. when altitude > 160 then hv(7).
  1321. when altitude > 200 then hv(6).
  1322. when altitude > 240 then hv(5).
  1323. when altitude > 280 then hv(4).
  1324. when altitude > 310 then hv(3).
  1325. when altitude > 330 then hv(2).
  1326. when altitude > 340 then hv(1).
  1327. when altitude > 345 then ha(350).
  1328. when alt:radar > 25 then gear off.
  1329. when airspeed > 60 then flaps off.
  1330. when airspeed > 75 then {
  1331. tt(275).
  1332. when abs(ang(ct(),275)) < 10 and abs(ang(ct(),runway["start"]:heading)) > 135 then {
  1333. hl(runway["name"]).
  1334. hg(4,runway["touchdown"]).
  1335. when runway["start"]:distance < 2000 then {
  1336. flaps on.
  1337. hs(vt + 10).
  1338. }
  1339. when runway["start"]:distance < 500 then hs(vt).
  1340. when runway["touchdown"]:distance < 250 then hs(vtd).
  1341. on ship:status {
  1342. revthrust on.
  1343. hs(1000).
  1344. flaps off.
  1345. spoilers on.
  1346. when groundspeed < 10 then {
  1347. revthrust off.
  1348. hs(0).
  1349. // ready to taxi
  1350. wait 5.
  1351. brakes on.
  1352. }.
  1353. }.
  1354. }.
  1355. }.
  1356. }.
  1357.  
  1358.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement