mirror of
https://github.com/arwidcool/Solder-Plate.git
synced 2024-11-28 08:20:52 +01:00
Un-reveresed the PID logic, a bit easier to follow now
This commit is contained in:
parent
8b78c29abc
commit
7f2c8f105a
@ -14,6 +14,7 @@ board = ATmega4809
|
|||||||
framework = arduino
|
framework = arduino
|
||||||
monitor_speed = 38400
|
monitor_speed = 38400
|
||||||
upload_speed = 115200
|
upload_speed = 115200
|
||||||
|
|
||||||
board_hardware.uart = uart0
|
board_hardware.uart = uart0
|
||||||
upload_protocol = arduino
|
upload_protocol = arduino
|
||||||
lib_ldf_mode = chain+
|
lib_ldf_mode = chain+
|
||||||
|
@ -14,7 +14,7 @@ PidController::PidController(PidControllerData *data)
|
|||||||
this->data = data;
|
this->data = data;
|
||||||
|
|
||||||
controller.begin(&(this->data->currentTemp), &(this->data->setPoint), &(this->data->targetTemp), PID_P, PID_I, PID_D);
|
controller.begin(&(this->data->currentTemp), &(this->data->setPoint), &(this->data->targetTemp), PID_P, PID_I, PID_D);
|
||||||
controller.reverse();
|
// controller.reverse();
|
||||||
controller.setOutputLimits(PID_OUTPUT_MIN, PID_OUTPUT_MAX);
|
controller.setOutputLimits(PID_OUTPUT_MIN, PID_OUTPUT_MAX);
|
||||||
controller.setSampleTime(PID_SAMPLE_TIME);
|
controller.setSampleTime(PID_SAMPLE_TIME);
|
||||||
controller.setWindUpLimits(PID_WINDUP_MIN, PID_WINDUP_MAX);
|
controller.setWindUpLimits(PID_WINDUP_MIN, PID_WINDUP_MAX);
|
||||||
@ -47,7 +47,10 @@ void PidController::loop()
|
|||||||
|
|
||||||
// float sysVoltage = analogRef.calculateSystemVoltage();
|
// float sysVoltage = analogRef.calculateSystemVoltage();
|
||||||
compute();
|
compute();
|
||||||
analogWrite(MOSTFET_PIN, data->setPoint);
|
|
||||||
|
//Reverseal of the PWM value is needed because the PID controller is set to work with a normal direction, Creates fopr a better PID control
|
||||||
|
//255= off, 0=full power
|
||||||
|
analogWrite(MOSTFET_PIN, 255- data->setPoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PidController::stop()
|
void PidController::stop()
|
||||||
|
@ -38,9 +38,7 @@ void TFT_Display::init(ReflowProfile *profile)
|
|||||||
tft.setCursor(xy.x, xy.y);
|
tft.setCursor(xy.x, xy.y);
|
||||||
tft.println(profile->name);
|
tft.println(profile->name);
|
||||||
getMaxTempFromProfile(profile);
|
getMaxTempFromProfile(profile);
|
||||||
|
|
||||||
this->profile = profile;
|
this->profile = profile;
|
||||||
|
|
||||||
drawTimer.reset();
|
drawTimer.reset();
|
||||||
|
|
||||||
drawTimer.setResolution(StopWatch::MILLIS);
|
drawTimer.setResolution(StopWatch::MILLIS);
|
||||||
@ -54,19 +52,11 @@ void TFT_Display::drawRealTemp(double *temp, float percentage)
|
|||||||
|
|
||||||
uint32_t timeSinceLastDraw = drawTimer.elapsed();
|
uint32_t timeSinceLastDraw = drawTimer.elapsed();
|
||||||
|
|
||||||
// Serial.print("Time since last draw:");
|
|
||||||
// Serial.println(timeSinceLastDraw);
|
|
||||||
|
|
||||||
if (timeSinceLastDraw >= 930)
|
if (timeSinceLastDraw >= 930)
|
||||||
{
|
{
|
||||||
|
|
||||||
float temperature = static_cast<float>(*temp);
|
float temperature = static_cast<float>(*temp);
|
||||||
|
|
||||||
// Serial.print("Time:");
|
|
||||||
// Serial.print(percentage);
|
|
||||||
// Serial.print(" Temp:");
|
|
||||||
// Serial.println(temperature);
|
|
||||||
|
|
||||||
uint16_t eplased = drawTimer.elapsed();
|
uint16_t eplased = drawTimer.elapsed();
|
||||||
|
|
||||||
// Get the xy and y pixel of the temp
|
// Get the xy and y pixel of the temp
|
||||||
@ -75,7 +65,7 @@ void TFT_Display::drawRealTemp(double *temp, float percentage)
|
|||||||
uint16_t y = tempYonGraph(temperature);
|
uint16_t y = tempYonGraph(temperature);
|
||||||
// Draw the pixel
|
// Draw the pixel
|
||||||
|
|
||||||
//tft.drawPixel(x, y, ST77XX_RED);
|
// tft.drawPixel(x, y, ST77XX_RED);
|
||||||
|
|
||||||
tft.drawLine(prevousTempXY.x, prevousTempXY.y, x, y, ST77XX_RED);
|
tft.drawLine(prevousTempXY.x, prevousTempXY.y, x, y, ST77XX_RED);
|
||||||
|
|
||||||
@ -84,7 +74,6 @@ void TFT_Display::drawRealTemp(double *temp, float percentage)
|
|||||||
drawTimer.reset();
|
drawTimer.reset();
|
||||||
drawTimer.start();
|
drawTimer.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TFT_Display::clear()
|
void TFT_Display::clear()
|
||||||
@ -272,7 +261,7 @@ void TFT_Display::drawGraphAxisTickLabels()
|
|||||||
TFT_XY position;
|
TFT_XY position;
|
||||||
|
|
||||||
// Always starts at 20c
|
// Always starts at 20c
|
||||||
position = getRightAlignedTextXY("20", graphXY.x, graphXY.y);
|
position = getRightAlignedTextXY("0", graphXY.x, graphXY.y);
|
||||||
tft.setCursor(position.x - tickMarkLength, position.y);
|
tft.setCursor(position.x - tickMarkLength, position.y);
|
||||||
tft.println("20");
|
tft.println("20");
|
||||||
|
|
||||||
@ -286,7 +275,7 @@ void TFT_Display::drawGraphAxisTickLabels()
|
|||||||
// Draw three tick labels on the temp axis at 1/4, 1/2 and 3/4 of the way along
|
// Draw three tick labels on the temp axis at 1/4, 1/2 and 3/4 of the way along
|
||||||
for (int i = 1; i <= 3; i++)
|
for (int i = 1; i <= 3; i++)
|
||||||
{
|
{
|
||||||
uint8_t temp = (maxTemp - minTemp) * i / 4;
|
uint8_t temp = ((maxTemp ) * i / 4)+minTemp;
|
||||||
char *tempCharPtr = numberToCharPtr(temp);
|
char *tempCharPtr = numberToCharPtr(temp);
|
||||||
position = getRightAlignedTextXY(tempCharPtr, graphXY.x, graphXY.y - (graphHeight * i / 4));
|
position = getRightAlignedTextXY(tempCharPtr, graphXY.x, graphXY.y - (graphHeight * i / 4));
|
||||||
tft.setCursor(position.x - tickMarkLength, position.y);
|
tft.setCursor(position.x - tickMarkLength, position.y);
|
||||||
@ -324,27 +313,29 @@ void TFT_Display::drawGraphReflowStagesBackground()
|
|||||||
{
|
{
|
||||||
uint16_t colors[4] = {preheat_COLOR, soak_COLOR, reflow_COLOR, cool_COLOR};
|
uint16_t colors[4] = {preheat_COLOR, soak_COLOR, reflow_COLOR, cool_COLOR};
|
||||||
// Draw the background for the reflow stages
|
// Draw the background for the reflow stages
|
||||||
uint16_t x= graphXY.x + 1;
|
uint16_t x = graphXY.x + 1;
|
||||||
uint16_t y= graphXY.y;
|
uint16_t y = graphXY.y;
|
||||||
uint16_t totalDuration = profile->endTimes[4];
|
uint16_t totalDuration = profile->endTimes[4];
|
||||||
for (int i=0; i<4; i++) {
|
for (int i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
uint16_t y = graphXY.y - graphHeight;
|
uint16_t y = graphXY.y - graphHeight;
|
||||||
uint16_t height = graphHeight;
|
uint16_t height = graphHeight;
|
||||||
float duration = profile->endTimes[i];
|
float duration = profile->endTimes[i];
|
||||||
float percAtEndStep = duration / totalDuration;
|
float percAtEndStep = duration / totalDuration;
|
||||||
float newX = percentageToX(percAtEndStep);
|
float newX = percentageToX(percAtEndStep);
|
||||||
Serial.println(String(i) + " - duration: "+ String(duration) + " |Perc: "+ String(percAtEndStep)+ " - x:" + String(x) + " y:" + String(y) + " newX:" + String(newX) + " height:" + String(height) + " color:" + String(colors[i]));
|
Serial.println(String(i) + " - duration: " + String(duration) + " |Perc: " + String(percAtEndStep) + " - x:" + String(x) + " y:" + String(y) + " newX:" + String(newX) + " height:" + String(height) + " color:" + String(colors[i]));
|
||||||
tft.drawRect(x, y, newX-x, graphHeight, colors[i]);
|
tft.drawRect(x, y, newX - x, graphHeight, colors[i]);
|
||||||
x = newX;
|
x = newX;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TFT_Display::drawReflowTargetTempLine()
|
||||||
void TFT_Display::drawReflowTargetTempLine() {
|
{
|
||||||
uint16_t y = tempYonGraph(chosenReflowProfile.startTemps[0]);
|
uint16_t y = tempYonGraph(chosenReflowProfile.startTemps[0]);
|
||||||
uint16_t x = percentageToX(0);
|
uint16_t x = percentageToX(0);
|
||||||
for (float i=0.00; i<=1; i+=0.01) {
|
|
||||||
|
for (float i = 0.00; i <= 1; i += 0.01)
|
||||||
|
{
|
||||||
float temp = profile->getTargetTempFromPercentage(i);
|
float temp = profile->getTargetTempFromPercentage(i);
|
||||||
uint16_t y2 = tempYonGraph(temp);
|
uint16_t y2 = tempYonGraph(temp);
|
||||||
uint16_t x2 = percentageToX(i);
|
uint16_t x2 = percentageToX(i);
|
||||||
@ -358,8 +349,8 @@ void TFT_Display::drawReflowTargetTempLine() {
|
|||||||
uint16_t TFT_Display::tempYonGraph(float temp)
|
uint16_t TFT_Display::tempYonGraph(float temp)
|
||||||
{
|
{
|
||||||
|
|
||||||
// Calculate the y position of the temperature on the graph based on the min and max temperatures and the min and max y of the graph the higher the temperature the lower the y values goes
|
|
||||||
|
|
||||||
|
// Calculate the y position based on the current temperature on the graph taking account for the Y start position and the height of the graph the y start is at the end of the graph
|
||||||
float y = graphXY.y - (graphHeight * ((temp - minTemp) / (maxTemp - minTemp)));
|
float y = graphXY.y - (graphHeight * ((temp - minTemp) / (maxTemp - minTemp)));
|
||||||
|
|
||||||
return y;
|
return y;
|
||||||
@ -367,7 +358,6 @@ uint16_t TFT_Display::tempYonGraph(float temp)
|
|||||||
|
|
||||||
uint16_t TFT_Display::tempYonGraph(float *temp)
|
uint16_t TFT_Display::tempYonGraph(float *temp)
|
||||||
{
|
{
|
||||||
|
|
||||||
float y = graphXY.y - (graphHeight * ((*temp - minTemp) / (maxTemp - minTemp)));
|
float y = graphXY.y - (graphHeight * ((*temp - minTemp) / (maxTemp - minTemp)));
|
||||||
return y;
|
return y;
|
||||||
}
|
}
|
||||||
|
@ -44,6 +44,7 @@ private:
|
|||||||
uint16_t graphHeight = 180;
|
uint16_t graphHeight = 180;
|
||||||
uint16_t graphWidth = 255;
|
uint16_t graphWidth = 255;
|
||||||
TFT_XY graphXY = {32, 220};
|
TFT_XY graphXY = {32, 220};
|
||||||
|
TFT_XY graphOrigin = {32, 40};
|
||||||
uint16_t maxTemp = 0;
|
uint16_t maxTemp = 0;
|
||||||
uint8_t minTemp = 20;
|
uint8_t minTemp = 20;
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ uint16_t cool_COLOR = 0x00a8;
|
|||||||
|
|
||||||
// These are the reflow profiles that you can choose from, you can add more if you want (up to 5) but you will have to change the nReflowProfiles variable to the number of profiles you have
|
// These are the reflow profiles that you can choose from, you can add more if you want (up to 5) but you will have to change the nReflowProfiles variable to the number of profiles you have
|
||||||
|
|
||||||
int nReflowProfiles = 3;
|
int nReflowProfiles = 4;
|
||||||
|
|
||||||
ReflowProfile reflowProfiles[] = {
|
ReflowProfile reflowProfiles[] = {
|
||||||
// 138c profile Sn42Bi58
|
// 138c profile Sn42Bi58
|
||||||
@ -74,13 +74,32 @@ ReflowProfile reflowProfiles[] = {
|
|||||||
ReflowStep(ReflowProcessState::DONE, 0, 0)},
|
ReflowStep(ReflowProcessState::DONE, 0, 0)},
|
||||||
"138c Sn42Bi58\0"),
|
"138c Sn42Bi58\0"),
|
||||||
|
|
||||||
ReflowProfile(new ReflowStep[5]{ReflowStep(ReflowProcessState::PREHEAT, 100, 150), ReflowStep(ReflowProcessState::SOAK, 30, 180), ReflowStep(ReflowProcessState::REFLOW, 80, 220, EASE_IN_OUT), ReflowStep(ReflowProcessState::COOL, 30, 183), ReflowStep(ReflowProcessState::DONE, 0, 0)}, "183C Sn63 Pb37 \0"),
|
|
||||||
|
// The profile target says to get to 100c in 30 seconds but our hotplate can not do that so we extended the time to 120 seconds and combine the 150 and 183c steps into one step
|
||||||
|
// With a 12V PSU it also takes a while to reach these high temps so we increase the times a bit, experemintation is needed for different boards.
|
||||||
|
ReflowProfile(new ReflowStep[5]{ReflowStep(ReflowProcessState::PREHEAT, 120, 100,EASE_OUT),
|
||||||
|
ReflowStep(ReflowProcessState::SOAK, 150, 183,EASE_IN),
|
||||||
|
ReflowStep(ReflowProcessState::REFLOW, 110, 235, EASE_OUT),
|
||||||
|
ReflowStep(ReflowProcessState::COOL, 30, 80,EASE_OUT),
|
||||||
|
ReflowStep(ReflowProcessState::DONE, 0, 0)},
|
||||||
|
"183C Sn63 Pb37 \0"),
|
||||||
|
|
||||||
|
|
||||||
|
ReflowProfile(new ReflowStep[5]{ReflowStep(ReflowProcessState::PREHEAT, 120, 77,LINEAR),
|
||||||
|
ReflowStep(ReflowProcessState::SOAK, 180, 135,LINEAR),
|
||||||
|
ReflowStep(ReflowProcessState::REFLOW, 110, 211, LINEAR),
|
||||||
|
ReflowStep(ReflowProcessState::COOL, 30, 80,EASE_OUT),
|
||||||
|
ReflowStep(ReflowProcessState::DONE, 0, 0)},
|
||||||
|
"RAMP HOLD 235c\0"),
|
||||||
|
|
||||||
|
|
||||||
ReflowProfile(new ReflowStep[5]{ReflowStep(
|
ReflowProfile(new ReflowStep[5]{ReflowStep(
|
||||||
ReflowProcessState::PREHEAT, 200, 100,MID_RAMP_HOLD),
|
ReflowProcessState::PREHEAT, 200, 100,MID_RAMP_HOLD),
|
||||||
ReflowStep(ReflowProcessState::SOAK, 150, 150,FAST_RAMP_HOLD),
|
ReflowStep(ReflowProcessState::SOAK, 150, 150,FAST_RAMP_HOLD),
|
||||||
ReflowStep(ReflowProcessState::REFLOW, 150, 220, SLOW_RAMP_HOLD),
|
ReflowStep(ReflowProcessState::REFLOW, 150, 220, SLOW_RAMP_HOLD),
|
||||||
ReflowStep(ReflowProcessState::COOL, 200, 0,LINEAR),
|
ReflowStep(ReflowProcessState::COOL, 200, 0,LINEAR),
|
||||||
ReflowStep(ReflowProcessState::DONE, 0, 0)}, "Tuning Profile \0"),
|
ReflowStep(ReflowProcessState::DONE, 0, 0)},
|
||||||
|
"Tuning Profile \0"),
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -36,17 +36,21 @@
|
|||||||
|
|
||||||
|
|
||||||
//PID Controller values
|
//PID Controller values
|
||||||
#define PID_P .3
|
#define PID_P .05
|
||||||
#define PID_I 1
|
#define PID_I .02
|
||||||
#define PID_D .2
|
#define PID_D .1
|
||||||
|
|
||||||
#define PID_WINDUP_MIN 60
|
#define PID_WINDUP_MIN -100
|
||||||
#define PID_WINDUP_MAX -20
|
#define PID_WINDUP_MAX 255
|
||||||
|
|
||||||
|
////////////////////////////////////////
|
||||||
|
//The actual PWM of the mosfet is 0 for max and 255 for off
|
||||||
|
//This gets inverted after the setpoint is grabbed from the PID controller in the main loop
|
||||||
|
#define PID_OUTPUT_MIN 255
|
||||||
|
#define PID_OUTPUT_MAX 0
|
||||||
|
//////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
//This gets reversed inside the PID controller
|
|
||||||
#define PID_OUTPUT_MIN 0
|
|
||||||
#define PID_OUTPUT_MAX 255
|
|
||||||
#define PID_SAMPLE_TIME 0.1
|
#define PID_SAMPLE_TIME 0.1
|
||||||
|
|
||||||
|
|
||||||
|
33
src/reflow.h
33
src/reflow.h
@ -70,18 +70,6 @@ public:
|
|||||||
return startTemp + (this->targetTemp - startTemp) * (sin(percentage * PI / (double)2));
|
return startTemp + (this->targetTemp - startTemp) * (sin(percentage * PI / (double)2));
|
||||||
case HALF_SINE:
|
case HALF_SINE:
|
||||||
return startTemp + (this->targetTemp - startTemp) * (sin(percentage * PI));
|
return startTemp + (this->targetTemp - startTemp) * (sin(percentage * PI));
|
||||||
case SLOW_RAMP_HOLD:
|
|
||||||
|
|
||||||
if (percentage <= 0.75)
|
|
||||||
{
|
|
||||||
// Ramp up to the target temperature over the first 25% of the time
|
|
||||||
return startTemp + (this->targetTemp - startTemp) * (percentage / 0.75);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Hold at the target temperature for the remaining 75% of the time
|
|
||||||
return this->targetTemp;
|
|
||||||
}
|
|
||||||
|
|
||||||
case MID_RAMP_HOLD:
|
case MID_RAMP_HOLD:
|
||||||
|
|
||||||
@ -95,18 +83,6 @@ public:
|
|||||||
// Hold at the target temperature for the remaining half of the time
|
// Hold at the target temperature for the remaining half of the time
|
||||||
return this->targetTemp;
|
return this->targetTemp;
|
||||||
}
|
}
|
||||||
|
|
||||||
case FAST_RAMP_HOLD:
|
|
||||||
if (percentage <= 0.25)
|
|
||||||
{
|
|
||||||
// Ramp up to the target temperature over the first 75% of the time
|
|
||||||
return startTemp + (this->targetTemp - startTemp) * (percentage / 0.25);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Hold at the target temperature for the remaining 25% of the time
|
|
||||||
return this->targetTemp;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -169,15 +145,8 @@ public:
|
|||||||
|
|
||||||
// We will grab the current PCB temp from the PID as the start temp otherwise the PID will be off
|
// We will grab the current PCB temp from the PID as the start temp otherwise the PID will be off
|
||||||
|
|
||||||
if (plateTemp > 30 && plateTemp < 60)
|
|
||||||
{
|
|
||||||
startTemps[0] = plateTemp; // USe ambient temp as the starting temp for the first step
|
|
||||||
}
|
|
||||||
|
|
||||||
else
|
|
||||||
{
|
|
||||||
startTemps[0] = 20;
|
startTemps[0] = 20;
|
||||||
}
|
|
||||||
|
|
||||||
endTemps[0] = steps[0].calcTempAtPercentage(startTemps[0], 1);
|
endTemps[0] = steps[0].calcTempAtPercentage(startTemps[0], 1);
|
||||||
endTemps[1] = steps[1].calcTempAtPercentage(endTemps[0], 1);
|
endTemps[1] = steps[1].calcTempAtPercentage(endTemps[0], 1);
|
||||||
|
@ -65,7 +65,6 @@ float Thermistor::getTemperature()
|
|||||||
float Thermistor::getWeightingFactor()
|
float Thermistor::getWeightingFactor()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
// If the thermistor is mounted on PCB we give it a weighting factor of 10
|
// If the thermistor is mounted on PCB we give it a weighting factor of 10
|
||||||
switch (zPlacement)
|
switch (zPlacement)
|
||||||
{
|
{
|
||||||
@ -129,6 +128,11 @@ float Thermistor::getWeightingFactor()
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case SIDE:
|
||||||
|
|
||||||
|
return 0.05;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return 1;
|
return 1;
|
||||||
break;
|
break;
|
||||||
|
Loading…
Reference in New Issue
Block a user