I’m not sure if this is the correct section, but I have a question regarding implementing a PID control loop and using timers in ROBOTC. I’m fairly new to programming for robotics and ROBOTC, but I have had previous programming experience.
I understand the concept and purpose of a PID control loop, and I understand how to both implement and tune it (at a very basic level), but I’m a bit confused on how to implement the time factor (delta time).
I understand that ROBOTC offers four timers that can be cleared using the ClearTimer() function, and that you can access these values through something like an array.
My question is, how do I access the values of the timers, and then how do I implement these values into the PID loop?
I’ve seen that there are different ways to access the values of the timers (perhaps in different units of time?), but I’m unsure as to which way I should access to the values to implement into the PID loop?
And once I have the value of the timer, how would I apply that to the derivative and the integral? It seems like the unit of time would matter when you go to include it (since it would cause the value to be different). Is that correct?
I honestly haven’t seen timers used as part of a PID loop, so I don’t have much advice for that part of your question.
You can access any of the four timers, T1, T2, T3, or T4 using the time1], time10], and time100] commands. Like you said, these commands differ based on their resolution. time1] uses milliseconds, time10] uses tens of milliseconds (not tenths), and time100] uses hundreds of milliseconds.
I’ve been reading this document and it made a reference to “delta time”, which I’ve read is the time in milliseconds between each time-checking event.
I haven’t read this in any other articles/tutorials, so is that true? Is time an aspect of PID loops (namely in the calculation of the integral and the derivative)?
This is a sample PID loop that I wrote and gave to the other programmer on my robotics team, its not the code for our full robot, just a test (mostly to learn about the implementation of control loops):
task main()
{
// constants - they must be "tuned" at a later time to ensure more stability and faster reaction
const float Kp = 1; // proportional
const float Ki = 1; // integral
const float Kd = 1; // derivative
const int target = 100; // the target value for the arm's position, note that this may vary, also note that this will NOT be constant when practically applied
float integral = 0; // this will store the integral, initialized to 0
float derivative = 0; // this will store the derivative, initialized to 0
float currentError = 0; // this will store the current error, initialized to 0
float lastError = 0; // this will store the error of the previous iteration, initialized to 0
int liftPos = 0; // this will store the current value read in through the sensor, initialized to 0
float output = 0; // this will store the output value of the PID, and will be applied to the appropriate motor, initialized to 0
ClearTimer(T1); // reset the timer
// this is an intentional infinite loop, it will constantly monitor and correct using the PID control loop
while (true)
{
liftPos = SensorValue[quad]; // reads the value of the quadrature encoder (sensor) into the liftPos (lift position)
currentError = target - liftPos; // calculate the error
integral += currentError * time1[T1]; // calculate the integral
derivative = (currentError - lastError) / time1[T1]; // calculate the derivative
ClearTimer(T1); // clears the timer, this will allow us to calculate the delta time each iteration
output = Kp * currentError + Ki * integral + Kd * derivative; // calculate the output (or the result of the PID loop), note that the proportional is calculated here
motor[liftMotor] = output; // apply the output to the motor, note that there may be certain constants to factor in here, but such constants are optional
lastError = currentError; // set the lastError
}
}
Is that code correct, or at least a fundamentally correct implementation of a PID loop? I know its certainly not perfect (and that there might actually be too many comments), but is this a correct example of a PID loop? If not, how would I correct it? Oh, and I know I have to control the integral to prevent it from overflowing, but I figured I’d do that at a later time (as it wasn’t vitally important right now).
To make my reference to delta time more clear, this is the part of the writing that mentions delta time as applied to the integral:
This is the part of the writing that deals with delta time as applied to the derivative:
Time can be used as part of a PID loop, I just don’t have any first hand experience doing so. The code below looks promising… what kind of results are you getting?
Okay, so I read jpearman’s post, and it seems to make sense (and upon rereading the article I linked to earlier, it seems that they recommended the same solution). Apparently delta time can just be a constant value (implemented using a wait1Msec or the like) and is actually factored into the constants for the integral and derivative. This does make a lot more sense than what I offered.
Upon switching to this technique, it seems to work a lot better (and generally seems cleaner in the code). As for the rest of the code (other than the time) everything works great.