1 # This is a small script that adjusts autopilot target values to track
2 # (fly in formation with) an AI or Multiplayer aircraft.
4 # Quick start instructions:
7 # 1. Copy this file into $FGROOT/data/Nasal (along with the other
8 # system nasal scripts.)
10 # 2. Start up FlightGear selecting an airplane with a reasonably configured
11 # autopilot that responds to and works with the standard autopilot
12 # dialog box (F11). The MiG 15 is one that works, the 777-200 works,
13 # the Citation Bravo does not work, the default c172 probably does not
16 # 3. Take off and establish stable flight.
18 # 4. Open the property browser (File->Browse Internal Properties) and navigate
19 # to /ai/models/ Choose one of the available aircraft[] or multiplayer[]
20 # entries. You can look at all those subtrees to find the call sign you
21 # want. Also note that the subtree for each entity has a radar area that
22 # will show range and offset from your current heading.
24 # 5. Open a second property browser window (upper left click box in the first
25 # property browser window.) Navigate to /autopilot/target-tracking/
27 # 6. Set "/autopilot/target-tracking/target-root" to point to the entity
28 # path you discovered in step #4. For instance, this should be set to
29 # something like /ai/models/multiplayer[2] or /ai/models/aircraft[0]
31 # 7. Set "/autopilot/target-tracking/goal-range-nm" to the follow distance
34 # 8. Set "/autopilot/target-tracking/enable" = 1, this will turn on the radar
35 # computation for each ai/multiplayer entity and will tell the tracking
36 # script to start updating the autopilot settings.
38 # 9. Open up the autopilot configuration window (F11) and activate any of the
39 # heading, pitch, and speed axes. The script will begin updating the heading
40 # bug angle, the "speed with throttle" value, and the "altitude hold" value.
42 # 10. You can choose to mix and match any of the autopilot modes you want, i.e.
43 # you could turn off the heading control and turn manually while the system
44 # holds speed and altitude for you.
46 # 11. It always helps to have a sensible target arcraft to chase. You are
47 # flying within the turn radius and climb rate limits of your autopilot.
49 # Don't forget you are pilot in command and at all times responsible for
50 # maintaining safe airspeed and altitude.
55 # print("Target Tracking script loading ...");
57 # script defaults (configurable if you like)
58 var default_update_period = 0.05;
59 var default_goal_range_nm = 0.05;
60 var default_target_root = "/ai/models/aircraft[0]";
61 var default_min_speed_kt = 120;
63 # master enable switch
64 var target_tracking_enable = 0;
67 var update_period = default_update_period;
69 # goal range to acheive when following target
70 var goal_range_nm = 0;
72 # minimum speed so we don't drop out of the sky
75 # Target property tree root
79 var tracker_loop_id = 0;
81 # Initialize target tracking
82 var TrackInit = func {
83 if (props.globals.getNode("autopilot") == nil)
86 target_tracking_enable = getprop("/autopilot/target-tracking/enable");
87 if ( target_tracking_enable == nil ) {
88 target_tracking_enable = 0;
89 setprop("/autopilot/target-tracking/enable", target_tracking_enable);
92 update_period = getprop("/autopilot/target-tracking/update-period");
93 if ( update_period == nil ) {
94 update_period = default_update_period;
95 setprop("/autopilot/target-tracking/update-period", update_period);
98 goal_range_nm = getprop("/autopilot/target-tracking/goal-range-nm");
99 if ( goal_range_nm == nil ) {
100 goal_range_nm = default_goal_range_nm;
101 setprop("/autopilot/target-tracking/goal-range-nm", goal_range_nm);
104 min_speed_kt = getprop("/autopilot/target-tracking/min-speed-kt");
105 if ( min_speed_kt == nil ) {
106 min_speed_kt = default_min_speed_kt;
107 setprop("/autopilot/target-tracking/min-speed-kt", min_speed_kt);
110 target_root = getprop("/autopilot/target-tracking/target-root");
111 if ( target_root == nil ) {
112 target_root = default_target_root;
113 setprop("/autopilot/target-tracking/target-root", target_root);
116 setlistener("/autopilot/target-tracking/enable", func { startTimer();} );
119 # If enabled, update our AP target values based on the target range,
121 var TrackUpdate = func(loop_id) {
122 # avoid running multiple concurrent timers
123 if (tracker_loop_id != loop_id)
126 if (props.globals.getNode("autopilot") == nil)
129 target_tracking_enable = getprop("/autopilot/target-tracking/enable");
131 if ( target_tracking_enable == 1 ) {
132 update_period = getprop("/autopilot/target-tracking/update-period");
134 # refresh user configurable values
135 goal_range_nm = getprop("/autopilot/target-tracking/goal-range-nm");
136 target_root = getprop("/autopilot/target-tracking/target-root");
138 # force radar debug-mode on (forced radar calculations even if
139 # no radar instrument and ai aircraft are out of range
140 setprop("/instrumentation/radar/debug-mode", 1);
142 my_hdg_prop = sprintf("/orientation/heading-magnetic-deg" );
143 my_hdg = getprop(my_hdg_prop);
145 my_hdg_true_prop = sprintf("/orientation/heading-deg" );
146 my_hdg_true = getprop(my_hdg_true_prop);
148 var alt_prop = sprintf("%s/position/altitude-ft", target_root );
149 var alt = getprop(alt_prop);
151 print("bad property path: ", alt_prop);
155 var speed_prop = sprintf("%s/velocities/true-airspeed-kt", target_root );
156 var speed = getprop(speed_prop);
157 if ( speed == nil ) {
158 print("bad property path: ", speed_prop);
162 var range_prop = sprintf("%s/radar/range-nm", target_root );
163 var range = getprop(range_prop);
164 if ( range == nil ) {
165 print("bad property path: ", range_prop);
169 var h_offset_prop = sprintf("%s/radar/h-offset", target_root );
170 var h_offset = getprop(h_offset_prop);
171 if ( h_offset == nil ) {
172 print("bad property path: ", h_offset_prop);
176 if ( h_offset > -90 and h_offset < 90 ) {
178 var range_error = range - goal_range_nm;
181 var range_error = goal_range_nm - range;
183 var target_speed = speed + range_error * 100.0;
184 if ( target_speed < min_speed_kt ) {
185 target_speed = min_speed_kt;
188 setprop( "/autopilot/settings/target-altitude-ft", alt );
189 setprop( "/autopilot/settings/heading-bug-deg", my_hdg + h_offset );
190 setprop( "/autopilot/settings/true-heading-deg",
191 my_hdg_true + h_offset );
192 setprop( "/autopilot/settings/target-speed-kt", target_speed );
194 # only keep the timer running when the feature is really enabled
195 settimer(func() { TrackUpdate(loop_id); }, update_period );
199 # create and start a new timer to cause our update function to be called periodially
201 tracker_loop_id += 1;
202 TrackUpdate(tracker_loop_id);
205 settimer(TrackInit, 0);