PID Inquiries

So after a long while of learning and creating new things with my PID, I’ve come across some interesting things.

  1. My pid only works for values plus or minus about 200 degrees to the value I tuned it for. To explain further, I tuned my pid for 1000 degrees with a rotation sensor, but if I try to run it say, 700 degrees, it just wont complete the task and my auton will stop (will hit like 750 degrees). Not sure how to fix this and I can post my code later.
  2. my pid seems to be slowing into turns and DriveForward statements rather than starting at full speed and then slowing down
  3. just as a note, it is still very accurate when it works, it just sometimes doesnt.

Tips would be appreciated, as i said, ill post code later

I mean 650 degrees not 750*

Your first problem is interesting, could you explain a bit further? (what do you mean by):

does it abruptly stop, or does it slow down using the PID?

As you said, seeing your code would help… I can’t really give any tips if I can’t see your program.

 //MForward pid
  //--------------------------------------------------------------------------------------------------------------------------------------------//

      //Lateral constants
      double MForwardkP = 0.02;

      //Desired value
      int MLatValue = 0;

      //defining errors
      int MLerror; //SensorValue - DesiredValue : Positional value

      int MLprevError = 0; //Position 20ms ago

      int MLderivative; // error - prevError : speed

      int MLtotalError = 0; //totalError = totalError + error
      
      //variables for settings
  
      bool resetMForwardSensors = false;

      void MresetDriveSensors(){
          Rot.setPosition(1, degrees);
          Rinertial.setRotation(1, degrees);
      }

      //Drive pid
      int MLateralPID(){

        if (resetMForwardSensors) {
          resetMForwardSensors = false;
          Rot.setPosition(1, degrees);
          Rinertial.setHeading(1, degrees);
        }


      while(enableDrivePID){

      
      //Getting drive position
      //---------------------------------------------------------------------------//


      //---------------------------------------------------------------------------//

        //Potential
        MLerror = MLatValue - Rot.position(degrees);

        //Derivative
        MLderivative = MLerror - MLprevError; 

        //Lateral PID equation
        double SLforwardSpeed = (MLerror * MForwardkP);
  

        FLDrive.spin(forward, SLforwardSpeed - Rinertial.rotation(degrees), voltageUnits::volt);
        BLDrive.spin(forward, SLforwardSpeed - Rinertial.rotation(degrees), voltageUnits::volt);
        TLDrive.spin(forward, SLforwardSpeed - Rinertial.rotation(degrees), voltageUnits::volt);
        FRDrive.spin(forward, SLforwardSpeed + Rinertial.rotation(degrees), voltageUnits::volt);
        BRDrive.spin(forward, SLforwardSpeed + Rinertial.rotation(degrees), voltageUnits::volt);
        TRDrive.spin(forward, SLforwardSpeed + Rinertial.rotation(degrees), voltageUnits::volt);

        MLprevError = MLerror;
        
        vex::task::sleep(20);
      
        }

        return 1;
        }
         
  //--------------------------------------------------------------------------------------------------------------------------------------------//

  //SForward pid
  //--------------------------------------------------------------------------------------------------------------------------------------------//

      //Lateral constants
      double SForwardkP = 0.035;

      //Desired value
      int SLatValue = 0;

      //defining errors
      int SLerror; //SensorValue - DesiredValue : Positional value

      int SLprevError = 0; //Position 20ms ago

      int SLderivative; // error - prevError : speed

      int SLtotalError = 0; //totalError = totalError + error
      
      //variables for settings
  
      bool resetSForwardSensors = false;

      void SresetDriveSensors(){
          Rot.setPosition(1, degrees);
          Rinertial.setRotation(1, degrees);
      }

      //Drive pid
      int SLateralPID(){

        if (resetSForwardSensors) {
          resetSForwardSensors = false;
          Rot.setPosition(1, degrees);
          Rinertial.setHeading(1, degrees);
        }


      while(enableDrivePID){

      
      //Getting drive position
      //---------------------------------------------------------------------------//


      //---------------------------------------------------------------------------//

        //Potential
        SLerror = SLatValue - Rot.position(degrees);

        //Derivative
        SLderivative = SLerror - SLprevError; 

        //Lateral PID equation
        double SLforwardSpeed = (SLerror * SForwardkP);
  

        FLDrive.spin(forward, SLforwardSpeed - Rinertial.rotation(degrees), voltageUnits::volt);
        BLDrive.spin(forward, SLforwardSpeed - Rinertial.rotation(degrees), voltageUnits::volt);
        TLDrive.spin(forward, SLforwardSpeed - Rinertial.rotation(degrees), voltageUnits::volt);
        FRDrive.spin(forward, SLforwardSpeed + Rinertial.rotation(degrees), voltageUnits::volt);
        BRDrive.spin(forward, SLforwardSpeed + Rinertial.rotation(degrees), voltageUnits::volt);
        TRDrive.spin(forward, SLforwardSpeed + Rinertial.rotation(degrees), voltageUnits::volt);

        SLprevError = SLerror;
        
        vex::task::sleep(20);
      
        }

        return 1;
        }
         
  //--------------------------------------------------------------------------------------------------------------------------------------------//

  //Turn 90 pid
  //--------------------------------------------------------------------------------------------------------------------------------------------//

        //turn right constants
        double turn90kP = 0.2;

        //Desired value
        double Turn90Value = 0;

        //defining errors
        int turn90Error; //SensorValue - DesiredValue : Positional value
        int turn90PrevError = 0; //Position 20ms ago
        int turn90Derivative; // error - prevError : speed
        int turn90TotalError = 0; //totalError = totalError + error
        
        //variables for settings
        bool enableTurn90PID = true;
        bool resetTurn90Sensors = false;

        //Drive pid
        int Turn90PID(){


        while(enableDrivePID){
        

          //Averaging position
          int TL90CurrentPosition = Rinertial.rotation(degrees);
          

          //Potential
          turn90Error = Turn90Value - TL90CurrentPosition;

          //Derivative
          turn90Derivative = turn90Error - turn90PrevError; 

          //Lateral PID equation
          double turnLeft90Speed = (turn90Error * turn90kP);

      
          FLDrive.spin(forward, turnLeft90Speed, voltageUnits::volt);
          BLDrive.spin(forward, turnLeft90Speed, voltageUnits::volt);
          TLDrive.spin(forward, turnLeft90Speed, voltageUnits::volt);
          FRDrive.spin(reverse, turnLeft90Speed, voltageUnits::volt);
          BRDrive.spin(reverse, turnLeft90Speed, voltageUnits::volt);
          TRDrive.spin(reverse, turnLeft90Speed, voltageUnits::volt);

          turn90PrevError = turn90Error;


          vex::task::sleep(20);

          }

          return 1;
          } 

  //--------------------------------------------------------------------------------------------------------------------------------------------//

  //Turn 45 pid
  //--------------------------------------------------------------------------------------------------------------------------------------------//

        //turn right constants
        double turn45kP = 0.3;

        //Desired value
        double Turn45Value = 0;

        //defining errors
        int turn45Error; //SensorValue - DesiredValue : Positional value
        int turn45PrevError = 0; //Position 20ms ago
        int turn45Derivative; // error - prevError : speed
        int turn45TotalError = 0; //totalError = totalError + error
        
        //variables for settings
        bool enableTurn45PID = true;
        bool resetTurn45Sensors = false;

        //Drive pid
        int Turn45PID(){


        while(enableDrivePID){
        

          //Averaging position
          int TL45CurrentPosition = Rinertial.rotation(degrees);
          

          //Potential
          turn45Error = Turn45Value - TL45CurrentPosition;

          //Derivative
          turn45Derivative = turn45Error - turn45PrevError; 

          //Lateral PID equation
          double turn45Speed = (turn45Error * turn45kP);

      
          FLDrive.spin(forward, turn45Speed, voltageUnits::volt);
          BLDrive.spin(forward, turn45Speed, voltageUnits::volt);
          TLDrive.spin(forward, turn45Speed, voltageUnits::volt);
          FRDrive.spin(reverse, turn45Speed, voltageUnits::volt);
          BRDrive.spin(reverse, turn45Speed, voltageUnits::volt);
          TRDrive.spin(reverse, turn45Speed, voltageUnits::volt);

          turn45PrevError = turn45Error;


          vex::task::sleep(20);

          }

          return 1;
          } 

  //--------------------------------------------------------------------------------------------------------------------------------------------//

