generic-yasim-engine.nas 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. # generic-yasim-engine.nas -- a generic Nasal-based engine control system for YASim
  2. # Version 1.0.0
  3. #
  4. # Copyright (C) 2011 Ryan Miller
  5. #
  6. # This program is free software; you can redistribute it and/or
  7. # modify it under the terms of the GNU General Public License as
  8. # published by the Free Software Foundation; either version 2 of the
  9. # License, or (at your option) any later version.
  10. #
  11. # This program is distributed in the hope that it will be useful, but
  12. # WITHOUT ANY WARRANTY; without even the implied warranty of
  13. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. # General Public License for more details.
  15. #
  16. # You should have received a copy of the GNU General Public License
  17. # along with this program; if not, write to the Free Software
  18. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  19. #
  20. var UPDATE_PERIOD = 0.01; # update interval for engine init() functions
  21. # jet engine class
  22. var Jet =
  23. {
  24. # creates a new engine object
  25. new: func(n, running = 0, idle_throttle = 0.01, max_start_n1 = 5.21, start_threshold = 5, spool_time = 4, start_time = 5, shutdown_time = 4)
  26. {
  27. # copy the Jet object
  28. var m = { parents: [Jet] };
  29. # declare object variables
  30. m.number = n;
  31. m.autostart_status = 0;
  32. m.autostart_id = -1;
  33. m.loop_running = 0;
  34. m.started = 0;
  35. m.starting = 0;
  36. m.idle_throttle = idle_throttle;
  37. m.max_start_n1 = max_start_n1;
  38. m.start_threshold = start_threshold;
  39. m.spool_time = spool_time;
  40. m.start_time = start_time;
  41. m.shutdown_time = shutdown_time;
  42. # create references to properties and set default values
  43. m.cutoff = props.globals.getNode("controls/engines/engine[" ~ n ~ "]/cutoff", 1);
  44. m.cutoff.setBoolValue(!running);
  45. m.n1 = props.globals.getNode("engines/engine[" ~ n ~ "]/n1", 1);
  46. m.n1.setDoubleValue(0);
  47. m.out_of_fuel = props.globals.getNode("engines/engine[" ~ n ~ "]/out-of-fuel", 1);
  48. m.out_of_fuel.setBoolValue(0);
  49. m.reverser = props.globals.getNode("controls/engines/engine[" ~ n ~ "]/reverser", 1);
  50. m.reverser.setBoolValue(0);
  51. m.rpm = props.globals.getNode("engines/engine[" ~ n ~ "]/rpm", 1);
  52. m.rpm.setDoubleValue(running ? 100 : 0);
  53. m.running = props.globals.getNode("engines/engine[" ~ n ~ "]/running", 1);
  54. m.running.setBoolValue(running);
  55. m.serviceable = props.globals.getNode("engines/engine[" ~ n ~ "]/serviceable", 1);
  56. m.serviceable.setBoolValue(1);
  57. m.starter = props.globals.getNode("controls/engines/engine[" ~ n ~ "]/starter", 1);
  58. m.starter.setBoolValue(0);
  59. m.throttle = props.globals.getNode("controls/engines/engine[" ~ n ~ "]/throttle", 1);
  60. m.throttle.setDoubleValue(0);
  61. m.throttle_lever = props.globals.getNode("controls/engines/engine[" ~ n ~ "]/throttle-lever", 1);
  62. m.throttle_lever.setDoubleValue(0);
  63. m.mp_engine_status = props.globals.getNode("sim/multiplay/generic/string[8]", 1);
  64. m.mp_engine_status.setValue(0);
  65. # return our new object
  66. return m;
  67. },
  68. # engine-specific autostart
  69. autostart: func
  70. {
  71. if (me.autostart_status)
  72. {
  73. me.autostart_status = 0;
  74. me.cutoff.setBoolValue(1);
  75. }
  76. else
  77. {
  78. me.autostart_status = 1;
  79. me.starter.setBoolValue(1);
  80. settimer(func
  81. {
  82. me.cutoff.setBoolValue(0);
  83. }, me.max_start_n1 / me.start_time);
  84. }
  85. },
  86. # creates an engine update loop (optional)
  87. init: func
  88. {
  89. if (me.loop_running) return;
  90. me.loop_running = 1;
  91. var loop = func
  92. {
  93. me.update();
  94. settimer(loop, UPDATE_PERIOD);
  95. };
  96. settimer(loop, 0);
  97. },
  98. # updates the engine
  99. update: func
  100. {
  101. if (me.running.getBoolValue() and !me.started)
  102. {
  103. me.running.setBoolValue(0);
  104. #me.mp_engine_status.setValue(3);
  105. }
  106. if (me.cutoff.getBoolValue() or !me.serviceable.getBoolValue() or me.out_of_fuel.getBoolValue())
  107. {
  108. var rpm = me.rpm.getValue();
  109. var time_delta = getprop("sim/time/delta-realtime-sec");
  110. if (me.starter.getBoolValue())
  111. {
  112. rpm += time_delta * me.spool_time;
  113. me.rpm.setValue(rpm >= me.max_start_n1 ? me.max_start_n1 : rpm);
  114. me.mp_engine_status.setValue(1);
  115. }
  116. else
  117. {
  118. rpm -= time_delta * me.shutdown_time;
  119. me.rpm.setValue(rpm <= 0 ? 0 : rpm);
  120. me.running.setBoolValue(0);
  121. me.throttle.setDoubleValue(0);
  122. me.throttle_lever.setDoubleValue(0);
  123. me.started = 0;
  124. if ( me.rpm.getValue() > 0 ) {
  125. me.mp_engine_status.setValue(3);
  126. }
  127. else {
  128. me.mp_engine_status.setValue(0);
  129. }
  130. }
  131. }
  132. elsif (me.starter.getBoolValue())
  133. {
  134. var rpm = me.rpm.getValue();
  135. if (rpm >= me.start_threshold)
  136. {
  137. var time_delta = getprop("sim/time/delta-realtime-sec");
  138. rpm += time_delta * me.spool_time;
  139. me.rpm.setValue(rpm);
  140. if (rpm >= me.n1.getValue())
  141. {
  142. me.running.setBoolValue(1);
  143. me.starter.setBoolValue(0);
  144. me.mp_engine_status.setValue(2);
  145. me.started = 1;
  146. }
  147. else
  148. {
  149. me.running.setBoolValue(0);
  150. me.mp_engine_status.setValue(1);
  151. }
  152. }
  153. }
  154. elsif (me.running.getBoolValue())
  155. {
  156. me.throttle_lever.setValue(me.idle_throttle + (1 - me.idle_throttle) * me.throttle.getValue());
  157. me.rpm.setValue(me.n1.getValue());
  158. me.mp_engine_status.setValue(2);
  159. }
  160. }
  161. };
  162. # turboprop engine class
  163. var turboprop_condition_cutoff = 0.001; # minimum condition value for YASim turboprops to start
  164. var Turboprop =
  165. {
  166. new: func(n, running = 0, min_condition = 0.2)
  167. {
  168. # copy the Turboprop object
  169. var m = { parents: [Turboprop] };
  170. # declare object variables
  171. m.number = n;
  172. m.autostart_status = 0;
  173. m.loop_running = 0;
  174. m.min_condition = min_condition;
  175. # create references to properties and set default values
  176. m.condition = props.globals.getNode("controls/engines/engine[" ~ n ~ "]/condition", 1);
  177. m.condition.setDoubleValue(0);
  178. m.condition_lever = props.globals.getNode("controls/engines/engine[" ~ n ~ "]/condition-lever", 1);
  179. m.condition_lever.setDoubleValue(running ? min_condition : 0);
  180. m.cutoff = props.globals.getNode("controls/engines/engine[" ~ n ~ "]/cutoff", 1);
  181. m.cutoff.setBoolValue(!running);
  182. m.n1 = props.globals.getNode("engines/engine[" ~ n ~ "]/n1", 1);
  183. m.n1.setDoubleValue(running ? 100 : 0);
  184. m.n2 = props.globals.getNode("engines/engine[" ~ n ~ "]/n2", 1);
  185. m.n2.setDoubleValue(0);
  186. m.out_of_fuel = props.globals.getNode("engines/engine[" ~ n ~ "]/out-of-fuel", 1);
  187. m.out_of_fuel.setBoolValue(0);
  188. m.propeller_feather = props.globals.getNode("controls/engines/engine[" ~ n ~ "]/propeller-feather", 1);
  189. m.propeller_feather.setBoolValue(0);
  190. m.starter = props.globals.getNode("controls/engines/engine[" ~ n ~ "]/starter", 1);
  191. m.starter.setBoolValue(0);
  192. # return our new object
  193. return m;
  194. },
  195. # engine-specific autostart
  196. autostart: func
  197. {
  198. if (me.autostart_status)
  199. {
  200. me.autostart_status = 0;
  201. me.cutoff.setBoolValue(1);
  202. me.condition.setValue(0);
  203. }
  204. else
  205. {
  206. me.autostart_status = 1;
  207. me.cutoff.setBoolValue(0);
  208. me.starter.setBoolValue(1);
  209. me.condition.setValue(me.min_condition);
  210. }
  211. },
  212. # creates an engine update loop (optional)
  213. init: func
  214. {
  215. if (me.loop_running) return;
  216. me.loop_running = 1;
  217. var loop = func
  218. {
  219. me.update();
  220. settimer(loop, UPDATE_PERIOD);
  221. };
  222. settimer(loop, 0);
  223. },
  224. # updates the engine
  225. update: func
  226. {
  227. if (me.cutoff.getBoolValue())
  228. {
  229. me.out_of_fuel.setBoolValue(1);
  230. }
  231. if (me.starter.getBoolValue() and me.condition_lever.getValue() < turboprop_condition_cutoff and me.condition.getValue() >= me.min_condition)
  232. {
  233. me.condition_lever.setValue(me._get_condition_value(me.condition.getValue()));
  234. }
  235. elsif (me.condition_lever.getValue() < turboprop_condition_cutoff and me.n2.getValue() < 0.5)
  236. {
  237. if (me.propeller_feather.getBoolValue())
  238. {
  239. me.n1.setValue(0);
  240. }
  241. me.condition_lever.setValue(0);
  242. }
  243. if (me.n2.getValue() >= 0.5)
  244. {
  245. if (me.condition_lever.getValue() >= turboprop_condition_cutoff)
  246. {
  247. me.condition_lever.setValue(me._get_condition_value(me.condition.getValue()));
  248. }
  249. else
  250. {
  251. me.condition_lever.setValue(0);
  252. }
  253. me.n1.setValue(me.n2.getValue());
  254. }
  255. },
  256. _get_condition_value: func(v)
  257. {
  258. if (v >= me.min_condition)
  259. {
  260. return turboprop_condition_cutoff + (v - me.min_condition) / (1 - me.min_condition) * (1 - turboprop_condition_cutoff);
  261. }
  262. return v / me.min_condition * turboprop_condition_cutoff;
  263. }
  264. };