]> git.mxchange.org Git - flightgear.git/blobdiff - src/FDM/JSBSim/FGLGear.cpp
Make yasim accept the launchbar and hook properties. They are not tied to anything...
[flightgear.git] / src / FDM / JSBSim / FGLGear.cpp
index 4826990ded172d84f4956ca4a4c7fdaa820ff9f1..22836a86ddbc978ebebd0599080fada2de1fdc1f 100644 (file)
@@ -39,7 +39,8 @@ INCLUDES
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
 
 #include "FGLGear.h"
-#include <algorithm>
+
+namespace JSBSim {
 
 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 DEFINITIONS
@@ -49,7 +50,6 @@ DEFINITIONS
 GLOBAL DATA
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
 
-
 static const char *IdSrc = "$Id$";
 static const char *IdHdr = ID_LGEAR;
 
@@ -57,35 +57,16 @@ static const char *IdHdr = ID_LGEAR;
 CLASS IMPLEMENTATION
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
 
-FGLGear::FGLGear(FGConfigFile* AC_cfg, FGFDMExec* fdmex) : vXYZ(3),
-                                                           vMoment(3),
-                                                           vWhlBodyVec(3),
-                                                           vForce(3),
-                                                           vLocalForce(3),
-                                                           vWhlVelVec(3),
-                                                           Exec(fdmex)
+FGLGear::FGLGear(FGConfigFile* AC_cfg, FGFDMExec* fdmex, int number) : Exec(fdmex)
 {
   string tmp;
-  string Retractable;
-  
+
+  GearNumber = number;
+
   *AC_cfg >> tmp >> name >> vXYZ(1) >> vXYZ(2) >> vXYZ(3)
             >> kSpring >> bDamp>> dynamicFCoeff >> staticFCoeff
-                  >> rollingFCoeff >> sSteerType >> sBrakeGroup 
-                     >> maxSteerAngle >> Retractable;
-
-  if (debug_lvl > 0) {
-    cout << "    Name: " << name << endl;
-    cout << "      Location: " << vXYZ << endl;
-    cout << "      Spring Constant:  " << kSpring << endl;
-    cout << "      Damping Constant: " << bDamp << endl;
-    cout << "      Dynamic Friction: " << dynamicFCoeff << endl;
-    cout << "      Static Friction:  " << staticFCoeff << endl;
-    cout << "      Rolling Friction: " << rollingFCoeff << endl;
-    cout << "      Steering Type:    " << sSteerType << endl;
-    cout << "      Grouping:         " << sBrakeGroup << endl;
-    cout << "      Max Steer Angle:  " << maxSteerAngle << endl;
-    cout << "      Retractable:      " << Retractable << endl;
-  }
+                  >> rollingFCoeff >> sSteerType >> sBrakeGroup
+                     >> maxSteerAngle >> sRetractable;
 
   if      (sBrakeGroup == "LEFT"  ) eBrakeGrp = bgLeft;
   else if (sBrakeGroup == "RIGHT" ) eBrakeGrp = bgRight;
@@ -105,50 +86,68 @@ FGLGear::FGLGear(FGConfigFile* AC_cfg, FGFDMExec* fdmex) : vXYZ(3),
     cerr << "Improper steering type specification in config file: "
          << sSteerType << " is undefined." << endl;
   }
-  
-  ifRetractable == "RETRACT" ) {
-    isRetractable=true;
+
+  if ( sRetractable == "RETRACT" ) {
+    isRetractable = true;
   } else  {
-    isRetractable=false;
-  }  
-  
-  GearUp=false; GearDown=true;
+    isRetractable = false;
+  }
+
+  GearUp = false;
+  GearDown = true;
+  Servicable = true;
 
 // Add some AI here to determine if gear is located properly according to its
 // brake group type ??
 
   State       = Exec->GetState();
   Aircraft    = Exec->GetAircraft();
-  Position    = Exec->GetPosition();
-  Rotation    = Exec->GetRotation();
+  Propagate   = Exec->GetPropagate();
+  Auxiliary   = Exec->GetAuxiliary();
   FCS         = Exec->GetFCS();
   MassBalance = Exec->GetMassBalance();
 
-  WOW = lastWOW = false;
+  WOW = lastWOW = true; // should the value be initialized to true?
   ReportEnable = true;
   FirstContact = false;
