Go to Post If they don't treat Dave nicely, he may just keep his big red ball, and not share with rest of us. - Barry Bonzack [more]
Home
Go Back   Chief Delphi > Technical > Programming > Java
CD-Media   CD-Spy  
portal register members calendar search Today's Posts Mark Forums Read FAQ rules

 
Reply
Thread Tools Rating: Thread Rating: 14 votes, 5.00 average. Display Modes
  #1   Spotlight this post!  
Unread 12-02-2013, 19:53
geel9 geel9 is offline
Registered User
FRC #1317
 
Join Date: Feb 2011
Location: Westerville
Posts: 5
geel9 is an unknown quantity at this point
PID loops using rate

Hey,

We're trying to get our PID loops to control the motors' rate, as opposed to their distance.

Here is our code:

Code:
//Initializes the motors.
    private final SpeedController left = new Jaguar(1);
    private final SpeedController right = new Jaguar(2);
    
    //Initializes the Encoders.
    private final Encoder leftEncoder = new Encoder(1, 2);
    private final Encoder rightEncoder = new Encoder(3, 4);
    
    //Proportional, Integral, and Dervative constants.
    //These values will need to be tuned for your robot.
    private final double Kp = 0.1;
    private final double Ki = 0.001;
    private final double Kd = 0;
    
    //This must be fully initialized in the constructor, after the settings
    //for the encoders have been done.
    private final PIDController leftPID;
    private final PIDController rightPID;

    public PIDDrive() {
        //Sets the distance per pulse in inches.
        leftEncoder.setDistancePerPulse(-1);
        rightEncoder.setDistancePerPulse(-1);

        
        //Starts the encoders.
        leftEncoder.start();
        rightEncoder.start();
        
        //Sets the encoders to use distance for PID.
        //If this is not done, the robot may not go anywhere.
        //It is also possible to use rate, by changing kDistance to kRate.
        leftEncoder.setPIDSourceParameter(Encoder.PIDSourceParameter.kRate);
        rightEncoder.setPIDSourceParameter(Encoder.PIDSourceParameter.kRate);
        
        //Initializes the PID Controllers
        leftPID = new PIDController(Kp, Ki, Kd, leftEncoder, left);
        rightPID = new PIDController(Kp, Ki, Kd, rightEncoder, right);
        
        leftPID.setPercentTolerance(25);
        rightPID.setPercentTolerance(25);
        
        leftPID.setContinuous();
        rightPID.setContinuous();
        
        //Enables the PID Controllers.
        leftPID.enable();
        rightPID.enable();
        

    }

    public static void WriteDriverStationLine(DriverStationLCD.Line line, String text){
        DriverStationLCD.getInstance().println(line, 1, text);
        DriverStationLCD.getInstance().updateLCD();
    }
    /**
     * This function is called once each time the robot enters operator control.
     * Teleop commands are put in here
     */
    public void operatorControl() {
        leftPID.setSetpoint(1000);
        rightPID.setSetpoint(1000);
        
        while(isOperatorControl()){
            
            WriteDriverStationLine(DriverStationLCD.Line.kUser1, "E: " + leftPID.getError());
            WriteDriverStationLine(DriverStationLCD.Line.kUser2, "E2: " + rightPID.getError());
            WriteDriverStationLine(DriverStationLCD.Line.kUser3, "D: " + leftEncoder.getRate());
            WriteDriverStationLine(DriverStationLCD.Line.kUser4, "D2: " + rightEncoder.getRate());
        }
The wheels spin forward, then rapidly switch directions.
Reply With Quote
  #2   Spotlight this post!  
Unread 12-02-2013, 20:28
NotInControl NotInControl is offline
Controls Engineer
AKA: Kevin
FRC #2168 (Aluminum Falcons)
Team Role: Engineer
 
Join Date: Oct 2011
Rookie Year: 2004
Location: Groton, CT
Posts: 261
NotInControl has a reputation beyond reputeNotInControl has a reputation beyond reputeNotInControl has a reputation beyond reputeNotInControl has a reputation beyond reputeNotInControl has a reputation beyond reputeNotInControl has a reputation beyond reputeNotInControl has a reputation beyond reputeNotInControl has a reputation beyond reputeNotInControl has a reputation beyond reputeNotInControl has a reputation beyond reputeNotInControl has a reputation beyond repute
Re: PID loops using rate

Quote:
Originally Posted by geel9 View Post
Hey,

We're trying to get our PID loops to control the motors' rate, as opposed to their distance.

Here is our code:

Code:
//Initializes the motors.
    private final SpeedController left = new Jaguar(1);
    private final SpeedController right = new Jaguar(2);
    
    //Initializes the Encoders.
    private final Encoder leftEncoder = new Encoder(1, 2);
    private final Encoder rightEncoder = new Encoder(3, 4);
    
    //Proportional, Integral, and Dervative constants.
    //These values will need to be tuned for your robot.
    private final double Kp = 0.1;
    private final double Ki = 0.001;
    private final double Kd = 0;
    
    //This must be fully initialized in the constructor, after the settings
    //for the encoders have been done.
    private final PIDController leftPID;
    private final PIDController rightPID;

    public PIDDrive() {
        //Sets the distance per pulse in inches.
        leftEncoder.setDistancePerPulse(-1);
        rightEncoder.setDistancePerPulse(-1);

        
        //Starts the encoders.
        leftEncoder.start();
        rightEncoder.start();
        
        //Sets the encoders to use distance for PID.
        //If this is not done, the robot may not go anywhere.
        //It is also possible to use rate, by changing kDistance to kRate.
        leftEncoder.setPIDSourceParameter(Encoder.PIDSourceParameter.kRate);
        rightEncoder.setPIDSourceParameter(Encoder.PIDSourceParameter.kRate);
        
        //Initializes the PID Controllers
        leftPID = new PIDController(Kp, Ki, Kd, leftEncoder, left);
        rightPID = new PIDController(Kp, Ki, Kd, rightEncoder, right);
        
        leftPID.setPercentTolerance(25);
        rightPID.setPercentTolerance(25);
        
        leftPID.setContinuous();
        rightPID.setContinuous();
        
        //Enables the PID Controllers.
        leftPID.enable();
        rightPID.enable();
        

    }

    public static void WriteDriverStationLine(DriverStationLCD.Line line, String text){
        DriverStationLCD.getInstance().println(line, 1, text);
        DriverStationLCD.getInstance().updateLCD();
    }
    /**
     * This function is called once each time the robot enters operator control.
     * Teleop commands are put in here
     */
    public void operatorControl() {
        leftPID.setSetpoint(1000);
        rightPID.setSetpoint(1000);
        
        while(isOperatorControl()){
            
            WriteDriverStationLine(DriverStationLCD.Line.kUser1, "E: " + leftPID.getError());
            WriteDriverStationLine(DriverStationLCD.Line.kUser2, "E2: " + rightPID.getError());
            WriteDriverStationLine(DriverStationLCD.Line.kUser3, "D: " + leftEncoder.getRate());
            WriteDriverStationLine(DriverStationLCD.Line.kUser4, "D2: " + rightEncoder.getRate());
        }
The wheels spin forward, then rapidly switch directions.

I would need to study the WPIJ PID class to see what its actually doing... to see if it clips the values, helps with integral windup and other control stuff to give you a complete answer... but off the bat, how did you get your gains?

Your setPoint is 1000 so your first iteration is 1000*0.1 = 100, because PWM only accepts +1 to -1 as inputs to the motor controllers.that instantly drives your motor to full power. I am not sure what the units of your 1000 but if your motor can spin faster than that, then your gains will cause your motor to oscillate... try reducing your gains.
__________________
Controls Engineer, Team 2168 - The Aluminum Falcons
[2016 Season] - World Championship Controls Award, District Controls Award, 3rd BlueBanner
-World Championship- #45 seed in Quals, World Championship Innovation in Controls Award - Curie
-NE Championship- #26 seed in Quals, winner(195,125,2168)
[2015 Season] - NE Championship Controls Award, 2nd Blue Banner
-NE Championship- #26 seed in Quals, NE Championship Innovation in Controls Award
-MA District Event- #17 seed in Quals, Winner(2168,3718,3146)
[2014 Season] - NE Championship Controls Award & Semi-finalists, District Controls Award, Creativity Award, & Finalists
-NE Championship- #36 seed in Quals, SemiFinalist(228,2168,3525), NE Championship Innovation in Controls Award
-RI District Event- #7 seed in Quals, Finalist(1519,2168,5163), Innovation in Controls Award
-Groton District Event- #9 seed in Quals, QuarterFinalist(2168, 125, 5112), Creativity Award
[2013 Season] - WPI Regional Winner - 1st Blue Banner
Reply With Quote
  #3   Spotlight this post!  
Unread 20-02-2013, 14:31
NotInControl NotInControl is offline
Controls Engineer
AKA: Kevin
FRC #2168 (Aluminum Falcons)
Team Role: Engineer
 
Join Date: Oct 2011
Rookie Year: 2004
Location: Groton, CT
Posts: 261
NotInControl has a reputation beyond reputeNotInControl has a reputation beyond reputeNotInControl has a reputation beyond reputeNotInControl has a reputation beyond reputeNotInControl has a reputation beyond reputeNotInControl has a reputation beyond reputeNotInControl has a reputation beyond reputeNotInControl has a reputation beyond reputeNotInControl has a reputation beyond reputeNotInControl has a reputation beyond reputeNotInControl has a reputation beyond repute
Re: PID loops using rate

Quote:
Originally Posted by NotInControl View Post
I would need to study the WPIJ PID class to see what its actually doing... to see if it clips the values, helps with integral windup and other control stuff to give you a complete answer... but off the bat, how did you get your gains?

Your setPoint is 1000 so your first iteration is 1000*0.1 = 100, because PWM only accepts +1 to -1 as inputs to the motor controllers.that instantly drives your motor to full power. I am not sure what the units of your 1000 but if your motor can spin faster than that, then your gains will cause your motor to oscillate... try reducing your gains.
Any update?
__________________
Controls Engineer, Team 2168 - The Aluminum Falcons
[2016 Season] - World Championship Controls Award, District Controls Award, 3rd BlueBanner
-World Championship- #45 seed in Quals, World Championship Innovation in Controls Award - Curie
-NE Championship- #26 seed in Quals, winner(195,125,2168)
[2015 Season] - NE Championship Controls Award, 2nd Blue Banner
-NE Championship- #26 seed in Quals, NE Championship Innovation in Controls Award
-MA District Event- #17 seed in Quals, Winner(2168,3718,3146)
[2014 Season] - NE Championship Controls Award & Semi-finalists, District Controls Award, Creativity Award, & Finalists
-NE Championship- #36 seed in Quals, SemiFinalist(228,2168,3525), NE Championship Innovation in Controls Award
-RI District Event- #7 seed in Quals, Finalist(1519,2168,5163), Innovation in Controls Award
-Groton District Event- #9 seed in Quals, QuarterFinalist(2168, 125, 5112), Creativity Award
[2013 Season] - WPI Regional Winner - 1st Blue Banner
Reply With Quote
  #4   Spotlight this post!  
Unread 20-02-2013, 18:05
pblankenbaker pblankenbaker is offline
Registered User
FRC #0868
 
Join Date: Feb 2012
Location: Carmel, IN, USA
Posts: 103
pblankenbaker is a glorious beacon of lightpblankenbaker is a glorious beacon of lightpblankenbaker is a glorious beacon of lightpblankenbaker is a glorious beacon of lightpblankenbaker is a glorious beacon of light
Re: PID loops using rate

My understanding is that the standard PID controller is set up to apply motor speeds to reach a certain distance. In this scenario, the end value goes to 0 when the target is reached.

For a rate controlled system, the end value is not 0 (you don't want your motor power to go to 0 when you achieve the desired rate).

So, what we have been doing is trapping the pidWrite() method (if you extend PIDSource) or usePIDOutput() method (if you extend PIDSubSystem). We then use the value passed in by the PID control loop as a "adjustment" to the current motor power. For example:

Code:
    /**
     * Processes the computed PID output value to apply to our system.
     *
     * <p>It is important to remember that the actual PID controller that is
     * making computations and calling our method will be trying to reach a
     * output level of 0.0 when the target is reached. This works well when your
     * PID is used to move to a certain distance (you want your motors to stop
     * when you reach your target).</p>
     *
     * <p>However, our motors are driving a spinning wheel and we want to reach
     * a certain speed (the motor will not be 0.0 when the speed is reached). In
     * order to handle this condition we need to treat the new values provided
     * by the PID controller as ADJUSTMENTS to the current motor power
     * setting.</p>
     *
     * @param power The power level adjustment to apply to the motors.
     */
    protected void usePIDOutput(double power) {
        if (DEBUG) {
            SmartDashboard.putDouble("ShooterPIDAdjust", power);
        }

        // Apply adjustment provided by PID controller to current power output
        // level and make sure its in the range of [0, 1].
        double ratePower = power + leftMotor.get();
        if (ratePower > 1.0) {
            ratePower = 1.0;
        } else if (ratePower < 0) {
            ratePower = 0;
        }

        // Apply the new power level to reach the target rate
        applyPower(ratePower);
    }
Hope that helps.
Reply With Quote
  #5   Spotlight this post!  
Unread 20-02-2013, 18:49
Ether's Avatar
Ether Ether is offline
systems engineer (retired)
no team
 
Join Date: Nov 2009
Rookie Year: 1969
Location: US
Posts: 8,089
Ether has a reputation beyond reputeEther has a reputation beyond reputeEther has a reputation beyond reputeEther has a reputation beyond reputeEther has a reputation beyond reputeEther has a reputation beyond reputeEther has a reputation beyond reputeEther has a reputation beyond reputeEther has a reputation beyond reputeEther has a reputation beyond reputeEther has a reputation beyond repute
Re: PID loops using rate


2013 FRC WPILib (at least for Java) has added a feedforward term to the PIDController to help support using the library PID for speed control.

So this gives you other options.

Instead of integrating the PID output, you can set your feedforward gain so that the feedforward motor command corresponds roughly to what you'd expect is required for the speed you are commanding. Then tune the PID with I only (set P and D to zero) to get the steady-state accuracy.


Reply With Quote
Reply


Thread Tools
Display Modes Rate This Thread
Rate This Thread:

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Forum Jump


All times are GMT -5. The time now is 11:42.

The Chief Delphi Forums are sponsored by Innovation First International, Inc.


Powered by vBulletin® Version 3.6.4
Copyright ©2000 - 2017, Jelsoft Enterprises Ltd.
Copyright © Chief Delphi