Jared’s example shows how PID controller is generally used but there is more to it. First, I assume you are doing the normal left and right motor drive instead of the mecanum 4-wheel drive so you only have left and right encoders. The PIDController class in the WPI library is generic so it only understands one input variable (PIDGet) and one output variable (PIDWrite). The general idea is:
Call SetSetpoint to set your target. It doesn’t care if the target is distance or speed or heading.
The PIDController thread will periodically call PIDGet (provided by your code) to get the current reading (e.g. distance, speed or angle), whatever it is. It calculates how much output force to apply depending on how far to the target (i.e. error). The greater the error, the greater the output force.
Therefore, the PIDController is agnostic on what the control variables are. It just calculates the difference between the set target and the current actual value and apply PID control to calculate the resulting force to apply.
With this understanding, you must provide a PIDGet that will read whatever sensor you have (whether it is a gyro, an accelerometer or multiple encoders) to give you the distance. In your case, averaging the left and right encoders is the appropriate way. You must also provide a PIDOutput to take the output force calculated by the PID controller to apply to the drive motors (that depends on your drive train: 2-wheel drive, 4-wheel drive etc.).
But that’s not the end of it. A major part of PID control is to tune the PID constants (Kp, Ki and Kd). This can be a whole new subject. Basically, if the PID controller calculated too large of the output force, it will cause ringing (e.g. the robot will drive to the target very quickly but overshoot the target and then it will attempt to reverse course to correct itself). This may go on for a number of iteratiions (back and forth a few times) before it stops within the tolerance range of the “target”. If ringing occurs, you generally need to decrease the amount of ringing by reducing Kp but you don’t want to reduce Kp too much that the robot never gets to the target (i.e. the output force is too weak). So you want to tune Kp to have a little bit ringing, then you move on to tuning Kd and possibly Ki to reduce the last bit of ringing so that the Robot will drive as fast as possible towards the target but will reduce speed as it approaches the target. If PID is tuned correctly, it will then stop dead on to the target.
I am fairly new to tuning PID. I would love to hear tips from experience teams on how they tune PID. We have two PID controller objects, one for distance PID and one for turn PID. Can we use one set of PID constants for both PID controllers? Since the weight and drive motors are the same on the robot, I have a theory that the two sets of PID constants should be fairly identical but since I did not study control theory in depth, I am not sure if that’s true.
BTW, we implemented mecanum drive on our bot this year so we have 4-wheel drive. This makes PID control with encoders very challenging. Since this is our first experience with mecanum drive train and because of other mechanical limitations, we chose not to use encoders and use the accelerometer as the “distance” sensor instead. Boy, that was a challenge. We found out the accelerometer is bad choice because we have to double integrate acceleration to get distance. Because of sensor noise, the double integration will cause error cumulation that eventaully cause the robot to accelerate out of control. But at the end, knowing the limitation of the sensor and some software workaround those issues, we have a decent distance PID control using the accelerometer.