Temperature code now working. PID may need a little tweaking.

This commit is contained in:
Adrian Bowyer 2013-07-11 20:22:21 +01:00
parent ce7522f682
commit b94bff107c
7 changed files with 242 additions and 62 deletions

View file

@ -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

View file

@ -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;
}
}

55
Heat.h
View file

@ -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

View file

@ -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);
}

View file

@ -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()
{

View file

@ -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

View file

@ -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;
}