Hey all,
After browsing through Brett Beauregard (Original author of PID_v1 library) blog, at brettbeauregard.com, I've seen on the comment some good ideas that never got implemented, so I decided I'll try to implement them.
The main improvement of v2 over v1 is the new library I wrote called PIDMaster which basically gathers together multiple instances of PID in order to run them simultaneously and efficiently using a single Timer interrupt (TimerOne) for making sure they all sample on time. The strategy of using interrupts over the use of just sampling around the sampling time (and not exactly on it) is most significantly showing better result when you have a lot of code in your loop() or when your sampling time is set to a low value.
Another small change from the original library is a different computation for the Anti Integral Wind-Up that was suggested in the blog's comments and received positive feedback from Brett but was never actually implemented.
GitHub source: GitHub - barzilaydn/Arduino-PID-Library
Basic Example:
/********************************************************
* Multiple PIDs with a PIDMaster
* Running multiple PID instances in parallel with Timer interrupts for better sampling.
********************************************************/
#include <TimerOne.h>
#include <PID_v2.h>
#include <PIDMaster.h>
//PID variables
volatile double Right_S, Right_I, Right_O;
volatile double Left_S, Left_I, Left_O;
volatile double Top_S, Top_I, Top_O;
//PID for each rotation type.
PID RightPID(&Right_I, &Right_O, &Right_S, 1.0, 2.0, 3.0, false, 10);
PID LeftPID (&Left_I , &Left_O , &Left_S , 2.0, 3.0, 4.0, false, 10);
PID TopPID (&Top_I , &Top_O , &Top_S , 3.0, 4.0, 5.0, false, 10);
PIDMaster masterPID (&RightPID, &LeftPID, &TopPID);
void setup()
{
// When using PIDMaster - Input, Output and Setpoint must be set and get using these setter / getter methods!
// But compatibility with PID_v1 code remains when not using the PIDMaster.
//initialize the variables we're linked to.
RightPID.SetInput(analogRead(0));
LeftPID.SetInput(analogRead(1));
TopPID.SetInput(analogRead(2));
RightPID.SetSetpoint(45);
LeftPID.SetSetpoint(15);
TopPID.SetSetpoint(0);
RightPID.SetOutputLimits(0,255);
LeftPID.SetOutputLimits(0,255);
TopPID.SetOutputLimits(0,255);
masterPID.Start(); //Starts the Timer which automatically handles all PID instances.
}
void loop()
{
RightPID.SetInput(analogRead(0));
LeftPID.SetInput(analogRead(1));
TopPID.SetInput(analogRead(2));
analogWrite(3, RightPID.GetOutput());
analogWrite(4, LeftPID.GetOutput());
analogWrite(5, TopPID.GetOutput());
}
I would love some feedback and will much appreciate people testing this out as I haven't tried it yet (still don't have the required hardware).
Feel free to ask any question and to suggest improvements.
Dan