Profiling a subsystem to get PID and FF constants - quasics/quasics-frc-sw-2015 GitHub Wiki
Generating good PID/feedforward values for a flywheel, turret, or any other system is really important for ensuring that we've got a stable shooter that will reliably do what you want. And there's a couple of approaches that can generally work, though the details will vary depending on what you're working on. (But pay attention to the following caveats.)
Caveats
- Some of the examples provided below assume that we're using onboard closed-loop control built into a specific motor (e.g., a SparkMax or a Talon), vs. other motors or the WPILib's
PIDController. Adjust accordingly if that assumption is broken.- For example, for information on tuning a flywheel using a CTRE TalonFX controller, you'd want to look at their documentation on SysId integration and extracting signal logs.
- Similarly, if you're tuning a system using a Thrifty Nova, you'll want to check out their docs on PID configuration.
- Using onboard closed-loop control is usually much better than using the WPILib controller, simply because it will be much more responsive to external changes (e.g., due to the flywheel actually starting to move something) because of its faster cycle time (e.g., 1000x per second with a SparkMax vs. ~50x per second with WPILib). On the other hand, it's easier to debug what's going on (if you're seeing unexpected behavior) if you're using the WPILib controller, since that's fully handled in your code, rather than "set it and forget it" on an embedded controller.
Profiling a flywheel for a shooter
Basic approaches
Option 1: Use the SysId tool
Using the SysId tool that comes with the development environment is arguably the best way to go about things, and is likely to give you the best results: it's going to look at a broad spread of data values, and does a lot of math to generate settings that hopefully should be optimized for your setup (vs. "seat of the pantsing it").
However, there's more work that's involved with this approach, so if you need something quick and dirty, keep reading for another approach....
Steps you'll need to take
- You need to set up the standard SysIdRoutine commands for the subsystem, but this isn't too hard. (And there's plenty of examples to choose from, including in our codebase.)
- When analyzing the data, you'll select:
- "Simple motor" as the mechanism type.
- "Velocity" (not "Position") as the analysis type.
- "Rotations" as the units.
- "1.0" for the units/revolution (if you aren't gearing the motor to the flywheel).
- "REV Brushless Encoder Port" as the gain presets (in the "Feedback analysis" block).
Option 2: Manual characterization
This is a fast, generally simple approach, but is also less precise than using SysId to really get the values dialed in.
Steps you'll need to take
- Start by setting kP, kI, and kD to 0.
- Figure out the feedforward value by increasing the feedforward gain until the flywheel reaches your target RPM (see below) using only feedforward.
- For this target value, we'll aim for the RPM to be right around (or just below) what we think we want to use for the shooting speed.
- Note that this means that we can also generate different values if we want to have different speeds for different ranges, etc.
- Gradually increase kP until the flywheel comes back up to speed quickly after we fire the ball.
- This is where logging/displaying the motor speed within the dashboard is helpful (if not essential), though a "calibrated eardrum" may be a little helpful in trying to find this this (by listening to the motor speed).
Also worth noting
- For flywheels, you can generally ignore kI and kD. The latter can cause instability, and usually isn't needed; if we see a persistent small gap between the target RPM and what we're actually getting out of the subsystem, then try adding a tiny bit of kI. (This will add up quickly.)
- kS usually isn't a factor for a high-speed flywheel, so you can generally get away with treating this as 0.
- kP will usually be a very small number (e.g., 0.0001 to 0.0005) because of the high-speed updating provided by the onboard control. (For WPILib PID control, it'll still be small, but not nearly as small.)
- If you see the motor stuttering or making a high-pitched noise, the kP value is too high for the update cycle, and you need to reduce it.
- If you change your hardware (e.g., swap in a new motor, even if it's the same type, or alter the wheels, etc.), you're likely to need to reprofile the setup, since it can alter key characteristics of the system (motor efficiency, mass, etc.). But you'll have done this once already, so a second pass will usually go faster, especially since your prior values may provide an informed guess for a starting point.
Profiling to guide a turret's position
TODO: Add details, expanding on the following notes
(Please note that the following is theoretical on the author's part, since Quasics has never built a rotating turret for a shooter. However, it's based on information shared by those that have, and generally makes sense from a "just physics" angle. Please feel free to provide corrections as needed!)
Differences from flywheel control
While flywheel control is about velocity (steady state speed), a rotating turret is about position control. This introduces a few new challenges, primarily related to things like:
- Handling cable drag associated with the turret, which can cause lag in adjustments if you're only configuring PID
- Subtle differences in the PID values you'll want to use
- Managing a physical range of motion (soft limits)
- The "wraparound" logic of a circular axis
The "cable drag" factor
The biggest "real world" problem (vs. simulation) that you will face is cable drag. As the turret rotates, the wires will pull back against the motor, slowing it down.
If the turret gets close to the target but stops 1 or 2 degrees short, increase your kI (Integral) or add a small kS (Static Feedforward) to overcome that initial friction and cable pull.
But the real solution is to use "feedforward". While PID is reactive (it waits for an error to happen, then fixes it), feedforward is proactive. It calculates exactly how much voltage the motor needs to overcome physical forces before it even starts moving.
As a result, making sure that you have values calculated for at least kS is the secret to getting a turret to "lock on" instantly. Without it, the PID controller has to "wind up" its error (Integral) to overcome the friction of the gear teeth and the wires. By the time it has enough power to move, it often "pops" and overshoots the target.
Key PID differences from flywheels
For a turret, your goal is to minimize steady-state error so that the turret doesn't "hunt" or oscillate when it's supposed to be locked on a target.
- P (Proportional): The primary "snap." If the turret is 20° off, P provides the torque to get it moving.
- D (Derivative): This is usually ignored for flywheels, but is critical for turrets. It acts as a "damper" to prevent the turret from overshooting the target as it arrives.
- I (Integral): This is often used in small amounts to overcome friction, or the pull of heavy wire bundles that might prevent the turret from reaching the exact center.
Soft limits
A turret usually cannot spin 360° infinitely because of the wires (the "umbilical cord"). You must set Soft Limits in the code so the motor stops itself before it rips the wires out.
For example, if you were using a TalonFX for your turret, you might want to use settings something like:
config.SoftwareLimitSwitch.ForwardSoftLimitEnable = true;
config.SoftwareLimitSwitch.ForwardSoftLimitThreshold = 0.5; // Half rotation
config.SoftwareLimitSwitch.ReverseSoftLimitEnable = true;
config.SoftwareLimitSwitch.ReverseSoftLimitThreshold = -0.5;
Continuous input (wraparound)
If your turret is capable of spinning 360° (using a slip ring), you should enable Continuous Input. This tells the PID controller that 359° and 1° are only 2° apart, rather than 358° apart.
Approach 1 - Use SysId
This uses the same general technique as profiling a flywheel or drivebase, but there are a few key differences that you need to keep in mind.
Things of which you should be aware
Mechanical limits (the "rip" risk)
Most turrets are not continuous 360° rotations. SysId works by sending voltage pulses to the motor, and during the Quasistatic test, the motor will move slowly but steadily.
The danger here is that if you don't stop the test in time, the motor will drive the turret straight into its hard stops, potentially stripping gears or snapping the wiring harness.
Addressing this risk:
- Start the turret at one extreme end of its travel before running Quasistatic (slow ramp) tests, so it has the maximum "runway" to move in the other direction.
- Note: for Dynamic (fast jerk) tests, you'll want to put it in the center.
- Set the Step Voltage in SysId to a low value so the turret doesn't move too fast to react.
- Have someone ready at the spacebar (emergency stop) on the laptop.
Directional bias (the "wire drag" problem)
Unlike a drivetrain, a turret often requires more force to turn in one direction than the other because of the resistance of the wire bundle.
The issue here is that if you only profile in one direction, your kS (static friction) value will be inaccurate for the other direction.
To address this, you'll want to bear in mind that SysId typically runs tests in both forward and reverse. Ensure your wires are routed exactly as they will be during a match. If the "pull" from the wires is significant, you may need to take the average of both directions or use the more conservative (higher) value.
Gearbox backlash
Many FRC turrets use high-reduction gearboxes (like a VersaPlanetary) or large ring gears. If there is "slop" or play in the gears, SysId will pick up that tiny movement before the turret actually starts rotating.
The issue here is that this can result in a kS value that is too low, causing the turret to "stutter" when it tries to start moving.
To addres this, you should ensure the turret has a slight load on it or that the gears are properly tensioned. When looking at the SysId data, look for "noise" at the very beginning of the velocity graph.
High reduction vs. resolution
Turrets usually move much slower than flywheels or drivetrains but require much higher precision.
The issue here is that if your encoder is on the motor (before the gearbox), the "counts per degree" is huge. If it's on the turret itself, the resolution might be too low for SysId to get a clean acceleration curve.
Addressing this risk is simple: ensure your encoder CPR and gearing ratio are entered perfectly into the SysId tool. If using a TalonFX, the built-in rotor encoder is usually the best source for profiling data. (The same may be true for other controllers.)
Soft limits while profiling
During characterization, the motor controller's built-in "soft limits" can interfere with the test data by cutting voltage prematurely.
As a result, you'll want to temporarily disable soft limits in your SysId Routine code, but be doubly vigilant with the physical safety of the robot. You want "pure" voltage-to-movement data without the controller intervening.
SysId settings to use
When analyzing the data, you'll select:
- Analysis Type: General or Position.
- Units: Rotations or Degrees. (Using Rotations is usually easier because it matches the internal math of the TalonFX/SparkMax.)
- Total Gearing: the ratio from the motor's internal encoder to the actual turret ring. (For example, if your motor turns 100 times to move the turret once, your gearing is 100:1.)
- If this is wrong, your
kVcan be off by an order of magnitude (or more), and your turret will either crawl at a snail's pace or slam into the hard stops.
- If this is wrong, your
- Gain Schedule: Select Position.
- Measurement Delay: For most FRC setups, a value between 10ms and 20ms is standard. This accounts for the time it takes the signal to travel over the CAN bus.
- Controller Period: Set this to 0.001s (1ms) if you are using a TalonFX or SparkMax with the PID loop running on the hardware. If you are running the PID loop in your
periodic()method, set it to 0.02s (20ms).
SysId doesn't just give you one kP value; it lets you decide how aggressive the turret should be using the LQR (Linear Quadratic Regulator) sliders.
- Max Error: This is the "tolerance." How many rotations/degrees is an "acceptable" mistake? For a turret, you might set this to 0.01 rotations (about 3.6°).
- If the turret is "jittery", you can increase the Max Error slider. This will lower the calculated
kPand make the turret less twitchy.
- If the turret is "jittery", you can increase the Max Error slider. This will lower the calculated
- Max Control Effort: Usually set to 12.0 (representing 12 Volts).
Because turrets are prone to backlash (slop in the gears), your velocity data might look "noisy."
- Window Size: If the velocity graph (top left) looks like a jagged saw blade, increase the Window Size to smooth the data.
- Trim: Use the "Trim" tool to cut off the data at the very end of the run where the turret might have hit a limit or the operator let go of the button.
Sanity checking the results
When you get your results, look at the R-squared (r^2) value for the Velocity vs. Voltage graph.
- 0.95 or higher: Excellent. Your
kVis reliable. - Below 0.90: Something is wrong. Usually, this means the turret was binding, the wires were pulling too hard, or the battery was dying.
- If you are getting a high
kS(static) value, but the turret still won't move when you command it, check if you profiled it while the robot wasn't fully assembled. The friction changes significantly when the turret is carrying a heavy shooter assembly!
A final tip
After SysId gives you a kS value, it's good to manually test it.
For example, let's say that SysId says kS is 0.15V.
- Try to move the turret with
0.14Vin the code. If it doesn't move, the value is good. - If the turret is able to move at a value like
0.10V(vs. the0.15Vvalue), the SysId test was likely skewed by gravity or momentum, and you should lower the value to avoid "jitter."
Approach 2 - Manual tuning
If you don't want to use the full SysId tool (or need something fast and can settle for quick-and-dirty), you can tune kS and kV manually:
- Tune kS: Slowly increase voltage to the motor until it just starts to move. That voltage is your kS.
- Tune kV: Command the motor to run at a set voltage (e.g., 6V). Measure the steady-state velocity.
kV = Voltage/Velocity. - Tuning for Turrets: Remember to tune it while the umbilical cord (wires) is attached! The resistance will be different depending on which direction the turret is turning.
You can then follow the general approach for PID calculations that was outlined for flywheel control.