Completed new PID mode for boost control

This commit is contained in:
Josh Stewart 2017-09-04 11:50:55 +10:00
parent 3b33094230
commit 4e858f1ca8
6 changed files with 56 additions and 61 deletions

View File

@ -714,7 +714,7 @@ page = 11
rotarySplitBins = array, U08, 17, [8], "TPS", 2.0, 0.0, 0.0, 100.0, 0
#endif
boostSens = scalar, U16, 25, "", 1, 0, 0, 5000, 0
boostIntv = scalar, U08, 27, "ms", 1, 0, 0, 80, 0
boostIntv = scalar, U08, 27, "ms", 1, 0, 0, 250, 0
unused11_28_192 = array, U08, 28,[164], "RPM", 100.0, 0.0, 100, 25500, 0
;-------------------------------------------------------------------------------
@ -786,6 +786,7 @@ page = 11
defaultValue = iacCLmaxDuty,100
defaultValue = boostMinDuty,0
defaultValue = boostMaxDuty,100
defaultValue = boostSens, 2000
defaultValue = boostIntv, 15
defaultValue = sparkDur, 1.0
defaultValue = speeduino_tsCanId, 0
@ -1297,11 +1298,13 @@ menuDialog = main
dialog = fuelpump, "Fuel pump"
field = "Fuel pump pin", fuelPumpPin
field = "Fuel pump prime duration", fpPrime
dialog = crankingEnrichDialog, "Cranking Enrichment", yAxis
panel = cranking_enrich_curve
dialog = crankingIgnOptions, "Cranking Timing", yAxis
field = "Cranking advance Angle", CrankAng
field = "Cranking bypass", ignBypassEnable
field = "Bypass output pin", ignBypassPin { ignBypassEnable }
field = "Fix cranking timing with trigger", ignCranklock, { TrigPattern == 1 || TrigPattern == 4 || TrigPattern == 10}

View File

@ -62,21 +62,21 @@ void initialiseAuxPWM()
ENABLE_VVT_TIMER(); //Turn on the B compare unit (ie turn on the interrupt)
boostPID.SetOutputLimits(configPage1.boostMinDuty, configPage1.boostMaxDuty);
boostPID.SetTunings(configPage3.boostKP, configPage3.boostKI, configPage3.boostKD);
boostPID.SetMode(AUTOMATIC); //Turn PID on
if(configPage3.boostMode == BOOST_MODE_SIMPLE) { boostPID.SetTunings(100, 100, 100); }
else { boostPID.SetTunings(configPage3.boostKP, configPage3.boostKI, configPage3.boostKD); }
currentStatus.boostDuty = 0;
boostCounter = 0;
}
#define BOOST_HYSTER 40
void boostControl()
{
if( configPage3.boostEnabled==1 )
{
if(currentStatus.MAP >= 50)
if( (boostCounter & 3) == 1) { currentStatus.boostTarget = get3DTableValue(&boostTable, currentStatus.TPS, currentStatus.RPM) * 2; } //Boost target table is in kpa and divided by 2
if(currentStatus.MAP >= (currentStatus.boostTarget - BOOST_HYSTER) )
{
if( (boostCounter & 3) == 1) { currentStatus.boostTarget = get3DTableValue(&boostTable, currentStatus.TPS, currentStatus.RPM) * 2; } //Boost target table is in kpa and divided by 2
//If flex fuel is enabled, there can be an adder to the boost target based on ethanol content
if( configPage1.flexEnabled == 1 )
{
@ -85,38 +85,39 @@ void boostControl()
currentStatus.boostTarget += boostAdder;
}
//boostTargetx100 = boost_cl_target_boost * 100;
//currentStatus.boostTarget = boost_cl_target_boost >> 1; //Boost target is sent as a byte value to TS and so is divided by 2
if(currentStatus.boostTarget > 0)
{
//This only needs to be run very infrequently, once every 16 calls to boostControl(). This is approx. once per second
if( (boostCounter & 15) == 1)
{
boostPID.SetOutputLimits(configPage1.boostMinDuty, configPage1.boostMaxDuty);
boostPID.SetTunings(configPage3.boostKP, configPage3.boostKI, configPage3.boostKD);
if(configPage3.boostMode == BOOST_MODE_SIMPLE) { boostPID.SetTunings(100, 100, 100); }
else { boostPID.SetTunings(configPage3.boostKP, configPage3.boostKI, configPage3.boostKD); }
}
boostPID.Compute();
byte PIDcomputed = boostPID.Compute(); //Compute() returns false if the required interval has not yet passed.
if(currentStatus.boostDuty == 0) { DISABLE_BOOST_TIMER(); BOOST_PIN_LOW(); } //If boost duty is 0, shut everything down
else
{
boost_pwm_target_value = ((unsigned long)(currentStatus.boostDuty) * boost_pwm_max_count) / 10000; //Convert boost duty (Which is a % multipled by 100) to a pwm count
ENABLE_BOOST_TIMER(); //Turn on the compare unit (ie turn on the interrupt) if boost duty >0
if(PIDcomputed == true)
{
boost_pwm_target_value = ((unsigned long)(currentStatus.boostDuty) * boost_pwm_max_count) / 10000; //Convert boost duty (Which is a % multipled by 100) to a pwm count
ENABLE_BOOST_TIMER(); //Turn on the compare unit (ie turn on the interrupt) if boost duty >0
}
}
}
else
{
//If boost target is 0, turn everything off
DISABLE_BOOST_TIMER(); //Turn off timer
BOOST_PIN_LOW();
boostDisable();
}
}
else
{
//Boost control does nothing if kPa below 100
DISABLE_BOOST_TIMER(); //Turn off timer
BOOST_PIN_LOW(); //Make sure solenoid is off (0% duty)
//Boost control does nothing if kPa below the hyster point
boostDisable();
}
}
else { DISABLE_BOOST_TIMER(); } // Disable timer channel
@ -150,6 +151,14 @@ void vvtControl()
else { DISABLE_VVT_TIMER(); } // Disable timer channel
}
void boostDisable()
{
boostPID.Initialize(); //This resets the ITerm value to prevent rubber banding
currentStatus.boostDuty = 0;
DISABLE_BOOST_TIMER(); //Turn off timer
BOOST_PIN_LOW(); //Make sure solenoid is off (0% duty)
}
//The interrupt to control the Boost PWM
#if defined(CORE_AVR)
ISR(TIMER1_COMPA_vect)

