Skip to content
Mechanical, Build & Pneumatics·Lesson 35 of 47

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.

Lesson quiz

Required

Answer 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.