https://github.com/auralius/yapid
Yet Another PID (YAPID) library for Arduino
https://github.com/auralius/yapid
arduino-library bilinear-transform control-systems digital-control digital-signal-processing low-pass-filter pid
Last synced: 13 days ago
JSON representation
Yet Another PID (YAPID) library for Arduino
- Host: GitHub
- URL: https://github.com/auralius/yapid
- Owner: auralius
- Created: 2025-01-05T11:32:07.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2026-03-25T14:45:55.000Z (3 months ago)
- Last Synced: 2026-03-26T17:22:29.435Z (3 months ago)
- Topics: arduino-library, bilinear-transform, control-systems, digital-control, digital-signal-processing, low-pass-filter, pid
- Language: C++
- Homepage: https://auralius.github.io/yapid/
- Size: 21.7 MB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Yet Another PID (YAPID) library for Arduino
Contact:
Auralius Manurung, Universitas Telkom,
Detailed documentations:
https://auralius.github.io/yapid/
---
In YAPID, the discrete implementations of both the control and the filter use bilinear transformation (Tustin or trapezoidal) method. **Check [this page](https://auralius.github.io/control-systems-with-sympy/digital-pid-2.html) for details on the control derivation.**
## Implemented functions:
* `float YAPID::Compute0(float set_value, float process_value)`
* This simply sends `set_value` as control output.
* There is no feedback control happening here.
* This function is useful to testing system's open-loop respose.
* `float YAPID::Compute1(float set_value, float process_value)`
* D-term is computed from the filtered errors.
* Derivative kicks will happen
* Simple integral windup prevention with clamping technique
* `float YAPID::Compute2(float set_value, float process_value)`
* D-term is computed from the filtered process values
* No more derivative kicks
* Simple integral windup prevention with clamping technique
* `float YAPID::FOLP(float tau, float in)`
* First-order low-pass filter (time-constant filter)
* `float YAPID::SOLP(float tau, float in)`
* Second-order low-pass filter (Butterworth filter)
## How to use the YAPID library
__Abbreviations__:
* ```sv```: set value
* ```pv```: process value
* ```co```: control output
* ```P```: P-term control output
* ```I```: I-term control output
* ```D```: D-term control output
* ```Kp```: proportinal gain
* ```Ki```: integral gian
* ```Kd```: derivative gain
* ```N```: derivative filter coefficient
__How to use__:
YAPID **DOES NOT** measure the elapsed time every iteration. It simply uses the provided sampling time during the setup. Therefore, to guarantee control determinism, it is easier if we use a timer interrupt handler to run the control periodically. All provided examples use timer interrupts.
To use YAPID library, first, we need to include the header file:
```cpp
#include "yapid.h"
```
Next, we create a global YAPID object and several global variables:
```cpp
// Create the PID controller
float kp = 100.; // kp
float ki = 10.0; // ki
float kd = 1.0; // kd
float N = 1.0; // derivative filter coefficient (Hz)
float Ts = 1e-3;
YAPID pid(Ts, kp, ki, kd, N);
```
Within the Arduino's ```setup()``` function, we define the limits for the control's output. The default limit is $0.0 \leq \text{CO} < 255.0$. Since we use a timer interrupt, we setup out timer interrupt also in this ```setup()``` function.
```cpp
#define TIMER2_INTERVAL_MS 1 // 1kHz
void setup()
{
// Setup the timer interrupt (we use NANO, timer-1, and
// https://github.com/khoih-prog/TimerInterrupt)
ITimer1.init();
ITimer1.attachInterruptInterval(TIMER1_INTERVAL_MS, Timer1Handler);
// Define the control output limits
// Here, the output becomes PWM signals (0 to 255)
pid.SetOutputLimits(0., 255)
// ...
// ...
}
```
Finally, in the timer interrupt function handler, we can put our PID control. The steps are:
* read the sensor (```pv```)
* compute the PID (```co```)
* apply the output to the actuator/plant
* measure the elapsed time
```cpp
void Timer1Handler()
{
float pv = (float)analogRead(A0) * 5.0 / 1024.0;
float co = pid.Compute1(SV, pv);
analogWrite(pwm_port, (int)co);
pid.UpdateTime();
}
```