Skip to content

A robust Arduino library for PID-based throttle control using PID_v1 library with filtering, smoothing, and failsafes.

Notifications You must be signed in to change notification settings

lily-osp/AutoThrottleNG

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

AutoThrottleNG Library

Overview

AutoThrottleNG is a robust and feature-rich Arduino library designed for creating sophisticated, failsafe throttle or output control systems. It builds upon the standard Arduino PID library to provide precise regulation, enhanced with input filtering, output smoothing, and multiple layers of safety checks.

This library is ideal for applications where smooth, stable, and reliable control of motors, actuators, or other output devices is critical, such as:

  • Robotics (e.g., wheel speed control, arm joints)
  • Drones and UAVs (e.g., altitude hold, motor speed regulation)
  • Automated Vehicles (e.g., cruise control, steering)
  • Process Control (e.g., temperature regulation, flow control)
  • Any system requiring closed-loop control with added safety and refinement.

AutoThrottleNG manages the complexities of filtering noisy sensor data, preventing abrupt output changes, monitoring system stability, and handling common failure scenarios, allowing you to focus on the higher-level logic of your application.


Core Concepts

AutoThrottleNG integrates several key control and signal processing techniques:

  1. PID Control (Proportional-Integral-Derivative)

    • The library uses the standard Arduino PID library (requiring PID.h) as its core control algorithm.

    • It continuously calculates an error value (e(t)) as the difference between the desired Setpoint and the current (filtered) Input.

    • It computes an Output value aiming to minimize this error over time.

    • Formula: The discrete PID algorithm can be represented as:

      Error[t] = Setpoint - Input[t]
      
      P = Kp * Error[t]
      I = I[t-1] + Ki * Error[t] * Δt
      D = Kd * (Error[t] - Error[t-1]) / Δt
      
      Output[t] = P + I + D
      

      Where:

      • Kp: Proportional Gain (reacts to current error)
      • Ki: Integral Gain (accumulates past errors to eliminate steady-state offset)
      • Kd: Derivative Gain (reacts to the rate of change of the error, dampens oscillations)
      • Δt: Time interval between calculations (Sample Time)
    • Proportional on Measurement (P_ON_M): The underlying PID library also supports P_ON_M, where the proportional term is calculated based on the change in input rather than the change in error. This can reduce "derivative kick" when the setpoint changes suddenly. AutoThrottleNG allows configuring this via the constructor or setTunings.

  2. Input Filtering (Exponential Moving Average - EMA)

    • Purpose: Sensor readings are often noisy. EMA filtering smooths the raw input signal before it's fed to the PID controller, leading to more stable control and preventing the derivative term (Kd) from overreacting to noise.

    • Formula:

      FilteredValue[t] = α * RawValue[t] + (1 - α) * FilteredValue[t-1]
      

      Where:

      • α (alpha) is the smoothing factor (0.0 to 1.0), configured via setInputFilterAlpha().
      • α = 0.0: No filtering (FilteredValue = PreviousFilteredValue) - Note: Library uses 0 to mean pass-through raw value.
      • α ≈ 1.0: Minimal filtering (FilteredValue ≈ RawValue)
      • Smaller α: More smoothing, but introduces more lag (delay) in the filtered signal's response to changes.
      • α = 0.0 is treated as "filter disabled" by the library.
    • Trade-off: Increased smoothing (lower α) reduces noise sensitivity but makes the system slower to respond to genuine changes in the input.

  3. Output Smoothing (Ramp Rate Limiting)

    • Purpose: Prevents the final throttle/output value from changing too abruptly, even if the PID controller calculates a large change. This is crucial for systems sensitive to sudden acceleration/deceleration (e.g., preventing jerky movements, mechanical stress, current spikes).
    • Mechanism: The library limits the maximum rate of change of the final output value per second.
    • Logic:
      1. Calculate the time elapsed (Δt) since the last compute() call.
      2. Calculate the maximum allowable change for this interval: MaxChange = MaxRatePerSecond * Δt / 1000.0
      3. Compare the raw PID output (TargetOutput) to the previous smoothed output (SmoothedOutput[t-1]).
      4. Limit the new smoothed output: SmoothedOutput[t] = constrain(TargetOutput, SmoothedOutput[t-1] - MaxChange, SmoothedOutput[t-1] + MaxChange)
    • Configuration: Enabled via enableSmoothing(true, maxRatePerSecond).
    • Trade-off: Increased smoothing (lower maxRatePerSecond) results in smoother transitions but limits how quickly the system can respond to requests for large output changes.

