From b94bff107cbed88f503fa79ec9a5ecafeeeb9276 Mon Sep 17 00:00:00 2001 From: Adrian Bowyer Date: Thu, 11 Jul 2013 20:22:21 +0100 Subject: [PATCH] Temperature code now working. PID may need a little tweaking. --- GCodes.h | 9 ++++++ GCodes.ino | 25 +++++++++++------ Heat.h | 55 +++++++++++++++++++++++++++++++----- Heat.ino | 63 ++++++++++++++++++++++++++++++++++-------- Move.ino | 41 +++++++++++++++++++++++++-- Platform.h | 78 ++++++++++++++++++++++++++++++++++------------------ Platform.ino | 33 +++++++++++++++++----- 7 files changed, 242 insertions(+), 62 deletions(-) diff --git a/GCodes.h b/GCodes.h index 73ba065..795ebd8 100644 --- a/GCodes.h +++ b/GCodes.h @@ -76,6 +76,7 @@ class GCodes boolean NoHome(); boolean Push(); boolean Pop(); + int8_t Heater(int8_t head); Platform* platform; boolean active; Webserver* webserver; @@ -133,4 +134,12 @@ inline boolean GCodes::NoHome() return !(homeX || homeY || homeZ); } +// This function takes care of the fact that the heater and head indices +// don't match because the bed is heater 0. + +inline int8_t GCodes::Heater(int8_t head) +{ + return head+1; +} + #endif diff --git a/GCodes.ino b/GCodes.ino index 9bac1ee..6fcef7b 100644 --- a/GCodes.ino +++ b/GCodes.ino @@ -381,11 +381,13 @@ boolean GCodes::SetOffsets(GCodeBuffer *gb) int8_t head; if(gb->Seen('P')) { - head = gb->GetIValue(); + head = gb->GetIValue() + 1; // 0 is the Bed if(gb->Seen('R')) - platform->SetStandbyTemperature(head+1, gb->GetFValue()); + reprap.GetHeat()->SetStandbyTemperature(head, gb->GetFValue()); + if(gb->Seen('S')) - platform->SetActiveTemperature(head+1, gb->GetFValue()); + reprap.GetHeat()->SetActiveTemperature(head, gb->GetFValue()); + // FIXME - do X, Y and Z } return true; } @@ -535,7 +537,10 @@ boolean GCodes::ActOnGcode(GCodeBuffer *gb) case 140: // Set bed temperature if(gb->Seen('S')) - reprap.GetHeat()->SetTemperature(0, gb->GetFValue()); + { + reprap.GetHeat()->SetActiveTemperature(0, gb->GetFValue()); + reprap.GetHeat()->Activate(0); + } break; case 141: // Chamber temperature @@ -553,17 +558,21 @@ boolean GCodes::ActOnGcode(GCodeBuffer *gb) if(gb->Seen('T')) { code = gb->GetIValue(); + if(code == selectedHead) + return result; + boolean ok = false; for(int8_t i = AXES; i < DRIVES; i++) { if(selectedHead == i - AXES) - { - reprap.GetHeat()->SetTemperature(selectedHead+1, platform->StandbyTemperature(selectedHead+1)); - } + reprap.GetHeat()->Standby(selectedHead + 1); // 0 is the Bed + } + for(int8_t i = AXES; i < DRIVES; i++) + { if(code == i - AXES) { - reprap.GetHeat()->SetTemperature(code+1, platform->ActiveTemperature(code+1)); selectedHead = code; + reprap.GetHeat()->Activate(selectedHead + 1); // 0 is the Bed ok = true; } } diff --git a/Heat.h b/Heat.h index 956dafe..974e862 100644 --- a/Heat.h +++ b/Heat.h @@ -28,14 +28,22 @@ class PID PID(Platform* p, int8_t h); void Init(); void Spin(); - void SetTemperature(const float& t); + void SetActiveTemperature(const float& t); + void SetStandbyTemperature(const float& t); + void Activate(); + void Standby(); float GetTemperature(); private: Platform* platform; - float setTemperature; + float activeTemperature; + float standbyTemperature; float temperature; + float lastTemperature; + float temp_iState; + float temp_dState; + boolean active; int8_t heater; }; @@ -48,7 +56,10 @@ class Heat void Spin(); void Init(); void Exit(); - void SetTemperature(int8_t heater, const float& t); + void SetActiveTemperature(int8_t heater, const float& t); + void SetStandbyTemperature(int8_t heater, const float& t); + void Activate(int8_t heater); + void Standby(int8_t heater); float GetTemperature(int8_t heater); private: @@ -63,9 +74,14 @@ class Heat //*********************************************************************************************************** -inline void PID::SetTemperature(const float& t) +inline void PID::SetActiveTemperature(const float& t) { - setTemperature = t; + activeTemperature = t; +} + +inline void PID::SetStandbyTemperature(const float& t) +{ + standbyTemperature = t; } inline float PID::GetTemperature() @@ -73,9 +89,24 @@ inline float PID::GetTemperature() return temperature; } -inline void Heat::SetTemperature(int8_t heater, const float& t) +inline void PID::Activate() { - pids[heater]->SetTemperature(t); + active = true; +} + +inline void PID::Standby() +{ + active = false; +} + +inline void Heat::SetActiveTemperature(int8_t heater, const float& t) +{ + pids[heater]->SetActiveTemperature(t); +} + +inline void Heat::SetStandbyTemperature(int8_t heater, const float& t) +{ + pids[heater]->SetStandbyTemperature(t); } inline float Heat::GetTemperature(int8_t heater) @@ -83,4 +114,14 @@ inline float Heat::GetTemperature(int8_t heater) return pids[heater]->GetTemperature(); } +inline void Heat::Activate(int8_t heater) +{ + pids[heater]->Activate(); +} + +inline void Heat::Standby(int8_t heater) +{ + pids[heater]->Standby(); +} + #endif diff --git a/Heat.ino b/Heat.ino index 7e4e22e..974b3b9 100644 --- a/Heat.ino +++ b/Heat.ino @@ -32,10 +32,7 @@ Heat::Heat(Platform* p, GCodes* g) void Heat::Init() { for(int8_t heater=0; heater < HEATERS; heater++) - { - platform->SetHeater(heater, -1); pids[heater]->Init(); - } lastTime = platform->Time(); active = true; } @@ -50,12 +47,12 @@ void Heat::Spin() if(!active) return; - unsigned long t = platform->Time(); - if(t - lastTime < platform->HeatSampleTime()) - return; - lastTime = t; - for(int8_t heater=0; heater < HEATERS; heater++) - pids[heater]->Spin(); + unsigned long t = platform->Time(); + if(t - lastTime < platform->HeatSampleTime()) + return; + lastTime = t; + for(int8_t heater=0; heater < HEATERS; heater++) + pids[heater]->Spin(); } //****************************************************************************************************** @@ -68,20 +65,62 @@ PID::PID(Platform* p, int8_t h) void PID::Init() { + platform->SetHeater(heater, 0.0); temperature = platform->GetTemperature(heater); - setTemperature = 0.0; - platform->SetHeater(heater, -1.0); + activeTemperature = ABS_ZERO; + standbyTemperature = ABS_ZERO; + lastTemperature = temperature; + temp_iState = 0.0; + temp_dState = 0.0; + active = false; } + void PID::Spin() { temperature = platform->GetTemperature(heater); + + float error; + if(active) + error = activeTemperature - temperature; + else + error = standbyTemperature - temperature; + if(!platform->UsePID(heater)) { - if(temperature < setTemperature) + if(error > 0.0) platform->SetHeater(heater, 1.0); else platform->SetHeater(heater, 0.0); return; } + + if(error < -platform->FullPidBand(heater)) + { + temp_iState = 0.0; + platform->SetHeater(heater, 0.0); + return; + } + if(error > platform->FullPidBand(heater)) + { + temp_iState = 0.0; + platform->SetHeater(heater, 1.0); + return; + } + + temp_iState += error; + + if (temp_iState < platform->PidMin(heater)) temp_iState = platform->PidMin(heater); + if (temp_iState > platform->PidMax(heater)) temp_iState = platform->PidMax(heater); + + temp_dState = platform->PidKd(heater)*(temperature - lastTemperature)*(1.0 - platform->DMix(heater)) + platform->DMix(heater)*temp_dState; + + float result = platform->PidKp(heater)*error + platform->PidKi(heater)*temp_iState - temp_dState; + + lastTemperature = temperature; + + if (result < 0.0) result = 0.0; + if (result > 255.0) result = 255.0; + result = result/255.0; + platform->SetHeater(heater, result); } diff --git a/Move.ino b/Move.ino index 93aa0e3..5cd6c54 100644 --- a/Move.ino +++ b/Move.ino @@ -151,7 +151,12 @@ void Move::Spin() if(!active) return; + // Do some look-ahead work, if there's any to do + DoLookAhead(); + + // If there's space in the DDA ring, and there are completed + // moves in the look-ahead ring, transfer them. if(!DDARingFull()) { @@ -163,10 +168,15 @@ void Move::Spin() } } + // If we either don't want to, or can't, add to the look-ahead ring, go home. + if(addNoMoreMoves || LookAheadRingFull()) return; - boolean waitForThisToFinish; + // boolean waitForThisToFinish; + + // If there's a G Code move available, add it to the look-ahead + // ring for proicessing. if(gCodes->ReadMove(nextMove, checkEndStopsOnNextMove)) { @@ -204,6 +214,12 @@ boolean Move::GetCurrentState(float m[]) return true; } +// Classify a move between to points. +// Is it (a combination of): +// A Z movement? +// An XY movement? +// Extruder movements? + int8_t Move::GetMovementType(float p0[], float p1[]) { int8_t result = noMove; @@ -227,6 +243,8 @@ int8_t Move::GetMovementType(float p0[], float p1[]) return result; } +// Take an item from the look-ahead ring and add it to the DDA ring, if +// possible. boolean Move::DDARingAdd(LookAhead* lookAhead) { @@ -256,6 +274,7 @@ boolean Move::DDARingAdd(LookAhead* lookAhead) return false; } +// Get a movement from the DDA ring, if we can. DDA* Move::DDARingGet() { @@ -275,6 +294,7 @@ DDA* Move::DDARingGet() return NULL; } +// Do the look-ahead calculations void Move::DoLookAhead() { @@ -286,9 +306,18 @@ void Move::DoLookAhead() LookAhead* n2; float u, v; + + // If there are a reasonable number of moves in there (LOOK_AHEAD), or if we are + // doing single moves with no other move immediately following on, run up and down + // the moves using the DDA Init() function to reduce the start or the end speed + // or both to the maximum that can be achieved because of the requirements of + // the adjacent moves. if(addNoMoreMoves || !gCodes->PrintingAFile() || lookAheadRingCount > LOOK_AHEAD) - { + { + + // Run up the moves + n1 = lookAheadRingGetPointer; n0 = n1->Previous(); n2 = n1->Next(); @@ -312,6 +341,8 @@ void Move::DoLookAhead() n2 = n2->Next(); } + // Now run down + do { if(!(n1->Processed() & complete)) @@ -335,6 +366,9 @@ void Move::DoLookAhead() n0->SetProcessed(complete); } + // If there are any new unprocessed moves in there, set their end speeds + // according to the cosine of the angle between them. + if(addNoMoreMoves || !gCodes->PrintingAFile() || lookAheadRingCount > 1) { n1 = lookAheadRingGetPointer; @@ -365,6 +399,8 @@ void Move::DoLookAhead() n2 = n2->Next(); } + // If we are just doing one isolated move, set its end velocity to 0. + if(addNoMoreMoves || !gCodes->PrintingAFile()) { n1->SetV(0); @@ -373,6 +409,7 @@ void Move::DoLookAhead() } } +// This is the function that's called by the timer interrupt to step the motors. void Move::Interrupt() { diff --git a/Platform.h b/Platform.h index 8a5247b..785788e 100644 --- a/Platform.h +++ b/Platform.h @@ -79,7 +79,7 @@ Licence: GPL #define MAX_FEEDRATES {300.0, 300.0, 3.0, 45.0} // mm/sec #define ACCELERATIONS {800.0, 800.0, 30.0, 250.0} // mm/sec^2?? //#define ACCELERATIONS {80, 80, 3, 25} -#define DRIVE_STEPS_PER_UNIT {91.4286, 91.4286, 4000.0, 929.0} +#define DRIVE_STEPS_PER_UNIT {91.4286, 91.4286, 4000.0, 948.0} #define INSTANT_DVS {15.0, 15.0, 0.4, 15.0} // (mm/sec) #define GCODE_LETTERS { 'X', 'Y', 'Z', 'E', 'F' } // The drives and feedrate in a GCode @@ -103,14 +103,17 @@ Licence: GPL #define THERMISTOR_BETAS {3480.0, 3960.0} // Bed thermistor: RS 484-0149; EPCOS B57550G103J; Extruder thermistor: RS 198-961 #define THERMISTOR_SERIES_RS {4700, 4700} // Ohms in series with the thermistors #define THERMISTOR_25_RS {10000.0, 100000.0} // Thermistor ohms at 25 C = 298.15 K -#define USE_PID {false, false} // PID or bang-bang for this heater? -#define PID_KIS {-1, 100} // PID constants... -#define PID_KDS {-1, 100} -#define PID_KPS {-1, 100} -#define PID_I_LIMITS {-1, 100} // ... to here -#define TEMP_INTERVAL 0.5 // secs - check and control temperatures this often -#define STANDBY_TEMPERATURES {0.0, 0.0} // We specify one for the bed, though it's not needed -#define ACTIVE_TEMPERATURES {0.0, 0.0} +#define USE_PID {false, true} // PID or bang-bang for this heater? +#define PID_KIS {-1, 2.2} // PID constants... +#define PID_KDS {-1, 80} +#define PID_KPS {-1, 12} +#define FULL_PID_BAND {-1, 150.0} +#define PID_MIN {-1, 0.0} +#define PID_MAX {-1, 125.0} +#define D_MIX {-1, 0.95} +#define TEMP_INTERVAL 0.122 // secs - check and control temperatures this often +#define STANDBY_TEMPERATURES {ABS_ZERO, ABS_ZERO} // We specify one for the bed, though it's not needed +#define ACTIVE_TEMPERATURES {ABS_ZERO, ABS_ZERO} #define AD_RANGE 1023.0//16383 // The A->D converter that measures temperatures gives an int this big as its max value @@ -256,14 +259,17 @@ class Platform float GetTemperature(int8_t heater); // Result is in degrees celsius void SetHeater(int8_t heater, const float& power); // power is a fraction in [0,1] - void SetStandbyTemperature(int8_t heater, const float& t); - void SetActiveTemperature(int8_t heater, const float& t); - float StandbyTemperature(int8_t heater); - float ActiveTemperature(int8_t heater); - float pidKp(int8_t heater); - float pidKi(int8_t heater); - float pidKd(int8_t heater); - float pidKw(int8_t heater); + //void SetStandbyTemperature(int8_t heater, const float& t); + //void SetActiveTemperature(int8_t heater, const float& t); + //float StandbyTemperature(int8_t heater); + //float ActiveTemperature(int8_t heater); + float PidKp(int8_t heater); + float PidKi(int8_t heater); + float PidKd(int8_t heater); + float FullPidBand(int8_t heater); + float PidMin(int8_t heater); + float PidMax(int8_t heater); + float DMix(int8_t heater); boolean UsePID(int8_t heater); float HeatSampleTime(); @@ -317,7 +323,10 @@ class Platform float pidKis[HEATERS]; float pidKds[HEATERS]; float pidKps[HEATERS]; - float pidILimits[HEATERS]; + float fullPidBand[HEATERS]; + float pidMin[HEATERS]; + float pidMax[HEATERS]; + float dMix[HEATERS]; float heatSampleTime; float standbyTemperatures[HEATERS]; float activeTemperatures[HEATERS]; @@ -459,26 +468,43 @@ inline boolean Platform::UsePID(int8_t heater) return usePID[heater]; } -inline void Platform::SetStandbyTemperature(int8_t heater, const float& t) + +inline float Platform::PidKi(int8_t heater) { - standbyTemperatures[heater] = t; + return pidKis[heater]*heatSampleTime; } -inline void Platform::SetActiveTemperature(int8_t heater, const float& t) +inline float Platform::PidKd(int8_t heater) { - activeTemperatures[heater] = t; + return pidKds[heater]/heatSampleTime; } -inline float Platform::StandbyTemperature(int8_t heater) +inline float Platform::PidKp(int8_t heater) { - return standbyTemperatures[heater]; + return pidKps[heater]; } -inline float Platform::ActiveTemperature(int8_t heater) +inline float Platform::FullPidBand(int8_t heater) { - return activeTemperatures[heater]; + return fullPidBand[heater]; } +inline float Platform::PidMin(int8_t heater) +{ + return pidMin[heater]; +} + +inline float Platform::PidMax(int8_t heater) +{ + return pidMax[heater]/PidKi(heater); +} + +inline float Platform::DMix(int8_t heater) +{ + return dMix[heater]; +} + + //********************************************************************************************************* // Interrupts diff --git a/Platform.ino b/Platform.ino index 0031fe7..b1ccf1f 100644 --- a/Platform.ino +++ b/Platform.ino @@ -103,14 +103,18 @@ void Platform::Init() pidKis = PID_KIS; pidKds = PID_KDS; pidKps = PID_KPS; - pidILimits = PID_I_LIMITS; + fullPidBand = FULL_PID_BAND; + pidMin = PID_MIN; + pidMax = PID_MAX; + dMix = D_MIX; + heatSampleTime = HEAT_SAMPLE_TIME; + standbyTemperatures = STANDBY_TEMPERATURES; + activeTemperatures = ACTIVE_TEMPERATURES; + webDir = WEB_DIR; gcodeDir = GCODE_DIR; sysDir = SYS_DIR; tempDir = TEMP_DIR; - heatSampleTime = HEAT_SAMPLE_TIME; - standbyTemperatures = STANDBY_TEMPERATURES; - activeTemperatures = ACTIVE_TEMPERATURES; } for(i = 0; i < DRIVES; i++) @@ -229,11 +233,26 @@ bool Platform::LoadFromStore() // Result is in degrees celsius +/* +#define A 100000.0 +#define B 150000.0 +#define RS 4700 +#define VLOW 3.362 +#define VT 4.65 +*/ + float Platform::GetTemperature(int8_t heater) { float r = (float)GetRawTemperature(heater); //Serial.println(r); return ABS_ZERO + thermistorBetas[heater]/log( (r*thermistorSeriesRs[heater]/(AD_RANGE - r))/thermistorInfRs[heater] ); +/* float v = VLOW*(float)GetRawTemperature(heater)/AD_RANGE; + Serial.print(v); Serial.print(' '); + float k = (A + B)*v/(B*VT); + float rp = RS*k/(1 - k); + float r = rp*(A+B)/(A + B - rp); + Serial.println(r); + return ABS_ZERO + thermistorBetas[heater]/log( r/thermistorInfRs[heater] );*/ } @@ -241,15 +260,15 @@ float Platform::GetTemperature(int8_t heater) void Platform::SetHeater(int8_t heater, const float& power) { - if(power <= 0.0) + if(power <= 0.00) { - digitalWrite(heatOnPins[heater], 0); + analogWrite(heatOnPins[heater], 0); return; } if(power >= 1.0) { - digitalWrite(heatOnPins[heater], 1); + analogWrite(heatOnPins[heater], 255); return; }