1 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6 Purpose: Model the flight controls
9 ------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) -------------
11 This program is free software; you can redistribute it and/or modify it under
12 the terms of the GNU General Public License as published by the Free Software
13 Foundation; either version 2 of the License, or (at your option) any later
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 General Public License for more
21 You should have received a copy of the GNU 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.
25 Further information about the GNU General Public License can also be found on
26 the world wide web at http://www.gnu.org.
28 FUNCTIONAL DESCRIPTION
29 --------------------------------------------------------------------------------
30 This class models the flight controls for a specific airplane
33 --------------------------------------------------------------------------------
36 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
38 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
41 #include <FGFDMExec.h>
42 #include <input_output/FGPropertyManager.h>
45 #include <models/flight_control/FGFilter.h>
46 #include <models/flight_control/FGDeadBand.h>
47 #include <models/flight_control/FGGain.h>
48 #include <models/flight_control/FGGradient.h>
49 #include <models/flight_control/FGSwitch.h>
50 #include <models/flight_control/FGSummer.h>
51 #include <models/flight_control/FGKinemat.h>
52 #include <models/flight_control/FGFCSFunction.h>
53 #include <models/flight_control/FGSensor.h>
57 static const char *IdSrc = "$Id$";
58 static const char *IdHdr = ID_FCS;
60 #if defined(WIN32) && !defined(__CYGWIN__)
61 #define snprintf _snprintf
64 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
66 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
68 FGFCS::FGFCS(FGFDMExec* fdmex) : FGModel(fdmex)
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;
79 for (i=0;i<=NForms;i++) {
80 DePos[i] = DaLPos[i] = DaRPos[i] = DrPos[i] = 0.0;
81 DfPos[i] = DsbPos[i] = DspPos[i] = 0.0;
87 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
91 if (PropertyManager->HasNode("fcs")) unbind( PropertyManager->GetNode("fcs") );
92 if (PropertyManager->HasNode("ap")) unbind( PropertyManager->GetNode("ap") );
93 PropertyManager->Untie( "gear/gear-cmd-norm" );
94 PropertyManager->Untie( "gear/gear-pos-norm" );
100 PropAdvanceCmd.clear();
103 PropFeatherCmd.clear();
108 for (i=0;i<APComponents.size();i++) delete APComponents[i];
109 for (i=0;i<FCSComponents.size();i++) delete FCSComponents[i];
110 for (i=0;i<sensors.size();i++) delete sensors[i];
112 APComponents.clear();
113 FCSComponents.clear();
115 interface_properties.clear();
120 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
121 // Notes: In this logic the default engine commands are set. This is simply a
122 // sort of safe-mode method in case the user has not defined control laws for
123 // throttle, mixture, and prop-advance. The throttle, mixture, and prop advance
124 // positions are set equal to the respective commands. Any control logic that is
125 // actually present in the flight_control or autopilot section will override
126 // these simple assignments.
128 bool FGFCS::Run(void)
132 if (FGModel::Run()) return true; // fast exit if nothing to do
133 if (FDMExec->Holding()) return false;
135 for (i=0; i<ThrottlePos.size(); i++) ThrottlePos[i] = ThrottleCmd[i];
136 for (i=0; i<MixturePos.size(); i++) MixturePos[i] = MixtureCmd[i];
137 for (i=0; i<PropAdvance.size(); i++) PropAdvance[i] = PropAdvanceCmd[i];
138 for (i=0; i<PropFeather.size(); i++) PropFeather[i] = PropFeatherCmd[i];
141 // Set the default steering angle
142 for (i=0; i<SteerPosDeg.size(); i++) {
143 FGLGear* gear = GroundReactions->GetGearUnit(i);
144 SteerPosDeg[i] = gear->GetDefaultSteerAngle( GetDsCmd() );
147 // Cycle through the sensor, autopilot, and flight control components
148 for (i=0; i<sensors.size(); i++) sensors[i]->Run();
149 for (i=0; i<APComponents.size(); i++) APComponents[i]->Run();
150 for (i=0; i<FCSComponents.size(); i++) FCSComponents[i]->Run();
155 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
157 void FGFCS::SetDaLPos( int form , double pos )
162 DaLPos[ofDeg] = pos*radtodeg;
165 DaLPos[ofRad] = pos*degtorad;
169 DaLPos[ofNorm] = pos;
171 DaLPos[ofMag] = fabs(DaLPos[ofRad]);
174 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
176 void FGFCS::SetDaRPos( int form , double pos )
181 DaRPos[ofDeg] = pos*radtodeg;
184 DaRPos[ofRad] = pos*degtorad;
188 DaRPos[ofNorm] = pos;
190 DaRPos[ofMag] = fabs(DaRPos[ofRad]);
193 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
195 void FGFCS::SetDePos( int form , double pos )
200 DePos[ofDeg] = pos*radtodeg;
203 DePos[ofRad] = pos*degtorad;
209 DePos[ofMag] = fabs(DePos[ofRad]);
212 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
214 void FGFCS::SetDrPos( int form , double pos )
219 DrPos[ofDeg] = pos*radtodeg;
222 DrPos[ofRad] = pos*degtorad;
228 DrPos[ofMag] = fabs(DrPos[ofRad]);
231 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
233 void FGFCS::SetDfPos( int form , double pos )
238 DfPos[ofDeg] = pos*radtodeg;
241 DfPos[ofRad] = pos*degtorad;
247 DfPos[ofMag] = fabs(DfPos[ofRad]);
250 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
252 void FGFCS::SetDsbPos( int form , double pos )
257 DsbPos[ofDeg] = pos*radtodeg;
260 DsbPos[ofRad] = pos*degtorad;
264 DsbPos[ofNorm] = pos;
266 DsbPos[ofMag] = fabs(DsbPos[ofRad]);
269 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
271 void FGFCS::SetDspPos( int form , double pos )
276 DspPos[ofDeg] = pos*radtodeg;
279 DspPos[ofRad] = pos*degtorad;
283 DspPos[ofNorm] = pos;
285 DspPos[ofMag] = fabs(DspPos[ofRad]);
288 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
290 void FGFCS::SetThrottleCmd(int engineNum, double setting)
294 if (engineNum < (int)ThrottlePos.size()) {
296 for (ctr=0;ctr<ThrottleCmd.size();ctr++) ThrottleCmd[ctr] = setting;
298 ThrottleCmd[engineNum] = setting;
301 cerr << "Throttle " << engineNum << " does not exist! " << ThrottleCmd.size()
302 << " engines exist, but attempted throttle command is for engine "
303 << engineNum << endl;
307 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
309 void FGFCS::SetThrottlePos(int engineNum, double setting)
313 if (engineNum < (int)ThrottlePos.size()) {
315 for (ctr=0;ctr<ThrottlePos.size();ctr++) ThrottlePos[ctr] = setting;
317 ThrottlePos[engineNum] = setting;
320 cerr << "Throttle " << engineNum << " does not exist! " << ThrottlePos.size()
321 << " engines exist, but attempted throttle position setting is for engine "
322 << engineNum << endl;
326 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
328 double FGFCS::GetThrottleCmd(int engineNum) const
330 if (engineNum < (int)ThrottlePos.size()) {
332 cerr << "Cannot get throttle value for ALL engines" << endl;
334 return ThrottleCmd[engineNum];
337 cerr << "Throttle " << engineNum << " does not exist! " << ThrottleCmd.size()
338 << " engines exist, but throttle setting for engine " << engineNum
339 << " is selected" << endl;
344 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
346 double FGFCS::GetThrottlePos(int engineNum) const
348 if (engineNum < (int)ThrottlePos.size()) {
350 cerr << "Cannot get throttle value for ALL engines" << endl;
352 return ThrottlePos[engineNum];
355 cerr << "Throttle " << engineNum << " does not exist! " << ThrottlePos.size()
356 << " engines exist, but attempted throttle position setting is for engine "
357 << engineNum << endl;
362 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
364 void FGFCS::SetMixtureCmd(int engineNum, double setting)
368 if (engineNum < (int)ThrottlePos.size()) {
370 for (ctr=0;ctr<MixtureCmd.size();ctr++) MixtureCmd[ctr] = setting;
372 MixtureCmd[engineNum] = setting;
377 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
379 void FGFCS::SetMixturePos(int engineNum, double setting)
383 if (engineNum < (int)ThrottlePos.size()) {
385 for (ctr=0;ctr<=MixtureCmd.size();ctr++) MixturePos[ctr] = MixtureCmd[ctr];
387 MixturePos[engineNum] = setting;
392 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
394 void FGFCS::SetPropAdvanceCmd(int engineNum, double setting)
398 if (engineNum < (int)ThrottlePos.size()) {
400 for (ctr=0;ctr<PropAdvanceCmd.size();ctr++) PropAdvanceCmd[ctr] = setting;
402 PropAdvanceCmd[engineNum] = setting;
407 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
409 void FGFCS::SetPropAdvance(int engineNum, double setting)
413 if (engineNum < (int)ThrottlePos.size()) {
415 for (ctr=0;ctr<=PropAdvanceCmd.size();ctr++) PropAdvance[ctr] = PropAdvanceCmd[ctr];
417 PropAdvance[engineNum] = setting;
422 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
424 void FGFCS::SetFeatherCmd(int engineNum, bool setting)
428 if (engineNum < (int)ThrottlePos.size()) {
430 for (ctr=0;ctr<PropFeatherCmd.size();ctr++) PropFeatherCmd[ctr] = setting;
432 PropFeatherCmd[engineNum] = setting;
437 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
439 void FGFCS::SetPropFeather(int engineNum, bool setting)
443 if (engineNum < (int)ThrottlePos.size()) {
445 for (ctr=0;ctr<=PropFeatherCmd.size();ctr++) PropFeather[ctr] = PropFeatherCmd[ctr];
447 PropFeather[engineNum] = setting;
452 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
454 bool FGFCS::Load(Element* el)
456 string name, file, fname, comp_name, interface_property_string;
458 vector <FGFCSComponent*> *Components;
459 Element *FCS_cfg, *document, *component_element, *property_element, *sensor_element;
460 Element *channel_element;
461 ifstream* controls_file = new ifstream();
462 FGXMLParse controls_file_parser;
465 // Determine if the FCS/Autopilot is defined inline in the aircraft configuration
466 // file or in a separate file. Set up the Element pointer as appropriate.
468 string separator = "/";
473 name = el->GetAttributeValue("name");
476 fname = el->GetAttributeValue("file");
477 file = FDMExec->GetAircraftPath() + separator + FDMExec->GetModelName() + separator + fname + ".xml";
479 cerr << "FCS/Autopilot does not appear to be defined inline nor in a file" << endl;
482 controls_file->open(file.c_str());
483 readXML(*controls_file, controls_file_parser);
484 delete controls_file;
485 document = controls_file_parser.GetDocument();
491 if (document->GetName() == "autopilot") {
492 Components = &APComponents;
493 Name = "Autopilot: " + document->GetAttributeValue("name");
494 } else if (document->GetName() == "flight_control") {
495 Components = &FCSComponents;
496 Name = "FCS: " + document->GetAttributeValue("name");
501 // ToDo: How do these get untied?
502 // ToDo: Consider having INPUT and OUTPUT interface properties. Would then
503 // have to duplicate this block of code after channel read code.
504 // Input properties could be write only (nah), and output could be read
507 if (document->GetName() == "flight_control") bindModel();
509 property_element = document->FindElement("property");
510 while (property_element) {
511 interface_properties.push_back(new double(0));
512 interface_property_string = property_element->GetDataLine();
513 PropertyManager->Tie(interface_property_string, interface_properties.back());
514 property_element = document->FindNextElement("property");
517 sensor_element = document->FindElement("sensor");
518 while (sensor_element) {
520 sensors.push_back(new FGSensor(this, sensor_element));
522 cerr << highint << fgred << endl << " " << s << endl;
525 sensor_element = document->FindNextElement("sensor");
528 channel_element = document->FindElement("channel");
529 while (channel_element) {
530 component_element = channel_element->FindElement("component");
531 if (component_element) {
532 cout << "This form of the component specification is being deprecated" << endl;
534 component_element = channel_element->GetElement();
536 while (component_element) {
537 comp_name = component_element->GetAttributeValue("type");
539 if ((comp_name == "LAG_FILTER") ||
540 (comp_name == "LEAD_LAG_FILTER") ||
541 (comp_name == "SECOND_ORDER_FILTER") ||
542 (comp_name == "WASHOUT_FILTER") ||
543 (comp_name == "INTEGRATOR") ||
544 (component_element->GetName() == string("lag_filter")) ||
545 (component_element->GetName() == string("lead_lag_filter")) ||
546 (component_element->GetName() == string("washout_filter")) ||
547 (component_element->GetName() == string("second_order_filter")) ||
548 (component_element->GetName() == string("integrator")) )
550 Components->push_back(new FGFilter(this, component_element));
551 } else if ((comp_name == "PURE_GAIN") ||
552 (comp_name == "SCHEDULED_GAIN") ||
553 (comp_name == "AEROSURFACE_SCALE") ||
554 (component_element->GetName() == string("pure_gain")) ||
555 (component_element->GetName() == string("scheduled_gain")) ||
556 (component_element->GetName() == string("aerosurface_scale")))
558 Components->push_back(new FGGain(this, component_element));
559 } else if ((comp_name == "SUMMER") || (component_element->GetName() == string("summer"))) {
560 Components->push_back(new FGSummer(this, component_element));
561 } else if ((comp_name == "DEADBAND") || (component_element->GetName() == string("deadband"))) {
562 Components->push_back(new FGDeadBand(this, component_element));
563 } else if (comp_name == "GRADIENT") {
564 Components->push_back(new FGGradient(this, component_element));
565 } else if ((comp_name == "SWITCH") || (component_element->GetName() == string("switch"))) {
566 Components->push_back(new FGSwitch(this, component_element));
567 } else if ((comp_name == "KINEMAT") || (component_element->GetName() == string("kinematic"))) {
568 Components->push_back(new FGKinemat(this, component_element));
569 } else if ((comp_name == "FUNCTION") || (component_element->GetName() == string("fcs_function"))) {
570 Components->push_back(new FGFCSFunction(this, component_element));
572 cerr << "Unknown FCS component: " << comp_name << endl;
575 cerr << highint << fgred << endl << " " << s << endl;
576 cerr << reset << endl;
579 if (comp_name.empty()) { // comp_name will be empty if using new format
580 component_element = channel_element->GetNextElement();
582 component_element = channel_element->FindNextElement("component");
585 channel_element = document->FindNextElement("channel");
591 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
593 double FGFCS::GetBrake(FGLGear::BrakeGroup bg)
596 case FGLGear::bgLeft:
598 case FGLGear::bgRight:
600 case FGLGear::bgCenter:
603 cerr << "GetBrake asked to return a bogus brake value" << endl;
608 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
610 string FGFCS::GetComponentStrings(string delimeter)
613 string CompStrings = "";
614 bool firstime = true;
616 for (comp = 0; comp < FCSComponents.size(); comp++) {
617 if (firstime) firstime = false;
618 else CompStrings += delimeter;
620 CompStrings += FCSComponents[comp]->GetName();
623 for (comp = 0; comp < APComponents.size(); comp++)
625 CompStrings += delimeter;
626 CompStrings += APComponents[comp]->GetName();
632 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
634 string FGFCS::GetComponentValues(string delimeter)
637 string CompValues = "";
639 bool firstime = true;
641 for (comp = 0; comp < FCSComponents.size(); comp++) {
642 if (firstime) firstime = false;
643 else CompValues += delimeter;
645 sprintf(buffer, "%9.6f", FCSComponents[comp]->GetOutput());
646 CompValues += string(buffer);
649 for (comp = 0; comp < APComponents.size(); comp++) {
650 sprintf(buffer, "%s%9.6f", delimeter.c_str(), APComponents[comp]->GetOutput());
651 CompValues += string(buffer);
657 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
659 void FGFCS::AddThrottle(void)
661 ThrottleCmd.push_back(0.0);
662 ThrottlePos.push_back(0.0);
663 MixtureCmd.push_back(0.0); // assume throttle and mixture are coupled
664 MixturePos.push_back(0.0);
665 PropAdvanceCmd.push_back(0.0); // assume throttle and prop pitch are coupled
666 PropAdvance.push_back(0.0);
667 PropFeatherCmd.push_back(false);
668 PropFeather.push_back(false);
670 unsigned int num = ThrottleCmd.size()-1;
674 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
676 void FGFCS::AddGear(void)
678 SteerPosDeg.push_back(0.0);
681 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
683 void FGFCS::bind(void)
685 PropertyManager->Tie("fcs/aileron-cmd-norm", this, &FGFCS::GetDaCmd, &FGFCS::SetDaCmd);
686 PropertyManager->Tie("fcs/elevator-cmd-norm", this, &FGFCS::GetDeCmd, &FGFCS::SetDeCmd);
687 PropertyManager->Tie("fcs/rudder-cmd-norm", this, &FGFCS::GetDrCmd, &FGFCS::SetDrCmd);
688 PropertyManager->Tie("fcs/steer-cmd-norm", this, &FGFCS::GetDsCmd, &FGFCS::SetDsCmd);
689 PropertyManager->Tie("fcs/flap-cmd-norm", this, &FGFCS::GetDfCmd, &FGFCS::SetDfCmd);
690 PropertyManager->Tie("fcs/speedbrake-cmd-norm", this, &FGFCS::GetDsbCmd, &FGFCS::SetDsbCmd);
691 PropertyManager->Tie("fcs/spoiler-cmd-norm", this, &FGFCS::GetDspCmd, &FGFCS::SetDspCmd);
692 PropertyManager->Tie("fcs/pitch-trim-cmd-norm", this, &FGFCS::GetPitchTrimCmd, &FGFCS::SetPitchTrimCmd);
693 PropertyManager->Tie("fcs/roll-trim-cmd-norm", this, &FGFCS::GetRollTrimCmd, &FGFCS::SetRollTrimCmd);
694 PropertyManager->Tie("fcs/yaw-trim-cmd-norm", this, &FGFCS::GetYawTrimCmd, &FGFCS::SetYawTrimCmd);
695 PropertyManager->Tie("gear/gear-cmd-norm", this, &FGFCS::GetGearCmd, &FGFCS::SetGearCmd);
697 PropertyManager->Tie("fcs/left-aileron-pos-rad", this, ofRad, &FGFCS::GetDaLPos, &FGFCS::SetDaLPos);
698 PropertyManager->Tie("fcs/left-aileron-pos-deg", this, ofDeg, &FGFCS::GetDaLPos, &FGFCS::SetDaLPos);
699 PropertyManager->Tie("fcs/left-aileron-pos-norm", this, ofNorm, &FGFCS::GetDaLPos, &FGFCS::SetDaLPos);
700 PropertyManager->Tie("fcs/mag-left-aileron-pos-rad", this, ofMag, &FGFCS::GetDaLPos);
702 PropertyManager->Tie("fcs/right-aileron-pos-rad", this, ofRad, &FGFCS::GetDaRPos, &FGFCS::SetDaRPos);
703 PropertyManager->Tie("fcs/right-aileron-pos-deg", this, ofDeg, &FGFCS::GetDaRPos, &FGFCS::SetDaRPos);
704 PropertyManager->Tie("fcs/right-aileron-pos-norm", this, ofNorm, &FGFCS::GetDaRPos, &FGFCS::SetDaRPos);
705 PropertyManager->Tie("fcs/mag-right-aileron-pos-rad", this, ofMag, &FGFCS::GetDaRPos);
707 PropertyManager->Tie("fcs/elevator-pos-rad", this, ofRad, &FGFCS::GetDePos, &FGFCS::SetDePos);
708 PropertyManager->Tie("fcs/elevator-pos-deg", this, ofDeg, &FGFCS::GetDePos, &FGFCS::SetDePos);
709 PropertyManager->Tie("fcs/elevator-pos-norm", this, ofNorm, &FGFCS::GetDePos, &FGFCS::SetDePos);
710 PropertyManager->Tie("fcs/mag-elevator-pos-rad", this, ofMag, &FGFCS::GetDePos);
712 PropertyManager->Tie("fcs/rudder-pos-rad", this,ofRad, &FGFCS::GetDrPos, &FGFCS::SetDrPos);
713 PropertyManager->Tie("fcs/rudder-pos-deg", this,ofDeg, &FGFCS::GetDrPos, &FGFCS::SetDrPos);
714 PropertyManager->Tie("fcs/rudder-pos-norm", this,ofNorm, &FGFCS::GetDrPos, &FGFCS::SetDrPos);
715 PropertyManager->Tie("fcs/mag-rudder-pos-rad", this,ofMag, &FGFCS::GetDrPos);
717 PropertyManager->Tie("fcs/flap-pos-rad", this,ofRad, &FGFCS::GetDfPos, &FGFCS::SetDfPos);
718 PropertyManager->Tie("fcs/flap-pos-deg", this,ofDeg, &FGFCS::GetDfPos, &FGFCS::SetDfPos);
719 PropertyManager->Tie("fcs/flap-pos-norm", this,ofNorm, &FGFCS::GetDfPos, &FGFCS::SetDfPos);
721 PropertyManager->Tie("fcs/speedbrake-pos-rad", this,ofRad, &FGFCS::GetDsbPos, &FGFCS::SetDsbPos);
722 PropertyManager->Tie("fcs/speedbrake-pos-deg", this,ofDeg, &FGFCS::GetDsbPos, &FGFCS::SetDsbPos);
723 PropertyManager->Tie("fcs/speedbrake-pos-norm", this,ofNorm, &FGFCS::GetDsbPos, &FGFCS::SetDsbPos);
724 PropertyManager->Tie("fcs/mag-speedbrake-pos-rad", this,ofMag, &FGFCS::GetDsbPos);
726 PropertyManager->Tie("fcs/spoiler-pos-rad", this, ofRad, &FGFCS::GetDspPos, &FGFCS::SetDspPos);
727 PropertyManager->Tie("fcs/spoiler-pos-deg", this, ofDeg, &FGFCS::GetDspPos, &FGFCS::SetDspPos);
728 PropertyManager->Tie("fcs/spoiler-pos-norm", this, ofNorm, &FGFCS::GetDspPos, &FGFCS::SetDspPos);
729 PropertyManager->Tie("fcs/mag-spoiler-pos-rad", this, ofMag, &FGFCS::GetDspPos);
731 PropertyManager->Tie("gear/gear-pos-norm", this, &FGFCS::GetGearPos, &FGFCS::SetGearPos);
734 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
735 // Technically, this function should probably bind propulsion type specific controls
736 // rather than mixture and prop-advance.
739 void FGFCS::bindThrottle(unsigned int num)
743 snprintf(tmp, 80, "fcs/throttle-cmd-norm[%u]",num);
744 PropertyManager->Tie( tmp, this, num, &FGFCS::GetThrottleCmd,
745 &FGFCS::SetThrottleCmd);
746 snprintf(tmp, 80, "fcs/throttle-pos-norm[%u]",num);
747 PropertyManager->Tie( tmp, this, num, &FGFCS::GetThrottlePos,
748 &FGFCS::SetThrottlePos);
749 snprintf(tmp, 80, "fcs/mixture-cmd-norm[%u]",num);
750 PropertyManager->Tie( tmp, this, num, &FGFCS::GetMixtureCmd,
751 &FGFCS::SetMixtureCmd);
752 snprintf(tmp, 80, "fcs/mixture-pos-norm[%u]",num);
753 PropertyManager->Tie( tmp, this, num, &FGFCS::GetMixturePos,
754 &FGFCS::SetMixturePos);
755 snprintf(tmp, 80, "fcs/advance-cmd-norm[%u]",num);
756 PropertyManager->Tie( tmp, this, num, &FGFCS::GetPropAdvanceCmd,
757 &FGFCS::SetPropAdvanceCmd);
758 snprintf(tmp, 80, "fcs/advance-pos-norm[%u]", num);
759 PropertyManager->Tie( tmp, this, num, &FGFCS::GetPropAdvance,
760 &FGFCS::SetPropAdvance);
761 snprintf(tmp, 80, "fcs/feather-cmd-norm[%u]", num);
762 PropertyManager->Tie( tmp, this, num, &FGFCS::GetFeatherCmd,
763 &FGFCS::SetFeatherCmd);
764 snprintf(tmp, 80, "fcs/feather-pos-norm[%u]", num);
765 PropertyManager->Tie( tmp, this, num, &FGFCS::GetPropFeather,
766 &FGFCS::SetPropFeather);
769 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
771 void FGFCS::bindModel(void)
776 for (i=0; i<SteerPosDeg.size(); i++) {
777 if (GroundReactions->GetGearUnit(i)->GetSteerable()) {
778 snprintf(tmp,80,"fcs/steer-pos-deg[%u]",i);
779 PropertyManager->Tie( tmp, this, i, &FGFCS::GetSteerPosDeg, &FGFCS::SetSteerPosDeg);
784 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
786 void FGFCS::unbind(FGPropertyManager *node)
788 int N = node->nChildren();
789 for (int i=0; i<N; i++) {
790 if (node->getChild(i)->nChildren() ) {
791 unbind( (FGPropertyManager*)node->getChild(i) );
792 } else if ( node->getChild(i)->isTied() ) {
793 node->getChild(i)->untie();
798 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
799 // The bitmasked value choices are as follows:
800 // unset: In this case (the default) JSBSim would only print
801 // out the normally expected messages, essentially echoing
802 // the config files as they are read. If the environment
803 // variable is not set, debug_lvl is set to 1 internally
804 // 0: This requests JSBSim not to output any messages
806 // 1: This value explicity requests the normal JSBSim
808 // 2: This value asks for a message to be printed out when
809 // a class is instantiated
810 // 4: When this value is set, a message is displayed when a
811 // FGModel object executes its Run() method
812 // 8: When this value is set, various runtime state variables
813 // are printed out periodically
814 // 16: When set various parameters are sanity checked and
815 // a message is printed out when they go out of bounds
817 void FGFCS::Debug(int from)
819 if (debug_lvl <= 0) return;
821 if (debug_lvl & 1) { // Standard console startup message output
822 if (from == 2) { // Loader
823 cout << endl << " Flight Control (" << Name << ")" << endl;
826 if (debug_lvl & 2 ) { // Instantiation/Destruction notification
827 if (from == 0) cout << "Instantiated: FGFCS" << endl;
828 if (from == 1) cout << "Destroyed: FGFCS" << endl;
830 if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
832 if (debug_lvl & 8 ) { // Runtime state variables
834 if (debug_lvl & 16) { // Sanity checking
836 if (debug_lvl & 64) {
837 if (from == 0) { // Constructor
838 cout << IdSrc << endl;
839 cout << IdHdr << endl;