Mini-Project 3: A Velocity-Controlled Flywheel Shooter
Build a flywheel: reason about moment of inertia and spin-up, pick a high-speed motor, and write SimpleMotorFeedforward + velocity PID that recovers RPM between shots.
Sign in to track progress, earn XP, and save lessons.
The goal
A flywheel shooter that holds a target surface speed and recovers quickly after each game piece. We'll size the wheel and write velocity control that doesn't sag on every shot.
Step 1 — Why flywheels are a velocity problem
Unlike arms/elevators, a shooter cares about angular velocity, not position. Each shot robs energy (RPM drops), and your control loop must shove it back fast. The energy stored is E = 0.5 * I * omega^2, where I is the wheel's moment of inertia.
Step 2 — Wheel and ratio
Use a 4 in stealth/compliant wheel pair. A direct or light reduction keeps speed high. A Kraken X60 (WCP/CTRE) free-spins at 6000 RPM in trapezoidal commutation (5800 RPM with FOC, per the WCP/CTRE Kraken X60 motor-performance docs); run it near direct drive (1:1 to 1.5:1) so the wheel spins fast. Higher wheel inertia = more stable exit velocity but slower recovery, a classic tradeoff documented in the 1678 Rapid React shooter writeup (backrollers, flywheel mass, hood actuation).
Step 3 — Velocity control code
For velocity you combine SimpleMotorFeedforward (predicts the voltage for a target speed) with a small kP that closes the gap on disturbances. You can run it on the Talon FX's onboard velocity loop or in code:
private final SimpleMotorFeedforward ff =
new SimpleMotorFeedforward(0.18, 0.123, 0.011); // kS, kV, kA (volts per rps)
private final PIDController pid = new PIDController(0.05, 0, 0);
private double targetRps = 0;
public void setTargetRps(double rps) { this.targetRps = rps; }
@Override
public void periodic() {
double measured = encoder.getVelocity(); // rotations/sec
double ffVolts = ff.calculate(targetRps);
double pidVolts = pid.calculate(measured, targetRps);
motor.setVoltage(ffVolts + pidVolts);
}
public boolean atSpeed() {
return Math.abs(encoder.getVelocity() - targetRps) < 2.0; // gate the feeder
}
Step 4 — The recovery trick
Never feed the next game piece until atSpeed() returns true. This is the single biggest reliability fix for shooters: an interlock that waits for RPM recovery prevents inconsistent shots. kV dominates here (volts to maintain speed), kA matters during spin-up, and kS overcomes static friction; get these from a SysId quasistatic+dynamic test, not by guessing.
Step 5 — Mechanical notes
- Use a backroller or top roller to add backspin for a flat, repeatable arc.
- Run the flywheel on a 1/2 in hex shaft with a heavy-duty hex bearing (e.g. AndyMark am-2986, 1/2 in hex ID, 1.125 in OD) so set-screw slip can't desync your encoder.
- Balance the wheel: an unbalanced flywheel at thousands of RPM shakes the whole superstructure and loosens fasteners over a match.
Key takeaways
- Flywheels are velocity-controlled: combine SimpleMotorFeedforward (kS/kV/kA) with a small kP for disturbance rejection.
- Gate the feeder on an atSpeed() check so the next game piece only fires after RPM recovers, the top reliability fix for shooters.
- Wheel inertia trades exit-velocity stability against recovery speed; characterize gains with SysId rather than guessing.
Go deeper
Lesson quiz
RequiredAnswer all 3 questions correctly to complete this lesson.
1.Why is a flywheel shooter treated as a velocity-control problem rather than a position-control problem?
2.What combination does the lesson use to hold flywheel speed and reject the disturbance of a shot?
3.What is described as the single biggest reliability fix for a flywheel shooter?
Answer every question to submit.