44#include "input_output/FGModelLoader.h"
45#include "input_output/FGLog.h"
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/FGActuator.h"
56#include "models/flight_control/FGAccelerometer.h"
57#include "models/flight_control/FGMagnetometer.h"
58#include "models/flight_control/FGGyro.h"
59#include "models/flight_control/FGWaypoint.h"
60#include "models/flight_control/FGAngles.h"
61#include "models/flight_control/FGDistributor.h"
62#include "models/flight_control/FGLinearActuator.h"
64#include "FGFCSChannel.h"
80 DaCmd = DeCmd = DrCmd = DfCmd = DsbCmd = DspCmd = 0;
81 PTrimCmd = YTrimCmd = RTrimCmd = 0.0;
82 GearCmd = GearPos = 1;
83 BrakePos.resize(FGLGear::bgNumBrakeGroups);
84 TailhookPos = WingFoldPos = 0.0;
87 for (i=0;i<NForms;i++) {
88 DePos[i] = DaLPos[i] = DaRPos[i] = DrPos[i] = 0.0;
89 DfPos[i] = DsbPos[i] = DspPos[i] = 0.0;
103 PropAdvanceCmd.clear();
105 PropFeatherCmd.clear();
110 for (i=0;i<SystemChannels.size();i++)
delete SystemChannels[i];
111 SystemChannels.clear();
118bool FGFCS::InitModel(
void)
120 if (!FGModel::InitModel())
return false;
124 for (i=0; i<ThrottlePos.size(); i++) ThrottlePos[i] = 0.0;
125 for (i=0; i<MixturePos.size(); i++) MixturePos[i] = 0.0;
126 for (i=0; i<ThrottleCmd.size(); i++) ThrottleCmd[i] = 0.0;
127 for (i=0; i<MixtureCmd.size(); i++) MixtureCmd[i] = 0.0;
128 for (i=0; i<PropAdvance.size(); i++) PropAdvance[i] = 0.0;
129 for (i=0; i<PropFeather.size(); i++) PropFeather[i] = 0.0;
131 DaCmd = DeCmd = DrCmd = DfCmd = DsbCmd = DspCmd = 0;
132 PTrimCmd = YTrimCmd = RTrimCmd = 0.0;
133 TailhookPos = WingFoldPos = 0.0;
135 for (i=0;i<NForms;i++) {
136 DePos[i] = DaLPos[i] = DaRPos[i] = DrPos[i] = 0.0;
137 DfPos[i] = DsbPos[i] = DspPos[i] = 0.0;
141 for (
unsigned int i=0; i<SystemChannels.size(); i++) SystemChannels[i]->Reset();
159 if (Holding)
return false;
163 for (i=0; i<ThrottlePos.size(); i++) ThrottlePos[i] = ThrottleCmd[i];
164 for (i=0; i<MixturePos.size(); i++) MixturePos[i] = MixtureCmd[i];
165 for (i=0; i<PropAdvance.size(); i++) PropAdvance[i] = PropAdvanceCmd[i];
166 for (i=0; i<PropFeather.size(); i++) PropFeather[i] = PropFeatherCmd[i];
169 for (i=0; i<SystemChannels.size(); i++) {
172 log <<
" Executing System Channel: " << SystemChannels[i]->GetName() << endl;
174 ChannelRate = SystemChannels[i]->GetRate();
175 SystemChannels[i]->Execute();
191 DaLPos[ofDeg] = pos*radtodeg;
194 DaLPos[ofRad] = pos*degtorad;
198 DaLPos[ofNorm] = pos;
200 DaLPos[ofMag] = fabs(DaLPos[ofRad]);
210 DaRPos[ofDeg] = pos*radtodeg;
213 DaRPos[ofRad] = pos*degtorad;
217 DaRPos[ofNorm] = pos;
219 DaRPos[ofMag] = fabs(DaRPos[ofRad]);
229 DePos[ofDeg] = pos*radtodeg;
232 DePos[ofRad] = pos*degtorad;
238 DePos[ofMag] = fabs(DePos[ofRad]);
248 DrPos[ofDeg] = pos*radtodeg;
251 DrPos[ofRad] = pos*degtorad;
257 DrPos[ofMag] = fabs(DrPos[ofRad]);
267 DfPos[ofDeg] = pos*radtodeg;
270 DfPos[ofRad] = pos*degtorad;
276 DfPos[ofMag] = fabs(DfPos[ofRad]);
286 DsbPos[ofDeg] = pos*radtodeg;
289 DsbPos[ofRad] = pos*degtorad;
293 DsbPos[ofNorm] = pos;
295 DsbPos[ofMag] = fabs(DsbPos[ofRad]);
305 DspPos[ofDeg] = pos*radtodeg;
308 DspPos[ofRad] = pos*degtorad;
312 DspPos[ofNorm] = pos;
314 DspPos[ofMag] = fabs(DspPos[ofRad]);
321 if (engineNum < (
int)ThrottleCmd.size()) {
323 for (
unsigned int ctr=0; ctr<ThrottleCmd.size(); ctr++)
324 ThrottleCmd[ctr] = setting;
326 ThrottleCmd[engineNum] = setting;
330 log <<
"Throttle " << engineNum <<
" does not exist! " << ThrottleCmd.size()
331 <<
" engines exist, but attempted throttle command is for engine "
332 << engineNum << endl;
340 if (engineNum < (
int)ThrottlePos.size()) {
342 for (
unsigned int ctr=0; ctr<ThrottlePos.size(); ctr++)
343 ThrottlePos[ctr] = setting;
345 ThrottlePos[engineNum] = setting;
349 log <<
"Throttle " << engineNum <<
" does not exist! " << ThrottlePos.size()
350 <<
" engines exist, but attempted throttle position setting is for engine "
351 << engineNum << endl;
357double FGFCS::GetThrottleCmd(
int engineNum)
const
359 if (engineNum < (
int)ThrottleCmd.size()) {
362 log <<
"Cannot get throttle value for ALL engines" << endl;
364 return ThrottleCmd[engineNum];
368 log <<
"Throttle " << engineNum <<
" does not exist! " << ThrottleCmd.size()
369 <<
" engines exist, but throttle setting for engine " << engineNum
370 <<
" is selected" << endl;
377double FGFCS::GetThrottlePos(
int engineNum)
const
379 if (engineNum < (
int)ThrottlePos.size()) {
382 log <<
"Cannot get throttle value for ALL engines" << endl;
384 return ThrottlePos[engineNum];
388 log <<
"Throttle " << engineNum <<
" does not exist! " << ThrottlePos.size()
389 <<
" engines exist, but attempted throttle position setting is for engine "
390 << engineNum << endl;
399 if (engineNum < (
int)MixtureCmd.size()) {
401 for (
unsigned int ctr=0; ctr<MixtureCmd.size(); ctr++)
402 MixtureCmd[ctr] = setting;
404 MixtureCmd[engineNum] = setting;
413 if (engineNum < (
int)MixturePos.size()) {
415 for (
unsigned int ctr=0; ctr<MixtureCmd.size(); ctr++)
416 MixturePos[ctr] = MixtureCmd[ctr];
418 MixturePos[engineNum] = setting;
427 if (engineNum < (
int)PropAdvanceCmd.size()) {
429 for (
unsigned int ctr=0; ctr<PropAdvanceCmd.size(); ctr++)
430 PropAdvanceCmd[ctr] = setting;
432 PropAdvanceCmd[engineNum] = setting;
441 if (engineNum < (
int)PropAdvance.size()) {
443 for (
unsigned int ctr=0; ctr<PropAdvanceCmd.size(); ctr++)
444 PropAdvance[ctr] = PropAdvanceCmd[ctr];
446 PropAdvance[engineNum] = setting;
455 if (engineNum < (
int)PropFeatherCmd.size()) {
457 for (
unsigned int ctr=0; ctr<PropFeatherCmd.size(); ctr++)
458 PropFeatherCmd[ctr] = setting;
460 PropFeatherCmd[engineNum] = setting;
469 if (engineNum < (
int)PropFeather.size()) {
471 for (
unsigned int ctr=0; ctr<PropFeatherCmd.size(); ctr++)
472 PropFeather[ctr] = PropFeatherCmd[ctr];
474 PropFeather[engineNum] = setting;
483 if (document->
GetName() ==
"autopilot") {
484 Name =
"Autopilot: ";
485 systype = stAutoPilot;
486 }
else if (document->
GetName() ==
"flight_control") {
489 }
else if (document->
GetName() ==
"system") {
504 while (channel_element) {
516 if (sOnOffProperty.length() > 0) {
517 SGPropertyNode* OnOffPropertyNode = PropertyManager->GetNode(sOnOffProperty);
518 if (OnOffPropertyNode ==
nullptr) {
520 err << LogFormat::BOLD << LogFormat::RED
521 <<
"The On/Off property, " << sOnOffProperty <<
" specified for channel "
523 <<
"understood. The simulation will abort" << LogFormat::RESET << endl;
526 newChannel =
new FGFCSChannel(
this, sChannelName, ChannelRate,
529 newChannel =
new FGFCSChannel(
this, sChannelName, ChannelRate);
531 SystemChannels.push_back(newChannel);
535 log << endl << LogFormat::BOLD << LogFormat::BLUE <<
" Channel "
536 << LogFormat::NORMAL << channel_element->
GetAttributeValue(
"name") << LogFormat::RESET << endl;
540 while (component_element) {
542 if ((component_element->
GetName() ==
string(
"lag_filter")) ||
543 (component_element->
GetName() ==
string(
"lead_lag_filter")) ||
544 (component_element->
GetName() ==
string(
"washout_filter")) ||
545 (component_element->
GetName() ==
string(
"second_order_filter")) )
547 newChannel->
Add(
new FGFilter(
this, component_element));
548 }
else if ((component_element->
GetName() ==
string(
"pure_gain")) ||
549 (component_element->
GetName() ==
string(
"scheduled_gain")) ||
550 (component_element->
GetName() ==
string(
"aerosurface_scale")))
552 newChannel->
Add(
new FGGain(
this, component_element));
553 }
else if (component_element->
GetName() ==
string(
"summer")) {
554 newChannel->
Add(
new FGSummer(
this, component_element));
555 }
else if (component_element->
GetName() ==
string(
"deadband")) {
557 }
else if (component_element->
GetName() ==
string(
"switch")) {
558 newChannel->
Add(
new FGSwitch(
this, component_element));
559 }
else if (component_element->
GetName() ==
string(
"kinematic")) {
560 newChannel->
Add(
new FGKinemat(
this, component_element));
561 }
else if (component_element->
GetName() ==
string(
"fcs_function")) {
563 }
else if (component_element->
GetName() ==
string(
"pid")) {
564 newChannel->
Add(
new FGPID(
this, component_element));
565 }
else if (component_element->
GetName() ==
string(
"integrator")) {
571 <<
" does not provide the parameter <c1>" << endl;
574 c1_el->ChangeName(
"ki");
577 newChannel->
Add(
new FGPID(
this, component_element));
578 }
else if (component_element->
GetName() ==
string(
"actuator")) {
580 }
else if (component_element->
GetName() ==
string(
"sensor")) {
581 newChannel->
Add(
new FGSensor(
this, component_element));
582 }
else if (component_element->
GetName() ==
string(
"accelerometer")) {
584 }
else if (component_element->
GetName() ==
string(
"magnetometer")) {
586 }
else if (component_element->
GetName() ==
string(
"gyro")) {
587 newChannel->
Add(
new FGGyro(
this, component_element));
588 }
else if ((component_element->
GetName() ==
string(
"waypoint_heading")) ||
589 (component_element->
GetName() ==
string(
"waypoint_distance")))
592 }
else if (component_element->
GetName() ==
string(
"angle")) {
593 newChannel->
Add(
new FGAngles(
this, component_element));
594 }
else if (component_element->
GetName() ==
string(
"distributor")) {
596 }
else if (component_element->
GetName() ==
string(
"linear_actuator")) {
600 log <<
"Unknown FCS component: " << component_element->
GetName() << endl;
604 log << LogFormat::BOLD << LogFormat::RED << endl <<
" " << s << endl;
605 log << LogFormat::RESET << endl;
613 PostLoad(document, FDMExec);
627SGPath FGFCS::FindFullPathName(
const SGPath& path)
const
629 SGPath name = FGModel::FindFullPathName(path);
630 if (systype != stSystem || !name.isNull())
return name;
633 const array<string, 1> dir_names = {
"Systems"};
636 const array<string, 2> dir_names = {
"Systems",
"systems"};
639 for(
const string& dir_name: dir_names) {
641 if (!name.isNull())
return name;
651 string CompStrings =
"";
652 bool firstime =
true;
655 for (
unsigned int i=0; i<SystemChannels.size(); i++)
657 for (
unsigned int c=0; c<SystemChannels[i]->GetNumComponents(); c++)
659 if (firstime) firstime =
false;
660 else CompStrings += delimiter;
662 CompStrings += SystemChannels[i]->GetComponent(c)->GetName();
674 std::ostringstream buf;
676 bool firstime =
true;
679 for (
unsigned int i=0; i<SystemChannels.size(); i++)
681 for (
unsigned int c=0; c<SystemChannels[i]->GetNumComponents(); c++)
683 if (firstime) firstime =
false;
684 else buf << delimiter;
686 buf << setprecision(9) << SystemChannels[i]->GetComponent(c)->GetOutput();
696void FGFCS::AddThrottle(
void)
698 ThrottleCmd.push_back(0.0);
699 ThrottlePos.push_back(0.0);
700 MixtureCmd.push_back(0.0);
701 MixturePos.push_back(0.0);
702 PropAdvanceCmd.push_back(0.0);
703 PropAdvance.push_back(0.0);
704 PropFeatherCmd.push_back(
false);
705 PropFeather.push_back(
false);
707 unsigned int num = (
unsigned int)ThrottleCmd.size()-1;
713double FGFCS::GetDt(
void)
const
720void FGFCS::bind(
void)
735 PropertyManager->Tie(
"fcs/mag-left-aileron-pos-rad",
this, ofMag, &
FGFCS::GetDaLPos);
740 PropertyManager->Tie(
"fcs/mag-right-aileron-pos-rad",
this, ofMag, &
FGFCS::GetDaRPos);
745 PropertyManager->Tie(
"fcs/mag-elevator-pos-rad",
this, ofMag, &
FGFCS::GetDePos);
750 PropertyManager->Tie(
"fcs/mag-rudder-pos-rad",
this,ofMag, &
FGFCS::GetDrPos);
759 PropertyManager->Tie(
"fcs/mag-speedbrake-pos-rad",
this,ofMag, &
FGFCS::GetDsbPos);
764 PropertyManager->Tie(
"fcs/mag-spoiler-pos-rad",
this, ofMag, &
FGFCS::GetDspPos);
774 PropertyManager->Tie(
"simulation/channel-dt",
this, &FGFCS::GetChannelDeltaT);
781void FGFCS::bindThrottle(
unsigned int num)
785 tmp = CreateIndexedPropertyName(
"fcs/throttle-cmd-norm", num);
786 PropertyManager->Tie( tmp.c_str(),
this, num, &FGFCS::GetThrottleCmd,
788 tmp = CreateIndexedPropertyName(
"fcs/throttle-pos-norm", num);
789 PropertyManager->Tie( tmp.c_str(),
this, num, &FGFCS::GetThrottlePos,
791 tmp = CreateIndexedPropertyName(
"fcs/mixture-cmd-norm", num);
792 PropertyManager->Tie( tmp.c_str(),
this, num, &FGFCS::GetMixtureCmd,
794 tmp = CreateIndexedPropertyName(
"fcs/mixture-pos-norm", num);
795 PropertyManager->Tie( tmp.c_str(),
this, num, &FGFCS::GetMixturePos,
797 tmp = CreateIndexedPropertyName(
"fcs/advance-cmd-norm", num);
800 tmp = CreateIndexedPropertyName(
"fcs/advance-pos-norm", num);
801 PropertyManager->Tie( tmp.c_str(),
this, num, &FGFCS::GetPropAdvance,
803 tmp = CreateIndexedPropertyName(
"fcs/feather-cmd-norm", num);
806 tmp = CreateIndexedPropertyName(
"fcs/feather-pos-norm", num);
807 PropertyManager->Tie( tmp.c_str(),
this, num, &FGFCS::GetPropFeather,
830void FGFCS::Debug(
int from)
832 if (debug_lvl <= 0)
return;
835 FGLogging log(LogLevel::DEBUG);
837 log << endl <<
" " << Name << endl;
840 if (debug_lvl & 2 ) {
841 FGLogging log(LogLevel::DEBUG);
842 if (from == 0) log <<
"Instantiated: FGFCS" << endl;
843 if (from == 1) log <<
"Destroyed: FGFCS" << endl;
845 if (debug_lvl & 4 ) {
847 if (debug_lvl & 8 ) {
849 if (debug_lvl & 16) {
851 if (debug_lvl & 64) {
Element * FindElement(const std::string &el="")
Searches for a specified element.
const std::string & GetName(void) const
Retrieves the element name.
double GetAttributeValueAsNumber(const std::string &key)
Retrieves an attribute value as a double precision real number.
Element * GetElement(unsigned int el=0)
Returns a pointer to the element requested by index.
std::string GetAttributeValue(const std::string &key)
Retrieves an attribute.
void AddAttribute(const std::string &name, const std::string &value)
Stores an attribute belonging to this element.
Element * FindNextElement(const std::string &el="")
Searches for the next element as specified.
bool HasAttribute(const std::string &key)
Determines if an element has the supplied attribute.
Element * GetNextElement(void)
Returns a pointer to the next element in the list.
Encapsulates a Accelerometer component for the flight control system.
Encapsulates an Actuator component for the flight control system.
Provides a way to determine the smallest included angle.
Models a deadband object.
Encapsulates a distributor for the flight control system.
void Add(FGFCSComponent *comp)
Adds a component to a channel.
Models a FCSFunction object.
void SetThrottlePos(int engine, double cmd)
Sets the actual throttle setting for the specified engine.
void SetPitchTrimCmd(double cmd)
Sets the pitch trim command.
void SetDaLPos(int form, double pos)
Sets the left aileron position.
bool Load(Element *el) override
Loads the Flight Control System.
void SetGearPos(double gearpos)
Set the gear extend/retract position, defaults to down.
double GetCBrake(void) const
Gets the center brake.
void SetDsbPos(int form, double pos)
Sets the speedbrake position.
double GetLBrake(void) const
Gets the left brake.
double GetDfPos(int form=ofRad) const
Gets the flaps position.
void SetDsbCmd(double cmd)
Sets the speedbrake command.
bool GetFeatherCmd(int engine) const
Gets the prop feather command.
double GetDfCmd(void) const
Gets the flaps command.
double GetDeCmd(void) const
Gets the elevator command.
std::string GetComponentStrings(const std::string &delimiter) const
Retrieves all component names for inclusion in output stream.
void SetMixtureCmd(int engine, double cmd)
Sets the mixture command for the specified engine.
double GetTailhookPos(void) const
Gets the tailhook position (0 up, 1 down)
void SetPropFeather(int engine, bool cmd)
Sets the actual prop feather setting for the specified engine.
double GetPropAdvanceCmd(int engine) const
Gets the prop pitch command.
void SetFeatherCmd(int engine, bool cmd)
Sets the propeller feather command for the specified engine.
void SetDeCmd(double cmd)
Sets the elevator command.
double GetDePos(int form=ofRad) const
Gets the elevator position.
void SetDrPos(int form, double pos)
Sets the rudder position.
void SetMixturePos(int engine, double cmd)
Sets the actual mixture setting for the specified engine.
void SetDaCmd(double cmd)
Sets the aileron command.
double GetDsbPos(int form=ofRad) const
Gets the speedbrake position.
double GetRBrake(void) const
Gets the right brake.
void SetDaRPos(int form, double pos)
Sets the right aileron position.
void SetDePos(int form, double pos)
Sets the elevator position.
void SetRBrake(double cmd)
Sets the right brake group.
void SetDrCmd(double cmd)
Sets the rudder command.
double GetDrCmd(void) const
Gets the rudder command.
FGFCS(FGFDMExec *)
Constructor.
bool Run(bool Holding) override
Runs the Flight Controls model; called by the Executive Can pass in a value indicating if the executi...
double GetDaCmd(void) const
Gets the aileron command.
double GetDaLPos(int form=ofRad) const
Gets the left aileron position.
double GetRollTrimCmd(void) const
Gets the aileron trim command.
~FGFCS() override
Destructor.
void SetDfPos(int form, double pos)
Sets the flaps position.
double GetDaRPos(int form=ofRad) const
Gets the right aileron position.
void SetDspPos(int form, double pos)
Sets the spoiler position.
void SetTailhookPos(double hookpos)
Set the tailhook position.
void SetDfCmd(double cmd)
Sets the flaps command.
double GetBrake(FGLGear::BrakeGroup bg)
Gets the brake for a specified group.
double GetWingFoldPos(void) const
Gets the wing fold position (0 unfolded, 1 folded)
double GetDspCmd(void) const
Gets the spoiler command.
void SetPropAdvance(int engine, double cmd)
Sets the actual prop pitch setting for the specified engine.
std::string GetComponentValues(const std::string &delimiter) const
Retrieves all component outputs for inclusion in output stream.
double GetPitchTrimCmd(void) const
Gets the pitch trim command.
void SetThrottleCmd(int engine, double cmd)
Sets the throttle command for the specified engine.
double GetGearPos(void) const
Gets the gear position (0 up, 1 down), defaults to down.
double GetDsbCmd(void) const
Gets the speedbrake command.
void SetDspCmd(double cmd)
Sets the spoilers command.
void SetLBrake(double cmd)
Sets the left brake group.
double GetDspPos(int form=ofRad) const
Gets the spoiler position.
void SetCBrake(double cmd)
Sets the center brake group.
double GetYawTrimCmd(void) const
Gets the rudder trim command.
void SetPropAdvanceCmd(int engine, double cmd)
Sets the propeller pitch command for the specified engine.
void SetRollTrimCmd(double cmd)
Sets the aileron trim command.
void SetYawTrimCmd(double cmd)
Sets the rudder trim command.
double GetGearCmd(void) const
Get the gear extend/retract command.
void SetWingFoldPos(double foldpos)
Set the wing fold position.
double GetDrPos(int form=ofRad) const
Gets the rudder position.
void SetGearCmd(double gearcmd)
Set the gear extend/retract command, defaults to down.
Encapsulates the JSBSim simulation executive.
const SGPath & GetFullAircraftPath(void)
Retrieves the full aircraft path name.
double GetDeltaT(void) const
Returns the simulation delta T.
const SGPath & GetSystemsPath(void)
Retrieves the systems path.
Encapsulates a filter for the flight control system.
Encapsulates a gain component for the flight control system.
Encapsulates a Gyro component for the flight control system.
Encapsulates a kinematic (mechanical) component for the flight control system.
BrakeGroup
Brake grouping enumerators.
Models a flight control system summing component.
Encapsulates a magnetometer component for the flight control system.
Base class for all scheduled JSBSim models.
virtual bool Run(bool Holding)
Runs the model; called by the Executive.
bool Upload(Element *el, bool preLoad)
Uploads this model in memory.
Encapsulates a PID control component for the flight control system.
Encapsulates a Sensor component for the flight control system.
Models a flight control system summing component.
Encapsulates a switch for the flight control system.
Models a Waypoint object.
A node in a property tree.
Main namespace for the JSBSim Flight Dynamics Model.