Skip to content

API Reference

Alex edited this page Aug 18, 2026 · 2 revisions

API Reference

setTunings()

auto PID::setTunings(
    const double Kp,
    const double Ki,
    const double Kd) -> void

Sets the proportional, integral, and derivative gains.

Proportional Gain Kp

The proportional term reacts to the current control error:

$e = setpoint - actual$

$P = K_p \cdot e$

Example:

Setpoint = 100
Actual   = 90
Error    = 10
Kp       = 5

P = 50

A larger Kp produces a stronger response to the current deviation from the setpoint.

Integral Gain Ki

The integral term reacts to an error that persists over time:

$I = K_i \int e(t),dt$

Its main purpose is to eliminate steady-state error.

Derivative Gain Kd

The derivative term reacts to the rate of change of the measured process value.

The implementation uses derivative-on-measurement instead of derivative-on-error. This avoids derivative kick when the setpoint changes and allows the controller to reduce the output while the process value is still approaching the setpoint.

Negative PID gains are clamped to 0.0.

Controller direction should be configured using setDirection().


reset()

auto PID::reset() -> void

Resets the internal dynamic state of the controller.

The configured PID gains and other settings are not changed.

The following internal states are reset:

mIntegral = 0.0;
mPrevActual = 0.0;
mDerivativeFiltered = 0.0;
mInitialized = false;

The internal timing reference is also restarted:

mLastComputeMs = millis();

The current output is preserved but clamped to the configured output limits:

mOut = clamp(mOut, mMin, mMax);

This avoids an unnecessary output jump simply because the controller state was reset.

Typical use cases include:

  • system startup
  • switching operating modes
  • restarting the control process
  • invalidating the previous derivative state
  • clearing the integral state

setLimits()

auto PID::setLimits(
    const double min,
    const double max) -> void

Defines the valid output range of the controller.

Example:

pid.setLimits(0.0, 100.0);

This can represent:

0 ... 100 %

Another example:

pid.setLimits(0.0, 1023.0);

can be used for a 10-bit internal control range.

If the calculated PID output exceeds the configured range, it is limited before being returned.

Invalid ranges are ignored:

if (max <= min)
    return;

If the current output is already outside the newly configured range, it is immediately clamped.


setSampletime()

auto PID::setSampletime(
    const uint32_t sampleTimeMs) -> void

Defines how often the PID controller is recalculated.

Example:

pid.setSampletime(100);

This corresponds to approximately:

10 calculations per second

Calling calc() more frequently is allowed. If the configured sample time has not elapsed, calc() simply returns the previous output.

A stable and known sample interval is important because both the integral and derivative calculations depend on elapsed time.

A value of 0 is rejected.


setDirection()

auto PID::setDirection(
    const Direction direction) -> void

Defines the direction of controller action.

Direction::DIRECT

Use DIRECT when the output must increase if the actual value is below the setpoint.

Typical example:

Heating system

Actual temperature below setpoint
        ->
Increase heater output

Example:

pid.setDirection(PID::Direction::DIRECT);

Direction::REVERSE

Use REVERSE when the output must increase if the actual value is above the setpoint.

Typical example:

Cooling system

Actual temperature above setpoint
        ->
Increase cooling output

Example:

pid.setDirection(PID::Direction::REVERSE);

Internally, direction is represented by a multiplier:

const double direction =
    (mDirection == Direction::DIRECT)
    ? 1.0
    : -1.0;

This keeps the remaining PID equations consistent.


setTolerance()

auto PID::setTolerance(
    const uint8_t percentage) -> void

Defines a percentage-based tolerance band around the setpoint.

Inside this band, the integral term is frozen.

The proportional and derivative terms remain active.

Example:

pid.setTolerance(2);

With:

Setpoint = 100

the tolerance band is:

98 ... 102

The controller does not stop controlling inside this band.

Only the integral accumulation is paused.

This prevents the integral term from continuously reacting to very small errors near the setpoint.


setIntegralActivationRange()

auto PID::setIntegralActivationRange(
    const double range) -> void

Defines how close the process value must be to the setpoint before the integral term is allowed to operate.

Example:

pid.setIntegralActivationRange(10.0);

With:

Setpoint = 100

the integral term may operate only while the actual value is inside:

90 ... 110

This is particularly useful for slow or thermal systems.

Without this restriction, a large error over a long period can build a very large integral term.

Example:

Setpoint = 100
Actual   = 20

If integration is active during the entire approach to the setpoint, the integral term may become very large before the actual value reaches the target.

When the setpoint is finally reached, the proportional term may already be near zero while the integral term still commands a high output.

This is a common cause of overshoot.

Setting the activation range to 0.0 disables this restriction.


setDerivativeFilter()

auto PID::setDerivativeFilter(
    const double tauSeconds) -> void

Configures the low-pass filter applied to the derivative term.

Derivative action is sensitive to measurement noise because even small fluctuations in the measured value can produce large changes in the calculated derivative.

The controller therefore uses a first-order low-pass filter:

$\alpha = \frac{dt}{\tau + dt}$

and

$D_{filtered} = D_{filtered,old} + \alpha ( D_{raw} - D_{filtered,old} )$

Example:

pid.setDerivativeFilter(0.5);

This configures a filter time constant of approximately:

500 ms

Typical qualitative behavior:

0.2 s   -> light filtering
0.5 s   -> moderate filtering
1.0 s   -> strong filtering
2.0 s   -> very strong / slow filtering

Setting the filter time constant to 0.0 disables derivative filtering.


setOutputSlewRate()

auto PID::setOutputSlewRate(
    const double unitsPerSecond) -> void

Limits how quickly the controller output may change.

Example:

pid.setOutputSlewRate(100.0);

This means:

Maximum output change = 100 units per second

With a sample time of:

100 ms

the maximum change per PID update becomes:

100 * 0.1 = 10 units

If the previous output is:

200

and the PID calculation suddenly requests:

700

the output will not immediately jump to 700.

Instead, it will increase gradually:

200
210
220
230
...

This reduces aggressive actuator behavior and makes the control output smoother.

Set the slew rate to 0.0 to disable the limiter.


getOutput()

auto getOutput() const -> double

Returns the most recently calculated controller output.

Example:

double currentOutput = pid.getOutput();

This function does not trigger a new PID calculation.

The const qualifier guarantees that the function does not modify the PID object.


clamp()

static auto clamp(
    double value,
    double min,
    double max) -> double

Internal helper function used to restrict a value to a defined range.

Examples:

clamp(120.0, 0.0, 100.0);  // 100
clamp(-20.0, 0.0, 100.0);  // 0
clamp(53.0, 0.0, 100.0);   // 53

It is declared static because it does not require access to any PID object state.


calc()

auto PID::calc(
    const double setpoint,
    const double actual) -> double

Performs the actual PID calculation.

Parameters:

Parameter Description
setpoint Desired process value
actual Current measured process value

Return value:

Current controller output

The function contains the complete control algorithm.


Clone this wiki locally