# AUTOPUSH # Basic pushback logic class. # # Copyright (c) 2018 Autopush authors: # Michael Danilov # Joshua Davidson http://github.com/Octal450 # Merspieler http://gitlab.com/merspieler # Distribute under the terms of GPLv2. var _enabled = 0; var _K_p = nil; var _F_p = nil; var _K_i = nil; var _F_i = nil; var _K_d = nil; var _F_d = nil; var _F = nil; var _int = nil; var _V = nil; var _T_f = nil; var _K_yaw = nil; var _yasim = 0; var _time = nil; # (ft / s^2) / ((km / h) / s) var _unitconv = M2FT / 3.6; var _debug = nil; var _loop = func() { if (!getprop("/sim/model/autopush/available")) { _stop(); return; } var force = 0.0; var x = 0.0; var y = 0.0; var z = 0.0; # Rollspeed is only adequate if the wheel is touching the ground. if (getprop("/gear/gear[0]/wow")) { var V = getprop("/gear/gear[0]/rollspeed-ms") * 3.6; var deltaV = getprop("/sim/model/autopush/target-speed-km_h") - V; var minus_dV = _V - V; var time = getprop("/sim/time/elapsed-sec"); var prop = math.min(math.max(_K_p * deltaV, -_F_p), _F_p); var dt = time - _time; var deriv = 0.0; # XXX Sanitising dt. Smaller chance of freakout on lag spike. if(dt > 0.0) { if(dt < 0.05) { _int = math.min(math.max(_int + _K_i * deltaV * dt, -_F_i), _F_i); } if(dt > 0.002) { deriv = math.min(math.max(_K_d * minus_dV / dt, -_F_d), _F_d); } } var accel = prop + _int + deriv; if (_debug > 2) { print("pushback prop " ~ prop ~ ", _int " ~ _int ~ ", deriv " ~ deriv); } _V = V; _time = time; if (!_yasim) { force = accel * getprop("/fdm/jsbsim/inertia/weight-lbs") * _unitconv; } else { force = accel * getprop("/fdm/yasim/gross-weight-lbs") * _unitconv; } var pitch = getprop("/sim/model/autopush/pitch-deg") * D2R; z = math.sin(pitch); var pz = math.cos(pitch); var yaw = getprop("/sim/model/autopush/yaw") * _K_yaw; x = math.cos(yaw) * pz; y = math.sin(yaw) * pz; setprop("/sim/model/autopush/force-x", x); setprop("/sim/model/autopush/force-y", y); # JSBSim force's z is down. setprop("/sim/model/autopush/force-z", -z); } setprop("/sim/model/autopush/force-lbf", force); if (_yasim) { # The force is divided by YASim thrust="100000.0" setting. setprop("/sim/model/autopush/force-x-yasim", x * force * 0.00001); # YASim force's y is to the left. setprop("/sim/model/autopush/force-y-yasim", -y * force * 0.00001); setprop("/sim/model/autopush/force-z-yasim", z * force * 0.00001); } } var _timer = maketimer(0.0167, func{_loop()}); var _start = func() { # Else overwritten by dialog. settimer(func() { setprop("/sim/model/autopush/target-speed-km_h", 0.0) }, 0.1); _K_p = getprop("/sim/model/autopush/K_p"); _F_p = getprop("/sim/model/autopush/F_p"); _K_i = getprop("/sim/model/autopush/K_i"); _F_i = getprop("/sim/model/autopush/F_i"); _K_d = getprop("/sim/model/autopush/K_d"); _F_d = getprop("/sim/model/autopush/F_d"); _F = getprop("/sim/model/autopush/F"); _T_f = getprop("/sim/model/autopush/T_f"); _K_yaw = getprop("/sim/model/autopush/yaw-mult") * D2R; _yasim = (getprop("/sim/flight-model") == "yasim"); _debug = getprop("/sim/model/autopush/debug") or 0; _int = 0.0; _V = 0.0; _time = getprop("/sim/time/elapsed-sec"); setprop("/sim/model/autopush/connected", 1); if (!_timer.isRunning) { if (getprop("/sim/model/autopush/chocks")) { setprop("/sim/model/autopush/chocks", 0); screen.log.write("(pushback): Pushback connected, chocks removed. Please release brakes."); } else { screen.log.write("(pushback): Pushback connected, please release brakes."); } } _timer.start(); } var _stop = func() { if (_timer.isRunning) { screen.log.write("(pushback): Pushback and bypass pin removed."); } _timer.stop(); setprop("/sim/model/autopush/force-lbf", 0.0); if (_yasim) { setprop("/sim/model/autopush/force-x-yasim", 0.0); setprop("/sim/model/autopush/force-y-yasim", 0.0); } setprop("/sim/model/autopush/connected", 0); setprop("/sim/model/autopush/enabled", 0); } setlistener("/sim/model/autopush/enabled", func(p) { var enabled = p.getValue(); if ((enabled > _enabled) and getprop("/sim/model/autopush/available")) { _start(); } else if (enabled < _enabled) { _stop(); } _enabled = enabled; });