]> git.mxchange.org Git - flightgear.git/blob - src/FDM/JSBSim/models/FGFCS.cpp
Sync with JSBSim CVS
[flightgear.git] / src / FDM / JSBSim / models / FGFCS.cpp
1 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2
3  Module:       FGFCS.cpp 
4  Author:       Jon Berndt
5  Date started: 12/12/98
6  Purpose:      Model the flight controls
7  Called by:    FDMExec
8
9  ------------- Copyright (C) 1999  Jon S. Berndt (jon@jsbsim.org) -------------
10
11  This program is free software; you can redistribute it and/or modify it under
12  the terms of the GNU Lesser General Public License as published by the Free Software
13  Foundation; either version 2 of the License, or (at your option) any later
14  version.
15
16  This program is distributed in the hope that it will be useful, but WITHOUT
17  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18  FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
19  details.
20
21  You should have received a copy of the GNU Lesser General Public License along with
22  this program; if not, write to the Free Software Foundation, Inc., 59 Temple
23  Place - Suite 330, Boston, MA  02111-1307, USA.
24
25  Further information about the GNU Lesser General Public License can also be found on
26  the world wide web at http://www.gnu.org.
27
28 FUNCTIONAL DESCRIPTION
29 --------------------------------------------------------------------------------
30 This class models the flight controls for a specific airplane
31
32 HISTORY
33 --------------------------------------------------------------------------------
34 12/12/98   JSB   Created
35
36 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
37 INCLUDES
38 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
39
40 #include "FGFCS.h"
41 #include "FGFDMExec.h"
42 #include "FGGroundReactions.h"
43 #include "input_output/FGPropertyManager.h"
44 #include <fstream>
45 #include <sstream>
46 #include <iomanip>
47
48 #include "models/flight_control/FGFilter.h"
49 #include "models/flight_control/FGDeadBand.h"
50 #include "models/flight_control/FGGain.h"
51 #include "models/flight_control/FGPID.h"
52 #include "models/flight_control/FGSwitch.h"
53 #include "models/flight_control/FGSummer.h"
54 #include "models/flight_control/FGKinemat.h"
55 #include "models/flight_control/FGFCSFunction.h"
56 #include "models/flight_control/FGSensor.h"
57 #include "models/flight_control/FGActuator.h"
58 #include "models/flight_control/FGAccelerometer.h"
59 #include "models/flight_control/FGMagnetometer.h"
60 #include "models/flight_control/FGGyro.h"
61
62 using namespace std;
63
64 namespace JSBSim {
65
66 static const char *IdSrc = "$Id: FGFCS.cpp,v 1.68 2010/03/18 13:21:24 jberndt Exp $";
67 static const char *IdHdr = ID_FCS;
68
69 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
70 CLASS IMPLEMENTATION
71 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
72
73 FGFCS::FGFCS(FGFDMExec* fdmex) : FGModel(fdmex)
74 {
75   int i;
76   Name = "FGFCS";
77
78   DaCmd = DeCmd = DrCmd = DsCmd = DfCmd = DsbCmd = DspCmd = 0;
79   PTrimCmd = YTrimCmd = RTrimCmd = 0.0;
80   GearCmd = GearPos = 1; // default to gear down
81   LeftBrake = RightBrake = CenterBrake = 0.0;
82   TailhookPos = WingFoldPos = 0.0; 
83
84   bind();
85   for (i=0;i<NForms;i++) {
86     DePos[i] = DaLPos[i] = DaRPos[i] = DrPos[i] = 0.0;
87     DfPos[i] = DsbPos[i] = DspPos[i] = 0.0;
88   }
89
90   Debug(0);
91 }
92
93 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
94
95 FGFCS::~FGFCS()
96 {
97   ThrottleCmd.clear();
98   ThrottlePos.clear();
99   MixtureCmd.clear();
100   MixturePos.clear();
101   PropAdvanceCmd.clear();
102   PropAdvance.clear();
103   SteerPosDeg.clear();
104   PropFeatherCmd.clear();
105   PropFeather.clear();
106
107   unsigned int i;
108
109   for (i=0;i<APComponents.size();i++) delete APComponents[i];
110   APComponents.clear();
111   for (i=0;i<FCSComponents.size();i++) delete FCSComponents[i];
112   FCSComponents.clear();
113   for (i=0;i<Systems.size();i++) delete Systems[i];
114   Systems.clear();
115
116
117   Debug(1);
118 }
119
120 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
121
122 bool FGFCS::InitModel(void)
123 {
124   unsigned int i;
125
126   if (!FGModel::InitModel()) return false;
127
128   for (i=0; i<ThrottlePos.size(); i++) ThrottlePos[i] = 0.0;
129   for (i=0; i<MixturePos.size(); i++) MixturePos[i] = 0.0;
130   for (i=0; i<ThrottleCmd.size(); i++) ThrottleCmd[i] = 0.0;
131   for (i=0; i<MixtureCmd.size(); i++) MixtureCmd[i] = 0.0;
132   for (i=0; i<PropAdvance.size(); i++) PropAdvance[i] = 0.0;
133   for (i=0; i<PropFeather.size(); i++) PropFeather[i] = 0.0;
134
135   DaCmd = DeCmd = DrCmd = DsCmd = DfCmd = DsbCmd = DspCmd = 0;
136   PTrimCmd = YTrimCmd = RTrimCmd = 0.0;
137   TailhookPos = WingFoldPos = 0.0;
138
139   for (i=0;i<NForms;i++) {
140     DePos[i] = DaLPos[i] = DaRPos[i] = DrPos[i] = 0.0;
141     DfPos[i] = DsbPos[i] = DspPos[i] = 0.0;
142   }
143
144   for (unsigned int i=0; i<Systems.size(); i++) {
145     if (Systems[i]->GetType() == "LAG" ||
146         Systems[i]->GetType() == "LEAD_LAG" ||
147         Systems[i]->GetType() == "WASHOUT" ||
148         Systems[i]->GetType() == "SECOND_ORDER_FILTER" ||
149         Systems[i]->GetType() == "INTEGRATOR")
150     {
151       ((FGFilter*)Systems[i])->ResetPastStates();
152     } else if (Systems[i]->GetType() == "PID" ) {
153       ((FGPID*)Systems[i])->ResetPastStates();
154     }
155   }
156
157   for (unsigned int i=0; i<FCSComponents.size(); i++) {
158     if (FCSComponents[i]->GetType() == "LAG" ||
159         FCSComponents[i]->GetType() == "LEAD_LAG" ||
160         FCSComponents[i]->GetType() == "WASHOUT" ||
161         FCSComponents[i]->GetType() == "SECOND_ORDER_FILTER" ||
162         FCSComponents[i]->GetType() == "INTEGRATOR")
163     {
164       ((FGFilter*)FCSComponents[i])->ResetPastStates();
165     } else if (FCSComponents[i]->GetType() == "PID" ) {
166       ((FGPID*)FCSComponents[i])->ResetPastStates();
167     }
168   }
169
170   for (unsigned int i=0; i<APComponents.size(); i++) {
171     if (APComponents[i]->GetType() == "LAG" ||
172         APComponents[i]->GetType() == "LEAD_LAG" ||
173         APComponents[i]->GetType() == "WASHOUT" ||
174         APComponents[i]->GetType() == "SECOND_ORDER_FILTER" ||
175         APComponents[i]->GetType() == "INTEGRATOR")
176     {
177       ((FGFilter*)APComponents[i])->ResetPastStates();
178     } else if (APComponents[i]->GetType() == "PID" ) {
179       ((FGPID*)APComponents[i])->ResetPastStates();
180     }
181   }
182
183   return true;
184 }
185   
186 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
187 // Notes: In this logic the default engine commands are set. This is simply a
188 // sort of safe-mode method in case the user has not defined control laws for
189 // throttle, mixture, and prop-advance. The throttle, mixture, and prop advance
190 // positions are set equal to the respective commands. Any control logic that is
191 // actually present in the flight_control or autopilot section will override
192 // these simple assignments.
193
194 bool FGFCS::Run(void)
195 {
196   unsigned int i;
197
198   if (FGModel::Run()) return true; // fast exit if nothing to do
199   if (FDMExec->Holding()) return false;
200
201   RunPreFunctions();
202
203   for (i=0; i<ThrottlePos.size(); i++) ThrottlePos[i] = ThrottleCmd[i];
204   for (i=0; i<MixturePos.size(); i++) MixturePos[i] = MixtureCmd[i];
205   for (i=0; i<PropAdvance.size(); i++) PropAdvance[i] = PropAdvanceCmd[i];
206   for (i=0; i<PropFeather.size(); i++) PropFeather[i] = PropFeatherCmd[i];
207
208   // Set the default steering angle
209   for (i=0; i<SteerPosDeg.size(); i++) {
210     FGLGear* gear = GroundReactions->GetGearUnit(i);
211     SteerPosDeg[i] = gear->GetDefaultSteerAngle( GetDsCmd() );
212   }
213
214   // Execute Systems in order
215   for (i=0; i<Systems.size(); i++) Systems[i]->Run();
216
217   // Execute Autopilot
218   for (i=0; i<APComponents.size(); i++) APComponents[i]->Run();
219
220   // Execute Flight Control System
221   for (i=0; i<FCSComponents.size(); i++) FCSComponents[i]->Run();
222
223   RunPostFunctions();
224
225   return false;
226 }
227
228 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
229
230 void FGFCS::SetDaLPos( int form , double pos )
231 {
232   switch(form) {
233   case ofRad:
234     DaLPos[ofRad] = pos;
235     DaLPos[ofDeg] = pos*radtodeg;
236     break;
237   case ofDeg:
238     DaLPos[ofRad] = pos*degtorad;
239     DaLPos[ofDeg] = pos;
240     break;
241   case ofNorm:
242     DaLPos[ofNorm] = pos;
243   }
244   DaLPos[ofMag] = fabs(DaLPos[ofRad]);
245 }
246
247 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
248
249 void FGFCS::SetDaRPos( int form , double pos )
250 {
251   switch(form) {
252   case ofRad:
253     DaRPos[ofRad] = pos;
254     DaRPos[ofDeg] = pos*radtodeg;
255     break;
256   case ofDeg:
257     DaRPos[ofRad] = pos*degtorad;
258     DaRPos[ofDeg] = pos;
259     break;
260   case ofNorm:
261     DaRPos[ofNorm] = pos;
262   }
263   DaRPos[ofMag] = fabs(DaRPos[ofRad]);
264 }
265
266 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
267
268 void FGFCS::SetDePos( int form , double pos )
269 {
270   switch(form) {
271   case ofRad:
272     DePos[ofRad] = pos;
273     DePos[ofDeg] = pos*radtodeg;
274     break;
275   case ofDeg:
276     DePos[ofRad] = pos*degtorad;
277     DePos[ofDeg] = pos;
278     break;
279   case ofNorm:
280     DePos[ofNorm] = pos;
281   }
282   DePos[ofMag] = fabs(DePos[ofRad]);
283 }
284
285 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
286
287 void FGFCS::SetDrPos( int form , double pos )
288 {
289   switch(form) {
290   case ofRad:
291     DrPos[ofRad] = pos;
292     DrPos[ofDeg] = pos*radtodeg;
293     break;
294   case ofDeg:
295     DrPos[ofRad] = pos*degtorad;
296     DrPos[ofDeg] = pos;
297     break;
298   case ofNorm:
299     DrPos[ofNorm] = pos;
300   }
301   DrPos[ofMag] = fabs(DrPos[ofRad]);
302 }
303
304 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
305
306 void FGFCS::SetDfPos( int form , double pos )
307 {
308   switch(form) {
309   case ofRad:
310     DfPos[ofRad] = pos;
311     DfPos[ofDeg] = pos*radtodeg;
312     break;
313   case ofDeg:
314     DfPos[ofRad] = pos*degtorad;
315     DfPos[ofDeg] = pos;
316     break;
317   case ofNorm:
318     DfPos[ofNorm] = pos;
319   }
320   DfPos[ofMag] = fabs(DfPos[ofRad]);
321 }
322
323 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
324
325 void FGFCS::SetDsbPos( int form , double pos )
326 {
327   switch(form) {
328   case ofRad:
329     DsbPos[ofRad] = pos;
330     DsbPos[ofDeg] = pos*radtodeg;
331     break;
332   case ofDeg:
333     DsbPos[ofRad] = pos*degtorad;
334     DsbPos[ofDeg] = pos;
335     break;
336   case ofNorm:
337     DsbPos[ofNorm] = pos;
338   }
339   DsbPos[ofMag] = fabs(DsbPos[ofRad]);
340 }
341
342 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
343
344 void FGFCS::SetDspPos( int form , double pos )
345 {
346   switch(form) {
347   case ofRad:
348     DspPos[ofRad] = pos;
349     DspPos[ofDeg] = pos*radtodeg;
350     break;
351   case ofDeg:
352     DspPos[ofRad] = pos*degtorad;
353     DspPos[ofDeg] = pos;
354     break;
355   case ofNorm:
356     DspPos[ofNorm] = pos;
357   }
358   DspPos[ofMag] = fabs(DspPos[ofRad]);
359 }
360
361 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
362
363 void FGFCS::SetThrottleCmd(int engineNum, double setting)
364 {
365   unsigned int ctr;
366
367   if (engineNum < (int)ThrottlePos.size()) {
368     if (engineNum < 0) {
369       for (ctr=0;ctr<ThrottleCmd.size();ctr++) ThrottleCmd[ctr] = setting;
370     } else {
371       ThrottleCmd[engineNum] = setting;
372     }
373   } else {
374     cerr << "Throttle " << engineNum << " does not exist! " << ThrottleCmd.size()
375          << " engines exist, but attempted throttle command is for engine "
376          << engineNum << endl;
377   }
378 }
379
380 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
381
382 void FGFCS::SetThrottlePos(int engineNum, double setting)
383 {
384   unsigned int ctr;
385
386   if (engineNum < (int)ThrottlePos.size()) {
387     if (engineNum < 0) {
388       for (ctr=0;ctr<ThrottlePos.size();ctr++) ThrottlePos[ctr] = setting;
389     } else {
390       ThrottlePos[engineNum] = setting;
391     }
392   } else {
393     cerr << "Throttle " << engineNum << " does not exist! " << ThrottlePos.size()
394          << " engines exist, but attempted throttle position setting is for engine "
395          << engineNum << endl;
396   }
397 }
398
399 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
400
401 double FGFCS::GetThrottleCmd(int engineNum) const
402 {
403   if (engineNum < (int)ThrottlePos.size()) {
404     if (engineNum < 0) {
405        cerr << "Cannot get throttle value for ALL engines" << endl;
406     } else {
407       return ThrottleCmd[engineNum];
408     }
409   } else {
410     cerr << "Throttle " << engineNum << " does not exist! " << ThrottleCmd.size()
411          << " engines exist, but throttle setting for engine " << engineNum
412          << " is selected" << endl;
413   }
414   return 0.0;
415 }
416
417 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
418
419 double FGFCS::GetThrottlePos(int engineNum) const
420 {
421   if (engineNum < (int)ThrottlePos.size()) {
422     if (engineNum < 0) {
423        cerr << "Cannot get throttle value for ALL engines" << endl;
424     } else {
425       return ThrottlePos[engineNum];
426     }
427   } else {
428     cerr << "Throttle " << engineNum << " does not exist! " << ThrottlePos.size()
429          << " engines exist, but attempted throttle position setting is for engine "
430          << engineNum << endl;
431   }
432   return 0.0;
433 }
434
435 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
436
437 void FGFCS::SetMixtureCmd(int engineNum, double setting)
438 {
439   unsigned int ctr;
440
441   if (engineNum < (int)ThrottlePos.size()) {
442     if (engineNum < 0) {
443       for (ctr=0;ctr<MixtureCmd.size();ctr++) MixtureCmd[ctr] = setting;
444     } else {
445       MixtureCmd[engineNum] = setting;
446     }
447   }
448 }
449
450 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
451
452 void FGFCS::SetMixturePos(int engineNum, double setting)
453 {
454   unsigned int ctr;
455
456   if (engineNum < (int)ThrottlePos.size()) {
457     if (engineNum < 0) {
458       for (ctr=0;ctr<MixtureCmd.size();ctr++) MixturePos[ctr] = MixtureCmd[ctr];
459     } else {
460       MixturePos[engineNum] = setting;
461     }
462   }
463 }
464
465 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
466
467 void FGFCS::SetPropAdvanceCmd(int engineNum, double setting)
468 {
469   unsigned int ctr;
470
471   if (engineNum < (int)ThrottlePos.size()) {
472     if (engineNum < 0) {
473       for (ctr=0;ctr<PropAdvanceCmd.size();ctr++) PropAdvanceCmd[ctr] = setting;
474     } else {
475       PropAdvanceCmd[engineNum] = setting;
476     }
477   }
478 }
479
480 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
481
482 void FGFCS::SetPropAdvance(int engineNum, double setting)
483 {
484   unsigned int ctr;
485
486   if (engineNum < (int)ThrottlePos.size()) {
487     if (engineNum < 0) {
488       for (ctr=0;ctr<PropAdvanceCmd.size();ctr++) PropAdvance[ctr] = PropAdvanceCmd[ctr];
489     } else {
490       PropAdvance[engineNum] = setting;
491     }
492   }
493 }
494
495 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
496
497 void FGFCS::SetFeatherCmd(int engineNum, bool setting)
498 {
499   unsigned int ctr;
500
501   if (engineNum < (int)ThrottlePos.size()) {
502     if (engineNum < 0) {
503       for (ctr=0;ctr<PropFeatherCmd.size();ctr++) PropFeatherCmd[ctr] = setting;
504     } else {
505       PropFeatherCmd[engineNum] = setting;
506     }
507   }
508 }
509
510 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
511
512 void FGFCS::SetPropFeather(int engineNum, bool setting)
513 {
514   unsigned int ctr;
515
516   if (engineNum < (int)ThrottlePos.size()) {
517     if (engineNum < 0) {
518       for (ctr=0;ctr<PropFeatherCmd.size();ctr++) PropFeather[ctr] = PropFeatherCmd[ctr];
519     } else {
520       PropFeather[engineNum] = setting;
521     }
522   }
523 }
524
525 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
526
527 bool FGFCS::Load(Element* el, SystemType systype)
528 {
529   string name, file, fname="", interface_property_string, parent_name;
530   vector <FGFCSComponent*> *Components;
531   Element *component_element;
532   Element *channel_element;
533
534   Components=0;
535
536 // ToDo: The handling of name and file attributes could be improved, here,
537 //       considering that a name can be in the external file, as well.
538
539   name = el->GetAttributeValue("name");
540
541   if (name.empty() || !el->GetAttributeValue("file").empty()) {
542     fname = el->GetAttributeValue("file");
543     if (systype == stSystem) {
544       file = FindSystemFullPathname(fname);
545     } else { 
546       file = FDMExec->GetFullAircraftPath() + "/" + fname + ".xml";
547     }
548     if (fname.empty()) {
549       cerr << "FCS, Autopilot, or system does not appear to be defined inline nor in a file" << endl;
550       return false;
551     } else {
552       document = LoadXMLDocument(file);
553       if (!document) {
554         cerr << "Error loading file " << file << endl;
555         return false;
556       }
557       name = document->GetAttributeValue("name");
558     }
559   } else {
560     document = el;
561   }
562
563   if (document->GetName() == "autopilot") {
564     Components = &APComponents;
565     Name = "Autopilot: " + document->GetAttributeValue("name");
566   } else if (document->GetName() == "flight_control") {
567     Components = &FCSComponents;
568     Name = "FCS: " + document->GetAttributeValue("name");
569   } else if (document->GetName() == "system") {
570     Components = &Systems;
571     Name = "System: " + document->GetAttributeValue("name");
572   }
573   Debug(2);
574
575   if (document->GetName() == "flight_control") bindModel();
576
577   FGModel::Load(document); // Load interface properties from document
578
579   // After reading interface properties in a file, read properties in the local
580   // flight_control, autopilot, or system element. This allows general-purpose
581   // systems to be defined in a file, with overrides or initial loaded constants
582   // supplied in the relevant element of the aircraft configuration file.
583
584   Element* property_element = 0;
585
586   if (!fname.empty()) {
587     property_element = el->FindElement("property");
588     if (property_element && debug_lvl > 0) cout << endl << "    Overriding properties" << endl << endl;
589     while (property_element) {
590       double value=0.0;
591       if ( ! property_element->GetAttributeValue("value").empty())
592         value = property_element->GetAttributeValueAsNumber("value");
593
594       interface_property_string = property_element->GetDataLine();
595       if (PropertyManager->HasNode(interface_property_string)) {
596         FGPropertyManager* node = PropertyManager->GetNode(interface_property_string);
597         if (debug_lvl > 0)
598           cout << "      " << "Overriding value for property " << interface_property_string
599                << " (old value: " << node->getDoubleValue() << "  new value: " << value << ")" << endl;
600         node->setDoubleValue(value);
601       } else {
602         interface_properties.push_back(new double(value));
603         PropertyManager->Tie(interface_property_string, interface_properties.back());
604         if (debug_lvl > 0)
605           cout << "      " << interface_property_string << " (initial value: " << value << ")" << endl;
606       }
607       
608       property_element = el->FindNextElement("property");
609     }
610   }
611
612   channel_element = document->FindElement("channel");
613   while (channel_element) {
614   
615     if (debug_lvl > 0)
616       cout << endl << highint << fgblue << "    Channel " 
617          << normint << channel_element->GetAttributeValue("name") << reset << endl;
618   
619     component_element = channel_element->GetElement();
620     while (component_element) {
621       try {
622         if ((component_element->GetName() == string("lag_filter")) ||
623             (component_element->GetName() == string("lead_lag_filter")) ||
624             (component_element->GetName() == string("washout_filter")) ||
625             (component_element->GetName() == string("second_order_filter")) ||
626             (component_element->GetName() == string("integrator")) )
627         {
628           Components->push_back(new FGFilter(this, component_element));
629         } else if ((component_element->GetName() == string("pure_gain")) ||
630                    (component_element->GetName() == string("scheduled_gain")) ||
631                    (component_element->GetName() == string("aerosurface_scale")))
632         {
633           Components->push_back(new FGGain(this, component_element));
634         } else if (component_element->GetName() == string("summer")) {
635           Components->push_back(new FGSummer(this, component_element));
636         } else if (component_element->GetName() == string("deadband")) {
637           Components->push_back(new FGDeadBand(this, component_element));
638         } else if (component_element->GetName() == string("switch")) {
639           Components->push_back(new FGSwitch(this, component_element));
640         } else if (component_element->GetName() == string("kinematic")) {
641           Components->push_back(new FGKinemat(this, component_element));
642         } else if (component_element->GetName() == string("fcs_function")) {
643           Components->push_back(new FGFCSFunction(this, component_element));
644         } else if (component_element->GetName() == string("pid")) {
645           Components->push_back(new FGPID(this, component_element));
646         } else if (component_element->GetName() == string("actuator")) {
647           Components->push_back(new FGActuator(this, component_element));
648         } else if (component_element->GetName() == string("sensor")) {
649           Components->push_back(new FGSensor(this, component_element));
650         } else if (component_element->GetName() == string("accelerometer")) {
651           Components->push_back(new FGAccelerometer(this, component_element));
652         } else if (component_element->GetName() == string("magnetometer")) {
653           Components->push_back(new FGMagnetometer(this, component_element));
654         } else if (component_element->GetName() == string("gyro")) {
655           Components->push_back(new FGGyro(this, component_element));
656         } else {
657           cerr << "Unknown FCS component: " << component_element->GetName() << endl;
658         }
659       } catch(string s) {
660         cerr << highint << fgred << endl << "  " << s << endl;
661         cerr << reset << endl;
662         return false;
663       }
664       component_element = channel_element->GetNextElement();
665     }
666     channel_element = document->FindNextElement("channel");
667   }
668
669   ResetParser();
670
671   return true;
672 }
673
674 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
675
676 double FGFCS::GetBrake(FGLGear::BrakeGroup bg)
677 {
678   switch (bg) {
679   case FGLGear::bgLeft:
680     return LeftBrake;
681   case FGLGear::bgRight:
682     return RightBrake;
683   case FGLGear::bgCenter:
684     return CenterBrake;
685   default:
686     cerr << "GetBrake asked to return a bogus brake value" << endl;
687   }
688   return 0.0;
689 }
690
691 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
692
693 string FGFCS::FindSystemFullPathname(const string& sysfilename)
694 {
695   string fullpath, localpath;
696   string system_filename = sysfilename;
697   string systemPath = FDMExec->GetSystemsPath();
698   string aircraftPath = FDMExec->GetFullAircraftPath();
699   ifstream system_file;
700
701   fullpath = systemPath + "/";
702   localpath = aircraftPath + "/Systems/";
703
704   if (system_filename.length() <=4 || system_filename.substr(system_filename.length()-4, 4) != ".xml") {
705     system_filename.append(".xml");
706   }
707
708   system_file.open(string(fullpath + system_filename).c_str());
709   if ( !system_file.is_open()) {
710     system_file.open(string(localpath + system_filename).c_str());
711       if ( !system_file.is_open()) {
712         cerr << " Could not open system file: " << system_filename << " in path "
713              << fullpath << " or " << localpath << endl;
714         return string("");
715       } else {
716         return string(localpath + system_filename);
717       }
718   }
719   return string(fullpath + system_filename);
720 }
721
722 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
723
724 ifstream* FGFCS::FindSystemFile(const string& sysfilename)
725 {
726   string fullpath, localpath;
727   string system_filename = sysfilename;
728   string systemPath = FDMExec->GetSystemsPath();
729   string aircraftPath = FDMExec->GetFullAircraftPath();
730   ifstream* system_file = new ifstream();
731
732   fullpath = systemPath + "/";
733   localpath = aircraftPath + "/Systems/";
734
735   if (system_filename.substr(system_filename.length()-4, 4) != ".xml") {
736     system_filename.append(".xml");
737   }
738
739   system_file->open(string(fullpath + system_filename).c_str());
740   if ( !system_file->is_open()) {
741     system_file->open(string(localpath + system_filename).c_str());
742       if ( !system_file->is_open()) {
743         cerr << " Could not open system file: " << system_filename << " in path "
744              << fullpath << " or " << localpath << endl;
745       }
746   }
747   return system_file;
748 }
749
750 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
751
752 string FGFCS::GetComponentStrings(const string& delimiter)
753 {
754   unsigned int comp;
755   string CompStrings = "";
756   bool firstime = true;
757   int total_count=0;
758
759   for (unsigned int i=0; i<Systems.size(); i++) {
760     if (firstime) firstime = false;
761     else          CompStrings += delimiter;
762
763     CompStrings += Systems[i]->GetName();
764     total_count++;
765   }
766
767   for (comp = 0; comp < APComponents.size(); comp++)
768   {
769     if (firstime) firstime = false;
770     else          CompStrings += delimiter;
771
772     CompStrings += APComponents[comp]->GetName();
773     total_count++;
774   }
775
776   for (comp = 0; comp < FCSComponents.size(); comp++) {
777     if (firstime) firstime = false;
778     else          CompStrings += delimiter;
779
780     CompStrings += FCSComponents[comp]->GetName();
781     total_count++;
782   }
783
784   return CompStrings;
785 }
786
787 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
788
789 string FGFCS::GetComponentValues(const string& delimiter)
790 {
791   std::ostringstream buf;
792
793   unsigned int comp;
794   bool firstime = true;
795   int total_count=0;
796
797   for (unsigned int i=0; i<Systems.size(); i++) {
798     if (firstime) firstime = false;
799     else          buf << delimiter;
800
801     buf << setprecision(9) << Systems[i]->GetOutput();
802     total_count++;
803   }
804
805   for (comp = 0; comp < APComponents.size(); comp++) {
806     if (firstime) firstime = false;
807     else          buf << delimiter;
808
809     buf << setprecision(9) << APComponents[comp]->GetOutput();
810     total_count++;
811   }
812
813   for (comp = 0; comp < FCSComponents.size(); comp++) {
814     if (firstime) firstime = false;
815     else          buf << delimiter;
816
817     buf << setprecision(9) << FCSComponents[comp]->GetOutput();
818     total_count++;
819   }
820
821   return buf.str();
822 }
823
824 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
825
826 void FGFCS::AddThrottle(void)
827 {
828   ThrottleCmd.push_back(0.0);
829   ThrottlePos.push_back(0.0);
830   MixtureCmd.push_back(0.0);     // assume throttle and mixture are coupled
831   MixturePos.push_back(0.0);
832   PropAdvanceCmd.push_back(0.0); // assume throttle and prop pitch are coupled
833   PropAdvance.push_back(0.0);
834   PropFeatherCmd.push_back(false);
835   PropFeather.push_back(false);
836
837   unsigned int num = (unsigned int)ThrottleCmd.size()-1;
838   bindThrottle(num);
839 }
840
841 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
842
843 void FGFCS::AddGear(void)
844 {
845   SteerPosDeg.push_back(0.0);
846 }
847
848 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
849
850 double FGFCS::GetDt(void)
851 {
852   return FDMExec->GetDeltaT()*rate;
853 }
854
855 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
856
857 void FGFCS::bind(void)
858 {
859   PropertyManager->Tie("fcs/aileron-cmd-norm", this, &FGFCS::GetDaCmd, &FGFCS::SetDaCmd);
860   PropertyManager->Tie("fcs/elevator-cmd-norm", this, &FGFCS::GetDeCmd, &FGFCS::SetDeCmd);
861   PropertyManager->Tie("fcs/rudder-cmd-norm", this, &FGFCS::GetDrCmd, &FGFCS::SetDrCmd);
862   PropertyManager->Tie("fcs/flap-cmd-norm", this, &FGFCS::GetDfCmd, &FGFCS::SetDfCmd);
863   PropertyManager->Tie("fcs/speedbrake-cmd-norm", this, &FGFCS::GetDsbCmd, &FGFCS::SetDsbCmd);
864   PropertyManager->Tie("fcs/spoiler-cmd-norm", this, &FGFCS::GetDspCmd, &FGFCS::SetDspCmd);
865   PropertyManager->Tie("fcs/pitch-trim-cmd-norm", this, &FGFCS::GetPitchTrimCmd, &FGFCS::SetPitchTrimCmd);
866   PropertyManager->Tie("fcs/roll-trim-cmd-norm", this, &FGFCS::GetRollTrimCmd, &FGFCS::SetRollTrimCmd);
867   PropertyManager->Tie("fcs/yaw-trim-cmd-norm", this, &FGFCS::GetYawTrimCmd, &FGFCS::SetYawTrimCmd);
868
869   PropertyManager->Tie("fcs/left-aileron-pos-rad", this, ofRad, &FGFCS::GetDaLPos, &FGFCS::SetDaLPos);
870   PropertyManager->Tie("fcs/left-aileron-pos-deg", this, ofDeg, &FGFCS::GetDaLPos, &FGFCS::SetDaLPos);
871   PropertyManager->Tie("fcs/left-aileron-pos-norm", this, ofNorm, &FGFCS::GetDaLPos, &FGFCS::SetDaLPos);
872   PropertyManager->Tie("fcs/mag-left-aileron-pos-rad", this, ofMag, &FGFCS::GetDaLPos);
873
874   PropertyManager->Tie("fcs/right-aileron-pos-rad", this, ofRad, &FGFCS::GetDaRPos, &FGFCS::SetDaRPos);
875   PropertyManager->Tie("fcs/right-aileron-pos-deg", this, ofDeg, &FGFCS::GetDaRPos, &FGFCS::SetDaRPos);
876   PropertyManager->Tie("fcs/right-aileron-pos-norm", this, ofNorm, &FGFCS::GetDaRPos, &FGFCS::SetDaRPos);
877   PropertyManager->Tie("fcs/mag-right-aileron-pos-rad", this, ofMag, &FGFCS::GetDaRPos);
878
879   PropertyManager->Tie("fcs/elevator-pos-rad", this, ofRad, &FGFCS::GetDePos, &FGFCS::SetDePos);
880   PropertyManager->Tie("fcs/elevator-pos-deg", this, ofDeg, &FGFCS::GetDePos, &FGFCS::SetDePos);
881   PropertyManager->Tie("fcs/elevator-pos-norm", this, ofNorm, &FGFCS::GetDePos, &FGFCS::SetDePos);
882   PropertyManager->Tie("fcs/mag-elevator-pos-rad", this, ofMag, &FGFCS::GetDePos);
883
884   PropertyManager->Tie("fcs/rudder-pos-rad", this,ofRad, &FGFCS::GetDrPos, &FGFCS::SetDrPos);
885   PropertyManager->Tie("fcs/rudder-pos-deg", this,ofDeg, &FGFCS::GetDrPos, &FGFCS::SetDrPos);
886   PropertyManager->Tie("fcs/rudder-pos-norm", this,ofNorm, &FGFCS::GetDrPos, &FGFCS::SetDrPos);
887   PropertyManager->Tie("fcs/mag-rudder-pos-rad", this,ofMag, &FGFCS::GetDrPos);
888
889   PropertyManager->Tie("fcs/flap-pos-rad", this,ofRad, &FGFCS::GetDfPos, &FGFCS::SetDfPos);
890   PropertyManager->Tie("fcs/flap-pos-deg", this,ofDeg, &FGFCS::GetDfPos, &FGFCS::SetDfPos);
891   PropertyManager->Tie("fcs/flap-pos-norm", this,ofNorm, &FGFCS::GetDfPos, &FGFCS::SetDfPos);
892
893   PropertyManager->Tie("fcs/speedbrake-pos-rad", this,ofRad, &FGFCS::GetDsbPos, &FGFCS::SetDsbPos);
894   PropertyManager->Tie("fcs/speedbrake-pos-deg", this,ofDeg, &FGFCS::GetDsbPos, &FGFCS::SetDsbPos);
895   PropertyManager->Tie("fcs/speedbrake-pos-norm", this,ofNorm, &FGFCS::GetDsbPos, &FGFCS::SetDsbPos);
896   PropertyManager->Tie("fcs/mag-speedbrake-pos-rad", this,ofMag, &FGFCS::GetDsbPos);
897
898   PropertyManager->Tie("fcs/spoiler-pos-rad", this, ofRad, &FGFCS::GetDspPos, &FGFCS::SetDspPos);
899   PropertyManager->Tie("fcs/spoiler-pos-deg", this, ofDeg, &FGFCS::GetDspPos, &FGFCS::SetDspPos);
900   PropertyManager->Tie("fcs/spoiler-pos-norm", this, ofNorm, &FGFCS::GetDspPos, &FGFCS::SetDspPos);
901   PropertyManager->Tie("fcs/mag-spoiler-pos-rad", this, ofMag, &FGFCS::GetDspPos);
902
903   PropertyManager->Tie("gear/gear-pos-norm", this, &FGFCS::GetGearPos, &FGFCS::SetGearPos);
904   PropertyManager->Tie("gear/gear-cmd-norm", this, &FGFCS::GetGearCmd, &FGFCS::SetGearCmd);
905   PropertyManager->Tie("fcs/left-brake-cmd-norm", this, &FGFCS::GetLBrake, &FGFCS::SetLBrake);
906   PropertyManager->Tie("fcs/right-brake-cmd-norm", this, &FGFCS::GetRBrake, &FGFCS::SetRBrake);
907   PropertyManager->Tie("fcs/center-brake-cmd-norm", this, &FGFCS::GetCBrake, &FGFCS::SetCBrake);
908   PropertyManager->Tie("fcs/steer-cmd-norm", this, &FGFCS::GetDsCmd, &FGFCS::SetDsCmd);
909
910   PropertyManager->Tie("gear/tailhook-pos-norm", this, &FGFCS::GetTailhookPos, &FGFCS::SetTailhookPos);
911   PropertyManager->Tie("fcs/wing-fold-pos-norm", this, &FGFCS::GetWingFoldPos, &FGFCS::SetWingFoldPos);
912 }
913
914 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
915 // Technically, this function should probably bind propulsion type specific controls
916 // rather than mixture and prop-advance.
917
918 void FGFCS::bindThrottle(unsigned int num)
919 {
920   string tmp;
921
922   tmp = CreateIndexedPropertyName("fcs/throttle-cmd-norm", num);
923   PropertyManager->Tie( tmp.c_str(), this, num, &FGFCS::GetThrottleCmd,
924                                         &FGFCS::SetThrottleCmd);
925   tmp = CreateIndexedPropertyName("fcs/throttle-pos-norm", num);
926   PropertyManager->Tie( tmp.c_str(), this, num, &FGFCS::GetThrottlePos,
927                                         &FGFCS::SetThrottlePos);
928   tmp = CreateIndexedPropertyName("fcs/mixture-cmd-norm", num);
929   PropertyManager->Tie( tmp.c_str(), this, num, &FGFCS::GetMixtureCmd,
930                                         &FGFCS::SetMixtureCmd);
931   tmp = CreateIndexedPropertyName("fcs/mixture-pos-norm", num);
932   PropertyManager->Tie( tmp.c_str(), this, num, &FGFCS::GetMixturePos,
933                                         &FGFCS::SetMixturePos);
934   tmp = CreateIndexedPropertyName("fcs/advance-cmd-norm", num);
935   PropertyManager->Tie( tmp.c_str(), this, num, &FGFCS::GetPropAdvanceCmd,
936                                         &FGFCS::SetPropAdvanceCmd);
937   tmp = CreateIndexedPropertyName("fcs/advance-pos-norm", num);
938   PropertyManager->Tie( tmp.c_str(), this, num, &FGFCS::GetPropAdvance,
939                                         &FGFCS::SetPropAdvance);
940   tmp = CreateIndexedPropertyName("fcs/feather-cmd-norm", num);
941   PropertyManager->Tie( tmp.c_str(), this, num, &FGFCS::GetFeatherCmd,
942                                         &FGFCS::SetFeatherCmd);
943   tmp = CreateIndexedPropertyName("fcs/feather-pos-norm", num);
944   PropertyManager->Tie( tmp.c_str(), this, num, &FGFCS::GetPropFeather,
945                                         &FGFCS::SetPropFeather);
946 }
947
948 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
949
950 void FGFCS::bindModel(void)
951 {
952   unsigned int i;
953   string tmp;
954
955   for (i=0; i<SteerPosDeg.size(); i++) {
956     if (GroundReactions->GetGearUnit(i)->GetSteerable()) {
957       tmp = CreateIndexedPropertyName("fcs/steer-pos-deg", i);
958       PropertyManager->Tie( tmp.c_str(), this, i, &FGFCS::GetSteerPosDeg, &FGFCS::SetSteerPosDeg);
959     }
960   }
961 }
962
963 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
964 //    The bitmasked value choices are as follows:
965 //    unset: In this case (the default) JSBSim would only print
966 //       out the normally expected messages, essentially echoing
967 //       the config files as they are read. If the environment
968 //       variable is not set, debug_lvl is set to 1 internally
969 //    0: This requests JSBSim not to output any messages
970 //       whatsoever.
971 //    1: This value explicity requests the normal JSBSim
972 //       startup messages
973 //    2: This value asks for a message to be printed out when
974 //       a class is instantiated
975 //    4: When this value is set, a message is displayed when a
976 //       FGModel object executes its Run() method
977 //    8: When this value is set, various runtime state variables
978 //       are printed out periodically
979 //    16: When set various parameters are sanity checked and
980 //       a message is printed out when they go out of bounds
981
982 void FGFCS::Debug(int from)
983 {
984   if (debug_lvl <= 0) return;
985
986   if (debug_lvl & 1) { // Standard console startup message output
987     if (from == 2) { // Loader
988       cout << endl << "  " << Name << endl;
989     }
990   }
991   if (debug_lvl & 2 ) { // Instantiation/Destruction notification
992     if (from == 0) cout << "Instantiated: FGFCS" << endl;
993     if (from == 1) cout << "Destroyed:    FGFCS" << endl;
994   }
995   if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
996   }
997   if (debug_lvl & 8 ) { // Runtime state variables
998   }
999   if (debug_lvl & 16) { // Sanity checking
1000   }
1001   if (debug_lvl & 64) {
1002     if (from == 0) { // Constructor
1003       cout << IdSrc << endl;
1004       cout << IdHdr << endl;
1005     }
1006   }
1007 }
1008
1009 }