Skip to content
Snippets Groups Projects
Commit fc5d1e4f authored by Myres's avatar Myres
Browse files

Improve TemperatureController for short duty cycles.

parent 016cdc0a
No related branches found
No related tags found
No related merge requests found
# CHANGELOG # CHANGELOG
## 2.0.0
_PID calculation changed to fraction, for upgrade reduce PID factors (Kp, Ki) by factor 1000._
### Changed
* Duty cycle is fraction of period instead per mille.
* Cycle period unit is ms instead of second, allowing 1 ms duty cycle.
* Duty cycle time resolution is µs instead of ms.
## 1.4.0 ## 1.4.0
### Added ### Added
......
...@@ -12,9 +12,9 @@ ...@@ -12,9 +12,9 @@
*/ */
//** CONSTANTS PARAMETERS change for your application **// //** CONSTANTS PARAMETERS change for your application **//
const String version = "1.4.0"; // Version of this script. Filename is added before, date of compilation afterwards. const String version = "2.0.0"; // Version of this script. Filename is added before, date of compilation afterwards.
const int cyclePeriod = 30; //program cycle period in s const unsigned long cyclePeriod = 1000; //program cycle period in ms
const int controlPin = 11; //Pin by which the control unit is controlled (11 or 12) const int controlPin = 11; //Pin by which the control unit is controlled (11 or 12)
const int secondaryControlPin = -1; // Secondary Pin to control output (or -1) const int secondaryControlPin = -1; // Secondary Pin to control output (or -1)
...@@ -40,13 +40,15 @@ const int redLedPin = 4; //Pin for a red LED ...@@ -40,13 +40,15 @@ const int redLedPin = 4; //Pin for a red LED
const int errorPin = 7; //Pin for a bright red warning LED const int errorPin = 7; //Pin for a bright red warning LED
// ERROR indicator // ERROR indicator
const int errorCyclePeriod = 2000; // Interval between two error indicators const int errorCyclePeriod = 2000; // Interval between two error indicators in ms
const int errorOnTime = 100; // How long the output is on (in ms) for a single blink const int errorOnTime = 100; // How long the output is on (in ms) for a single blink
const int errorInterval = 200; // Interval for the error blinks const int errorInterval = 200; // Interval for the error blinks
// MISC // MISC
const long rolloverThreshold = 4294965000; //After how many milliseconds should we suspend normal operation to await millis()-rollover? const unsigned long cycle_period_us = cyclePeriod * 1000; // for the µs counter
// (Should be at least cyclePeriod+digitalPinSetDelay below the maximum value of an unsigned long of 4.294.967.295) const unsigned long max_ulong = -1; // maximum value of unsigned long needed for rollover detection
const float duty_cycle_upper_limit = 1.05; // what the duty cycle should be at most. Should be more than 1 for continuous control
const unsigned long rolloverThreshold = max_ulong - cycle_period_us * duty_cycle_upper_limit * 1.5; // when the rollover protection should kick in.
// ******************************************************************************** // ********************************************************************************
...@@ -88,7 +90,7 @@ float setpoint; // setpoint for the temperature = 36°C ...@@ -88,7 +90,7 @@ float setpoint; // setpoint for the temperature = 36°C
float PIDKp; //Wert für die PID Regelung (Proportional-Teil) float PIDKp; //Wert für die PID Regelung (Proportional-Teil)
float PIDKi; //Wert für die PID Regelung (Integral-Teil) float PIDKi; //Wert für die PID Regelung (Integral-Teil)
float integral; //Wert für die PID Integralteil float integral; //Wert für die PID Integralteil
float duty_cycle; //Current duty cycle in per mille float duty_cycle; //Current duty cycle as fraction of cycle period
int controller = 1; // controller mode: 0 = off, 1 = on int controller = 1; // controller mode: 0 = off, 1 = on
int error = 0; // current error code int error = 0; // current error code
...@@ -118,15 +120,15 @@ void setup() { ...@@ -118,15 +120,15 @@ void setup() {
} }
EEPROM.get(1 * floatsize, PIDKp); EEPROM.get(1 * floatsize, PIDKp);
if ( isnan(PIDKp)){ if ( isnan(PIDKp)){
PIDKp = 1000; PIDKp = 1;
} }
EEPROM.get(2 * floatsize, PIDKi); EEPROM.get(2 * floatsize, PIDKi);
if ( isnan(PIDKi)){ if ( isnan(PIDKi)){
PIDKi = 1; PIDKi = 0.001;
} }
EEPROM.get(3 * floatsize, integral); EEPROM.get(3 * floatsize, integral);
if ( isnan(integral) || integral < 0 || integral > 1000 ){ if ( isnan(integral) || integral < 0 || integral > 1 ){
integral = 100; integral = 0.1;
} }
} }
...@@ -253,7 +255,7 @@ void loop(){ ...@@ -253,7 +255,7 @@ void loop(){
case 'x': // Parameters, name TBD case 'x': // Parameters, name TBD
Serial.print("cyclePeriod: "); Serial.print("cyclePeriod: ");
Serial.print(cyclePeriod); Serial.print(cyclePeriod);
Serial.print("s, "); Serial.print("ms, ");
Serial.print("controlPin: "); Serial.print("controlPin: ");
Serial.print(controlPin); Serial.print(controlPin);
Serial.print(", "); Serial.print(", ");
...@@ -280,15 +282,15 @@ void loop(){ ...@@ -280,15 +282,15 @@ void loop(){
} }
// Start new pulse, calculating the duty cycle and pulse length // Start new pulse, calculating the duty cycle and pulse length
if ( millis() >= nextCycle ){ if ( micros() >= nextCycle ){
if (controller > 0){ if (controller > 0){
calculatePID(); calculatePID();
} }
nextCycle += cyclePeriod * 1000; nextCycle += cycle_period_us;
} }
// stop the pulse, if pulse length elapsed // stop the pulse, if pulse length elapsed
if ( millis() >= nextOff && nextOff > 0){ if ( micros() >= nextOff && nextOff > 0){
enable_control(false); enable_control(false);
} }
...@@ -298,10 +300,10 @@ void loop(){ ...@@ -298,10 +300,10 @@ void loop(){
nextError = millis() + errorCyclePeriod; nextError = millis() + errorCyclePeriod;
} }
//if we are within 2300ms of rollover of millis counter suspend normal operation //if we are within cycle_period of rollover of counter suspend normal operation
if (millis() > rolloverThreshold){ if (micros() > rolloverThreshold){
nextCycle = cyclePeriod * 1000; //set everything for continuing normal operation after rollover while (micros() > rolloverThreshold){}; //wait for rollover to happen
while (millis() > rolloverThreshold){}; //wait for rollover to happen nextCycle = 0; // continue normally after rollover
}; };
} }
...@@ -346,17 +348,21 @@ void calculatePID(){ ...@@ -346,17 +348,21 @@ void calculatePID(){
// Calculate the PID signal and duty cycle, and start a new pulse // Calculate the PID signal and duty cycle, and start a new pulse
float error = setpoint - average0.getAverage(); float error = setpoint - average0.getAverage();
// calculate integral part, clamp it between 0 and 1000 // calculate integral part, clamp it between 0 and 1
integral += PIDKi * error; integral += PIDKi * error;
if (integral > 1000){ if (integral > 1){
integral = 1000; integral = 1;
} }
else if (integral < 0){ else if (integral < 0){
integral = 0; integral = 0;
} }
// caclulate the duty cycle, clamp it between 0 and 1000 // calculate the duty cycle, clamp it between 0 and 1
duty_cycle = PIDKp * error + integral; duty_cycle = PIDKp * error + integral;
// limit duty cycle against overflow
if (duty_cycle > duty_cycle_upper_limit){
duty_cycle = duty_cycle_upper_limit;
}
if (duty_cycle < 0){ if (duty_cycle < 0){
nextOff = 0; nextOff = 0;
duty_cycle = 0; duty_cycle = 0;
...@@ -364,12 +370,9 @@ void calculatePID(){ ...@@ -364,12 +370,9 @@ void calculatePID(){
} }
else { else {
// start a new pulse and set the pulse length // start a new pulse and set the pulse length
nextOff = millis() + cyclePeriod * duty_cycle; nextOff = micros() + cycle_period_us * duty_cycle;
enable_control( true ); enable_control( true );
} }
if (duty_cycle > 1000){
duty_cycle = 1000;
}
} }
void enable_control(const boolean enabled){ void enable_control(const boolean enabled){
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment