Giter VIP home page Giter VIP logo

fastpid's Introduction

FastPID

A fast 32-bit fixed-point PID controller for Arduino

About

This PID controller is faster than alternatives for Arduino becuase it avoids expensive floating point operations. The PID controller is configured with floating point coefficients and translates them to fixed point internally. This imposes limitations on the domain of the coefficients. Setting the I and D terms to zero makes the controller run faster. The controller is configured to run at a fixed frequency and calling code is responsible for running at that frequency. The Ki and Kd parameters are scaled by the frequency to save time during the step() operation.

Description of Coefficients

  • Kp - P term of the PID controller.
  • Ki - I term of the PID controller.
  • Kd - D term of the PID controller.
  • Hz - The execution frequency of the controller.

Coefficient Domain

The computation pipeline expects 16 bit coefficients. This is controlled by PARAM_BITS and should not be changed or caluclations may overflow. The number of bits before and after the decimal place is controlled by PARAM_SHIFT in FastPID.h. The default value for PARAM_SHIFT is 8 and can be changed to suit your application.

  • The parameter P domain is [0.00390625 to 255] inclusive.
  • The parameter I domain is P / Hz
  • The parameter D domain is P * Hz

The controller checks for parameter domain violations and won't operate if a coefficient is outside of the range. All of the configuration operations return bool to alert the user of an error. The err() function checks the error condition. Errors can be cleared with the clear() function.

Execution Frequency

The execution frequency is not automatically detected as of version v1.1.0 This greatly improves the controller performance. Instead the Ki and Kd terms are scaled in the configuration step. It's essential to call step() at the rate that you specify.

Input and Output

The input and the setpoint are an int16_t this matches the width of Analog pins and accomodate negative readings and setpoints. The output of the PID is an int16_t. The actual bit-width and signedness of the output can be configured.

  • bits - The output width will be limited to values inside of this bit range. Valid values are 1 through 16
  • sign If true the output range is [-2^(bits-1), -2^(bits-1)-1]. If false output range is [0, 2^(bits-1)-1]. The maximum output value of the controller is 32767 (even in 16 bit unsigned mode)

Performance

FastPID performance varies depending on the coefficients. When a coefficient is zero less calculation is done. The controller was benchmarked using an Arduino UNO and the code below.

Kp Ki Kd Step Time (uS)
0.1 0.5 0.1 ~64
0.1 0.5 0 ~56
0.1 0 0 ~28

For comparison the excellent ArduinoPID library takes an average of about 90-100 uS per step with all non-zero coefficients.

API

The API strives to be simple and clear. I won't implment functions in the controller that would be better implemented outside of the controller.

FastPID()

Construct a default controller. The default coefficients are all zero. Do not use a default-constructed controller until after you've called setCoefficients() and setOutputconfig()

FastPID(float kp, float ki, float kd, float hz, int bits=16, bool sign=false)

Construct a controller that's ready to go. Calls the following:

configure(kp, ki, kd, hz, bits, sign);
bool setCoefficients(float kp, float ki, float kd, float hz);

Set the PID coefficients. The coefficients ki and kd are scaled by the value of hz. The hz value informs the PID of the rate you will call step(). Calling code is responsible for calling step() at the rate in hz. Returns false if a configuration error has occured. Which could be from a previous call.

bool setOutputConfig(int bits, bool sign);

Set the ouptut configuration by bits/sign. The ouput range will be:

For signed equal to true

  • 2^(n-1) - 1 down to -2^(n-1)

For signed equal to false

  • 2^n-1 down to 0

Bits equals 16 is a special case. When bits is 16 and sign is false the output range is

  • 32767 down to 0

Returns false if a configuration error has occured. Which could be from a previous call.

bool setOutputRange(int16_t min, int16_t max);

Set the ouptut range directly. The effective range is:

  • Min: -32768 to 32766
  • Max: -32767 to 32767

Min must be greater than max.

Returns false if a configuration error has occured. Which could be from a previous call.

void clear();

Reset the controller. This should be done before changing the configuration in any way.

bool configure(float kp, float ki, float kd, float hz, int bits=16, bool sign=false);

Bulk configure the controller. Equivalent to:

clear();
setCoefficients(kp, ki, kd, hz);
setOutputConfig(bits, sign);
int16_t step(int16_t sp, int16_t fb);

Run a single step of the controller and return the next output.

bool err();

Test for a confiuration error. The controller will not run if this function returns true.

Integeral Windup

Applications that control slow moving systems and have a non-zero integral term often see significant overshoot on startup. This is caused by the integral sum "winidng up" as it remembers a long time away from the setpoint. If this describes your system there are two things you can do.

Addressing Windup: Limit the Sum

There are constants in FastPID.h that control the maximum allowable integral. Lowering these prevents the controller from remembering as much offset from the setpoint and will reduce the overshoot.

#define INTEG_MAX    (INT32_MAX)
#define INTEG_MIN    (INT32_MIN)

Change these constants with caution. Setting them too low will fix your overshoot problem but it will negatively affect the controller's ability to regulate the load. If you're unsure of the right constant use the next solution instead of limiting the sum.

Limiting Windup: Bounded Regulation

The PID controller works best when the system is close to the setpoint. During the startup phase, or in the case of a significant excursion, you can disable PID control entirely. An example of this can be found in the Sous-Vide controller example in this project. The core of the logic is in this code:

if (feedback < (setpoint * 0.9)) {
  analogWrite(PIN_OUTPUT, 1);
  myPID.clear();
}
else {
  analogWrite(PIN_OUTPUT, myPID.step(setpoint, feedback));
}

