Open Source · ESP32 · PID · PSM

Project Features

A dual closed-loop control system for espresso machines: Pressure loop (PID + Phase-Skip Modulation) and Temperature loop (PID + MCPWM), paired with an OLED menu and real-time sensor smoothing.

Overview

Espresso Controller stabilizes brew pressure and water temperature using two independent PID loops. The system reads a 0.5–4.5V pressure transducer via ADC averaging and a MAX6675 thermocouple for temperature, then modulates power through PSM (phase-skip with zero-cross detection) and MCPWM (heater duty control).

Highlights

Dual-Loop Control

Independent PID loops for pressure (PSM) and temperature (MCPWM) to ensure consistent extraction.

Real-Time Sensors

ADC-averaged pressure readings with MPa/psi conversion; MAX6675 thermocouple for boiler temp.

OLED Menu UX

Rotary encoder + push button navigation, target setpoints, brew animation, and countdown.

Power Safety

Zero-cross triac control (PSM) and clamped PID outputs; debounced interrupts for stability.

Live Demo Web Dashboard

Two-function API (init(), update()) renders real-time charts on GitHub Pages.

Ready to Extend

Pluggable pins via pins.h; future Wi-Fi dashboard, data logging, and profiling.

Pressure Control (PID + PSM)

The pressure loop reads the transducer, applies averaging to reduce noise, converts to psi, and feeds the PID controller. The PID output (0–100%) is mapped to PSM levels (0–127) to modulate AC power via zero-cross detection.

// Minimal usage example
pressureCtl.setSetpoint(9.0);            // target = 9 bar
pressureCtl.setCurrentPressure(psiReading);
pressureCtl.update();                     // runs PID and updates PSM

Tip: keep the ISR tiny (zero-cross flag only) and compute in the main loop for stability.

Temperature Control (PID + MCPWM)

The temperature loop reads MAX6675, drives ESP32 MCPWM to control heater duty cycle, and maintains a stable brew temperature.

// Minimal usage example
tempControl::setSetpoint(93.0);          // 93 °C
tempControl::setCurrentTemp(currentC);
tempControl::update();                    // PID compute + MCPWM duty update

OLED User Interface

The OLED (Adafruit SH1106) shows live pressure/temperature, setpoints, and a brewing animation. A rotary encoder provides intuitive navigation; short press to select, rotate to adjust.

OLED main status screen
Main status: live Temp/PSI and setpoints
OLED mode menu
Mode menu: navigate with rotary encoder
OLED settings screen
Settings: adjust targets on device

Live Demo Web Dashboard

For the capstone demo, we provide a lightweight browser dashboard (GitHub Pages) to visualize telemetry in real time. The page exposes exactly two global functions for the firmware or a small host script to call: init() and update(tempC, psi, tempSetpointC, psiSetpoint). No extra dependencies or build steps.

Live dashboard with sensor table and temperature chart
Live Dashboard: current values, setpoints, and real-time chart.

API

  • init() — call once on start (e.g., in setup()).
  • update(tempC, psi, tempSetpointC, psiSetpoint) — call periodically (e.g., every 100–250 ms).

Units: tempC/tempSetpointC in °C, psi/psiSetpoint in psi.

// Pseudocode (firmware/host bridge)
  void setup() {
    // ...
    dashboard.init();          // maps to page's init()
  }
  
  void loop() {
    // read sensors + setpoints ...
    dashboard.update(tempC, psi, targetC, targetPsi);
    delay(150);                // update rate for smooth charting
  }

Styling (colors, layout, images) is easily customizable if we want a different look for the poster/demo.

Why this helps the demo
  • Zero friction: open the page and call the two functions — no local setup.
  • Clear storytelling: side-by-side table + chart shows control loops reacting to setpoints.
  • Flexible I/O: can be driven by serial bridge, WebSerial, WebSocket, or offline replay.

Planned & Future

Quick Links