Faster responding boost PID

This commit is contained in:
Josh Stewart 2017-02-15 16:51:01 +11:00
parent a7d0a95611
commit f6818adecc
3 changed files with 80 additions and 65 deletions

View File

@ -17,10 +17,15 @@ volatile unsigned int boost_pwm_cur_value;
long boost_pwm_target_value; long boost_pwm_target_value;
long boost_cl_target_boost; long boost_cl_target_boost;
byte boostCounter; byte boostCounter;
//Boost control uses a scaling factor of 100 on the MAP reading and MAP target in order to have a reasonable response time
//These are the values that are passed to the PID controller
long MAPx100;
long boostTargetx100;
volatile bool vvt_pwm_state; volatile bool vvt_pwm_state;
unsigned int vvt_pwm_max_count; //Used for variable PWM frequency unsigned int vvt_pwm_max_count; //Used for variable PWM frequency
volatile unsigned int vvt_pwm_cur_value; volatile unsigned int vvt_pwm_cur_value;
long vvt_pwm_target_value; long vvt_pwm_target_value;
#endif #endif

View File

@ -3,7 +3,8 @@ Speeduino - Simple engine management for the Arduino Mega 2560 platform
Copyright (C) Josh Stewart Copyright (C) Josh Stewart
A full copy of the license may be found in the projects root directory A full copy of the license may be found in the projects root directory
*/ */
integerPID boostPID(&currentStatus.MAP, &boost_pwm_target_value, &boost_cl_target_boost, configPage3.boostKP, configPage3.boostKI, configPage3.boostKD, DIRECT); //This is the PID object if that algorithm is used. Needs to be global as it maintains state outside of each function call //integerPID boostPID(&currentStatus.MAP, &boost_pwm_target_value, &boost_cl_target_boost, configPage3.boostKP, configPage3.boostKI, configPage3.boostKD, DIRECT); //This is the PID object if that algorithm is used. Needs to be global as it maintains state outside of each function call
integerPID boostPID(&MAPx100, &boost_pwm_target_value, &boostTargetx100, configPage3.boostKP, configPage3.boostKI, configPage3.boostKD, DIRECT); //This is the PID object if that algorithm is used. Needs to be global as it maintains state outside of each function call
/* /*
Fan control Fan control
@ -48,6 +49,7 @@ void initialiseAuxPWM()
TIMSK1 |= (1 << OCIE1B); //Turn on the B compare unit (ie turn on the interrupt) TIMSK1 |= (1 << OCIE1B); //Turn on the B compare unit (ie turn on the interrupt)
boostPID.SetOutputLimits(0, boost_pwm_max_count); boostPID.SetOutputLimits(0, boost_pwm_max_count);
boostPID.SetTunings(configPage3.boostKP, configPage3.boostKI, configPage3.boostKD);
boostPID.SetMode(AUTOMATIC); //Turn PID on boostPID.SetMode(AUTOMATIC); //Turn PID on
boostCounter = 0; boostCounter = 0;
@ -58,10 +60,17 @@ void boostControl()
if(configPage3.boostEnabled) if(configPage3.boostEnabled)
{ {
if(currentStatus.MAP < 100) { TIMSK1 &= ~(1 << OCIE1A); digitalWrite(pinBoost, LOW); return; } //Set duty to 0 and turn off timer compare if(currentStatus.MAP < 100) { TIMSK1 &= ~(1 << OCIE1A); digitalWrite(pinBoost, LOW); return; } //Set duty to 0 and turn off timer compare
MAPx100 = currentStatus.MAP * 100;
boost_cl_target_boost = get3DTableValue(&boostTable, currentStatus.TPS, currentStatus.RPM) * 2; //Boost target table is in kpa and divided by 2 boost_cl_target_boost = get3DTableValue(&boostTable, currentStatus.TPS, currentStatus.RPM) * 2; //Boost target table is in kpa and divided by 2
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 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) { TIMSK1 &= ~(1 << OCIE1A); digitalWrite(pinBoost, LOW); return; } //Set duty to 0 and turn off timer compare if the target is 0
if( (boostCounter & 31) == 1) { boostPID.SetTunings(configPage3.boostKP, configPage3.boostKI, configPage3.boostKD); } //This only needs to be run very infrequently, once every 32 calls to boostControl(). This is approx. once per second if( (boostCounter & 31) == 1) { boostPID.SetTunings(configPage3.boostKP, configPage3.boostKI, configPage3.boostKD); } //This only needs to be run very infrequently, once every 32 calls to boostControl(). This is approx. once per second
boostPID.Compute(); boostPID.Compute();
TIMSK1 |= (1 << OCIE1A); //Turn on the compare unit (ie turn on the interrupt) TIMSK1 |= (1 << OCIE1A); //Turn on the compare unit (ie turn on the interrupt)
} }
else { TIMSK1 &= ~(1 << OCIE1A); } // Disable timer channel else { TIMSK1 &= ~(1 << OCIE1A); } // Disable timer channel

View File

@ -236,27 +236,28 @@ bool integerPID::Compute()
unsigned long now = millis(); unsigned long now = millis();
//SampleTime = (now - lastTime); //SampleTime = (now - lastTime);
unsigned long timeChange = (now - lastTime); unsigned long timeChange = (now - lastTime);
if(timeChange>=SampleTime) if(timeChange >= SampleTime)
{ {
/*Compute all the working error variables*/ /*Compute all the working error variables*/
long input = *myInput; long input = *myInput;
long error = *mySetpoint - input; long error = *mySetpoint - input;
ITerm+= (ki * error)/1000; //Note that ki is multiplied by 1000 rather than 100, so it must be divided by 1000 here ITerm += (ki * error)/1000; //Note that ki is multiplied by 1000 rather than 100, so it must be divided by 1000 here
if(ITerm > outMax) ITerm= outMax; if(ITerm > outMax) { ITerm = outMax; }
else if(ITerm < outMin) ITerm= outMin; else if(ITerm < outMin) { ITerm = outMin; }
long dInput = (input - lastInput); long dInput = (input - lastInput);
/*Compute PID Output*/ /*Compute PID Output*/
long output = (kp * error)/100 + ITerm - (kd * dInput)/100; long output = (kp * error)/100 + ITerm - (kd * dInput)/100;
if(output > outMax) output = outMax; if(output > outMax) output = outMax;
else if(output < outMin) output = outMin; else if(output < outMin) output = outMin;
*myOutput = output; *myOutput = output;
/*Remember some variables for next time*/ /*Remember some variables for next time*/
lastInput = input; lastInput = input;
lastTime = now; lastTime = now;
return true;
return true;
} }
else return false; else return false;
} }