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 Lesser 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 Lesser General Public License for more
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.
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.
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/FGPID.h>
49 #include <models/flight_control/FGGradient.h>
50 #include <models/flight_control/FGSwitch.h>
51 #include <models/flight_control/FGSummer.h>
52 #include <models/flight_control/FGKinemat.h>
53 #include <models/flight_control/FGFCSFunction.h>
54 #include <models/flight_control/FGSensor.h>
55 #include <models/flight_control/FGActuator.h>
59 static const char *IdSrc = "$Id$";
60 static const char *IdHdr = ID_FCS;
62 #if defined(WIN32) && !defined(__CYGWIN__)
63 #define snprintf _snprintf
66 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
68 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
70 FGFCS::FGFCS(FGFDMExec* fdmex) : FGModel(fdmex)
75 DaCmd = DeCmd = DrCmd = DsCmd = DfCmd = DsbCmd = DspCmd = 0;
76 PTrimCmd = YTrimCmd = RTrimCmd = 0.0;
77 GearCmd = GearPos = 1; // default to gear down
78 LeftBrake = RightBrake = CenterBrake = 0.0;
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;
89 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
93 if (PropertyManager->HasNode("fcs")) unbind( PropertyManager->GetNode("fcs") );
94 if (PropertyManager->HasNode("ap")) unbind( PropertyManager->GetNode("ap") );
95 PropertyManager->Untie( "gear/gear-cmd-norm" );
96 PropertyManager->Untie( "gear/gear-pos-norm" );
102 PropAdvanceCmd.clear();
105 PropFeatherCmd.clear();
110 for (i=0;i<APComponents.size();i++) delete APComponents[i];
111 for (i=0;i<FCSComponents.size();i++) delete FCSComponents[i];
112 for (i=0;i<sensors.size();i++) delete sensors[i];
114 APComponents.clear();
115 FCSComponents.clear();
117 interface_properties.clear();
122 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
123 // Notes: In this logic the default engine commands are set. This is simply a
124 // sort of safe-mode method in case the user has not defined control laws for
125 // throttle, mixture, and prop-advance. The throttle, mixture, and prop advance
126 // positions are set equal to the respective commands. Any control logic that is
127 // actually present in the flight_control or autopilot section will override
128 // these simple assignments.
130 bool FGFCS::Run(void)
134 if (FGModel::Run()) return true; // fast exit if nothing to do
135 if (FDMExec->Holding()) return false;
137 for (i=0; i<ThrottlePos.size(); i++) ThrottlePos[i] = ThrottleCmd[i];
138 for (i=0; i<MixturePos.size(); i++) MixturePos[i] = MixtureCmd[i];
139 for (i=0; i<PropAdvance.size(); i++) PropAdvance[i] = PropAdvanceCmd[i];
140 for (i=0; i<PropFeather.size(); i++) PropFeather[i] = PropFeatherCmd[i];
143 // Set the default steering angle
144 for (i=0; i<SteerPosDeg.size(); i++) {
145 FGLGear* gear = GroundReactions->GetGearUnit(i);
146 SteerPosDeg[i] = gear->GetDefaultSteerAngle( GetDsCmd() );
149 // Cycle through the sensor, autopilot, and flight control components
150 for (i=0; i<sensors.size(); i++) sensors[i]->Run();
151 for (i=0; i<APComponents.size(); i++) {
152 APComponents[i]->Run();
154 for (i=0; i<FCSComponents.size(); i++) FCSComponents[i]->Run();
159 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
161 void FGFCS::SetDaLPos( int form , double pos )
166 DaLPos[ofDeg] = pos*radtodeg;
169 DaLPos[ofRad] = pos*degtorad;
173 DaLPos[ofNorm] = pos;
175 DaLPos[ofMag] = fabs(DaLPos[ofRad]);
178 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
180 void FGFCS::SetDaRPos( int form , double pos )
185 DaRPos[ofDeg] = pos*radtodeg;
188 DaRPos[ofRad] = pos*degtorad;
192 DaRPos[ofNorm] = pos;
194 DaRPos[ofMag] = fabs(DaRPos[ofRad]);
197 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
199 void FGFCS::SetDePos( int form , double pos )
204 DePos[ofDeg] = pos*radtodeg;
207 DePos[ofRad] = pos*degtorad;
213 DePos[ofMag] = fabs(DePos[ofRad]);
216 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
218 void FGFCS::SetDrPos( int form , double pos )
223 DrPos[ofDeg] = pos*radtodeg;
226 DrPos[ofRad] = pos*degtorad;
232 DrPos[ofMag] = fabs(DrPos[ofRad]);
235 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
237 void FGFCS::SetDfPos( int form , double pos )
242 DfPos[ofDeg] = pos*radtodeg;
245 DfPos[ofRad] = pos*degtorad;
251 DfPos[ofMag] = fabs(DfPos[ofRad]);
254 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
256 void FGFCS::SetDsbPos( int form , double pos )
261 DsbPos[ofDeg] = pos*radtodeg;
264 DsbPos[ofRad] = pos*degtorad;
268 DsbPos[ofNorm] = pos;
270 DsbPos[ofMag] = fabs(DsbPos[ofRad]);
273 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
275 void FGFCS::SetDspPos( int form , double pos )
280 DspPos[ofDeg] = pos*radtodeg;
283 DspPos[ofRad] = pos*degtorad;
287 DspPos[ofNorm] = pos;
289 DspPos[ofMag] = fabs(DspPos[ofRad]);
292 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
294 void FGFCS::SetThrottleCmd(int engineNum, double setting)
298 if (engineNum < (int)ThrottlePos.size()) {
300 for (ctr=0;ctr<ThrottleCmd.size();ctr++) ThrottleCmd[ctr] = setting;
302 ThrottleCmd[engineNum] = setting;
305 cerr << "Throttle " << engineNum << " does not exist! " << ThrottleCmd.size()
306 << " engines exist, but attempted throttle command is for engine "
307 << engineNum << endl;
311 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
313 void FGFCS::SetThrottlePos(int engineNum, double setting)
317 if (engineNum < (int)ThrottlePos.size()) {
319 for (ctr=0;ctr<ThrottlePos.size();ctr++) ThrottlePos[ctr] = setting;
321 ThrottlePos[engineNum] = setting;
324 cerr << "Throttle " << engineNum << " does not exist! " << ThrottlePos.size()
325 << " engines exist, but attempted throttle position setting is for engine "
326 << engineNum << endl;
330 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
332 double FGFCS::GetThrottleCmd(int engineNum) const
334 if (engineNum < (int)ThrottlePos.size()) {
336 cerr << "Cannot get throttle value for ALL engines" << endl;
338 return ThrottleCmd[engineNum];
341 cerr << "Throttle " << engineNum << " does not exist! " << ThrottleCmd.size()
342 << " engines exist, but throttle setting for engine " << engineNum
343 << " is selected" << endl;
348 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
350 double FGFCS::GetThrottlePos(int engineNum) const
352 if (engineNum < (int)ThrottlePos.size()) {
354 cerr << "Cannot get throttle value for ALL engines" << endl;
356 return ThrottlePos[engineNum];
359 cerr << "Throttle " << engineNum << " does not exist! " << ThrottlePos.size()
360 << " engines exist, but attempted throttle position setting is for engine "
361 << engineNum << endl;
366 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
368 void FGFCS::SetMixtureCmd(int engineNum, double setting)
372 if (engineNum < (int)ThrottlePos.size()) {
374 for (ctr=0;ctr<MixtureCmd.size();ctr++) MixtureCmd[ctr] = setting;
376 MixtureCmd[engineNum] = setting;
381 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
383 void FGFCS::SetMixturePos(int engineNum, double setting)
387 if (engineNum < (int)ThrottlePos.size()) {
389 for (ctr=0;ctr<=MixtureCmd.size();ctr++) MixturePos[ctr] = MixtureCmd[ctr];
391 MixturePos[engineNum] = setting;
396 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
398 void FGFCS::SetPropAdvanceCmd(int engineNum, double setting)
402 if (engineNum < (int)ThrottlePos.size()) {
404 for (ctr=0;ctr<PropAdvanceCmd.size();ctr++) PropAdvanceCmd[ctr] = setting;
406 PropAdvanceCmd[engineNum] = setting;
411 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
413 void FGFCS::SetPropAdvance(int engineNum, double setting)
417 if (engineNum < (int)ThrottlePos.size()) {
419 for (ctr=0;ctr<=PropAdvanceCmd.size();ctr++) PropAdvance[ctr] = PropAdvanceCmd[ctr];
421 PropAdvance[engineNum] = setting;
426 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
428 void FGFCS::SetFeatherCmd(int engineNum, bool setting)
432 if (engineNum < (int)ThrottlePos.size()) {
434 for (ctr=0;ctr<PropFeatherCmd.size();ctr++) PropFeatherCmd[ctr] = setting;
436 PropFeatherCmd[engineNum] = setting;
441 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
443 void FGFCS::SetPropFeather(int engineNum, bool setting)
447 if (engineNum < (int)ThrottlePos.size()) {
449 for (ctr=0;ctr<=PropFeatherCmd.size();ctr++) PropFeather[ctr] = PropFeatherCmd[ctr];
451 PropFeather[engineNum] = setting;
456 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
458 bool FGFCS::Load(Element* el)
460 string name, file, fname, interface_property_string;
461 vector <FGFCSComponent*> *Components;
462 Element *component_element, *property_element, *sensor_element;
463 Element *channel_element;
466 // Determine if the FCS/Autopilot is defined inline in the aircraft configuration
467 // file or in a separate file. Set up the Element pointer as appropriate.
469 string separator = "/";
474 name = el->GetAttributeValue("name");
477 fname = el->GetAttributeValue("file");
478 file = FDMExec->GetFullAircraftPath() + separator + fname + ".xml";
480 cerr << "FCS/Autopilot does not appear to be defined inline nor in a file" << endl;
483 document = LoadXMLDocument(file);
489 if (document->GetName() == "autopilot") {
490 Components = &APComponents;
491 Name = "Autopilot: " + document->GetAttributeValue("name");
492 } else if (document->GetName() == "flight_control") {
493 Components = &FCSComponents;
494 Name = "FCS: " + document->GetAttributeValue("name");
499 // ToDo: How do these get untied?
500 // ToDo: Consider having INPUT and OUTPUT interface properties. Would then
501 // have to duplicate this block of code after channel read code.
502 // Input properties could be write only (nah), and output could be read
505 if (document->GetName() == "flight_control") bindModel();
507 property_element = document->FindElement("property");
508 while (property_element) {
509 interface_properties.push_back(new double(0));
510 interface_property_string = property_element->GetDataLine();
511 PropertyManager->Tie(interface_property_string, interface_properties.back());
512 property_element = document->FindNextElement("property");
515 sensor_element = document->FindElement("sensor");
516 while (sensor_element) {
518 sensors.push_back(new FGSensor(this, sensor_element));
520 cerr << highint << fgred << endl << " " << s << endl;
523 sensor_element = document->FindNextElement("sensor");
526 channel_element = document->FindElement("channel");
527 while (channel_element) {
528 component_element = channel_element->GetElement();
529 while (component_element) {
531 if ((component_element->GetName() == string("lag_filter")) ||
532 (component_element->GetName() == string("lead_lag_filter")) ||
533 (component_element->GetName() == string("washout_filter")) ||
534 (component_element->GetName() == string("second_order_filter")) ||
535 (component_element->GetName() == string("integrator")) )
537 Components->push_back(new FGFilter(this, component_element));
538 } else if ((component_element->GetName() == string("pure_gain")) ||
539 (component_element->GetName() == string("scheduled_gain")) ||
540 (component_element->GetName() == string("aerosurface_scale")))
542 Components->push_back(new FGGain(this, component_element));
543 } else if (component_element->GetName() == string("summer")) {
544 Components->push_back(new FGSummer(this, component_element));
545 } else if (component_element->GetName() == string("deadband")) {
546 Components->push_back(new FGDeadBand(this, component_element));
547 } else if (component_element->GetName() == string("switch")) {
548 Components->push_back(new FGSwitch(this, component_element));
549 } else if (component_element->GetName() == string("kinematic")) {
550 Components->push_back(new FGKinemat(this, component_element));
551 } else if (component_element->GetName() == string("fcs_function")) {
552 Components->push_back(new FGFCSFunction(this, component_element));
553 } else if (component_element->GetName() == string("pid")) {
554 Components->push_back(new FGPID(this, component_element));
555 } else if (component_element->GetName() == string("actuator")) {
556 Components->push_back(new FGActuator(this, component_element));
558 cerr << "Unknown FCS component: " << component_element->GetName() << endl;
561 cerr << highint << fgred << endl << " " << s << endl;
562 cerr << reset << endl;
565 component_element = channel_element->GetNextElement();
567 channel_element = document->FindNextElement("channel");
573 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
575 double FGFCS::GetBrake(FGLGear::BrakeGroup bg)
578 case FGLGear::bgLeft:
580 case FGLGear::bgRight:
582 case FGLGear::bgCenter:
585 cerr << "GetBrake asked to return a bogus brake value" << endl;
590 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
592 string FGFCS::GetComponentStrings(string delimeter)
595 string CompStrings = "";
596 bool firstime = true;
598 for (comp = 0; comp < FCSComponents.size(); comp++) {
599 if (firstime) firstime = false;
600 else CompStrings += delimeter;
602 CompStrings += FCSComponents[comp]->GetName();
605 for (comp = 0; comp < APComponents.size(); comp++)
607 if (firstime) firstime = false;
608 else CompStrings += delimeter;
610 CompStrings += APComponents[comp]->GetName();
616 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
618 string FGFCS::GetComponentValues(string delimeter)
621 string CompValues = "";
623 bool firstime = true;
625 for (comp = 0; comp < FCSComponents.size(); comp++) {
626 if (firstime) firstime = false;
627 else CompValues += delimeter;
629 sprintf(buffer, "%9.6f", FCSComponents[comp]->GetOutput());
630 CompValues += string(buffer);
633 for (comp = 0; comp < APComponents.size(); comp++) {
634 if (firstime) firstime = false;
635 else CompValues += delimeter;
637 sprintf(buffer, "%9.6f", APComponents[comp]->GetOutput());
638 CompValues += string(buffer);
645 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
647 void FGFCS::AddThrottle(void)
649 ThrottleCmd.push_back(0.0);
650 ThrottlePos.push_back(0.0);
651 MixtureCmd.push_back(0.0); // assume throttle and mixture are coupled
652 MixturePos.push_back(0.0);
653 PropAdvanceCmd.push_back(0.0); // assume throttle and prop pitch are coupled
654 PropAdvance.push_back(0.0);
655 PropFeatherCmd.push_back(false);
656 PropFeather.push_back(false);
658 unsigned int num = (unsigned int)ThrottleCmd.size()-1;
662 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
664 void FGFCS::AddGear(void)
666 SteerPosDeg.push_back(0.0);
669 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
671 double FGFCS::GetDt(void)
673 return FDMExec->GetDeltaT()*rate;
676 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
678 void FGFCS::bind(void)
680 PropertyManager->Tie("fcs/aileron-cmd-norm", this, &FGFCS::GetDaCmd, &FGFCS::SetDaCmd);
681 PropertyManager->Tie("fcs/elevator-cmd-norm", this, &FGFCS::GetDeCmd, &FGFCS::SetDeCmd);
682 PropertyManager->Tie("fcs/rudder-cmd-norm", this, &FGFCS::GetDrCmd, &FGFCS::SetDrCmd);
683 PropertyManager->Tie("fcs/flap-cmd-norm", this, &FGFCS::GetDfCmd, &FGFCS::SetDfCmd);
684 PropertyManager->Tie("fcs/speedbrake-cmd-norm", this, &FGFCS::GetDsbCmd, &FGFCS::SetDsbCmd);
685 PropertyManager->Tie("fcs/spoiler-cmd-norm", this, &FGFCS::GetDspCmd, &FGFCS::SetDspCmd);
686 PropertyManager->Tie("fcs/pitch-trim-cmd-norm", this, &FGFCS::GetPitchTrimCmd, &FGFCS::SetPitchTrimCmd);
687 PropertyManager->Tie("fcs/roll-trim-cmd-norm", this, &FGFCS::GetRollTrimCmd, &FGFCS::SetRollTrimCmd);
688 PropertyManager->Tie("fcs/yaw-trim-cmd-norm", this, &FGFCS::GetYawTrimCmd, &FGFCS::SetYawTrimCmd);
690 PropertyManager->Tie("fcs/left-aileron-pos-rad", this, ofRad, &FGFCS::GetDaLPos, &FGFCS::SetDaLPos);
691 PropertyManager->Tie("fcs/left-aileron-pos-deg", this, ofDeg, &FGFCS::GetDaLPos, &FGFCS::SetDaLPos);
692 PropertyManager->Tie("fcs/left-aileron-pos-norm", this, ofNorm, &FGFCS::GetDaLPos, &FGFCS::SetDaLPos);
693 PropertyManager->Tie("fcs/mag-left-aileron-pos-rad", this, ofMag, &FGFCS::GetDaLPos);
695 PropertyManager->Tie("fcs/right-aileron-pos-rad", this, ofRad, &FGFCS::GetDaRPos, &FGFCS::SetDaRPos);
696 PropertyManager->Tie("fcs/right-aileron-pos-deg", this, ofDeg, &FGFCS::GetDaRPos, &FGFCS::SetDaRPos);
697 PropertyManager->Tie("fcs/right-aileron-pos-norm", this, ofNorm, &FGFCS::GetDaRPos, &FGFCS::SetDaRPos);
698 PropertyManager->Tie("fcs/mag-right-aileron-pos-rad", this, ofMag, &FGFCS::GetDaRPos);
700 PropertyManager->Tie("fcs/elevator-pos-rad", this, ofRad, &FGFCS::GetDePos, &FGFCS::SetDePos);
701 PropertyManager->Tie("fcs/elevator-pos-deg", this, ofDeg, &FGFCS::GetDePos, &FGFCS::SetDePos);
702 PropertyManager->Tie("fcs/elevator-pos-norm", this, ofNorm, &FGFCS::GetDePos, &FGFCS::SetDePos);
703 PropertyManager->Tie("fcs/mag-elevator-pos-rad", this, ofMag, &FGFCS::GetDePos);
705 PropertyManager->Tie("fcs/rudder-pos-rad", this,ofRad, &FGFCS::GetDrPos, &FGFCS::SetDrPos);
706 PropertyManager->Tie("fcs/rudder-pos-deg", this,ofDeg, &FGFCS::GetDrPos, &FGFCS::SetDrPos);
707 PropertyManager->Tie("fcs/rudder-pos-norm", this,ofNorm, &FGFCS::GetDrPos, &FGFCS::SetDrPos);
708 PropertyManager->Tie("fcs/mag-rudder-pos-rad", this,ofMag, &FGFCS::GetDrPos);
710 PropertyManager->Tie("fcs/flap-pos-rad", this,ofRad, &FGFCS::GetDfPos, &FGFCS::SetDfPos);
711 PropertyManager->Tie("fcs/flap-pos-deg", this,ofDeg, &FGFCS::GetDfPos, &FGFCS::SetDfPos);
712 PropertyManager->Tie("fcs/flap-pos-norm", this,ofNorm, &FGFCS::GetDfPos, &FGFCS::SetDfPos);
714 PropertyManager->Tie("fcs/speedbrake-pos-rad", this,ofRad, &FGFCS::GetDsbPos, &FGFCS::SetDsbPos);
715 PropertyManager->Tie("fcs/speedbrake-pos-deg", this,ofDeg, &FGFCS::GetDsbPos, &FGFCS::SetDsbPos);
716 PropertyManager->Tie("fcs/speedbrake-pos-norm", this,ofNorm, &FGFCS::GetDsbPos, &FGFCS::SetDsbPos);
717 PropertyManager->Tie("fcs/mag-speedbrake-pos-rad", this,ofMag, &FGFCS::GetDsbPos);
719 PropertyManager->Tie("fcs/spoiler-pos-rad", this, ofRad, &FGFCS::GetDspPos, &FGFCS::SetDspPos);
720 PropertyManager->Tie("fcs/spoiler-pos-deg", this, ofDeg, &FGFCS::GetDspPos, &FGFCS::SetDspPos);
721 PropertyManager->Tie("fcs/spoiler-pos-norm", this, ofNorm, &FGFCS::GetDspPos, &FGFCS::SetDspPos);
722 PropertyManager->Tie("fcs/mag-spoiler-pos-rad", this, ofMag, &FGFCS::GetDspPos);
724 PropertyManager->Tie("gear/gear-pos-norm", this, &FGFCS::GetGearPos, &FGFCS::SetGearPos);
725 PropertyManager->Tie("gear/gear-cmd-norm", this, &FGFCS::GetGearCmd, &FGFCS::SetGearCmd);
726 PropertyManager->Tie("fcs/left-brake-cmd-norm", this, &FGFCS::GetLBrake, &FGFCS::SetLBrake);
727 PropertyManager->Tie("fcs/right-brake-cmd-norm", this, &FGFCS::GetRBrake, &FGFCS::SetRBrake);
728 PropertyManager->Tie("fcs/center-brake-cmd-norm", this, &FGFCS::GetCBrake, &FGFCS::SetCBrake);
729 PropertyManager->Tie("fcs/steer-cmd-norm", this, &FGFCS::GetDsCmd, &FGFCS::SetDsCmd);
732 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
733 // Technically, this function should probably bind propulsion type specific controls
734 // rather than mixture and prop-advance.
737 void FGFCS::bindThrottle(unsigned int num)
741 snprintf(tmp, 80, "fcs/throttle-cmd-norm[%u]",num);
742 PropertyManager->Tie( tmp, this, num, &FGFCS::GetThrottleCmd,
743 &FGFCS::SetThrottleCmd);
744 snprintf(tmp, 80, "fcs/throttle-pos-norm[%u]",num);
745 PropertyManager->Tie( tmp, this, num, &FGFCS::GetThrottlePos,
746 &FGFCS::SetThrottlePos);
747 snprintf(tmp, 80, "fcs/mixture-cmd-norm[%u]",num);
748 PropertyManager->Tie( tmp, this, num, &FGFCS::GetMixtureCmd,
749 &FGFCS::SetMixtureCmd);
750 snprintf(tmp, 80, "fcs/mixture-pos-norm[%u]",num);
751 PropertyManager->Tie( tmp, this, num, &FGFCS::GetMixturePos,
752 &FGFCS::SetMixturePos);
753 snprintf(tmp, 80, "fcs/advance-cmd-norm[%u]",num);
754 PropertyManager->Tie( tmp, this, num, &FGFCS::GetPropAdvanceCmd,
755 &FGFCS::SetPropAdvanceCmd);
756 snprintf(tmp, 80, "fcs/advance-pos-norm[%u]", num);
757 PropertyManager->Tie( tmp, this, num, &FGFCS::GetPropAdvance,
758 &FGFCS::SetPropAdvance);
759 snprintf(tmp, 80, "fcs/feather-cmd-norm[%u]", num);
760 PropertyManager->Tie( tmp, this, num, &FGFCS::GetFeatherCmd,
761 &FGFCS::SetFeatherCmd);
762 snprintf(tmp, 80, "fcs/feather-pos-norm[%u]", num);
763 PropertyManager->Tie( tmp, this, num, &FGFCS::GetPropFeather,
764 &FGFCS::SetPropFeather);
767 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
769 void FGFCS::bindModel(void)
774 for (i=0; i<SteerPosDeg.size(); i++) {
775 if (GroundReactions->GetGearUnit(i)->GetSteerable()) {
776 snprintf(tmp,80,"fcs/steer-pos-deg[%u]",i);
777 PropertyManager->Tie( tmp, this, i, &FGFCS::GetSteerPosDeg, &FGFCS::SetSteerPosDeg);
782 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
784 void FGFCS::unbind(FGPropertyManager *node)
786 int N = node->nChildren();
787 for (int i=0; i<N; i++) {
788 if (node->getChild(i)->nChildren() ) {
789 unbind( (FGPropertyManager*)node->getChild(i) );
790 } else if ( node->getChild(i)->isTied() ) {
791 node->getChild(i)->untie();
796 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
797 // The bitmasked value choices are as follows:
798 // unset: In this case (the default) JSBSim would only print
799 // out the normally expected messages, essentially echoing
800 // the config files as they are read. If the environment
801 // variable is not set, debug_lvl is set to 1 internally
802 // 0: This requests JSBSim not to output any messages
804 // 1: This value explicity requests the normal JSBSim
806 // 2: This value asks for a message to be printed out when
807 // a class is instantiated
808 // 4: When this value is set, a message is displayed when a
809 // FGModel object executes its Run() method
810 // 8: When this value is set, various runtime state variables
811 // are printed out periodically
812 // 16: When set various parameters are sanity checked and
813 // a message is printed out when they go out of bounds
815 void FGFCS::Debug(int from)
817 if (debug_lvl <= 0) return;
819 if (debug_lvl & 1) { // Standard console startup message output
820 if (from == 2) { // Loader
821 cout << endl << " Flight Control (" << Name << ")" << endl;
824 if (debug_lvl & 2 ) { // Instantiation/Destruction notification
825 if (from == 0) cout << "Instantiated: FGFCS" << endl;
826 if (from == 1) cout << "Destroyed: FGFCS" << endl;
828 if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
830 if (debug_lvl & 8 ) { // Runtime state variables
832 if (debug_lvl & 16) { // Sanity checking
834 if (debug_lvl & 64) {
835 if (from == 0) { // Constructor
836 cout << IdSrc << endl;
837 cout << IdHdr << endl;