View File

@ -110,6 +110,9 @@
#define ROTARY_IGN_FD 1
#define ROTARY_IGN_RX8 2
#define BOOST_MODE_SIMPLE 0
#define BOOST_MODE_FULL 1
#define SIZE_BYTE 8
#define SIZE_INT 16

View File

@ -123,7 +123,7 @@ void (*ign4EndFunction)();
void (*ign5StartFunction)();
void (*ign5EndFunction)();
int timePerDegree;
volatile int timePerDegree;
byte degreesPerLoop; //The number of crank degrees that pass for each mainloop of the program
volatile bool fpPrimed = false; //Tracks whether or not the fuel pump priming has been completed yet
bool initialisationComplete = false; //Tracks whether the setup() functino has run completely
@ -723,8 +723,7 @@ void loop()
currentStatus.rpmDOT = 0;
ignitionOn = false;
fuelOn = false;
if (fpPrimed) { digitalWrite(pinFuelPump, LOW); } //Turn off the fuel pump, but only if the priming is complete
fuelPumpOn = false;
if (fpPrimed == true) { digitalWrite(pinFuelPump, LOW); fuelPumpOn = false; } //Turn off the fuel pump, but only if the priming is complete
disableIdle(); //Turn off the idle PWM
BIT_CLEAR(currentStatus.engine, BIT_ENGINE_CRANK); //Clear cranking bit (Can otherwise get stuck 'on' even with 0 rpm)
BIT_CLEAR(currentStatus.engine, BIT_ENGINE_WARMUP); //Same as above except for WUE
@ -735,8 +734,7 @@ void loop()
VVT_PIN_LOW();
DISABLE_VVT_TIMER();
DISABLE_BOOST_TIMER(); //Turn off timer
BOOST_PIN_LOW();
boostDisable();
}
//Uncomment the following for testing
@ -794,9 +792,10 @@ void loop()
//And check whether the tooth log buffer is ready
if(toothHistoryIndex > TOOTH_LOG_SIZE) { BIT_SET(currentStatus.squirt, BIT_SQUIRT_TOOTHLOG1READY); }
//Most boost tends to run at about 30Hz, so placing it here ensures a new target time is fetched frequently enough
//currentStatus.RPM = 3000;
boostControl();
}
if(BIT_CHECK(LOOP_TIMER, BIT_TIMER_30HZ)) //Every 64 loops
{

View File

@ -389,6 +389,7 @@ int integerPID::GetMode(){ return inAuto ? AUTOMATIC : MANUAL;}
int integerPID::GetDirection(){ return controllerDirection;}
//************************************************************************************************************************
#define limitMultiplier 100 //How much outMin and OutMax must be multiplied by to get them in the same scale as the output
/*Constructor (...)*********************************************************
* The parameters specified here are those for for which we can't set up
@ -403,11 +404,8 @@ integerPID_ideal::integerPID_ideal(long* Input, uint16_t* Output, uint16_t* Setp
mySetpoint = Setpoint;
mySensitivity = Sensitivity;
mySampleTime = SampleTime;
inAuto = false;
integerPID_ideal::SetOutputLimits(0, 255); //default output limit corresponds to
//the arduino pwm limits
integerPID_ideal::SetOutputLimits(20, 80); //default output limits
integerPID_ideal::SetControllerDirection(ControllerDirection);
integerPID_ideal::SetTunings(Kp, Ki, Kd);
@ -424,7 +422,6 @@ integerPID_ideal::integerPID_ideal(long* Input, uint16_t* Output, uint16_t* Setp
**********************************************************************************/
bool integerPID_ideal::Compute()
{
if(!inAuto) return false;
unsigned long now = millis();
//SampleTime = (now - lastTime);
unsigned long timeChange = (now - lastTime);
@ -432,14 +429,13 @@ bool integerPID_ideal::Compute()
{
/*Compute all the working error variables*/
uint16_t sensitivity = 5001 - *mySensitivity;
long limitMultiplier = 100; //How much outMin and OutMax must be multiplied by to get them in the same scale as the output
long unitless_setpoint = (((long)*mySetpoint - 0) * 10000L) / (sensitivity - 0);
long unitless_input = (((long)*myInput - 0) * 10000L) / (sensitivity - 0);
long error = unitless_setpoint - unitless_input;
ITerm += error;
uint16_t bias = 20; //Base target DC%
uint16_t bias = 50; //Base target DC%
long output = 0;
if(ki != 0)
@ -459,7 +455,7 @@ bool integerPID_ideal::Compute()
/*Compute PID Output*/
output = (kp * error) + (ki * ITerm) + (kd * (error - lastError));
output = (bias * 100) + (output / 10);
output = (bias * limitMultiplier) + (output / 10); //output is % multipled by 1000. To get % with 2 decimal places, divide it by 10. Likewise, bias is % in whole numbers. Multiply it by 100 to get it with 2 places.
if(output > (outMax * limitMultiplier)) { output = (outMax * limitMultiplier); }
if(output < (outMin * limitMultiplier)) { output = (outMin * limitMultiplier); }
@ -509,33 +505,21 @@ void integerPID_ideal::SetTunings(byte Kp, byte Ki, byte Kd)
**************************************************************************/
void integerPID_ideal::SetOutputLimits(long Min, long Max)
{
if(Min >= Max) return;
outMin = Min;
outMax = Max;
if(inAuto)
if(Min < Max)
{
if(*myOutput > outMax) *myOutput = outMax;
else if(*myOutput < outMin) *myOutput = outMin;
if(ITerm > outMax) ITerm= outMax;
else if(ITerm < outMin) ITerm= outMin;
outMin = Min;
outMax = Max;
}
}
/*
long outMax_resized = outMax * limitMultiplier;
long outMin_resized = outMin * limitMultiplier;
/* SetMode(...)****************************************************************
* Allows the controller Mode to be set to manual (0) or Automatic (non-zero)
* when the transition from manual to auto occurs, the controller is
* automatically initialized
******************************************************************************/
void integerPID_ideal::SetMode(int Mode)
{
bool newAuto = (Mode == AUTOMATIC);
if(newAuto == !inAuto)
{ /*we just went from manual to auto*/
integerPID_ideal::Initialize();
}
inAuto = newAuto;
if(*myOutput > outMax_resized) { *myOutput = outMax_resized; }
else if(*myOutput < outMin_resized) { *myOutput = outMin_resized; }
if(ITerm > outMax_resized) ITerm = outMax_resized;
else if(ITerm < outMin_resized) ITerm = outMin_resized;
*/
}
/* Initialize()****************************************************************
@ -556,7 +540,7 @@ void integerPID_ideal::Initialize()
******************************************************************************/
void integerPID_ideal::SetControllerDirection(byte Direction)
{
if(inAuto && Direction !=controllerDirection)
if(Direction != controllerDirection)
{
kp = (0 - kp);
ki = (0 - ki);
@ -573,5 +557,4 @@ void integerPID_ideal::SetControllerDirection(byte Direction)
byte integerPID_ideal::GetKp(){ return dispKp; }
byte integerPID_ideal::GetKi(){ return dispKi;}
byte integerPID_ideal::GetKd(){ return dispKd;}
int integerPID_ideal::GetMode(){ return inAuto ? AUTOMATIC : MANUAL;}
int integerPID_ideal::GetDirection(){ return controllerDirection;}

View File

@ -168,8 +168,6 @@ class integerPID_ideal
integerPID_ideal(long*, uint16_t*, uint16_t*, uint16_t*, byte*, // * constructor. links the PID to the Input, Output, and
byte, byte, byte, byte); // Setpoint. Initial tuning parameters are also set here
void SetMode(int Mode); // * sets PID to either Manual (0) or Auto (non-0)
bool Compute(); // * performs the PID calculation. it should be
// called every time loop() cycles. ON/OFF and
// calculation frequency can be set using SetMode
@ -198,9 +196,10 @@ class integerPID_ideal
byte GetKd(); // where it's important to know what is actually
int GetMode(); // inside the PID.
int GetDirection(); //
void Initialize();
private:
void Initialize();
byte dispKp; // * we'll hold on to the tuning parameters in user-entered
byte dispKi; // format for display purposes
@ -224,6 +223,5 @@ class integerPID_ideal
long ITerm, lastInput;
long outMin, outMax;
bool inAuto;
};
#endif