Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BLDC engine added #560

Merged
merged 27 commits into from
Jan 11, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
ad4550d
first release FRBLdc.cpp and test scripts
pbecchi Dec 19, 2021
bafa85a
Programmable braking torque
pbecchi Dec 28, 2021
db1afa1
Delete Cobra2217.xml
pbecchi Dec 28, 2021
3708f40
added F450 test case
pbecchi Dec 28, 2021
541753a
Update FGBldc.h
pbecchi Dec 28, 2021
49df919
FGpropulsion.cpp modified
pbecchi Dec 29, 2021
0ec7d4d
local modifications
pbecchi Dec 29, 2021
8ea4b13
Merge branch 'DLBGengine' of https://github.com/pbecchi/jsbsim into D…
pbecchi Dec 29, 2021
43e2f64
Cmakelists_propulsion
pbecchi Jan 1, 2022
701190c
cleaned_examples
pbecchi Jan 8, 2022
be747db
Merge branch 'DLBGengine' of https://github.com/pbecchi/jsbsim into D…
pbecchi Jan 8, 2022
f566702
FGBLdc.cpp_reformatted
pbecchi Jan 8, 2022
841d32f
formatCorrections
pbecchi Jan 8, 2022
031a001
Correction_Reformat_requested
pbecchi Jan 8, 2022
313b169
updatedMakefile&addedElectricalUnits
pbecchi Jan 8, 2022
9c2b187
corrections
pbecchi Jan 10, 2022
e76c643
AdditionalCorrections
pbecchi Jan 10, 2022
927d82b
Update src/models/propulsion/FGBrushLessDCMotor.cpp
pbecchi Jan 10, 2022
7b27fc6
Update src/input_output/FGXMLElement.cpp
pbecchi Jan 10, 2022
5948851
Update src/models/propulsion/FGBrushLessDCMotor.h
pbecchi Jan 10, 2022
2ce9a4e
Update src/models/propulsion/FGBrushLessDCMotor.cpp
pbecchi Jan 10, 2022
3da9f59
Update src/models/propulsion/FGBrushLessDCMotor.cpp
pbecchi Jan 10, 2022
7273ed7
Update src/models/propulsion/FGBrushLessDCMotor.cpp
pbecchi Jan 10, 2022
4d5b655
Update src/models/propulsion/FGBrushLessDCMotor.cpp
pbecchi Jan 10, 2022
d19358f
Update src/models/propulsion/FGBrushLessDCMotor.cpp
pbecchi Jan 10, 2022
073615f
Remaining_comments
pbecchi Jan 11, 2022
58a7d77
Merge branch 'DLBGengine' of https://github.com/pbecchi/jsbsim into D…
pbecchi Jan 11, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions JSBSim.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,7 @@
<ClInclude Include="src\models\flight_control\FGDistributor.h" />
<ClInclude Include="src\models\flight_control\FGLinearActuator.h" />
<ClInclude Include="src\models\flight_control\FGWaypoint.h" />
<ClInclude Include="src\models\propulsion\FGBrushLessDCMotor.h" />
<ClInclude Include="src\models\propulsion\FGTransmission.h" />
<ClInclude Include="src\simgear\xml\ascii.h" />
<ClInclude Include="src\simgear\xml\asciitab.h" />
Expand Down Expand Up @@ -371,6 +372,7 @@
<ClCompile Include="src\models\flight_control\FGDistributor.cpp" />
<ClCompile Include="src\models\flight_control\FGLinearActuator.cpp" />
<ClCompile Include="src\models\flight_control\FGWaypoint.cpp" />
<ClCompile Include="src\models\propulsion\FGBrushLessDCMotor.cpp" />
<ClCompile Include="src\models\propulsion\FGTransmission.cpp" />
<ClCompile Include="src\simgear\magvar\coremag.cxx" />
<ClCompile Include="src\simgear\xml\easyxml.cxx" />
Expand Down
6 changes: 6 additions & 0 deletions JSBSim.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,9 @@
<ClCompile Include="src\math\FGStateSpace.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\models\propulsion\FGBrushLessDCMotor.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\input_output\FGInputSocket.h">
Expand Down Expand Up @@ -673,5 +676,8 @@
<ClInclude Include="src\math\FGStateSpace.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\models\propulsion\FGBrushLessDCMotor.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>
4 changes: 4 additions & 0 deletions src/input_output/FGXMLElement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,10 @@ Element::Element(const string& nm)
// Gravitational
convert["FT3/SEC2"]["FT3/SEC2"] = 1.0;
convert["M3/SEC2"]["M3/SEC2"] = 1.0;
// Electrical
convert["VOLTS"]["VOLTS"] = 1.0;
convert["OHMS"]["OHMS"] = 1.0;
convert["AMPERES"]["AMPERES"] = 1.0;
}
}

Expand Down
8 changes: 7 additions & 1 deletion src/models/FGPropulsion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ INCLUDES
#include "models/propulsion/FGTurboProp.h"
#include "models/propulsion/FGTank.h"
#include "input_output/FGModelLoader.h"
#include "models/propulsion/FGBrushLessDCMotor.h"


using namespace std;

Expand Down Expand Up @@ -397,7 +399,11 @@ bool FGPropulsion::Load(Element* el)
} else if (engine_element->FindElement("electric_engine")) {
Element *element = engine_element->FindElement("electric_engine");
Engines.push_back(make_shared<FGElectric>(FDMExec, element, numEngines, in));
} else {
} else if (engine_element->FindElement("brushless_dc_motor")) {
Element *element = engine_element->FindElement("brushless_dc_motor");
Engines.push_back(make_shared<FGBrushLessDCMotor>(FDMExec, element, numEngines, in));
}
else {
cerr << engine_element->ReadFrom() << " Unknown engine type" << endl;
return false;
}
Expand Down
70 changes: 36 additions & 34 deletions src/models/propulsion/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,34 +1,36 @@
set(SOURCES FGElectric.cpp
pbecchi marked this conversation as resolved.
Show resolved Hide resolved
FGEngine.cpp
FGForce.cpp
FGNozzle.cpp
FGPiston.cpp
FGPropeller.cpp
FGRocket.cpp
FGTank.cpp
FGThruster.cpp
FGTurbine.cpp
FGTurboProp.cpp
FGTransmission.cpp
FGRotor.cpp)

set(HEADERS FGElectric.h
FGEngine.h
FGForce.h
FGNozzle.h
FGPiston.h
FGPropeller.h
FGRocket.h
FGTank.h
FGThruster.h
FGTurbine.h
FGTurboProp.h
FGTransmission.h
FGRotor.h)

add_library(Propulsion OBJECT ${HEADERS} ${SOURCES})
set_target_properties(Propulsion PROPERTIES TARGET_DIRECTORY
${CMAKE_CURRENT_SOURCE_DIR})

install(FILES ${HEADERS} DESTINATION include/JSBSim/models/propulsion
COMPONENT devel)
set(SOURCES FGElectric.cpp
FGEngine.cpp
FGForce.cpp
FGNozzle.cpp
FGPiston.cpp
FGPropeller.cpp
FGRocket.cpp
FGTank.cpp
FGThruster.cpp
FGTurbine.cpp
FGTurboProp.cpp
FGTransmission.cpp
FGRotor.cpp
FGBrushLessDCMotor.cpp)

set(HEADERS FGElectric.h
FGEngine.h
FGForce.h
FGNozzle.h
FGPiston.h
FGPropeller.h
FGRocket.h
FGTank.h
FGThruster.h
FGTurbine.h
FGTurboProp.h
FGTransmission.h
FGRotor.h
FGBrushLessDCMotor.h)

add_library(Propulsion OBJECT ${HEADERS} ${SOURCES})
set_target_properties(Propulsion PROPERTIES TARGET_DIRECTORY
${CMAKE_CURRENT_SOURCE_DIR})

install(FILES ${HEADERS} DESTINATION include/JSBSim/models/propulsion
COMPONENT devel)
253 changes: 253 additions & 0 deletions src/models/propulsion/FGBrushLessDCMotor.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,253 @@
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Module: FGBrushLessDCMotor.cpp
Autor Paolo Becchi
1st release 1/1/2022
Purpose: This module models an BLDC electric motor

------------- Copyright (C) 2022 Paolo Becchi ([email protected]) -------------

This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the Free
Software Foundation; either version 2 of the License, or (at your option) any
later version.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
details.

