PIDController - control speed vs distance - SetSetpoint

Hi,

I need help in understanding how to measure distance vs measuring speed.

We are using the following encoder:

The encoder can give information on speed (rate) and distance.

I looked into FIRST example on this page:
http://wpilib.screenstepslive.com/s/3120/m/7912/l/79828-operating-the-robot-with-feedback-from-sensors-pid-control

Please help me understand what value should we set in the SetSetpoint() method and how the controller knows to measure the distance or the rate?

Thanks!

In general, a PID algorithm requires that your setpoint (“desired”) and actual values be of the same units. If you want to control your motor-powered mechanism to a certain position, use distance for both. If you want to have it rotate at a constant speed, use speed for both.

In Java, this is accomplished by two methods - setSetpoint(), which you already mentioned, and returnPIDInput().

setSetpoint gets called by other classes in your code, when they want to change the operation of the controlled system (ex: set a new speed to the shooter).

The PID class requires that you define the contents of returnPIDInput(). As long as the PID subsystem is running, it will periodically call returnPIDInput() to figure out where it’s actually at, and compare that to the most recent value given via setSetpoint().

tl;dr - setSetpoint = Desired, returnPIDInput = Actual, must be same units.

Note that depending on whether you choose to control to a speed or position, the tuning philosophies do tend to change… but that’s a broader discussion on the nature of the controlled system…

Thanks for the help!
But how/where do i set the returnPIDInput so when i want to control the speed it will return the rate and when I want to control the distance it will return the distance?

I read a bit more the wpilib documentation and found the PIDSubsystems class and how to use it. I understand now that i can override the returnPIDInput() and return the values i need to compare.

Can it be done with the PIDController class?
Does Encoder.setPIDSourceType has anything to do with it?

Yah, as you probably are finding out, there are two independent ways to do PID in Java:

option 1:
Create your own class which extends PIDSubsystem

  • In this case, you must provide implementations for returnPIDInput() and usePIDOutput(). returnPIDInput must be implemented to return the proper value (either a position or a speed, depending on what you want). setSepoint() must use the same units as whatever returnPIDInput() returns.
  • I personally prefer this methodology, because I have more control over exactly what goes into the PID algorithm (was also what I had assumed when I answered your post at first)
  • This is the method referenced in the last section of http://wpilib.screenstepslive.com/s/3120/m/7912/l/79828-operating-the-robot-with-feedback-from-sensors-pid-control

option 2:
Declare a PIDController, and provide it with references to the input and output devices (motor, encoder, etc).

  • I haven’t used this much at all. But, the basic theory still applies - Encoder.setPIDSourceType() should called for any encoder which is used as input to a PID subsystem. Whether you choose to do displacement or speed, just ensure that whatever you set the encoder to, you call setSetpoint with the same units.

On 1389, we reimplemented PIDController to fit our code design, so I don’t have any direct experience with the WPILib version, but here is the process I just used to try to figure out how to use it properly:

check out this page on using the WPILib encoder class.
The screensteps explains just how to get the information you want from the encoder: use getDistance() or getRate().

With regard to using it with a PIDController:
When you pass an object to a PIDController as a PIDSource, that object must implement the PIDSource interface. Most of the sensor classes in WPILib implement this interface, and can be used as a PIDSource.
The interface includes a method called getPIDSourceType. This is intended to be used by the sensor to tell the PIDController how the sensor should be PID tuned: an ultrasonic sensor would be kDisplacement, a gyro would be kRate (by default) and an encoder can be EITHER rate OR displacement.
If the sensor’s getPIDSourceType() method returns kDisplacement, the PIDController will set itself up for distance mode, and if it returns kRate, the PIDController will set itself up for velocity control mode.
As we can see in the source code for the Encoder class, it already implements the PIDSource interface, which means it can be passed to the PIDController as a source of input. What we need to find out is whether it will be used as a rate source or a displacement source. We can see that the encoder is set up to return either rate or displacement, as set in the instance variable: m_pidSource, but this variable is set to private. by default, it looks like the encoder sets it to kDisplacement

To someone involved with WPILib, what is the intended way of setting the preferred encoder mode to kRate? there appears to be no way to set the mode yourself.
EDIT: you can use encoder.setPIDSourceType() to set the encoder to velocity mode

Ditto, but for PIDSubsystem:

http://robotcasserole1736.github.io/CasseroleLib/java/javadoc/org/usfirst/frc/team1736/lib/CasserolePID/package-summary.html

Thank you guys, while reading the docs and implementing the code your answers really helping and we already implemented the pid controllers. It seems to work fine.

What is the best practice in enabling and disabling the pid controller.
Lets say i want to autonomously drive the robot to point X - SetSetpoint(distance_from_X).
When the robot reach the target and stops, should i disable the controller?
If so, what is the best way to trigger this event?

Thanks.

I’ve seen both done:

-Leaving the controller on will help keep you in the same position. This is often simpler too.
-Turning off the controller (and setting the drivetrain to zero) will assume the robot will stay in the same spot, and yield drivetrain power & computing resources for other tasks to use.

Regardless, the trigger condition I like to use for saying “We are now done using this controller” is:
–Error Magnititude is less than some threshold (say, 3 inches?) and stays that way for a certain time period (say, 0.25 seconds?)

Thank you!!