1
0
Fork 0
fgdata/Nasal/track_target.nas

192 lines
7.4 KiB
Text
Raw Normal View History

# This is a small script that adjusts autopilot target values to track
# (fly in formation with) an AI or Multiplayer aircraft.
# Quick start instructions:
#
#
# 1. Copy this file into $FGROOT/data/Nasal (along with the other
# system nasal scripts.)
#
# 2. Start up FlightGear selecting an airplane with a reasonably configured
# autopilot that responds to and works with the standard autopilot
# dialog box (F11). The MiG 15 is one that works, the 777-200 works,
# the Citation Bravo does not work, the default c172 probably does not
# work, etc.
#
# 3. Take off and establish stable flight.
#
# 4. Open the property browser (File->Browse Internal Properties) and navigate
# to /ai/models/ Choose one of the available aircraft[] or multiplayer[]
# entries. You can look at all those subtrees to find the call sign you
# want. Also note that the subtree for each entity has a radar area that
# will show range and offset from your current heading.
#
# 5. Open a second property browser window (upper left click box in the first
# property browser window.) Navigate to /autopilot/target-tracking/
#
# 6. Set "/autopilot/target-tracking/target-root" to point to the entity
# path you discovered in step #4. For instance, this should be set to
# something like /ai/models/multiplayer[2] or /ai/models/aircraft[0]
#
# 7. Set "/autopilot/target-tracking/goal-range-nm" to the follow distance
# you want.
#
# 8. Set "/autopilot/target-tracking/enable" = 1, this will turn on the radar
# computation for each ai/multiplayer entity and will tell the tracking
# script to start updating the autopilot settings.
#
# 9. Open up the autopilot configuration window (F11) and activate any of the
# heading, pitch, and speed axes. The script will begin updating the heading
# bug angle, the "speed with throttle" value, and the "altitude hold" value.
#
# 10. You can choose to mix and match any of the autopilot modes you want, i.e.
# you could turn off the heading control and turn manually while the system
# holds speed and altitude for you.
#
# 11. It always helps to have a sensible target arcraft to chase. You are
# flying within the turn radius and climb rate limits of your autopilot.
#
# Don't forget you are pilot in command and at all times responsible for
# maintaining safe airspeed and altitude.
#
# Enjoy the ride!
2007-05-15 16:07:15 +00:00
# print("Target Tracking script loading ...");
# script defaults (configurable if you like)
var default_update_period = 0.05;
var default_goal_range_nm = 0.15;
var default_target_root = "/ai/models/aircraft[0]";
var default_min_speed_kt = 120;
# master enable switch
var target_tracking_enable = 0;
# update period
var update_period = default_update_period;
# goal range to acheive when following target
var goal_range_nm = 0;
# minimum speed so we don't drop out of the sky
var min_speed_kt = 0;
# Target property tree root
var target_root = "";
# Loop identifier
var tracker_loop_id = 0;
# Initialize target tracking
var TrackInit = func {
if (props.globals.getNode("autopilot") == nil)
return;
props.globals.initNode("/autopilot/target-tracking/enable", 0, "BOOL");
props.globals.initNode("/autopilot/target-tracking/update-period", default_update_period, "DOUBLE");
props.globals.initNode("/autopilot/target-tracking/goal-range-nm", default_goal_range_nm, "DOUBLE");
props.globals.initNode("/autopilot/target-tracking/min-speed-kt", default_min_speed_kt, "DOUBLE");
props.globals.initNode("/autopilot/target-tracking/target-root", default_target_root, "STRING");
setlistener("/autopilot/target-tracking/enable", func { startTimer();} );
}
# If enabled, update our AP target values based on the target range,
# bearing, and speed
var TrackUpdate = func(loop_id) {
# avoid running multiple concurrent timers
if (tracker_loop_id != loop_id)
return;
if (props.globals.getNode("autopilot") == nil)
return;
target_tracking_enable = getprop("/autopilot/target-tracking/enable");
if ( target_tracking_enable == 1 ) {
update_period = getprop("/autopilot/target-tracking/update-period");
# refresh user configurable values
goal_range_nm = getprop("/autopilot/target-tracking/goal-range-nm");
target_root = getprop("/autopilot/target-tracking/target-root");
min_speed_kt = getprop("/autopilot/target-tracking/min-speed-kt");
# force radar debug-mode on (forced radar calculations even if
# no radar instrument and ai aircraft are out of range
setprop("/instrumentation/radar/debug-mode", 1);
my_hdg_prop = sprintf("/orientation/heading-magnetic-deg" );
my_hdg = getprop(my_hdg_prop);
my_hdg_true_prop = sprintf("/orientation/heading-deg" );
my_hdg_true = getprop(my_hdg_true_prop);
var alt_prop = sprintf("%s/position/altitude-ft", target_root );
var alt = getprop(alt_prop);
if ( alt == nil ) {
print("bad property path: ", alt_prop);
return;
}
var speed_prop = sprintf("%s/velocities/true-airspeed-kt", target_root );
#correct by local IAS/TAS ratio, because autopilot uses IAS
#I need to calculate my TAS, not taking wind into account (MP velocities/true-airspeed-kt does not as well)
var northSpeed = getprop("/velocities/speed-north-fps");
var eastSpeed = getprop("/velocities/speed-east-fps");
var downSpeed = getprop("/velocities/speed-down-fps");
var true_airspeed = FPS2KT * math.sqrt(northSpeed*northSpeed + eastSpeed*eastSpeed + downSpeed*downSpeed);
#take target TAS and multiply it by my own IAS/TAS ratio to get target IAS
var speedTAS = getprop(speed_prop);
if ( speedTAS == nil ) {
print("bad property path: ", speed_prop);
return;
}
var speed = speedTAS * (getprop("/velocities/airspeed-kt") / true_airspeed);
var range_prop = sprintf("%s/radar/range-nm", target_root );
var range = getprop(range_prop);
if ( range == nil ) {
print("bad property path: ", range_prop);
return;
}
var h_offset_prop = sprintf("%s/radar/h-offset", target_root );
var h_offset = getprop(h_offset_prop);
if ( h_offset == nil ) {
print("bad property path: ", h_offset_prop);
return;
}
if ( h_offset > -90 and h_offset < 90 ) {
# in front of us
var range_error = range - goal_range_nm;
} else {
# behind us
var range_error = goal_range_nm - range;
}
var target_speed = speed + range_error * 100.0;
if ( !debug.isnan(target_speed) and target_speed < min_speed_kt ) {
target_speed = min_speed_kt;
}
setprop( "/autopilot/settings/target-altitude-ft", alt );
setprop( "/autopilot/settings/heading-bug-deg", my_hdg + h_offset );
setprop( "/autopilot/settings/true-heading-deg",
my_hdg_true + h_offset );
if( !debug.isnan(target_speed) ) setprop( "/autopilot/settings/target-speed-kt", target_speed ); #isnan check because I divide by TAS before
# only keep the timer running when the feature is really enabled
settimer(func() { TrackUpdate(loop_id); }, update_period );
}
}
# create and start a new timer to cause our update function to be called periodially
startTimer = func {
tracker_loop_id += 1;
TrackUpdate(tracker_loop_id);
}
settimer(TrackInit, 0);