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>
58 static const char *IdSrc = "$Id$";
59 static const char *IdHdr = ID_FCS;
61 #if defined(WIN32) && !defined(__CYGWIN__)
62 #define snprintf _snprintf
65 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
67 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
69 FGFCS::FGFCS(FGFDMExec* fdmex) : FGModel(fdmex)
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;
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;
88 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
92 if (PropertyManager->HasNode("fcs")) unbind( PropertyManager->GetNode("fcs") );
93 if (PropertyManager->HasNode("ap")) unbind( PropertyManager->GetNode("ap") );
94 PropertyManager->Untie( "gear/gear-cmd-norm" );
95 PropertyManager->Untie( "gear/gear-pos-norm" );
101 PropAdvanceCmd.clear();
104 PropFeatherCmd.clear();
109 for (i=0;i<APComponents.size();i++) delete APComponents[i];
110 for (i=0;i<FCSComponents.size();i++) delete FCSComponents[i];
111 for (i=0;i<sensors.size();i++) delete sensors[i];
113 APComponents.clear();
114 FCSComponents.clear();
116 interface_properties.clear();
121 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
122 // Notes: In this logic the default engine commands are set. This is simply a
123 // sort of safe-mode method in case the user has not defined control laws for
124 // throttle, mixture, and prop-advance. The throttle, mixture, and prop advance
125 // positions are set equal to the respective commands. Any control logic that is
126 // actually present in the flight_control or autopilot section will override
127 // these simple assignments.
129 bool FGFCS::Run(void)
133 if (FGModel::Run()) return true; // fast exit if nothing to do
134 if (FDMExec->Holding()) return false;
136 for (i=0; i<ThrottlePos.size(); i++) ThrottlePos[i] = ThrottleCmd[i];
137 for (i=0; i<MixturePos.size(); i++) MixturePos[i] = MixtureCmd[i];
138 for (i=0; i<PropAdvance.size(); i++) PropAdvance[i] = PropAdvanceCmd[i];
139 for (i=0; i<PropFeather.size(); i++) PropFeather[i] = PropFeatherCmd[i];
142 // Set the default steering angle
143 for (i=0; i<SteerPosDeg.size(); i++) {
144 FGLGear* gear = GroundReactions->GetGearUnit(i);
145 SteerPosDeg[i] = gear->GetDefaultSteerAngle( GetDsCmd() );
148 // Cycle through the sensor, autopilot, and flight control components
149 for (i=0; i<sensors.size(); i++) sensors[i]->Run();
150 for (i=0; i<APComponents.size(); i++) APComponents[i]->Run();
151 for (i=0; i<FCSComponents.size(); i++) FCSComponents[i]->Run();
156 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
158 void FGFCS::SetDaLPos( int form , double pos )
163 DaLPos[ofDeg] = pos*radtodeg;
166 DaLPos[ofRad] = pos*degtorad;
170 DaLPos[ofNorm] = pos;
172 DaLPos[ofMag] = fabs(DaLPos[ofRad]);
175 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
177 void FGFCS::SetDaRPos( int form , double pos )
182 DaRPos[ofDeg] = pos*radtodeg;
185 DaRPos[ofRad] = pos*degtorad;
189 DaRPos[ofNorm] = pos;
191 DaRPos[ofMag] = fabs(DaRPos[ofRad]);
194 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
196 void FGFCS::SetDePos( int form , double pos )
201 DePos[ofDeg] = pos*radtodeg;
204 DePos[ofRad] = pos*degtorad;
210 DePos[ofMag] = fabs(DePos[ofRad]);
213 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
215 void FGFCS::SetDrPos( int form , double pos )
220 DrPos[ofDeg] = pos*radtodeg;
223 DrPos[ofRad] = pos*degtorad;
229 DrPos[ofMag] = fabs(DrPos[ofRad]);
232 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
234 void FGFCS::SetDfPos( int form , double pos )
239 DfPos[ofDeg] = pos*radtodeg;
242 DfPos[ofRad] = pos*degtorad;
248 DfPos[ofMag] = fabs(DfPos[ofRad]);
251 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
253 void FGFCS::SetDsbPos( int form , double pos )
258 DsbPos[ofDeg] = pos*radtodeg;
261 DsbPos[ofRad] = pos*degtorad;
265 DsbPos[ofNorm] = pos;
267 DsbPos[ofMag] = fabs(DsbPos[ofRad]);
270 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
272 void FGFCS::SetDspPos( int form , double pos )
277 DspPos[ofDeg] = pos*radtodeg;
280 DspPos[ofRad] = pos*degtorad;
284 DspPos[ofNorm] = pos;
286 DspPos[ofMag] = fabs(DspPos[ofRad]);
289 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
291 void FGFCS::SetThrottleCmd(int engineNum, double setting)
295 if (engineNum < (int)ThrottlePos.size()) {
297 for (ctr=0;ctr<ThrottleCmd.size();ctr++) ThrottleCmd[ctr] = setting;
299 ThrottleCmd[engineNum] = setting;
302 cerr << "Throttle " << engineNum << " does not exist! " << ThrottleCmd.size()
303 << " engines exist, but attempted throttle command is for engine "
304 << engineNum << endl;
308 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
310 void FGFCS::SetThrottlePos(int engineNum, double setting)
314 if (engineNum < (int)ThrottlePos.size()) {
316 for (ctr=0;ctr<ThrottlePos.size();ctr++) ThrottlePos[ctr] = setting;
318 ThrottlePos[engineNum] = setting;
321 cerr << "Throttle " << engineNum << " does not exist! " << ThrottlePos.size()
322 << " engines exist, but attempted throttle position setting is for engine "
323 << engineNum << endl;
327 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
329 double FGFCS::GetThrottleCmd(int engineNum) const
331 if (engineNum < (int)ThrottlePos.size()) {
333 cerr << "Cannot get throttle value for ALL engines" << endl;
335 return ThrottleCmd[engineNum];
338 cerr << "Throttle " << engineNum << " does not exist! " << ThrottleCmd.size()
339 << " engines exist, but throttle setting for engine " << engineNum
340 << " is selected" << endl;
345 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
347 double FGFCS::GetThrottlePos(int engineNum) const
349 if (engineNum < (int)ThrottlePos.size()) {
351 cerr << "Cannot get throttle value for ALL engines" << endl;
353 return ThrottlePos[engineNum];
356 cerr << "Throttle " << engineNum << " does not exist! " << ThrottlePos.size()
357 << " engines exist, but attempted throttle position setting is for engine "
358 << engineNum << endl;
363 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
365 void FGFCS::SetMixtureCmd(int engineNum, double setting)
369 if (engineNum < (int)ThrottlePos.size()) {
371 for (ctr=0;ctr<MixtureCmd.size();ctr++) MixtureCmd[ctr] = setting;
373 MixtureCmd[engineNum] = setting;
378 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
380 void FGFCS::SetMixturePos(int engineNum, double setting)
384 if (engineNum < (int)ThrottlePos.size()) {
386 for (ctr=0;ctr<=MixtureCmd.size();ctr++) MixturePos[ctr] = MixtureCmd[ctr];
388 MixturePos[engineNum] = setting;
393 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
395 void FGFCS::SetPropAdvanceCmd(int engineNum, double setting)
399 if (engineNum < (int)ThrottlePos.size()) {
401 for (ctr=0;ctr<PropAdvanceCmd.size();ctr++) PropAdvanceCmd[ctr] = setting;
403 PropAdvanceCmd[engineNum] = setting;
408 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
410 void FGFCS::SetPropAdvance(int engineNum, double setting)
414 if (engineNum < (int)ThrottlePos.size()) {
416 for (ctr=0;ctr<=PropAdvanceCmd.size();ctr++) PropAdvance[ctr] = PropAdvanceCmd[ctr];
418 PropAdvance[engineNum] = setting;
423 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
425 void FGFCS::SetFeatherCmd(int engineNum, bool setting)
429 if (engineNum < (int)ThrottlePos.size()) {
431 for (ctr=0;ctr<PropFeatherCmd.size();ctr++) PropFeatherCmd[ctr] = setting;
433 PropFeatherCmd[engineNum] = setting;
438 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
440 void FGFCS::SetPropFeather(int engineNum, bool setting)
444 if (engineNum < (int)ThrottlePos.size()) {
446 for (ctr=0;ctr<=PropFeatherCmd.size();ctr++) PropFeather[ctr] = PropFeatherCmd[ctr];
448 PropFeather[engineNum] = setting;
453 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
455 bool FGFCS::Load(Element* el)
457 string name, file, fname, interface_property_string;
458 vector <FGFCSComponent*> *Components;
459 Element *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->GetFullAircraftPath() + 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->GetElement();
531 while (component_element) {
533 if ((component_element->GetName() == string("lag_filter")) ||
534 (component_element->GetName() == string("lead_lag_filter")) ||
535 (component_element->GetName() == string("washout_filter")) ||
536 (component_element->GetName() == string("second_order_filter")) ||
537 (component_element->GetName() == string("integrator")) )
539 Components->push_back(new FGFilter(this, component_element));
540 } else if ((component_element->GetName() == string("pure_gain")) ||
541 (component_element->GetName() == string("scheduled_gain")) ||
542 (component_element->GetName() == string("aerosurface_scale")))
544 Components->push_back(new FGGain(this, component_element));
545 } else if (component_element->GetName() == string("summer")) {
546 Components->push_back(new FGSummer(this, component_element));
547 } else if (component_element->GetName() == string("deadband")) {
548 Components->push_back(new FGDeadBand(this, component_element));
549 } else if (component_element->GetName() == string("switch")) {
550 Components->push_back(new FGSwitch(this, component_element));
551 } else if (component_element->GetName() == string("kinematic")) {
552 Components->push_back(new FGKinemat(this, component_element));
553 } else if (component_element->GetName() == string("fcs_function")) {
554 Components->push_back(new FGFCSFunction(this, component_element));
555 } else if (component_element->GetName() == string("pid")) {
556 Components->push_back(new FGPID(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 CompStrings += delimeter;
608 CompStrings += APComponents[comp]->GetName();
614 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
616 string FGFCS::GetComponentValues(string delimeter)
619 string CompValues = "";
621 bool firstime = true;
623 for (comp = 0; comp < FCSComponents.size(); comp++) {
624 if (firstime) firstime = false;
625 else CompValues += delimeter;
627 sprintf(buffer, "%9.6f", FCSComponents[comp]->GetOutput());
628 CompValues += string(buffer);
631 for (comp = 0; comp < APComponents.size(); comp++) {
632 sprintf(buffer, "%s%9.6f", delimeter.c_str(), APComponents[comp]->GetOutput());
633 CompValues += string(buffer);
640 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
642 void FGFCS::AddThrottle(void)
644 ThrottleCmd.push_back(0.0);
645 ThrottlePos.push_back(0.0);
646 MixtureCmd.push_back(0.0); // assume throttle and mixture are coupled
647 MixturePos.push_back(0.0);
648 PropAdvanceCmd.push_back(0.0); // assume throttle and prop pitch are coupled
649 PropAdvance.push_back(0.0);
650 PropFeatherCmd.push_back(false);
651 PropFeather.push_back(false);
653 unsigned int num = (unsigned int)ThrottleCmd.size()-1;
657 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
659 void FGFCS::AddGear(void)
661 SteerPosDeg.push_back(0.0);
664 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
666 void FGFCS::bind(void)
668 PropertyManager->Tie("fcs/aileron-cmd-norm", this, &FGFCS::GetDaCmd, &FGFCS::SetDaCmd);
669 PropertyManager->Tie("fcs/elevator-cmd-norm", this, &FGFCS::GetDeCmd, &FGFCS::SetDeCmd);
670 PropertyManager->Tie("fcs/rudder-cmd-norm", this, &FGFCS::GetDrCmd, &FGFCS::SetDrCmd);
671 PropertyManager->Tie("fcs/flap-cmd-norm", this, &FGFCS::GetDfCmd, &FGFCS::SetDfCmd);
672 PropertyManager->Tie("fcs/speedbrake-cmd-norm", this, &FGFCS::GetDsbCmd, &FGFCS::SetDsbCmd);
673 PropertyManager->Tie("fcs/spoiler-cmd-norm", this, &FGFCS::GetDspCmd, &FGFCS::SetDspCmd);
674 PropertyManager->Tie("fcs/pitch-trim-cmd-norm", this, &FGFCS::GetPitchTrimCmd, &FGFCS::SetPitchTrimCmd);
675 PropertyManager->Tie("fcs/roll-trim-cmd-norm", this, &FGFCS::GetRollTrimCmd, &FGFCS::SetRollTrimCmd);
676 PropertyManager->Tie("fcs/yaw-trim-cmd-norm", this, &FGFCS::GetYawTrimCmd, &FGFCS::SetYawTrimCmd);
678 PropertyManager->Tie("fcs/left-aileron-pos-rad", this, ofRad, &FGFCS::GetDaLPos, &FGFCS::SetDaLPos);
679 PropertyManager->Tie("fcs/left-aileron-pos-deg", this, ofDeg, &FGFCS::GetDaLPos, &FGFCS::SetDaLPos);
680 PropertyManager->Tie("fcs/left-aileron-pos-norm", this, ofNorm, &FGFCS::GetDaLPos, &FGFCS::SetDaLPos);
681 PropertyManager->Tie("fcs/mag-left-aileron-pos-rad", this, ofMag, &FGFCS::GetDaLPos);
683 PropertyManager->Tie("fcs/right-aileron-pos-rad", this, ofRad, &FGFCS::GetDaRPos, &FGFCS::SetDaRPos);
684 PropertyManager->Tie("fcs/right-aileron-pos-deg", this, ofDeg, &FGFCS::GetDaRPos, &FGFCS::SetDaRPos);
685 PropertyManager->Tie("fcs/right-aileron-pos-norm", this, ofNorm, &FGFCS::GetDaRPos, &FGFCS::SetDaRPos);
686 PropertyManager->Tie("fcs/mag-right-aileron-pos-rad", this, ofMag, &FGFCS::GetDaRPos);
688 PropertyManager->Tie("fcs/elevator-pos-rad", this, ofRad, &FGFCS::GetDePos, &FGFCS::SetDePos);
689 PropertyManager->Tie("fcs/elevator-pos-deg", this, ofDeg, &FGFCS::GetDePos, &FGFCS::SetDePos);
690 PropertyManager->Tie("fcs/elevator-pos-norm", this, ofNorm, &FGFCS::GetDePos, &FGFCS::SetDePos);
691 PropertyManager->Tie("fcs/mag-elevator-pos-rad", this, ofMag, &FGFCS::GetDePos);
693 PropertyManager->Tie("fcs/rudder-pos-rad", this,ofRad, &FGFCS::GetDrPos, &FGFCS::SetDrPos);
694 PropertyManager->Tie("fcs/rudder-pos-deg", this,ofDeg, &FGFCS::GetDrPos, &FGFCS::SetDrPos);
695 PropertyManager->Tie("fcs/rudder-pos-norm", this,ofNorm, &FGFCS::GetDrPos, &FGFCS::SetDrPos);
696 PropertyManager->Tie("fcs/mag-rudder-pos-rad", this,ofMag, &FGFCS::GetDrPos);
698 PropertyManager->Tie("fcs/flap-pos-rad", this,ofRad, &FGFCS::GetDfPos, &FGFCS::SetDfPos);
699 PropertyManager->Tie("fcs/flap-pos-deg", this,ofDeg, &FGFCS::GetDfPos, &FGFCS::SetDfPos);
700 PropertyManager->Tie("fcs/flap-pos-norm", this,ofNorm, &FGFCS::GetDfPos, &FGFCS::SetDfPos);
702 PropertyManager->Tie("fcs/speedbrake-pos-rad", this,ofRad, &FGFCS::GetDsbPos, &FGFCS::SetDsbPos);
703 PropertyManager->Tie("fcs/speedbrake-pos-deg", this,ofDeg, &FGFCS::GetDsbPos, &FGFCS::SetDsbPos);
704 PropertyManager->Tie("fcs/speedbrake-pos-norm", this,ofNorm, &FGFCS::GetDsbPos, &FGFCS::SetDsbPos);
705 PropertyManager->Tie("fcs/mag-speedbrake-pos-rad", this,ofMag, &FGFCS::GetDsbPos);
707 PropertyManager->Tie("fcs/spoiler-pos-rad", this, ofRad, &FGFCS::GetDspPos, &FGFCS::SetDspPos);
708 PropertyManager->Tie("fcs/spoiler-pos-deg", this, ofDeg, &FGFCS::GetDspPos, &FGFCS::SetDspPos);
709 PropertyManager->Tie("fcs/spoiler-pos-norm", this, ofNorm, &FGFCS::GetDspPos, &FGFCS::SetDspPos);
710 PropertyManager->Tie("fcs/mag-spoiler-pos-rad", this, ofMag, &FGFCS::GetDspPos);
712 PropertyManager->Tie("gear/gear-pos-norm", this, &FGFCS::GetGearPos, &FGFCS::SetGearPos);
713 PropertyManager->Tie("gear/gear-cmd-norm", this, &FGFCS::GetGearCmd, &FGFCS::SetGearCmd);
714 PropertyManager->Tie("fcs/left-brake-cmd-norm", this, &FGFCS::GetLBrake, &FGFCS::SetLBrake);
715 PropertyManager->Tie("fcs/right-brake-cmd-norm", this, &FGFCS::GetRBrake, &FGFCS::SetRBrake);
716 PropertyManager->Tie("fcs/center-brake-cmd-norm", this, &FGFCS::GetCBrake, &FGFCS::SetCBrake);
717 PropertyManager->Tie("fcs/steer-cmd-norm", this, &FGFCS::GetDsCmd, &FGFCS::SetDsCmd);
720 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
721 // Technically, this function should probably bind propulsion type specific controls
722 // rather than mixture and prop-advance.
725 void FGFCS::bindThrottle(unsigned int num)
729 snprintf(tmp, 80, "fcs/throttle-cmd-norm[%u]",num);
730 PropertyManager->Tie( tmp, this, num, &FGFCS::GetThrottleCmd,
731 &FGFCS::SetThrottleCmd);
732 snprintf(tmp, 80, "fcs/throttle-pos-norm[%u]",num);
733 PropertyManager->Tie( tmp, this, num, &FGFCS::GetThrottlePos,
734 &FGFCS::SetThrottlePos);
735 snprintf(tmp, 80, "fcs/mixture-cmd-norm[%u]",num);
736 PropertyManager->Tie( tmp, this, num, &FGFCS::GetMixtureCmd,
737 &FGFCS::SetMixtureCmd);
738 snprintf(tmp, 80, "fcs/mixture-pos-norm[%u]",num);
739 PropertyManager->Tie( tmp, this, num, &FGFCS::GetMixturePos,
740 &FGFCS::SetMixturePos);
741 snprintf(tmp, 80, "fcs/advance-cmd-norm[%u]",num);
742 PropertyManager->Tie( tmp, this, num, &FGFCS::GetPropAdvanceCmd,
743 &FGFCS::SetPropAdvanceCmd);
744 snprintf(tmp, 80, "fcs/advance-pos-norm[%u]", num);
745 PropertyManager->Tie( tmp, this, num, &FGFCS::GetPropAdvance,
746 &FGFCS::SetPropAdvance);
747 snprintf(tmp, 80, "fcs/feather-cmd-norm[%u]", num);
748 PropertyManager->Tie( tmp, this, num, &FGFCS::GetFeatherCmd,
749 &FGFCS::SetFeatherCmd);
750 snprintf(tmp, 80, "fcs/feather-pos-norm[%u]", num);
751 PropertyManager->Tie( tmp, this, num, &FGFCS::GetPropFeather,
752 &FGFCS::SetPropFeather);
755 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
757 void FGFCS::bindModel(void)
762 for (i=0; i<SteerPosDeg.size(); i++) {
763 if (GroundReactions->GetGearUnit(i)->GetSteerable()) {
764 snprintf(tmp,80,"fcs/steer-pos-deg[%u]",i);
765 PropertyManager->Tie( tmp, this, i, &FGFCS::GetSteerPosDeg, &FGFCS::SetSteerPosDeg);
770 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
772 void FGFCS::unbind(FGPropertyManager *node)
774 int N = node->nChildren();
775 for (int i=0; i<N; i++) {
776 if (node->getChild(i)->nChildren() ) {
777 unbind( (FGPropertyManager*)node->getChild(i) );
778 } else if ( node->getChild(i)->isTied() ) {
779 node->getChild(i)->untie();
784 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
785 // The bitmasked value choices are as follows:
786 // unset: In this case (the default) JSBSim would only print
787 // out the normally expected messages, essentially echoing
788 // the config files as they are read. If the environment
789 // variable is not set, debug_lvl is set to 1 internally
790 // 0: This requests JSBSim not to output any messages
792 // 1: This value explicity requests the normal JSBSim
794 // 2: This value asks for a message to be printed out when
795 // a class is instantiated
796 // 4: When this value is set, a message is displayed when a
797 // FGModel object executes its Run() method
798 // 8: When this value is set, various runtime state variables
799 // are printed out periodically
800 // 16: When set various parameters are sanity checked and
801 // a message is printed out when they go out of bounds
803 void FGFCS::Debug(int from)
805 if (debug_lvl <= 0) return;
807 if (debug_lvl & 1) { // Standard console startup message output
808 if (from == 2) { // Loader
809 cout << endl << " Flight Control (" << Name << ")" << endl;
812 if (debug_lvl & 2 ) { // Instantiation/Destruction notification
813 if (from == 0) cout << "Instantiated: FGFCS" << endl;
814 if (from == 1) cout << "Destroyed: FGFCS" << endl;
816 if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
818 if (debug_lvl & 8 ) { // Runtime state variables
820 if (debug_lvl & 16) { // Sanity checking
822 if (debug_lvl & 64) {
823 if (from == 0) { // Constructor
824 cout << IdSrc << endl;
825 cout << IdHdr << endl;