Understanding PID Controllers

As a programmer for a post-rookie team that knew nothing going into its first season, I’ve been working intensively on programming development over the summer. I’m writing my own control classes and I understand basic controls like PID pretty fully except for the following questions:

  1. How is the output of the PID (and related) algorithms converted into a usable control signal? Also, what is the control signal range accepted by motor controllers?

  2. What frequencies do you all run your control loops at?

  3. When do you use PI, PD, as opposed to full PID in FRC? What are the use cases for these?

  4. I haven’t found a resource that explains feed forward control well to me yet. Would someone mind explaining what feed forward is, how to tune FF gains, and how the feed forward value fed to the motor controller is determined?

  5. What is your favorite control equation for motion profiling? I’m asking for something like P + I + D + accFF + velFF, except a real equation. I’m familiar with motion profiling libraries like Pathfinder, just not the control algorithm used for following those points.

Thanks for any help! For reference, I’ve read PID without a PhD, the FRC PDR docs (which didn’t help much), the wikipedia article, and some excellent articles from https://controlguru.com/table-of-contents/

edit: typo correction, Clarified question #5

The sum of the terms (kP * E + kI * int(E) + kD * dE/dt) is your control signal. FRC motor controllers take -1 to 1 as inputs, so you should choose your constants in the correct units, although I prefer to think of this in -12v to 12v range because it makes the math easier.

50hz, except for Talon control loops which run at 1kHz. It doesn’t help to run much higher than this in my experience.

Really consider this on a case-by-case basis, as each term affects your system differently. The P term reduces error, the I term eliminates steady-state error (error that the P term can’t get rid of) and the D term dampens the system (resisting changes in input, a bit like virtual friction.)

Feed-forward, is, in my opinion, the most important part of the control loop. It isn’t a single term, but a combination of things that model how the system works. It’s like if you take a virtual model of your system, figure out how the state of the system changes based on your control input (voltage), then invert that to find out what control input you need to use to get the system to a desired state. This depends on the setpoint and the current state of the system. I’m writing a paper with some physical derivations of common systems, but there’s some basic explanations on the PDR as well.

Again, FF is just added to the output of the controller, so you have Vout = FF(t) + kP * E + kI * int(E) + kD * dE/dt. If you have a good feedforward, you probably don’t need to do a lot of tuning on the other gains.

Not really sure what you mean by this. Trapezoidal motion profiles are the standard, then you just either cascade position and velocity control loops (use the output of a position loop into a velocity loop) or use a position loop with feedforward terms that take your velocity and acceleration into account.

Control loops are one of the more complex topics in FRC, and it hurts more when you’re thrown in without an explanation. I’ve been trying to update the PID article on the PDR, so maybe I’ll try to pull in some ideas from the other resources you have listed, as well as address some of the practical questions you have here.

