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