-  Reported = false;
-  DistanceTraveled = 0.0;
+  StartedGroundRun = false;
+  TakeoffReported = LandingReported = false;
+  LandingDistanceTraveled = TakeoffDistanceTraveled = TakeoffDistanceTraveled50ft = 0.0;
   MaximumStrutForce = MaximumStrutTravel = 0.0;
+  SideForce = RollingForce = 0.0;
   SinkRate = GroundSpeed = 0.0;
 
-  vWhlBodyVec     = (vXYZ - MassBalance->GetXYZcg()) / 12.0;
-  vWhlBodyVec(eX) = -vWhlBodyVec(eX);
-  vWhlBodyVec(eZ) = -vWhlBodyVec(eZ);
+  vWhlBodyVec = MassBalance->StructuralToBody(vXYZ);
 
-  vLocalGear = State->GetTb2l() * vWhlBodyVec;
+  vLocalGear = Propagate->GetTb2l() * vWhlBodyVec;
 
-  if (debug_lvl & 2) cout << "Instantiated: FGLGear" << endl;
+  compressLength  = 0.0;
+  compressSpeed   = 0.0;
+  brakePct        = 0.0;
+  maxCompLen      = 0.0;
+
+  WheelSlip = lastWheelSlip = 0.0;
+
+  compressLength  = 0.0;
+  compressSpeed   = 0.0;
+  brakePct        = 0.0;
+  maxCompLen      = 0.0;
+
+  TirePressureNorm = 1.0;
+
+  Debug(0);
 }
 
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
 FGLGear::FGLGear(const FGLGear& lgear)
 {
+  GearNumber = lgear.GearNumber;
+
   State    = lgear.State;
   Aircraft = lgear.Aircraft;
-  Position = lgear.Position;
-  Rotation = lgear.Rotation;
+  Propagate = lgear.Propagate;
+  Auxiliary = lgear.Auxiliary;
   Exec     = lgear.Exec;
   FCS      = lgear.FCS;
   MassBalance = lgear.MassBalance;
@@ -162,9 +161,14 @@ FGLGear::FGLGear(const FGLGear& lgear)
   lastWOW            = lgear.lastWOW;
   ReportEnable       = lgear.ReportEnable;
   FirstContact       = lgear.FirstContact;
-  DistanceTraveled   = lgear.DistanceTraveled;
+  StartedGroundRun   = lgear.StartedGroundRun;
+  LandingDistanceTraveled   = lgear.LandingDistanceTraveled;
+  TakeoffDistanceTraveled   = lgear.TakeoffDistanceTraveled;
+  TakeoffDistanceTraveled50ft   = lgear.TakeoffDistanceTraveled50ft;
   MaximumStrutForce  = lgear.MaximumStrutForce;
   MaximumStrutTravel = lgear.MaximumStrutTravel;
+  SideForce          = lgear.SideForce;
+  RollingForce       = lgear.RollingForce;
 
   kSpring         = lgear.kSpring;
   bDamp           = lgear.bDamp;
@@ -177,9 +181,11 @@ FGLGear::FGLGear(const FGLGear& lgear)
   maxCompLen      = lgear.maxCompLen;
   SinkRate        = lgear.SinkRate;
   GroundSpeed     = lgear.GroundSpeed;
-  Reported        = lgear.Reported;
+  LandingReported = lgear.LandingReported;
+  TakeoffReported = lgear.TakeoffReported;
   name            = lgear.name;
   sSteerType      = lgear.sSteerType;
+  sRetractable    = lgear.sRetractable;
   eSteerType      = lgear.eSteerType;
   sBrakeGroup     = lgear.sBrakeGroup;
   eBrakeGrp       = lgear.eBrakeGrp;
@@ -187,50 +193,74 @@ FGLGear::FGLGear(const FGLGear& lgear)
   isRetractable   = lgear.isRetractable;
   GearUp          = lgear.GearUp;
   GearDown        = lgear.GearDown;
+  WheelSlip       = lgear.WheelSlip;
+  lastWheelSlip   = lgear.lastWheelSlip;
+  TirePressureNorm = lgear.TirePressureNorm;
+  Servicable      = lgear.Servicable;
 }
 
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
 FGLGear::~FGLGear()
 {
-  if (debug_lvl & 2) cout << "Destroyed:    FGLGear" << endl;
+  Debug(1);
 }
 
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
 FGColumnVector3& FGLGear::Force(void)
 {
+  double SinWheel, CosWheel;
+  double deltaT = State->Getdt()*Aircraft->GetRate();
+
   vForce.InitMatrix();
   vMoment.InitMatrix();
-  if(isRetractable ) {
-    if( FCS->GetGearPos() < 0.01 ) {
-      GearUp=true;GearDown=false;
-     } else if(FCS->GetGearPos() > 0.99) {
-      GearDown=true;GearUp=false;
+
+  if (isRetractable) {
+    if (FCS->GetGearPos() < 0.01) {
+      GearUp   = true;
+      GearDown = false;
+     } else if (FCS->GetGearPos() > 0.99) {
+      GearDown = true;
+      GearUp   = false;
      } else {
-      GearUp=false; GearDown=false;
+      GearUp   = false;
+      GearDown = false;
      }
   } else {
-      GearUp=false; GearDown=true;
-  }         
-      
-  if( GearDown ) {
-    double SteerGain = 0;
-    double SinWheel, CosWheel, SideWhlVel, RollingWhlVel;
-    double RollingForce, SideForce, FCoeff;
-    double WheelSlip;
-
-    vWhlBodyVec     = (vXYZ - MassBalance->GetXYZcg()) / 12.0;
-    vWhlBodyVec(eX) = -vWhlBodyVec(eX);
-    vWhlBodyVec(eZ) = -vWhlBodyVec(eZ);
+      GearUp   = false;
+      GearDown = true;
+  }
+
+  // Compute the steering angle in any case.
+  // Will make shure that animations will look right.
+  switch (eSteerType) {
+  case stSteer:
+    SteerAngle = degtorad * FCS->GetSteerPosDeg(GearNumber);
+    break;
+  case stFixed:
+    SteerAngle = 0.0;
+    break;
+  case stCaster:
+    // Note to Jon: This is not correct for castering gear.  I'll fix it later.
+    SteerAngle = 0.0;
+    break;
+  default:
+    cerr << "Improper steering type membership detected for this gear." << endl;
+    break;
+  }
+
+  if (GearDown) {
+
+    vWhlBodyVec = MassBalance->StructuralToBody(vXYZ);
 
 // vWhlBodyVec now stores the vector from the cg to this wheel
 
-    vLocalGear = State->GetTb2l() * vWhlBodyVec;
+    vLocalGear = Propagate->GetTb2l() * vWhlBodyVec;
 
 // vLocalGear now stores the vector from the cg to the wheel in local coords.
 
-    compressLength = vLocalGear(eZ) - Position->GetDistanceAGL();
+    compressLength = vLocalGear(eZ) - Propagate->GetDistanceAGL();
 
 // The compression length is currently measured in the Z-axis, only, at this time.
 // It should be measured along the strut axis. If the local-frame gear position
@@ -239,7 +269,7 @@ FGColumnVector3& FGLGear::Force(void)
 
     if (compressLength > 0.00) {
 
-      WOW = true;// Weight-On-Wheels is true
+      WOW = true; // Weight-On-Wheels is true
 
 // The next equation should really use the vector to the contact patch of the tire
 // including the strut compression and not vWhlBodyVec.  Will fix this later.
@@ -252,10 +282,8 @@ FGColumnVector3& FGLGear::Force(void)
 // (used for calculating damping force) is found by taking the Z-component of the
 // wheel velocity.
 
-      vWhlVelVec      =  State->GetTb2l() * (Rotation->GetPQR() * vWhlBodyVec);
-
-      vWhlVelVec     +=  Position->GetVel();
-
+      vWhlVelVec      =  Propagate->GetTb2l() * (Propagate->GetPQR() * vWhlBodyVec);
+      vWhlVelVec     +=  Propagate->GetVel();
       compressSpeed   =  vWhlVelVec(eZ);
 
 // If this is the first time the wheel has made contact, remember some values
@@ -264,7 +292,20 @@ FGColumnVector3& FGLGear::Force(void)
       if (!FirstContact) {
         FirstContact  = true;
         SinkRate      =  compressSpeed;
-        GroundSpeed   =  Position->GetVel().Magnitude();
+        GroundSpeed   =  Propagate->GetVel().Magnitude();
+        TakeoffReported = false;
+      }
+
+// If the takeoff run is starting, initialize.
+
+      if ((Propagate->GetVel().Magnitude() > 0.1) &&
+          (FCS->GetBrake(bgLeft) == 0) &&
+          (FCS->GetBrake(bgRight) == 0) &&
+          (FCS->GetThrottlePos(0) == 1) && !StartedGroundRun)
+      {
+        TakeoffDistanceTraveled = 0;
+        TakeoffDistanceTraveled50ft = 0;
+        StartedGroundRun = true;
       }
 
 // The following needs work regarding friction coefficients and braking and
@@ -276,59 +317,39 @@ FGColumnVector3& FGLGear::Force(void)
 
       switch (eBrakeGrp) {
       case bgLeft:
-        SteerGain = -0.10;
-        BrakeFCoeff = rollingFCoeff*(1.0 - FCS->GetBrake(bgLeft)) +
-                                              staticFCoeff*FCS->GetBrake(bgLeft);
+         BrakeFCoeff = ( rollingFCoeff*(1.0 - FCS->GetBrake(bgLeft)) +
+                        staticFCoeff*FCS->GetBrake(bgLeft) );
         break;
       case bgRight:
-        SteerGain = -0.10;
-        BrakeFCoeff = rollingFCoeff*(1.0 - FCS->GetBrake(bgRight)) +
-                                             staticFCoeff*FCS->GetBrake(bgRight);
+        BrakeFCoeff =  ( rollingFCoeff*(1.0 - FCS->GetBrake(bgRight)) +
+                         staticFCoeff*FCS->GetBrake(bgRight) );
         break;
       case bgCenter:
-        SteerGain = -0.10;
-        BrakeFCoeff = rollingFCoeff*(1.0 - FCS->GetBrake(bgCenter)) +
-                                             staticFCoeff*FCS->GetBrake(bgCenter);
+        BrakeFCoeff =  ( rollingFCoeff*(1.0 - FCS->GetBrake(bgCenter)) +
+                         staticFCoeff*FCS->GetBrake(bgCenter) );
         break;
       case bgNose:
-        SteerGain = 0.10;
-        BrakeFCoeff = rollingFCoeff;
+        BrakeFCoeff =  ( rollingFCoeff*(1.0 - FCS->GetBrake(bgCenter)) +
+                         staticFCoeff*FCS->GetBrake(bgCenter) );
         break;
       case bgTail:
-        SteerGain = -0.10;
-        BrakeFCoeff = rollingFCoeff;
+        BrakeFCoeff =  ( rollingFCoeff*(1.0 - FCS->GetBrake(bgCenter)) +
+                         staticFCoeff*FCS->GetBrake(bgCenter) );
         break;
       case bgNone:
-        SteerGain = -0.10;
-        BrakeFCoeff = rollingFCoeff;
+        BrakeFCoeff =  rollingFCoeff;
         break;
       default:
         cerr << "Improper brake group membership detected for this gear." << endl;
         break;
       }
 
-      switch (eSteerType) {
-      case stSteer:
-        SteerAngle = SteerGain*FCS->GetDrPos();
-        break;
-      case stFixed:
-        SteerAngle = 0.0;
-        break;
-      case stCaster:
-// Note to Jon: This is not correct for castering gear.  I'll fix it later.
-        SteerAngle = 0.0;
-        break;
-      default:
-        cerr << "Improper steering type membership detected for this gear." << endl;
-        break;
-      }
-
 // Transform the wheel velocities from the local axis system to the wheel axis system.
 // For now, steering angle is assumed to happen in the Local Z axis,
 // not the strut axis as it should be.  Will fix this later.
 
-      SinWheel      = sin(Rotation->Getpsi() + SteerAngle);
-      CosWheel      = cos(Rotation->Getpsi() + SteerAngle);
+      SinWheel      = sin(Propagate->GetEuler(ePsi) + SteerAngle);
+      CosWheel      = cos(Propagate->GetEuler(ePsi) + SteerAngle);
       RollingWhlVel = vWhlVelVec(eX)*CosWheel + vWhlVelVec(eY)*SinWheel;
       SideWhlVel    = vWhlVelVec(eY)*CosWheel - vWhlVelVec(eX)*SinWheel;
 
@@ -336,27 +357,49 @@ FGColumnVector3& FGLGear::Force(void)
 
       if (RollingWhlVel == 0.0 && SideWhlVel == 0.0) {
         WheelSlip = 0.0;
+      } else if (fabs(RollingWhlVel) < 1.0) {
+        WheelSlip = 0.05*radtodeg*atan2(SideWhlVel, fabs(RollingWhlVel)) + 0.95*WheelSlip;
       } else {
-        WheelSlip = radtodeg*atan2(SideWhlVel, RollingWhlVel);
+        WheelSlip = radtodeg*atan2(SideWhlVel, fabs(RollingWhlVel));
       }
+/*
+      double maxdeltaSlip = 0.5*deltaT;
 
-// The following code normalizes the wheel velocity vector, reverses it, and zeroes out
-// the z component of the velocity. The question is, should the Z axis velocity be zeroed
-// out first before the normalization takes place or not? Subsequent to that, the Wheel
-// Velocity vector now points as a unit vector backwards and parallel to the wheel
-// velocity vector. It acts AT the wheel.
+      if (RollingWhlVel == 0.0 && SideWhlVel == 0.0) {
+        WheelSlip = 0.0;
+      } else if (RollingWhlVel < 1.0) {
+        WheelSlip = radtodeg*atan2(SideWhlVel, RollingWhlVel);
+        deltaSlip = WheelSlip - lastWheelSlip;
+        if (fabs(deltaSlip) > maxdeltaSlip) {
+          if (WheelSlip > lastWheelSlip) {
+            WheelSlip = lastWheelSlip + maxdeltaSlip;
+          } else if (WheelSlip < lastWheelSlip) {
+            WheelSlip = lastWheelSlip - maxdeltaSlip;
+          }
+        }
+      } else {
+        WheelSlip = radtodeg*atan2(SideWhlVel, RollingWhlVel);
+      }
 
-// Note to Jon: I commented out this line because I wasn't sure we want to do this.
-//    vWhlVelVec      = -1.0 * vWhlVelVec.Normalize();
-//    vWhlVelVec(eZ)  =  0.00;
+      if ((WheelSlip < 0.0 && lastWheelSlip > 0.0) ||
+          (WheelSlip > 0.0 && lastWheelSlip < 0.0))
+      {
+        WheelSlip = 0.0;
+      }
+*/
+      lastWheelSlip = WheelSlip;
 
 // Compute the sideforce coefficients using similar assumptions to LaRCSim for now.
 // Allow a maximum of 10 degrees tire slip angle before wheel slides.  At that point,
 // transition from static to dynamic friction.  There are more complicated formulations
-// of this that avoid the discrete jump.  Will fix this later.
-
-      if (fabs(WheelSlip) <= 10.0) {
-        FCoeff = staticFCoeff*WheelSlip/10.0;
+// of this that avoid the discrete jump (similar to Pacejka).  Will fix this later.
+
+      if (fabs(WheelSlip) <= 20.0) {
+        FCoeff = staticFCoeff*WheelSlip/20.0;
+      } else if (fabs(WheelSlip) <= 40.0) {
+//        FCoeff = dynamicFCoeff*fabs(WheelSlip)/WheelSlip;
+        FCoeff = (dynamicFCoeff*(fabs(WheelSlip) - 20.0)/20.0 +
+                  staticFCoeff*(40.0 - fabs(WheelSlip))/20.0)*fabs(WheelSlip)/WheelSlip;
       } else {
         FCoeff = dynamicFCoeff*fabs(WheelSlip)/WheelSlip;
       }
@@ -365,7 +408,7 @@ FGColumnVector3& FGLGear::Force(void)
 // in paper AIAA-2000-4303 - see header prologue comments). We might consider
 // allowing for both square and linear damping force calculation. Also need to
 // possibly give a "rebound damping factor" that differs from the compression
-// case. NOTE: SQUARE LAW DAMPING NO GOOD!
+// case.
 
       vLocalForce(eZ) =  min(-compressLength * kSpring
                              - compressSpeed * bDamp, (double)0.0);
@@ -377,7 +420,9 @@ FGColumnVector3& FGLGear::Force(void)
 
       RollingForce = 0;
       if (fabs(RollingWhlVel) > 1E-3) {
-        RollingForce = vLocalForce(eZ) * BrakeFCoeff * fabs(RollingWhlVel)/RollingWhlVel;
+        RollingForce = (1.0 - TirePressureNorm) * 30
+                       + vLocalForce(eZ) * BrakeFCoeff
+                       * fabs(RollingWhlVel)/RollingWhlVel;
       }
       SideForce    = vLocalForce(eZ) * FCoeff;
 
@@ -400,35 +445,46 @@ FGColumnVector3& FGLGear::Force(void)
 
 // Transform the forces back to the body frame and compute the moment.
 
-      vForce  = State->GetTl2b() * vLocalForce;
+      vForce  = Propagate->GetTl2b() * vLocalForce;
       vMoment = vWhlBodyVec * vForce;
 
-    } else {
+    } else { // Gear is NOT compressed
 
       WOW = false;
 
-      if (Position->GetDistanceAGL() > 200.0) {
+      // Return to neutral position between 1.0 and 0.8 gear pos.
+      SteerAngle *= max(FCS->GetGearPos()-0.8, 0.0)/0.2;
+
+      if (Propagate->GetDistanceAGL() > 200.0) {
         FirstContact = false;
-        Reported = false;
-        DistanceTraveled = 0.0;
+        StartedGroundRun = false;
+        LandingReported = false;
+        LandingDistanceTraveled = 0.0;
         MaximumStrutForce = MaximumStrutTravel = 0.0;
       }
 
-      compressLength = 0.0;// reset compressLength to zero for data output validity
+      compressLength = 0.0; // reset compressLength to zero for data output validity
+    }
+
+    if (FirstContact) LandingDistanceTraveled += Auxiliary->GetVground()*deltaT;
 
-      
+    if (StartedGroundRun) {
+       TakeoffDistanceTraveled50ft += Auxiliary->GetVground()*deltaT;
+      if (WOW) TakeoffDistanceTraveled += Auxiliary->GetVground()*deltaT;
     }
 
-    if (FirstContact) {
-      DistanceTraveled += Position->GetVel().Magnitude()*State->Getdt()*Aircraft->GetRate();
+    if (ReportEnable && Auxiliary->GetVground() <= 0.05 && !LandingReported) {
+      if (debug_lvl > 0) Report(erLand);
     }
-  
-    if (ReportEnable && Position->GetVel().Magnitude() <= 0.05 && !Reported) {
-      if (debug_lvl > 0) Report();
+
+    if (ReportEnable && !TakeoffReported &&
+       (vLocalGear(eZ) - Propagate->GetDistanceAGL()) < -50.0)
+    {
+      if (debug_lvl > 0) Report(erTakeoff);
     }
 
     if (lastWOW != WOW) {
-      PutMessage("GEAR_CONTACT", WOW);
+      PutMessage("GEAR_CONTACT: " + name, WOW);
     }
 
     lastWOW = WOW;
@@ -440,37 +496,98 @@ FGColumnVector3& FGLGear::Force(void)
         vMoment.Magnitude() > 5000000000.0 ||
         SinkRate > 1.4666*30)
     {
-      PutMessage("Crash Detected");
+      PutMessage("Crash Detected: Simulation FREEZE.");
       Exec->Freeze();
     }
-
-    
-  } 
-  return vForce; 
+  }
+  return vForce;
 }
 
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
-void FGLGear::Report(void)
+void FGLGear::Report(ReportType repType)
 {
-  cout << endl << "Touchdown report for " << name << endl;
-  cout << "  Sink rate at contact:  " << SinkRate                << " fps,    "
-                              << SinkRate*0.3408          << " mps"     << endl;
-  cout << "  Contact ground speed:  " << GroundSpeed*.5925       << " knots,  "
-                              << GroundSpeed*0.3408       << " mps"     << endl;
-  cout << "  Maximum contact force: " << MaximumStrutForce       << " lbs,    "
-                              << MaximumStrutForce*4.448  << " Newtons" << endl;
-  cout << "  Maximum strut travel:  " << MaximumStrutTravel*12.0 << " inches, "
-                              << MaximumStrutTravel*30.48 << " cm"      << endl;
-  cout << "  Distance traveled:     " << DistanceTraveled        << " ft,     "
-                              << DistanceTraveled*0.3408  << " meters"  << endl;
-  Reported = true;
+  switch(repType) {
+  case erLand:
+    cout << endl << "Touchdown report for " << name << endl;
+    cout << "  Sink rate at contact:  " << SinkRate                << " fps,    "
+                                << SinkRate*0.3048          << " mps"     << endl;
+    cout << "  Contact ground speed:  " << GroundSpeed*.5925       << " knots,  "
+                                << GroundSpeed*0.3048       << " mps"     << endl;
+    cout << "  Maximum contact force: " << MaximumStrutForce       << " lbs,    "
+                                << MaximumStrutForce*4.448  << " Newtons" << endl;
+    cout << "  Maximum strut travel:  " << MaximumStrutTravel*12.0 << " inches, "
+                                << MaximumStrutTravel*30.48 << " cm"      << endl;
+    cout << "  Distance traveled:     " << LandingDistanceTraveled        << " ft,     "
+                                << LandingDistanceTraveled*0.3048  << " meters"  << endl;
+    LandingReported = true;
+    break;
+  case erTakeoff:
+    cout << endl << "Takeoff report for " << name << endl;
+    cout << "  Distance traveled:                " << TakeoffDistanceTraveled
+         << " ft,     " << TakeoffDistanceTraveled*0.3048  << " meters"  << endl;
+    cout << "  Distance traveled (over 50'):     " << TakeoffDistanceTraveled50ft
+         << " ft,     " << TakeoffDistanceTraveled50ft*0.3048 << " meters" << endl;
+    TakeoffReported = true;
+    break;
+  }
 }
 
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGLGear::Debug(void)
+//    The bitmasked value choices are as follows:
+//    unset: In this case (the default) JSBSim would only print
+//       out the normally expected messages, essentially echoing
+//       the config files as they are read. If the environment
+//       variable is not set, debug_lvl is set to 1 internally
+//    0: This requests JSBSim not to output any messages
+//       whatsoever.
+//    1: This value explicity requests the normal JSBSim
+//       startup messages
+//    2: This value asks for a message to be printed out when
+//       a class is instantiated
+//    4: When this value is set, a message is displayed when a
+//       FGModel object executes its Run() method
+//    8: When this value is set, various runtime state variables
+//       are printed out periodically
+//    16: When set various parameters are sanity checked and
+//       a message is printed out when they go out of bounds
+
+void FGLGear::Debug(int from)
 {
-  // TODO: Add user code here
+  if (debug_lvl <= 0) return;
+
+  if (debug_lvl & 1) { // Standard console startup message output
+    if (from == 0) { // Constructor
+      cout << "    Name: "               << name          << endl;
+      cout << "      Location: "         << vXYZ          << endl;
+      cout << "      Spring Constant:  " << kSpring       << endl;
+      cout << "      Damping Constant: " << bDamp         << endl;
+      cout << "      Dynamic Friction: " << dynamicFCoeff << endl;
+      cout << "      Static Friction:  " << staticFCoeff  << endl;
+      cout << "      Rolling Friction: " << rollingFCoeff << endl;
+      cout << "      Steering Type:    " << sSteerType    << endl;
+      cout << "      Grouping:         " << sBrakeGroup   << endl;
+      cout << "      Max Steer Angle:  " << maxSteerAngle << endl;
+      cout << "      Retractable:      " << sRetractable  << endl;
+    }
+  }
+  if (debug_lvl & 2 ) { // Instantiation/Destruction notification
+    if (from == 0) cout << "Instantiated: FGLGear" << endl;
+    if (from == 1) cout << "Destroyed:    FGLGear" << endl;
+  }
+  if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
+  }
+  if (debug_lvl & 8 ) { // Runtime state variables
+  }
+  if (debug_lvl & 16) { // Sanity checking
+  }
+  if (debug_lvl & 64) {
+    if (from == 0) { // Constructor
+      cout << IdSrc << endl;
+      cout << IdHdr << endl;
+    }
+  }
 }
 
+} // namespace JSBSim
+