Please ask for more clarification if needed.

  1. For all of our PID Loops, the controller outputs a percent value to send to a motor. This value ranges between -1 and 1.

  2. We run most of our control loops in asynchronous (Kotlin) coroutines at 50Hz or a 20ms dt.

  3. We don’t use the D term very often. The time we did use it was for a “turn to angle” controller to dampen some oscillation. Otherwise the P term usually does a lot of the work. We played around with the I term for correcting steady state error (error that is too small to be corrected by the P term itself), but a majority of the time, the P does most of the work.

  4. Nick’s explanation above is perfect!

  5. By “motion profiling” if you mean tracking a trajectory, we implemented a really neat trajectory tracking controller((equation 5.12 from the paper) in the last month that Software Mentor Jared Russell from Team 254 recommended on the FRC Discord:
    https://www.dis.uniroma1.it/~labrob/pub/papers/Ramsete01.pdf. ](https://www.dis.uniroma1.it/~labrob/pub/papers/Ramsete01.pdf)

We are currently testing it when we have meetings and we are pretty happy with it’s correction and ability to track trajectories with accuracy.

During the season, however, we used Pathfinder https://github.com/JacisNonsense/Pathfinder/ and it’s built-in motion profiling framework. This is really robust and is very easy to set up and get going with following trajectories. It follows paths with reasonable accuracy.

If you just mean 1d motion profiling, we used trapezoidal profiles for our elevator and arm mechanisms.

I’m pretty sure this is essentially a units question. What are you plugging the controller into? If you’re doing this on the RoboRIO, you should probably be generating a desired voltage and then converting that into a PWM signal.

  1. What frequencies do you all run your control loops at?

If you run your control loops on the RoboRIO, they’re typically running at 50 Hz/20 ms. The exact details depend on the base class you’re using. See the docs for details.

If you run your control loops on the Talon SRX/Victor SP, you’ll be running at 1000 Hz/1 ms per their documentation. See section 10.

  1. When do you use PI, PD, as opposed to full PID in FRC? What are the use cases for these?

I will defer to smarter people than me on this one. My personal philosophy is to use mechanical hard stops and pneumatics and avoid continuously-variable mechanisms that need to be kept within a tight tolerance.

I remember Austin Schuh mentioning that if 971 needs to do anything more intense than a PD loop, they typically will use a state-space control model instead of PID.

  1. I haven’t found a resource that explains feed forward control well to me yet. Would someone mind explaining what feed forward is, how to tune FF gains, and how the feed forward value fed to the motor controller is determined?

This one is pretty good. It was written by a 1678 alum. I suggest this particular blog post for feedforward.

  1. What is your favorite control algorithm for motion profiling?

6844 hasn’t done this yet, but if we were to start, we’d probably start by looking at the work Jaci has done. If we wanted something more generic and less specific to drivetrains, the Talon SRX supports something called Motion Magic (see 10.7 in that same document I referenced for the loop period on the Talon SRX). Additionally, 254 gave a really good presentation on motion profiling in 2015 that’s worth your time.

Tuning-wise, for drivetrain, we tune it first. If you know the maximum speed of your drivetrain, it can be calculated as 1/max_speed. Start with this, tweak till it’s as good as you think it can be. Then, slowly start adding in P and then other feedback terms.

The equation listed has less to do with motion profiling, and more to do with a PID with a fancy feed-forward term - Since you know the desired acceleration & Velocity at every point of the pre-planned route, you can inject this information into the controller to help it behave better.

In general I prefer to keep the problems of motion profiling and drivetrain control separate. The Drivetrain classes are designed to accept velocity & Heading commands, and are implemented to cause the physical drivetrain to follow those commands as closely as possible.

Separately, a motion profiling system generates those commands in real time. As long as they speak the common language of velocity/heading commands, you can swap either block out with a different algorithm without changing the other.

PID controllers work on error.

You’ve got a setpoint, where you want your system to be at. You’ve also got a measurement (the feedback), where your system is at. The PID controller does math on the error (the difference between setpoint and measurement) and then changes your control variable to try and correct for the error.

Suppose you knew something about your system and had a model for it. You knew that in order to control to a certain point (run the shooter wheel at 600 rpm), you had to have a specific output (throttle motors at 70%). Instead of relying on the PID to react to your setpoint to control the error to get what you already know, you can feed forward the model as an input into your control variable (output is PID only versus 70% + PID).

If you’ve ever used a microscope, it’s similar to using one of either the fine adjustment or the coarse adjustment to focus versus using the coarse adjustment to get close (feedforward), then using the fine adjustment (PID feedback) to focus better.

This is crucially important, and you should take it to heart.

Motion profiling has nothing to do with system control - it is just a setpoint generation scheme.

Thanks for the great answers!

I think there were some misunderstandings around my fifth question, correct me if I’m wrong. I intended to ask for a control algorithm used to follow the trajectory points provided by a motion profile. I’m vaguely aware that its a PID loop with feed forward added, I just haven’t seen an actual equation. Thanks!

The point is that the answer to that question is “it is not fundamentally different from the algorithm you should use to control a drive during teleop.” The only difference is that, pending your choice of profile, you are guaranteed to have a meaningful acceleration setpoint which can be used for feedforward, and the opportunity to close the loop on position instead of velocity (which doesn’t change much in theory, but in practice can have a few subtle effects that are a bit too complicated to summarize briefly here). But it’s not as if you should use feedforward when following trajectory points and not when driving in teleop - you should always be using feedforward, regardless.

If you want more details on what the equations for the feedforward should look like, you can read the whitepaper linked in my signature.