Skip to content
CrocoDocs
Starter GuideProgrammingEngineeringDesignPortfolio
Documentation

Introduction

IntroductionBIOBUZZ game overview

Getting started

Getting startedBlocksOnBot JavaAndroid StudioYour first OpModeJava basicsMotors and servosNonblocking codeDebugging robot code

Control systems

Control systemsJoystick mappingField-centric mecanum drivePID controlFeedforwardFlywheel velocity controlSystem identificationMotion profilingKalman filterLow-pass filter

Autonomous

AutonomousTimed and encoder movementOdometryLocalization troubleshootingMotion planningReliable autonomous sequencesPure PursuitSensor fusionAuto to TeleOp handoff

Season topics

Season topicsProjectile mathematicsTurret aimingShooting on the move

Code practices

Code practicesNaming conventionsCode organizationLoop timing and bulk readsFormattingComments and documentationTeam collaboration

Libraries

LibrariesNextFTCFTCLibSolversLibPedro PathingRoad RunnerFTC DashboardMercurial v2Mercurial v1PanelsSloth

Community software

Community softwareBlaze FTCOpenLoopHive Vision

Sensors and vision

Vision overviewVision basicsLimelight 3A
Starter Guide
Engineering
Design
Portfolio
Appearance

Flywheel velocity control

Choose one velocity controller, convert encoder units, and wait for measured recovery before feeding

Control a flywheel's speed, then check that speed before feeding the next piece. Repeatedly changing gains will not fix an unplugged , an unreachable speed, or a feeder that launches the next ball before the wheel recovers.

Choose one controller

Approach mode and commandWhere the velocity feedback runs
Hub velocity controlRUN_USING_ENCODER with DcMotorEx.setVelocity()REV motor controller
Your own PID/feedforwardRUN_WITHOUT_ENCODER with setPower()Your control loop

RUN_TO_POSITION is a position target, not the normal choice for a continuously spinning flywheel. Do not run an external power-based velocity PID on top of the hub's velocity regulation by accident. Pick one owner and one interpretation of its output.

Encoder units

The one-argument setVelocity() and getVelocity() use ticks per second, not . Let CfC_fCf​ be the encoder counts produced by one complete flywheel revolution, including any gearing between the encoder and flywheel:

ticks/s=flywheel RPM Cf60,flywheel RPM=60 ticks/sCf\text{ticks/s}=\frac{\text{flywheel RPM}\,C_f}{60},\qquad \text{flywheel RPM}=\frac{60\,\text{ticks/s}}{C_f}ticks/s=60flywheel RPMCf​​,flywheel RPM=Cf​60ticks/s​

Check whether a motor specification describes the encoder or output. Do not apply the gearbox ratio twice. Verify the sign and counts by rotating the unloaded a known amount before a powered test.

For example, suppose a measured assembly produces 28 counts per flywheel turn. A target of 3,600 RPM becomes 3600×28/60=16803600\times28/60=16803600×28/60=1680 ticks/s. A measured 1,540 ticks/s becomes 1540×60/28=33001540\times60/28=33001540×60/28=3300 RPM, so the wheel is 300 RPM below target. The 28-count value is illustrative; using a gearbox-output specification for a different shaft changes the result.

These SDK 12 fragments belong in an . Set COUNTS_PER_FLYWHEEL_TURN from your assembly, and targetRpm from a measured operating range:

// During initialization. Import DcMotor and DcMotorEx.
DcMotorEx flywheel = hardwareMap.get(DcMotorEx.class, "flywheel");
flywheel.setMode(DcMotor.RunMode.RUN_USING_ENCODER);

// In the active control loop, after checking a finite, nonnegative target
// and a positive, finite COUNTS_PER_FLYWHEEL_TURN:
double requestedTicksPerSecond = targetRpm * COUNTS_PER_FLYWHEEL_TURN / 60.0;
flywheel.setVelocity(requestedTicksPerSecond);
double measuredTicksPerSecond = flywheel.getVelocity();
double measuredRpm = measuredTicksPerSecond * 60.0 / COUNTS_PER_FLYWHEEL_TURN;

