Parachute.nas 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. # Parachute for YASim by Tomaskom
  2. # This code drives three thrusters which need to be defined in the YASim FDM definition. They point in the X, Y, Z axis direction. The thrusters should be placed where the parachute is attached, not where the top of the parachute is! Only this way, it can properly reflect different directions of airflow.
  3. ### User defined variables ###
  4. var chuteArea = 104; #size of the parachute in square meters
  5. var Cd = 1.42; #coefficient of drag: 1.42 for hollow hemisphere (like parachute)
  6. var loop = 0.02; #seconds for looping force calculation; tested for 0.05 (20Hz) or faster
  7. var chuteUnfold = 3; #seconds of chute unfolding time
  8. var chutePower = "/controls/flight/parachute"; #property used for slow applying of the force as chute unfolds
  9. var listen = "/controls/flight/drag-chute"; #boolean property triggering the parachute deployment
  10. var show = "surface-positions/chute-pos-norm"; #property used to show/hide parachute model
  11. var animTheta = "/orientation/parachute-theta"; #property for parachute 3D model animation
  12. var animPhi = "/orientation/parachute-phi"; #property for parachute 3D model animation
  13. var forcePoint = {x:0, y:0, z:1}; #vector pointing from CG to the point where force is applied - must reflect thrusters position!
  14. var thrustCoef = 10000; #nominal thruster thrust as defined in YASim - must be the same to get properly scaled force
  15. var limit = 1500; #limit of drag force, in multiples of nominal thruster thrust in YASim
  16. var ftTom = 0.3048; #ft to m
  17. var degToRad = 3.141592654/180;
  18. props.globals.initNode("/controls/engines/thruster[1]/throttle", 0, "DOUBLE");
  19. props.globals.initNode("/controls/engines/thruster[2]/throttle", 0, "DOUBLE");
  20. props.globals.initNode("/controls/engines/thruster[3]/throttle", 0, "DOUBLE");
  21. props.globals.initNode(chutePower, 0, "DOUBLE");
  22. props.globals.initNode(show, 0, "DOUBLE");
  23. props.globals.initNode(animTheta, 0, "DOUBLE");
  24. props.globals.initNode(animPhi, 0, "DOUBLE");
  25. ### Extended trigonometric functions by Ampere K. [Hardraade] ###
  26. # Returns arccos(x), with -1 < x < 1.
  27. math.arccos = func(x){
  28. return (3.141592654/2 - math.arcsin(x));
  29. }
  30. # Returns arcsin(x), with -1 < x < 1.
  31. math.arcsin = func(x){
  32. # Find arcsin(x) by first doing a table look-up, then interopolate the value of the desire point using
  33. # integration. Accuracy could be achieved up to the 8th decimal place if necessary.
  34. factor = 1;
  35. power = math.pow(10, 6); # Accuracy up to the nth decimal place.
  36. precision = math.pow(power, -1);
  37. tableSize = 100; # Size of the look-up table.
  38. # Negative and positive angles yield the same result, only the signs are different.
  39. if (x < 0){
  40. factor = -1;
  41. x = x * factor;
  42. }
  43. # Look-up table for every 1.8 degrees, for a total of 180 degrees.
  44. table = [0,
  45. 0.010000167, 0.020001334, 0.030004502, 0.040010674, 0.050020857,
  46. 0.060036058, 0.070057293, 0.080085580, 0.090121945, 0.100167421,
  47. 0.110223050, 0.120289882, 0.130368980, 0.140461415, 0.150568273,
  48. 0.160690653, 0.170829669, 0.180986451, 0.191162147, 0.201357921,
  49. 0.211574960, 0.221814470, 0.232077683, 0.242365851, 0.252680255,
  50. 0.263022203, 0.273393031, 0.283794109, 0.294226838, 0.304692654,
  51. 0.315193032, 0.325729487, 0.336303575, 0.346916898, 0.357571104,
  52. 0.368267893, 0.379009021, 0.389796296, 0.400631593, 0.411516846,
  53. 0.422454062, 0.433445320, 0.444492777, 0.455598673, 0.466765339,
  54. 0.477995199, 0.489290778, 0.500654712, 0.512089753, 0.523598776,
  55. 0.535184790, 0.546850951, 0.558600565, 0.570437109, 0.582364238,
  56. 0.594385800, 0.606505855, 0.618728691, 0.631058841, 0.643501109,
  57. 0.656060591, 0.668742703, 0.681553212, 0.694498266, 0.707584437,
  58. 0.720818761, 0.734208787, 0.747762635, 0.761489053, 0.775397497,
  59. 0.789498209, 0.803802319, 0.818321951, 0.833070358, 0.848062079,
  60. 0.863313115, 0.878841152, 0.894665817, 0.910808997, 0.927295218,
  61. 0.944152115, 0.961411019, 0.979107684, 0.997283222, 1.015985294,
  62. 1.035269672, 1.055202321, 1.075862200, 1.097345170, 1.119769515,
  63. 1.143284062, 1.168080485, 1.194412844, 1.222630306, 1.253235898,
  64. 1.287002218, 1.325230809, 1.370461484, 1.429256853, 1.570796327];
  65. intPart = int(x * tableSize + 0.5);
  66. decPart = (x * tableSize - intPart) / tableSize ;
  67. area = 0;
  68. # Perform integration to calculate arcsin(x).
  69. # Positive case:
  70. for(i = intPart/tableSize; i < intPart/tableSize + decPart; i = i + precision){
  71. # Calculate the area of a trapezoid.
  72. a = 1 / math.sqrt(1 - math.pow(i, 2));
  73. b = 1 / math.sqrt(1 - math.pow(i + precision, 2));
  74. area = area + a + b;
  75. }
  76. # Negative case:
  77. for(i = (intPart - precision) / tableSize; i > intPart/tableSize + decPart; i = i - precision){
  78. # Calculate the area of a trapezoid.
  79. a = 1 / math.sqrt(1 - math.pow(i - precision, 2));
  80. b = 1 / math.sqrt(1 - math.pow(i, 2));
  81. area = area - a - b;
  82. }
  83. return ((table[intPart] + int(area + 0.5) * precision / 2) * factor);
  84. }
  85. ### END OF Extended trigonometric functions ###
  86. #the main loop computing force
  87. var chute = func {
  88. var heading = degToRad * getprop("/orientation/heading-deg"); #right is positive
  89. var pitch = degToRad * getprop("/orientation/pitch-deg"); #up is positive
  90. var roll = degToRad * getprop("/orientation/roll-deg"); #right is positive
  91. #get velocity components
  92. var speedUp = -getprop("/velocities/speed-down-fps");
  93. var speedEast = getprop("/velocities/speed-east-fps");
  94. var speedNorth = getprop("/velocities/speed-north-fps");
  95. var windUp = getprop("/environment/wind-from-down-fps");
  96. var windEast = -getprop("/environment/wind-from-east-fps"); #wind TO east
  97. var windNorth = -getprop("/environment/wind-from-north-fps"); # winf TO north
  98. #subtract wind components
  99. var up = speedUp - windUp;
  100. var east = speedEast - windEast;
  101. var north = speedNorth - windNorth;
  102. var up_mps = ftTom * up;
  103. var east_mps = ftTom * east;
  104. var north_mps = ftTom * north;
  105. #take heading in account
  106. var fwd_mps = math.cos(heading) * north_mps + math.sin(heading) * east_mps;
  107. var left_mps = math.sin(heading) * north_mps - math.cos(heading) * east_mps;
  108. #transform speed components to local up, fwd and side
  109. var up_local = up_mps * math.cos(pitch) * math.cos(roll) - fwd_mps * math.sin(pitch) * math.cos(roll) - left_mps * math.sin(roll);
  110. var fwd_local = fwd_mps * math.cos(pitch) + up_mps * math.sin(pitch);
  111. var left_local = left_mps * math.cos(roll) + up_mps * math.sin(roll) * math.cos(pitch) - fwd_mps * math.sin(pitch) * math.sin(roll);
  112. var pitchRateFix = (abs(getprop("/orientation/roll-deg"))<90 ? 1 : -1);
  113. var pitchRate = degToRad * getprop("/orientation/pitch-rate-degps");
  114. var rollRate = degToRad * getprop("/orientation/roll-rate-degps");
  115. var yawRate = degToRad * getprop("/orientation/yaw-rate-degps") * pitchRateFix;
  116. #forcePoint speed components relative to air - add components caused by rotation of hanging aircraft (dampens oscillations if I don't omit this)
  117. var upPoint =
  118. up_local
  119. + forcePoint.x * pitchRate * pitchRateFix
  120. + forcePoint.y * rollRate
  121. + math.sin(roll) * forcePoint.x * yawRate * math.cos(pitch);
  122. var fwdPoint =
  123. fwd_local
  124. - forcePoint.z * pitchRate * pitchRateFix
  125. + forcePoint.y * yawRate * math.cos(pitch)
  126. - math.sin(roll) * forcePoint.y * pitchRate;
  127. var leftPoint =
  128. left_local
  129. - forcePoint.x * yawRate * math.cos(pitch)
  130. - forcePoint.z * rollRate
  131. + math.sin(roll) * forcePoint.x * pitchRate;
  132. #debugging output
  133. #print("up_local:"~up_local~" fwd_local:"~fwd_local~" left_local:"~left_local);
  134. #print("upPoint:"~upPoint~ " fwdPoint:"~fwdPoint~" leftPoint:"~leftPoint); print("");
  135. #get normalized vector
  136. var vectSize = math.sqrt(upPoint*upPoint + fwdPoint*fwdPoint + leftPoint*leftPoint);
  137. var direction = {x:fwdPoint/vectSize, y:leftPoint/vectSize, z:upPoint/vectSize};
  138. #get total drag force
  139. var airDensity = 515.4 * getprop("/environment/density-slugft3");
  140. var force = 0.5 * airDensity * vectSize*vectSize * Cd * chuteArea;
  141. var forcelb = 0.2248 * force;
  142. var xThrust = -forcelb * direction.x / thrustCoef;
  143. var yThrust = -forcelb * direction.y / thrustCoef;
  144. var zThrust = -forcelb * direction.z / thrustCoef;
  145. setprop("/controls/engines/thruster[1]/throttle", (abs(xThrust)>limit?limit*math.sgn(xThrust):xThrust)*getprop(chutePower));
  146. setprop("/controls/engines/thruster[2]/throttle", (abs(yThrust)>limit?limit*math.sgn(yThrust):yThrust)*getprop(chutePower));
  147. setprop("/controls/engines/thruster[3]/throttle", (abs(zThrust)>limit?limit*math.sgn(zThrust):zThrust)*getprop(chutePower));
  148. #parachude 3D model orientation calculation
  149. setprop(animTheta, math.arccos(-direction.z)/degToRad);
  150. setprop(animPhi, math.atan2(direction.x,-direction.y)/degToRad);
  151. }
  152. #cycle the main loop only when chute is deployed
  153. var chuteTimer = maketimer(loop, chute);
  154. chuteTimer.singleShot = 0;
  155. setlistener(listen,
  156. func {
  157. if(getprop(listen)) {
  158. setprop(chutePower, 0);
  159. interpolate(chutePower, 1, chuteUnfold);
  160. setprop(show, 1);
  161. print("Deploying parachute!");
  162. chuteTimer.start();
  163. }
  164. else {
  165. interpolate(chutePower, 0, 0);
  166. print("Parachute cut away!");
  167. setprop(show, 0);
  168. chuteTimer.stop();
  169. setprop("/controls/engines/thruster[1]/throttle", 0);
  170. setprop("/controls/engines/thruster[2]/throttle", 0);
  171. setprop("/controls/engines/thruster[3]/throttle", 0);
  172. setprop(chutePower, 0);
  173. }
  174. }
  175. );