Heater Plate Control System
R&D rig for measuring heatsink dissipation on a 20x20mm ceramic resistive heater
Overview
This is my bachelor thesis project, carried out at the University of Girona during my Erasmus exchange in 2026. The goal was to build a research and development rig capable of precisely measuring heatsink dissipation on a 20x20mm ceramic resistive heater element. The application context is thermal characterisation: understanding how much heat a given heatsink configuration can extract from a small, high-power-density component.
The challenge is accuracy. PT100 sensors drift, self-heating is real, and a PID controller that is tuned for speed will overshoot into territory that destroys the sample. Getting stable, repeatable temperature data at the heater surface and at multiple points on the heatsink required careful sensor placement, a proper 3-wire PT100 circuit to cancel lead resistance, and a control strategy that prioritised stability over response time.
What I Built
Firmware (ESP32-S3)
The core of the rig is an ESP32-S3 running custom firmware written in C. The microcontroller handles:
- 3-wire PT100 resistance measurement via a precision ADC front-end
- PWM output to a MOSFET driving the ceramic heater
- Cascade PID control: an outer temperature loop sets the heater power target, an inner loop handles the PWM duty cycle
- Serial data logging at configurable intervals
- USB serial communication for real-time monitoring and parameter adjustment
The cascade architecture was chosen because a single PID loop trying to regulate temperature by directly controlling PWM had too much lag and produced oscillatory behaviour. The inner loop runs at a much higher frequency and handles the fast dynamics of the electrical side, while the outer loop runs slower and handles the thermal dynamics. Tuning the two loops independently made the whole system much easier to stabilise.
PT100 3-Wire Sensing
Standard 2-wire PT100 measurements include lead resistance in the reading, which becomes significant at the cable lengths needed to keep electronics away from the heat. 3-wire sensing cancels lead resistance by measuring the resistance of one lead and subtracting it from the total. The implementation required careful layout and a matched pair of reference resistors to keep the measurement accurate across the full temperature range.
Python Data Pipeline
I built the analysis tooling from scratch in Python rather than using a generic serial monitor. The pipeline reads the comma-separated log output from the ESP32, timestamps each reading, applies basic filtering, and produces plots for each test run. A configuration file lets me adjust which channels to plot, set axis limits, and annotate specific events like setpoint changes.
I wrote it this way because I wanted control over how the data was processed and how the results looked. Using a generic tool would have made it harder to overlay multiple test runs or extract the specific metrics I needed for the thesis write-up.
Heatsink Characterisation
The rig measures steady-state temperature at the heater surface and at multiple points on the heatsink for each power level and airflow condition being tested. Thermal resistance (junction to ambient) is calculated from the temperature differential and the known heater power. The Python tooling automates this calculation across all test points and outputs a thermal resistance curve.
What I Learned
Running this project taught me more about thermal management than any lecture. The gap between “apply power and measure temperature” and “get a measurement you can trust” is larger than it looks. Sources of error that seem small, lead resistance, sensor placement, radiated heat from neighbouring components, compound quickly when you are trying to characterise something to within a degree or two.
The cascade PID approach was new to me going in. Getting the two loops to play together without fighting each other took several iterations, and I am glad I did it. A single-loop controller would have worked, but the cascade version is noticeably more stable and the inner loop dynamics are visible and tunable separately, which matters when you are iterating on the hardware.
TODO: add image at public/projects/heater-plate/schematic.png (schematic of PT100 sensing and heater driver circuit)
TODO: add image at public/projects/heater-plate/data-plot.png (Python-generated temperature vs. time plot showing setpoint tracking)
TODO: add image at public/projects/heater-plate/bench.jpg (photo of the assembled test rig)