Start with a low, mechanically appropriate test speed and a guarded flywheel. On cancellation and STOP, command zero velocity and zero power in the OpMode's cleanup. Verify that the encoder responds before increasing speed; a missing or reversed feedback signal can make a controller demand excessive output.

Tune and measure

Begin with one flywheel at a fixed target. Record target speed, measured speed, battery , commanded output when available, and the instant a ball enters. Measure unloaded regulation and loaded recovery separately.

For hub control, setVelocityPIDFCoefficients(p, i, d, f) configures its velocity gains. Those coefficients use the hub's controller conventions; they are not interchangeable with a custom controller's normalized-power gains.

For custom control, establish the sign with error = target - measured, then combine feedback with a fitted velocity/feedforward model. Check saturation before increasing integral gain. A motor already receiving its maximum available output cannot reach an arbitrarily high target. Use system identification for voltage-based coefficients and consistent battery compensation.

Two mechanically linked motors need compatible directions and targets. If one fluctuates, compare encoder traces, wiring, loading, and controller settings before declaring the motor defective. A common shaft can make two independently misconfigured controllers fight each other.

Gate the feeder

Define a ready state from measured behaviour:

  1. The requested speed is positive and inside the calibrated range.
  2. The encoder data is valid and recent.
  3. The measured speed remains within the chosen RPM for a settling interval.
  4. The pose, turret, and hood satisfy their own conditions.

Reset that settling interval whenever speed leaves tolerance, the target changes, or a ball is fed. Permit one feed event, confirm that the piece cleared, then wait for recovery again. Give recovery a deadline and report a failure instead of waiting forever.

For an illustrative 3,600 RPM target, ±100 RPM band, and 0.15-second settling interval, a trace might look like this. Assume the other readiness conditions pass and the control loop keeps sampling between rows:

Time after spin-up beginsMeasured RPMSpeed gate
0.20 s3,300Outside the band; not ready
0.30 s3,540Enter the band; start settling
0.40 s3,480Leave the band; reset settling
0.50 s3,560Re-enter; start a new interval
0.65 s3,590Ready if every intervening sample stayed in the band
0.67 s, after one feed3,180Reset readiness and wait for measured recovery

Checking only the first and last row cannot prove settling. A telemetry display may update less often than the control loop; evaluate the gate on each fresh control measurement.

A fixed delay may work over a narrow tested setup, but measured recovery adapts to the actual speed dip. Faster feeding can reduce accuracy if the wheel has not recovered. Compare hit rate and the complete multi-ball time using the same ball condition, compression, range, and battery conditions.

Diagnose the miss

ObservationInvestigate
Speed units are off by a constant factorEncoder counts, RPM conversion, and gearing
Speed never reaches target and output saturatesAvailable motor speed/, battery, friction, and compression
First shot works; following shots fall shortRecovery, feeder timing, and ball contact
Speed recovers but shots still varyHood position, ball condition, alignment, and mechanical consistency
Tuning changes appear on screen but not on the Whether control rereads the live fields and whether the dashboard matches the installed libraries

For shot calibration, continue with projectile mathematics. Add shooting-on-the-move compensation after stationary shots and feeding are repeatable.

Sources

  • FTC SDK 12 RobotCore source — DcMotorEx velocity units and PIDF methods.
  • FTC SDK 12 Hardware source — LynxDcMotorController velocity and motor-mode implementation.
  • REV: encoder feedback and motor control

Feedforward

Add a measured gravity term to an arm controller and check its assumptions

System identification

Measure a mechanism's voltage, speed, and acceleration to fit and test a feedforward model

On this page

Choose one controllerEncoder unitsTune and measureGate the feederDiagnose the missSources