PID with encoder

Last spring was my first introduction to FRC and with my 17 years of Automation controls background I help a team figure out how to use some of their feedback devices I.E. pot, Ultrasonic, encoders. They had a lifting arm that fit itself well to a pot and PID subsystem. They where using Iterative type coding and with a little research and video tutorial on Command Base programming I quickly became a fan special with the test mode and how easily it was to test code bits and PID systems. The past few weeks during pre-launch I was teaching a new bunch of programmers the command base system and how the different parts work. We have only a robot drive train sub system currently with four wheels and encoders on each. Diving with joysticks and selecting different modes on the smartdashboard has been successful. Today I thought why don’t we try a PID subsystem. We created a new project with only a PID subsystem with a motor and associated encoder. With 360 pulses per one rev of the output wheel verified by manually spinning the motor in test mode. When I enable the PID the motor shacks rapidly. It seems real hot but with turning down the P and leaving the I,D at 0 dose not seem to help.

Is using an encoder not a good idea for PID?
Is there a way to set the max output so if the error is large the motor output can not raise above 50%?
Maybe its because the resolution is to course?
Maybe we should try setting the units per pulse to .1 and set point to 3600?

How much play is there between your motors and your encoder mount?

I’m not super familiar with PID theory, but I do know that for 2016 they’ve added a velocity mode that does the PID calculations slightly differently. That might explain why you’re having issues.

Here’s a link to the new code: https://github.com/robotpy/allwpilib/blob/master/wpilibj/src/shared/java/edu/wpi/first/wpilibj/PIDController.java#L265

I have a few questions about your system so that we might be able to help you better, if you don’t mind me asking.

What language are you using?

Are you controlling speed or position with your PID system? Getting the encoder speed has been known to not work entirely properly all the time, having large jumps in value, because of how the roboRIO does timing loops. Taking a manual derivative (oldSpeed - currentSpeed) / periodicInterval (20 ms, unless you are making your own loops)] works much better and smoother.

Is there any other system controlling the motor? I know that in labVIEW, the same motor set to different values in different places will cause the motor to rapidly twitch between them, due to the parallel nature of the language. Our team hasn’t run into this problem in any of the text based options, but we also haven’t had as much experience with them, and have very little experience in command-based programming (we’ve programmed all our new robots iteratively). If you are doing any threading or parallel processes, then definitely search for race conditions.

Now, to answer your questions:

“Is using an encoder not a good idea for PID?”
Encoders work great - they are the best (only?) method of getting the position and velocity of a robot. We’ve used them ourselves in 2014 on our drive train and had great success with them. If you know what you’re doing, you can do some really cool things with them (note: this isn’t completely PID, but it is motion profiling with encoders as feedback sensors)

“Is there a way to set the max output for PID?”
the PIDSubsystem and PIDController classes both seem to have “setOutputRange” methods. I haven’t used them myself, but the documentation says “Sets the maximum and minimum values to write”, so I would start there.

“Maybe its resolution is too coarse?”
Most teams use encoders with resolutions of 360 or 256 and have reasonable success with both, so it’s not likely that the resolution is where the problem lies.

“Maybe we should try setting the units per pulse to .1 and set point to 3600?”
If you are controlling the position of the encoders, then that would work well for finding any offending behaviors in the PID controller (obviously it’s not a permanent solution).

Best of luck, it’s good to see mentors helping students learn and explore more advanced control options in FRC :slight_smile:

BL0X3R was on the money, but I will add graph it. When I graph our encoder data, depending on a number of factors I have seen very “jittery” velocity data (solutions are as mentioned, calculate yourself, if necessary calculate an average velocity over the last n encoder reads).

If you are using labVIEW visualizing data in real time is trivial. If not, I have taken to writing my logs in JSON and then using javascript and the browser for visualizing (I use http://www.flotcharts.org/), rather than trying to write code in C++ or Java to display graphs.

In many cases seeing is understanding.

By shakes (shacks?), do you mean that the motor just reciprocates but doesn’t make any net revolution, or that it goes in the right direction but have a shake riding on top of that?

If it’s the first, you may want to try swapping your encoder channels.

If it’s the second, check for loose connections, especially on the encoder but also on the power.

SoftwareBug2.0

Quite Sloppy gear box. Is a likely problem. I did try to place the wheel attach on the ground to try and eliminate the backlash and is why I asked about setting the max speed. (answered possibly by GeeTwo)

virtuald

I did just see the Velocity mode in RobotBuilder and was going to play some with changing that. I was not aware this is new for 2016.

BL0X3R

We are using Command Based Java

As virtuald stated and I found it was set to velocity.

Is there any other system controlling the motor?
No this is a fresh program with only the few components declared.

Some of my ideas posted where me brain storming for tonight to get the community input. Thanks for the kind words too.

phurley67

Graphing is a great idea. I need to show them how to get the data in the smartdashboard displayed this way and see the power of the tool. I remember myself doing this last spring when I was testing the new PDP current draw of each channel. Thanks for reminding me to show this to them.

GeeTwo

Shakes yes like over shoot. I could not see if it made a revolution. Graphing and trying to use the “setOutputRange” the others have mentioned should help identify this. We did have the encoder channels swapped and seen the motor run away with the error growing not closing.

Thanks to all lots of great ideas given and confirmed.

Another thing you can do to work on this issue is to leverage the smartdashboard (I know you can’t use it very much while in test mode) to display the distance/rate as you run the system manually (outside the PID loop) and see that things are changing as you expect (direction, magnitude, sensitivity).

SUCCESS!

The setOutputRange worked perfectly to slow things down so not to overshoot so violently. Also with closer examination of Robotbuilder and only after manually entering the code into the PID subsystem there is a check box and min/max value boxes. With kDistance selected as PID source I was able to tune the P factor to .005 and eliminate the overshoot. Tonight will be a successful learning experience thanks to your input.

A very lightly loaded motor is going to be extremely difficult to tune for speed control, unless (as you discovered) you limit the power. What really works best is limiting the acceleration so the system is not as prone to oscillation. You can do that in software by limiting the rate of change of motor power, or you can do it in hardware by adding inertia.

Do you have any suggestions on how to software limit the acceleration?

You could run a current loop on the talon and limit the current.

My favorite method is to limit the voltage difference from the BEMF voltage. That will limit the current, which will limit the torque. You won’t be able to do that with the standard PID controller, but it isn’t very hard to write a new one.

CANTalons have a “setVoltageRampRate” function

We are using a CANTalon and have tested the “setVoltageRampRate” but it seems to play badly with position overshoot.

This is one of the classic problems that people run into with controls. The math behind most control loops assumes that the loops and system are linear and time-invariant. That can essentially be boiled down to meaning that your system can be simply modeled as an ordinary differential equation. You can’t model taking the output of your PID loop and doing a voltage ramp on it as an ODE. I’d recommend only doing operations that can be modeled with differential equations (or constant coefficient difference equations since we are actually operating in discrete time) in your control loops.

In this case, that would be doing a current loop and limiting the current, or feeding a motion profile into the talon (or from outside the talon). There are other methods that also work, but they won’t work without being able to modify the firmware on the talon.