You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation, Inc., 59
Temple Place - Suite 330, Boston, MA 02111-1307, USA.

Further information about the GNU Lesser General Public License can also be
found on the world wide web at http://www.gnu.org

FUNCTIONAL DESCRIPTION
--------------------------------------------------------------------------------
Following code represent a new BrushLess DC motor to be used as alternative
to basic electric motor.
BLDC motor code is based on basic "3 constant motor equations"
pbecchi marked this conversation as resolved.
Show resolved Hide resolved
It require 3 basic physical motor properties:
Kv speed motor constant [RPM/Volt]
Rm internal coil resistance [Ohms]
I0 no load current [Amperes]

HISTORY
--------------------------------------------------------------------------------
1/01/2022 Created


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/

#include <iostream>
#include <sstream>
#include <math.h>

#include "FGFDMExec.h"
#include "FGBrushLessDCMotor.h"
#include "FGPropeller.h"
#include "input_output/FGXMLElement.h"

using namespace std;

namespace JSBSim {

/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
CLASS IMPLEMENTATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/

FGBrushLessDCMotor::FGBrushLessDCMotor(FGFDMExec* exec, Element* el, int engine_number, struct FGEngine::Inputs& input)
: FGEngine(engine_number, input)
{
Load(exec, el);

Type = etElectric;



if (el->FindElement("maxvolts"))
MaxVolts = el->FindElementValueAsNumberConvertTo("maxvolts", "VOLTS");
else {
cerr << el->ReadFrom()
<< "<maxvolts> is a mandatory parameter" << endl;
throw JSBBaseException("Missing parameter");
}

if (el->FindElement("velocityconstant"))
VelocityConstant = el->FindElementValueAsNumber("velocityconstant");
pbecchi marked this conversation as resolved.
Show resolved Hide resolved
else {
cerr << el->ReadFrom()
<< "<velocityconstant> is a mandatory parameter" << endl;
throw JSBBaseException("Missing parameter");
}

if (el->FindElement("coilresistance"))
CoilResistance = el->FindElementValueAsNumberConvertTo("coilresistance", "OHMS");
else {
cerr << el->ReadFrom()
<< "<coilresistance> is a mandatory parameter" << endl;
throw JSBBaseException("Missing parameter");
}
if (el->FindElement("noloadcurrent"))
NoLoadCurrent = el->FindElementValueAsNumberConvertTo("noloadcurrent", "AMPERES");
else {
cerr << el->ReadFrom()
<< "<noloadcurrent> is a mandatory parameter" << endl;
throw JSBBaseException("Missing parameter");
}
if (el->FindElement("deceleration_factor"))
DecelerationFactor = el->FindElementValueAsNumber("deceleration_factor");
pbecchi marked this conversation as resolved.
Show resolved Hide resolved
else {
cout << el->ReadFrom()
<< "Using default value " << DecelerationFactor << " for <deceleration_factor>" << endl;
}

MaxCurrent = MaxVolts / CoilResistance + NoLoadCurrent;

PowerWatts = MaxCurrent * MaxVolts;

string base_property_name = CreateIndexedPropertyName("propulsion/engine", EngineNumber);

exec->GetPropertyManager()->Tie(base_property_name + "/power-hp", &HP);

exec->GetPropertyManager()->Tie(base_property_name + "/current-amperes", &CurrentRequired);

Debug(0); // Call Debug() routine from constructor if needed
}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

FGBrushLessDCMotor::~FGBrushLessDCMotor()
{
Debug(1); // Call Debug() routine from constructor if needed
}


//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

void FGBrushLessDCMotor::Calculate(void)
{
RunPreFunctions();

if (Thruster->GetType() == FGThruster::ttPropeller) {
((FGPropeller*)Thruster)->SetAdvance(in.PropAdvance[EngineNumber]);
((FGPropeller*)Thruster)->SetFeather(in.PropFeather[EngineNumber]);
}

RPM = Thruster->GetRPM();
TorqueRequired = abs(((FGPropeller*)Thruster)->GetTorque()); //units [#*ft]

CurrentRequired = (TorqueRequired * VelocityConstant) / TorqueConstant;

// total current required must include no load current i0
CurrentRequired = CurrentRequired + NoLoadCurrent;

V = MaxVolts * in.ThrottlePos[EngineNumber];

// Delta RPM = (input voltage - currentRequired * coil resistance) * velocity costant
DeltaRPM = round((V - CurrentRequired * CoilResistance) * VelocityConstant);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the purpose of this call to round() ? Why should DeltaRPM be rounded to the nearest integer ? I'd expect that to be destabilizing numerically the computations.


// Torque is MaxTorque (stall torque) at 0 RPM and linearly go to 0 at max RPM (MaxVolts*VelocityCostant)
// MaxTorque = MaxCurrent*torqueconstant/velocityconstant*(1-RPM/maxRPM)

MaxTorque = MaxCurrent / VelocityConstant * TorqueConstant * (1 - RPM / (MaxVolts* VelocityConstant));

TorqueAvailable = MaxTorque - TorqueRequired;
InertiaTorque = (((DeltaRPM/60)*(2.0 * M_PI))/(max(0.00001, in.TotalDeltaT))) * ((FGPropeller*)Thruster)->GetIxx();

// compute acceleration and deceleration phases:
// Acceleration is due to the max delta torque available and is limited to the inertial forces

if (DeltaRPM >= 0) {
TargetTorque = min(InertiaTorque, TorqueAvailable) + TorqueRequired;
} else {
// Deceleration is due to braking force given by the ESC and set by parameter deceleration_time
TargetTorque = TorqueRequired - min(abs(InertiaTorque)/(max(DecelerationFactor,0.01)*30),RPM*TorqueConstant/VelocityConstant/VelocityConstant/CoilResistance);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This wait the factor is approximately the time delay in seconds

Rather make this a constant with an appropriate name and comment so that anyone else looking at the code knows what it is.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RPM*TorqueConstant/VelocityConstant/VelocityConstant/CoilResistance) describes the energy dissipated by the Joule effect, doesn't it ?

}

EnginePower = ((2 * M_PI) * max(RPM, 0.0001) * TargetTorque) / 60; //units [#*ft/s]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are you using max(RPM, 0.0001) ? What's wrong with getting EnginePower null ? There again I'd expect this to destabilize the motionless state of the propeller.

HP = EnginePower /hptowatts*NMtoftpound; // units[HP]
LoadThrusterInputs();
Thruster->Calculate(EnginePower);

RunPostFunctions();
}


