574
edits
m (cat) |
(→How to install the current system on an aircraft: version 0.11) |
||
Line 10: | Line 10: | ||
== How to install the current system on an aircraft == | == How to install the current system on an aircraft == | ||
Copy this code into your aircrafts Nasal folder as | Copy this code into your aircrafts Nasal folder as crash-and-stress.nas file: | ||
<syntaxhighlight lang="nasal"> | <syntaxhighlight lang="nasal"> | ||
# | # | ||
Line 20: | Line 20: | ||
# | # | ||
# | # | ||
# Version 0. | # Version 0.11 | ||
# | # | ||
# License: | # License: | ||
Line 29: | Line 29: | ||
var FALSE = 0; | var FALSE = 0; | ||
var | var CrashAndStress = { | ||
# pattern singleton | # pattern singleton | ||
_instance: nil, | _instance: nil, | ||
Line 38: | Line 38: | ||
if(me._instance == nil) { | if(me._instance == nil) { | ||
me._instance = {}; | me._instance = {}; | ||
me._instance["parents"] = [ | me._instance["parents"] = [CrashAndStress]; | ||
m = me._instance; | m = me._instance; | ||
Line 48: | Line 48: | ||
m.wingsAttached = TRUE; | m.wingsAttached = TRUE; | ||
m.wingLoadLimitUpper = nil; | m.wingLoadLimitUpper = nil; | ||
m.wingLoadLimitLower = nil; | m.wingLoadLimitLower = nil; | ||
m. | m._looptimer = maketimer(0, m, m._loop); | ||
m.input = { | m.input = { | ||
# trembleOn: "damage/g-tremble-on", | |||
# trembleMax: "damage/g-tremble-max", | |||
replay: "sim/replay/replay-state", | replay: "sim/replay/replay-state", | ||
lat: "position/latitude-deg", | lat: "position/latitude-deg", | ||
lon: "position/longitude-deg", | lon: "position/longitude-deg", | ||
Line 61: | Line 61: | ||
altAgl: "position/altitude-agl-ft", | altAgl: "position/altitude-agl-ft", | ||
elev: "position/ground-elev-ft", | elev: "position/ground-elev-ft", | ||
crackOn: "damage/sounds/crack-on", | crackOn: "damage/sounds/crack-on", | ||
creakOn: "damage/sounds/creaking-on", | creakOn: "damage/sounds/creaking-on", | ||
crackVol: "damage/sounds/crack-volume", | crackVol: "damage/sounds/crack-volume", | ||
creakVol: "damage/sounds/creaking-volume", | creakVol: "damage/sounds/creaking-volume", | ||
wCrashOn: "damage/sounds/water-crash-on", | wCrashOn: "damage/sounds/water-crash-on", | ||
crashOn: "damage/sounds/crash-on", | crashOn: "damage/sounds/crash-on", | ||
detachOn: "damage/sounds/detach-on", | detachOn: "damage/sounds/detach-on", | ||
explodeOn: "damage/sounds/explode-on", | explodeOn: "damage/sounds/explode-on", | ||
}; | }; | ||
foreach(var ident; keys(m.input)) { | foreach(var ident; keys(m.input)) { | ||
Line 82: | Line 74: | ||
} | } | ||
m.fdm = nil; | |||
if(getprop("sim/flight-model") == "jsb") { | |||
m.fdm = jsbSimProp; | |||
} elsif(getprop("sim/flight-model") == "yasim") { | |||
m.fdm = yaSimProp; | |||
} else { | |||
return nil; | |||
} | |||
m.fdm.convert(); | |||
m.wowStructure = []; | m.wowStructure = []; | ||
m.wowGear = []; | m.wowGear = []; | ||
Line 123: | Line 126: | ||
me.lastMessageTime = 0; | me.lastMessageTime = 0; | ||
me.repairing = TRUE; | me.repairing = TRUE; | ||
var timer = maketimer(10, me, me._finishRepair); | |||
timer.start(); | |||
}, | }, | ||
# accepts a vector with failure mode IDs, they will fail when wings break off. | # accepts a vector with failure mode IDs, they will fail when wings break off. | ||
setWingsFailureModes: func (modes) { | setWingsFailureModes: func (modes) { | ||
me. | if(modes == nil) { | ||
modes = []; | |||
} | |||
## | |||
# Returns an actuator object that will set the serviceable property at | |||
# the given node to zero when the level of failure is > 0. | |||
# it will also fail additionally failure modes. | |||
var set_unserviceable_cascading = func(path, casc_paths) { | |||
var prop = path ~ "/serviceable"; | |||
if (props.globals.getNode(prop) == nil) { | |||
props.globals.initNode(prop, TRUE, "BOOL"); | |||
} else { | |||
props.globals.getNode(prop).setValue(TRUE);#in case this gets initialized empty from a recorder signal or MP alias. | |||
} | |||
return { | |||
parents: [FailureMgr.FailureActuator], | |||
mode_paths: casc_paths, | |||
set_failure_level: func(level) { | |||
setprop(prop, level > 0 ? 0 : 1); | |||
foreach(var mode_path ; me.mode_paths) { | |||
FailureMgr.set_failure_level(mode_path, level); | |||
} | |||
}, | |||
get_failure_level: func { getprop(prop) ? 0 : 1 } | |||
} | |||
} | |||
var prop = me.fdm.wingsFailureID; | |||
var actuator_wings = set_unserviceable_cascading(prop, modes); | |||
FailureMgr.add_failure_mode(prop, "Main wings", actuator_wings); | |||
}, | }, | ||
# set the stresslimit for the main wings | # set the stresslimit for the main wings | ||
setStressLimit: func (stressLimit = nil) { | setStressLimit: func (stressLimit = nil) { | ||
if (stressLimit != nil) { | if (stressLimit != nil) { | ||
var wingloadMax = stressLimit[' | var wingloadMax = stressLimit['wingloadMaxLbs']; | ||
var wingloadMin = stressLimit[' | var wingloadMin = stressLimit['wingloadMinLbs']; | ||
var maxG = stressLimit['maxG']; | var maxG = stressLimit['maxG']; | ||
var minG = stressLimit['minG']; | var minG = stressLimit['minG']; | ||
var weight = stressLimit[' | var weight = stressLimit['weightLbs']; | ||
if(wingloadMax != nil) { | if(wingloadMax != nil) { | ||
me.wingLoadLimitUpper = wingloadMax; | me.wingLoadLimitUpper = wingloadMax; | ||
Line 150: | Line 188: | ||
me.wingLoadLimitLower = -me.wingLoadLimitUpper * 0.4;#estimate for when lower is not specified | me.wingLoadLimitLower = -me.wingLoadLimitUpper * 0.4;#estimate for when lower is not specified | ||
} | } | ||
me. | me._looptimer.start(); | ||
} else { | } else { | ||
me. | me._looptimer.stop(); | ||
} | } | ||
}, | }, | ||
Line 198: | Line 235: | ||
}, | }, | ||
_startImpactListeners: func () { | _startImpactListeners: func () { | ||
ImpactStructureListener.crash = me; | |||
foreach(var structure; me.wowStructure) { | foreach(var structure; me.wowStructure) { | ||
setlistener(structure, func {call( | setlistener(structure, func {call(ImpactStructureListener.run, nil, ImpactStructureListener, ImpactStructureListener)},0,0); | ||
} | } | ||
}, | }, | ||
_isRunning: func () { | |||
if (me.inService == FALSE or me.input.replay.getBoolValue() == TRUE or me.repairing == TRUE) { | |||
return FALSE; | |||
if (me.inService == | |||
} | } | ||
var time = me.fdm.input.simTime.getValue(); | |||
var time = me.input.simTime.getValue(); | |||
if (time != nil and time > 1) { | if (time != nil and time > 1) { | ||
return TRUE; | return TRUE; | ||
Line 223: | Line 251: | ||
}, | }, | ||
_calcGroundSpeed: func () { | _calcGroundSpeed: func () { | ||
var horzSpeed = me.input.vgFps.getValue(); | var horzSpeed = me.fdm.input.vgFps.getValue(); | ||
var vertSpeed = me.input.downFps.getValue(); | var vertSpeed = me.fdm.input.downFps.getValue(); | ||
var realSpeed = math.sqrt((horzSpeed * horzSpeed) + (vertSpeed * vertSpeed)); | var realSpeed = math.sqrt((horzSpeed * horzSpeed) + (vertSpeed * vertSpeed)); | ||
realSpeed = realSpeed | realSpeed = me.fdm.fps2kt(realSpeed); | ||
return realSpeed; | return realSpeed; | ||
}, | }, | ||
Line 239: | Line 267: | ||
var failure_modes = FailureMgr._failmgr.failure_modes; | var failure_modes = FailureMgr._failmgr.failure_modes; | ||
var mode_list = keys(failure_modes); | var mode_list = keys(failure_modes); | ||
var probability = speed / 200.0;#200kt will fail everything, 0kt will fail nothing. | var probability = speed / 200.0;# 200kt will fail everything, 0kt will fail nothing. | ||
#test for explosion | # test for explosion | ||
if(probability > 1.0 and me.input.fuel.getValue() > 2500) { | if(probability > 1.0 and me.fdm.input.fuel.getValue() > 2500) { | ||
#200kt+ and fuel | # 200kt+ and fuel in tanks will explode the aircraft on impact. | ||
me._explodeBegin(); | me._explodeBegin(); | ||
return; | return; | ||
Line 270: | Line 298: | ||
if (speed > 5) {#check if sound already running? | if (speed > 5) {#check if sound already running? | ||
me.input.wCrashOn.setValue(1); | me.input.wCrashOn.setValue(1); | ||
var timer = maketimer(3, me, me._impactSoundWaterEnd); | |||
timer.start(); | |||
} | } | ||
}, | }, | ||
Line 279: | Line 308: | ||
if (speed > 5) { | if (speed > 5) { | ||
me.input.crashOn.setValue(1); | me.input.crashOn.setValue(1); | ||
var timer = maketimer(3, me, me._impactSoundEnd); | |||
timer.start(); | |||
} | } | ||
}, | }, | ||
Line 297: | Line 327: | ||
me._output("Aircraft exploded.", TRUE); | me._output("Aircraft exploded.", TRUE); | ||
var timer = maketimer(3, me, me._explodeEnd); | |||
timer.start(); | |||
}, | }, | ||
_explodeEnd: func () { | _explodeEnd: func () { | ||
Line 305: | Line 336: | ||
me._output("Aircraft damaged: Wings broke off, due to "~str~" G forces."); | me._output("Aircraft damaged: Wings broke off, due to "~str~" G forces."); | ||
me.input.detachOn.setValue(1); | me.input.detachOn.setValue(1); | ||
FailureMgr.set_failure_level(me.fdm.wingsFailureID, 1); | |||
me.wingsAttached = FALSE; | me.wingsAttached = FALSE; | ||
var timer = maketimer(3, me, me._stressDamageEnd); | |||
timer.start(); | |||
}, | }, | ||
_stressDamageEnd: func () { | _stressDamageEnd: func () { | ||
Line 318: | Line 347: | ||
}, | }, | ||
_output: func (str, override = FALSE) { | _output: func (str, override = FALSE) { | ||
var time = me.input.simTime.getValue(); | var time = me.fdm.input.simTime.getValue(); | ||
if (override == TRUE or (time - me.lastMessageTime) > 3) { | if (override == TRUE or (time - me.lastMessageTime) > 3) { | ||
me.lastMessageTime = time; | me.lastMessageTime = time; | ||
Line 328: | Line 357: | ||
me._testStress(); | me._testStress(); | ||
me._testWaterImpact(); | me._testWaterImpact(); | ||
}, | }, | ||
_testWaterImpact: func () { | _testWaterImpact: func () { | ||
Line 344: | Line 370: | ||
}, | }, | ||
_testStress: func () { | _testStress: func () { | ||
if ( | if (me._isRunning() == TRUE and me.wingsAttached == TRUE) { | ||
var gForce = me.input.Nz.getValue() == nil?1:me.input.Nz.getValue(); | var gForce = me.fdm.input.Nz.getValue() == nil?1:me.fdm.input.Nz.getValue(); | ||
var weight = me.input.weight.getValue(); | var weight = me.fdm.input.weight.getValue(); | ||
var wingload = gForce * weight; | var wingload = gForce * weight; | ||
Line 404: | Line 430: | ||
}, | }, | ||
}; | }; | ||
var ImpactStructureListener = { | |||
crash: nil, | |||
run: func () { | |||
if (crash._isRunning() == TRUE) { | |||
var wow = crash._isStructureInContact(); | |||
if (wow == TRUE) { | |||
crash._impactDamage(); | |||
} | |||
} | |||
}, | |||
}; | |||
# static class | |||
var fdmProperties = { | |||
input: {}, | |||
convert: func () { | |||
foreach(var ident; keys(me.input)) { | |||
me.input[ident] = props.globals.getNode(me.input[ident], 1); | |||
} | |||
}, | |||
fps2kt: func (fps) { | |||
return fps * 0.5924838; | |||
}, | |||
wingsFailureID: nil, | |||
}; | |||
var jsbSimProp = { | |||
parents: [fdmProperties], | |||
input: { | |||
weight: "fdm/jsbsim/inertia/weight-lbs", | |||
fuel: "fdm/jsbsim/propulsion/total-fuel-lbs", | |||
simTime: "fdm/jsbsim/simulation/sim-time-sec", | |||
vgFps: "fdm/jsbsim/velocities/vg-fps", | |||
downFps: "velocities/down-relground-fps", | |||
Nz: "fdm/jsbsim/accelerations/Nz", | |||
}, | |||
wingsFailureID: "fdm/jsbsim/structural/wings", | |||
}; | |||
var yaSimProp = { | |||
parents: [fdmProperties], | |||
input: { | |||
weight: "yasim/gross-weight-lbs", | |||
fuel: "consumables/fuel/total-fuel-lbs", | |||
simTime: "sim/time/elapsed-sec", | |||
vgFps: "velocities/groundspeed-kt", | |||
Nz: "accelerations/n-z-cg-fps_sec", | |||
}, | |||
convert: func () { | |||
call(fdmProperties.convert, [], me); | |||
me.input.downFps = props.Node.new().setValue(0); | |||
}, | |||
fps2kt: func (fps) { | |||
return fps; | |||
}, | |||
wingsFailureID: "structural/wings", | |||
}; | |||
# TODO: | # TODO: | ||
Line 412: | Line 499: | ||
# Explosion depending on bumpiness and speed when sliding? | # Explosion depending on bumpiness and speed when sliding? | ||
# Tie in with damage from Bombable? | # Tie in with damage from Bombable? | ||
# Use galvedro's UpdateLoop framework when it gets merged | |||
# example uses: | # example uses: | ||
# | # | ||
# var crashCode = | # var crashCode = CrashAndStress.new([0,1,2]; | ||
# | # | ||
# var crashCode = | # var crashCode = CrashAndStress.new([0,1,2], {"weightLbs":30000, "maxG": 12}); | ||
# | # | ||
# var crashCode = | # var crashCode = CrashAndStress.new([0,1,2,3], {"weightLbs":20000, "maxG": 11, "minG": -5}); | ||
# | # | ||
# var crashCode = | # var crashCode = CrashAndStress.new([0,1,2], {"wingloadMaxLbs": 90000, "wingloadMinLbs": -45000}, ["controls/flight/aileron", "controls/flight/elevator", "controls/flight/flaps"]); | ||
# | # | ||
# var crashCode = | # var crashCode = CrashAndStress.new([0,1,2], {"wingloadMaxLbs":90000}, ["controls/flight/aileron", "controls/flight/elevator", "controls/flight/flaps"]); | ||
# | # | ||
# Gears parameter must be defined. | # Gears parameter must be defined. | ||
Line 435: | Line 523: | ||
# use: | # use: | ||
var crashCode = | var crashCode = CrashAndStress.new([0,1,2], {"weightLbs":30000, "maxG": 12}, ["controls/gear1", "controls/gear2", "controls/flight/aileron", "controls/flight/elevator", "consumables/fuel/wing-tanks"]); | ||
crashCode.start(); | crashCode.start(); | ||
Line 450: | Line 538: | ||
<syntaxhighlight lang="xml"> | <syntaxhighlight lang="xml"> | ||
<crash> | <crash> | ||
<file>Aircraft/[aircraft name here]/Nasal/ | <file>Aircraft/[aircraft name here]/Nasal/crash-and-stress.nas</file> | ||
</crash> | </crash> | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Line 575: | Line 663: | ||
<type>float</type> | <type>float</type> | ||
<property type="string">damage/sounds/creaking-volume</property> | <property type="string">damage/sounds/creaking-volume</property> | ||
</signal> | |||
<signal> | |||
<type>bool</type> | |||
<property type="string">fdm/jsbsim/structural/wings/serviceable</property> | |||
</signal> | |||
</syntaxhighlight> | |||
Notice that the last signal is jsbsim specific, the corresponding yasim signal is: | |||
<syntaxhighlight lan="nasal"> | |||
<signal> | |||
<type>bool</type> | |||
<property type="string">structural/wings/serviceable</property> | |||
</signal> | </signal> | ||
</syntaxhighlight> | </syntaxhighlight> | ||
That property is also what you would use to animate wings being detached and/or changes in the aerodynamics. | |||
== Performance == | == Performance == |
edits