]> git.mxchange.org Git - flightgear.git/blob - src/Autopilot/newauto.cxx
Autopilot "class-ification".
[flightgear.git] / src / Autopilot / newauto.cxx
1 // newauto.cxx -- autopilot defines and prototypes (very alpha)
2 // 
3 // Started April 1998  Copyright (C) 1998
4 //
5 // Contributions by Jeff Goeke-Smith <jgoeke@voyager.net>
6 //                  Norman Vine <nhv@cape.com>
7 //                  Curtis Olson <curt@flightgear.org>
8 //
9 // This program is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU General Public License as
11 // published by the Free Software Foundation; either version 2 of the
12 // License, or (at your option) any later version.
13 //
14 // This program is distributed in the hope that it will be useful, but
15 // WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 // General Public License for more details.
18 //
19 // You should have received a copy of the GNU General Public License
20 // along with this program; if not, write to the Free Software
21 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 //
23 // $Id$
24
25
26 #ifdef HAVE_CONFIG_H
27 #  include <config.h>
28 #endif
29
30 #include <stdio.h>              // sprintf()
31
32 #include <simgear/constants.h>
33 #include <simgear/debug/logstream.hxx>
34 #include <simgear/math/fg_geodesy.hxx>
35
36 #include <Controls/controls.hxx>
37 #include <FDM/flight.hxx>
38 #include <Main/bfi.hxx>
39 #include <Main/options.hxx>
40 #include <Scenery/scenery.hxx>
41
42 #include "newauto.hxx"
43
44
45 FGAutopilot *current_autopilot;
46
47
48 // Climb speed constants
49 const double min_climb = 70.0;  // kts
50 const double best_climb = 75.0; // kts
51 const double ideal_climb_rate = 500.0; // fpm
52
53 /// These statics will eventually go into the class
54 /// they are just here while I am experimenting -- NHV :-)
55 // AutoPilot Gain Adjuster members
56 static double MaxRollAdjust;        // MaxRollAdjust       = 2 * APData->MaxRoll;
57 static double RollOutAdjust;        // RollOutAdjust       = 2 * APData->RollOut;
58 static double MaxAileronAdjust;     // MaxAileronAdjust    = 2 * APData->MaxAileron;
59 static double RollOutSmoothAdjust;  // RollOutSmoothAdjust = 2 * APData->RollOutSmooth;
60
61 #if 0
62 static float MaxRollValue;          // 0.1 -> 1.0
63 static float RollOutValue;
64 static float MaxAileronValue;
65 static float RollOutSmoothValue;
66
67 static float TmpMaxRollValue;       // for cancel operation
68 static float TmpRollOutValue;
69 static float TmpMaxAileronValue;
70 static float TmpRollOutSmoothValue;
71 #endif
72
73 static char NewTgtAirportId[16];
74 // static char NewTgtAirportLabel[] = "Enter New TgtAirport ID"; 
75
76 extern char *coord_format_lat(float);
77 extern char *coord_format_lon(float);
78                         
79
80 void FGAutopilot::MakeTargetLatLonStr( double lat, double lon ) {
81     sprintf( TargetLatitudeStr , "%s", coord_format_lat(TargetLatitude) );
82     sprintf( TargetLongitudeStr, "%s", coord_format_lon(TargetLongitude) );
83     sprintf( TargetLatLonStr, "%s  %s", TargetLatitudeStr, TargetLongitudeStr );
84 }
85
86
87 void FGAutopilot::MakeTargetAltitudeStr( double altitude ) {
88     sprintf( TargetAltitudeStr, "APAltitude  %6.0f", altitude );
89 }
90
91
92 void FGAutopilot::MakeTargetHeadingStr( double bearing ) {
93     if( bearing < 0. ) {
94         bearing += 360.;
95     } else if (bearing > 360. ) {
96         bearing -= 360.;
97     }
98     sprintf( TargetHeadingStr, "APHeading  %6.1f", bearing );
99 }
100
101
102 void FGAutopilot::update_old_control_values() {
103     old_aileron = FGBFI::getAileron();
104     old_elevator = FGBFI::getElevator();
105     old_elevator_trim = FGBFI::getElevatorTrim();
106     old_rudder = FGBFI::getRudder();
107 }
108
109
110 // Initialize autopilot subsystem
111 void FGAutopilot::init() {
112     FG_LOG( FG_AUTOPILOT, FG_INFO, "Init AutoPilot Subsystem" );
113
114     heading_hold = false ;      // turn the heading hold off
115     altitude_hold = false ;     // turn the altitude hold off
116     auto_throttle = false ;     // turn the auto throttle off
117
118     // Initialize target location to startup location
119     old_lat = TargetLatitude = FGBFI::getLatitude();
120     old_lon = TargetLongitude = FGBFI::getLongitude();
121
122     MakeTargetLatLonStr( TargetLatitude, TargetLongitude);
123         
124     TargetHeading = 0.0;        // default direction, due north
125     TargetAltitude = 3000;      // default altitude in meters
126     alt_error_accum = 0.0;
127
128     MakeTargetAltitudeStr( 3000.0);
129     MakeTargetHeadingStr( 0.0 );
130         
131     // These eventually need to be read from current_aircaft somehow.
132
133     // the maximum roll, in Deg
134     MaxRoll = 20;
135
136     // the deg from heading to start rolling out at, in Deg
137     RollOut = 20;
138
139     // how far can I move the aleron from center.
140     MaxAileron = .2;
141
142     // Smoothing distance for alerion control
143     RollOutSmooth = 10;
144
145     // Hardwired for now should be in options
146     // 25% max control variablilty  0.5 / 2.0
147     disengage_threshold = 1.0;
148
149 #if !defined( USING_SLIDER_CLASS )
150     MaxRollAdjust = 2 * MaxRoll;
151     RollOutAdjust = 2 * RollOut;
152     MaxAileronAdjust = 2 * MaxAileron;
153     RollOutSmoothAdjust = 2 * RollOutSmooth;
154 #endif  // !defined( USING_SLIDER_CLASS )
155
156     update_old_control_values();
157         
158     // Initialize GUI components of autopilot
159     // NewTgtAirportInit();
160     // fgAPAdjustInit() ;
161     // NewHeadingInit();
162     // NewAltitudeInit();
163 };
164
165
166 // Reset the autopilot system
167 void FGAutopilot::reset() {
168
169     heading_hold = false ;      // turn the heading hold off
170     altitude_hold = false ;     // turn the altitude hold off
171     auto_throttle = false ;     // turn the auto throttle off
172
173     TargetHeading = 0.0;        // default direction, due north
174     MakeTargetHeadingStr( TargetHeading );                      
175         
176     TargetAltitude = 3000;   // default altitude in meters
177     MakeTargetAltitudeStr( TargetAltitude );
178         
179     alt_error_accum = 0.0;
180         
181     update_old_control_values();
182
183     sprintf( NewTgtAirportId, "%s", current_options.get_airport_id().c_str() );
184         
185     TargetLatitude = FGBFI::getLatitude();
186     TargetLongitude = FGBFI::getLongitude();
187     MakeTargetLatLonStr( TargetLatitude, TargetLongitude );
188 }
189
190
191 static inline double get_speed( void ) {
192     return( cur_fdm_state->get_V_equiv_kts() );
193 }
194
195 static inline double get_ground_speed() {
196     // starts in ft/s so we convert to kts
197     double ft_s = cur_fdm_state->get_V_ground_speed() 
198         * current_options.get_speed_up();;
199     double kts = ft_s * FEET_TO_METER * 3600 * METER_TO_NM;
200
201     return kts;
202 }
203
204
205 void FGAutopilot::MakeTargetDistanceStr( double distance ) {
206     double eta = distance*METER_TO_NM / get_ground_speed();
207     if ( eta >= 100.0 ) { eta = 99.999; }
208     int major, minor;
209     if ( eta < (1.0/6.0) ) {
210         // within 10 minutes, bump up to min/secs
211         eta *= 60.0;
212     }
213     major = (int)eta;
214     minor = (int)((eta - (int)eta) * 60.0);
215     sprintf( TargetDistanceStr, "APDistance %.2f NM  ETA %d:%02d",
216              distance*METER_TO_NM, major, minor );
217     // cout << "distance = " << distance*METER_TO_NM
218     //      << "  gndsp = " << get_ground_speed() 
219     //      << "  time = " << eta
220     //      << "  major = " << major
221     //      << "  minor = " << minor
222     //      << endl;
223 }
224
225
226 static double NormalizeDegrees( double Input ) {
227     // normalize the input to the range (-180,180]
228     // Input should not be greater than -360 to 360.
229     // Current rules send the output to an undefined state.
230     if ( Input > 180 )
231         while(Input > 180 )
232             Input -= 360;
233     else if ( Input <= -180 )
234         while ( Input <= -180 )
235             Input += 360;
236     return ( Input );
237 };
238
239 static double LinearExtrapolate( double x, double x1, double y1, double x2, double y2 ) {
240     // This procedure extrapolates the y value for the x posistion on a line defined by x1,y1; x2,y2
241     //assert(x1 != x2); // Divide by zero error.  Cold abort for now
242
243         // Could be
244         // static double y = 0.0;
245         // double dx = x2 -x1;
246         // if( (dx < -FG_EPSILON ) || ( dx > FG_EPSILON ) )
247         // {
248
249     double m, b, y;          // the constants to find in y=mx+b
250     // double m, b;
251
252     m = ( y2 - y1 ) / ( x2 - x1 );   // calculate the m
253
254     b = y1 - m * x1;       // calculate the b
255
256     y = m * x + b;       // the final calculation
257
258     // }
259
260     return ( y );
261
262 };
263
264
265 int FGAutopilot::run() {
266     // Remove the following lines when the calling funcitons start
267     // passing in the data pointer
268
269     // get control settings 
270     // double aileron = FGBFI::getAileron();
271     // double elevator = FGBFI::getElevator();
272     // double elevator_trim = FGBFI::getElevatorTrim();
273     // double rudder = FGBFI::getRudder();
274         
275     double lat = FGBFI::getLatitude();
276     double lon = FGBFI::getLongitude();
277
278 #ifdef FG_FORCE_AUTO_DISENGAGE
279     // see if somebody else has changed them
280     if( fabs(aileron - old_aileron) > disengage_threshold ||
281         fabs(elevator - old_elevator) > disengage_threshold ||
282         fabs(elevator_trim - old_elevator_trim) > 
283         disengage_threshold ||          
284         fabs(rudder - old_rudder) > disengage_threshold )
285     {
286         // if controls changed externally turn autopilot off
287         waypoint_hold = false ;   // turn the target hold off
288         heading_hold = false ;    // turn the heading hold off
289         altitude_hold = false ;   // turn the altitude hold off
290         terrain_follow = false;   // turn the terrain_follow hold off
291         // auto_throttle = false; // turn the auto_throttle off
292
293         // stash this runs control settings
294         old_aileron = aileron;
295         old_elevator = elevator;
296         old_elevator_trim = elevator_trim;
297         old_rudder = rudder;
298         
299         return 0;
300     }
301 #endif
302         
303     // heading hold enabled?
304     if ( heading_hold == true ) {
305
306         if ( heading_mode == FG_HEADING_LOCK ) {
307             // leave target heading alone
308         } else if ( heading_mode == FG_HEADING_WAYPOINT ) {
309             // update target heading to waypoint
310
311             double wp_course, wp_reverse, wp_distance;
312
313 #ifdef DO_fgAP_CORRECTED_COURSE
314             // compute course made good
315             // this needs lots of special casing before use
316             double course, reverse, distance, corrected_course;
317             // need to test for iter
318             geo_inverse_wgs_84( 0, //fgAPget_altitude(),
319                                 old_lat,
320                                 old_lon,
321                                 lat,
322                                 lon,
323                                 &course,
324                                 &reverse,
325                                 &distance );
326 #endif // DO_fgAP_CORRECTED_COURSE
327
328             // compute course to way_point
329             // need to test for iter
330             if( ! geo_inverse_wgs_84( 0, //fgAPget_altitude(),
331                                       lat,
332                                       lon,
333                                       TargetLatitude,
334                                       TargetLongitude,
335                                       &wp_course,
336                                       &wp_reverse,
337                                       &wp_distance ) ) {
338                 
339 #ifdef DO_fgAP_CORRECTED_COURSE
340                 corrected_course = course - wp_course;
341                 if( fabs(corrected_course) > 0.1 )
342                     printf("fgAP: course %f  wp_course %f  %f  %f\n",
343                            course, wp_course, fabs(corrected_course),
344                            distance );
345 #endif // DO_fgAP_CORRECTED_COURSE
346                 
347                 if ( wp_distance > 100 ) {
348                     // corrected_course = course - wp_course;
349                     TargetHeading = NormalizeDegrees(wp_course);
350                 } else {
351                     printf("distance(%f) to close\n", wp_distance);
352                     // Real Close -- set heading hold to current heading
353                     // and Ring the arival bell !!
354                     heading_mode = FG_HEADING_LOCK;
355                     // use current heading
356                     TargetHeading = FGBFI::getHeading();
357                 }
358                 MakeTargetHeadingStr( TargetHeading );
359                 // Force this just in case
360                 TargetDistance = wp_distance;
361                 MakeTargetDistanceStr( wp_distance );
362             }
363         }
364
365         double RelHeading;
366         double TargetRoll;
367         double RelRoll;
368         double AileronSet;
369
370         RelHeading = NormalizeDegrees( TargetHeading - FGBFI::getHeading() );
371         // figure out how far off we are from desired heading
372
373         // Now it is time to deterime how far we should be rolled.
374         FG_LOG( FG_AUTOPILOT, FG_DEBUG, "RelHeading: " << RelHeading );
375
376
377         // Check if we are further from heading than the roll out point
378         if ( fabs( RelHeading ) > RollOut ) {
379             // set Target Roll to Max in desired direction
380             if ( RelHeading < 0 ) {
381                 TargetRoll = 0 - MaxRoll;
382             } else {
383                 TargetRoll = MaxRoll;
384             }
385         } else {
386             // We have to calculate the Target roll
387
388             // This calculation engine thinks that the Target roll
389             // should be a line from (RollOut,MaxRoll) to (-RollOut,
390             // -MaxRoll) I hope this works well.  If I get ambitious
391             // some day this might become a fancier curve or
392             // something.
393
394             TargetRoll = LinearExtrapolate( RelHeading, -RollOut,
395                                             -MaxRoll, RollOut,
396                                             MaxRoll );
397         }
398
399         // Target Roll has now been Found.
400
401         // Compare Target roll to Current Roll, Generate Rel Roll
402
403         FG_LOG( FG_COCKPIT, FG_BULK, "TargetRoll: " << TargetRoll );
404
405         RelRoll = NormalizeDegrees( TargetRoll - FGBFI::getRoll() );
406
407         // Check if we are further from heading than the roll out smooth point
408         if ( fabs( RelRoll ) > RollOutSmooth ) {
409             // set Target Roll to Max in desired direction
410             if ( RelRoll < 0 ) {
411                 AileronSet = 0 - MaxAileron;
412             } else {
413                 AileronSet = MaxAileron;
414             }
415         } else {
416             AileronSet = LinearExtrapolate( RelRoll, -RollOutSmooth,
417                                             -MaxAileron,
418                                             RollOutSmooth,
419                                             MaxAileron );
420         }
421
422         controls.set_aileron( AileronSet );
423         controls.set_rudder( AileronSet / 4.0 );
424         // controls.set_rudder( 0.0 );
425     }
426
427     // altitude hold?
428     if ( altitude_hold ) {
429         double speed, max_climb, error;
430         double prop_error, int_error;
431         double prop_adj, int_adj, total_adj;
432
433         if ( altitude_mode == FG_ALTITUDE_LOCK ) {
434             // normal altitude hold
435             // cout << "TargetAltitude = " << TargetAltitude
436             //      << "Altitude = " << FGBFI::getAltitude() * FEET_TO_METER
437             //      << endl;
438             TargetClimbRate =
439                 ( TargetAltitude - FGBFI::getAltitude() * FEET_TO_METER ) * 8.0;
440         } else if ( altitude_mode == FG_ALTITUDE_TERRAIN ) {
441             // brain dead ground hugging with no look ahead
442             TargetClimbRate =
443                 ( TargetAGL - FGBFI::getAGL()*FEET_TO_METER ) * 16.0;
444             // cout << "target agl = " << TargetAGL 
445             //      << "  current agl = " << fgAPget_agl() 
446             //      << "  target climb rate = " << TargetClimbRate 
447             //      << endl;
448         } else {
449             // just try to zero out rate of climb ...
450             TargetClimbRate = 0.0;
451         }
452
453         speed = get_speed();
454
455         if ( speed < min_climb ) {
456             max_climb = 0.0;
457         } else if ( speed < best_climb ) {
458             max_climb = ((best_climb - min_climb) - (best_climb - speed)) 
459                 * ideal_climb_rate 
460                 / (best_climb - min_climb);
461         } else {                        
462             max_climb = ( speed - best_climb ) * 10.0 + ideal_climb_rate;
463         }
464
465         // this first one could be optional if we wanted to allow
466         // better climb performance assuming we have the airspeed to
467         // support it.
468         if ( TargetClimbRate > ideal_climb_rate ) {
469             TargetClimbRate = ideal_climb_rate;
470         }
471
472         if ( TargetClimbRate > max_climb ) {
473             TargetClimbRate = max_climb;
474         }
475
476         if ( TargetClimbRate < -ideal_climb_rate ) {
477             TargetClimbRate = -ideal_climb_rate;
478         }
479
480         error = FGBFI::getVerticalSpeed() * FEET_TO_METER - TargetClimbRate;
481         // cout << "climb rate = " << fgAPget_climb() 
482         //      << "  error = " << error << endl;
483
484         // accumulate the error under the curve ... this really should
485         // be *= delta t
486         alt_error_accum += error;
487
488         // calculate integral error, and adjustment amount
489         int_error = alt_error_accum;
490         // printf("error = %.2f  int_error = %.2f\n", error, int_error);
491         int_adj = int_error / 8000.0;
492
493         // caclulate proportional error
494         prop_error = error;
495         prop_adj = prop_error / 2000.0;
496
497         total_adj = 0.9 * prop_adj + 0.1 * int_adj;
498         // if ( total_adj > 0.6 ) {
499         //     total_adj = 0.6;
500         // } else if ( total_adj < -0.2 ) {
501         //     total_adj = -0.2;
502         // }
503         if ( total_adj > 1.0 ) {
504             total_adj = 1.0;
505         } else if ( total_adj < -1.0 ) {
506             total_adj = -1.0;
507         }
508
509         controls.set_elevator( total_adj );
510     }
511
512     // auto throttle enabled?
513     if ( auto_throttle ) {
514         double error;
515         double prop_error, int_error;
516         double prop_adj, int_adj, total_adj;
517
518         error = TargetSpeed - get_speed();
519
520         // accumulate the error under the curve ... this really should
521         // be *= delta t
522         speed_error_accum += error;
523         if ( speed_error_accum > 2000.0 ) {
524             speed_error_accum = 2000.0;
525         }
526         else if ( speed_error_accum < -2000.0 ) {
527             speed_error_accum = -2000.0;
528         }
529
530         // calculate integral error, and adjustment amount
531         int_error = speed_error_accum;
532
533         // printf("error = %.2f  int_error = %.2f\n", error, int_error);
534         int_adj = int_error / 200.0;
535
536         // caclulate proportional error
537         prop_error = error;
538         prop_adj = 0.5 + prop_error / 50.0;
539
540         total_adj = 0.9 * prop_adj + 0.1 * int_adj;
541         if ( total_adj > 1.0 ) {
542             total_adj = 1.0;
543         }
544         else if ( total_adj < 0.0 ) {
545             total_adj = 0.0;
546         }
547
548         controls.set_throttle( FGControls::ALL_ENGINES, total_adj );
549     }
550
551 #ifdef THIS_CODE_IS_NOT_USED
552     if (Mode == 2) // Glide slope hold
553         {
554             double RelSlope;
555             double RelElevator;
556
557             // First, calculate Relative slope and normalize it
558             RelSlope = NormalizeDegrees( TargetSlope - get_pitch());
559
560             // Now calculate the elevator offset from current angle
561             if ( abs(RelSlope) > SlopeSmooth )
562                 {
563                     if ( RelSlope < 0 )     //  set RelElevator to max in the correct direction
564                         RelElevator = -MaxElevator;
565                     else
566                         RelElevator = MaxElevator;
567                 }
568
569             else
570                 RelElevator = LinearExtrapolate(RelSlope,-SlopeSmooth,-MaxElevator,SlopeSmooth,MaxElevator);
571
572             // set the elevator
573             fgElevMove(RelElevator);
574
575         }
576 #endif // THIS_CODE_IS_NOT_USED
577
578     // stash this runs control settings
579     //  update_old_control_values();
580     old_aileron = controls.get_aileron();
581     old_elevator = controls.get_elevator();
582     old_elevator_trim = controls.get_elevator_trim();
583     old_rudder = controls.get_rudder();
584
585     // for cross track error
586     old_lat = lat;
587     old_lon = lon;
588         
589         // Ok, we are done
590     return 0;
591 }
592
593
594 void FGAutopilot::set_HeadingMode( fgAutoHeadingMode mode ) {
595     heading_mode = mode;
596
597     if ( heading_mode == FG_HEADING_LOCK ) {
598         // set heading hold to current heading
599         TargetHeading = FGBFI::getHeading();
600     } else if ( heading_mode == FG_HEADING_WAYPOINT ) {
601         double course, reverse, distance;
602         // turn on location hold
603         // turn on heading hold
604         old_lat = FGBFI::getLatitude();
605         old_lon = FGBFI::getLongitude();
606                         
607         // need to test for iter
608         if( !geo_inverse_wgs_84( FGBFI::getAltitude() * FEET_TO_METER,
609                                  FGBFI::getLatitude(),
610                                  FGBFI::getLongitude(),
611                                  TargetLatitude,
612                                  TargetLongitude,
613                                  &course,
614                                  &reverse,
615                                  &distance ) ) {
616             TargetHeading = course;
617             TargetDistance = distance;
618             MakeTargetDistanceStr( distance );
619         }
620
621         FG_LOG( FG_COCKPIT, FG_INFO, " fgAPSetLocation: ( "
622                 << TargetLatitude  << " "
623                 << TargetLongitude << " ) "
624                 );
625     }
626         
627     MakeTargetHeadingStr( TargetHeading );                      
628     update_old_control_values();
629 }
630
631
632 void FGAutopilot::set_AltitudeMode( fgAutoAltitudeMode mode ) {
633     altitude_mode = mode;
634
635     if ( altitude_mode == FG_ALTITUDE_LOCK ) {
636         // lock at current altitude
637         TargetAltitude = FGBFI::getAltitude() * FEET_TO_METER;
638         alt_error_accum = 0.0;
639
640         MakeTargetAltitudeStr( TargetAltitude );
641     } else if ( altitude_mode == FG_ALTITUDE_TERRAIN ) {
642         TargetAGL = FGBFI::getAGL() * FEET_TO_METER;
643         alt_error_accum = 0.0;
644     }
645     
646     update_old_control_values();
647     FG_LOG( FG_COCKPIT, FG_INFO, " set_AltitudeMode():" );
648 }
649
650
651 #if 0
652 static inline double get_aoa( void ) {
653     return( cur_fdm_state->get_Gamma_vert_rad() * RAD_TO_DEG );
654 }
655
656 static inline double fgAPget_latitude( void ) {
657     return( cur_fdm_state->get_Latitude() * RAD_TO_DEG );
658 }
659
660 static inline double fgAPget_longitude( void ) {
661     return( cur_fdm_state->get_Longitude() * RAD_TO_DEG );
662 }
663
664 static inline double fgAPget_roll( void ) {
665     return( cur_fdm_state->get_Phi() * RAD_TO_DEG );
666 }
667
668 static inline double get_pitch( void ) {
669     return( cur_fdm_state->get_Theta() );
670 }
671
672 double fgAPget_heading( void ) {
673     return( cur_fdm_state->get_Psi() * RAD_TO_DEG );
674 }
675
676 static inline double fgAPget_altitude( void ) {
677     return( cur_fdm_state->get_Altitude() * FEET_TO_METER );
678 }
679
680 static inline double fgAPget_climb( void ) {
681     // return in meters per minute
682     return( cur_fdm_state->get_Climb_Rate() * FEET_TO_METER * 60 );
683 }
684
685 static inline double get_sideslip( void ) {
686     return( cur_fdm_state->get_Beta() );
687 }
688
689 static inline double fgAPget_agl( void ) {
690     double agl;
691
692     agl = cur_fdm_state->get_Altitude() * FEET_TO_METER
693         - scenery.cur_elev;
694
695     return( agl );
696 }
697 #endif
698
699
700 void FGAutopilot::AltitudeSet( double new_altitude ) {
701     double target_alt = new_altitude;
702
703     // cout << "new altitude = " << new_altitude << endl;
704
705     if ( current_options.get_units() == fgOPTIONS::FG_UNITS_FEET ) {
706         target_alt = new_altitude * FEET_TO_METER;
707     }
708
709     if( target_alt < scenery.cur_elev ) {
710         target_alt = scenery.cur_elev;
711     }
712
713     TargetAltitude = target_alt;
714     altitude_mode = FG_ALTITUDE_LOCK;
715
716     // cout << "TargetAltitude = " << TargetAltitude << endl;
717
718     if ( current_options.get_units() == fgOPTIONS::FG_UNITS_FEET ) {
719         target_alt *= METER_TO_FEET;
720     }
721     // ApAltitudeDialogInput->setValue((float)target_alt);
722     MakeTargetAltitudeStr( target_alt );
723         
724     update_old_control_values();
725 }
726
727
728 void FGAutopilot::AltitudeAdjust( double inc )
729 {
730     double target_alt, target_agl;
731
732     if ( current_options.get_units() == fgOPTIONS::FG_UNITS_FEET ) {
733         target_alt = TargetAltitude * METER_TO_FEET;
734         target_agl = TargetAGL * METER_TO_FEET;
735     } else {
736         target_alt = TargetAltitude;
737         target_agl = TargetAGL;
738     }
739
740     target_alt = ( int ) ( target_alt / inc ) * inc + inc;
741     target_agl = ( int ) ( target_agl / inc ) * inc + inc;
742
743     if ( current_options.get_units() == fgOPTIONS::FG_UNITS_FEET ) {
744         target_alt *= FEET_TO_METER;
745         target_agl *= FEET_TO_METER;
746     }
747
748     TargetAltitude = target_alt;
749     TargetAGL = target_agl;
750         
751     if ( current_options.get_units() == fgOPTIONS::FG_UNITS_FEET )
752         target_alt *= METER_TO_FEET;
753     // ApAltitudeDialogInput->setValue((float)target_alt);
754     MakeTargetAltitudeStr( target_alt );
755
756     update_old_control_values();
757 }
758
759
760 void FGAutopilot::HeadingAdjust( double inc ) {
761     heading_mode = FG_HEADING_LOCK;
762         
763     double target = ( int ) ( TargetHeading / inc ) * inc + inc;
764
765     TargetHeading = NormalizeDegrees( target );
766     // following cast needed ambiguous plib
767     // ApHeadingDialogInput -> setValue ((float)TargetHeading );
768     MakeTargetHeadingStr( TargetHeading );                      
769     update_old_control_values();
770 }
771
772
773 void FGAutopilot::HeadingSet( double new_heading ) {
774     heading_mode = FG_HEADING_LOCK;
775         
776     new_heading = NormalizeDegrees( new_heading );
777     TargetHeading = new_heading;
778     // following cast needed ambiguous plib
779     // ApHeadingDialogInput -> setValue ((float)APData->TargetHeading );
780     MakeTargetHeadingStr( TargetHeading );                      
781     update_old_control_values();
782 }
783
784 void FGAutopilot::AutoThrottleAdjust( double inc ) {
785     double target = ( int ) ( TargetSpeed / inc ) * inc + inc;
786
787     TargetSpeed = target;
788 }
789
790
791 void FGAutopilot::set_AutoThrottleEnabled( bool value ) {
792     auto_throttle = value;
793
794     if ( auto_throttle = true ) {
795         TargetSpeed = FGBFI::getAirspeed();
796         speed_error_accum = 0.0;
797     }
798
799     update_old_control_values();
800     FG_LOG( FG_COCKPIT, FG_INFO, " fgAPSetAutoThrottle: ("
801             << auto_throttle << ") " << TargetSpeed );
802 }