The code bypasses the PID when the temperature is less than 90% of the setpoint, simply turning the heater on. When the temperature is above 90% of the setpoint the PID is enabled. Fixing your overshoot this way gives you much better control of your system without having to add complex, invalid and difficult to understand features to the PID controller.

Sample Code

#include <FastPID.h>

#define PIN_INPUT     A0
#define PIN_SETPOINT  A1
#define PIN_OUTPUT    9

float Kp=0.1, Ki=0.5, Kd=0.1, Hz=10;
int output_bits = 8;
bool output_signed = false;

FastPID myPID(Kp, Ki, Kd, Hz, output_bits, output_signed);

void setup()
{
  Serial.begin(9600);
  if (myPID.err()) {
    Serial.println("There is a configuration error!");
    for (;;) {}
  }
}

void loop()
{
  int setpoint = analogRead(PIN_SETPOINT) / 2; 
  int feedback = analogRead(PIN_INPUT);
  int ts = micros();
  uint8_t output = myPID.step(setpoint, feedback);
  int tss = micros();
  analogWrite(PIN_OUTPUT, output);
  Serial.print("(Fast) micros: "); 
  Serial.print(tss - ts);
  Serial.print(" sp: "); 
  Serial.print(setpoint); 
  Serial.print(" fb: "); 
  Serial.print(feedback);
  Serial.print(" out: ");
  Serial.println(output);
  delay(100);
}

fastpid's People

Contributors

aamott avatar adammck avatar mike-matera avatar per1234 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

fastpid's Issues

[Feature Request] Setting a maximum and minimum output

Hello!

Thanks for your excellent library, I'm using it to control a boost regulator, and I'd like to make a feature request - The PWM to the FET needs to be constrained between 30 and 180, and doing so without your library being "aware" causes it to seemingly rise above 180 internally. This means when the feedback drops below the setpoint, the output takes a long time to drop back down from whatever it is internally to less than 180. Similarly to the upper end, the library takes a long time to begin increasing the output, since it has to go from 0-30 before anything appears to happen.

With a built-in constrain function, the values would be clamped internally so this wouldn't be a problem.

Thanks
-Elijah

Appying bit shift to possibly negative value.

In the step() function in the end there is:
// Remove the integer scaling factor.
int16_t rval = out >> PARAM_SHIFT;
out variable type here is: int64_t out
When applying shift to the negative integer, the sign bit gets shifted also and may mess up the result.
So when the limits are set to allow also for negative values, what happens? Or are only postitive values allowed, and I missed that? Seems to be no check done for that in the code to allow only positive values.

allow for fractional parameters

I'm not sure if this is an issue for your target application, but oftentimes a parameter value of 1 is just too big. older industrial pids (whose internals are all integer math) will often divide the parameter by a fixed value (and tell the user what that is). So it might be /10 for P and D, /100 for I. The user then enters a P of 50 if they want 5. This allows the user to have an effective P value of as low as 0.1, which can be helpful for aggressive processes.

[Feature Reques] Anti-windup

You enabled setting the max and min output - can you also clamp the integer term to a settable limit, not just the limit of the int32? This will enable better motor tuning.

Thanks!
Saul

Ported to C

I don't know if this is of interest to anyone, but I've ported this to straight C so that I can use it with avr-gcc rather than Arduino. You can find the fork at https://github.com/larsks/FastPID. Since there's nothing AVR-specific in the code, I've also added some simple unit tests that compile on the host.

I have not yet ported the example code: because the standard avr-libc environment has neither millis()/micros() nor any serial support I'll have to add in some additional code to make the examples work as intended.

The new unit tests are run by travis for pull requests and commits.

type conflict

In line 53 of FastPID.h the variable _p is defined as uint32_t.
In line 88 of FastPID.cpp "P = int32_t(_p) * int32_t(err);" is used as signed int.
This is should not be an issue but maybe the definition should be fixed.

fixed point

I'd like your thoughts on avoiding the use of floats altogether.
Patched FastPID so the library uses fixed-point integers instead of float.
You define a scale factor SCALE in FastPID.h.
Kp, Ki, Kd and hz are then fixed-point integers, witch scaling factor SCALE.
Use case is a small arm processor without FPU.
What is your opinion?

FastPID_patch.txt

Use FastPID for cooling?

Hi

I wonder how to use FastPID for cooling, i.e. you want the output to increase when the input increases? One way of doing it would be to use negative Kp,Ki and Kd. But the FastPID do not accept values below 0. By modifying the library I have done tests with negative values and works as intended, but I assume the check for negative values are there for a reason?

/Henrik

v1.3.2 not released to Arduino?

Hi!

Forgive my ignorance, but when I use the Arduino library manager (v1.8.13) I can only install FastPID up to v1.3.1.

You released v1.3.2 back in 2019.

How are your changes propagated to Arduino library manager?

Sous Vide example

Should the step() be called in a blink without delay type of conditional statement ensuring 10hz is achieved or is 200ms delay at end of loop sufficient?

how to use setoutput range?

Hi, newbie here.

How do i use the bool setOutputRange(int16_t min, int16_t max); command to set the range i cant figure it out. Thankyou :)

Hello my friend

Help with the FastPID library. When the feedback changes, the output changes between 0 and 1.

Update License

I have ported this to C.

I desire to add a MIT License on my forked repository: https://github.com/SRA-VJTI/FastPID

Since your License file is missing the copyright names and year, technically I can re license.

Can you please let me know if it is possible

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.