machines/projects/HugeFancy/TeensyArduino_Codes/Code_Teensy_Extruder/PID_TemperatureControl.ino
2023-11-12 21:43:05 +01:00

169 lines
5.0 KiB
C++

/*
*
* Code that is responsible for controling the hotend heat-bands with PID
*
* PID Example: https://github.com/br3ttb/Arduino-PID-Library/blob/master/examples/PID_RelayOutput/PID_RelayOutput.ino
* relevant Forum post: https://forum.arduino.cc/index.php?topic=142526.0
*
*/
/********************************************************
* PID RelayOutput for Temperature control
* the pid library is designed to Output an analog value,
* but the relay can only be On/Off.
*
* to connect them together we use "time proportioning
* control" it's essentially a really slow version of PWM.
* first we decide on a window size (5000mS say.) we then
* set the pid to adjust its output between 0 and that window
* size. lastly, we add some logic that translates the PID
* output into "Relay On Time" with the remainder of the
* window being "Relay Off Time"
********************************************************/
#include <PID_v1.h>
//see Relays.ino for pinout
const int Zone1_TargetOffset = 5 ; // Heating Zone 1 will be different from Zone 2
int TargetTemperatureZone_1 = 0; // max 9 Bit = 511°C
int TargetTemperatureZone_2 = 0; // max 9 Bit = 511°C
// ->
int RealTemperatureZone_1 = 0; // max 9 Bit = 511°C
int RealTemperatureZone_2 = 0; // max 9 Bit = 511°C
double AveragedRealTempZone_1 = 0; //average temperature over the last 5 measurements
double AveragedRealTempZone_2 = 0;
double HeatPowerZone_1 = 0;
double HeatPowerZone_2 = 0;
/// Hotend Bools
//these are status bools that do not affect the actual prcess but simply indicate a status.
//Changing them here will not activate the relays
int LuefterZone_1 = 0;
int LuefterZone_2 = 0;
int HeaterZone_1 = 0;
int HeaterZone_2 = 0;
//Define Variables we'll be connecting to
double Setpoint_Zone1, Input_Zone1, Output_Zone1; //Heating Zone 1
double Setpoint_Zone2, Input_Zone2, Output_Zone2; //Heating Zone 2
//Specify the links and initial tuning parameters
//TODO: find out if P_ON_M is needed (proportional on measurement) http://brettbeauregard.com/blog/2017/06/introducing-proportional-on-measurement/
//Heating Zone_1
double Kp_Zone1=120, Ki_Zone1=0.3274, Kd_Zone1=150;
PID myPID_Zone1(&Input_Zone1, &Output_Zone1, &Setpoint_Zone1, Kp_Zone1, Ki_Zone1, Kd_Zone1, 1, DIRECT);
//Heating Zon0
double Kp_Zone2=120, Ki_Zone2=0.3274, Kd_Zone2=150;
PID myPID_Zone2(&Input_Zone2, &Output_Zone2, &Setpoint_Zone2, Kp_Zone2, Ki_Zone1, Kd_Zone2, 1, DIRECT);
int WindowSize = 4000;
unsigned long windowStartTime;
double averageZ1,averageZ2;
double OutputBufferZ1, OutputBufferZ2;
void PID_setup()
{
windowStartTime = millis();
//initialize the variables we're linked to
Setpoint_Zone1 = 0;
Setpoint_Zone2 = 0;
//tell the PID to range between 0 and the full window size
myPID_Zone1.SetOutputLimits(0, WindowSize);
myPID_Zone2.SetOutputLimits(0, WindowSize);
//turn the PID on
myPID_Zone1.SetMode(AUTOMATIC);
myPID_Zone2.SetMode(AUTOMATIC);
}
void PID_loop()
{
//Set the current temperature targets
Setpoint_Zone1 = (double)TargetTemperatureZone_1;
Setpoint_Zone2 = (double)TargetTemperatureZone_2;
//Get the current temperature
//Input_Zone1 = RealTemperatureZone_1;
//Input_Zone2 = RealTemperatureZone_2;
Input_Zone1 = AveragedRealTempZone_1;
Input_Zone2 = AveragedRealTempZone_2;
//Compute PID from Input Values
myPID_Zone1.Compute();
myPID_Zone2.Compute();
if (Output_Zone1/WindowSize < 0.5 && Input_Zone1 > Setpoint_Zone1 *1.01)
{
RelayCoolerZone_1_SetStatus(true) ;
}
else
{
RelayCoolerZone_1_SetStatus(false) ;
}
if (Output_Zone2/WindowSize < 0.5 && Input_Zone2 > Setpoint_Zone2 *1.01)
{
RelayCoolerZone_2_SetStatus(true) ;
}
else
{
RelayCoolerZone_2_SetStatus(false) ;
}
/************************************************
* turn the output pin on/off based on pid output
************************************************/
if ( (abs(millis() - windowStartTime) > WindowSize) )
{ //time to shift the Relay Window
windowStartTime = millis();
}
OutputBufferZ1 = (OutputBufferZ1 + Output_Zone1) / 2;
HeatPowerZone_1 = OutputBufferZ1/WindowSize *25;
if (OutputBufferZ1 > millis() - windowStartTime)
{
RelayHeaterZone_1_SetStatus(true);
//RelayCoolerZone_1_SetStatus(false) ;
LuefterZone_1 = 0;
HeaterZone_1 = 15;
//Serial.print(15);
//Serial.print(",");
}
else
{
RelayHeaterZone_1_SetStatus(false);
//RelayCoolerZone_1_SetStatus(true) ;
LuefterZone_1 = 18;
HeaterZone_1 = 0;
//Serial.print(0);
//Serial.print(",");
}
OutputBufferZ2 = (OutputBufferZ2 + Output_Zone2) / 2;
HeatPowerZone_2 = OutputBufferZ2/WindowSize *25;
if (OutputBufferZ2 > millis() - windowStartTime)
{
RelayHeaterZone_2_SetStatus(true);
//RelayCoolerZone_2_SetStatus(false) ;
LuefterZone_2 = 0;
HeaterZone_2 = 10;
//Serial.print(10);
//Serial.print(",");
}
else
{
RelayHeaterZone_2_SetStatus(false);
//RelayCoolerZone_2_SetStatus(true) ;
LuefterZone_2 = 7;
HeaterZone_2 = 0;
//Serial.print(0);
//Serial.print(",");
}
}