]> git.mxchange.org Git - flightgear.git/blob - src/FDM/JSBSim/FGLGear.cpp
Syncing with most recent JSBSim.
[flightgear.git] / src / FDM / JSBSim / FGLGear.cpp
1 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2
3  Module:       FGLGear.cpp
4  Author:       Jon S. Berndt
5                Norman H. Princen
6  Date started: 11/18/99
7  Purpose:      Encapsulates the landing gear elements
8  Called by:    FGAircraft
9
10  ------------- Copyright (C) 1999  Jon S. Berndt (jsb@hal-pc.org) -------------
11
12  This program is free software; you can redistribute it and/or modify it under
13  the terms of the GNU General Public License as published by the Free Software
14  Foundation; either version 2 of the License, or (at your option) any later
15  version.
16
17  This program is distributed in the hope that it will be useful, but WITHOUT
18  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
19  FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
20  details.
21
22  You should have received a copy of the GNU General Public License along with
23  this program; if not, write to the Free Software Foundation, Inc., 59 Temple
24  Place - Suite 330, Boston, MA  02111-1307, USA.
25
26  Further information about the GNU General Public License can also be found on
27  the world wide web at http://www.gnu.org.
28
29 FUNCTIONAL DESCRIPTION
30 --------------------------------------------------------------------------------
31
32 HISTORY
33 --------------------------------------------------------------------------------
34 11/18/99   JSB   Created
35 01/30/01   NHP   Extended gear model to properly simulate steering and braking
36
37 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
38 INCLUDES
39 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
40
41 #include "FGLGear.h"
42 #include <algorithm>
43
44 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
45 DEFINITIONS
46 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
47
48 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
49 GLOBAL DATA
50 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
51
52
53 static const char *IdSrc = "$Id$";
54 static const char *IdHdr = ID_LGEAR;
55
56 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
57 CLASS IMPLEMENTATION
58 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
59
60 FGLGear::FGLGear(FGConfigFile* AC_cfg, FGFDMExec* fdmex) : Exec(fdmex)
61 {
62   string tmp;
63   string Retractable;
64   
65   *AC_cfg >> tmp >> name >> vXYZ(1) >> vXYZ(2) >> vXYZ(3)
66             >> kSpring >> bDamp>> dynamicFCoeff >> staticFCoeff
67                   >> rollingFCoeff >> sSteerType >> sBrakeGroup 
68                      >> maxSteerAngle >> Retractable;
69
70   if (debug_lvl > 0) {
71     cout << "    Name: " << name << endl;
72     cout << "      Location: " << vXYZ << endl;
73     cout << "      Spring Constant:  " << kSpring << endl;
74     cout << "      Damping Constant: " << bDamp << endl;
75     cout << "      Dynamic Friction: " << dynamicFCoeff << endl;
76     cout << "      Static Friction:  " << staticFCoeff << endl;
77     cout << "      Rolling Friction: " << rollingFCoeff << endl;
78     cout << "      Steering Type:    " << sSteerType << endl;
79     cout << "      Grouping:         " << sBrakeGroup << endl;
80     cout << "      Max Steer Angle:  " << maxSteerAngle << endl;
81     cout << "      Retractable:      " << Retractable << endl;
82   }
83
84   if      (sBrakeGroup == "LEFT"  ) eBrakeGrp = bgLeft;
85   else if (sBrakeGroup == "RIGHT" ) eBrakeGrp = bgRight;
86   else if (sBrakeGroup == "CENTER") eBrakeGrp = bgCenter;
87   else if (sBrakeGroup == "NOSE"  ) eBrakeGrp = bgNose;
88   else if (sBrakeGroup == "TAIL"  ) eBrakeGrp = bgTail;
89   else if (sBrakeGroup == "NONE"  ) eBrakeGrp = bgNone;
90   else {
91     cerr << "Improper braking group specification in config file: "
92          << sBrakeGroup << " is undefined." << endl;
93   }
94
95   if      (sSteerType == "STEERABLE") eSteerType = stSteer;
96   else if (sSteerType == "FIXED"    ) eSteerType = stFixed;
97   else if (sSteerType == "CASTERED" ) eSteerType = stCaster;
98   else {
99     cerr << "Improper steering type specification in config file: "
100          << sSteerType << " is undefined." << endl;
101   }
102   
103   if( Retractable == "RETRACT" ) {
104     isRetractable=true;
105   } else  {
106     isRetractable=false;
107   }  
108   
109   GearUp=false; GearDown=true;
110
111 // Add some AI here to determine if gear is located properly according to its
112 // brake group type ??
113
114   State       = Exec->GetState();
115   Aircraft    = Exec->GetAircraft();
116   Position    = Exec->GetPosition();
117   Rotation    = Exec->GetRotation();
118   FCS         = Exec->GetFCS();
119   MassBalance = Exec->GetMassBalance();
120
121   WOW = lastWOW = false;
122   ReportEnable = true;
123   FirstContact = false;
124   Reported = false;
125   DistanceTraveled = 0.0;
126   MaximumStrutForce = MaximumStrutTravel = 0.0;
127   SinkRate = GroundSpeed = 0.0;
128
129   vWhlBodyVec     = (vXYZ - MassBalance->GetXYZcg()) / 12.0;
130   vWhlBodyVec(eX) = -vWhlBodyVec(eX);
131   vWhlBodyVec(eZ) = -vWhlBodyVec(eZ);
132
133   vLocalGear = State->GetTb2l() * vWhlBodyVec;
134
135   if (debug_lvl & 2) cout << "Instantiated: FGLGear" << endl;
136 }
137
138 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
139
140 FGLGear::FGLGear(const FGLGear& lgear)
141 {
142   State    = lgear.State;
143   Aircraft = lgear.Aircraft;
144   Position = lgear.Position;
145   Rotation = lgear.Rotation;
146   Exec     = lgear.Exec;
147   FCS      = lgear.FCS;
148   MassBalance = lgear.MassBalance;
149
150   vXYZ = lgear.vXYZ;
151   vMoment = lgear.vMoment;
152   vWhlBodyVec = lgear.vWhlBodyVec;
153   vLocalGear = lgear.vLocalGear;
154
155   WOW                = lgear.WOW;
156   lastWOW            = lgear.lastWOW;
157   ReportEnable       = lgear.ReportEnable;
158   FirstContact       = lgear.FirstContact;
159   DistanceTraveled   = lgear.DistanceTraveled;
160   MaximumStrutForce  = lgear.MaximumStrutForce;
161   MaximumStrutTravel = lgear.MaximumStrutTravel;
162
163   kSpring         = lgear.kSpring;
164   bDamp           = lgear.bDamp;
165   compressLength  = lgear.compressLength;
166   compressSpeed   = lgear.compressSpeed;
167   staticFCoeff    = lgear.staticFCoeff;
168   dynamicFCoeff   = lgear.dynamicFCoeff;
169   rollingFCoeff   = lgear.rollingFCoeff;
170   brakePct        = lgear.brakePct;
171   maxCompLen      = lgear.maxCompLen;
172   SinkRate        = lgear.SinkRate;
173   GroundSpeed     = lgear.GroundSpeed;
174   Reported        = lgear.Reported;
175   name            = lgear.name;
176   sSteerType      = lgear.sSteerType;
177   eSteerType      = lgear.eSteerType;
178   sBrakeGroup     = lgear.sBrakeGroup;
179   eBrakeGrp       = lgear.eBrakeGrp;
180   maxSteerAngle   = lgear.maxSteerAngle;
181   isRetractable   = lgear.isRetractable;
182   GearUp          = lgear.GearUp;
183   GearDown        = lgear.GearDown;
184 }
185
186 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
187
188 FGLGear::~FGLGear()
189 {
190   if (debug_lvl & 2) cout << "Destroyed:    FGLGear" << endl;
191 }
192
193 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
194
195 FGColumnVector3& FGLGear::Force(void)
196 {
197   vForce.InitMatrix();
198   vMoment.InitMatrix();
199
200   if (isRetractable) {
201     if (FCS->GetGearPos() < 0.01) {
202       GearUp   = true;
203       GearDown = false;
204      } else if (FCS->GetGearPos() > 0.99) {
205       GearDown = true;
206       GearUp   = false;
207      } else {
208       GearUp   = false;
209       GearDown = false;
210      }
211   } else {
212       GearUp   = false;
213       GearDown = true;
214   }         
215       
216   if (GearDown) {
217     double SteerGain = 0;
218     double SinWheel, CosWheel, SideWhlVel, RollingWhlVel;
219     double RollingForce, SideForce, FCoeff;
220     double WheelSlip;
221
222     vWhlBodyVec     = (vXYZ - MassBalance->GetXYZcg()) / 12.0;
223     vWhlBodyVec(eX) = -vWhlBodyVec(eX);
224     vWhlBodyVec(eZ) = -vWhlBodyVec(eZ);
225
226 // vWhlBodyVec now stores the vector from the cg to this wheel
227
228     vLocalGear = State->GetTb2l() * vWhlBodyVec;
229
230 // vLocalGear now stores the vector from the cg to the wheel in local coords.
231
232     compressLength = vLocalGear(eZ) - Position->GetDistanceAGL();
233
234 // The compression length is currently measured in the Z-axis, only, at this time.
235 // It should be measured along the strut axis. If the local-frame gear position
236 // "hangs down" below the CG greater than the altitude, then the compressLength
237 // will be positive - i.e. the gear will have made contact.
238
239     if (compressLength > 0.00) {
240
241       WOW = true;// Weight-On-Wheels is true
242
243 // The next equation should really use the vector to the contact patch of the tire
244 // including the strut compression and not vWhlBodyVec.  Will fix this later.
245 // As it stands, now, the following equation takes the aircraft body-frame
246 // rotational rate and calculates the cross-product with the vector from the CG
247 // to the wheel, thus producing the instantaneous velocity vector of the tire
248 // in Body coords. The frame is also converted to local coordinates. When the
249 // aircraft local-frame velocity is added to this quantity, the total velocity of
250 // the wheel in local frame is then known. Subsequently, the compression speed
251 // (used for calculating damping force) is found by taking the Z-component of the
252 // wheel velocity.
253
254       vWhlVelVec      =  State->GetTb2l() * (Rotation->GetPQR() * vWhlBodyVec);
255
256       vWhlVelVec     +=  Position->GetVel();
257
258       compressSpeed   =  vWhlVelVec(eZ);
259
260 // If this is the first time the wheel has made contact, remember some values
261 // for later printout.
262
263       if (!FirstContact) {
264         FirstContact  = true;
265         SinkRate      =  compressSpeed;
266         GroundSpeed   =  Position->GetVel().Magnitude();
267       }
268
269 // The following needs work regarding friction coefficients and braking and
270 // steering The BrakeFCoeff formula assumes that an anti-skid system is used.
271 // It also assumes that we won't be turning and braking at the same time.
272 // Will fix this later.
273 // [JSB] The braking force coefficients include normal rolling coefficient +
274 // a percentage of the static friction coefficient based on braking applied.
275
276       switch (eBrakeGrp) {
277       case bgLeft:
278         SteerGain = -0.10;
279         BrakeFCoeff = rollingFCoeff*(1.0 - FCS->GetBrake(bgLeft)) +
280                                               staticFCoeff*FCS->GetBrake(bgLeft);
281         break;
282       case bgRight:
283         SteerGain = -0.10;
284         BrakeFCoeff = rollingFCoeff*(1.0 - FCS->GetBrake(bgRight)) +
285                                              staticFCoeff*FCS->GetBrake(bgRight);
286         break;
287       case bgCenter:
288         SteerGain = -0.10;
289         BrakeFCoeff = rollingFCoeff*(1.0 - FCS->GetBrake(bgCenter)) +
290                                              staticFCoeff*FCS->GetBrake(bgCenter);
291         break;
292       case bgNose:
293         SteerGain = 0.10;
294         BrakeFCoeff = rollingFCoeff;
295         break;
296       case bgTail:
297         SteerGain = -0.10;
298         BrakeFCoeff = rollingFCoeff;
299         break;
300       case bgNone:
301         SteerGain = -0.10;
302         BrakeFCoeff = rollingFCoeff;
303         break;
304       default:
305         cerr << "Improper brake group membership detected for this gear." << endl;
306         break;
307       }
308
309       switch (eSteerType) {
310       case stSteer:
311         SteerAngle = SteerGain*FCS->GetDrPos();
312         break;
313       case stFixed:
314         SteerAngle = 0.0;
315         break;
316       case stCaster:
317 // Note to Jon: This is not correct for castering gear.  I'll fix it later.
318         SteerAngle = 0.0;
319         break;
320       default:
321         cerr << "Improper steering type membership detected for this gear." << endl;
322         break;
323       }
324
325 // Transform the wheel velocities from the local axis system to the wheel axis system.
326 // For now, steering angle is assumed to happen in the Local Z axis,
327 // not the strut axis as it should be.  Will fix this later.
328
329       SinWheel      = sin(Rotation->Getpsi() + SteerAngle);
330       CosWheel      = cos(Rotation->Getpsi() + SteerAngle);
331       RollingWhlVel = vWhlVelVec(eX)*CosWheel + vWhlVelVec(eY)*SinWheel;
332       SideWhlVel    = vWhlVelVec(eY)*CosWheel - vWhlVelVec(eX)*SinWheel;
333
334 // Calculate tire slip angle.
335
336       if (RollingWhlVel == 0.0 && SideWhlVel == 0.0) {
337         WheelSlip = 0.0;
338       } else {
339         WheelSlip = radtodeg*atan2(SideWhlVel, RollingWhlVel);
340       }
341
342 // The following code normalizes the wheel velocity vector, reverses it, and zeroes out
343 // the z component of the velocity. The question is, should the Z axis velocity be zeroed
344 // out first before the normalization takes place or not? Subsequent to that, the Wheel
345 // Velocity vector now points as a unit vector backwards and parallel to the wheel
346 // velocity vector. It acts AT the wheel.
347
348 // Note to Jon: I commented out this line because I wasn't sure we want to do this.
349 //    vWhlVelVec      = -1.0 * vWhlVelVec.Normalize();
350 //    vWhlVelVec(eZ)  =  0.00;
351
352 // Compute the sideforce coefficients using similar assumptions to LaRCSim for now.
353 // Allow a maximum of 10 degrees tire slip angle before wheel slides.  At that point,
354 // transition from static to dynamic friction.  There are more complicated formulations
355 // of this that avoid the discrete jump.  Will fix this later.
356
357       if (fabs(WheelSlip) <= 10.0) {
358         FCoeff = staticFCoeff*WheelSlip/10.0;
359       } else {
360         FCoeff = dynamicFCoeff*fabs(WheelSlip)/WheelSlip;
361       }
362
363 // Compute the vertical force on the wheel using square-law damping (per comment
364 // in paper AIAA-2000-4303 - see header prologue comments). We might consider
365 // allowing for both square and linear damping force calculation. Also need to
366 // possibly give a "rebound damping factor" that differs from the compression
367 // case. NOTE: SQUARE LAW DAMPING NO GOOD!
368
369       vLocalForce(eZ) =  min(-compressLength * kSpring
370                              - compressSpeed * bDamp, (double)0.0);
371
372       MaximumStrutForce = max(MaximumStrutForce, fabs(vLocalForce(eZ)));
373       MaximumStrutTravel = max(MaximumStrutTravel, fabs(compressLength));
374
375 // Compute the forces in the wheel ground plane.
376
377       RollingForce = 0;
378       if (fabs(RollingWhlVel) > 1E-3) {
379         RollingForce = vLocalForce(eZ) * BrakeFCoeff * fabs(RollingWhlVel)/RollingWhlVel;
380       }
381       SideForce    = vLocalForce(eZ) * FCoeff;
382
383 // Transform these forces back to the local reference frame.
384
385       vLocalForce(eX) = RollingForce*CosWheel - SideForce*SinWheel;
386       vLocalForce(eY) = SideForce*CosWheel    + RollingForce*SinWheel;
387
388 // Note to Jon: At this point the forces will be too big when the airplane is
389 // stopped or rolling to a stop.  We need to make sure that the gear forces just
390 // balance out the non-gear forces when the airplane is stopped.  That way the
391 // airplane won't start to accelerate until the non-gear/ forces are larger than
392 // the gear forces.  I think that the proper fix should go into FGAircraft::FMGear.
393 // This routine would only compute the local strut forces and return them to
394 // FMGear. All of the gear forces would get adjusted in FMGear using the total
395 // non-gear forces. Then the gear moments would be calculated. If strange things
396 // start happening to the airplane during testing as it rolls to a stop, then we
397 // need to implement this change.  I ran out of time to do it now but have the
398 // equations.
399
400 // Transform the forces back to the body frame and compute the moment.
401
402       vForce  = State->GetTl2b() * vLocalForce;
403       vMoment = vWhlBodyVec * vForce;
404
405     } else {
406
407       WOW = false;
408
409       if (Position->GetDistanceAGL() > 200.0) {
410         FirstContact = false;
411         Reported = false;
412         DistanceTraveled = 0.0;
413         MaximumStrutForce = MaximumStrutTravel = 0.0;
414       }
415
416       compressLength = 0.0;// reset compressLength to zero for data output validity
417
418       
419     }
420
421     if (FirstContact) {
422       DistanceTraveled += Position->GetVel().Magnitude()*State->Getdt()*Aircraft->GetRate();
423     }
424   
425     if (ReportEnable && Position->GetVel().Magnitude() <= 0.05 && !Reported) {
426       if (debug_lvl > 0) Report();
427     }
428
429     if (lastWOW != WOW) {
430       PutMessage("GEAR_CONTACT", WOW);
431     }
432
433     lastWOW = WOW;
434
435 // Crash detection logic (really out-of-bounds detection)
436
437     if (compressLength > 500.0 ||
438         vForce.Magnitude() > 100000000.0 ||
439         vMoment.Magnitude() > 5000000000.0 ||
440         SinkRate > 1.4666*30)
441     {
442       PutMessage("Crash Detected");
443       Exec->Freeze();
444     }
445
446     
447   } 
448   return vForce; 
449 }
450
451 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
452
453 void FGLGear::Report(void)
454 {
455   cout << endl << "Touchdown report for " << name << endl;
456   cout << "  Sink rate at contact:  " << SinkRate                << " fps,    "
457                               << SinkRate*0.3408          << " mps"     << endl;
458   cout << "  Contact ground speed:  " << GroundSpeed*.5925       << " knots,  "
459                               << GroundSpeed*0.3408       << " mps"     << endl;
460   cout << "  Maximum contact force: " << MaximumStrutForce       << " lbs,    "
461                               << MaximumStrutForce*4.448  << " Newtons" << endl;
462   cout << "  Maximum strut travel:  " << MaximumStrutTravel*12.0 << " inches, "
463                               << MaximumStrutTravel*30.48 << " cm"      << endl;
464   cout << "  Distance traveled:     " << DistanceTraveled        << " ft,     "
465                               << DistanceTraveled*0.3408  << " meters"  << endl;
466   Reported = true;
467 }
468
469 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
470
471 void FGLGear::Debug(void)
472 {
473   // TODO: Add user code here
474 }
475