Key Features

  • Standard PID Integration: Leverages the well-established Arduino PID library (PID.h) for core control logic.
  • Input Filtering: Built-in optional Exponential Moving Average (EMA) filter to smooth noisy sensor inputs before they reach the PID.
  • Output Smoothing: Optional time-based ramp rate limiting on the final output to prevent sudden jumps or jerky behavior.
  • Failsafe Mechanisms:
    • Input Validity: Rejects NaN or Infinity sensor readings.
    • Input Timeout: Triggers an error if updateInput() isn't called within a configurable duration.
    • Stability Timeout: Triggers an error if the system's error (|Setpoint - FilteredInput|) remains larger than a tolerance for a configurable duration.
    • Configurable Failsafe Output: Sets a predefined, safe output value when any error state is active.
    • Clear Error Reporting: Provides methods to check the current error state.
    • Manual Error Reset: Requires user code intervention (clearErrorState()) to resume normal operation after a failsafe.
  • Status Monitoring: Provides getters for raw input, filtered input, raw PID output, smoothed throttle output, PID gains, mode, setpoint, error state, stability status, output saturation, and last update time.
  • Flexible Configuration: Allows runtime adjustment of PID tunings, output limits, sample time, controller direction, filter parameters, smoothing parameters, and failsafe settings.
  • Robust Design: Includes checks and constraints to handle edge cases and invalid configurations.

Dependencies

  • Arduino PID Library: Requires the standard "PID" library by Brett Beauregard (often referred to as PID v1) to be installed in your Arduino IDE. This library provides PID.h. Install it via the Arduino Library Manager (Search for "PID").

Installation

  1. Install PID Library: If not already installed, open the Arduino IDE, go to Tools -> Manage Libraries..., search for "PID" by Brett Beauregard, and click Install.
  2. Download AutoThrottleNG: Download the AutoThrottleNG library files (e.g., as a ZIP from GitHub).
  3. Install AutoThrottleNG: In the Arduino IDE, go to Sketch -> Include Library -> Add .ZIP Library... and select the downloaded ZIP file.
  4. Restart IDE: It's often good practice to restart the Arduino IDE after installing new libraries.
  5. Examples: Check File -> Examples -> AutoThrottleNG for example sketches.

API Documentation

Constructor

AutoThrottleNG(double minOutput, double maxOutput,
               double kp, double ki, double kd,
               int POn = P_ON_E, int direction = DIRECT);
  • Initializes the AutoThrottleNG controller.
  • Parameters:
    • minOutput (double): The minimum value the PID controller's output (_pidOutput) and the final throttle (getThrottle()) can have.
    • maxOutput (double): The maximum value the PID controller's output and final throttle can have.
    • kp (double): Initial Proportional tuning gain.
    • ki (double): Initial Integral tuning gain.
    • kd (double): Initial Derivative tuning gain.
    • POn (int): Proportional calculation mode. Use P_ON_E (Proportional on Error, default) or P_ON_M (Proportional on Measurement). These constants are typically defined by the underlying PID.h.
    • direction (int): Controller direction. Use DIRECT (increase output to increase input, default) or REVERSE (increase output to decrease input). Constants defined by PID.h.

Core Runtime Methods

void setTarget(double target);
  • Sets the desired target value (setpoint) for the PID controller.
  • NaN or Infinity values are ignored.
  • Parameters:
    • target (double): The target value the controller should aim for, in the same units as the input signal.
void updateInput(double rawInputValue);
  • Provides the latest raw sensor reading to the controller.
  • This value is filtered (if enabled) before being used by the PID.
  • Must be called regularly and more frequently than the configured Input Timeout.
  • NaN or Infinity values are rejected, and the INPUT_INVALID error state is set.
  • Parameters:
    • rawInputValue (double): The latest raw reading from the sensor.
double compute();
  • The main workhorse method. Call this in every iteration of your loop().
  • Checks for failsafe conditions (timeouts).
  • If no failsafe is active, it triggers the internal _pid.Compute() method (which uses the filtered input and setpoint).
  • Applies output smoothing (if enabled) to the raw PID output.
  • Clamps the final output to the defined limits.
  • Handles setting the failsafe output value if an error state is active.
  • Returns:
    • (double): The final, calculated throttle value (smoothed or failsafe value), constrained within minOutputLimit and maxOutputLimit.
void reset();
  • Resets the internal state of the PID controller (typically clears the integral sum by cycling the mode) and resets AutoThrottleNG's failsafe timers and error state.
  • Does NOT reset: PID gains (Kp, Ki, Kd), output limits, setpoint, filter settings, smoothing settings, or failsafe configuration values. Call setTarget() again after reset() if needed.

PID Configuration