say I want to drive forward for 1000 degrees, then I want to turn left 90 degrees, then drive forward 1000 degrees again.

my robot will go forward 1000 degrees, turn left 89 degrees, then it will not drive forward 1000 degrees because it didnt turn for 90 degrees. If I physically push the robot to where it does turn for 90 degrees, then it will drive forward for the final 1000 degrees.

I am using many different pid loops for this reason. if I tune one for 90 degrees and one for 45 degrees, this isnt as much of an issue.

What you’re probably running into is what I like to call a “black hole” in the PID. You’ve got PID happening, but the I & D are offsetting the P, and each other, such that you’re generating a very small motor command.

I’d recommend making a check on your PID such that if the voltage is below a certain threshold before you send it to the motors, you set it equal to that minimum threshold. This should allow your robot to have enough “oomph” to push it to get to its target. You’ll have to play with it to find what you want that to be; usually like 5% if it were in percentage should be enough, but if your robot is heavier, you may need a bit more, and if it’s lighter it may need a bit less.

This is why tuning PIDs can be a thing of nightmares. Theoretically, you could rebalance your PID values to not get have that happen, but I prefer the route of sanity and do a minimum speed check (and a minimum input speed happens in industry anyway, as there’s plenty of motors that won’t like to have an input value of 0.0003 volts without eventually burning something up).

2 Likes

what do you think about this

if(turnLeft90Speed < 0.5){
            turnLeft90Speed = 0.5;

          }

It’s a starting point for sure; again, it will totally depend on your robot’s individual characteristics, but that seems like a reasonable place to start.