From 3c308aebbf179b155b854596f92fcdf2b269823b Mon Sep 17 00:00:00 2001 From: Michael Moon Date: Sun, 30 Dec 2012 23:49:17 +1100 Subject: [PATCH] PID Autotuner initial commit - results are poor, needs fine tuning --- .../temperaturecontrol/PID_Autotuner.cpp | 115 ++++++++++++++++++ .../tools/temperaturecontrol/PID_Autotuner.h | 34 ++++++ .../temperaturecontrol/TemperatureControl.cpp | 12 ++ .../temperaturecontrol/TemperatureControl.h | 6 +- .../TemperatureControlPool.cpp | 3 + .../TemperatureControlPool.h | 2 + 6 files changed, 171 insertions(+), 1 deletion(-) create mode 100644 src/modules/tools/temperaturecontrol/PID_Autotuner.cpp create mode 100644 src/modules/tools/temperaturecontrol/PID_Autotuner.h diff --git a/src/modules/tools/temperaturecontrol/PID_Autotuner.cpp b/src/modules/tools/temperaturecontrol/PID_Autotuner.cpp new file mode 100644 index 00000000..020b96e6 --- /dev/null +++ b/src/modules/tools/temperaturecontrol/PID_Autotuner.cpp @@ -0,0 +1,115 @@ +#include "PID_Autotuner.h" + +#include "Kernel.h" + +PID_Autotuner::PID_Autotuner() +{ + t = NULL; + s = NULL; +} + +void PID_Autotuner::on_module_loaded() +{ + this->kernel->slow_ticker->attach(20, this, &PID_Autotuner::on_tick ); +} + +void PID_Autotuner::begin(TemperatureControl *temp, double target, StreamOutput *stream) +{ + if (t) + { + t->target_temperature = 0.0; + } + + t = temp; + + t->p_factor = 1000000000.0; + t->i_factor = 0.0; + t->d_factor = 0.0; + t->i_max = 0.0; + + t->target_temperature = target; + + for (cycle = 0; cycle < 8; cycle++) + { + cycles[cycle].ticks = 0; + cycles[cycle].t_max = 0.0; + cycles[cycle].t_min = 1000.0; + } + cycle = 0; + + s = stream; + + s->printf("%s: Starting PID Autotune\n", t->designator.c_str()); + + last_output = true; +} + +uint32_t PID_Autotuner::on_tick(uint32_t dummy) +{ + if (cycle >= PID_AUTOTUNER_CYCLES) + return 0; + if (t == NULL) + return 0; + + if (last_output == false && (t->o > 128)) + { + s->printf("Cycle %d:\n\tMax: %5.1f Min: %5.1f time: %3.1fs\n", cycle, cycles[cycle].t_max, cycles[cycle].t_min, cycles[cycle].ticks / 20.0); + cycle++; + if (cycle == PID_AUTOTUNER_CYCLES) + { + t->set_desired_temperature(0.0); + // TODO: finish + double tmax_avg = 0.0, + tmin_avg = 0.0, + tcycle_avg = 0.0; + for (cycle = 1; cycle < PID_AUTOTUNER_CYCLES; cycle++) + { + tmax_avg += cycles[cycle].t_max; + tmin_avg += cycles[cycle].t_min; + tcycle_avg += cycles[cycle].ticks; + } + tmax_avg /= 7.0; + tmin_avg /= 7.0; + tcycle_avg /= 7.0; + s->printf("Averages over last %d cycles: Max: %5.1fc Min: %5.1fc samples: %3.0f\n", PID_AUTOTUNER_CYCLES - 2, tmax_avg, tmin_avg, tcycle_avg); + + // from http://brettbeauregard.com/blog/2012/01/arduino-pid-autotune-library/ + // TODO: work out why the results of this algorithm are dreadfully poor + double ku = 4 * 128 / ((tmax_avg - tmin_avg) * 3.141592653589); + double pu = tcycle_avg; + + double kp = 0.6 * ku; + double ki = 1.2 * ku / pu; + double kd = 0.075 * ku * pu; + + s->printf("PID Autotune complete. Try M301 S%d P%4g I%4g D%4g\n", t->pool_index, kp, ki, kd); + + t->p_factor = kp; + t->i_factor = ki; + t->d_factor = kd; + t->i_max = 128; + + t = NULL; + s = NULL; + + return 0; + } + } + + last_output = (t->o > 128); + + cycles[cycle].ticks++; + + if ((cycles[cycle].ticks % 16) == 0) + { + s->printf("%s: %5.1f/%5.1f @%d %d %d/8\n", t->designator.c_str(), t->last_reading, t->target_temperature, t->o, (last_output?1:0), cycle); + } + + if (t->last_reading > cycles[cycle].t_max) + cycles[cycle].t_max = t->last_reading; + + if (t->last_reading < cycles[cycle].t_min) + cycles[cycle].t_min = t->last_reading; + + return 0; +} diff --git a/src/modules/tools/temperaturecontrol/PID_Autotuner.h b/src/modules/tools/temperaturecontrol/PID_Autotuner.h new file mode 100644 index 00000000..48e82bb1 --- /dev/null +++ b/src/modules/tools/temperaturecontrol/PID_Autotuner.h @@ -0,0 +1,34 @@ +#ifndef _PID_AUTOTUNE_H +#define _PID_AUTOTUNE_H + +#include + +#include "Module.h" +#include "TemperatureControl.h" +#include "StreamOutput.h" + +#define PID_AUTOTUNER_CYCLES 8 + +class PID_Autotuner : public Module +{ +public: + PID_Autotuner(); + void begin(TemperatureControl*, double, StreamOutput*); + + void on_module_loaded(void); + uint32_t on_tick(uint32_t); + + TemperatureControl *t; + + int cycle; + bool last_output; + StreamOutput *s; + + struct { + double t_max; + double t_min; + int ticks; + } cycles[PID_AUTOTUNER_CYCLES]; +}; + +#endif /* _PID_AUTOTUNE_H */ diff --git a/src/modules/tools/temperaturecontrol/TemperatureControl.cpp b/src/modules/tools/temperaturecontrol/TemperatureControl.cpp index 11e40a2b..a04efd4b 100644 --- a/src/modules/tools/temperaturecontrol/TemperatureControl.cpp +++ b/src/modules/tools/temperaturecontrol/TemperatureControl.cpp @@ -11,6 +11,7 @@ #include "libs/Kernel.h" #include #include "TemperatureControl.h" +#include "TemperatureControlPool.h" #include "libs/Pin.h" TemperatureControl::TemperatureControl(){} @@ -83,6 +84,7 @@ void TemperatureControl::on_config_reload(void* argument){ // ADC smoothing running_total = 0; + // sigma-delta output modulation o = 0; @@ -170,6 +172,16 @@ void TemperatureControl::on_gcode_execute(void* argument){ } gcode->stream->printf("%s(S%d): Pf:%g If:%g Df:%g X(I_max):%g Pv:%g Iv:%g Dv:%g O:%d\n", this->designator.c_str(), this->pool_index, this->p_factor, this->i_factor, this->d_factor, this->i_max, this->p, this->i, this->d, o); } + if (gcode->m == 303) + { + if (gcode->has_letter('S') && (gcode->get_value('S') == this->pool_index)) + { + double target = 150.0; + if (gcode->has_letter('T')) + target = gcode->get_value('T'); + this->pool->PIDtuner->begin(this, target, gcode->stream); + } + } } } diff --git a/src/modules/tools/temperaturecontrol/TemperatureControl.h b/src/modules/tools/temperaturecontrol/TemperatureControl.h index 6f4185c8..76ff7bf9 100644 --- a/src/modules/tools/temperaturecontrol/TemperatureControl.h +++ b/src/modules/tools/temperaturecontrol/TemperatureControl.h @@ -11,6 +11,8 @@ #include "libs/Pin.h" #include +#include "RingBuffer.h" + #define UNDEFINED -1 #define thermistor_checksum 41045 @@ -38,6 +40,7 @@ #define i_max_checksum 4112 +class TemperatureControlPool; class TemperatureControl : public Module { public: @@ -75,7 +78,6 @@ class TemperatureControl : public Module { // PID runtime double i_max; - double i_accumulator; double p, i, d; int o; @@ -100,6 +102,8 @@ class TemperatureControl : public Module { uint16_t get_m_code; string designator; + + TemperatureControlPool *pool; int pool_index; }; diff --git a/src/modules/tools/temperaturecontrol/TemperatureControlPool.cpp b/src/modules/tools/temperaturecontrol/TemperatureControlPool.cpp index 301fa904..5a31a207 100644 --- a/src/modules/tools/temperaturecontrol/TemperatureControlPool.cpp +++ b/src/modules/tools/temperaturecontrol/TemperatureControlPool.cpp @@ -12,6 +12,7 @@ using namespace std; #include #include "TemperatureControlPool.h" #include "TemperatureControl.h" +#include "PID_Autotuner.h" TemperatureControlPool::TemperatureControlPool(){} @@ -24,12 +25,14 @@ void TemperatureControlPool::on_module_loaded(){ // If module is enabled if( this->kernel->config->value(temperature_control_checksum, modules[i], enable_checksum )->as_bool() == true ){ TemperatureControl* controller = new TemperatureControl(modules[i]); + controller->pool = this; controller->pool_index = i; this->kernel->add_module(controller); this->controllers.push_back( controller ); } } + this->kernel->add_module( this->PIDtuner = new PID_Autotuner() ); } diff --git a/src/modules/tools/temperaturecontrol/TemperatureControlPool.h b/src/modules/tools/temperaturecontrol/TemperatureControlPool.h index 28d663ce..80a59c4b 100644 --- a/src/modules/tools/temperaturecontrol/TemperatureControlPool.h +++ b/src/modules/tools/temperaturecontrol/TemperatureControlPool.h @@ -9,6 +9,7 @@ #define TEMPERATURECONTROLPOOL_H #include "TemperatureControl.h" +#include "PID_Autotuner.h" #include using namespace std; #include @@ -23,6 +24,7 @@ class TemperatureControlPool : public Module { void on_module_loaded(); vector controllers; + PID_Autotuner* PIDtuner; }; -- 2.20.1