In the world of electronics and systems control, temperature management is crucial for ensuring optimal performance and longevity of electronic components. Whether you're cooling down a computer, controlling a robotic system, or fine-tuning an IoT application, PID (Proportional, Integral, Derivative) control offers an effective solution. This article explores how a DIY PID temperature controller using an Arduino can be implemented to manage temperature-sensitive systems such as computer motherboard, robotics, and more, and how the same principles can be applied across various domains.
The Role of PID Control in Temperature Regulation
PID control is a type of feedback control system that automatically adjusts an output (in this case, fan speed) to achieve and maintain a desired state (setpoint). In our DIY setup, an Arduino is used to control the temperature by monitoring readings from a thermistor, and adjusting the speed of a fan using a PID algorithm.
A sample implementation of this PID controller, written for Arduino, involves several key components: a thermistor to measure temperature, a fan controlled by PWM (Pulse Width Modulation), and an OLED display to show real-time feedback. The controller operates by comparing the current temperature to a preset setpoint, and the fan speed is adjusted accordingly to bring the temperature closer to the desired value.
Core Components of the PID Controller
This project uses the following key components:
- Thermistor: Measures the ambient temperature and feeds it to the Arduino.
- Fan (controlled via PWM): Adjusts cooling based on the output of the PID controller.
- OLED Display: Provides a real-time interface showing the temperature, setpoint, fan speed, and PID output.
The following shows the thermistor used in this tutorial.
The PC fan is a four wire fan with Vcc, gnd, pwm control and tachometer but here only three pins are used the Vcc, gnd and the pwm control pin. The PC fan and thermistor were salvaged from old desktop computer and from laptop battery charging circuit respectively.
The code which is explained below, continuously monitors the temperature, calculates the PID output, and adjusts the fan speed to maintain the target setpoint temperature. When the temperature deviates from the setpoint, the fan speed is adjusted proportionally, integrally, and derivatively to bring it back within range.
PC/Laptop Motherboad PID Temperature Controller Program Code:
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SH1106.h>
#include <PID_v1.h>
// OLED display setup
#define OLED_RESET 4
Adafruit_SH1106 display(OLED_RESET);
// Pins and variables
const int thermistorPin = A0; // Thermistor input pin
const int fanPin = 9; // PWM pin for controlling the fan
const int GreenLED = 12; // Green LED pin
const int RedLED = 11; // Red LED pin
const int potPin = A2; // Potentiometer input pin (for setpoint)
// Thermistor constants
const float R1 = 10000; // Resistance at 25°C (in ohms)
const float T0 = 25.0; // Reference temperature in Celsius
const float B = 3950.0; // B constant of the thermistor
// PID constants
double Kp = 2.0, Ki = 5.0, Kd = 1.0; // Default PID constants
double Setpoint, Input, Output; // PID variables
PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT);
// Sample rate for PID
const int sampleRate = 1000; // PID sample rate in milliseconds
void setup() {
// Setup serial communication and OLED
Serial.begin(9600);
analogReference(EXTERNAL);
// Initialize OLED display
display.begin(SH1106_SWITCHCAPVCC, 0x3C); // SH1106 OLED, 128x64 resolution
display.display();
delay(2000);
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(20, 10);
display.println("Temperature PID");
display.setCursor(30, 20);
display.println("Controller");
display.setCursor(20, 30);
display.println("ee-diary.com");
display.display();
delay(2000);
// Setup LEDs
pinMode(GreenLED, OUTPUT);
pinMode(RedLED, OUTPUT);
pinMode(fanPin, OUTPUT);
// Initialize the PID controller
myPID.SetMode(AUTOMATIC);
myPID.SetSampleTime(sampleRate);
// Set initial setpoint to 22°C (this will be overridden by the potentiometer reading)
Setpoint = 22.0;
}
void loop() {
// Read thermistor value and calculate temperature
int rawReading = analogRead(thermistorPin);
float resistance = (1023.0 / rawReading - 1.0) * R1;
float temperature = 1.0 / (log(resistance / R1) / B + 1.0 / (T0 + 273.15)) - 273.15;
// Read potentiometer to set the desired temperature setpoint
int potValue = analogRead(potPin); // Read potentiometer value (0-1023)
Setpoint = map(potValue, 0, 1023, 0, 80); // Map to temperature range 20-80°C
// Update PID input and compute output
Input = temperature;
myPID.Compute(); // Calculate PID output (fan speed)
// Invert the logic of the PID output since we want to decrease the temperature (cooling)
int outPWM = 255 - Output; // Invert the PID output so the fan speed is higher when cooling is needed
int outPercent = (outPWM/255)*100;
// Control fan speed with PWM
analogWrite(fanPin, (int)Output);
// Control LEDs based on temperature range
if (temperature >= Setpoint - 2 && temperature <= Setpoint + 2) {
digitalWrite(RedLED, LOW);
digitalWrite(GreenLED, HIGH);
} else {
digitalWrite(RedLED, HIGH);
digitalWrite(GreenLED, LOW);
}
// Display the current temperature and setpoint on OLED
display.clearDisplay();
display.setCursor(0, 0);
display.print("Setpoint: ");
display.print(Setpoint);
display.print(" C");
display.setCursor(0, 10);
display.print("Temperature: ");
display.print(temperature);
display.print(" C");
display.setCursor(0, 20);
display.print("Fan Speed: ");
display.print(outPWM);
display.print(" PWM");
display.setCursor(0, 30);
display.print("Output: ");
display.print(outPercent);
display.print("%");
display.display(); // Refresh OLED display
// Display data on serial monitor for debugging
Serial.print("Temperature: ");
Serial.print(temperature);
Serial.print("°C, Setpoint: ");
Serial.print(Setpoint);
Serial.print("°C, Fan Speed: ");
Serial.println((int)Output);
// Tuning PID parameters through serial monitor
if (Serial.available() > 0) {
Kp = Serial.parseFloat();
Ki = Serial.parseFloat();
Kd = Serial.parseFloat();
myPID.SetTunings(Kp, Ki, Kd);
Serial.print("New Kp, Ki, Kd: ");
Serial.print(Kp);
Serial.print(", ");
Serial.print(Ki);
Serial.print(", ");
Serial.println(Kd);
}
delay(sampleRate); // Wait for the next PID calculation
}
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SH1106.h>
#include <PID_v1.h>
// OLED display setup
#define OLED_RESET 4
Adafruit_SH1106 display(OLED_RESET);
// Pins and variables
const int thermistorPin = A0; // Thermistor input pin
const int fanPin = 9; // PWM pin for controlling the fan
const int GreenLED = 12; // Green LED pin
const int RedLED = 11; // Red LED pin
const int potPin = A2; // Potentiometer input pin (for setpoint)
// Thermistor constants
const float R1 = 10000; // Resistance at 25°C (in ohms)
const float T0 = 25.0; // Reference temperature in Celsius
const float B = 3950.0; // B constant of the thermistor
// PID constants
double Kp = 2.0, Ki = 5.0, Kd = 1.0; // Default PID constants
double Setpoint, Input, Output; // PID variables
PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT);
// Sample rate for PID
const int sampleRate = 1000; // PID sample rate in milliseconds
void setup() {
// Setup serial communication and OLED
Serial.begin(9600);
analogReference(EXTERNAL);
// Initialize OLED display
display.begin(SH1106_SWITCHCAPVCC, 0x3C); // SH1106 OLED, 128x64 resolution
display.display();
delay(2000);
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(20, 10);
display.println("Temperature PID");
display.setCursor(30, 20);
display.println("Controller");
display.setCursor(20, 30);
display.println("ee-diary.com");
display.display();
delay(2000);
// Setup LEDs
pinMode(GreenLED, OUTPUT);
pinMode(RedLED, OUTPUT);
pinMode(fanPin, OUTPUT);
// Initialize the PID controller
myPID.SetMode(AUTOMATIC);
myPID.SetSampleTime(sampleRate);
// Set initial setpoint to 22°C (this will be overridden by the potentiometer reading)
Setpoint = 22.0;
}
void loop() {
// Read thermistor value and calculate temperature
int rawReading = analogRead(thermistorPin);
float resistance = (1023.0 / rawReading - 1.0) * R1;
float temperature = 1.0 / (log(resistance / R1) / B + 1.0 / (T0 + 273.15)) - 273.15;
// Read potentiometer to set the desired temperature setpoint
int potValue = analogRead(potPin); // Read potentiometer value (0-1023)
Setpoint = map(potValue, 0, 1023, 0, 80); // Map to temperature range 20-80°C
// Update PID input and compute output
Input = temperature;
myPID.Compute(); // Calculate PID output (fan speed)
// Invert the logic of the PID output since we want to decrease the temperature (cooling)
int outPWM = 255 - Output; // Invert the PID output so the fan speed is higher when cooling is needed
int outPercent = (outPWM/255)*100;
// Control fan speed with PWM
analogWrite(fanPin, (int)Output);
// Control LEDs based on temperature range
if (temperature >= Setpoint - 2 && temperature <= Setpoint + 2) {
digitalWrite(RedLED, LOW);
digitalWrite(GreenLED, HIGH);
} else {
digitalWrite(RedLED, HIGH);
digitalWrite(GreenLED, LOW);
}
// Display the current temperature and setpoint on OLED
display.clearDisplay();
display.setCursor(0, 0);
display.print("Setpoint: ");
display.print(Setpoint);
display.print(" C");
display.setCursor(0, 10);
display.print("Temperature: ");
display.print(temperature);
display.print(" C");
display.setCursor(0, 20);
display.print("Fan Speed: ");
display.print(outPWM);
display.print(" PWM");
display.setCursor(0, 30);
display.print("Output: ");
display.print(outPercent);
display.print("%");
display.display(); // Refresh OLED display
// Display data on serial monitor for debugging
Serial.print("Temperature: ");
Serial.print(temperature);
Serial.print("°C, Setpoint: ");
Serial.print(Setpoint);
Serial.print("°C, Fan Speed: ");
Serial.println((int)Output);
// Tuning PID parameters through serial monitor
if (Serial.available() > 0) {
Kp = Serial.parseFloat();
Ki = Serial.parseFloat();
Kd = Serial.parseFloat();
myPID.SetTunings(Kp, Ki, Kd);
Serial.print("New Kp, Ki, Kd: ");
Serial.print(Kp);
Serial.print(", ");
Serial.print(Ki);
Serial.print(", ");
Serial.println(Kd);
}
delay(sampleRate); // Wait for the next PID calculation
}
Understanding the Code
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SH1106.h>
#include <PID_v1.h>
// OLED display setup
#define OLED_RESET 4
Adafruit_SH1106 display(OLED_RESET);
// Pins and variables
const int thermistorPin = A0; // Thermistor input pin
const int fanPin = 9; // PWM pin for controlling the fan
const int GreenLED = 12; // Green LED pin
const int RedLED = 11; // Red LED pin
const int potPin = A2; // Potentiometer input pin (for setpoint)
This section initializes the required components, such as the OLED display, thermistor, fan, and LEDs. A potentiometer is used to dynamically adjust the temperature setpoint.
// PID constants
double Kp = 2.0, Ki = 5.0, Kd = 1.0; // Default PID constants
double Setpoint, Input, Output; // PID variables
PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT);
Here, the PID controller is initialized with default Kp, Ki, Kd values, which you can tune to optimize the system's response. The controller adjusts its output based on the temperature error (difference between the setpoint and current temperature).
// Sample rate for PID
const int sampleRate = 1000; // PID sample rate in milliseconds
The sample rate determines how frequently the PID algorithm is updated, ensuring timely adjustments to the fan speed.
Tuning PID Parameters for Optimal Control
In PID control, the parameters Kp (proportional), Ki (integral), and Kd (derivative) control the responsiveness of the system. Proper tuning of these parameters is crucial for achieving smooth and stable temperature regulation. Too high a value for any parameter might lead to oscillations or instability, while too low might result in sluggish performance.
If you're interested in learning how to fine-tune these parameters, check out our detailed guide on how to tune PID parameters: Kp, Ki, Kd, which explores different tuning methods to achieve optimal system performance.
How This DIY Setup Can Benefit Your Projects
While this setup is designed to control temperature in a computer system, the principles of PID control can be applied to virtually any system where you need precise regulation, such as robotics, IoT devices, and even drones. For example, in robotics, you could control the temperature of sensitive electronics like motors, sensors, and batteries. In drones, maintaining optimal temperatures can help increase flight time and avoid overheating issues.
This PID temperature controller can be scaled to other applications. For example, it can be used in oven temperature regulation, aquarium heaters, or even power supply management.
Integration with Other Control Systems
This PID setup can also be enhanced with adaptive control systems or feedforward control systems to achieve better performance in more dynamic environments. Adaptive controllers can adjust their parameters in real-time, while feedforward control anticipates changes based on inputs, improving the responsiveness of the system.
To explore these advanced control techniques, consider checking out the following resources:
- Feedforward Control System with Arduino — Learn how to implement feedforward control to improve the system’s predictive accuracy.
- Adaptive Control System with Arduino — Discover how adaptive control allows systems to learn and adjust to changing conditions.
Managing Heat Dissipation in Electronics
Managing heat dissipation in electronic systems is vital, especially when dealing with high-power components. You can calculate and optimize the heat dissipation in your PCB designs using our PCB Heat Dissipation Thermal Resistance Calculator, which can help you design more efficient systems that stay cool under load.
PWM Control in ATmega328P for Efficient Fan Speed Regulation
For those looking to integrate PWM control for efficient fan speed regulation, check out our article on ATmega328P Fast PWM Mode Programming. PWM is a critical component of controlling fan speed in temperature-sensitive applications, and this guide will help you optimize your PWM control for more efficient cooling.
Why This DIY PID Setup Works Across Applications
The underlying principle behind this PID controller is feedback regulation, which ensures that the output (fan speed) is adjusted based on the input (temperature). This concept is foundational not just in cooling systems, but in various control applications, from regulating the speed of a motor in robotics to controlling the power in an IoT device. The adaptive control and feedforward strategies discussed earlier can further enhance this approach by making it more responsive to changing conditions.
For more information on control systems, check out our comprehensive research articles on thermocouple-based temperature regulation in ovens and other appliances, which dive deep into PID applications for precise control.
- Arduino PID Controller for Thermocouple and Oven-Based Temperature Control — A deeper look at how PID control is implemented with thermocouples and used in oven systems.
- PC/Laptop Motherboard PID Temperature Regulation — Learn how PID controllers are applied to regulate temperature in computer motherboards.
Conclusion
This DIY PID temperature controller offers an affordable, flexible solution for managing temperature in a variety of applications, from cooling your computer to controlling robotics and IoT(Internet of Things) systems. By utilizing a simple Arduino-based setup, you can achieve highly accurate temperature control and extend the life of your devices. Whether you're a hobbyist, maker, or engineer, understanding and implementing PID control can significantly enhance the performance of your projects.
For a more in-depth understanding of PID control, and to optimize your setup for different applications, don't forget to check out the additional articles and resources linked above.