Exiting a PID loop

My team is trying to implement a PID loop for autonomous this year but the loop doesn’t seem to end it just keeps running. Does anyone have advice? thanks in advance!

If you are looking for someone to help debug your code, please post it in a reply (remember to wrap it in [code]...[/code] tags for formatting), otherwise it’s very difficult for others to diagnose problems with code they can’t see.

1 Like

Do you have v5 or Cortex. Also plz share code, so we can find the problem

What is inside your while() loop for your PID? You could try to make the PID loop exit once the error is low or after some time has passed.

Unless there’s an exit situation it’ll just stay there (assuming you are using a while loop to regularly update motor power)
I have a manual interrupt on one of mine. It sort of looks like this:

while(!controller.ButtonY.pressing() || positionMet){
    //run pid
}
2 Likes

Ive explored the idea of exiting the PID loop once the integral error is 0. Although without any testing im not sure how well that will work.

On second thought this probably wont work at all.

1 Like

I suggest making the condition to exit the loop have some threshold as it’s very hard to tune a PID controller to be exactly precise 100% of the time.

4 Likes

Unless tuned perfectly, the error will never actually become 0, and tuning it perfectly is difficult. What you can do is rather than have the condition of the while loop be error != 0, make a range for error. As long as the action PID is controlling is happening, and the only problem is it won’t exit, making a range for error should work.

2 Likes

Sorry for not posting in the original. Here is our code…

void drivePID(void){

  int errorLeft;
  int errorRight;
  float kp = 0.075;
  float kpTurn = 0.2;
  int acc = 5;
  int voltageLeft = 0;
  int voltageRight = 0;
  int signLeft;
  int signRight;
    task::sleep(1000);
  
    errorLeft = targetLeft -  Leftfront.rotation(rotationUnits::deg);
    errorRight = targetRight - Rightfront.rotation(rotationUnits::deg);
    signLeft = errorLeft / abs(errorLeft); 
    signRight = errorRight / abs(errorRight);

    if(signLeft == signRight){
      voltageLeft = errorLeft * kp; 
      voltageRight = errorRight * kp;
    }
    else{
      voltageLeft = errorLeft * kpTurn; 
      voltageRight = errorRight * kpTurn;
    }

Where do you call the function? The function on its own wouldn’t get stuck in an infinite loop.

The problem is not that stops, but it coasts past the value.

Do you have any examples of how you called it later on in the auto section of the match that you could possibly share

This doesn’t look like a pid loop to me. You never change your voltage after initial calling.

void drivePID(double target) {
target *= 360 / (3.25 * M_PI);
DLB.resetRotation();

double kp = 0.33;
double ki = 0.0005;
double kd = 0.2;

double proportion;
double integralRaw;
double integral;
double integralActiveZone = 360 / (3.25 * M_PI);
double integralPowerLimit = 50 / ki;
double derivative;
double finalPower;

double error = target;
double lastError = target;
sleepMs(50);
while(abs(error) > 75){
    error = target - DLB.rotation(rotationUnits::deg);
    if(error == 0){
        break;
    }
    proportion = kp * error;
    
    if(abs(error) < integralActiveZone && error != 0){
    integralRaw += error;
    } 
    else integralRaw = 0.0;
    
    if(integralRaw > integralPowerLimit){
        integralRaw = integralPowerLimit;
    }
    if(integralRaw < -integralPowerLimit){
        integralRaw = integralPowerLimit;
    }
    
    integral = ki * integralRaw;
    
    derivative = kd * (error - lastError);
    lastError = error;
    
    if(error == 0){
        derivative = 0;
        
    }
    finalPower = 0.5 * (proportion + integral + derivative);
    driveForward(finalPower);
    sleepMs(20);
}
DLF.stop(brakeType::coast);
DLB.stop(brakeType::coast);
DRF.stop(brakeType::coast);
DRB.stop(brakeType::coast);
}

We had the loop in the actual function, and then passed our target as a parameter. If by coasting past the value you mean that you use brakeType::coast, you could always try a different brakeType.

7 Likes

Is this written in VCS

We wrote it in Robot Mesh.

Ok Thank You So Much

driveForward(finalPower);

Is the driveForward a function that you have in your code

It’s just a function to make the robot drive forward or back.

Oh sorry my question was if the driveForward is a function that you created or another function embedded inside of the coding language itself