JSBSim Flight Dynamics Model  1.0 (02 March 2017)
An Open Source Flight Dynamics and Control Software Library in C++
FGTrimAnalysisControl.cpp
1 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2 
3  Header: FGTrimAnalysisControl.cpp
4  Author: Agostino De Marco
5  Date started: Dec/14/2006
6 
7  ------------- Copyright (C) 2006 Agostino De Marco (agodemar@unina.it) -------
8 
9  This program is free software; you can redistribute it and/or modify it under
10  the terms of the GNU Lesser General Public License as published by the Free Software
11  Foundation; either version 2 of the License, or (at your option) any later
12  version.
13 
14  This program is distributed in the hope that it will be useful, but WITHOUT
15  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16  FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
17  details.
18 
19  You should have received a copy of the GNU Lesser General Public License along with
20  this program; if not, write to the Free Software Foundation, Inc., 59 Temple
21  Place - Suite 330, Boston, MA 02111-1307, USA.
22 
23  Further information about the GNU Lesser General Public License can also be found on
24  the world wide web at http://www.gnu.org.
25 
26 
27  HISTORY
28 --------------------------------------------------------------------------------
29 12/14/06 ADM Created
30 
31 
32 FUNCTIONAL DESCRIPTION
33 --------------------------------------------------------------------------------
34 
35 
36 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
37 SENTRY
38 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
39 
40 #ifdef _MSC_VER
41 # pragma warning (disable : 4786)
42 #endif
43 
44 #include <string>
45 #include <stdlib.h>
46 
47 #include "FGFDMExec.h"
48 #include "models/FGAtmosphere.h"
49 #include "initialization/FGInitialCondition.h"
50 #include "FGTrimAnalysisControl.h"
51 #include "models/FGAircraft.h"
52 #include "models/FGPropulsion.h"
53 #include "models/FGAerodynamics.h"
54 
55 namespace JSBSim {
56 
57 IDENT(IdSrc,"$Id: FGTrimAnalysisControl.cpp,v 1.7 2014/01/13 10:46:00 ehofman Exp $");
58 IDENT(IdHdr,ID_TRIMANALYSISCONTROL);
59 
60 /*****************************************************************************/
61 
63  //State st,
64  TaControl ctrl) {
65  fdmex=fdex;
66  fgic=ic;
67  state=taAll;
68  control=ctrl;
69  control_initial_value = 0.;
70  control_value=0;
71  state_convert=1.0;
72  control_convert=1.0;
73  state_value=0;
74  state_target=0;
75  control_tolerance = DEFAULT_TOLERANCE;
76 
77  switch(control) {
78  case taThrottle:
79  control_min=0;
80  control_max=1;
81  control_step=0.2;
82  control_initial_value = 0.5;
83  control_value=control_initial_value;
84  control_name = "Throttle (cmd,norm)";
85  break;
86  case taBeta:
87  control_min=-30*degtorad;
88  control_max=30*degtorad;
89  control_step=1*degtorad;
90  control_convert=radtodeg;
91  break;
92  case taAlpha:
93  control_min=fdmex->GetAerodynamics()->GetAlphaCLMin();
94  control_max=fdmex->GetAerodynamics()->GetAlphaCLMax();
95  if(control_max <= control_min) {
96  control_max=20*degtorad;
97  control_min=-5*degtorad;
98  }
99  control_step=1*degtorad;
100  control_initial_value = (control_min+control_max)/2;
101  control_value= control_initial_value;
102  control_convert=radtodeg;
103  break;
104  case taPitchTrim:
105  control_name = "Pitch Trim (cmd,norm)";
106  control_min=-1;
107  control_max=1;
108  control_step=0.1;
109  state_convert=radtodeg;
110  break;
111  case taElevator:
112  control_name = "Elevator (cmd,norm)";
113  control_min=-1;
114  control_max=1;
115  control_step=0.1;
116  state_convert=radtodeg;
117  break;
118  case taRollTrim:
119  control_name = "Roll Trim (cmd,norm)";
120  control_min=-1;
121  control_max=1;
122  control_step=0.1;
123  state_convert=radtodeg;
124  break;
125  case taAileron:
126  control_name = "Ailerons (cmd,norm)";
127  control_min=-1;
128  control_max=1;
129  control_step=0.1;
130  state_convert=radtodeg;
131  break;
132  case taYawTrim:
133  control_name = "Yaw Trim (cmd,norm)";
134  control_min=-1;
135  control_max=1;
136  control_step=0.1;
137  state_convert=radtodeg;
138  break;
139  case taRudder:
140  control_name = "Rudder (cmd,norm)";
141  control_min=-1;
142  control_max=1;
143  control_step=0.1;
144  state_convert=radtodeg;
145  break;
146  case taAltAGL:
147  control_name = "Altitude (ft)";
148  control_min=0;
149  control_max=30;
150  control_step=2;
151  control_initial_value = fdmex->GetPropagate()->GetDistanceAGL();
152  control_value = control_initial_value;
153  break;
154  case taPhi:
155  control_name = "Phi (rad)";
156  control_min=fdmex->GetPropagate()->GetEuler(ePhi) - 30*degtorad;
157  control_max=fdmex->GetPropagate()->GetEuler(ePhi) + 30*degtorad;
158  control_step=1*degtorad;
159  state_convert=radtodeg;
160  control_convert=radtodeg;
161  break;
162  case taTheta:
163  control_name = "Theta (rad)";
164  control_min=fdmex->GetPropagate()->GetEuler(eTht) - 5*degtorad;
165  control_max=fdmex->GetPropagate()->GetEuler(eTht) + 5*degtorad;
166  control_step=1*degtorad;
167  state_convert=radtodeg;
168  break;
169  case taHeading:
170  control_name = "Heading (rad)";
171  control_min=fdmex->GetPropagate()->GetEuler(ePsi) - 30*degtorad;
172  control_max=fdmex->GetPropagate()->GetEuler(ePsi) + 30*degtorad;
173  control_step=1*degtorad;
174  state_convert=radtodeg;
175  break;
176  case taGamma:
177  control_name = "Gamma (rad)";
178  control_min=-80*degtorad;
179  control_max=80*degtorad;
180  control_step=1*degtorad;
181  control_convert=radtodeg;
182  break;
183  }
184 
185 // if (debug_lvl > 0)
186 // cout << "FGTrimAnalysisControl created: "<< control_name << endl;
187 
188  Debug(0);
189 }
190 
191 /*****************************************************************************/
192 
194 {
195  Debug(1);
196 }
197 
198 /*****************************************************************************/
199 
200 void FGTrimAnalysisControl::getState(void) {
201  switch(state) {
202  case taUdot: state_value=fdmex->GetPropagate()->GetUVWdot(1)-state_target; break;
203  case taVdot: state_value=fdmex->GetPropagate()->GetUVWdot(2)-state_target; break;
204  case taWdot: state_value=fdmex->GetPropagate()->GetUVWdot(3)-state_target; break;
205  case taPdot: state_value=fdmex->GetPropagate()->GetPQRdot(1)-state_target; break;
206  case taQdot: state_value=fdmex->GetPropagate()->GetPQRdot(2)-state_target;break;
207  case taRdot: state_value=fdmex->GetPropagate()->GetPQRdot(3)-state_target; break;
208  case taHmgt: state_value=computeHmgt()-state_target; break;
209  case taNlf: state_value=fdmex->GetAircraft()->GetNlf()-state_target; break;
210  case taAll: break;
211  }
212 }
213 
214 /*****************************************************************************/
215 
216 //States are not settable
217 
218 void FGTrimAnalysisControl::getControl(void) {
219  switch(control) {
220  case taThrottle: control_value=fdmex->GetFCS()->GetThrottleCmd(0); break;
221  case taBeta: control_value=fdmex->GetAuxiliary()->Getbeta(); break;
222  case taAlpha: control_value=fdmex->GetAuxiliary()->Getalpha(); break;
223  case taPitchTrim: control_value=fdmex->GetFCS()->GetPitchTrimCmd(); break;
224  case taElevator: control_value=fdmex->GetFCS()->GetDeCmd(); break;
225  case taRollTrim:
226  case taAileron: control_value=fdmex->GetFCS()->GetDaCmd(); break;
227  case taYawTrim:
228  case taRudder: control_value=fdmex->GetFCS()->GetDrCmd(); break;
229  case taAltAGL: control_value=fdmex->GetPropagate()->GetDistanceAGL();break;
230  case taTheta: control_value=fdmex->GetPropagate()->GetEuler(eTht); break;
231  case taPhi: control_value=fdmex->GetPropagate()->GetEuler(ePhi); break;
232  case taGamma: control_value=fdmex->GetAuxiliary()->GetGamma();break;
233  case taHeading: control_value=fdmex->GetPropagate()->GetEuler(ePsi); break;
234  }
235 }
236 
237 /*****************************************************************************/
238 
239 double FGTrimAnalysisControl::computeHmgt(void) {
240  double diff;
241 
242  diff = fdmex->GetPropagate()->GetEuler(ePsi) -
243  fdmex->GetAuxiliary()->GetGroundTrack();
244 
245  if( diff < -M_PI ) {
246  return (diff + 2*M_PI);
247  } else if( diff > M_PI ) {
248  return (diff - 2*M_PI);
249  } else {
250  return diff;
251  }
252 
253 }
254 
255 /*****************************************************************************/
256 
257 
258 void FGTrimAnalysisControl::setControl(void) {
259  switch(control) {
260  case taThrottle: setThrottlesPct(); break;
261  case taBeta: fgic->SetBetaRadIC(control_value); break;
262  case taAlpha: fgic->SetAlphaRadIC(control_value); break;
263  case taPitchTrim: fdmex->GetFCS()->SetPitchTrimCmd(control_value); break;
264  case taElevator: fdmex->GetFCS()->SetDeCmd(control_value); break;
265  case taRollTrim:
266  case taAileron: fdmex->GetFCS()->SetDaCmd(control_value); break;
267  case taYawTrim:
268  case taRudder: fdmex->GetFCS()->SetDrCmd(control_value); break;
269  case taAltAGL: fgic->SetAltitudeAGLFtIC(control_value); break;
270  case taTheta: fgic->SetThetaRadIC(control_value); break;
271  case taPhi: fgic->SetPhiRadIC(control_value); break;
272  case taGamma: fgic->SetFlightPathAngleRadIC(control_value); break;
273  case taHeading: fgic->SetPsiRadIC(control_value); break;
274  }
275 }
276 
277 
278 
279 
280 
281 /*****************************************************************************/
282 
283 // the aircraft center of rotation is no longer the cg once the gear
284 // contact the ground so the altitude needs to be changed when pitch
285 // and roll angle are adjusted. Instead of attempting to calculate the
286 // new center of rotation, pick a gear unit as a reference and use its
287 // location vector to calculate the new height change. i.e. new altitude =
288 // earth z component of that vector (which is in body axes )
290  int center,i,ref;
291 
292  // favor an off-center unit so that the same one can be used for both
293  // pitch and roll. An on-center unit is used (for pitch)if that's all
294  // that's in contact with the ground.
295  i=0; ref=-1; center=-1;
296  while( (ref < 0) && (i < fdmex->GetGroundReactions()->GetNumGearUnits()) ) {
297  if(fdmex->GetGroundReactions()->GetGearUnit(i)->GetWOW()) {
298  if(fabs(fdmex->GetGroundReactions()->GetGearUnit(i)->GetBodyLocation(2)) > 0.01)
299  ref=i;
300  else
301  center=i;
302  }
303  i++;
304  }
305  if((ref < 0) && (center >= 0)) {
306  ref=center;
307  }
308  cout << "SetThetaOnGround ref gear: " << ref << endl;
309  if(ref >= 0) {
310  double sp = fdmex->GetPropagate()->GetSinEuler(ePhi);
311  double cp = fdmex->GetPropagate()->GetCosEuler(ePhi);
312  double lx = fdmex->GetGroundReactions()->GetGearUnit(ref)->GetBodyLocation(1);
313  double ly = fdmex->GetGroundReactions()->GetGearUnit(ref)->GetBodyLocation(2);
314  double lz = fdmex->GetGroundReactions()->GetGearUnit(ref)->GetBodyLocation(3);
315  double hagl = -1*lx*sin(ff) +
316  ly*sp*cos(ff) +
317  lz*cp*cos(ff);
318 
319  fgic->SetAltitudeAGLFtIC(hagl);
320  cout << "SetThetaOnGround new alt: " << hagl << endl;
321  }
322  fgic->SetThetaRadIC(ff);
323  cout << "SetThetaOnGround new theta: " << ff << endl;
324 }
325 
326 /*****************************************************************************/
327 
329  int i,N;
330  int iForward = 0;
331  int iAft = 1;
332  double zAft,zForward,zDiff,theta;
333  double xAft,xForward,xDiff;
334  bool level;
335  double saveAlt;
336 
337  saveAlt=fgic->GetAltitudeAGLFtIC();
338  fgic->SetAltitudeAGLFtIC(100);
339 
340 
341  N=fdmex->GetGroundReactions()->GetNumGearUnits();
342 
343  //find the first wheel unit forward of the cg
344  //the list is short so a simple linear search is fine
345  for( i=0; i<N; i++ ) {
346  if(fdmex->GetGroundReactions()->GetGearUnit(i)->GetBodyLocation(1) > 0 ) {
347  iForward=i;
348  break;
349  }
350  }
351  //now find the first wheel unit aft of the cg
352  for( i=0; i<N; i++ ) {
353  if(fdmex->GetGroundReactions()->GetGearUnit(i)->GetBodyLocation(1) < 0 ) {
354  iAft=i;
355  break;
356  }
357  }
358 
359  // now adjust theta till the wheels are the same distance from the ground
360  xAft=fdmex->GetGroundReactions()->GetGearUnit(iAft)->GetBodyLocation(1);
361  xForward=fdmex->GetGroundReactions()->GetGearUnit(iForward)->GetBodyLocation(1);
362  xDiff = xForward - xAft;
363  zAft=fdmex->GetGroundReactions()->GetGearUnit(iAft)->GetLocalGear(3);
364  zForward=fdmex->GetGroundReactions()->GetGearUnit(iForward)->GetLocalGear(3);
365  zDiff = zForward - zAft;
366  level=false;
367  theta=fgic->GetThetaDegIC();
368  while(!level && (i < 100)) {
369  theta+=radtodeg*atan(zDiff/xDiff);
370  fgic->SetThetaDegIC(theta);
371  fdmex->SuspendIntegration();
372  fdmex->Initialize(fgic);
373  fdmex->Run();
374  fdmex->ResumeIntegration();
375  zAft=fdmex->GetGroundReactions()->GetGearUnit(iAft)->GetLocalGear(3);
376  zForward=fdmex->GetGroundReactions()->GetGearUnit(iForward)->GetLocalGear(3);
377  zDiff = zForward - zAft;
378  //cout << endl << theta << " " << zDiff << endl;
379  //cout << "0: " << fdmex->GetGroundReactions()->GetGearUnit(0)->GetLocalGear() << endl;
380  //cout << "1: " << fdmex->GetGroundReactions()->GetGearUnit(1)->GetLocalGear() << endl;
381  if(fabs(zDiff ) < 0.1)
382  level=true;
383  i++;
384  }
385  //cout << i << endl;
386  if (debug_lvl > 0) {
387  cout << " Initial Theta: " << fdmex->GetPropagate()->GetEuler(eTht)*radtodeg << endl;
388  cout << " Used gear unit " << iAft << " as aft and " << iForward << " as forward" << endl;
389  }
390  control_min=(theta+5)*degtorad;
391  control_max=(theta-5)*degtorad;
392  fgic->SetAltitudeAGLFtIC(saveAlt);
393  if(i < 100)
394  return true;
395  else
396  return false;
397 }
398 
399 /*****************************************************************************/
400 
402  int i,ref;
403 
404  i=0; ref=-1;
405  //must have an off-center unit here
406  while ( (ref < 0) && (i < fdmex->GetGroundReactions()->GetNumGearUnits()) ) {
407  if ( (fdmex->GetGroundReactions()->GetGearUnit(i)->GetWOW()) &&
408  (fabs(fdmex->GetGroundReactions()->GetGearUnit(i)->GetBodyLocation(2)) > 0.01))
409  ref=i;
410  i++;
411  }
412  if (ref >= 0) {
413  double st = fdmex->GetPropagate()->GetSinEuler(eTht);
414  double ct = fdmex->GetPropagate()->GetCosEuler(eTht);
415  double lx = fdmex->GetGroundReactions()->GetGearUnit(ref)->GetBodyLocation(1);
416  double ly = fdmex->GetGroundReactions()->GetGearUnit(ref)->GetBodyLocation(2);
417  double lz = fdmex->GetGroundReactions()->GetGearUnit(ref)->GetBodyLocation(3);
418  double hagl = -1*lx*st +
419  ly*sin(ff)*ct +
420  lz*cos(ff)*ct;
421 
422  fgic->SetAltitudeAGLFtIC(hagl);
423  }
424  fgic->SetPhiRadIC(ff);
425 
426 }
427 
428 /*****************************************************************************/
429 
431 
432  // ... what's going on here ??
433 }
434 
435 /*****************************************************************************/
436 
437 void FGTrimAnalysisControl::setThrottlesPct(void) {
438  double tMin,tMax;
439  for(unsigned i=0;i<fdmex->GetPropulsion()->GetNumEngines();i++) {
440  tMin=fdmex->GetPropulsion()->GetEngine(i)->GetThrottleMin();
441  tMax=fdmex->GetPropulsion()->GetEngine(i)->GetThrottleMax();
442  //cout << "setThrottlespct: " << i << ", " << control_min << ", " << control_max << ", " << control_value;
443  fdmex->GetFCS()->SetThrottleCmd(i,tMin+control_value*(tMax-tMin));
444  //cout << "setThrottlespct: " << fdmex->GetFCS()->GetThrottleCmd(i) << endl;
445  fdmex->SuspendIntegration();
446  fdmex->Initialize(fgic);
447  fdmex->Run();
448  fdmex->ResumeIntegration();
449  fdmex->GetPropulsion()->GetSteadyState();
450  }
451 }
452 
453 /*****************************************************************************/
454 
455 
456 /*****************************************************************************/
457 // The bitmasked value choices are as follows:
458 // unset: In this case (the default) JSBSim would only print
459 // out the normally expected messages, essentially echoing
460 // the config files as they are read. If the environment
461 // variable is not set, debug_lvl is set to 1 internally
462 // 0: This requests JSBSim not to output any messages
463 // whatsoever.
464 // 1: This value explicity requests the normal JSBSim
465 // startup messages
466 // 2: This value asks for a message to be printed out when
467 // a class is instantiated
468 // 4: When this value is set, a message is displayed when a
469 // FGModel object executes its Run() method
470 // 8: When this value is set, various runtime state variables
471 // are printed out periodically
472 // 16: When set various parameters are sanity checked and
473 // a message is printed out when they go out of bounds
474 
475 void FGTrimAnalysisControl::Debug(int from)
476 {
477 
478  if (debug_lvl <= 0) return;
479  if (debug_lvl & 1 ) { // Standard console startup message output
480  if (from == 0) { // Constructor
481 
482  }
483  }
484  if (debug_lvl & 2 ) { // Instantiation/Destruction notification
485  if (from == 0) cout << "Instantiated: FGTrimAnalysisControl" << endl;
486  if (from == 1) cout << "Destroyed: FGTrimAnalysisControl" << endl;
487  }
488  if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
489  }
490  if (debug_lvl & 8 ) { // Runtime state variables
491  }
492  if (debug_lvl & 16) { // Sanity checking
493  }
494  if (debug_lvl & 64) {
495  if (from == 0) { // Constructor
496  cout << IdSrc << endl;
497  cout << IdHdr << endl;
498  }
499  }
500 }
501 }
void SetThetaDegIC(double theta)
Sets pitch angle initial condition in degrees.
void SetThetaRadIC(double theta)
Sets the initial pitch angle.
double GetThetaDegIC(void) const
Gets the initial pitch angle.
FGColumnVector3 GetBodyLocation(void) const
Gets the location of the gear in Body axes.
Definition: FGLGear.h:245
double GetCosEuler(int idx) const
Retrieves the cosine of a vehicle Euler angle component.
Definition: FGPropagate.h:406
void Run(void)
This function iterates through a call to the FGFDMExec::RunIC() function until the desired trimming c...
double GetDeCmd(void) const
Gets the elevator command.
Definition: FGFCS.h:222
double GetAltitudeAGLFtIC(void) const
Gets the initial altitude above ground level.
void SuspendIntegration(void)
Suspends the simulation and sets the delta T to zero.
Definition: FGFDMExec.h:539
void SetPhiRadIC(double phi)
Sets the initial roll angle.
FGAuxiliary * GetAuxiliary(void)
Returns the FGAuxiliary pointer.
Definition: FGFDMExec.h:371
FGEngine * GetEngine(unsigned int index) const
Retrieves an engine object pointer from the list of engines.
Definition: FGPropulsion.h:140
double GetSinEuler(int idx) const
Retrieves the sine of a vehicle Euler angle component.
Definition: FGPropagate.h:418
void SetThrottleCmd(int engine, double cmd)
Sets the throttle command for the specified engine.
Definition: FGFCS.cpp:323
void SetDaCmd(double cmd)
Sets the aileron command.
Definition: FGFCS.h:379
void SetPhiOnGround(double ff)
Set phi value on ground for trim.
void SetFlightPathAngleRadIC(double gamma)
Sets the initial flight path angle.
void SetPitchTrimCmd(double cmd)
Sets the pitch trim command.
Definition: FGFCS.h:407
void Initialize(FGInitialCondition *FGIC)
Initializes the simulation with initial conditions.
Definition: FGFDMExec.cpp:591
double GetPitchTrimCmd(void) const
Gets the pitch trim command.
Definition: FGFCS.h:270
double GetThrottleCmd(int engine) const
Gets the throttle command.
Definition: FGFCS.cpp:359
bool initTheta(void)
Calculate steady state thetas value on ground.
FGAircraft * GetAircraft(void)
Returns the FGAircraft pointer.
Definition: FGFDMExec.h:367
FGGroundReactions * GetGroundReactions(void)
Returns the FGGroundReactions pointer.
Definition: FGFDMExec.h:361
void SetThetaOnGround(double ff)
Set theta value on ground for trim.
void SetDrCmd(double cmd)
Sets the rudder command.
Definition: FGFCS.h:387
const FGColumnVector3 & GetEuler(void) const
Retrieves the Euler angles that define the vehicle orientation.
Definition: FGPropagate.h:260
void SetDeCmd(double cmd)
Sets the elevator command.
Definition: FGFCS.h:383
void SetAltitudeAGLFtIC(double agl)
Sets the initial Altitude above ground level.
void ResumeIntegration(void)
Resumes the simulation by resetting delta T to the correct value.
Definition: FGFDMExec.h:542
double GetDaCmd(void) const
Gets the aileron command.
Definition: FGFCS.h:218
Initializes the simulation run.
FGFCS * GetFCS(void)
Returns the FGFCS pointer.
Definition: FGFDMExec.h:351
void SetAlphaRadIC(double alpha)
Sets the initial angle of attack.
bool GetSteadyState(void)
Loops the engines until thrust output steady (used for trimming)
FGTrimAnalysisControl(FGFDMExec *fdmex, FGInitialCondition *IC, TaControl control)
Constructor for Trim Analysis Control class.
FGLGear * GetGearUnit(int gear) const
Gets a gear instance.
FGAerodynamics * GetAerodynamics(void)
Returns the FGAerodynamics pointer.
Definition: FGFDMExec.h:357
FGPropulsion * GetPropulsion(void)
Returns the FGPropulsion pointer.
Definition: FGFDMExec.h:353
bool Run(void)
This function executes each scheduled model in succession.
Definition: FGFDMExec.cpp:310
Encapsulates the JSBSim simulation executive.
Definition: FGFDMExec.h:189
void SetBetaRadIC(double beta)
Sets the initial sideslip angle.
double GetDrCmd(void) const
Gets the rudder command.
Definition: FGFCS.h:226
void SetPsiRadIC(double psi)
Sets the initial heading angle.
bool GetWOW(void) const
Gets the Weight On Wheels flag value.
Definition: FGLGear.h:259
FGPropagate * GetPropagate(void)
Returns the FGPropagate pointer.
Definition: FGFDMExec.h:369
unsigned int GetNumEngines(void) const
Retrieves the number of engines defined for the aircraft.
Definition: FGPropulsion.h:134