sumguytwitches

Clone of Kadin's autopilot2

Apr 9th, 2021 (edited)
89
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. set k_autopilot2_version to "0.7".
  2. print "Kadin's autopilot2 V" + k_autopilot2_version:tostring.
  3.  
  4.  
  5. print "There are three versions of this code.".
  6. print "Unstable/development version, newest features, newest bugs: !runscript NHwvPAp3".
  7. print "Recent working version, seems like it is fairly stable: !runscript 0pgtewL5".
  8. print "Oldest version, least features but also fairly stable: !runscript dHtuDeGx".
  9.  
  10.  
  11. //latest change: hl() for hold line.: hl(runway_west,runway_east).
  12. //latest change: blurb about version of the code.
  13. //latest change: added hg() for hold glideslope: hg(target_slope, ground_target, voffset, hoffset).
  14.  
  15. set bank_change_rate to 3. // How fast we change between bank angles .
  16. set rudder_rate to 0.4. // How much rudder to kick in to help increase the turn rate.
  17. set default_bank_limit to 40. // This is how many degrees of bank for a turn if none are specified.
  18. 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!".
  19.  
  20. if ship:name:startswith("Mallard") or ship:name:startswith("kadin landed here") {
  21. set vs to 65. // stall speed in level flight - complete guess.
  22. set vsr to 60. //normal stall speed.
  23. set vs0 to 40. //stall speed with flaps out
  24. set vto to 100. //take off speed
  25. set vfe to 65. //speed above which you would remove flaps.
  26. set vlo to 60. //speed below which you CAN extend/retract gear.
  27. set vc to 80. //cruise speed.
  28. set vt to 45. //threshold speed.
  29. set vtd to 40. //touchdown speed.
  30. set alt_radar_adj to 3.0433.
  31. //for p in ship:partsnamed("smallCtrlSrf") p:getmodule("ModuleControlSurface"):setfield("deploy direction",true).
  32. for p in ship:partsnamed("airlinerCtrlSrf") set p:tag to "flaps".
  33. for p in ship:partsnamed("airlinerCtrlSrf") p:getmodule("ModuleControlSurface"):setfield("deploy direction",choose false if p:position:mag < 8 else true).
  34. if not (bodyexists("Lua")) {
  35. for p in ship:partsnamed("airlinerCtrlSrf") {
  36. if p:position:mag > 6 and p:position:mag <8 p:getmodule("ModuleControlSurface"):setfield("deploy direction",true).
  37. }
  38. }
  39. for p in ship:partsnamed("airlinerCtrlSrf") p:getmodule("ModuleControlSurface"):setfield("deploy angle",choose 23 if p:position:mag < 8 else 15).
  40. for p in ship:partstagged("flaps") p:getmodule("ModuleControlSurface"):setfield("deploy",false).
  41. for p in ship:partsnamed("airbrake1") set p:tag to "airbrakes".
  42. for p in ship:partstagged("airbrakes") p:getmodule("ModuleAeroSurface"):setfield("deploy",false).
  43. for p in ship:partsnamed("tailfin") set p:tag to "spoilers".
  44. for p in ship:partsnamed("tailfin") p:getmodule("ModuleControlSurface"):setfield("deploy angle",15).
  45. for p in ship:partstagged("spoilers") p:getmodule("ModuleControlSurface"):setfield("deploy",false).
  46. set bank_limit to 40.
  47.  
  48. for p in ship:partsnamed("GearMedium") p:getmodule("ModuleWheelBrakes"):setfield("brakes",200).
  49.  
  50. for p in ship:partsnamed("JetEngine") set p:tag to "jets".
  51.  
  52. } else if ship:name:startswith("Aeris 4A") {
  53. set alt_radar_adj to 1.6. // has wheels on the ground at a reported alt:radar of 1.6
  54. local rude_word is "thru" + "st limiter". //thank you so much Pastebin!
  55. //differential_thrust is a possibility partsnamed("turboFanEngine") getmodule("ModuleEnginesFX") setfield(rude_word,0).
  56. //differential braking is a possibility partsnamed("SmallGearBay") getModule("ModuleWheelBase", "ModuleWheelBrakes" "ModuleWheelSteering"....
  57. // speed boost using the aerospike maybe? partsnamed("toroidalAerospike") getmodule("ModuleEnginesFX") setfield(rude_word,0)
  58. set bank_limit to 50.
  59. for p in ship:partsnamed("elevon2") p:getmodule("ModuleControlSurface"):setfield("deploy direction",true).
  60. for p in ship:partsnamed("StandardCtrlSrf") p:getmodule("ModuleControlSurface"):setfield("deploy direction",true).
  61. for p in ship:partsnamed("elevon2") p:getmodule("ModuleControlSurface"):setfield("deploy angle",10).
  62. for p in ship:partsnamed("StandardCtrlSrf") p:getmodule("ModuleControlSurface"):setfield("deploy angle",10).
  63. for p in ship:partsnamed("R8winglet") p:getmodule("ModuleControlSurface"):setfield("deploy angle",15).
  64. for p in ship:partsnamed("elevon2") set p:tag to "flaps".
  65. for p in ship:partsnamed("StandardCtrlSrf") set p:tag to "flaps".
  66. for p in ship:partsnamed("R8winglet") set p:tag to "flaps".
  67. ship:partsnamed("SmallGearBay")[0]:getmodule("ModuleWheelBrakes"):setfield("brakes",25).
  68. ship:partsnamed("SmallGearBay")[0]:getmodule("ModuleWheelBrakes"):setfield("brakes",150).
  69. ship:partsnamed("SmallGearBay")[0]:getmodule("ModuleWheelBrakes"):setfield("brakes",150).
  70. set vs to 55.
  71. set vsr to 55.
  72. set vs0 to 55.
  73. set vfe to 65.
  74. set vlo to 65.
  75. set vto to 100.
  76. set vc to 80.
  77. set vtd to 55.
  78. set vt to 60.
  79. } else if ship:name:startswith("Aeris 3A") {
  80. set alt_radar_adj to 1.410271525383.
  81. for p in ship:partsnamed("R8winglet") if p:position:mag < 4 p:getmodule("ModuleControlSurface"):setfield("deploy angle",10).
  82. for p in ship:partsnamed("R8winglet") if p:position:mag < 4 set p:tag to "flaps".
  83. for p in ship:partsnamed("elevon3") p:getmodule("ModuleControlSurface"):setfield("deploy angle",15).
  84. for p in ship:partsnamed("elevon3") set p:tag to "flaps".
  85. for p in ship:partsnamed("R8winglet") { if p:position:mag > 4 p:getmodule("ModuleControlSurface"):setfield("deploy angle",15). }
  86. for p in ship:partsnamed("R8winglet") if p:position:mag > 4 set p:tag to "spoilers".
  87. set bank_limit to 60.
  88. set vs to 32.
  89. set vsr to 32.
  90. set vs0 to 32.
  91. set vfe to 35.
  92. set vlo to 35.
  93. set vto to 80.
  94. set vc to 60.
  95. set vtd to 32.
  96. set vt to 35.
  97. } else if ship:name:startswith("Lockheed Jetstar") {
  98. set alt_radar_adj to 1.6479332447952.
  99. ship:partsnamed("SmallGearBay")[0]:getmodule("ModuleWheelBrakes"):setfield("brakes",25).
  100. ship:partsnamed("SmallGearBay")[0]:getmodule("ModuleWheelBrakes"):setfield("brakes",150).
  101. ship:partsnamed("SmallGearBay")[0]:getmodule("ModuleWheelBrakes"):setfield("brakes",150).
  102. set bank_limit to 50.
  103. set vs to 60.
  104. set vsr to 60.
  105. set vs0 to 60.
  106. set vfe to 65.
  107. set vlo to 65.
  108. set vto to 100.
  109. set vc to 80.
  110. set vtd to 60.
  111. set vt to 60.
  112. } else if ship:name:startswith("stratoprop") {
  113. set alt_radar_adj to 1.09926223754883.
  114. set vs to 120.
  115. set vsr to 120.
  116. set vs0 to 120.
  117. set vfe to 120.
  118. set vlo to 120.
  119. set vto to 120.
  120. set vc to 120.
  121. set vtd to 120.
  122. set vt to 120.
  123. } else if ship:name:startswith("Reusable Moons Rocketship") {
  124. set alt_radar_adj to 4.58227.
  125. set vs to 80.
  126. set vsr to 80.
  127. set vs0 to 80.
  128. set vfe to 100.
  129. set vlo to 100.
  130. set vto to 150.
  131. set vc to 125.
  132. set vtd to 80.
  133. set vt to 90.
  134. } else if ship:name:startswith("SG Rescue 2") {
  135. //AG1 = rapier engine
  136. //ag2 = toggle rapier mode
  137. //ag3 = airbrakes.
  138. //ag5 = cargobay
  139. //ag7,9,10 do drill stuff.
  140. // enable nuclear engines with: list engines in es. for e in es if e:name:contains("nuc") e:activate
  141. //show engine mode for rapiers: list engines in es. for e in es if e:multimode print e:mode
  142. //All engines on: list engines in es. for e in es e:activate
  143. //use execute_node_old for any multi egine craft with some engines on or off or jet engines in space etc...
  144. //extend antenna: for a in ship:modulesnamed("ModuleDeployableAntenna") a:DoAction("extend antenna", true)
  145. set alt_radar_adj to 6.
  146. set vs to 120.
  147. set vsr to 120.
  148. set vs0 to 120.
  149. set vfe to 120.
  150. set vlo to 120.
  151. set vto to 120.
  152. set vc to 120.
  153. set vtd to 120.
  154. set vt to 120.
  155. } else {
  156. set vs to 120.
  157. set vsr to 120.
  158. set vs0 to 120.
  159. set vfe to 120.
  160. set vlo to 120.
  161. set vto to 120.
  162. set vc to 120.
  163. set vtd to 120.
  164. set vt to 120.
  165. set alt_radar_adj to 5.
  166. }
  167.  
  168. // stall speed increases at high bank angles. Keep this updated so we can refer to this increased stall speed.
  169. lock bank_stall_angle to arccos(vs^2/max(vs,airspeed)^2).
  170.  
  171. set flaps to false.
  172. set spoilers to false.
  173. set airbrakes to false.
  174. set revthrust to false.
  175.  
  176. on revthrust {
  177. for p in ship:partstagged("jets") {
  178. local m is p:getmodule("ModuleAnimateGeneric").
  179. if revthrust and m:hasevent("reverse thr" + "ust") m:doevent("reverse thr" + "ust").
  180. else if m:hasevent("forward thr" + "ust") m:doevent("forward thr" + "ust").
  181. }
  182. return true.
  183. }
  184.  
  185. on flaps {
  186. for p in ship:partstagged("flaps") p:getmodule("ModuleControlSurface"):setfield("deploy",flaps).
  187. if flaps set vs to vs0.
  188. else set vs to vsr.
  189. return true.
  190. }
  191.  
  192. //merge airbrakes into spoilers for the moment.
  193. on spoilers {
  194. for p in ship:partstagged("spoilers") p:getmodule("ModuleControlSurface"):setfield("deploy",spoilers).
  195. for p in ship:partstagged("airbrakes") p:getmodule("ModuleAeroSurface"):setfield("deploy",spoilers).
  196. return true.
  197. }
  198.  
  199. //merge airbrakes into spoilers for the moment.
  200. //on airbrakes {
  201. // for p in ship:partstagged("airbrakes") p:getmodule("ModuleAeroSurface"):setfield("deploy",airbrakes).
  202. // return true.
  203. //}
  204.  
  205.  
  206. function alt_radar {
  207. if defined alt_radar_adj return alt:radar - alt_radar_adj.
  208. else return alt:radar.
  209. }
  210.  
  211. //compass heading of our current direction of travel. (compass travel).
  212. function ct {
  213. if airspeed < 0.1 {
  214. return body:geopositionof(ship:facing:vector:normalized):heading.
  215. } else {
  216. return body:geopositionof(srfprograde:vector:normalized):heading.
  217. }
  218. }
  219.  
  220. //compass heading of the direction we are facing. (compass facing).
  221. function cf {
  222. return body:geopositionof(ship:facing:vector:normalized):heading.
  223. }
  224.  
  225. // Use set to change these values. locking steering and THEN doing more locks on the steering variables /seems/ to cause issues.
  226. set x to 90.5.
  227. if alt_radar() > 10 set x to ct().
  228. set p to 10.
  229. set b to 0.
  230. lock steering to heading(x,p,b).
  231. set pitch_mode to "fixed". // used to know when we are switching from hv() to ha() so we can do a pid:reset().
  232. set hdg to x.
  233. set hdg_mode to "fixed".
  234. set pitch_info to p:tostring + " degrees".
  235. set heading_info to x:tostring + " degrees".
  236.  
  237. set tpid to pidloop(0.5,0.01,0.1,0,1). //used for holding speed
  238. set vpid to pidloop(1,0.1,0.2,-45,45). //used for holding_vertical_speeed
  239. set apid to pidloop(0.5,0.02,0.4,-15,45). //used for holding altitude
  240. set rpid to pidloop(0.5,0.02,0.5,-10,60). //used for flying NOE
  241. set lpid to pidloop(0.2,0.02,0.05,-5,5). //used for following a line
  242.  
  243. set using_wheelsteer to false.
  244. set turn_dir to 0.
  245. set turn_force_dir to 45.
  246. set m_per_deg to (2 * constant():pi * body:radius) / 360.
  247. set line_distance_target to 100. // when flying a line, aim 500m further along the line....
  248.  
  249.  
  250. if exists("0:/json/kerbin.json") {
  251. set places to readjson("0:/json/kerbin.json").
  252. } else {
  253. // assume we are an airplane and on the end of the runway pointing at the far end. pretty big guesses!
  254. set places to lexicon().
  255. places:add("runway west",latlng(-0.048551152502, 285.27366496477202)).
  256. //places:add("runway east",body:geopositionof(ship:geoposition:position + ship:facing:forevector * 2400)).
  257. places:add("runway east", latlng(-0.0502131097,-74.48863)).
  258. places:add("vab pad 1",latlng(-0.0967891863704034, 285.382581254365)).
  259. places:add("vab pad 2",latlng(-0.0967891863704034, 285.3802528234891)).
  260. }
  261.  
  262. //Work out some key spots for landing at the runway.
  263. set runway_start to places["runway west"].
  264. set runway_end to places["runway east"].
  265.  
  266. set runway_normalized to ( runway_end :position - runway_start:position ):normalized.
  267. set runway_touchdown to body:geopositionof(runway_start:position + (runway_end:position - runway_start:position) * 0.075).
  268. set runway_final to body:geopositionof(runway_normalized * -2000 + runway_start:position).
  269. set runway_right to body:geopositionof(
  270. ( runway_normalized * -2000) +
  271. (vcrs(up:vector,runway_normalized):normalized*1000) + runway_start:position
  272. ).
  273. set runway_left to body:geopositionof(
  274. ( runway_normalized * -2000) +
  275. (vcrs(runway_normalized,up:vector):normalized*1000) + runway_start:position
  276. ).
  277.  
  278.  
  279. // return the angle between two compass headings (second defaults to the direction we are travelling).
  280. // -ve means you need to subtract from the current direction of travel to get to the first headings.
  281. // +ve means you need to turn right (i.e.add to the current direction of travel).
  282. function ang {
  283. parameter a.
  284. parameter b is ct().
  285. //extra 720 added for a bit more resiliency against supplied angles like "-370 degrees" etc.
  286. return mod(720 + a-b + 180 + 360,360) - 180.
  287. }.
  288.  
  289.  
  290. // truncate num so that it is between min and max (inclusive). optionally, do a call back to say you did something.
  291. function constrain {
  292. parameter num.
  293. parameter min is -1.
  294. parameter max is 1.
  295. parameter action is "".
  296. if num < min {
  297. if not (action = "") action(num,min).
  298. return(min).
  299. } else if num > max {
  300. if not (action = "") action(num,max).
  301. return(max).
  302. } else {
  303. return num.
  304. }
  305. }
  306.  
  307. set steeringmanager:pitchtorquefactor to 0.2.
  308. set steeringmanager:yawtorquefactor to 0.5.
  309. set steeringmanager:rollcontrolanglerange to 180.
  310. steeringmanager:resetpids().
  311.  
  312. // default_bank_limit is how steep to turn if the pilot does not specify...
  313. // bank_limit is how steep to turn (pilot can change this value but it defaults to default_bank_limit).
  314. set bank_limit to default_bank_limit.
  315.  
  316. set bank_fudge_factor to 3. // we try to bank this many degrees for every degree of heading we want to change.
  317. // other constraints will stop us banking that exact ammount, this will have more
  318. // effect at very small changes in heading angle. heading angle change of 1 deg = 3deg bank.
  319.  
  320. set current_rudder to 0.
  321.  
  322. //safetey features.
  323. set dynamic_brakes_enable to false. // when ground handling, apply/release brakes to help maintain target speeds <= 15.
  324. set electric_throttle_enable to false. // kick in the throttle if ship:electric charge gets too low.
  325. set wing_leveler_enable to true. // when lower than 40m off the ground, level the wings.
  326. // this gives better climb rates, and might mean avoiding touch a wingtip on the ground.
  327. set auto_spoilers_enable to true. // TODO need an inidcator like DBE
  328.  
  329. // 1 minute timer
  330. on floor(time:seconds / 60) {
  331. if hud_message <> "" {
  332. hudtext(hud_message, 15, 2, 25, purple, false).
  333. }
  334. return true.
  335. }
  336.  
  337. // terrain following radar - lookahead to see what the terrain is like - and peek out to the sides a bit too.
  338. //Try to predict where we are heading by looking at how fast our direction of travel is changing.
  339. set tft_prev_hdg to ct().
  340. set tft_prev_time to time:seconds.
  341.  
  342. // hold a 2d array of vectors to draw.
  343. set tfr_vecdraws to list().
  344. set tfr_lookahead to 3. // how many seconds ahead should the tfr radar look.
  345.  
  346. function tfr {
  347. parameter lookahead is 3.
  348. local max_ht is ship:geoposition:terrainheight.
  349. local alpha is ang(tft_prev_hdg,ct()) * 50 * groundspeed *(time:seconds - tft_prev_time ).
  350. set tft_prev_time to time:seconds.
  351. set tft_prev_hdg to ct().
  352. from { local dt is 1. } until dt > lookahead step { set dt to dt + 1. } do {
  353. from { local base_rot is -5. } until base_rot > 5 step { set base_rot to base_rot +5. } do {
  354. local actual_rot is base_rot - alpha * dt.
  355. //local th is body:geopositionof(vxcl(ship:up,velocity:surface * dt * r(actual_rot,0,0))):terrainheight.
  356. local th is body:geopositionof(vxcl(up:vector,velocity:surface) * dt * r(actual_rot,0,0)):terrainheight.
  357. //local th is body:geopositionof(positionat(ship,time:seconds + dt )*r(actual_rot,0,0)):terrainheight.
  358. if dt -1 >= tfr_vecdraws:length {
  359. print "add row = " + (dt -1).
  360. tfr_vecdraws:add(list()).
  361. }
  362. if base_rot/5 + 1 >= tfr_vecdraws[dt -1]:length {
  363. print "add index = " + (dt -1) + "," + (base_rot/5 + 1).
  364. tfr_vecdraws[dt-1]:add( vecdraw(v(0,0,0),v(0,0,0),yellow,"",1,true)).
  365. }
  366. if th > max_ht {
  367. set max_ht to th.
  368. set tfr_vecdraws[dt -1][base_rot/5 +1]:color to red.
  369. } else {
  370. set tfr_vecdraws[dt -1][base_rot/5 +1]:color to yellow.
  371. }
  372. //set tfr_vecdraws[dt -1][base_rot /5 + 1]:vec to vxcl(ship:up,velocity:surface * dt * r(0,0,actual_rot)).
  373. set tfr_vecdraws[dt -1][base_rot /5 + 1]:vec to vxcl(up:vector,velocity:surface) * dt * r(0,0,actual_rot).
  374. tfr_vecdraws[dt -1][base_rot/5 +1]:show.
  375. }
  376. }
  377. return max_ht .
  378. }.
  379.  
  380. set the_gui to gui(300).
  381. set gui_fields to lexicon().
  382. {
  383. // hide some local veriables that can be thrown away.
  384. gui_fields:add("gui",the_gui).
  385. local vl is the_gui:addvlayout().
  386. local hl1 is vl:addhlayout().
  387. hl1:addlabel("Throttle:").
  388. gui_fields:add("speed",hl1:addtextfield(tpid:setpoint:tostring)).
  389. hl1:addlabel("m/s").
  390. gui_fields:add("stall",hl1:addlabel("<color=black>Stall</color>")).
  391. local hl2 is vl:addhlayout().
  392. hl2:addlabel("Pitch:").
  393. gui_fields:add("pitch_mode",hl2:addtextfield(pitch_mode)).
  394. set gui_fields["pitch_mode"]:style:fontsize to 10.
  395. gui_fields:add("pitch_info",hl2:addtextfield(p:tostring)).
  396. set gui_fields["pitch_info"]:STYLE:HSTRETCH TO True.
  397. set gui_fields["pitch_info"]:STYLE:FONTSIZE TO 10.
  398. local hl3 is vl:addhlayout().
  399. hl3:addlabel("Heading:").
  400. gui_fields:add("heading_mode",hl3:addtextfield(hdg_mode)).
  401. set gui_fields["heading_mode"]:style:fontsize to 10.
  402. gui_fields:add("heading_info",hl3:addtextfield(hdg:tostring)).
  403. set gui_fields["heading_info"]:STYLE:HSTRETCH TO True.
  404. set gui_fields["heading_info"]:STYLE:FONTSIZE TO 10.
  405. local hl4 is vl:addhlayout().
  406. hl4:addlabel("Bank Ang:").
  407. gui_fields:add("bank",hl4:addtextfield(b:tostring)).
  408. local lab is hl4:addlabel("Limit:").
  409. set lab:style:align to "RIGHT".
  410. gui_fields:add("bank_limit",hl4:addtextfield(bank_limit:tostring)).
  411. local hl5 is vl:addhlayout().
  412. gui_fields:add("brakes", hl5:addlabel((choose "<color=green>Brakes</color>" if brakes else "<color=black>Brakes</color>"))).
  413. gui_fields:add("gear", hl5:addlabel((choose "<color=green>Gear</color>" if gear else "<color=black>Gear</color>"))).
  414. gui_fields:add("flaps", hl5:addlabel((choose "<color=green>Flaps</color>" if flaps else "<color=black>Flaps</color>"))).
  415. gui_fields:add("spoilers", hl5:addlabel( (choose "<color=green>Spoilers</color>" if spoilers else "<color=black>Spoilers</color>"))).
  416. local hl6 is vl:addhlayout().
  417. gui_fields:add("revthrust",hl6:addlabel( (choose "<color=green>Reverse</color>" if revthrust else "<color=black>Reverse</color>"))).
  418. gui_fields:add("electric_throttle",hl6:addlabel( (choose "<color=green>ETE</color>" if electric_throttle_enable else "<color=black>ETE</color>"))).
  419. gui_fields:add("dynamic_brakes",hl6:addlabel( (choose "<color=green>DBE</color>" if dynamic_brakes_enable else "<color=black>DBE</color>"))).
  420. gui_fields:add("wing_leveler",hl6:addlabel( (choose "<color=green>WLE</color>" if wing_leveler_enable else "<color=black>WLE</color>"))).
  421. set the_gui:x to -100.
  422. set the_gui:y to 100.
  423. the_gui:show().
  424. }
  425.  
  426. set main_loop_timestamp to 0.
  427.  
  428. // 1 second timer
  429. on time:second {
  430. //check on the current goal - change if need be. this is a big TODO, and encompasses the flight plan ideas I've had.
  431.  
  432. //display useful information - currently just using the console for debugging, but a GUI might be better.
  433. //print (("Heading: " + round(ct(),1)):padright(15) + "target: " + round(hdg,1)):padright(terminal:width) at (0,0).
  434. //print (
  435. // (
  436. // "Pitch: " + round(p,1)
  437. // ):padright(15) + "Tgt: " + pitch_mode +"("+
  438. // (
  439. // choose p if pitch_mode = "fixed"
  440. // else choose vpid:setpoint if pitch_mode = "vert"
  441. // else choose apid:setpoint if pitch_mode = "alt"
  442. // else choose rpid:setpoint if pitch_mode = "radar" else "Unknown"
  443. // )
  444. // + ")"
  445. //):padright(terminal:width) at (0,1).
  446. //print ("Bank: " + round(b,1)):padright(terminal:width) at (0,2).
  447. //print (("Throttle: " + round(throttle,1)):padright(15) + "TgtSpd:" + round(tpid:setpoint) +"m/s"):padright(terminal:width) at (0,3).
  448. //print ("Bank Stall angle: " + round(bank_stall_angle,1) + "deg"):padright(terminal:width) at(0,4).
  449. //print (("VertSpd: " + round(verticalspeed,1) + "m/s"):padright(15) + "Current GR: " + (choose "---" if verticalspeed < 0.001 else round(-groundspeed/verticalspeed,1) + ":1")):padright(terminal:width) at (0,5).
  450.  
  451. //local str is "".
  452. //if electric_throttle_enable {
  453. // if not (str = "") set str to str + ", ".
  454. // set str to str + "Electric Throttle".
  455. //}
  456. //if dynamic_brakes_enable {
  457. // if not (str = "") set str to str + ", ".
  458. // set str to str + "Dynamic Brakes".
  459. //}
  460. //if wing_leveler_enable {
  461. // if not (str = "") set str to str + ", ".
  462. // set str to str + "Wing Leveler".
  463. //}
  464. //print str:padright(terminal:width) at (0,6).
  465. //print " ":padright(terminal:width) at (0,7).
  466.  
  467.  
  468. // finally some flight related code that needs to go in here.
  469. //Nice in theory - but flaps tend to come on at inopportune times, and that then messes with stall speeds too!
  470. //if airspeed < vfe {
  471. // if alt_radar() < 120 if not flaps flaps on.
  472. //} else {
  473. // if alt_radar() > 120 if flaps flaps off.
  474. //}
  475.  
  476. //Gear at least does not mess with stallspeeds in KSP (I think!? If so it does not have much effect).
  477. if alt_radar() < 80 and verticalspeed < 0 if not gear gear on.
  478.  
  479. if gui_fields["gui"]:visible {
  480. local blink is false.
  481. if mod(time:second,2) = 0 set blink to true.
  482. set gui_fields["speed"]:text to tpid:setpoint:tostring.
  483. 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>".
  484. else set gui_fields["stall"]:text to "<color=black>Stall</color>".
  485. set gui_fields["pitch_mode"]:text to pitch_mode.
  486. set gui_fields["pitch_info"]:text to pitch_info.
  487. set gui_fields["heading_mode"]:text to hdg_mode.
  488. set gui_fields["heading_info"]:text to heading_info.
  489. set gui_fields["bank"]:text to round(abs(90 - vang(ship:facing:starvector,up:vector)),1):tostring + " deg".
  490. set gui_fields["bank_limit"]:text to bank_limit:tostring + " deg".
  491. if brakes set gui_fields["brakes"]:text to "<color=green>Brakes</color>".
  492. else set gui_fields["brakes"]:text to "<color=black>Brakes</color>".
  493. if gear {
  494. if defined vlo and airspeed > vlo set gui_fields["gear"]:text to "<color=" + (choose "red" if blink else "yellow") + ">Gear</color>".
  495. else set gui_fields["gear"]:text to "<color=green>Gear</color>".
  496. } else {
  497. set gui_fields["gear"]:text to "<color=black>Gear</color>".
  498. }
  499. if flaps {
  500. if defined vfe and airspeed > vfe set gui_fields["flaps"]:text to "<color=" + (choose "red" if blink else "yellow") + ">Flaps</color>".
  501. else set gui_fields["flaps"]:text to "<color=green>Flaps</color>".
  502. } else {
  503. set gui_fields["flaps"]:text to "<color=black>Flaps</color>".
  504. }
  505. if spoilers set gui_fields["spoilers"]:text to "<color=green>Spoilers</color>".
  506. else set gui_fields["spoilers"]:text to "<color=black>Spoilers</color>".
  507. if revthrust set gui_fields["revthrust"]:text to "<color=green>Reverse</color>".
  508. else set gui_fields["revthrust"]:text to "<color=black>Reverse</color>".
  509.  
  510. if electric_throttle_enable set gui_fields["electric_throttle"]:text to "<color=green>ETE</color>".
  511. else set gui_fields["electric_throttle"]:text to "<color=black>ETE</color>".
  512. if dynamic_brakes_enable set gui_fields["dynamic_brakes"]:text to "<color=green>DBE</color>".
  513. else set gui_fields["dynamic_brakes"]:text to "<color=black>DBE</color>".
  514. if wing_leveler_enable set gui_fields["wing_leveler"]:text to "<color=green>WLE</color>".
  515. else set gui_fields["wing_leveler"]:text to "<color=black>WLE</color>".
  516. }
  517.  
  518. if main_loop_timestamp > 0 and main_loop_timestamp +5 < time:seconds {
  519. print "MAIN LOOP IS DEAD".
  520. }.
  521. return true.
  522. }
  523.  
  524. //set vd_line to vecdraw(v(0,0,0),v(0,0,0),yellow,"",1,true,10).
  525. //set vd_runway to vecdraw(v(0,0,0),v(0,0,0),red,"",1,true,100).
  526.  
  527. set runway_vec to places["runway east"]:position - places["runway west"]:position.
  528.  
  529. // Fast timer
  530. when true then {
  531. set main_loop_timestamp to time:seconds.
  532. //set vd_runway:start to places["runway west"]:position + up:vector * 10.
  533. //set vd_runway:vec to places["runway west"]:position + up:vector*10 + runway_vec.
  534. if pitch_mode = "vert" {
  535. // pilot has asked to try to maintain climb/sink rate
  536. set p to vpid:update(time:seconds,verticalspeed).
  537. } else if pitch_mode = "alt" {
  538. // pilot has asked to try to maintain altitude
  539. set p to apid:update(time:seconds,altitude).
  540. } else if pitch_mode = "radar" {
  541. // pilot has ask to to fly NOE
  542. set p to rpid:update(time:seconds,altitude - tfr(tfr_lookahead)).
  543. } else if pitch_mode = "slope" {
  544. local actual_dist is (slope_target:position - ship:geoposition:position):mag + slope_distance_adj.
  545. local actual_vert is altitude - slope_target:terrainheight - slope_height_adj.
  546. local actual_slope is arctan(actual_vert / actual_dist).
  547. local new_dist is actual_dist / 3.
  548. local new_vert is altitude - slope_target:terrainheight - slope_height_adj - ( actual_dist * tan(slope_angle)*2/3).
  549. set vpid:setpoint to ((-new_vert)/ (new_dist / airspeed)).
  550. set p to vpid:update(time:seconds,verticalspeed).
  551. //print "SL TGT: " + round(slope_angle,1) + " ACT: " + round(actual_slope,1) + " NEW: " + round(arctan(new_vert/new_dist),1) + " VS TG=" + round(vpid:setpoint,1).
  552. if auto_spoilers_enable {
  553. if tpid:setpoint * 1.1 < airspeed and actual_slope > slope_angle spoilers on.
  554. else spoilers off.
  555. }
  556. } // else pitch_mode = "fixed" => just leave the pitch alone.
  557. if hdg_mode = "circle" {
  558. if circle_target:altitudeposition(altitude):mag > circle_radius {
  559. local alpha is arcsin( circle_radius / circle_target:altitudeposition(altitude):mag ).
  560. set hdg to circle_target:heading + (choose alpha if circle_dir = -1 else -alpha).
  561. } else {
  562. set hdg to circle_target:heading + 92 * -circle_dir.
  563. }
  564. } else if hdg_mode = "target" {
  565. if hdg_target:altitudeposition(altitude):mag < (3 * groundspeed) {
  566. // if we get "close", just keep flying that heading TODO: this should be more rigorous shouldn't it?
  567. set hdg_mode to "heading".
  568. set heading_info to round(hdg,1):tostring + " degrees".
  569. } else {
  570. set hdg to hdg_target:heading.
  571. }
  572. } else if hdg_mode = "line" {
  573. // We are going to make a few of big assumptions and approximations.
  574. // LAT/LNG give us a catersian plane. This is an issue near the poles. And its not really a plane - it's a sphere.
  575. // As you move away from the equator degrees of longitude get smaller by a factor of: sin(90 - abs(latitude)).
  576. // We will use the latitude of the ship for that scaling factor, and hope that distances are small and
  577. // spherical nature of the planet will not be very apparent at the scales we are working with.
  578.  
  579. // We will leave this code commented out - and instead try to stick with using LAT/LNG coordinates.
  580. // first convert lat/lng to x,y in meters. take account the curvature of the planet.
  581. // local x_ship is 0. local y_ship is 0.
  582. // local x_near is (line_tgt_from:lng - ship:geoposition:lng) * m_per_deg * sin(90 - abs(ship:geoposition:lat)).
  583. // local y_near is (line_tgt_from:lat - ship:geoposition:lat) * m_per_deg.
  584. // local x_far is (line_tgt_to:lng - ship:geoposition:lng) * m_per_deg * sin(90 - abs(ship:geoposition:lat)).
  585. // local y_far is (line_tgt_to:lat - ship:geoposition:lat) *m_per_deg.
  586.  
  587. if (line_tgt_to:lng - line_tgt_from:lng) = 0 {
  588. // line has formula x = line_tgt_from:lng i.e. line runs directly north/south through line_tgt_from:lng.
  589. if line_tgt_to:lat > line_tgt_from:lat {
  590. //we need to heard north
  591. // fly towards a point on the line, (line_distance_target) meters north.
  592. local spot is body:geopositionlatlng(ship:geoposition:lat + line_distance_target/m_per_deg, line_tgt_from:lng).
  593. set hdg to spot:heading.
  594. //set vd_line:start to ship:geoposition:position + spot:position.
  595. //set vd_line:vec to ship:geoposition:position + spot:position + up:vector * 50.
  596. } else {
  597. // we need to head south.
  598. local spot is body:geopositionlatlng(ship:geoposition:lat - line_distance_target/m_per_deg, line_tgt_from:lng).
  599. set hdg to spot:heading.
  600. //set vd_line:start to ship:geoposition:position + spot:position.
  601. //set vd_line:vec to ship:geoposition:position + spot:position + up:vector * 50.
  602. }
  603. } else {
  604. local m to (line_tgt_to:lat - line_tgt_from:lat) / (sin(90 - abs(line_tgt_to:lat))*line_tgt_to:lng - sin(90 - abs(line_tgt_from:lat))*line_tgt_from:lng).
  605. local c is line_tgt_from:lat - m * sin(90 - abs(line_tgt_from:lat)) * line_tgt_from:lng.
  606. // line has formula lat = m * sin(90-abs(lat)*lng + c.
  607.  
  608. local new_x is 0.
  609. local a is c * cos(arctan(m))*cos(90-arctan(m)).
  610. local b is cos(arctan(m)) + (line_distance_target/m_per_deg).
  611. if line_tgt_to:lng > line_tgt_from:lng {
  612. set new_x to (ship:geoposition:lng -a + b).
  613. } else {
  614. set new_x to (ship:geoposition:lng -a -b).
  615. }
  616. local spot is body:geopositionlatlng(m * new_x + c, new_x / sin(90-abs(m * new_x + c))).
  617. set hdg to spot:heading.
  618. //set vd_line:start to ship:geoposition:position + spot:position.
  619. //set vd_line:vec to ship:geoposition:position + spot:position + up:vector * 50.
  620. }
  621. }
  622. if hdg_mode = "fixed" or hdg_mode = "target" or hdg_mode = "circle" or hdg_mode = "line" {
  623. if ship:status = "PRELAUNCH" or ship:status = "LANDED" {
  624. set b to 0.
  625. set x to hdg.
  626. //still on the ground - try to steer, but as speed increases do a LOT less wheelsteering.
  627. if abs(ang(hdg,cf())) < 1 {
  628. set ship:control:wheelsteer to 0.
  629. set using_wheelsteer to false.
  630. } else {
  631. set using_wheelsteer to true.
  632. set ship:control:wheelsteer to constrain(
  633. constrain(
  634. -ang(hdg,cf())/10,
  635. -100/(groundspeed+1)^2,
  636. 100/(groundspeed+1)^2
  637. ),
  638. -1,
  639. 1
  640. ).
  641. }.
  642. // we might be using throttle to maintain ship:electriccharge... so using brakes on the ground could be really important.
  643. if dynamic_brakes_enable {
  644. if tpid:setpoint < 0.1 {
  645. brakes on.
  646. } else {
  647. if groundspeed > tpid:setpoint * 1.1 brakes on.
  648. if groundspeed < tpid:setpoint brakes off.
  649. }
  650. }
  651. } else {
  652. //in the air
  653. //if brakes brakes off.
  654. if using_wheelsteer {
  655. set ship:control:wheelsteer to 0.
  656. set using_wheelsteer to false.
  657. }.
  658. local bank_dir is 0.
  659. if hdg_mode = "circle" {
  660. set bank_dir to circle_dir.
  661. set turn_force_dir to 90.
  662. }
  663. if hdg_mode = "fixed" set bank_dir to turn_dir.
  664.  
  665. // force a turn in a particular direction if the angle is over turn_force_dir degrees.
  666. // otherwise turn which ever way is smaller.
  667. if abs(ang(hdg,ct())) < turn_force_dir set bank_dir to 0.
  668. local hdg_error is ang(hdg,ct()).
  669. // force us to turn the other way by faking how much we need to turn :-/
  670. if bank_dir = -1 and hdg_error > 0 {
  671. set hdg_error to hdg_error - 180.
  672. } else if bank_dir = 1 and hdg_error < 0 {
  673. set hdg_error to hdg_error + 180.
  674. }
  675.  
  676. // don't bank so much you stall,
  677. // don't exceed normal bank limits,
  678. // don't change bank too rapidly,
  679. set b to constrain(
  680. -hdg_error * bank_fudge_factor,
  681. max(-bank_stall_angle,max(-bank_limit,b - bank_change_rate)),
  682. min(bank_stall_angle,min(bank_limit,b + bank_change_rate))
  683. ).
  684. set target_rudder to rudder_rate * -b.
  685. if wing_leveler_enable {
  686. // don't bank steeply close to the ground.
  687. set b to constrain(b,-alt_radar(), alt_radar()).
  688. }
  689. set current_rudder to constrain(target_rudder,current_rudder -1, current_rudder + 1).
  690. set x to mod(720 + ct() + current_rudder,360).
  691. }
  692. }
  693. return true.
  694. }
  695.  
  696.  
  697. set valid_dirs to list("left","right","either").
  698. // try to hold a circle - if not landmark to reference is given, circle the current location.
  699. //if "either" direction is given (or no direction given) then a direction has to be determined here.
  700. function circle {
  701. parameter tgt is ship:geoposition.
  702. parameter radius is 1000.
  703. parameter dir is "either".
  704. if not (tgt:hassuffix("distance") and tgt:hassuffix("heading")) and not places:haskey(tgt) {
  705. print char(7) + "ERROR: cannot circle - unrecognised target".
  706. return.
  707. }
  708. if valid_dirs:find(dir) = -1 {
  709. print char(7) + "ERROR: cannot circle - unrecognised direction".
  710. return.
  711. }
  712. if places:haskey(tgt) {
  713. set tgt to places[tgt].
  714. set heading_info to tgt + " radius=" + round(circle_radius) + "m ".
  715. } else {
  716. set heading_info to "LAT:" + round(tgt:lat,3) + " LNG:" + round(tgt:lng,3).
  717. }
  718. set hdg_mode to "circle".
  719. set circle_target to tgt.
  720. set circle_radius to radius.
  721.  
  722. if dir = "either" {
  723. if circle_target:altitudeposition(altitude):mag > circle_radius {
  724. set circle_dir to (choose 1 if ang(circle_target:heading,ct()) > 0 else -1).
  725. } else {
  726. set circle_dir to (choose 1 if abs(ang(circle_target:heading -90 ,ct())) < 90 else -1).
  727. }
  728. } else {
  729. set circle_dir to (choose -1 if dir = "left" else 1 ).
  730. }
  731. set heading_info to heading_info + (choose "left" if circle_dir < 0 else "right").
  732. }.
  733.  
  734.  
  735. // 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.
  736. // 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.
  737. // be careful setting small force angles, any perturbation of the heading could result in complete 360degree turns.
  738. set force_dirs to list("closest","left","right").
  739. function tt {
  740. parameter tgt.
  741. parameter force_dir is "closest".
  742. parameter force_angle is 45.
  743. if force_dirs:find(force_dir) = -1 {
  744. print char(7) + "ERROR: " + force_dir + " is not a recognised direction".
  745. } else {
  746. set turn_force_dir to force_angle.
  747. if force_dir = "closest" or abs(ang(tgt,ct())) < force_angle {
  748. set hdg_mode to "fixed".
  749. set hdg to tgt.
  750. set turn_dir to 0.
  751. } else if force_dir = "left" {
  752. set hdg_mode to "fixed".
  753. set hdg to tgt.
  754. set turn_dir to -1.
  755. } else if force_dir = "right" {
  756. set hdg_mode to "fixed".
  757. set hdg to tgt.
  758. set turn_dir to 1.
  759. }
  760. set heading_info to hdg:tostring + " deg".
  761. }
  762. return true.
  763. }.
  764.  
  765. //pilot is requesting to fly to a particular location.
  766. function goto {
  767. parameter where.
  768. if where:hassuffix("heading") and where:hassuffix("distance") {
  769. set hdg_mode to "target".
  770. set hdg_target to where.
  771. set heading_info to "LAT:" + round(where:lat,3) + " LNG:" + round(where:lng,3).
  772. } else if places:haskey(where) {
  773. set hdg_mode to "target".
  774. set hdg_target to places[where].
  775. set heading_info to where.
  776. } else {
  777. print "Sorry, I don't know where " + where + " is.".
  778. }
  779. return true.
  780. }.
  781.  
  782.  
  783. // pilot is requesting to fly NOE at a certain height off the ground.
  784. function hr {
  785. parameter tgt.
  786. if pitch_mode <> "radar" {
  787. rpid:reset().
  788. set pitch_mode to "radar".
  789. }
  790. set rpid:setpoint to tgt.
  791. set pitch_info to "NOE " + round(tgt,1) + " m".
  792. return true.
  793. }.
  794.  
  795. //pilot is requesting to hold a particular speed - if we are using throttle to maintain electric charge,
  796. //then when electriccharge is low, kick in enough throttle to maintain some charge!
  797. //in the air electric_throttle_enable might not be noticed, but on the ground a small change in throttle could
  798. //easily cause problems... so might be a good idea to also set dynamic_brakes_enable to true to prevent overspeeds.
  799. function hs {
  800. parameter tgt is 0.
  801. if tgt = "" {
  802. unlock throttle.
  803. } else {
  804. set tpid:setpoint to tgt.
  805. lock throttle to max(tpid:update(time:seconds,airspeed),choose 100 - ship:electriccharge if electric_throttle_enable else 0).
  806. }
  807. return true.
  808. }.
  809.  
  810. //pilot has requested to hold a particular pitch
  811. function hp {
  812. parameter tgt.
  813. set pitch_mode to "fixed".
  814. set p to tgt.
  815. set pitch_info to round(tgt,1) + " deg".
  816. return true.
  817. }
  818.  
  819. //pilot is requesting to hold a particular climb/sink rate
  820. function hv {
  821. parameter tgt.
  822. if pitch_mode <> "vert" and pitch_mode <> "slope" {
  823. vpid:reset().
  824. }
  825. set pitch_mode to "vert".
  826. set vpid:setpoint to tgt.
  827. if tgt < 0 {
  828. set pitch_info to "Descend " + round(tgt,1) + " m/s".
  829. } else if tgt > 0 {
  830. set pitch_info to "Climb " + round(tgt,1) + " m/s".
  831. } else {
  832. set pitch_info to "Level Flight".
  833. }.
  834. return true.
  835. }.
  836.  
  837. //hold glideslope.
  838. function hg {
  839. parameter slope.
  840. parameter tgt.
  841. parameter ht is 0.
  842. parameter dist is 0.
  843.  
  844. set slope_angle to slope.
  845. set slope_target to tgt.
  846. set slope_height_adj to ht.
  847. set slope_distance_adj to dist.
  848. if pitch_mode <> "vert" and pitch_mode <> "slope" {
  849. vpid:reset().
  850. }
  851. //main flight loop will calculate the vertspd to fly and set p accordingly.
  852. set pitch_mode to "slope".
  853. set pitch_info to round(slope,1) + " deg slope".
  854. return true.
  855. }
  856.  
  857. //hold line - note this says NOTHING about how close to those points we are - just that we want to be on that line.
  858. function hl {
  859. parameter tgt_from.
  860. parameter tgt_to.
  861. if hdg_mode <> "line" lpid:reset().
  862. set hdg_mode to "line".
  863. set line_tgt_from to tgt_from.
  864. set line_tgt_to to tgt_to.
  865. set heading_info to "runway 90".
  866. }
  867.  
  868. //pilot is requesting to hold a particular altitude.
  869. function ha {
  870. parameter tgt.
  871. if pitch_mode <> "alt" {
  872. apid:reset().
  873. set pitch_mode to "alt".
  874. }
  875. set apid:setpoint to tgt.
  876. set pitch_info to "hold " + round(tgt,1) + " m".
  877. }.
  878.  
  879.  
  880. if ship:status <> "flying" {
  881.  
  882. wait 2.
  883.  
  884. set runway_start to places["vab pad 1"].
  885. set runway_end to places["vab pad 2"].
  886. set runway_normalized to ( runway_end:position - runway_start:position ):normalized.
  887. set runway_touchdown to body:geopositionof(runway_start:position - runway_normalized * 5).
  888. set runway_final to body:geopositionof(runway_normalized * -2000 + runway_start:position).
  889. set runway_right to body:geopositionof(
  890. ( runway_normalized * -2000) +
  891. (vcrs(up:vector,runway_normalized):normalized*800) + runway_start:position
  892. ).
  893. set runway_left to body:geopositionof(
  894. ( runway_normalized * -2000) +
  895. (vcrs(runway_normalized,up:vector):normalized*800) + runway_start:position
  896. ).
  897.  
  898.  
  899. set runway_alt to altitude.
  900. stage.
  901. brakes off.
  902. lights on.
  903. flaps on.
  904. hs(vto).
  905. hp(10).
  906. when alt:radar > 50 then gear off.
  907. when altitude > (runway_alt + 100) then {
  908. flaps off.
  909. hs(vc).
  910. tt(0).
  911. when altitude > (runway_alt + 310) then {
  912. ha(runway_alt + 330).
  913. circle(runway_left,970,"left").
  914. when abs(runway_final:altitudeposition(altitude):mag) < 500 and abs(ang(runway_touchdown:heading,ct())) < 10 then {
  915. hl(runway_start,runway_end).
  916. flaps on.
  917. hs(vtd).
  918. hg(5,runway_touchdown,0,0).
  919. when airspeed < vlo or alt:radar < 50 then gear on.
  920. when runway_touchdown:altitudeposition(altitude):mag < 80 then {
  921. set auto_spoilers_enable to false.
  922. hv(-1).
  923. revthrust on.
  924. lock throttle to 1.
  925. brakes on.
  926. flaps off.
  927. spoilers on.
  928. when airspeed < 5 then lock throttle to 0.
  929. }.
  930. }
  931. }
  932. }
  933. }
  934.  
  935. if not (bodyexists("Lua")) {
  936. wait until rcs.
  937. clearguis().
  938. clearvecdraws().
  939. }
  940.  
  941.  
  942.  
Add Comment
Please, Sign In to add comment