void setTunings(double kp, double ki, double kd, int POn = -1);
  • Sets the PID gains and optionally the Proportional mode.
  • Parameters:
    • kp, ki, kd (double): New tuning gains.
    • POn (int): Optional. Set to P_ON_E or P_ON_M to change mode, or leave as -1 (or omit) to keep the current Proportional mode.
void setOutputLimits(double minOutput, double maxOutput);
  • Sets the minimum and maximum allowed values for the raw PID output and the final smoothed throttle. Clamps the current output and failsafe value if necessary.
  • Parameters:
    • minOutput, maxOutput (double): New lower and upper output bounds. minOutput must be less than maxOutput.
void setControllerDirection(int direction);
  • Sets the controller direction.
  • Parameters:
    • direction (int): DIRECT or REVERSE.
void setSampleTime(int sampleTimeMillis);
  • Sets how often (in milliseconds) the PID algorithm attempts to calculate a new output.
  • Parameters:
    • sampleTimeMillis (int): The desired interval > 0.
void setMode(int mode);
  • Sets the PID operating mode. An active failsafe will override this and force MANUAL.
  • Parameters:
    • mode (int): AUTOMATIC (PID enabled) or MANUAL (PID calculations disabled, output holds).

Filtering Configuration

void setInputFilterAlpha(double alpha);
  • Configures the Exponential Moving Average (EMA) input filter.
  • Parameters:
    • alpha (double): Smoothing factor, clamped between 0.0 and 1.0.
      • 0.0: Filter disabled (raw input used directly).
      • Values closer to 0.0: More smoothing, more lag.
      • Values closer to 1.0: Less smoothing, less lag.

Smoothing Configuration

void enableSmoothing(bool enable, double maxRatePerSecond = 10.0);
  • Enables or disables time-based ramp rate limiting on the final output.
  • Parameters:
    • enable (bool): true to enable, false to disable.
    • maxRatePerSecond (double): The maximum allowed change in output units per second when smoothing is enabled. Must be > 0. Default: 10.0.

Failsafe Configuration

void setFailsafeValue(double value);
  • Sets the output value that getThrottle() will return when any failsafe condition is active. The value is constrained by the output limits.
  • Parameters:
    • value (double): The desired failsafe output value.
void setInputTimeout(unsigned long durationMillis);
  • Sets the maximum allowed time (in milliseconds) between successful calls to updateInput(). If this time is exceeded, the INPUT_TIMEOUT error state is triggered.
  • Parameters:
    • durationMillis (unsigned long): Timeout duration in ms. Set to 0 to disable this check.
void setStabilityParams(double tolerance, unsigned long durationMillis);
  • Configures the stability check failsafe.
  • Parameters:
    • tolerance (double): The maximum absolute difference allowed between the setpoint (_pidSetpoint) and the filtered input (_pidInput) for the system to be considered stable. Must be >= 0.
    • durationMillis (unsigned long): The maximum time (in ms) the system's error can continuously exceed the tolerance before the STABILITY_TIMEOUT error state is triggered. Set to 0 to disable this check.

Status & Debugging Methods

double getThrottle() const;
  • Returns the final calculated throttle output value after PID computation, smoothing (if enabled), and failsafe checks. This is the value you should apply to your actuator.
double getRawPIDOutput() const;
  • Returns the raw output value calculated by the internal _pid.Compute() method, before output smoothing is applied. Useful for debugging PID behavior.
double getFilteredInput() const;
  • Returns the input value after the EMA filter has been applied. This is the value actually used by the PID algorithm.
double getRawInput() const;
  • Returns the last valid raw input value provided via updateInput(), before filtering.
bool isStable() const;
  • Checks if the current absolute difference between the setpoint and the filtered input is within the configured stabilityToleranceValue. Note that this is an instantaneous check and doesn't relate directly to the STABILITY_TIMEOUT error state, which requires the condition to persist.
double getKp() const;
double getKi() const;
double getKd() const;
  • Return the current Proportional, Integral, or Derivative gain being used by the PID controller.
int getMode() const;
  • Returns the current operating mode of the PID controller (AUTOMATIC or MANUAL).
double getSetpoint() const;
  • Returns the current target setpoint value stored within AutoThrottleNG.
bool isSaturated() const;
  • Returns true if the last raw PID output (_pidOutput) was at the minimum or maximum output limit, false otherwise. Indicates the PID is trying to command an output beyond its limits.
unsigned long getLastUpdateTime() const;
  • Returns the millis() timestamp of when updateInput() was last called with a valid (non-NaN, non-Inf) value. Useful for debugging input timeout issues.

Error Handling (Failsafe Status)

