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
## 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
### Added
......
......@@ -12,9 +12,9 @@
*/
//** 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 secondaryControlPin = -1; // Secondary Pin to control output (or -1)
......@@ -40,13 +40,15 @@ const int redLedPin = 4; //Pin for a red LED
const int errorPin = 7; //Pin for a bright red warning LED
// 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 errorInterval = 200; // Interval for the error blinks
// MISC
const long rolloverThreshold = 4294965000; //After how many milliseconds should we suspend normal operation to await millis()-rollover?
// (Should be at least cyclePeriod+digitalPinSetDelay below the maximum value of an unsigned long of 4.294.967.295)
const unsigned long cycle_period_us = cyclePeriod * 1000; // for the µs counter
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
float PIDKp; //Wert für die PID Regelung (Proportional-Teil)
float PIDKi; //Wert für die PID Regelung (Integral-Teil)
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 error = 0; // current error code
......@@ -118,15 +120,15 @@ void setup() {
}
EEPROM.get(1 * floatsize, PIDKp);
if ( isnan(PIDKp)){
PIDKp = 1000;
PIDKp = 1;
}
EEPROM.get(2 * floatsize, PIDKi);
if ( isnan(PIDKi)){
PIDKi = 1;
PIDKi = 0.001;
}
EEPROM.get(3 * floatsize, integral);
if ( isnan(integral) || integral < 0 || integral > 1000 ){
integral = 100;
if ( isnan(integral) || integral < 0 || integral > 1 ){
integral = 0.1;
}
}
......@@ -253,7 +255,7 @@ void loop(){
case 'x': // Parameters, name TBD
Serial.print("cyclePeriod: ");
Serial.print(cyclePeriod);
Serial.print("s, ");
Serial.print("ms, ");
Serial.print("controlPin: ");
Serial.print(controlPin);
Serial.print(", ");
......@@ -280,15 +282,15 @@ void loop(){
}
// Start new pulse, calculating the duty cycle and pulse length
if ( millis() >= nextCycle ){
if ( micros() >= nextCycle ){
if (controller > 0){
calculatePID();
}
nextCycle += cyclePeriod * 1000;
nextCycle += cycle_period_us;
}
// stop the pulse, if pulse length elapsed
if ( millis() >= nextOff && nextOff > 0){
if ( micros() >= nextOff && nextOff > 0){
enable_control(false);
}
......@@ -298,10 +300,10 @@ void loop(){
nextError = millis() + errorCyclePeriod;
}
//if we are within 2300ms of rollover of millis counter suspend normal operation
if (millis() > rolloverThreshold){
nextCycle = cyclePeriod * 1000; //set everything for continuing normal operation after rollover
while (millis() > rolloverThreshold){}; //wait for rollover to happen
//if we are within cycle_period of rollover of counter suspend normal operation
if (micros() > rolloverThreshold){
while (micros() > rolloverThreshold){}; //wait for rollover to happen
nextCycle = 0; // continue normally after rollover
};
}
......@@ -346,17 +348,21 @@ void calculatePID(){
// Calculate the PID signal and duty cycle, and start a new pulse
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;
if (integral > 1000){
integral = 1000;
if (integral > 1){
integral = 1;
}
else if (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;
// limit duty cycle against overflow
if (duty_cycle > duty_cycle_upper_limit){
duty_cycle = duty_cycle_upper_limit;
}
if (duty_cycle < 0){
nextOff = 0;
duty_cycle = 0;
......@@ -364,12 +370,9 @@ void calculatePID(){
}
else {
// start a new pulse and set the pulse length
nextOff = millis() + cyclePeriod * duty_cycle;
nextOff = micros() + cycle_period_us * duty_cycle;
enable_control( true );
}
if (duty_cycle > 1000){
duty_cycle = 1000;
}
}
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