LCOV - code coverage report
Current view: top level - models - FGLGear.cpp (source / functions) Hit Total Coverage
Test: JSBSim-Coverage-Statistics Lines: 2 433 0.5 %
Date: 2010-08-24 Functions: 3 26 11.5 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 6 361 1.7 %

           Branch data     Line data    Source code
       1                 :            : /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
       2                 :            : 
       3                 :            :  Module:       FGLGear.cpp
       4                 :            :  Author:       Jon S. Berndt
       5                 :            :                Norman H. Princen
       6                 :            :                Bertrand Coconnier
       7                 :            :  Date started: 11/18/99
       8                 :            :  Purpose:      Encapsulates the landing gear elements
       9                 :            :  Called by:    FGAircraft
      10                 :            : 
      11                 :            :  ------------- Copyright (C) 1999  Jon S. Berndt (jon@jsbsim.org) -------------
      12                 :            : 
      13                 :            :  This program is free software; you can redistribute it and/or modify it under
      14                 :            :  the terms of the GNU Lesser General Public License as published by the Free Software
      15                 :            :  Foundation; either version 2 of the License, or (at your option) any later
      16                 :            :  version.
      17                 :            : 
      18                 :            :  This program is distributed in the hope that it will be useful, but WITHOUT
      19                 :            :  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
      20                 :            :  FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
      21                 :            :  details.
      22                 :            : 
      23                 :            :  You should have received a copy of the GNU Lesser General Public License along with
      24                 :            :  this program; if not, write to the Free Software Foundation, Inc., 59 Temple
      25                 :            :  Place - Suite 330, Boston, MA  02111-1307, USA.
      26                 :            : 
      27                 :            :  Further information about the GNU Lesser General Public License can also be found on
      28                 :            :  the world wide web at http://www.gnu.org.
      29                 :            : 
      30                 :            : FUNCTIONAL DESCRIPTION
      31                 :            : --------------------------------------------------------------------------------
      32                 :            : 
      33                 :            : HISTORY
      34                 :            : --------------------------------------------------------------------------------
      35                 :            : 11/18/99   JSB   Created
      36                 :            : 01/30/01   NHP   Extended gear model to properly simulate steering and braking
      37                 :            : 07/08/09   BC    Modified gear model to support large angles between aircraft and ground
      38                 :            : 
      39                 :            : /%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      40                 :            : INCLUDES
      41                 :            : %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
      42                 :            : 
      43                 :            : #include "FGLGear.h"
      44                 :            : #include "FGGroundReactions.h"
      45                 :            : #include "FGFCS.h"
      46                 :            : #include "FGAuxiliary.h"
      47                 :            : #include "FGAtmosphere.h"
      48                 :            : #include "FGMassBalance.h"
      49                 :            : #include "math/FGTable.h"
      50                 :            : #include <cstdlib>
      51                 :            : 
      52                 :            : using namespace std;
      53                 :            : 
      54                 :            : namespace JSBSim {
      55                 :            : 
      56                 :            : /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      57                 :            : DEFINITIONS
      58                 :            : %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
      59                 :            : 
      60                 :            : /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      61                 :            : GLOBAL DATA
      62                 :            : %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
      63                 :            : 
      64                 :            : static const char *IdSrc = "$Id: FGLGear.cpp,v 1.76 2010/07/30 11:50:01 jberndt Exp $";
      65                 :            : static const char *IdHdr = ID_LGEAR;
      66                 :            : 
      67                 :            : // Body To Structural (body frame is rotated 180 deg about Y and lengths are given in
      68                 :            : // ft instead of inches)
      69 [ +  + ][ +  - ]:          4 : const FGMatrix33 FGLGear::Tb2s(-1./inchtoft, 0., 0., 0., 1./inchtoft, 0., 0., 0., -1./inchtoft);
      70                 :            : 
      71                 :            : /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      72                 :            : CLASS IMPLEMENTATION
      73                 :            : %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
      74                 :            : 
      75                 :          0 : FGLGear::FGLGear(Element* el, FGFDMExec* fdmex, int number) :
      76                 :            :   FGForce(fdmex),
      77                 :            :   GearNumber(number),
      78                 :            :   SteerAngle(0.0),
      79 [ #  # ][ #  # ]:          0 :   Castered(false)
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
      80                 :            : {
      81                 :          0 :   Element *force_table=0;
      82                 :          0 :   Element *dampCoeff=0;
      83                 :          0 :   Element *dampCoeffRebound=0;
      84                 :          0 :   string force_type="";
      85                 :            : 
      86                 :          0 :   kSpring = bDamp = bDampRebound = dynamicFCoeff = staticFCoeff = rollingFCoeff = maxSteerAngle = 0;
      87                 :          0 :   sSteerType = sBrakeGroup = sSteerType = "";
      88                 :          0 :   isRetractable = 0;
      89                 :          0 :   eDampType = dtLinear;
      90                 :          0 :   eDampTypeRebound = dtLinear;
      91                 :            : 
      92                 :          0 :   name = el->GetAttributeValue("name");
      93                 :          0 :   sContactType = el->GetAttributeValue("type");
      94   [ #  #  #  # ]:          0 :   if (sContactType == "BOGEY") {
      95                 :          0 :     eContactType = ctBOGEY;
      96 [ #  # ][ #  # ]:          0 :   } else if (sContactType == "STRUCTURE") {
      97                 :          0 :     eContactType = ctSTRUCTURE;
      98                 :            :   } else {
      99                 :            :     // Unknown contact point types will be treated as STRUCTURE.
     100                 :          0 :     eContactType = ctSTRUCTURE;
     101                 :            :   }
     102                 :            : 
     103 [ #  # ][ #  # ]:          0 :   if (el->FindElement("spring_coeff"))
     104                 :          0 :     kSpring = el->FindElementValueAsNumberConvertTo("spring_coeff", "LBS/FT");
     105 [ #  # ][ #  # ]:          0 :   if (el->FindElement("damping_coeff")) {
     106                 :          0 :     dampCoeff = el->FindElement("damping_coeff");
     107 [ #  # ][ #  # ]:          0 :     if (dampCoeff->GetAttributeValue("type") == "SQUARE") {
     108                 :          0 :       eDampType = dtSquare;
     109                 :          0 :       bDamp   = el->FindElementValueAsNumberConvertTo("damping_coeff", "LBS/FT2/SEC2");
     110                 :            :     } else {
     111                 :          0 :       bDamp   = el->FindElementValueAsNumberConvertTo("damping_coeff", "LBS/FT/SEC");
     112                 :            :     }
     113                 :            :   }
     114                 :            : 
     115 [ #  # ][ #  # ]:          0 :   if (el->FindElement("damping_coeff_rebound")) {
     116                 :          0 :     dampCoeffRebound = el->FindElement("damping_coeff_rebound");
     117 [ #  # ][ #  # ]:          0 :     if (dampCoeffRebound->GetAttributeValue("type") == "SQUARE") {
     118                 :          0 :       eDampTypeRebound = dtSquare;
     119                 :          0 :       bDampRebound   = el->FindElementValueAsNumberConvertTo("damping_coeff_rebound", "LBS/FT2/SEC2");
     120                 :            :     } else {
     121                 :          0 :       bDampRebound   = el->FindElementValueAsNumberConvertTo("damping_coeff_rebound", "LBS/FT/SEC");
     122                 :            :     }
     123                 :            :   } else {
     124                 :          0 :     bDampRebound   = bDamp;
     125                 :          0 :     eDampTypeRebound = eDampType;
     126                 :            :   }
     127                 :            : 
     128 [ #  # ][ #  # ]:          0 :   if (el->FindElement("dynamic_friction"))
     129                 :          0 :     dynamicFCoeff = el->FindElementValueAsNumber("dynamic_friction");
     130 [ #  # ][ #  # ]:          0 :   if (el->FindElement("static_friction"))
     131                 :          0 :     staticFCoeff = el->FindElementValueAsNumber("static_friction");
     132 [ #  # ][ #  # ]:          0 :   if (el->FindElement("rolling_friction"))
     133                 :          0 :     rollingFCoeff = el->FindElementValueAsNumber("rolling_friction");
     134 [ #  # ][ #  # ]:          0 :   if (el->FindElement("max_steer"))
     135                 :          0 :     maxSteerAngle = el->FindElementValueAsNumberConvertTo("max_steer", "DEG");
     136 [ #  # ][ #  # ]:          0 :   if (el->FindElement("retractable"))
     137                 :          0 :     isRetractable = ((unsigned int)el->FindElementValueAsNumber("retractable"))>0.0?true:false;
     138                 :            : 
     139                 :          0 :   ForceY_Table = 0;
     140                 :          0 :   force_table = el->FindElement("table");
     141 [ #  # ][ #  # ]:          0 :   while (force_table) {
     142                 :          0 :     force_type = force_table->GetAttributeValue("type");
     143   [ #  #  #  # ]:          0 :     if (force_type == "CORNERING_COEFF") {
     144                 :          0 :       ForceY_Table = new FGTable(fdmex->GetPropertyManager(), force_table);
     145                 :            :     } else {
     146                 :          0 :       cerr << "Undefined force table for " << name << " contact point" << endl;
     147                 :            :     }
     148                 :          0 :     force_table = el->FindNextElement("table");
     149                 :            :   }
     150                 :            : 
     151                 :          0 :   sBrakeGroup = el->FindElementValue("brake_group");
     152                 :            : 
     153   [ #  #  #  # ]:          0 :   if (maxSteerAngle == 360) sSteerType = "CASTERED";
     154 [ #  # ][ #  # ]:          0 :   else if (maxSteerAngle == 0.0) sSteerType = "FIXED";
     155                 :          0 :   else sSteerType = "STEERABLE";
     156                 :            : 
     157                 :          0 :   Element* element = el->FindElement("location");
     158 [ #  # ][ #  # ]:          0 :   if (element) vXYZn = element->FindElementTripletConvertTo("IN");
     159                 :          0 :   else {cerr << "No location given for contact " << name << endl; exit(-1);}
     160                 :          0 :   SetTransformType(FGForce::tCustom);
     161                 :            : 
     162                 :          0 :   element = el->FindElement("orientation");
     163         [ #  # ]:          0 :   if (element && (eContactType == ctBOGEY)) {
           [ #  #  #  # ]
                 [ #  # ]
     164                 :          0 :     vGearOrient = element->FindElementTripletConvertTo("RAD");
     165                 :            : 
     166                 :            :     double cp,sp,cr,sr,cy,sy;
     167                 :            : 
     168                 :          0 :     cp=cos(vGearOrient(ePitch)); sp=sin(vGearOrient(ePitch));
     169                 :          0 :     cr=cos(vGearOrient(eRoll));  sr=sin(vGearOrient(eRoll));
     170                 :          0 :     cy=cos(vGearOrient(eYaw));   sy=sin(vGearOrient(eYaw));
     171                 :            : 
     172                 :          0 :     mTGear(1,1) =  cp*cy;
     173                 :          0 :     mTGear(2,1) =  cp*sy;
     174                 :          0 :     mTGear(3,1) = -sp;
     175                 :            : 
     176                 :          0 :     mTGear(1,2) = sr*sp*cy - cr*sy;
     177                 :          0 :     mTGear(2,2) = sr*sp*sy + cr*cy;
     178                 :          0 :     mTGear(3,2) = sr*cp;
     179                 :            : 
     180                 :          0 :     mTGear(1,3) = cr*sp*cy + sr*sy;
     181                 :          0 :     mTGear(2,3) = cr*sp*sy - sr*cy;
     182                 :          0 :     mTGear(3,3) = cr*cp;
     183                 :            :   }
     184                 :            :   else {
     185                 :          0 :     mTGear(1,1) = 1.;
     186                 :          0 :     mTGear(2,2) = 1.;
     187                 :          0 :     mTGear(3,3) = 1.;
     188                 :            :   }
     189                 :            : 
     190 [ #  # ][ #  # ]:          0 :   if      (sBrakeGroup == "LEFT"  ) eBrakeGrp = bgLeft;
     191 [ #  # ][ #  # ]:          0 :   else if (sBrakeGroup == "RIGHT" ) eBrakeGrp = bgRight;
     192 [ #  # ][ #  # ]:          0 :   else if (sBrakeGroup == "CENTER") eBrakeGrp = bgCenter;
     193 [ #  # ][ #  # ]:          0 :   else if (sBrakeGroup == "NOSE"  ) eBrakeGrp = bgNose;
     194 [ #  # ][ #  # ]:          0 :   else if (sBrakeGroup == "TAIL"  ) eBrakeGrp = bgTail;
     195 [ #  # ][ #  # ]:          0 :   else if (sBrakeGroup == "NONE"  ) eBrakeGrp = bgNone;
     196 [ #  # ][ #  # ]:          0 :   else if (sBrakeGroup.empty()    ) {eBrakeGrp = bgNone;
     197                 :          0 :                                      sBrakeGroup = "NONE (defaulted)";}
     198                 :            :   else {
     199                 :            :     cerr << "Improper braking group specification in config file: "
     200                 :          0 :          << sBrakeGroup << " is undefined." << endl;
     201                 :            :   }
     202                 :            : 
     203 [ #  # ][ #  # ]:          0 :   if      (sSteerType == "STEERABLE") eSteerType = stSteer;
     204 [ #  # ][ #  # ]:          0 :   else if (sSteerType == "FIXED"    ) eSteerType = stFixed;
     205 [ #  # ][ #  # ]:          0 :   else if (sSteerType == "CASTERED" ) {eSteerType = stCaster; Castered = true;}
     206 [ #  # ][ #  # ]:          0 :   else if (sSteerType.empty()       ) {eSteerType = stFixed;
     207                 :          0 :                                        sSteerType = "FIXED (defaulted)";}
     208                 :            :   else {
     209                 :            :     cerr << "Improper steering type specification in config file: "
     210                 :          0 :          << sSteerType << " is undefined." << endl;
     211                 :            :   }
     212                 :            : 
     213                 :          0 :   Auxiliary       = fdmex->GetAuxiliary();
     214                 :          0 :   Propagate       = fdmex->GetPropagate();
     215                 :          0 :   FCS             = fdmex->GetFCS();
     216                 :          0 :   MassBalance     = fdmex->GetMassBalance();
     217                 :          0 :   GroundReactions = fdmex->GetGroundReactions();
     218                 :            : 
     219                 :          0 :   GearUp = false;
     220                 :          0 :   GearDown = true;
     221                 :          0 :   GearPos  = 1.0;
     222                 :          0 :   useFCSGearPos = false;
     223                 :          0 :   Servicable = true;
     224                 :            : 
     225                 :            : // Add some AI here to determine if gear is located properly according to its
     226                 :            : // brake group type ??
     227                 :            : 
     228                 :          0 :   WOW = lastWOW = false;
     229                 :          0 :   ReportEnable = true;
     230                 :          0 :   FirstContact = false;
     231                 :          0 :   StartedGroundRun = false;
     232                 :          0 :   TakeoffReported = LandingReported = false;
     233                 :          0 :   LandingDistanceTraveled = TakeoffDistanceTraveled = TakeoffDistanceTraveled50ft = 0.0;
     234                 :          0 :   MaximumStrutForce = MaximumStrutTravel = 0.0;
     235                 :          0 :   SinkRate = GroundSpeed = 0.0;
     236                 :            : 
     237                 :          0 :   vWhlBodyVec = MassBalance->StructuralToBody(vXYZn);
     238                 :          0 :   vLocalGear = Propagate->GetTb2l() * vWhlBodyVec;
     239                 :          0 :   vWhlVelVec.InitMatrix();
     240                 :            : 
     241                 :          0 :   compressLength  = 0.0;
     242                 :          0 :   compressSpeed   = 0.0;
     243                 :          0 :   brakePct        = 0.0;
     244                 :          0 :   maxCompLen      = 0.0;
     245                 :            : 
     246                 :          0 :   WheelSlip = 0.0;
     247                 :          0 :   TirePressureNorm = 1.0;
     248                 :            : 
     249                 :            :   // Set Pacejka terms
     250                 :            : 
     251                 :          0 :   Stiffness = 0.06;
     252                 :          0 :   Shape = 2.8;
     253                 :          0 :   Peak = staticFCoeff;
     254                 :          0 :   Curvature = 1.03;
     255                 :            : 
     256                 :            :   // Initialize Lagrange multipliers
     257                 :          0 :   LMultiplier[ftRoll].value = 0.;
     258                 :          0 :   LMultiplier[ftSide].value = 0.;
     259                 :          0 :   LMultiplier[ftRoll].value = 0.;
     260                 :            : 
     261                 :          0 :   Debug(0);
     262 [ #  # ][ #  # ]:          0 : }
         [ #  # ][ #  # ]
     263                 :            : 
     264                 :            : //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     265                 :            : 
     266                 :          0 : FGLGear::~FGLGear()
     267                 :            : {
     268 [ #  # ][ #  # ]:          0 :   delete ForceY_Table;
     269                 :          0 :   Debug(1);
     270         [ #  # ]:          0 : }
           [ #  #  #  # ]
         [ #  # ][ #  # ]
           [ #  #  #  # ]
                 [ #  # ]
     271                 :            : 
     272                 :            : //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     273                 :            : 
     274                 :          0 : FGColumnVector3& FGLGear::GetBodyForces(void)
     275                 :            : {
     276                 :          0 :   double t = fdmex->GetSimTime();
     277                 :          0 :   dT = fdmex->GetDeltaT()*GroundReactions->GetRate();
     278                 :            : 
     279                 :          0 :   vFn.InitMatrix();
     280                 :            : 
     281         [ #  # ]:          0 :   if (isRetractable) ComputeRetractionState();
     282                 :            : 
     283         [ #  # ]:          0 :   if (GearDown) {
     284                 :          0 :     vWhlBodyVec = MassBalance->StructuralToBody(vXYZn); // Get wheel in body frame
     285                 :          0 :     vLocalGear = Propagate->GetTb2l() * vWhlBodyVec; // Get local frame wheel location
     286                 :            : 
     287                 :          0 :     gearLoc = Propagate->GetLocation().LocalToLocation(vLocalGear);
     288                 :            :     // Compute the height of the theoretical location of the wheel (if strut is
     289                 :            :     // not compressed) with respect to the ground level
     290                 :          0 :     double height = fdmex->GetGroundCallback()->GetAGLevel(t, gearLoc, contact, normal, cvel);
     291                 :          0 :     vGroundNormal = Propagate->GetTec2b() * normal;
     292                 :            : 
     293                 :            :     // The height returned above is the AGL and is expressed in the Z direction
     294                 :            :     // of the ECEF coordinate frame. We now need to transform this height in
     295                 :            :     // actual compression of the strut (BOGEY) of in the normal direction to the
     296                 :            :     // ground (STRUCTURE)
     297                 :          0 :     double normalZ = (Propagate->GetTec2l()*normal)(eZ);
     298                 :          0 :     double LGearProj = -(mTGear.Transposed() * vGroundNormal)(eZ);
     299                 :            : 
     300      [ #  #  # ]:          0 :     switch (eContactType) {
     301                 :            :     case ctBOGEY:
     302         [ #  # ]:          0 :       compressLength = LGearProj > 0.0 ? height * normalZ / LGearProj : 0.0;
     303                 :          0 :       break;
     304                 :            :     case ctSTRUCTURE:
     305                 :          0 :       compressLength = height * normalZ / DotProduct(normal, normal);
     306                 :            :       break;
     307                 :            :     }
     308                 :            : 
     309         [ #  # ]:          0 :     if (compressLength > 0.00) {
     310                 :            : 
     311                 :          0 :       WOW = true;
     312                 :            : 
     313                 :            :       // The following equations use the vector to the tire contact patch
     314                 :            :       // including the strut compression.
     315                 :          0 :       FGColumnVector3 vWhlDisplVec;
     316                 :            : 
     317      [ #  #  # ]:          0 :       switch(eContactType) {
     318                 :            :       case ctBOGEY:
     319                 :          0 :         vWhlDisplVec = mTGear * FGColumnVector3(0., 0., -compressLength);
     320                 :            :         break;
     321                 :            :       case ctSTRUCTURE:
     322                 :          0 :         vWhlDisplVec = compressLength * vGroundNormal;
     323                 :            :         break;
     324                 :            :       }
     325                 :            : 
     326                 :          0 :       FGColumnVector3 vWhlContactVec = vWhlBodyVec + vWhlDisplVec;
     327                 :          0 :       vActingXYZn = vXYZn + Tb2s * vWhlDisplVec;
     328                 :          0 :       FGColumnVector3 vBodyWhlVel = Propagate->GetPQR() * vWhlContactVec;
     329                 :          0 :       vBodyWhlVel += Propagate->GetUVW() - Propagate->GetTec2b() * cvel;
     330                 :            : 
     331                 :          0 :       vWhlVelVec = mTGear.Transposed() * vBodyWhlVel;
     332                 :            : 
     333                 :          0 :       InitializeReporting();
     334                 :          0 :       ComputeSteeringAngle();
     335                 :          0 :       ComputeGroundCoordSys();
     336                 :            : 
     337                 :          0 :       vLocalWhlVel = Transform().Transposed() * vBodyWhlVel;
     338                 :            : 
     339                 :          0 :       compressSpeed = -vLocalWhlVel(eX);
     340         [ #  # ]:          0 :       if (eContactType == ctBOGEY)
     341                 :          0 :         compressSpeed /= LGearProj;
     342                 :            : 
     343                 :          0 :       ComputeVerticalStrutForce();
     344                 :            : 
     345                 :            :       // Compute the friction coefficients in the wheel ground plane.
     346         [ #  # ]:          0 :       if (eContactType == ctBOGEY) {
     347                 :          0 :         ComputeSlipAngle();
     348                 :          0 :         ComputeBrakeForceCoefficient();
     349                 :          0 :         ComputeSideForceCoefficient();
     350                 :            :       }
     351                 :            : 
     352                 :            :       // Prepare the Jacobians and the Lagrange multipliers for later friction
     353                 :            :       // forces calculations.
     354                 :          0 :       ComputeJacobian(vWhlContactVec);
     355                 :            : 
     356                 :            :     } else { // Gear is NOT compressed
     357                 :            : 
     358                 :          0 :       WOW = false;
     359                 :          0 :       compressLength = 0.0;
     360                 :          0 :       compressSpeed = 0.0;
     361                 :          0 :       WheelSlip = 0.0;
     362                 :          0 :       StrutForce = 0.0;
     363                 :            : 
     364                 :            :       // Let wheel spin down slowly
     365                 :          0 :       vWhlVelVec(eX) -= 13.0*dT;
     366         [ #  # ]:          0 :       if (vWhlVelVec(eX) < 0.0) vWhlVelVec(eX) = 0.0;
     367                 :            : 
     368                 :            :       // Return to neutral position between 1.0 and 0.8 gear pos.
     369                 :          0 :       SteerAngle *= max(GetGearUnitPos()-0.8, 0.0)/0.2;
     370                 :            : 
     371                 :          0 :       ResetReporting();
     372                 :            :     }
     373                 :            :   }
     374                 :            : 
     375                 :          0 :   ReportTakeoffOrLanding();
     376                 :            : 
     377                 :            :   // Require both WOW and LastWOW to be true before checking crash conditions
     378                 :            :   // to allow the WOW flag to be used in terminating a scripted run.
     379 [ #  # ][ #  # ]:          0 :   if (WOW && lastWOW) CrashDetect();
     380                 :            : 
     381                 :          0 :   lastWOW = WOW;
     382                 :            : 
     383                 :          0 :   return FGForce::GetBodyForces();
     384                 :            : }
     385                 :            : 
     386                 :            : //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     387                 :            : // Build a local "ground" coordinate system defined by
     388                 :            : //  eX : normal to the ground
     389                 :            : //  eY : projection of the rolling direction on the ground
     390                 :            : //  eZ : projection of the sliping direction on the ground
     391                 :            : 
     392                 :          0 : void FGLGear::ComputeGroundCoordSys(void)
     393                 :            : {
     394                 :            :   // Euler angles are built up to create a local frame to describe the forces
     395                 :            :   // applied to the gear by the ground. Here pitch, yaw and roll do not have
     396                 :            :   // any physical meaning. It is just a convenient notation.
     397                 :            :   // First, "pitch" and "yaw" are determined in order to align eX with the
     398                 :            :   // ground normal.
     399         [ #  # ]:          0 :   if (vGroundNormal(eZ) < -1.0)
     400                 :          0 :     vOrient(ePitch) = 0.5*M_PI;
     401         [ #  # ]:          0 :   else if (1.0 < vGroundNormal(eZ))
     402                 :          0 :     vOrient(ePitch) = -0.5*M_PI;
     403                 :            :   else
     404                 :          0 :     vOrient(ePitch) = asin(-vGroundNormal(eZ));
     405                 :            : 
     406         [ #  # ]:          0 :   if (fabs(vOrient(ePitch)) == 0.5*M_PI)
     407                 :          0 :     vOrient(eYaw) = 0.;
     408                 :            :   else
     409                 :          0 :     vOrient(eYaw) = atan2(vGroundNormal(eY), vGroundNormal(eX));
     410                 :            :   
     411                 :          0 :   vOrient(eRoll) = 0.;
     412                 :          0 :   UpdateCustomTransformMatrix();
     413                 :            : 
     414         [ #  # ]:          0 :   if (eContactType == ctBOGEY) {
     415                 :            :     // In the case of a bogey, the third angle "roll" is used to align the axis eY and eZ
     416                 :            :     // to the rolling and sliping direction respectively.
     417                 :            :     FGColumnVector3 updatedRollingAxis = Transform().Transposed() * mTGear
     418                 :          0 :                                        * FGColumnVector3(-sin(SteerAngle), cos(SteerAngle), 0.);
     419                 :            : 
     420                 :          0 :     vOrient(eRoll) = atan2(updatedRollingAxis(eY), -updatedRollingAxis(eZ));
     421                 :          0 :     UpdateCustomTransformMatrix();
     422                 :            :   }
     423                 :          0 : }
     424                 :            : 
     425                 :            : //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     426                 :            : 
     427                 :          0 : void FGLGear::ComputeRetractionState(void)
     428                 :            : {
     429                 :          0 :   double gearPos = GetGearUnitPos();
     430         [ #  # ]:          0 :   if (gearPos < 0.01) {
     431                 :          0 :     GearUp   = true;
     432                 :          0 :     WOW      = false;
     433                 :          0 :     GearDown = false;
     434                 :          0 :     vWhlVelVec.InitMatrix();
     435         [ #  # ]:          0 :   } else if (gearPos > 0.99) {
     436                 :          0 :     GearDown = true;
     437                 :          0 :     GearUp   = false;
     438                 :            :   } else {
     439                 :          0 :     GearUp   = false;
     440                 :          0 :     GearDown = false;
     441                 :            :   }
     442                 :          0 : }
     443                 :            : 
     444                 :            : //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     445                 :            : // Calculate tire slip angle.
     446                 :            : 
     447                 :          0 : void FGLGear::ComputeSlipAngle(void)
     448                 :            : {
     449                 :            : // Check that the speed is non-null otherwise use the current angle
     450         [ #  # ]:          0 :   if (vLocalWhlVel.Magnitude(eY,eZ) > 1E-3)
     451                 :          0 :     WheelSlip = -atan2(vLocalWhlVel(eZ), fabs(vLocalWhlVel(eY)))*radtodeg;
     452                 :          0 : }
     453                 :            : 
     454                 :            : //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     455                 :            : // Compute the steering angle in any case.
     456                 :            : // This will also make sure that animations will look right.
     457                 :            : 
     458                 :          0 : void FGLGear::ComputeSteeringAngle(void)
     459                 :            : {
     460   [ #  #  #  # ]:          0 :   switch (eSteerType) {
     461                 :            :   case stSteer:
     462                 :          0 :     SteerAngle = degtorad * FCS->GetSteerPosDeg(GearNumber);
     463                 :          0 :     break;
     464                 :            :   case stFixed:
     465                 :          0 :     SteerAngle = 0.0;
     466                 :          0 :     break;
     467                 :            :   case stCaster:
     468         [ #  # ]:          0 :     if (!Castered)
     469                 :          0 :       SteerAngle = degtorad * FCS->GetSteerPosDeg(GearNumber);
     470                 :            :     else {
     471                 :            :       // Check that the speed is non-null otherwise use the current angle
     472         [ #  # ]:          0 :       if (vWhlVelVec.Magnitude(eX,eY) > 0.1)
     473                 :          0 :         SteerAngle = atan2(vWhlVelVec(eY), fabs(vWhlVelVec(eX)));
     474                 :            :     }
     475                 :            :     break;
     476                 :            :   default:
     477                 :          0 :     cerr << "Improper steering type membership detected for this gear." << endl;
     478                 :            :     break;
     479                 :            :   }
     480                 :          0 : }
     481                 :            : 
     482                 :            : //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     483                 :            : // Reset reporting functionality after takeoff
     484                 :            : 
     485                 :          0 : void FGLGear::ResetReporting(void)
     486                 :            : {
     487         [ #  # ]:          0 :   if (Propagate->GetDistanceAGL() > 200.0) {
     488                 :          0 :     FirstContact = false;
     489                 :          0 :     StartedGroundRun = false;
     490                 :          0 :     LandingReported = false;
     491                 :          0 :     TakeoffReported = true;
     492                 :          0 :     LandingDistanceTraveled = 0.0;
     493                 :          0 :     MaximumStrutForce = MaximumStrutTravel = 0.0;
     494                 :            :   }
     495                 :          0 : }
     496                 :            : 
     497                 :            : //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     498                 :            : 
     499                 :          0 : void FGLGear::InitializeReporting(void)
     500                 :            : {
     501                 :            :   // If this is the first time the wheel has made contact, remember some values
     502                 :            :   // for later printout.
     503                 :            : 
     504         [ #  # ]:          0 :   if (!FirstContact) {
     505                 :          0 :     FirstContact  = true;
     506                 :          0 :     SinkRate      =  compressSpeed;
     507                 :          0 :     GroundSpeed   =  Propagate->GetVel().Magnitude();
     508                 :          0 :     TakeoffReported = false;
     509                 :            :   }
     510                 :            : 
     511                 :            :   // If the takeoff run is starting, initialize.
     512                 :            : 
     513 [ #  # ][ #  # ]:          0 :   if ((Propagate->GetVel().Magnitude() > 0.1) &&
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     514                 :            :       (FCS->GetBrake(bgLeft) == 0) &&
     515                 :            :       (FCS->GetBrake(bgRight) == 0) &&
     516                 :            :       (FCS->GetThrottlePos(0) > 0.90) && !StartedGroundRun)
     517                 :            :   {
     518                 :          0 :     TakeoffDistanceTraveled = 0;
     519                 :          0 :     TakeoffDistanceTraveled50ft = 0;
     520                 :          0 :     StartedGroundRun = true;
     521                 :            :   }
     522                 :          0 : }
     523                 :            : 
     524                 :            : //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     525                 :            : // Takeoff and landing reporting functionality
     526                 :            : 
     527                 :          0 : void FGLGear::ReportTakeoffOrLanding(void)
     528                 :            : {
     529         [ #  # ]:          0 :   if (FirstContact)
     530                 :          0 :     LandingDistanceTraveled += Auxiliary->GetVground()*dT;
     531                 :            : 
     532         [ #  # ]:          0 :   if (StartedGroundRun) {
     533                 :          0 :     TakeoffDistanceTraveled50ft += Auxiliary->GetVground()*dT;
     534         [ #  # ]:          0 :     if (WOW) TakeoffDistanceTraveled += Auxiliary->GetVground()*dT;
     535                 :            :   }
     536                 :            : 
     537 [ #  # ][ #  # ]:          0 :   if ( ReportEnable
         [ #  # ][ #  # ]
                 [ #  # ]
     538                 :            :        && Auxiliary->GetVground() <= 0.05
     539                 :            :        && !LandingReported
     540                 :            :        && GroundReactions->GetWOW())
     541                 :            :   {
     542         [ #  # ]:          0 :     if (debug_lvl > 0) Report(erLand);
     543                 :            :   }
     544                 :            : 
     545 [ #  # ][ #  # ]:          0 :   if ( ReportEnable
         [ #  # ][ #  # ]
                 [ #  # ]
     546                 :            :        && !TakeoffReported
     547                 :            :        && (Propagate->GetDistanceAGL() - vLocalGear(eZ)) > 50.0
     548                 :            :        && !GroundReactions->GetWOW())
     549                 :            :   {
     550         [ #  # ]:          0 :     if (debug_lvl > 0) Report(erTakeoff);
     551                 :            :   }
     552                 :            : 
     553         [ #  # ]:          0 :   if (lastWOW != WOW) PutMessage("GEAR_CONTACT: " + name, WOW);
     554                 :          0 : }
     555                 :            : 
     556                 :            : //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     557                 :            : // Crash detection logic (really out-of-bounds detection)
     558                 :            : 
     559                 :          0 : void FGLGear::CrashDetect(void)
     560                 :            : {
     561 [ #  # ][ #  # ]:          0 :   if ( (compressLength > 500.0 ||
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     562                 :            :       vFn.Magnitude() > 100000000.0 ||
     563                 :            :       GetMoments().Magnitude() > 5000000000.0 ||
     564                 :            :       SinkRate > 1.4666*30 ) && !fdmex->IntegrationSuspended())
     565                 :            :   {
     566                 :          0 :     PutMessage("Crash Detected: Simulation FREEZE.");
     567                 :          0 :     fdmex->SuspendIntegration();
     568                 :            :   }
     569                 :          0 : }
     570                 :            : 
     571                 :            : //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     572                 :            : // The following needs work regarding friction coefficients and braking and
     573                 :            : // steering The BrakeFCoeff formula assumes that an anti-skid system is used.
     574                 :            : // It also assumes that we won't be turning and braking at the same time.
     575                 :            : // Will fix this later.
     576                 :            : // [JSB] The braking force coefficients include normal rolling coefficient +
     577                 :            : // a percentage of the static friction coefficient based on braking applied.
     578                 :            : 
     579                 :          0 : void FGLGear::ComputeBrakeForceCoefficient(void)
     580                 :            : {
     581   [ #  #  #  #  :          0 :   switch (eBrakeGrp) {
                #  #  # ]
     582                 :            :   case bgLeft:
     583                 :            :     BrakeFCoeff =  ( rollingFCoeff*(1.0 - FCS->GetBrake(bgLeft)) +
     584                 :          0 :                      staticFCoeff*FCS->GetBrake(bgLeft) );
     585                 :          0 :     break;
     586                 :            :   case bgRight:
     587                 :            :     BrakeFCoeff =  ( rollingFCoeff*(1.0 - FCS->GetBrake(bgRight)) +
     588                 :          0 :                      staticFCoeff*FCS->GetBrake(bgRight) );
     589                 :          0 :     break;
     590                 :            :   case bgCenter:
     591                 :            :     BrakeFCoeff =  ( rollingFCoeff*(1.0 - FCS->GetBrake(bgCenter)) +
     592                 :          0 :                      staticFCoeff*FCS->GetBrake(bgCenter) );
     593                 :          0 :     break;
     594                 :            :   case bgNose:
     595                 :            :     BrakeFCoeff =  ( rollingFCoeff*(1.0 - FCS->GetBrake(bgCenter)) +
     596                 :          0 :                      staticFCoeff*FCS->GetBrake(bgCenter) );
     597                 :          0 :     break;
     598                 :            :   case bgTail:
     599                 :            :     BrakeFCoeff =  ( rollingFCoeff*(1.0 - FCS->GetBrake(bgCenter)) +
     600                 :          0 :                      staticFCoeff*FCS->GetBrake(bgCenter) );
     601                 :          0 :     break;
     602                 :            :   case bgNone:
     603                 :          0 :     BrakeFCoeff =  rollingFCoeff;
     604                 :          0 :     break;
     605                 :            :   default:
     606                 :          0 :     cerr << "Improper brake group membership detected for this gear." << endl;
     607                 :            :     break;
     608                 :            :   }
     609                 :          0 : }
     610                 :            : 
     611                 :            : //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     612                 :            : // Compute the sideforce coefficients using Pacejka's Magic Formula.
     613                 :            : //
     614                 :            : //   y(x) = D sin {C arctan [Bx - E(Bx - arctan Bx)]}
     615                 :            : //
     616                 :            : // Where: B = Stiffness Factor (0.06, here)
     617                 :            : //        C = Shape Factor (2.8, here)
     618                 :            : //        D = Peak Factor (0.8, here)
     619                 :            : //        E = Curvature Factor (1.03, here)
     620                 :            : 
     621                 :          0 : void FGLGear::ComputeSideForceCoefficient(void)
     622                 :            : {
     623         [ #  # ]:          0 :   if (ForceY_Table) {
     624                 :          0 :     FCoeff = ForceY_Table->GetValue(WheelSlip);
     625                 :            :   } else {
     626                 :          0 :     double StiffSlip = Stiffness*WheelSlip;
     627                 :          0 :     FCoeff = Peak * sin(Shape*atan(StiffSlip - Curvature*(StiffSlip - atan(StiffSlip))));
     628                 :            :   }
     629                 :          0 : }
     630                 :            : 
     631                 :            : //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     632                 :            : // Compute the vertical force on the wheel using square-law damping (per comment
     633                 :            : // in paper AIAA-2000-4303 - see header prologue comments). We might consider
     634                 :            : // allowing for both square and linear damping force calculation. Also need to
     635                 :            : // possibly give a "rebound damping factor" that differs from the compression
     636                 :            : // case.
     637                 :            : 
     638                 :          0 : void FGLGear::ComputeVerticalStrutForce(void)
     639                 :            : {
     640                 :          0 :   double springForce = 0;
     641                 :          0 :   double dampForce = 0;
     642                 :            : 
     643                 :          0 :   springForce = -compressLength * kSpring;
     644                 :            : 
     645         [ #  # ]:          0 :   if (compressSpeed >= 0.0) {
     646                 :            : 
     647         [ #  # ]:          0 :     if (eDampType == dtLinear)   dampForce = -compressSpeed * bDamp;
     648                 :          0 :     else         dampForce = -compressSpeed * compressSpeed * bDamp;
     649                 :            : 
     650                 :            :   } else {
     651                 :            : 
     652         [ #  # ]:          0 :     if (eDampTypeRebound == dtLinear)
     653                 :          0 :       dampForce   = -compressSpeed * bDampRebound;
     654                 :            :     else
     655                 :          0 :       dampForce   =  compressSpeed * compressSpeed * bDampRebound;
     656                 :            : 
     657                 :            :   }
     658                 :            : 
     659                 :          0 :   StrutForce = min(springForce + dampForce, (double)0.0);
     660                 :            : 
     661                 :            :   // The reaction force of the wheel is always normal to the ground
     662      [ #  #  # ]:          0 :   switch (eContactType) {
     663                 :            :   case ctBOGEY:
     664                 :            :     // Project back the strut force in the local coordinate frame of the ground
     665                 :          0 :     vFn(eX) = StrutForce / (mTGear.Transposed()*vGroundNormal)(eZ);
     666                 :            :     break;
     667                 :            :   case ctSTRUCTURE:
     668                 :          0 :     vFn(eX) = -StrutForce;
     669                 :            :     break;
     670                 :            :   }
     671                 :            : 
     672                 :            :   // Remember these values for reporting
     673                 :          0 :   MaximumStrutForce = max(MaximumStrutForce, fabs(StrutForce));
     674                 :          0 :   MaximumStrutTravel = max(MaximumStrutTravel, fabs(compressLength));
     675                 :          0 : }
     676                 :            : 
     677                 :            : //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     678                 :            : 
     679                 :          0 : double FGLGear::GetGearUnitPos(void)
     680                 :            : {
     681                 :            :   // hack to provide backward compatibility to gear/gear-pos-norm property
     682 [ #  # ][ #  # ]:          0 :   if( useFCSGearPos || FCS->GetGearPos() != 1.0 ) {
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     683                 :          0 :     useFCSGearPos = true;
     684                 :          0 :     return FCS->GetGearPos();
     685                 :            :   }
     686                 :          0 :   return GearPos;
     687                 :            : }
     688                 :            : 
     689                 :            : //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     690                 :            : // Compute the jacobian entries for the friction forces resolution later
     691                 :            : // in FGPropagate
     692                 :            : 
     693                 :          0 : void FGLGear::ComputeJacobian(const FGColumnVector3& vWhlContactVec)
     694                 :            : {
     695                 :            :   // When the point of contact is moving, dynamic friction is used
     696                 :            :   // This type of friction is limited to ctSTRUCTURE elements because their
     697                 :            :   // friction coefficient is the same in every directions
     698   [ #  #  #  # ]:          0 :   if ((eContactType == ctSTRUCTURE) && (vLocalWhlVel.Magnitude(eY,eZ) > 1E-3)) {
                 [ #  # ]
     699                 :          0 :     FGColumnVector3 velocityDirection = vLocalWhlVel;
     700                 :            : 
     701                 :          0 :     StaticFriction = false;
     702                 :            : 
     703                 :          0 :     velocityDirection(eX) = 0.;
     704                 :          0 :     velocityDirection.Normalize();
     705                 :            : 
     706                 :          0 :     LMultiplier[ftDynamic].ForceJacobian = Transform()*velocityDirection;
     707                 :          0 :     LMultiplier[ftDynamic].MomentJacobian = vWhlContactVec * LMultiplier[ftDynamic].ForceJacobian;
     708                 :          0 :     LMultiplier[ftDynamic].Max = 0.;
     709                 :          0 :     LMultiplier[ftDynamic].Min = -fabs(dynamicFCoeff * vFn(eX));
     710                 :          0 :     LMultiplier[ftDynamic].value = Constrain(LMultiplier[ftDynamic].Min, LMultiplier[ftDynamic].value, LMultiplier[ftDynamic].Max);
     711                 :            :   }
     712                 :            :   else {
     713                 :            :     // Static friction is used for ctSTRUCTURE when the contact point is not moving.
     714                 :            :     // It is always used for ctBOGEY elements because the friction coefficients
     715                 :            :     // of a tyre depend on the direction of the movement (roll & side directions).
     716                 :            :     // This cannot be handled properly by the so-called "dynamic friction".
     717                 :          0 :     StaticFriction = true;
     718                 :            : 
     719                 :          0 :     LMultiplier[ftRoll].ForceJacobian = Transform()*FGColumnVector3(0.,1.,0.);
     720                 :          0 :     LMultiplier[ftSide].ForceJacobian = Transform()*FGColumnVector3(0.,0.,1.);
     721                 :          0 :     LMultiplier[ftRoll].MomentJacobian = vWhlContactVec * LMultiplier[ftRoll].ForceJacobian;
     722                 :          0 :     LMultiplier[ftSide].MomentJacobian = vWhlContactVec * LMultiplier[ftSide].ForceJacobian;
     723                 :            : 
     724      [ #  #  # ]:          0 :     switch(eContactType) {
     725                 :            :     case ctBOGEY:
     726                 :          0 :       LMultiplier[ftRoll].Max = fabs(BrakeFCoeff * vFn(eX));
     727                 :          0 :       LMultiplier[ftSide].Max = fabs(FCoeff * vFn(eX));
     728                 :          0 :       break;
     729                 :            :     case ctSTRUCTURE:
     730                 :          0 :       LMultiplier[ftRoll].Max = fabs(staticFCoeff * vFn(eX));
     731                 :          0 :       LMultiplier[ftSide].Max = fabs(staticFCoeff * vFn(eX));
     732                 :            :       break;
     733                 :            :     }
     734                 :            : 
     735                 :          0 :     LMultiplier[ftRoll].Min = -LMultiplier[ftRoll].Max;
     736                 :          0 :     LMultiplier[ftSide].Min = -LMultiplier[ftSide].Max;
     737                 :          0 :     LMultiplier[ftRoll].value = Constrain(LMultiplier[ftRoll].Min, LMultiplier[ftRoll].value, LMultiplier[ftRoll].Max);
     738                 :          0 :     LMultiplier[ftSide].value = Constrain(LMultiplier[ftSide].Min, LMultiplier[ftSide].value, LMultiplier[ftSide].Max);
     739                 :            :   }
     740                 :          0 : }
     741                 :            : 
     742                 :            : //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     743                 :            : // This function is used by the MultiplierIterator class to enumerate the
     744                 :            : // Lagrange multipliers of a landing gear. This allows to encapsulate the storage
     745                 :            : // of the multipliers in FGLGear without exposing it. From an outside point of
     746                 :            : // view, each FGLGear instance has a number of Lagrange multipliers which can be
     747                 :            : // accessed through this routine without knowing the exact constraint which they
     748                 :            : // model.
     749                 :            : 
     750                 :          0 : FGPropagate::LagrangeMultiplier* FGLGear::GetMultiplierEntry(int entry)
     751                 :            : {
     752      [ #  #  # ]:          0 :   switch(entry) {
     753                 :            :   case 0:
     754         [ #  # ]:          0 :     if (StaticFriction)
     755                 :          0 :       return &LMultiplier[ftRoll];
     756                 :            :     else
     757                 :          0 :       return &LMultiplier[ftDynamic];
     758                 :            :   case 1:
     759         [ #  # ]:          0 :     if (StaticFriction)
     760                 :          0 :       return &LMultiplier[ftSide];
     761                 :            :   default:
     762                 :          0 :     return NULL;
     763                 :            :   }
     764                 :            : }
     765                 :            : 
     766                 :            : //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     767                 :            : // This routine is called after the Lagrange multiplier has been computed. The
     768                 :            : // friction forces of the landing gear are then updated accordingly.
     769                 :          0 : FGColumnVector3& FGLGear::UpdateForces(void)
     770                 :            : {
     771         [ #  # ]:          0 :   if (StaticFriction) {
     772                 :          0 :     vFn(eY) = LMultiplier[ftRoll].value;
     773                 :          0 :     vFn(eZ) = LMultiplier[ftSide].value;
     774                 :            :   }
     775                 :            :   else
     776                 :          0 :     vFn += LMultiplier[ftDynamic].value * (Transform ().Transposed() * LMultiplier[ftDynamic].ForceJacobian);
     777                 :            : 
     778                 :            :   // Return the updated force in the body frame
     779                 :          0 :   return FGForce::GetBodyForces();
     780                 :            : }
     781                 :            : 
     782                 :            : //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     783                 :            : 
     784                 :          0 : void FGLGear::bind(void)
     785                 :            : {
     786                 :          0 :   string property_name;
     787                 :          0 :   string base_property_name;
     788                 :          0 :   base_property_name = CreateIndexedPropertyName("gear/unit", GearNumber);
     789         [ #  # ]:          0 :   if (eContactType == ctBOGEY) {
     790                 :          0 :     property_name = base_property_name + "/slip-angle-deg";
     791                 :          0 :     fdmex->GetPropertyManager()->Tie( property_name.c_str(), &WheelSlip );
     792                 :          0 :     property_name = base_property_name + "/WOW";
     793                 :          0 :     fdmex->GetPropertyManager()->Tie( property_name.c_str(), &WOW );
     794                 :          0 :     property_name = base_property_name + "/wheel-speed-fps";
     795                 :            :     fdmex->GetPropertyManager()->Tie( property_name.c_str(), (FGLGear*)this,
     796                 :          0 :                           &FGLGear::GetWheelRollVel);
     797                 :          0 :     property_name = base_property_name + "/z-position";
     798                 :            :     fdmex->GetPropertyManager()->Tie( property_name.c_str(), (FGForce*)this,
     799                 :          0 :                           &FGForce::GetLocationZ, &FGForce::SetLocationZ);
     800                 :          0 :     property_name = base_property_name + "/compression-ft";
     801                 :          0 :     fdmex->GetPropertyManager()->Tie( property_name.c_str(), &compressLength );
     802                 :          0 :     property_name = base_property_name + "/side_friction_coeff";
     803                 :          0 :     fdmex->GetPropertyManager()->Tie( property_name.c_str(), &FCoeff );
     804                 :            : 
     805                 :          0 :     property_name = base_property_name + "/static_friction_coeff";
     806                 :          0 :     fdmex->GetPropertyManager()->Tie( property_name.c_str(), &staticFCoeff );
     807                 :            : 
     808         [ #  # ]:          0 :     if (eSteerType == stCaster) {
     809                 :          0 :       property_name = base_property_name + "/steering-angle-deg";
     810                 :          0 :       fdmex->GetPropertyManager()->Tie( property_name.c_str(), this, &FGLGear::GetSteerAngleDeg );
     811                 :          0 :       property_name = base_property_name + "/castered";
     812                 :          0 :       fdmex->GetPropertyManager()->Tie( property_name.c_str(), &Castered);
     813                 :            :     }
     814                 :            :   }
     815                 :            : 
     816         [ #  # ]:          0 :   if( isRetractable ) {
     817                 :          0 :     property_name = base_property_name + "/pos-norm";
     818                 :          0 :     fdmex->GetPropertyManager()->Tie( property_name.c_str(), &GearPos );
     819                 :          0 :   }
     820                 :          0 : }
     821                 :            : 
     822                 :            : //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     823                 :            : 
     824                 :          0 : void FGLGear::Report(ReportType repType)
     825                 :            : {
     826         [ #  # ]:          0 :   if (fabs(TakeoffDistanceTraveled) < 0.001) return; // Don't print superfluous reports
     827                 :            : 
     828      [ #  #  # ]:          0 :   switch(repType) {
     829                 :            :   case erLand:
     830                 :            :     cout << endl << "Touchdown report for " << name << " (WOW at time: "
     831                 :          0 :          << fdmex->GetSimTime() << " seconds)" << endl;
     832                 :            :     cout << "  Sink rate at contact:  " << SinkRate                << " fps,    "
     833                 :          0 :                                 << SinkRate*0.3048          << " mps"     << endl;
     834                 :            :     cout << "  Contact ground speed:  " << GroundSpeed*.5925       << " knots,  "
     835                 :          0 :                                 << GroundSpeed*0.3048       << " mps"     << endl;
     836                 :            :     cout << "  Maximum contact force: " << MaximumStrutForce       << " lbs,    "
     837                 :          0 :                                 << MaximumStrutForce*4.448  << " Newtons" << endl;
     838                 :            :     cout << "  Maximum strut travel:  " << MaximumStrutTravel*12.0 << " inches, "
     839                 :          0 :                                 << MaximumStrutTravel*30.48 << " cm"      << endl;
     840                 :            :     cout << "  Distance traveled:     " << LandingDistanceTraveled        << " ft,     "
     841                 :          0 :                                 << LandingDistanceTraveled*0.3048  << " meters"  << endl;
     842                 :          0 :     LandingReported = true;
     843                 :          0 :     break;
     844                 :            :   case erTakeoff:
     845                 :            :     cout << endl << "Takeoff report for " << name << " (Liftoff at time: "
     846                 :          0 :         << fdmex->GetSimTime() << " seconds)" << endl;
     847                 :            :     cout << "  Distance traveled:                " << TakeoffDistanceTraveled
     848                 :          0 :          << " ft,     " << TakeoffDistanceTraveled*0.3048  << " meters"  << endl;
     849                 :            :     cout << "  Distance traveled (over 50'):     " << TakeoffDistanceTraveled50ft
     850                 :          0 :          << " ft,     " << TakeoffDistanceTraveled50ft*0.3048 << " meters" << endl;
     851                 :            :     cout << "  [Altitude (ASL): " << Propagate->GetAltitudeASL() << " ft. / "
     852                 :            :          << Propagate->GetAltitudeASLmeters() << " m  | Temperature: "
     853                 :            :          << fdmex->GetAtmosphere()->GetTemperature() - 459.67 << " F / "
     854                 :          0 :          << RankineToCelsius(fdmex->GetAtmosphere()->GetTemperature()) << " C]" << endl;
     855                 :          0 :     cout << "  [Velocity (KCAS): " << Auxiliary->GetVcalibratedKTS() << "]" << endl;
     856                 :          0 :     TakeoffReported = true;
     857                 :            :     break;
     858                 :            :   case erNone:
     859                 :            :     break;
     860                 :            :   }
     861                 :            : }
     862                 :            : 
     863                 :            : //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     864                 :            : //    The bitmasked value choices are as follows:
     865                 :            : //    unset: In this case (the default) JSBSim would only print
     866                 :            : //       out the normally expected messages, essentially echoing
     867                 :            : //       the config files as they are read. If the environment
     868                 :            : //       variable is not set, debug_lvl is set to 1 internally
     869                 :            : //    0: This requests JSBSim not to output any messages
     870                 :            : //       whatsoever.
     871                 :            : //    1: This value explicity requests the normal JSBSim
     872                 :            : //       startup messages
     873                 :            : //    2: This value asks for a message to be printed out when
     874                 :            : //       a class is instantiated
     875                 :            : //    4: When this value is set, a message is displayed when a
     876                 :            : //       FGModel object executes its Run() method
     877                 :            : //    8: When this value is set, various runtime state variables
     878                 :            : //       are printed out periodically
     879                 :            : //    16: When set various parameters are sanity checked and
     880                 :            : //       a message is printed out when they go out of bounds
     881                 :            : 
     882                 :          0 : void FGLGear::Debug(int from)
     883                 :            : {
     884         [ #  # ]:          0 :   if (debug_lvl <= 0) return;
     885                 :            : 
     886         [ #  # ]:          0 :   if (debug_lvl & 1) { // Standard console startup message output
     887         [ #  # ]:          0 :     if (from == 0) { // Constructor - loading and initialization
     888                 :          0 :       cout << "    " << sContactType << " " << name          << endl;
     889                 :          0 :       cout << "      Location: "         << vXYZn          << endl;
     890                 :          0 :       cout << "      Spring Constant:  " << kSpring       << endl;
     891                 :            : 
     892         [ #  # ]:          0 :       if (eDampType == dtLinear)
     893                 :          0 :         cout << "      Damping Constant: " << bDamp << " (linear)" << endl;
     894                 :            :       else
     895                 :          0 :         cout << "      Damping Constant: " << bDamp << " (square law)" << endl;
     896                 :            : 
     897         [ #  # ]:          0 :       if (eDampTypeRebound == dtLinear)
     898                 :          0 :         cout << "      Rebound Damping Constant: " << bDampRebound << " (linear)" << endl;
     899                 :            :       else 
     900                 :          0 :         cout << "      Rebound Damping Constant: " << bDampRebound << " (square law)" << endl;
     901                 :            : 
     902                 :          0 :       cout << "      Dynamic Friction: " << dynamicFCoeff << endl;
     903                 :          0 :       cout << "      Static Friction:  " << staticFCoeff  << endl;
     904         [ #  # ]:          0 :       if (eContactType == ctBOGEY) {
     905                 :          0 :         cout << "      Rolling Friction: " << rollingFCoeff << endl;
     906                 :          0 :         cout << "      Steering Type:    " << sSteerType    << endl;
     907                 :          0 :         cout << "      Grouping:         " << sBrakeGroup   << endl;
     908                 :          0 :         cout << "      Max Steer Angle:  " << maxSteerAngle << endl;
     909                 :          0 :         cout << "      Retractable:      " << isRetractable  << endl;
     910                 :            :       }
     911                 :            :     }
     912                 :            :   }
     913         [ #  # ]:          0 :   if (debug_lvl & 2 ) { // Instantiation/Destruction notification
     914         [ #  # ]:          0 :     if (from == 0) cout << "Instantiated: FGLGear" << endl;
     915         [ #  # ]:          0 :     if (from == 1) cout << "Destroyed:    FGLGear" << endl;
     916                 :            :   }
     917                 :          0 :   if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
     918                 :            :   }
     919                 :          0 :   if (debug_lvl & 8 ) { // Runtime state variables
     920                 :            :   }
     921                 :          0 :   if (debug_lvl & 16) { // Sanity checking
     922                 :            :   }
     923         [ #  # ]:          0 :   if (debug_lvl & 64) {
     924         [ #  # ]:          0 :     if (from == 0) { // Constructor
     925                 :          0 :       cout << IdSrc << endl;
     926                 :          0 :       cout << IdHdr << endl;
     927                 :            :     }
     928                 :            :   }
     929                 :            : }
     930                 :            : 
     931 [ +  + ][ +  - ]:         12 : } // namespace JSBSim
     932                 :            : 

Generated by: LCOV version 1.9