AutoThrottleNG::Error getErrorState() const;
  • Returns the current failsafe error state.
  • Return Values (enum AutoThrottleNG::Error):
    • NONE: No error active.
    • INPUT_INVALID: Last call to updateInput() received NaN or Infinity.
    • INPUT_TIMEOUT: updateInput() hasn't been called within the configured timeout.
    • STABILITY_TIMEOUT: System error has exceeded tolerance for too long.
bool isInErrorState() const;
  • Returns true if getErrorState() is anything other than Error::NONE, false otherwise. Convenient check before taking failsafe actions.
void clearErrorState();
  • Manually resets the error state back to Error::NONE.
  • Crucially, you MUST call this function in your code once the condition causing the failsafe has been resolved (or is assumed resolved) to allow the controller to resume AUTOMATIC operation. The library will not automatically clear most error states.

Control Flow Diagram (Conceptual)

  +-------------------+      +-----------------+      +---------------------+      +------------------+
  | Raw Sensor Signal | ---> | updateInput()   | ---> | Input Filter (EMA)  | ---> | Filtered Input   | ----+
  +-------------------+      | (Validity Check)|      | (if alpha > 0)    |      | (_pidInput)      |     |
                             +-----------------+      +---------------------+      +------------------+     |
                                                                                                           | V
                               +-------------------+   +-------------------+     +---------------------+    | [PID]
                               | setTarget()       |-->| Target Setpoint   | --> | PID Algorithm       | <--+
                               +-------------------+   | (_pidSetpoint)    |     | (_pid.Compute())    |
                                                       +-------------------+     +-------+-------------+
                                                                                       | Output
                                                                                       V (_pidOutput)
+-------------------+      +--------------------+      +---------------------+      +------------------+
| Final Throttle    | <--- | Output Smoothing   | <--- | Raw PID Output      | <--- | (Check Output    |
| Value             |      | (Ramp Limit)       |      |                     |      |  Saturation)     |
| (to Actuator)     |      | (if enabled)       |      |                     |      +------------------+
+-------------------+      +-----+--------------+      +---------------------+
                              ^
                              | [Failsafe Override]
                              |
+-------------------+ <-------+
| Failsafe Value    |
| (if Error State!) |
+-------------------+

* Failsafe Checks (Timeouts) occur within compute() before PID calculation.
* If Error State is active, PID is bypassed, and Failsafe Value is used (potentially smoothed).

Notes on Usage

  • PID Tuning is Crucial: You must tune the Kp, Ki, and Kd values for your specific system. Start with Kp and gradually add Ki and Kd. Use methods like Ziegler-Nichols or trial-and-error. Monitor the getRawPIDOutput() and getFilteredInput() to understand behavior.
  • Input Filtering: Use setInputFilterAlpha() to reduce noise. Start with a small value (e.g., 0.1-0.3) if noise is significant. Be aware this adds lag. If your sensor is clean, leave alpha at 0.0 (disabled).
  • Output Smoothing: Use enableSmoothing() if you need smooth output transitions. Adjust the maxRatePerSecond based on your system's requirements – lower values give more smoothing but limit responsiveness.
  • Failsafes:
    • Configure timeouts (setInputTimeout, setStabilityParams) appropriate for your system's response time and sensor update rate. Don't set them too short or too long.
    • Set a safe failsafeValue (e.g., 0% throttle, hover throttle).
    • Your main loop must check isInErrorState() and potentially take further action (e.g., disarm, alert).
    • You must call clearErrorState() to recover from a failsafe once the underlying issue is resolved.
  • compute() Frequency: Call compute() in every loop() iteration for consistent timing and responsiveness of smoothing and PID calculations (the internal PID library manages its own sample time).
  • updateInput() Frequency: Call updateInput() as often as you get new sensor readings, and definitely faster than the configured inputTimeoutMillis.
  • Units: Ensure consistency! The units for setTarget, updateInput, and stabilityTolerance must all match. The output units will be defined by minOutput/maxOutput.
  • Constants: Verify the exact names/values of DIRECT, REVERSE, AUTOMATIC, MANUAL, P_ON_E, P_ON_M as defined in the PID.h file included with your Arduino core or the installed PID library.

Contributing

Contributions are welcome! Please follow standard GitHub practices:

  1. Fork the repository.
  2. Create a new branch for your feature or fix.
  3. Commit your changes with clear messages.
  4. Push your branch and submit a Pull Request.
  5. Provide a detailed description of your changes in the PR.

License

This library is released under the MIT License. See the LICENSE file for details.


About

A robust Arduino library for PID-based throttle control using PID_v1 library with filtering, smoothing, and failsafes.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages