Is it ok to use slew rate with a P controller? Would the slew rate throw it off and make it inaccurate?
You’ll want to apply the P controller before the slew rate, but yes, you can do both
What’s a slew rate?
Slew rate is a programming technique to prevent motors from being overworked by gradually changing to different motor targets, instead of directly setting them.
For example:
Without a slew rate controller, you might set motors like so:
motor[3] = 0;
motor[3] = 127;
This can be harmful to the motor controllers, so you can ease their strain by doing something like this:
motor[3] = 0;
motor[3] = 10;
motor[3] = 20;
…
motor[3] = 127;
Note that no one actually does slew rate like that, it’s more automated, but that’s a good way to conceptualize it
Would you need slew rate with P control?
You do not need it, but it does take of some of the strain from the motors
Slew rate helps with Proportional functions at the start of the movement. If your first P command tells the robot it has 500 ticks to travel it will set the motor to the max speed which may cause the robot to jump or lose traction. Like jumping on the gas pedal in a car when a stop light turns green - many think this is a bad idea.
If you have a separate function that handles the acceleration (slew) then the Proportional function would request a speed change and the slew function would control the rate of change.
Here is a rough draft
#pragma config(Sensor, dgtl1, leftEncoder, sensorRotation)
#pragma config(Motor, port1, left, tmotorNone, openLoop)
int currentSpeed = 0;
int SlewControl(int requestedSpeed)
{
if(requestedSpeed < currentSpeed)
currentSpeed--;
else if(requestedSpeed > currentSpeed)
currentSpeed++;
wait1Msec(20);
return currentSpeed;
}
void DriveTo(int target){
//Check the distance to the target.
int error = target - SensorValue[leftEncoder];
//While the encoder has more than 50 ticks to travel
while(abs(error) > 50)
{
//Set the motor speed equal to the error through the SlewControl;
motor[left] = SlewControl(error);
//Check the distance to the target.
error = target - SensorValue[leftEncoder];
}
//Close enough. Stop motor.
motor[left] = 0;
}
task main()
{
DriveTo(500); //Drive forward
DriveTo(-500); //Drive backward
}
I see. Thank you, this was very helpful.
Also, one more question. Do you have to check the error at the beginning and end of the function like that? Or can you just do it once in the while loop? You should only have to do it once since the while loop checks again and again until the condition is false right?
Just a couple of cents:
Keep in mind that with a P controller, the above works as it doesn’t matter how long it takes to reach your target, as the setpoint is dynamically generated from the current error (it doesn’t make predictions and use previous values).
With a PID controller, you will have to tune your entire controller around the slew rate to make it less aggressive, otherwise your output variable will run away due to the different system characteristics.
If you are interested, you can also read about adding feed-forward controller theory to your PID loop. This is usually the way that industry implementations that are limited by acceleration or inertial constraints are implemented.
Finally, you could also use a cascaded controller. I.e. a more aggressive overseeing controller and a considerably less aggressive PID controller to take the output of the first as a process variable and keep the motors healthy - though this may just be adding unneeded complexity.
The reason they are doing that is because they need to check the condition of the error in order to actually evaluate whether the loop should run on its first operation. Another way of doing this (slightly differently) is to use a do while loop, as that will run the loop before considering the conditions of its operation; something along these lines:
do
{
//Check the distance to the target.
error = target - SensorValue[leftEncoder];
//Set the motor speed equal to the error through the SlewControl;
motor[left] = SlewControl(error);
}
//While the encoder has more than 50 ticks to travel
while(abs(error) > 50);