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