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