//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

string FGBrushLessDCMotor::GetEngineLabels(const string& delimiter)
{
std::ostringstream buf;

buf << Name << " HP (engine " << EngineNumber << ")" << delimiter
<< Thruster->GetThrusterLabels(EngineNumber, delimiter);

return buf.str();
}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

string FGBrushLessDCMotor::GetEngineValues(const string& delimiter)
{
std::ostringstream buf;

buf << HP << delimiter
<< Thruster->GetThrusterValues(EngineNumber, delimiter);

return buf.str();
}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//
// The bitmasked value choices are as follows:
// unset: In this case (the default) JSBSim would only print
// out the normally expected messages, essentially echoing
// the config files as they are read. If the environment
// variable is not set, debug_lvl is set to 1 internally
// 0: This requests JSBSim not to output any messages
// whatsoever.
// 1: This value explicity requests the normal JSBSim
// startup messages
// 2: This value asks for a message to be printed out when
// a class is instantiated
// 4: When this value is set, a message is displayed when a
// FGModel object executes its Run() method
// 8: When this value is set, various runtime state variables
// are printed out periodically
// 16: When set various parameters are sanity checked and
// a message is printed out when they go out of bounds

void FGBrushLessDCMotor::Debug(int from)
{
if (debug_lvl <= 0) return;

if (debug_lvl & 1) { // Standard console startup message output
if (from == 0) { // Constructor

cout << "\n Engine Name: " << Name << endl;
cout << " Power Watts: " << PowerWatts << endl;

}
}
if (debug_lvl & 2 ) { // Instantiation/Destruction notification
if (from == 0) cout << "Instantiated: FGBrushLessDCMotor" << endl;
if (from == 1) cout << "Destroyed: FGBrushLessDCMotor" << endl;
}
if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
}
if (debug_lvl & 8 ) { // Runtime state variables
}
if (debug_lvl & 16) { // Sanity checking
}
if (debug_lvl & 64) {
if (from == 0) { // Constructor
}
}
}

} // namespace JSBSim
Loading