Completed new PID mode for boost control
This commit is contained in:
parent
3b33094230
commit
4e858f1ca8
|
@ -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}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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;}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue