Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[Bug] Divide by zero in PressureController when pressure reaches 15 bar #534

@ncheung13579

Description

@ncheung13579

Brief summary of the bug

PressureController.cpp lines 244 and 251 divide by (1 - P / _maxPressure). When pressure reaches 15 bar, this evaluates to division by zero, producing infinity/NaN values that corrupt pump control output. Since the pressure sensor is mounted at the pump outlet, 15 bar is reachable during normal operation.

Describe the issue in greater detail

Found during code review of lib/NayrodPID/src/PressureController/PressureController.cpp.

Vulnerable code (lines 244 and 251):

// Line 244
float Ki = _integralGain / (1 - P / _maxPressure);

// Line 251
float K = _commutationGain / (1 - P / _maxPressure) * Qa / Ceq;

Where _maxPressure is defined (PressureController.h line 70):

const float _maxPressure = 15.0f;  // Maximum pressure (bar)

What happens when P = 15.0 bar:

1 - P / _maxPressure = 1 - 15.0/15.0 = 0.0

Ki = _integralGain / 0.0 = inf
K = _commutationGain / 0.0 * ... = inf

These infinity values propagate through the calculation:

// Line 252
_pumpDutyCycle = Ceq / Qa * (...) - iterm;  // iterm contains inf

The final clamp (line 263) produces unpredictable results:

  • std::clamp(inf, 0, 100) → 100 (pump full blast)
  • std::clamp(-inf, 0, 100) → 0 (pump stops)
  • std::clamp(nan, 0, 100) → undefined

Why 15 bar is reachable during normal operation:

The GaggiMate Pro uses a 0-1.6 MPa (16 bar) pressure transducer installed at the pump outlet, between the pump and the 3-way solenoid valve. This location sees full pump pressure, not post-OPV extraction pressure.

The Ulka vibration pump in a Gaggia Classic is rated for ~15 bar maximum output. At the pump outlet, 15 bar can be reached during:

  1. Pressure profile ramp-up — Aggressive profiles targeting 12-14 bar can overshoot or experience sensor noise that spikes to 15 bar
  2. Valve transitions — When the solenoid valve closes during a shot, the pump momentarily sees full back-pressure
  3. Preinfusion phases — Some profiles deliberately push high pressure before backing off
  4. Transient blockages — Brief flow restrictions cause pressure spikes

This is not an edge case requiring equipment failure — it's a boundary condition reachable during normal pressure profiling.

When pressure hits exactly 15 bar:

  1. Pump output becomes erratic — Jumps instantly to 100% or drops to 0%, disrupting the shot in progress
  2. Pressure profile fails mid-shot — A carefully tuned profile goes haywire at the worst possible moment
  3. Potential pressure spike — If pump goes to 100% while pressure is already at 15 bar, it's pushing maximum force into an already high-pressure system
  4. Confusing diagnostics — User sees pump misbehave and doesn't know if it's the puck, the profile, or the controller

Suggested fix:

float pressureRatio = P / _maxPressure;
float denominator = fmaxf(1.0f - pressureRatio, 0.01f);  // Clamp to minimum 0.01
float Ki = _integralGain / denominator;

Are you able to reproduce the issue?

No

Steps to reproduce

  1. Create a pressure profile that targets 12-14 bar
  2. Run the profile with a fine grind that creates high resistance
  3. Monitor for pressure spikes to 15 bar (sensor noise, overshoot, or valve transitions)
  4. Observe pump output becomes erratic when pressure hits exactly 15 bar

Expected behavior

When pressure approaches the maximum, the controller should gracefully limit its gain rather than producing infinity/NaN values. The pump output should remain stable and controlled.

Has this function/fetaure worked before with your GaggiMate?

No

Relevant logs or error messages

N/A — ESP32 float division by zero doesn't throw an exception. It silently returns inf/nan which propagates through calculations.

Firmware version

Code review performed on current master branch

What machine are you experiencing this issue on?

N/A — affects all GaggiMate Pro configurations using pressure profiling

Additional context

CWE-369 (Divide By Zero). The pressure sensor is mounted at the pump outlet per installation instructions, where it sees full pump pressure (up to 15 bar) rather than post-OPV extraction pressure. The gain scheduling formula 1/(1 - P/Pmax) is mathematically undefined at the boundary. This is a latent bug that will trigger whenever pressure reaches exactly 15 bar during normal pressure profiling operations.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions