diff --git a/Docs/Goldhofert.xml b/Docs/Goldhofert.xml new file mode 100644 index 000000000..06d2c8e77 --- /dev/null +++ b/Docs/Goldhofert.xml @@ -0,0 +1,152 @@ + + + + + + + + + + + + + + + + + + + + + +]> + + + + + + + Models/Airport/Pushback/Goldhofert.ac + + + + + Models/Airport/Pushback/Goldhofert-warning-light.xml + + -2.908 + 0.260 + 1.326 + 0 + + + + + Models/Airport/Pushback/Goldhofert-warning-light.xml + + -1.781 + 0.260 + 1.326 + 90 + + + + + spin + wheelfl + wheelfr + &ROLLSPEED-PROP; + -16.3 +
+ -2.8976 + 0 + 0.5809 +
+ + 0 + 1 + 0 + +
+ + + spin + wheelrl + wheelrr + &ROLLSPEED-PROP; + -16.3 +
+ 2.0501 + 0 + 0.5735 +
+ + 0 + 1 + 0 + +
+ + + select + + &CONNECTED-PROP; + + + + + rotate + &YAW-PROP; + &YAW-MULT; +
+ 0 + 0 + 0 +
+ + 0 + 0 + -1 + +
+ + + translate + &COMPRESSION-PROP; + 0.3048 + + 0 + 0 + 1 + + + + + rotate + &PITCH-PROP; + &PITCH-FACTOR; + &PITCH-OFFSET; +
+ 0 + 0 + 0 +
+ + 0 + 1 + 0 + +
+
diff --git a/Docs/README.autopush b/Docs/README.autopush new file mode 100644 index 000000000..d599572f9 --- /dev/null +++ b/Docs/README.autopush @@ -0,0 +1,255 @@ +AUTOMATIC PUSHBACK FOR FLIGHTGEAR +http://gitlab.com/mdanil/flightgear-autopush + +Version 2.0.1 + +Copyright (c) 2018 Autopush authors: + Michael Danilov + Joshua Davidson http://github.com/Octal450 + Merspieler http://gitlab.com/merspieler +Some of the code (c) FlightGear +Distribute under the terms of GPLv2. + + +This project aims to develop a generic pushback for JSBSim and YASim +aircraft, with the following characteristics. + +1. Do the pushback procedure automatically. +2. Scale to different aircraft with minimum changes to their logic. +3. Use no computer resources in flight. + + +INSTALLATION + +Minimum FlightGear version: 2018.0 + +NOTE: these steps cover the minimal testing setup. To get the most +realism out of Autopush, you will have to add logic aircraft-side as +described in the last step. + +1. Copy the autopush.config.xml.template into your aircraft directory +and the Goldhofert.xml into /Models/Autopush/ + +2. Set up the pushback logic. + +Add the following line under of your set.xml + + + +Rename autopush-config.xml.template to autopush-config.xml and edit +the file as described below. + +Alternatively, you can copy the contents of +autopush-config.xml.template to under of your +set.xml and make these modifications there. + +Change the aliases to point to the following data: + +steer-cmd-norm nose wheel steering command norm +yaw nose wheel steering output norm or angle (see below) +chocks chocks command bool (or leave it until step 7) +available pushback availability bool (or leave it until step 7) + +Replace the MULTIPLIER in yaw-mult with: + +max steering angle if yaw is norm +1.0 if yaw is degrees +57.3 if yaw is radians + +Replace PITCH with the pushback's pitch relative to aircraft. If your +aircraft's ground pitch varies greatly, you can make an alias to +property with calculated relative pitch. + +Replace MIN_RADIUS with the minimum allowed turning radius in m of the +center of the aircraft during pushback procedure. + +NOTE: on some aircraft the turning radius is different for taxi and +pushback. Please check the aircraft's literature. + +Replace STOP_DIST with the stopping distance in m from pushback speed. + +Add under of your set.xml: + + + Nasal/Autopush/autopush.nas + + + Nasal/Autopush/driver.nas + + + Nasal/Autopush/dynarr.nas + + + Nasal/Autopush/route.nas + + +Add under of your set.xml: + + /sim/model/autopush/route/show + /sim/model/autopush/route/show-wingtip + +3. Connect the force to FDM. + + 3.a. JSBSim: + + 3.a.1. Add the following under of your JSBSim + XML. + + + + FRONT-X + FRONT-Y + FRONT-Z + + + 1.0 + 0.0 + 0.0 + + + +Replace FRONT-X, FRONT-Y, FRONT-Z with coordinates of your front +bogey. + + 3.a.2. Add the following under of + your set.xml. + + + + + + + + + 3.b. YASim. Add the following under of your YASim xml. + + + + + + + + + + + +Replace FRONT-X, FRONT-Y, FRONT-Z with coordinates of your front +bogey. + +4. Add the pushback model to your Model XML: + + + Pushback + MODEL + + FRONT-X + FRONT-Y + FRONT-Z + + + +Replace FRONT-X, FRONT-Y, FRONT-Z with coordinates of your front +bogey. Replace MODEL with one of the following file names: + +Autopush/Goldhofert.xml for Goldhofer towbarless pushback + +Edit the "SETTINGS" part in the beginning of the Goldhofert.xml to match +your setup. + +5. Add gui/dialogs/autopush.xml to your aircraft's menu (see + FlightGear documentation for editing the menu). + +6. If you have a bug tracker, please add a note, that autopush related + bugs should be reported here: + +https://gitlab.com/mdanil/flightgear-autopush/issues + +7. Launch the simulator and try Autopush. After making sure it works, + complete the support by implementing some logic in your aircraft + and connecting the rest of the interface. + +CAUTION. +1. Make sure to HAVE A BACK-UP COPY of your work. +2. If anything is not clear in the instruction below, do not guess -- + contact the authors. + + 7.1. When pushback is connected ("/sim/model/autopush/connected"), + nose wheel steering must actuate at different speed, depending + on its rollspeed. The exact dependency is different per aircraft + and used pushback visual, and for most aircraft the only way to + find it is trial and error until it "looks right": + - the input must be taken from pushback steering command norm + (set by autopush-config.xml, default: + "/controls/flight/rudder"); + - the output must be written to pushback orientation in degrees, + radians or norm (set by autopush-config.xml, default: + "/gear/gear[0]/steering-norm"). + + 7.2. Set or alias (in autopush-config.xml) the availability property + "/sim/model/autopush/available". It must be false if e.g. the + aircraft is moving too fast, the front wheel is not touching + the ground, the aircraft is damaged or is outside of an airport + etc. + + 7.3. Make Autopush remove wheel chocks by setting the alias in + autopush-config.xml to the chocks property. (default: + "/controls/gear/wheel-chocks"). + + 7.4. Optionally, Autopush may be made visible in multiplayer by + duplicating the properties used in its model.xml into some + unused MP properties. See the list in + +https://sourceforge.net/p/flightgear/flightgear/ci/next/tree/src/MultiPlayer/multiplaymgr.cxx + + around line 215, and then using those properties in the + "SETTINGS" part of Autopush model.xml. + + After making these changes check the Autopush model.xml's settings + and make sure they match the setup. Launch the simulator and try + Autopush. + + +TUNING + +There should normally be no need to change the coefficients, because +the inertia of different aircraft is already taken into account. But +the gear setup may differ enough to require some tuning. + +If these settings are changed during simulation, they take effect +after disconnecting and reconnecting the pushback. + +Pushback (/sim/model/autopush): + +Coefficient Unit Description + +K_p ((km/h)/s)/(km/h) Proportional coefficient of PID. + Defines the start/stop throttle + and immediate response to speed + difference deltaV = V_set - V. + +F_p (km/h)/s Proportional clipping. + +K_i ((km/h)/s)/((km/h)*s) Integral coefficient of PID. + Defines how fast the steady + throttle is ramped during the + push. + +F_i (km/h)/s Integral clipping. + +K_d -((km/h)/s)/((km/h)/s) Differential coefficient of PID. + Stabilizes the approaching of + steady throttle. + +F_d (km/h)/s Differential clipping. + +Pushback driver (/sim/model/autopush/driver): + +Coefficient Unit Description + +F_V km/h Max towing speed in auto mode. +K_psi 1/deg Amount of steering per heading correction. +F_psi 1/deg Max steering per heading correction. +K_deltapsi -1/(deg/s) Amount of steering compensation per heading + derivative. +F_psi 1/(deg/s) Max amount of steering compensation per + heading derivative. diff --git a/Docs/autopush-config.xml.template b/Docs/autopush-config.xml.template new file mode 100644 index 000000000..f34540c8b --- /dev/null +++ b/Docs/autopush-config.xml.template @@ -0,0 +1,30 @@ + + + + MULTIPLIER + PITCH + MIN_RADIUS + STOP_DIST + + 1 + + false + 0.0 + 0.5 + 0.15 + 0.25 + 0.1 + 0.0 + 0.0 + + 8.0 + 0.03 + 1.0 + 0.03 + 1.0 + + + + + 0 + diff --git a/Models/Autopush/cursor.ac b/Models/Autopush/cursor.ac new file mode 100644 index 000000000..0b3206772 --- /dev/null +++ b/Models/Autopush/cursor.ac @@ -0,0 +1,589 @@ +AC3Db +MATERIAL "autopush cursor" rgb 0.0000 0.0000 0.0000 amb 0.0000 0.0000 0.0000 emis 1.000 0.173 0.545 spec 0.0000 0.0000 0.0000 shi 50 trans 0.0000 +OBJECT world +name "Blender_exporter_v2.26__cursor.ac" +kids 1 +OBJECT poly +name "Circle" +data 11 +Circle.mesh +crease 40.0 +numvert 128 +0 0.2 -0.75 +0 0.2 -1 +-0.09802 0.2 -0.99518 +-0.19509 0.2 -0.98079 +-0.29028 0.2 -0.95694 +-0.38268 0.2 -0.92388 +-0.4714 0.2 -0.88192 +-0.55557 0.2 -0.83147 +-0.63439 0.2 -0.77301 +-0.70711 0.2 -0.70711 +-0.77301 0.2 -0.63439 +-0.83147 0.2 -0.55557 +-0.88192 0.2 -0.4714 +-0.92388 0.2 -0.38268 +-0.95694 0.2 -0.29028 +-0.98079 0.2 -0.19509 +-0.99518 0.2 -0.09802 +-1 0.2 0 +-0.99518 0.2 0.09802 +-0.98079 0.2 0.19509 +-0.95694 0.2 0.29028 +-0.92388 0.2 0.38268 +-0.88192 0.2 0.4714 +-0.83147 0.2 0.55557 +-0.77301 0.2 0.63439 +-0.70711 0.2 0.70711 +-0.63439 0.2 0.77301 +-0.55557 0.2 0.83147 +-0.4714 0.2 0.88192 +-0.38268 0.2 0.92388 +-0.29028 0.2 0.95694 +-0.19509 0.2 0.98079 +-0.09802 0.2 0.99518 +0 0.2 1 +0.09802 0.2 0.99518 +0.19509 0.2 0.98079 +0.29029 0.2 0.95694 +0.38268 0.2 0.92388 +0.4714 0.2 0.88192 +0.55557 0.2 0.83147 +0.63439 0.2 0.77301 +0.70711 0.2 0.70711 +0.77301 0.2 0.63439 +0.83147 0.2 0.55557 +0.88192 0.2 0.4714 +0.92388 0.2 0.38268 +0.95694 0.2 0.29028 +0.98079 0.2 0.19509 +0.99518 0.2 0.09802 +1 0.2 0 +0.99518 0.2 -0.09802 +0.98079 0.2 -0.19509 +0.95694 0.2 -0.29028 +0.92388 0.2 -0.38268 +0.88192 0.2 -0.4714 +0.83147 0.2 -0.55557 +0.77301 0.2 -0.63439 +0.70711 0.2 -0.70711 +0.6344 0.2 -0.77301 +0.55557 0.2 -0.83147 +0.4714 0.2 -0.88192 +0.38269 0.2 -0.92388 +0.29029 0.2 -0.95694 +0.19509 0.2 -0.98078 +0.09802 0.2 -0.99518 +-0.07351 0.2 -0.74639 +-0.14632 0.2 -0.73559 +-0.21771 0.2 -0.71771 +-0.28701 0.2 -0.69291 +-0.35355 0.2 -0.66144 +-0.41668 0.2 -0.6236 +-0.47579 0.2 -0.57976 +-0.53033 0.2 -0.53033 +-0.57976 0.2 -0.47579 +-0.6236 0.2 -0.41668 +-0.66144 0.2 -0.35355 +-0.69291 0.2 -0.28701 +-0.71771 0.2 -0.21771 +-0.73559 0.2 -0.14632 +-0.74639 0.2 -0.07351 +-0.75 0.2 0 +-0.74639 0.2 0.07351 +-0.73559 0.2 0.14632 +-0.71771 0.2 0.21771 +-0.69291 0.2 0.28701 +-0.66144 0.2 0.35355 +-0.6236 0.2 0.41668 +-0.57976 0.2 0.4758 +-0.53033 0.2 0.53033 +-0.47579 0.2 0.57976 +-0.41668 0.2 0.6236 +-0.35355 0.2 0.66144 +-0.28701 0.2 0.69291 +-0.21771 0.2 0.71771 +-0.14632 0.2 0.73559 +-0.07351 0.2 0.74639 +0 0.2 0.75 +0.07351 0.2 0.74639 +0.14632 0.2 0.73559 +0.21771 0.2 0.71771 +0.28701 0.2 0.69291 +0.35355 0.2 0.66144 +0.41668 0.2 0.6236 +0.4758 0.2 0.57976 +0.53033 0.2 0.53033 +0.57976 0.2 0.47579 +0.6236 0.2 0.41668 +0.66144 0.2 0.35355 +0.69291 0.2 0.28701 +0.71771 0.2 0.21771 +0.73559 0.2 0.14632 +0.74639 0.2 0.07351 +0.75 0.2 0 +0.74639 0.2 -0.07351 +0.73559 0.2 -0.14632 +0.71771 0.2 -0.21771 +0.69291 0.2 -0.28701 +0.66144 0.2 -0.35355 +0.6236 0.2 -0.41668 +0.57976 0.2 -0.47579 +0.53033 0.2 -0.53033 +0.4758 0.2 -0.57976 +0.41668 0.2 -0.6236 +0.35355 0.2 -0.66144 +0.28701 0.2 -0.69291 +0.21772 0.2 -0.7177 +0.14632 0.2 -0.73559 +0.07352 0.2 -0.74639 +numsurf 64 +SURF 0X10 +mat 0 +refs 4 +25 0.080806 0.323223 +88 0.091854 0.367417 +87 0.088765 0.381051 +24 0.076687 0.341402 +SURF 0X10 +mat 0 +refs 4 +12 0.06988 0.617849 +75 0.08366 0.588387 +74 0.086025 0.604169 +11 0.073033 0.638893 +SURF 0X10 +mat 0 +refs 4 +51 0.186299 0.548772 +114 0.170974 0.536579 +113 0.171649 0.518378 +50 0.187199 0.524504 +SURF 0X10 +mat 0 +refs 4 +64 0.131126 0.748796 +127 0.129595 0.686597 +126 0.134145 0.683897 +63 0.137193 0.745196 +SURF 0X10 +mat 0 +refs 4 +11 0.073033 0.638893 +74 0.086025 0.604169 +73 0.088765 0.618949 +10 0.076687 0.658598 +SURF 0X10 +mat 0 +refs 4 +24 0.076687 0.341402 +87 0.088765 0.381051 +86 0.086025 0.39583 +23 0.073033 0.361107 +SURF 0X10 +mat 0 +refs 4 +37 0.148918 0.26903 +100 0.142938 0.326773 +99 0.138607 0.320574 +36 0.143143 0.260765 +SURF 0X10 +mat 0 +refs 4 +50 0.187199 0.524504 +113 0.171649 0.518378 +112 0.171875 0.5 +49 0.1875 0.5 +SURF 0X10 +mat 0 +refs 4 +63 0.137193 0.745196 +126 0.134145 0.683897 +125 0.138607 0.679426 +62 0.143143 0.739235 +SURF 0X10 +mat 0 +refs 4 +10 0.076687 0.658598 +73 0.088765 0.618949 +72 0.091854 0.632583 +9 0.080806 0.676777 +SURF 0X10 +mat 0 +refs 4 +23 0.073033 0.361107 +86 0.086025 0.39583 +85 0.08366 0.411613 +22 0.06988 0.382151 +SURF 0X10 +mat 0 +refs 4 +36 0.143143 0.260765 +99 0.138607 0.320574 +98 0.134145 0.316103 +35 0.137193 0.254804 +SURF 0X10 +mat 0 +refs 4 +49 0.1875 0.5 +112 0.171875 0.5 +111 0.171649 0.481622 +48 0.187199 0.475496 +SURF 0X10 +mat 0 +refs 4 +62 0.143143 0.739235 +125 0.138607 0.679426 +124 0.142938 0.673227 +61 0.148918 0.73097 +SURF 0X10 +mat 0 +refs 4 +9 0.080806 0.676777 +72 0.091854 0.632583 +71 0.095263 0.644939 +8 0.08535 0.693253 +SURF 0X10 +mat 0 +refs 4 +22 0.06988 0.382151 +85 0.08366 0.411613 +84 0.081693 0.428247 +21 0.067258 0.404329 +SURF 0X10 +mat 0 +refs 4 +35 0.137193 0.254804 +98 0.134145 0.316103 +97 0.129595 0.313403 +34 0.131126 0.251204 +SURF 0X10 +mat 0 +refs 4 +48 0.187199 0.475496 +111 0.171649 0.481622 +110 0.170974 0.463421 +47 0.186299 0.451227 +SURF 0X10 +mat 0 +refs 4 +61 0.148918 0.73097 +124 0.142938 0.673227 +123 0.147097 0.66536 +60 0.154463 0.72048 +SURF 0X10 +mat 0 +refs 4 +8 0.08535 0.693253 +71 0.095263 0.644939 +70 0.098958 0.6559 +7 0.090277 0.707867 +SURF 0X10 +mat 0 +refs 4 +21 0.067258 0.404329 +84 0.081693 0.428247 +83 0.080143 0.445572 +20 0.065191 0.427429 +SURF 0X10 +mat 0 +refs 4 +34 0.131126 0.251204 +97 0.129595 0.313403 +96 0.125 0.3125 +33 0.125 0.25 +SURF 0X10 +mat 0 +refs 4 +47 0.186299 0.451227 +110 0.170974 0.463421 +109 0.169857 0.445572 +46 0.184809 0.427429 +SURF 0X10 +mat 0 +refs 4 +60 0.154463 0.72048 +123 0.147097 0.66536 +122 0.151043 0.6559 +59 0.159723 0.707867 +SURF 0X10 +mat 0 +refs 4 +7 0.090277 0.707867 +70 0.098958 0.6559 +69 0.102903 0.66536 +6 0.095538 0.72048 +SURF 0X10 +mat 0 +refs 4 +20 0.065191 0.427429 +83 0.080143 0.445572 +82 0.079026 0.46342 +19 0.063701 0.451227 +SURF 0X10 +mat 0 +refs 4 +33 0.125 0.25 +96 0.125 0.3125 +95 0.120406 0.313403 +32 0.118874 0.251204 +SURF 0X10 +mat 0 +refs 4 +46 0.184809 0.427429 +109 0.169857 0.445572 +108 0.168307 0.428247 +45 0.182743 0.404329 +SURF 0X10 +mat 0 +refs 4 +59 0.159723 0.707867 +122 0.151043 0.6559 +121 0.154737 0.644939 +58 0.16465 0.693252 +SURF 0X10 +mat 0 +refs 4 +6 0.095538 0.72048 +69 0.102903 0.66536 +68 0.107062 0.673227 +5 0.101082 0.73097 +SURF 0X10 +mat 0 +refs 4 +19 0.063701 0.451227 +82 0.079026 0.46342 +81 0.078351 0.481622 +18 0.062801 0.475496 +SURF 0X10 +mat 0 +refs 4 +32 0.118874 0.251204 +95 0.120406 0.313403 +94 0.115855 0.316103 +31 0.112807 0.254804 +SURF 0X10 +mat 0 +refs 4 +45 0.182743 0.404329 +108 0.168307 0.428247 +107 0.16634 0.411613 +44 0.18012 0.382151 +SURF 0X10 +mat 0 +refs 4 +58 0.16465 0.693252 +121 0.154737 0.644939 +120 0.158146 0.632582 +57 0.169194 0.676776 +SURF 0X10 +mat 0 +refs 4 +5 0.101082 0.73097 +68 0.107062 0.673227 +67 0.111393 0.679426 +4 0.106857 0.739235 +SURF 0X10 +mat 0 +refs 4 +18 0.062801 0.475496 +81 0.078351 0.481622 +80 0.078125 0.5 +17 0.0625 0.5 +SURF 0X10 +mat 0 +refs 4 +31 0.112807 0.254804 +94 0.115855 0.316103 +93 0.111393 0.320574 +30 0.106857 0.260765 +SURF 0X10 +mat 0 +refs 4 +44 0.18012 0.382151 +107 0.16634 0.411613 +106 0.163975 0.395831 +43 0.176967 0.361108 +SURF 0X10 +mat 0 +refs 4 +57 0.169194 0.676776 +120 0.158146 0.632582 +119 0.161235 0.618949 +56 0.173313 0.658598 +SURF 0X10 +mat 0 +refs 4 +4 0.106857 0.739235 +67 0.111393 0.679426 +66 0.115855 0.683897 +3 0.112807 0.745196 +SURF 0X10 +mat 0 +refs 4 +17 0.0625 0.5 +80 0.078125 0.5 +79 0.078351 0.518378 +16 0.062801 0.524504 +SURF 0X10 +mat 0 +refs 4 +30 0.106857 0.260765 +93 0.111393 0.320574 +92 0.107062 0.326772 +29 0.101082 0.26903 +SURF 0X10 +mat 0 +refs 4 +43 0.176967 0.361108 +106 0.163975 0.395831 +105 0.161235 0.381051 +42 0.173313 0.341402 +SURF 0X10 +mat 0 +refs 4 +56 0.173313 0.658598 +119 0.161235 0.618949 +118 0.163975 0.604169 +55 0.176967 0.638892 +SURF 0X10 +mat 0 +refs 4 +3 0.112807 0.745196 +66 0.115855 0.683897 +65 0.120406 0.686597 +2 0.118874 0.748796 +SURF 0X10 +mat 0 +refs 4 +16 0.062801 0.524504 +79 0.078351 0.518378 +78 0.079026 0.536579 +15 0.063701 0.548773 +SURF 0X10 +mat 0 +refs 4 +29 0.101082 0.26903 +92 0.107062 0.326772 +91 0.102903 0.33464 +28 0.095538 0.27952 +SURF 0X10 +mat 0 +refs 4 +42 0.173313 0.341402 +105 0.161235 0.381051 +104 0.158146 0.367418 +41 0.169194 0.323223 +SURF 0X10 +mat 0 +refs 4 +55 0.176967 0.638892 +118 0.163975 0.604169 +117 0.16634 0.588387 +54 0.18012 0.617849 +SURF 0X10 +mat 0 +refs 4 +15 0.063701 0.548773 +78 0.079026 0.536579 +77 0.080143 0.554428 +14 0.065191 0.572571 +SURF 0X10 +mat 0 +refs 4 +28 0.095538 0.27952 +91 0.102903 0.33464 +90 0.098958 0.344099 +27 0.090277 0.292132 +SURF 0X10 +mat 0 +refs 4 +41 0.169194 0.323223 +104 0.158146 0.367418 +103 0.154737 0.355061 +40 0.16465 0.306747 +SURF 0X10 +mat 0 +refs 4 +54 0.18012 0.617849 +117 0.16634 0.588387 +116 0.168307 0.571753 +53 0.182743 0.595671 +SURF 0X10 +mat 0 +refs 4 +0 0.125 0.6875 +1 0.125 0.75 +2 0.118874 0.748796 +65 0.120406 0.686597 +SURF 0X10 +mat 0 +refs 4 +14 0.065191 0.572571 +77 0.080143 0.554428 +76 0.081693 0.571753 +13 0.067258 0.595671 +SURF 0X10 +mat 0 +refs 4 +27 0.090277 0.292132 +90 0.098958 0.344099 +89 0.095263 0.35506 +26 0.08535 0.306747 +SURF 0X10 +mat 0 +refs 4 +40 0.16465 0.306747 +103 0.154737 0.355061 +102 0.151042 0.344099 +39 0.159723 0.292133 +SURF 0X10 +mat 0 +refs 4 +53 0.182743 0.595671 +116 0.168307 0.571753 +115 0.169857 0.554428 +52 0.184809 0.572571 +SURF 0X10 +mat 0 +refs 4 +13 0.067258 0.595671 +76 0.081693 0.571753 +75 0.08366 0.588387 +12 0.06988 0.617849 +SURF 0X10 +mat 0 +refs 4 +26 0.08535 0.306747 +89 0.095263 0.35506 +88 0.091854 0.367417 +25 0.080806 0.323223 +SURF 0X10 +mat 0 +refs 4 +39 0.159723 0.292133 +102 0.151042 0.344099 +101 0.147097 0.33464 +38 0.154462 0.27952 +SURF 0X10 +mat 0 +refs 4 +52 0.184809 0.572571 +115 0.169857 0.554428 +114 0.170974 0.536579 +51 0.186299 0.548772 +SURF 0X10 +mat 0 +refs 4 +1 0.125 0.75 +0 0.125 0.6875 +127 0.129595 0.686597 +64 0.131126 0.748796 +SURF 0X10 +mat 0 +refs 4 +38 0.154462 0.27952 +101 0.147097 0.33464 +100 0.142938 0.326773 +37 0.148918 0.26903 +kids 0 diff --git a/Models/Autopush/cursor.xml b/Models/Autopush/cursor.xml new file mode 100644 index 000000000..489f98152 --- /dev/null +++ b/Models/Autopush/cursor.xml @@ -0,0 +1,46 @@ + + + + + cursor.ac + + + false + + + + scale + /sim/model/autopush/stopping-distance-m + 0.0 + 1.0 + + + + material + + /sim/model/autopush/route/invalid + + + 1.0 + 0.0 + 0.0 + + + 1.0 + 0.0 + 0.0 + + + + diff --git a/Models/Autopush/cursor_reverse.ac b/Models/Autopush/cursor_reverse.ac new file mode 100644 index 000000000..938b7fc65 --- /dev/null +++ b/Models/Autopush/cursor_reverse.ac @@ -0,0 +1,133 @@ +AC3Db +MATERIAL "autopush cursor" rgb 0.0000 0.0000 0.0000 amb 0.0000 0.0000 0.0000 emis 1.000 0.173 0.545 spec 0.0000 0.0000 0.0000 shi 50 trans 0.0000 +OBJECT world +name "Blender_exporter_v2.26__cursor_reverse.ac" +kids 1 +OBJECT poly +name "Circle" +data 11 +Circle.mesh +crease 40.0 +numvert 36 +-0.86603 0.2 0.15 +-0.64952 0.2 0.15 +-0.64952 0.2 -0.375 +-0.86603 0.2 -0.15 +-0.64952 0.2 -0.15 +-0.86603 0.2 -0.5 +-0.56292 0.2 -0.675 +-0.45466 0.2 -0.4875 +-0 0.2 -0.75 +-0 0.2 -1 +-0.30311 0.2 -0.825 +-0.19486 0.2 -0.6375 +0.30311 0.2 -0.825 +0.19486 0.2 -0.6375 +0.64952 0.2 -0.375 +0.86603 0.2 -0.5 +0.56292 0.2 -0.675 +0.45466 0.2 -0.4875 +0.86603 0.2 -0.15 +0.64952 0.2 -0.15 +0.86603 0.2 0.5 +0.86603 0.2 0.15 +0.64952 0.2 0.15 +0.64952 0.2 0.375 +0.56292 0.2 0.675 +0.45466 0.2 0.4875 +0.30311 0.2 0.825 +0.19486 0.2 0.6375 +-0 0.2 0.75 +-0 0.2 1 +-0.30311 0.2 0.825 +-0.19486 0.2 0.6375 +-0.64952 0.2 0.375 +-0.86603 0.2 0.5 +-0.56292 0.2 0.675 +-0.45466 0.2 0.4875 +numsurf 12 +SURF 0X10 +mat 0 +refs 4 +2 0.078125 0.40625 +5 0.0625 0.375 +3 0.0625 0.5 +4 0.078125 0.5 +SURF 0X10 +mat 0 +refs 4 +32 0.078125 0.40625 +1 0.078125 0.5 +0 0.0625 0.5 +33 0.0625 0.375 +SURF 0X10 +mat 0 +refs 4 +8 0.078125 0.40625 +9 0.0625 0.375 +10 0.0625 0.5 +11 0.078125 0.5 +SURF 0X10 +mat 0 +refs 4 +2 0.078125 0.40625 +7 0.078125 0.5 +6 0.0625 0.5 +5 0.0625 0.375 +SURF 0X10 +mat 0 +refs 4 +14 0.078125 0.40625 +15 0.0625 0.375 +16 0.0625 0.5 +17 0.078125 0.5 +SURF 0X10 +mat 0 +refs 4 +8 0.078125 0.40625 +13 0.078125 0.5 +12 0.0625 0.5 +9 0.0625 0.375 +SURF 0X10 +mat 0 +refs 4 +23 0.078125 0.40625 +20 0.0625 0.375 +21 0.0625 0.5 +22 0.078125 0.5 +SURF 0X10 +mat 0 +refs 4 +14 0.078125 0.40625 +19 0.078125 0.5 +18 0.0625 0.5 +15 0.0625 0.375 +SURF 0X10 +mat 0 +refs 4 +28 0.078125 0.40625 +29 0.0625 0.375 +26 0.0625 0.5 +27 0.078125 0.5 +SURF 0X10 +mat 0 +refs 4 +23 0.078125 0.40625 +25 0.078125 0.5 +24 0.0625 0.5 +20 0.0625 0.375 +SURF 0X10 +mat 0 +refs 4 +32 0.078125 0.40625 +33 0.0625 0.375 +34 0.0625 0.5 +35 0.078125 0.5 +SURF 0X10 +mat 0 +refs 4 +28 0.078125 0.40625 +31 0.078125 0.5 +30 0.0625 0.5 +29 0.0625 0.375 +kids 0 diff --git a/Models/Autopush/cursor_reverse.xml b/Models/Autopush/cursor_reverse.xml new file mode 100644 index 000000000..a09f24966 --- /dev/null +++ b/Models/Autopush/cursor_reverse.xml @@ -0,0 +1,46 @@ + + + + + cursor_reverse.ac + + + false + + + + scale + /sim/model/autopush/stopping-distance-m + 0.0 + 1.0 + + + + material + + /sim/model/autopush/route/invalid + + + 1.0 + 0.0 + 0.0 + + + 1.0 + 0.0 + 0.0 + + + + diff --git a/Models/Autopush/cursor_sharp.ac b/Models/Autopush/cursor_sharp.ac new file mode 100644 index 000000000..e89929598 --- /dev/null +++ b/Models/Autopush/cursor_sharp.ac @@ -0,0 +1,67 @@ +AC3Db +MATERIAL "autopush cursor" rgb 0.0000 0.0000 0.0000 amb 0.0000 0.0000 0.0000 emis 1.000 0.173 0.545 spec 0.0000 0.0000 0.0000 shi 50 trans 0.0000 +OBJECT world +name "Blender_exporter_v2.26__cursor_sharp.ac" +kids 1 +OBJECT poly +name "Circle" +data 11 +Circle.mesh +crease 40.0 +numvert 12 +0 0.2 -0.75 +0 0.2 -1 +0.64952 0.2 -0.375 +0.86603 0.2 -0.5 +0.64952 0.2 0.375 +0.86603 0.2 0.5 +0 0.2 0.75 +0 0.2 1 +-0.64952 0.2 0.375 +-0.86603 0.2 0.5 +-0.64952 0.2 -0.375 +-0.86603 0.2 -0.5 +numsurf 6 +SURF 0X10 +mat 0 +refs 4 +0 0.125 0.6875 +2 0.171875 0.59375 +3 0.1875 0.625 +1 0.125 0.75 +SURF 0X10 +mat 0 +refs 4 +2 0.171875 0.59375 +4 0.171875 0.40625 +5 0.1875 0.375 +3 0.1875 0.625 +SURF 0X10 +mat 0 +refs 4 +4 0.171875 0.40625 +6 0.125 0.3125 +7 0.125 0.25 +5 0.1875 0.375 +SURF 0X10 +mat 0 +refs 4 +6 0.125 0.3125 +8 0.078125 0.40625 +9 0.0625 0.375 +7 0.125 0.25 +SURF 0X10 +mat 0 +refs 4 +8 0.078125 0.40625 +10 0.078125 0.59375 +11 0.0625 0.625 +9 0.0625 0.375 +SURF 0X10 +mat 0 +refs 4 +10 0.078125 0.59375 +0 0.125 0.6875 +1 0.125 0.75 +11 0.0625 0.625 +kids 0 diff --git a/Models/Autopush/cursor_sharp.xml b/Models/Autopush/cursor_sharp.xml new file mode 100644 index 000000000..df04653cc --- /dev/null +++ b/Models/Autopush/cursor_sharp.xml @@ -0,0 +1,46 @@ + + + + + cursor_sharp.ac + + + false + + + + scale + /sim/model/autopush/stopping-distance-m + 0.0 + 1.0 + + + + material + + /sim/model/autopush/route/invalid + + + 1.0 + 0.0 + 0.0 + + + 1.0 + 0.0 + 0.0 + + + + diff --git a/Models/Autopush/waypoint.ac b/Models/Autopush/waypoint.ac new file mode 100644 index 000000000..e6c3ff93e --- /dev/null +++ b/Models/Autopush/waypoint.ac @@ -0,0 +1,276 @@ +AC3Db +MATERIAL "autopush cursor" rgb 0.0000 0.0000 0.0000 amb 0.0000 0.0000 0.0000 emis 1.000 0.173 0.545 spec 0.0000 0.0000 0.0000 shi 50 trans 0.0000 +OBJECT world +name "Blender_exporter_v2.26__waypoint.ac" +kids 3 +OBJECT poly +name "Waypoint" +data 11 +Circle.mesh +crease 40.0 +numvert 33 +0.03902 0.2 -0.19616 +0.07654 0.2 -0.18478 +0.11111 0.2 -0.16629 +0.14142 0.2 -0.14142 +0.16629 0.2 -0.11111 +0.18478 0.2 -0.07654 +0.19616 0.2 -0.03902 +0.2 0.2 0 +0.19616 0.2 0.03902 +0.18478 0.2 0.07654 +0.16629 0.2 0.11111 +0.14142 0.2 0.14142 +0.11111 0.2 0.16629 +0.07654 0.2 0.18478 +0.03902 0.2 0.19616 +0 0.2 0.2 +-0.03902 0.2 0.19616 +-0.07654 0.2 0.18478 +-0.11111 0.2 0.16629 +-0.14142 0.2 0.14142 +-0.16629 0.2 0.11111 +-0.18478 0.2 0.07654 +-0.19616 0.2 0.03902 +-0.2 0.2 0 +-0.19616 0.2 -0.03902 +-0.18478 0.2 -0.07654 +-0.16629 0.2 -0.11111 +-0.14142 0.2 -0.14142 +-0.11111 0.2 -0.16629 +-0.07654 0.2 -0.18478 +-0.03902 0.2 -0.19616 +0 0.2 -0.2 +0 0.2 0 +numsurf 32 +SURF 0X0 +mat 0 +refs 3 +32 0.125 0.5 +18 0.090277 0.292133 +17 0.101082 0.26903 +SURF 0X0 +mat 0 +refs 3 +32 0.125 0.5 +31 0.125 0.75 +30 0.112807 0.745197 +SURF 0X0 +mat 0 +refs 3 +32 0.125 0.5 +4 0.176967 0.638893 +3 0.169194 0.676777 +SURF 0X0 +mat 0 +refs 3 +32 0.125 0.5 +17 0.101082 0.26903 +16 0.112807 0.254804 +SURF 0X0 +mat 0 +refs 3 +32 0.125 0.5 +30 0.112807 0.745197 +29 0.101082 0.73097 +SURF 0X0 +mat 0 +refs 3 +32 0.125 0.5 +3 0.169194 0.676777 +2 0.159723 0.707868 +SURF 0X0 +mat 0 +refs 3 +32 0.125 0.5 +16 0.112807 0.254804 +15 0.125 0.25 +SURF 0X0 +mat 0 +refs 3 +32 0.125 0.5 +29 0.101082 0.73097 +28 0.090277 0.707868 +SURF 0X0 +mat 0 +refs 3 +32 0.125 0.5 +2 0.159723 0.707868 +1 0.148918 0.73097 +SURF 0X0 +mat 0 +refs 3 +32 0.125 0.5 +15 0.125 0.25 +14 0.137193 0.254804 +SURF 0X0 +mat 0 +refs 3 +32 0.125 0.5 +28 0.090277 0.707868 +27 0.080806 0.676777 +SURF 0X0 +mat 0 +refs 3 +32 0.125 0.5 +1 0.148918 0.73097 +0 0.137193 0.745197 +SURF 0X0 +mat 0 +refs 3 +32 0.125 0.5 +14 0.137193 0.254804 +13 0.148918 0.26903 +SURF 0X0 +mat 0 +refs 3 +32 0.125 0.5 +27 0.080806 0.676777 +26 0.073033 0.638893 +SURF 0X0 +mat 0 +refs 3 +32 0.125 0.5 +0 0.137193 0.745197 +31 0.125 0.75 +SURF 0X0 +mat 0 +refs 3 +32 0.125 0.5 +13 0.148918 0.26903 +12 0.159723 0.292133 +SURF 0X0 +mat 0 +refs 3 +32 0.125 0.5 +26 0.073033 0.638893 +25 0.067258 0.595671 +SURF 0X0 +mat 0 +refs 3 +32 0.125 0.5 +12 0.159723 0.292133 +11 0.169194 0.323224 +SURF 0X0 +mat 0 +refs 3 +32 0.125 0.5 +25 0.067258 0.595671 +24 0.063701 0.548773 +SURF 0X0 +mat 0 +refs 3 +32 0.125 0.5 +11 0.169194 0.323224 +10 0.176967 0.361108 +SURF 0X0 +mat 0 +refs 3 +32 0.125 0.5 +24 0.063701 0.548773 +23 0.0625 0.5 +SURF 0X0 +mat 0 +refs 3 +32 0.125 0.5 +10 0.176967 0.361108 +9 0.182743 0.404329 +SURF 0X0 +mat 0 +refs 3 +32 0.125 0.5 +23 0.0625 0.5 +22 0.063701 0.451228 +SURF 0X0 +mat 0 +refs 3 +32 0.125 0.5 +9 0.182743 0.404329 +8 0.186299 0.451228 +SURF 0X0 +mat 0 +refs 3 +32 0.125 0.5 +22 0.063701 0.451228 +21 0.067258 0.404329 +SURF 0X0 +mat 0 +refs 3 +32 0.125 0.5 +8 0.186299 0.451228 +7 0.1875 0.5 +SURF 0X0 +mat 0 +refs 3 +32 0.125 0.5 +21 0.067258 0.404329 +20 0.073033 0.361108 +SURF 0X0 +mat 0 +refs 3 +32 0.125 0.5 +7 0.1875 0.5 +6 0.186299 0.548773 +SURF 0X0 +mat 0 +refs 3 +32 0.125 0.5 +20 0.073033 0.361108 +19 0.080806 0.323223 +SURF 0X0 +mat 0 +refs 3 +32 0.125 0.5 +6 0.186299 0.548773 +5 0.182742 0.595671 +SURF 0X0 +mat 0 +refs 3 +32 0.125 0.5 +19 0.080806 0.323223 +18 0.090277 0.292133 +SURF 0X0 +mat 0 +refs 3 +32 0.125 0.5 +5 0.182742 0.595671 +4 0.176967 0.638893 +kids 0 +OBJECT poly +name "WingtipL" +data 15 +Circle.mesh.001 +crease 40.0 +numvert 4 +-0.1 0.2 -0.1 +-0.1 0.2 0.1 +0.1 0.2 -0.1 +0.1 0.2 0.1 +numsurf 1 +SURF 0X0 +mat 0 +refs 4 +0 0 0 +1 0 0 +3 0 0 +2 0 0 +kids 0 +OBJECT poly +name "WingtipR" +data 15 +Circle.mesh.007 +crease 40.0 +numvert 4 +-0.1 0.2 -0.1 +-0.1 0.2 0.1 +0.1 0.2 -0.1 +0.1 0.2 0.1 +numsurf 1 +SURF 0X0 +mat 0 +refs 4 +0 0 0 +1 0 0 +3 0 0 +2 0 0 +kids 0 diff --git a/Models/Autopush/waypoint.xml b/Models/Autopush/waypoint.xml new file mode 100644 index 000000000..8708adc85 --- /dev/null +++ b/Models/Autopush/waypoint.xml @@ -0,0 +1,87 @@ + + + + + waypoint.ac + + + false + + + + select + WingtipL + WingtipR + + /sim/model/autopush/route/show-wingtip + + + + + translate + WingtipL + /sim/model/autopush/route/wingspan-m + 0.5 + + 0 + 1 + 0 + + 0.0 + 1.0 + + + + translate + WingtipR + /sim/model/autopush/route/wingspan-m + -0.5 + + 0 + 1 + 0 + + 0.0 + 1.0 + + + + scale + + Waypoint + WingtipL + WingtipR + /sim/model/autopush/stopping-distance-m + 0.0 + 1.0 + + + + material + + /sim/model/autopush/route/invalid + + + 1.0 + 0.0 + 0.0 + + + 1.0 + 0.0 + 0.0 + + + + diff --git a/Nasal/Autopush/autopush.nas b/Nasal/Autopush/autopush.nas new file mode 100644 index 000000000..02b7f13f1 --- /dev/null +++ b/Nasal/Autopush/autopush.nas @@ -0,0 +1,141 @@ +# 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 _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) and getprop("/sim/model/autopush/available")) { + _start(); + } else { + _stop(); + } +}, 1, 0); diff --git a/Nasal/Autopush/driver.nas b/Nasal/Autopush/driver.nas new file mode 100644 index 000000000..a8c1cbb1d --- /dev/null +++ b/Nasal/Autopush/driver.nas @@ -0,0 +1,155 @@ +# AUTOPUSH +# Pushback driver class. +# +# Command the pushback to tow/push the aircraft. +# +# 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 _K_V = nil; +var _F_V = nil; +var _R_turn_min = nil; +var _D_stop = nil; +var _K_psi = nil; +var _F_psi = nil; +var _K_psidot = nil; +var _F_psidot = nil; +var _debug = nil; +var _psi = nil; +var _time = nil; + +var _route = nil; +var _route_reverse = nil; +var _push = nil; +var _sign = nil; + +var _to_wp = 0; +var _is_last_wp = 0; +var _is_reverse_wp = 0; + + +var _advance_wp = func(flip_sign = 0) { + _to_wp += 1; + _is_last_wp = (_to_wp == (size(_route) - 1)); + _is_reverse_wp = (_route_reverse[_to_wp]); + if (flip_sign) { + _sign *= -1; + _push = !_push; + } + if (_debug == 1) { + print("autopush_driver to_wp " ~ _to_wp); + } +} + +var _loop = func() { + if (!getprop("/sim/model/autopush/connected")) { + stop(); + return; + } + var (A, D) = courseAndDistance(_route[_to_wp]); + D *= NM2M; + var (psi_leg, D_leg) = courseAndDistance(_route[_to_wp - 1], _route[_to_wp]); + var deltapsi = geo.normdeg180(A - psi_leg); + var psi = getprop("/orientation/heading-deg") + _push * 180.0; + var deltaA = math.min(math.max(_K_psi * geo.normdeg180(A - psi), -_F_psi), _F_psi); + var time = getprop("/sim/time/elapsed-sec"); + var dt = time - _time; + var minus_psidot = (dt > 0.002) * math.min(math.max(_K_psidot * (_psi - psi) / dt, -_F_psidot), _F_psidot); + _psi = psi; + _time = time; + # TODO Either use _K_V and total remaining distance or turn radius to calculate speed. + # TODO Make slider input override speed. + var V = _F_V; + if (_is_reverse_wp or _is_last_wp) { + if ((D < _D_stop) or (abs(deltapsi) > 90.0)) { + if (_is_last_wp) { + _done(); + return; + } + if (_is_reverse_wp) { + _advance_wp(1); + } + } + } else { + if ((D < _R_turn_min) or (abs(deltapsi) > 90.0)) { + _advance_wp(); + } + } + var steering = math.min(math.max(_sign * (deltaA + minus_psidot), -1.0), 1.0); + if (_debug > 1) { + print("autopush_driver to_wp " ~ _to_wp ~ ", A " ~ geo.normdeg(A) ~ ", deltaA " ~ deltaA ~ ", minus_psidot " ~ minus_psidot); + } + setprop("/sim/model/autopush/target-speed-km_h", _sign * V); + setprop("/sim/model/autopush/steer-cmd-norm", steering); +} + +var _timer = maketimer(0.051, func{_loop()}); + +var _done = func() { + stop(); + autopush_route.clear(); + screen.log.write("(pushback): Pushback complete, please set parking brake."); +} + +var start = func() { + if (_timer.isRunning) { + gui.popupTip("Already moving"); + return; + } + if (!getprop("/sim/model/autopush/connected")) { + gui.popupTip("Pushback not connected"); + return; + } + _route = autopush_route.route(); + _route_reverse = autopush_route.route_reverse(); + if ((_route == nil) or size(_route) < 2) { + gui.popupTip("Pushback route empty or invalid"); + return; + } else { + autopush_route.done(); + } + _K_V = getprop("/sim/model/autopush/driver/K_V"); + _F_V = getprop("/sim/model/autopush/driver/F_V"); + _R_turn_min = getprop("/sim/model/autopush/min-turn-radius-m"); + _D_stop = getprop("/sim/model/autopush/stopping-distance-m"); + _K_psi = getprop("/sim/model/autopush/driver/K_psi"); + _F_psi = getprop("/sim/model/autopush/driver/F_psi"); + _K_psidot = getprop("/sim/model/autopush/driver/K_psidot"); + _F_psidot = getprop("/sim/model/autopush/driver/F_psidot"); + _debug = getprop("/sim/model/autopush/debug") or 0; + if (!_to_wp) { + var (psi_park, D_park) = courseAndDistance(_route[0], _route[1]); + _push = (abs(geo.normdeg180(getprop("/orientation/heading-deg") - psi_park)) > 90.0); + _sign = 1.0 - 2.0 * _push; + _advance_wp(); + _psi = 0.0; + } + _time = getprop("/sim/time/elapsed-sec"); + _timer.start(); + var endsign = _sign; + for (ii = _to_wp; ii < size(_route_reverse); ii += 1) { + if (_route_reverse[ii]) { + endsign = -endsign; + } + } + var (psi_twy, D_twy) = courseAndDistance(_route[size(_route) - 2], _route[size(_route) - 1]); + if (endsign < 0.0) { + screen.log.write("(pushback): Push back facing " ~ math.round(geo.normdeg(psi_twy + 180.0 - magvar()), 1.0) ~ "."); + } else { + screen.log.write("(pushback): Tow facing " ~ math.round(geo.normdeg(psi_twy - magvar()), 1.0) ~ "."); + } +} + +var pause = func() { + _timer.stop(); + setprop("/sim/model/autopush/target-speed-km_h", 0.0); +} + +var stop = func() { + pause(); + _to_wp = 0; +} diff --git a/Nasal/Autopush/dynarr.nas b/Nasal/Autopush/dynarr.nas new file mode 100644 index 000000000..03518aa0f --- /dev/null +++ b/Nasal/Autopush/dynarr.nas @@ -0,0 +1,61 @@ +# Class for dynamic arrays +# +# Copyright (c) 2018 dynamic arrays authors: +# Michael Danilov +# Merspieler http://gitlab.com/merspieler +# Distribute under the terms of GPLv2. + +## Useage +# to create a new object: var = dynarr.new(); +# to add elements: .add(); +# you can access the full stored array as: .arr +# to get only the used area of the array: var = .get_spliced() + +var dynarr = +{ + new: func(size = 8) + { + var this = {parents:[dynarr]}; + this.maxsize = size; + this.size = 0; + this.arr = setsize([], size); + + return this; + }, + + # add a new element to the array + add: func(obj) + { + # case there's no space left + if (me.size + 1 >= me.maxsize) + { + # double array size + me.maxsize *= 2; + me.arr = setsize(me.arr, me.maxsize); + } + + # add object and increase used counter + me.arr[me.size] = obj; + me.size += 1; + }, + + # delete an element from the array + del: func(id) + { + me.size -= 1; + for(ii = id; ii < me.size - 1; ii += 1){ + me.arr[ii] = me.arr[ii + 1]; + } + }, + + # returns only the filled part of the array or nil if array is empty + get_sliced: func() + { + if (me.size == 0) + { + return nil; + } + + return me.arr[0:me.size - 1]; + } +}; diff --git a/Nasal/Autopush/route.nas b/Nasal/Autopush/route.nas new file mode 100644 index 000000000..b67c60723 --- /dev/null +++ b/Nasal/Autopush/route.nas @@ -0,0 +1,433 @@ +# AUTOPUSH +# Visual entry of pushback route. +# +# 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 _listener = nil; +var _view_listener = nil; +var _user_points = dynarr.dynarr.new(4); +var _user_point_modes = dynarr.dynarr.new(4); # Modes: 0 = Bezier node, 1 = Bezier end/start node, 2 = Reverse +var _route = []; +var _route_hdg = []; +var _route_reverse = []; +var _top_view_index = nil; +var _top_view_heading_offset_deg = 180.0; +var _reset_view_index = nil; +var _view_z_offset = nil; +var _view_pitch_offset_deg = nil; +var _view_heading_offset_deg = nil; +var _user_point_models = []; +var _waypoint_models = []; +var _N = 0; +var _show = 0; +var _R_turn_min = 0; +var _invalid = 0; + +# Make top-down view point north in old FG. +var __fg_version = num(string.replace(getprop("/sim/version/flightgear"),".","")); +if (__fg_version < 201920) { + _top_view_heading_offset_deg = 94.5; +} + + +var _add = func(pos) { + if (_N) { + var (A, S) = courseAndDistance(_user_points.arr[_N - 1], pos); + S *= NM2M; + if (S < _R_turn_min) { + gui.popupTip("Too close to the previous point,\ntry again"); + return; + }else if (S > 10000.0) { + gui.popupTip("Too far from the previous point,\ntry again"); + return; + } + } + _user_points.add(geo.Coord.new(pos)); + + if (_user_point_modes.maxsize == 1 and _user_point_modes.size == 1) { + _user_point_modes.arr[0] = 0; + } else { + _user_point_modes.add(0); + } + setsize(_user_point_models, _N + 1); + _user_point_models[_N] = geo.put_model("Models/Autopush/cursor.xml", pos, 0.0); + _N += 1; + if (_N == 1) { + gui.popupTip("Click waypoints, press \"Done\" to finish"); + } else { + _calculate_route(); + _place_waypoint_models(); + } +} + +var delete_last = func() { + if (_listener == nil) { + return; + } + if (_N > 1) { + _N -= 1; + _user_points.del(_N); + _user_point_modes.del(_N); + _user_point_models[_N].remove(); + _user_point_models[_N] = nil; + setsize(_user_point_models, _N); + _calculate_route(); + _place_waypoint_models(); + } +} + +var _stop = func(fail = 0) { + if (_listener != nil) { + removelistener(_listener); + _listener = nil; + if (!fail) { + settimer(func() { + _finalize_top_view(); + gui.popupTip("Done"); + }, 1.0); + } else { + _finalize_top_view(); + } + } +} + +var _place_user_point_models = func() { + _clear_user_point_models(); + setsize(_user_point_models, _N); + var user_points = _user_points.get_sliced(); + for (var ii = 0; ii < _N; ii += 1) { + var model = "Models/Autopush/cursor.xml"; + if (_user_point_modes.arr[ii] == 1) { + model = "Models/Autopush/cursor_sharp.xml"; + } else if (_user_point_modes.arr[ii] == 2) { + model = "Models/Autopush/cursor_reverse.xml"; + } + _user_point_models[ii] = geo.put_model(model, user_points[ii], 0.0); + } +} + +var _clear_user_point_models = func() { + for (var ii = 0; ii < size(_user_point_models); ii += 1) { + if (_user_point_models[ii] != nil) { + _user_point_models[ii].remove(); + _user_point_models[ii] = nil; + } + } + setsize(_user_point_models, 0); +} + +var _place_waypoint_models = func() { + _clear_waypoint_models(); + setsize(_waypoint_models, size(_route)); + for (var ii = 0; ii < size(_route); ii += 1) { + _waypoint_models[ii] = geo.put_model("Models/Autopush/waypoint.xml", _route[ii], _route_hdg[ii]); + } +} + +var _clear_waypoint_models = func() { + for (var ii = 0; ii < size(_waypoint_models); ii += 1) { + if (_waypoint_models[ii] != nil) { + _waypoint_models[ii].remove(); + _waypoint_models[ii] = nil; + } + } + setsize(_waypoint_models, 0); +} + +var top_view = func() { + if (_view_listener != nil) { + return; + } + _top_view_index = view.indexof("Chase View Without Yaw"); + _reset_view_index = getprop("/sim/current-view/view-number"); + setprop("/sim/current-view/view-number", _top_view_index); + _view_pitch_offset_deg = getprop("/sim/current-view/pitch-offset-deg"); + _view_heading_offset_deg = getprop("/sim/current-view/heading-offset-deg"); + _view_z_offset = getprop("/sim/current-view/z-offset-m"); + setprop("/sim/current-view/z-offset-m", -500.0); + setprop("/sim/current-view/heading-offset-deg", _top_view_heading_offset_deg); + setprop("/sim/current-view/pitch-offset-deg", 90.0); + _view_listener = setlistener("/sim/current-view/name", func { + _finalize_top_view(); + }, 0, 0); +} + +var _finalize_top_view = func() { + if (_view_listener == nil) { + return; + } + removelistener(_view_listener); + _view_listener = nil; + # Go back to the view to restore settings, in case user has switched away. + setprop("/sim/current-view/view-number", _top_view_index); + setprop("/sim/current-view/z-offset-m", _view_z_offset); + setprop("/sim/current-view/heading-offset-deg", _view_heading_offset_deg); + setprop("/sim/current-view/pitch-offset-deg", _view_pitch_offset_deg); + setprop("/sim/current-view/view-number", _reset_view_index); + if (!_show) { + _clear_user_point_models(); + _clear_waypoint_models(); + } +} + +var _calculate_route = func() { + _route = []; + _route_reverse = []; + var user_points = _user_points.get_sliced(); + var route = dynarr.dynarr.new(); + # add the first point cause it will be fix at this pos + route.add(geo.Coord.new(user_points[0])); + n = size(user_points); + var base = 0; + # Detect points where push/pull direction is reversed. + for (var i = 0; i < n; i += 1) { + if (i and (i < n - 1)) { + if((_user_point_modes.arr[i] == 1) or (_user_point_modes.arr[i] == 2)) { + var newmode = 1; + var deltaA = abs(geo.normdeg180(user_points[i - 1].course_to(user_points[i]) - user_points[i].course_to(user_points[i + 1]))); + if (deltaA > 91.0) { + newmode = 2; + } + if(newmode != _user_point_modes.arr[i]){ + _set_userpoint_mode(i, newmode); + } + } + } else { + # Clear reverse for first and last points. + if(_user_point_modes.arr[i] == 2) { + if(_user_point_modes.arr[i] != 1){ + _set_userpoint_mode(i, 1); + } + } + } + } + for (var i = 0; i < n; i += 1) { + if (_user_point_modes.arr[i] or (i == n - 1)) { + if (i - base > 0) { + var bezier = _calculate_bezier(user_points[base:i]); + if (bezier != nil) { + var m = size(bezier); + for (var j = 0; j < m; j += 1) { + route.add(geo.Coord.new(bezier[j])); + } + } + } + base = i; + route.add(geo.Coord.new(user_points[i])); + if (_user_point_modes.arr[i] == 2) { + var route_size = size(route.get_sliced()); + setsize(_route_reverse, route_size); + _route_reverse[route_size - 1] = 1; + } + } + } + var PNumber = size(user_points); + _route = route.get_sliced(); + setsize(_route_reverse, size(_route)); + _check_turn_radius(); + _calculate_hdg(); +} + +var _calculate_bezier = func(user_points) { + var route = dynarr.dynarr.new(); + + var PNumber = size(user_points); + + if (PNumber > 1) { + var pointList = []; + setsize(pointList, PNumber); + for (var i = 0; i < PNumber; i += 1) { + pointList[i] = []; + setsize(pointList[i], PNumber); + } + + pointList[0] = user_points; + + var len = 0; + for (var i = 0; i < PNumber - 1; i += 1) { + len += user_points[i].distance_to(user_points[i + 1]); + } + + if (len < _R_turn_min) { + route.add(geo.Coord.new(user_points[PNumber - 1])) + } else { + var step = _R_turn_min / len; + + for (var i = step; i < 1 - step; i+= step) { + # start iterating from 1 cause we don't need to iterate over Pn + for (var j = 1; j < PNumber; j += 1) { + for (var k = 0; k < PNumber - j; k += 1) { + pointList[j][k] = geo.Coord.new(pointList[j - 1][k]); + var dist = pointList[j - 1][k].distance_to(pointList[j - 1][k + 1]); + var course = pointList[j - 1][k].course_to(pointList[j - 1][k + 1]); + pointList[j][k].apply_course_distance(course, dist * i); + } + } + pointList[PNumber - 1][0].set_alt(geo.elevation(pointList[PNumber - 1][0].lat(),pointList[PNumber - 1][0].lon())); + route.add(geo.Coord.new(pointList[PNumber - 1][0])); + } + } + } + + return route.get_sliced(); +} + +var _calculate_hdg = func() { + _route_hdg = []; + var route_hdg = dynarr.dynarr.new(); + var ilast = size(_route) - 1; + for (i = 0; i < ilast; i += 1) { + var hdg = _route[i].course_to(_route[i + 1]); + route_hdg.add(hdg); + } + # Last heading would be undefined, so just repeat the one before the last. + route_hdg.add(route_hdg.get_sliced()[ilast - 1]); + _route_hdg = route_hdg.get_sliced(); +} + +# Checks each waypoint's turn radius and marks the route invalid if +# it is smaller than the aircraft's turn radius. +var _check_turn_radius = func() { + # A waypoint's turn radius is the radius of a circle circumscribed around the waypoint, previous and next waypoints. + # Formula source: https://math.stackexchange.com/questions/947882/radius-of-circumscribed-circle-of-triangle-as-function-of-the-sides + + var len = size(_route); + _invalid = 0; + + # We can't calculate the radius for the first and last point + for (i = 1; i < len - 2; i += 1) { + # Disable check for push and pull points + if (_route_reverse[i] != 1) { + var a = _route[i].distance_to(_route[i + 1]); + var b = _route[i].distance_to(_route[i - 1]); + var c = _route[i - 1].distance_to(_route[i + 1]); + + + var margin = _R_turn_min / 5000; + + # Stright line check with marging to prevent floating point error + if (a + b + margin >= c and a + b - margin <= c) { + var r = - 1; + } else { + var r = (a * b * c) / math.sqrt( + 2 * a * a * b * b + + 2 * a * a * c * c + + 2 * b * b * c * c + - a * a * a * a + - b * b * b * b + - c * c * c * c + ); + } + + if ((r < _R_turn_min) and (r != -1)) { + _invalid = 1; + } + } + } + + setprop("/sim/model/autopush/route/invalid", _invalid); +} + +setlistener("/sim/model/autopush/route/show", func(p) { + var show = p.getValue(); + if (_listener == nil) { + if (show) { + _place_user_point_models(); + _place_waypoint_models(); + } else { + _clear_user_point_models(); + _clear_waypoint_models(); + } + } + _show = show; +}, 1, 0); + + +var enter = func() { + clear(); + top_view(); + _R_turn_min = getprop("/sim/model/autopush/min-turn-radius-m"); + var wp = geo.aircraft_position(); + var H = geo.elevation(wp.lat(), wp.lon()); + if (H != nil) { + wp.set_alt(H); + } + _add(wp); + _listener = setlistener("/sim/signals/click", func { + _add(geo.click_position()); + }); + # This property can be overridden manually, if needed. + var wingspan = getprop("/sim/model/autopush/route/wingspan-m"); + if ((wingspan == nil) or (wingspan == 0.0)) { + # JSBSim + wingspan = getprop("/fdm/jsbsim/metrics/bw-ft"); + if (wingspan != nil) { + wingspan *= FT2M; + } else { + # YAsim + wingspan = getprop("/fdm/yasim/model/wings/wing/wing-span"); + } + setprop("/sim/model/autopush/route/wingspan-m", wingspan); + } +} + +var _set_userpoint_mode = func(id, mode) { + if (_user_point_modes.arr[id] != mode) { + _user_point_modes.arr[id] = mode; + } + if (_user_point_models[id] != nil) { + _user_point_models[id].remove(); + var model = "Models/Autopush/cursor.xml"; + if (_user_point_modes.arr[id] == 1) { + model = "Models/Autopush/cursor_sharp.xml"; + } else if (_user_point_modes.arr[id] == 2) { + model = "Models/Autopush/cursor_reverse.xml"; + } + _user_point_models[id] = geo.put_model(model, _user_points.get_sliced()[id], 0.0); + } +} + +var toggle_sharp = func() { + if (_listener == nil) { + return; + } + id = _N - 1; + if (_user_point_modes.arr[id]) { + _set_userpoint_mode(id, 0); + } else { + _set_userpoint_mode(id, 1); + } +} + +var done = func() { + _stop(0); +} + +var clear = func() { + autopush_driver.stop(); + _stop(1); + _clear_user_point_models(); + _clear_waypoint_models(); + _N = 0; + _user_points = dynarr.dynarr.new(4); + _user_point_modes = dynarr.dynarr.new(1); +} + +var route = func() { + if (_invalid or (_N < 2)) { + return nil; + } + return _route; +} + +var route_reverse = func() { + if (_invalid or (_N < 2)) { + return nil; + } + return _route_reverse; +} diff --git a/gui/dialogs/autopush.xml b/gui/dialogs/autopush.xml new file mode 100644 index 000000000..7a619bd8d --- /dev/null +++ b/gui/dialogs/autopush.xml @@ -0,0 +1,361 @@ + + + + + + + autopush + vbox + + + + hbox + + + + + + + true + + + + + + + + + + + true + vbox + center + top + + + left + + /sim/model/autopush/enabled + true + + dialog-apply + + + + + table + + + 0 + 0 + + left + + + + + + 0 + 2 + -1.0 + 1.0 + /sim/model/autopush/steer-cmd-norm + 0.1 + true + + dialog-apply + + + + + + + + + 1 + 0 + + left + + + + + + 1 + 2 + -25 + 25 + /sim/model/autopush/target-speed-km_h + 1.0 + true + + dialog-apply + + + + + + + + + 1 + 5 + 16 + /sim/model/autopush/target-speed-km_h + %3.0f + true + right + + + + 1 + 6 + + left + + + + + + + + table + + + 0 + 0 + + left + + + + + + + + + + 1 + 0 + + left + + + + + + + + 1 + 3 + left + + /sim/model/autopush/route/show + true + + dialog-apply + + + + + 2 + 0 + + left + + + + + + + + 2 + 3 + left + + true + /sim/model/autopush/route/show-wingtip + + dialog-apply + + + + + + + +