Skip to content

Commit 2a9687d

Browse files
added feedback control
1 parent 5af3052 commit 2a9687d

4 files changed

Lines changed: 166 additions & 76 deletions

File tree

docs/section-7/feedback-control.md

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
<script
2+
src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"
3+
type="text/javascript">
4+
</script>
5+
6+
## Feedback Control: PID Algorithm
7+
PID (Proportional Integral Derivative) control is a method that issue corrective commands to move a mechanism from where it actually is, to where you want it to be using sensors that detect the difference between the two states. WPILIB and vendor libraries usually have PID implemented with a few additional features. We will first cover the underlying theory, then the implementation.
8+
## Theory
9+
Here is an intuitive explanation of PID:
10+
<iframe width="640" height="360" src="https://www.youtube.com/embed/wkfEZmsQqiA" title="What Is PID Control? | Understanding PID Control, Part 1" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
11+
12+
As a summary, the controller has 3 parts:
13+
14+
- kP (Proportional term): drives the position error to zero by contributing to the control signal proportionally to the current position error
15+
16+
- kI (Integral term): drives the total accumulated error to zero by contributing to the control signal proportionally to the sum of all past errors
17+
18+
- kD (Derivative term): drive the change of the error to zero by contributing to the control signal proportionally to the change of the error
19+
20+
The three quantities are added together to drive the error to zero. The three constants can be "tuned" (by changing around their values) for the error to be driven faster, slower, or to be less volatile.
21+
22+
In code, it looks something like this:
23+
``` Java
24+
25+
// kP, kI, kD can be any value, for example kP can = 0.5
26+
// You "tune" these values by finding the optimal value
27+
double kP = 0.2;
28+
double kI = 0.01;
29+
double kD = 0.05;
30+
31+
double lastTimestamp = Timer.getFPGATimestamp();
32+
double accumulatedError = 0; // for the kI term
33+
double previousError = 0; // for the kD term
34+
35+
// runs every 20 ms
36+
@Override
37+
void periodic() {
38+
double targetAltitude = 100;
39+
drone.fly(calculate(drone.getAltitude(), targetAltitude))
40+
}
41+
42+
/* calculates the output of the PID controller given the error (input) */
43+
double calculate(double currentPosition, double targetPosition) {
44+
double error = targetPosition - currentPosition;
45+
double currentTimestamp = Timer.getFPGATimestamp();
46+
// amount of time that passed since the last time the controller was run
47+
double deltaTime = currentTimestamp - lastTimestamp;
48+
accumulatedError += kI * error * deltaTime
49+
double derivative = (error - previousError) / deltaTime;
50+
51+
// update values for next time this method is called
52+
lastTimestamp = currentTimestamp;
53+
previousError = error;
54+
55+
return kP * error + accumulatedError + kD * derivative;
56+
}
57+
```
58+
59+
For those that know calculus, the formal definition of PID control is:
60+
61+
$$ u(t) = K_{p}e(t) + \int_{0}^{t}e(\tau)d\tau + K_{d}\frac{de}{dt} $$
62+
where u(t) is the control effort (amount of feedback at time t), e(t) is the error at current time t, and \\(\tau\\) is the integration variable. Do not worry about the formula as long as you understand the video and how the code works.
63+
64+
### **PID in a nutshell:**
65+
![PID Shorthand Explanation](pid_shorthand_explanation.png)
66+
(I'm too lazy to draw all the red lines representing kI)
67+
68+
If you want more details, WPIlib has an [article of PID](https://docs.wpilib.org/en/stable/docs/software/advanced-control/introduction/introduction-to-pid.html).
69+
70+
## Tuning
71+
How do you find kP, kI, and kD? What are the optimal values of these constants? What is optimal?
72+
73+
In general, the "optimal" PID controller gets the error to zero as fast as possible, while not overshooting or oscillating. For the following graphs, the red line represents the target/goal while the purple line represents the current position. With the ideal constants, you should get close to the 3rd graph.
74+
75+
![PID Tuning Graphs](pid_tuning_graphs.png)
76+
77+
To get those ideal constants... you kind of just guess and check. WPILIB provides a nice simulation of how it is like to tune these constants. Go to this [page](https://docs.wpilib.org/en/stable/docs/software/advanced-controls/introduction/tuning-flywheel.html) and skip everything until you get to "Pure Feedback Control". Follow the instructions and see if you can get the optimal tuning solution.
78+
79+
## Other constants/terms
80+
81+
### kIz or "I-Zone"
82+
Sometimes, the I term can accumulate error very fast and overshoot the target. In that case, we only want the I term to be accumulating error when the error is smaller than a certain threshold. The "I-Zone", typically denoted as kIz, lets you set that threshold.
83+
84+
### kF or "Feed-Forward Gain"
85+
This is a sneak peek to what will be discussed in the Feedforward section, but given the target, what is the estimated motor output necessary to get to the target? Say for example we need get a motor to a certain velocity. It probably needs a set amount of voltage to get to that speed, so we should just add it. Note that this is different from kP since kP contributes proportionally to the error, not the target. kF is usually only used for velocity or current (draw) closed loop control, and even then not really used most of the time. The content discussed in the Feed-forward section essentially does what kF does, but better. However, sometimes you will see this constant in other documentation so it is nice to know what it is.
86+
87+
### kMaxOutput, kMinOutput
88+
Should be self-explanatory, used to make sure you don't give your mechanism too much power
89+
90+
### setReference(), setSetpoint(), etc
91+
There are many names for "target", such as "reference", "setpoint", and more. When tuned properly, after you set the target the motor should drive to the setpoint.
92+
93+
There are many other methods and configurations that are used to PID control which you can find in the documentation.
94+
95+
## Implementation
96+
You remember the code used to implement PID shown near the beginning of this page? Often, one does not need to implement PID Control from the ground-up. WPILIB and many motor controllers have PID controllers built into the class. All that needs to be done is set the setpoint, kP, kI, and kD (as well as other configurations that you may want).
97+
98+
!!! warning
99+
Ever since the last time this website was updated (2024), the team has not used motors from the CTRE Phoenix API. The information regarding the PID implementation of the CTRE Phoenix motors may be outdated. However, SparkMaxes and other motors should be updated.
100+
101+
For example, all [`BaseMotorControllers`](https://www.ctr-electronics.com/downloads/api/cpp/html classctre_1_1phoenix_1_1motorcontrol_1_1can_1_1_base_motor_controller.html) in the CTRE Phoenix API (Talon_SRX and Victor_SPX) can do PID as follows:
102+
103+
``` Java
104+
// Config
105+
motor.config_kP(0, kP);
106+
motor.config_kI(0, kI);
107+
motor.config_kD(0, kD);
108+
// Tell the PID loop how close we want to get to the setpoint in sensor units
109+
motor.configAllowableClosedloopError(0, closeness);
110+
// Tell the PID loop which sensor to use. In this case use a quadrature encoder
111+
motor.configSelectedFeedbackSensor(FeedbackDevice.QuadEncoder);
112+
// Move to 0 on the selected sensor
113+
motor.set(ControlMode.Position, 0);
114+
```
115+
116+
And for SparkMax, SparkFlex, or other Rev motor controllers, we use the [`SparkPIDController`](https://codedocs.revrobotics.com/java/com/revrobotics/sparkpidcontroller) (Take a look at the javadocs). Notice how there are other methods that let you control the velocity, acceleration, setting target, and more:
117+
``` Java
118+
CANPIDController pidController = motor.getPIDController();
119+
// Config
120+
pidController.setOutputRange(-1.0, 1.0);
121+
pidController.setP(kP, 0);
122+
pidController.setI(kI, 0);
123+
pidController.setD(kD, 0);
124+
// Tell the PID loop how close we want to get to the setpoint in rotations
125+
pidController.setSmartMotionAllowedClosedLoopError​(closeness, 0);
126+
127+
// Move to 0 on the quadrature encoder
128+
pidController.setReference​(0.0, ControlType.kPosition, 0)
129+
```
130+
131+
For general purposes, you can use WPILIB's [`PIDController`](https://github.wpilib.org/allwpilib/docs/release/java/edu/wpi/first/math/controller/PIDController.html) class:
132+
``` Java
133+
PIDController pidController = new PIDController(kP, kI, kD);
134+
pidController.setSetpoint(0);
135+
// Tell the PID loop how close we want to get to the setpoint in rotations
136+
pidController.setTolerance(closeness);
137+
138+
// This code is assumed to be in a method or command called frequently.
139+
double state;
140+
if (!pidController.atSetpoint()) {
141+
// getError() and update() are not actual functions. They are placeholders for your own code.
142+
// Get the current state of what is being controlled
143+
error = getError();
144+
// Do something with the adjustment
145+
update(pidController.calculate(error));
146+
}
147+
// Only use this line once the error is "close enough"
148+
pidController.reset();
149+
```
150+
151+
You need to check out the documentation for each of these classes and familiarize youself with them.
152+
153+
# Conclusion
154+
Thankfully, most of the math is handled by WPIlib or motor controller firmware. However, it is important to understand what is actually happening so that you can properly tune your control loops.
155+
156+
But PID is just the beginning. There are many more complicated and more powerful control methods built upon PID that will be discussed later in this section, including Following Trajectories using PathPlanner and Drivetrain Characterization. In addition, PID is often not enough to properly control a mechanism, feedforward algorithms are also needed...
157+
158+
***
159+
160+
> **xkcd #689: FIRST Design**
161+
>
162+
> ![FIRST](https://imgs.xkcd.com/comics/first_design.png)
163+
>
164+
> You might use PID to control the elevator.
165+
>
166+
> _<https://xkcd.com/689/>_

docs/section-7/pid-control.md

Lines changed: 0 additions & 76 deletions
This file was deleted.
107 KB
Loading
39.6 KB
Loading

0 commit comments

Comments
 (0)