Just to put this out there, PID isn’t the magical fix everyone raises it up to be
It’s just a nice tool that helps you get better results more consistently
People make it out to be like the difference between eyeballing a distance and using a laser distance finder when it’s probably just closer to the difference of eyeballing it and using a tape measure
The crude definition is, “Go fast when you’re far away from the target and slow as you approach” but that’s not quite all there is to it
typedef struct { // init a reusable list of variables
float current;
float kP;
float kI;
float kD;
float target;
float error;
float integral;
float derivative;
float lastError;
float threshold;
int lastTime;
} pid;
pid sPID; // init struct "PID" with the prefix "sPID"
// Cookie-Cutter PID loop for intelligently reaching a desired destination.
int iPID( int iDes , int iSensorInput, const float kP, const float kI, const float kD, const float kILimit) {
sPID.current = iSensorInput;
sPID.error = iDes - sPID.current;
sPID.integral;
if( kI != 0 ) // integral - if Ki is not 0
{ // If we are inside controllable window then integrate the error
if( abs(sPID.error) < kILimit )
sPID.integral = sPID.integral + sPID.error;
else
sPID.integral = 0;
}
else // Otherwise set integral to 0
sPID.integral = 0;
sPID.derivative = sPID.error - sPID.lastError; // Calculate Derivative
wait1Msec(5);
sPID.lastError = sPID.error;
return ( (sPID.error * kP) + (sPID.integral * kI) + (sPID.derivative * kD) );
}
Since I have yet to find a post that straight up displays a good, functioning PID loop that doesn’t get unnecessarily long winded on how to use it, here’s the basics:
kP does most of the work but using it alone can cause your robot to fall a little short
kI gets rid of undershoot but can quickly spiral out of control and cause overshoot if not used carefully ( as you can see there’s a specific case for just not using integral and it’s because of this)
kD is your dampener that makes motions when you’re close to the target less jerky
beware though, setting the control constants (kP, kI, and kD) too high or to the wrong settings can cause unwanted and painful to watch sights
generally all of them should be less than 1, but here’s a general rulesheet:
- kP should NEVER go above 1
- If kI is above 0 and you’re having overshoot/oscilation issues, just don’t use kI
- kD should never exceed .05 UNLESS you’re using PID for fully controlling an arm (AKA not as a brake) in which case your cap should be .15
- if to make something work you have to set any of these constants to something outside of these bounds you likely have a problem that’s not coding related because a lot of people will tell you that these bounds are all waaaay too large for PID constants
so, break a leg
[EDIT 1]
something i should probably mention is that I use this loop in RobotC, so I don’t know if it’ll work or no in PROS though I don’t see why it shouldn’t with how its made beyond replacing wait1Msec with taskDelay