This text is being translated into English. My native language is Spanish.
A few days ago, I started a project to build a machine that converts PET bottles into PET filament for a 3D printer. Everything was going well until I had to write the PID control code myself, since all the examples online use MOSFETs. My problem is that I don’t have one, so I tried to make it work with a relay before buying one. The reality is that it works, but it works very poorly—the temperatures fluctuate WAY too much, making the filament quality terrible. Also, I had a lot of trouble with something as simple as measuring the temperature. I don’t know why, but I find it really difficult to get an accurate reading.
Data:
- I am using a 100k thermistor (pin A0) (the same type used in 3D printers).
- I am using a single-channel relay module, optocoupled with inverted logic, meaning that when it receives a HIGH (1), the relay turns off, and when it receives a LOW (0), the relay turns on.
- I am using a 12V 40W heating cartridge.
- 1.7mm nozzle.
- The reference resistor I am using is 10k.
- The target temperature set in the code is 220°C (428°F), but the correct operating range should be between 180°C and 220°C (356°F–428°F).
Problem:
I have to guess the temperature because the code returns an unstable reading, and on top of that, it fails to fully stabilize the temperature. This means I don’t really know how hot the hotend is, as the measurement could be off by several degrees.
Notes:
Besides being a beginner at this and having never done it before, several parts of the code were "fixed" with the help of ChatGPT, so I don’t fully understand what is failing.
#include <LiquidCrystal_I2C.h>
#include <PID_v1.h>
#include <Wire.h>
// Configuración del LCD
LiquidCrystal_I2C lcd(0x27, 16, 2);
// Pines y configuración
#define THERMISTOR_PIN A0
#define RELAY_PIN 5
// Variables PID
double Setpoint = 220.0; // Temperatura objetivo en grados Celsius
double Input; // Temperatura medida
double Output; // Salida PID
// Coeficientes del PID
double Kp = 2.0, Ki = 5.0, Kd = 1.0;
PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT);
// Configuración del divisor de tensión
#define SERIES_RESISTOR 10000 // Resistencia en ohmios (ajustada)
#define THERMISTOR_NOMINAL 100000 // Resistencia nominal del termistor
#define TEMPERATURE_NOMINAL 25 // Temperatura nominal del termistor
#define BCOEFFICIENT 3950 // Coeficiente beta del termistor
#define ADC_MAX 1023.0 // Resolución ADC
#define VCC 5.0 // Voltaje de referencia
void setup() {
// Configuración de pines
pinMode(RELAY_PIN, OUTPUT);
digitalWrite(RELAY_PIN, LOW); // Apaga el relay inicialmente
// Inicialización del LCD
lcd.init();
lcd.backlight();
lcd.print("Iniciando...");
// Configuración del PID
myPID.SetMode(AUTOMATIC);
myPID.SetOutputLimits(0, 255); // Límite de salida para PWM o activación
delay(2000);
lcd.clear();
}
void loop() {
// Leer el termistor
int adcValue = analogRead(THERMISTOR_PIN);
// Corregir cálculo de resistencia
double voltage = adcValue * (VCC / ADC_MAX);
double resistance = (VCC * SERIES_RESISTOR / voltage) - SERIES_RESISTOR;
// Calcular la temperatura en grados Celsius
double steinhart;
steinhart = resistance / THERMISTOR_NOMINAL; // (R/Ro)
steinhart = log(steinhart); // ln(R/Ro)
steinhart /= BCOEFFICIENT; // 1/B * ln(R/Ro)
steinhart += 1.0 / (TEMPERATURE_NOMINAL + 273.15); // + (1/To)
steinhart = 1.0 / steinhart; // Invertir
Input = steinhart - 273.15; // Convertir a Celsius
// Actualizar el PID
myPID.Compute();
// Control del relay con histeresis para mayor precisión
static bool relayState = false;
if (!relayState && Input < (Setpoint - 2)) {
relayState = true;
digitalWrite(RELAY_PIN, HIGH);
} else if (relayState && Input > (Setpoint + 2)) {
relayState = false;
digitalWrite(RELAY_PIN, LOW);
}
// Mostrar en el LCD
lcd.setCursor(0, 0);
lcd.print("Temp: ");
lcd.print(Input, 1); // Una cifra decimal
lcd.print(" C ");
lcd.setCursor(0, 1);
lcd.print("Set: ");
lcd.print(Setpoint, 1);
lcd.print(" C ");
delay(500); // Tiempo de actualización
}
Thank you for your help, I am at your disposal.