PID function to reduce drift

Hello. So my team has been trying to write code to get the robot to drive in a straight line for a certain distance, which we managed to do using encoders and gyro input; however, once the encoders register that we have traveled the ideal distance and the motor shuts off, our robot drifts a considerable amount. We’re trying to come up with a solution using PIDs, as shown below.
Any help with deciding on what the Kp, Ki and Kd values should be or with
any potential logic flaws we have would be appreciated. Also, if anyone has any better ideas than PIDs to reduce drifting, feel free to comment them. Ask for more code if you need to see anything else.Thanks!


//Initialization code for the gyrodrive command that is called to drive
the robot forward along a straight line until it reaches the desired dist.
protected void initialize() {
        log("Initialized GyroDriveCommand"); // prints to show that
        CommandBasedRobot.resetEncoders();   // resets encoders
        drivesub.enable();                   //
        gyroCalc();                          //
        
    }
//isFinished method for gyroDrive to try to stop without passing the desired
position
protected boolean isFinished() {
    
        return(drivesub.getPosition() - setpoint) < 1; // finishes when pos - setpoint < 1
            
        
    }

Declarations for the Kp, Ki and Kd values as well as the PIDInput and
PID output methods:


    private static final double Kp = 3;
    private static final double Ki = 0.2;
    private static final double Kd = 0.0;

protected double returnPIDInput() {
        return EncoderInfo.distanceL;//returns the current encoder distance
    }

    protected void usePIDOutput(double d) {
        System.out.println(d);
        start(d, 0);//gives the speed value to arcade drive
    }
public DriveTrainSubsystem(){
        super("DriveTrainSubsystem", Kp, Ki, Kd);
//OI code for calling the gyrodrivecommand
                                                               //dist, speed, setpoint
button1.whenPressed(new GyroDriveCommand(24, 0.70, 24));
    }

sounds like your motor controllers are in coast mode.

When we use a PID for driving a certain distance, we check for the encoder speed as well as the distance to be below a certain threshold before stopping the PID.

This keeps it from drifting past the setpoint at the end because the command won’t finish until the robot is no longer moving.

I agree with Ether, switching the motors to brake mode will help alleviate this issue. We usually have one motor controller on each side set to brake while the other is set to coast.

PID_varyingP.jpg

Right now your isFinished() criteria will turn off the PID loop as soon as the output gets close to the setpoint. To be able to stop precisely at the setpoint your robot will need to start slowing down before it gets there. Try letting the PID loop run for n cycles or delta time past your current criteria in the isFinished() method to let the dynamics settle. Then plot the encoder distance output vs time (SmartDashboard or print/Excel) so you can get a better idea of how well your Kp, Ki, Kd coefficients are set. If you have a lot of overshoot like the purple line in the attached graph the robot will continue to coast/skid past the setpoint no matter what you do. Play with the coefficients until you reach the optimal time/position for your system.

PID_varyingP.jpg


PID_varyingP.jpg

Thanks for the suggestions. We`re not actually in coast mode, but it still drifts past the point that we want it to stop at. We’re going to try testing out some new P, I and D values on Monday, so hopefully that clears things up.

You should not shut off your pid loop when you reach your target. Instead, you should make sure that your error is near zero, and the rate at which your error is changing is near zero.

You should also increase the D gain of your PID controller to decrease the overshoot you’re describing. The D gain compensates for the robot’s tendency to keep moving when power applied to the motors is zero.