🎾 Control Algorithms · Flywheel

Take Back Half

TBH is a single-gain velocity controller that outperforms bang-bang for flywheel control with almost no added complexity. One parameter to tune. Dramatically less oscillation. The right tool when your game has a launcher, catapult, or disc shooter.

1
How It Works
2
Implementation
3
Tuning
// Section 01
The Take Back Half Concept
TBH works like a smart integrator. It accumulates error over time — like PID's I-term — but when the error crosses zero (the motor passes the target velocity), it takes back half the accumulated output instead of just continuing to integrate.
💡
The key insight: when the flywheel velocity passes through the target (error changes sign), TBH cuts the output estimate in half. This prevents the overshoot that makes a pure integrator oscillate — instead of sailing past and correcting back, TBH converges to the target from one side.

Why TBH Beats Bang-Bang for Flywheels

ℹ️
TBH is specifically designed for systems that accelerate faster than they decelerate — which describes most VRC flywheels exactly. The motor spins up quickly under full power but loses speed slowly due to flywheel inertia. TBH’s asymmetric handling of positive vs negative error matches this behavior well.
// Section 02
Complete TBH Implementation
The full algorithm in ~20 lines. One gain constant, one state variable.
include/flywheel.hpp
#pragma once void flywheelSetTarget(double rpm); void flywheelUpdate(); // call every 10ms in a task bool flywheelAtSpeed(); // true when within tolerance
src/flywheel.cpp
#include "main.h" #include "flywheel.hpp" // ── TBH state ───────────────────────────────────────────────────────── static double tbh_output = 0; // current motor output (0.0 - 1.0) static double tbh_prev = 0; // the "take back half" reference static double tbh_error = 0; // last loop's error static double tbh_target = 0; // target RPM // ── TBH gain — start at 0.0005, tune up if too slow, down if overshoot const double TBH_GAIN = 0.0005; const double AT_SPEED_TOLERANCE = 50; // RPM void flywheelSetTarget(double rpm) { tbh_target = rpm; tbh_output = 0; // reset on target change tbh_prev = 0; } void flywheelUpdate() { double velocity = flywheel.get_actual_velocity(); double error = tbh_target - velocity; // Accumulate output (like an integrator) tbh_output += TBH_GAIN * error; tbh_output = std::clamp(tbh_output, 0.0, 1.0); // "Take back half" — when error crosses zero, average with last reference if ((error >= 0) != (tbh_error >= 0)) { tbh_output = 0.5 * (tbh_output + tbh_prev); tbh_prev = tbh_output; } tbh_error = error; flywheel.move((int)(tbh_output * 127)); } bool flywheelAtSpeed() { return abs(tbh_target - flywheel.get_actual_velocity()) < AT_SPEED_TOLERANCE; }
src/main.cpp — run TBH in a background task
// In initialize() — start the flywheel control task pros::Task fw_task([](){ while(true) { flywheelUpdate(); pros::delay(10); } }); // In opcontrol() — set target and fire when ready flywheelSetTarget(3000); // start spinning at 3000 RPM if (master.get_digital_new_press(DIGITAL_R1) && flywheelAtSpeed()) { fireIndexer(); // only fire when flywheel is at target speed }
// Section 03
Tuning TBH_GAIN
One parameter. Two symptoms. Easy to fix.
Tuning procedure: set target RPM, start a timer, watch the Brain screen’s motor velocity until it stabilizes. Good TBH converges in under 2 seconds with no visible overshoot. Log the gain value that works in your notebook — it counts as testing data for the Design Award.
ℹ️
The gain varies with gear ratio and flywheel mass. A heavier flywheel needs a smaller gain (more inertia, slower to change speed). A lighter flywheel needs a larger gain. Always retune when the mechanical design changes.
⚙ STEM Highlight Mathematics: Convergence, Overshoot & Velocity Control
Take Back Half exploits a key property of asymmetric systems: flywheels accelerate slowly (high inertia) but decelerate quickly (friction + inertia). TBH’s “take back half” operation — averaging current output with previous output whenever the sign of error changes — is a bisection algorithm applied to control output. Each crossing bisects the search interval, converging toward the steady-state output value geometrically (halving the error bound each cycle). The mathematical guarantee: the output converges to the true steady-state value from both sides, eliminating the bang-bang limit cycle.
🎤 Interview line: “TBH uses a bisection algorithm — each time error crosses zero, we halve the output adjustment. This is a classic numerical methods technique for root finding. It guarantees convergence because we approach the equilibrium from alternating sides, narrowing the interval by half each crossing.”
🔬 Check for Understanding
TBH divides the output by 2 each time the error crosses zero. After 5 zero-crossings starting from an initial output error of 0.8, what is the maximum remaining output error?
0.4
0.025
0.1
0.05
Related Guides
⚡ Bang-Bang Controller →🎯 Flywheel Shooters →📊 Data Logging →
← ALL GUIDES