The 2026–27 Override Hero Bot is the team's second training robot — what the Clawbot was for fundamentals, Flex is for game-relevant practice. Build it from the kit, program it with EZ-Template, and add sensors one at a time on the path to competition.
The Clawbot's value is its simplicity — one drive, one arm, one claw, no game-specific mess. Flex's value is the opposite: it's the actual game robot, with the same scoring mechanisms a competition robot will have. Once a student has finished the Clawbot curriculum, the Flex is the next step before they touch the team's competition robot.
Same four-track structure as the Clawbot — one robot, four parallel training tracks. Each track produces a notebook artifact. Tap a track to see what's involved.
| Aspect | Clawbot | Flex | Why It Matters |
|---|---|---|---|
| Game-relevance | None (synthetic) | Override game robot | Practice transfers to real matches |
| Drive motors | 2 (red cartridge) | 2 (green cartridge) | Flex is faster; PID retune required |
| Wheels | 4" standard | 4" omni (modified) | Omni allows pivot turns; no scrub |
| Mechanisms | Arm + claw | Lift + claw | Same code patterns, real geometry |
| Sensors day-one | None (add IMU) | IMU only (added) | Both need pots/limits/optical later |
| Notebook value | Build log + drills | Full EDP comparison opportunity | Flex is a real "iteration target" |
The V5 Inertial Sensor (IMU) is what makes chassis.pid_turn_set(90, 110) actually turn 90 degrees instead of guessing from wheel rotations. On Flex with omni wheels, this matters even more than on Clawbot — omnis can slip during pivot turns, and wheel-encoder-derived heading would be wrong. The IMU reads angular velocity from a vibrating-MEMS gyroscope and integrates it over time to produce heading.
chassis.initialize() at the start of initialize() — the robot must sit perfectly still for 2-3 seconds while calibration runs. If the robot moves during this window, the heading will be off by exactly that amount for the whole match. Plug the brain in BEFORE positioning the robot on the field.Every V5 smart motor has an internal encoder. After the chassis spins, you can read total ticks via chassis.drive_sensor_left() and chassis.drive_sensor_right(). EZ-Template uses these internally for distance PID. You can also read the lift and claw motor positions:
Before the first time you use the IMU in code, confirm it's actually working with a 30-second test:
pros terminal from your project folder.Pick the robot up, rotate it 90° clockwise by hand. The terminal should show heading change from ~0 to ~90. Rotate another 90° — should read ~180. If the number moves at all but the magnitude is off, the IMU mounting orientation is wrong (it should be flat with the chip parallel to the ground). If the number doesn't change, check the port.
chassis.imu_get_rotation() instead, which returns a continuous rotation count (-720, -90, 45, 270, 540...).From a stock Flex with just the IMU and motor encoders, you can do all of this:
You cannot do any of this until you add the sensors in Section 6:
That gap — what the bare robot can do vs. what a sensored robot can do — is what makes Flex such a good training platform. Every sensor adds capability you can see and measure.
Your team has settled on this port assignment for Flex. Use the same in code, on the wiring diagram, and on the engineering notebook page. Mismatches between any of those three are how an entire afternoon gets eaten by a bug that turns out to be a swapped cable.
| Port | Device | Purpose | Polarity |
|---|---|---|---|
| 6 | Smart Motor | Left drivetrain | Reversed |
| 4 | Smart Motor | Right drivetrain | Forward |
| 13 | Inertial Sensor | Heading + tilt | — |
| 15 | Smart Motor | Claw | Verify on bench |
| 17 | Smart Motor | Lift | Verify on bench |
Download EZ-Template 3.2.2 from github.com/EZ-Robotics/EZ-Template if your team doesn't have a clean copy. Unzip the Example Project. Open the folder in VS Code (or wherever your team writes PROS code).
The starter project has working defaults — you can build and upload before changing anything. Verify the upload works first (with the robot off the ground): pros mu in the terminal. The brain screen should show the EZ-Template logo and the team number it was last flashed with.
subsystems.hppOpen include/subsystems.hpp. This is where you wire ports to objects. Replace whatever's there with the Flex version:
main.cppEZ-Template's initialize() function sets PID constants and prepares the chassis. Match yours to Flex's drivetrain values:
drive_test auton and measure overshoot. If it overshoots, lower kP. If it undershoots, raise kP. See PID Diagnostics for the full tuning procedure.EZ-Template ships with example auton routines. Match the team's first run to the simplest one — drive forward 12 inches. Save the file, then in the terminal:
On the brain, navigate to the auton selector (LCD buttons). Select Drive Forward 12in. Disable the competition switch. The robot should drive forward roughly one foot and stop.
The opcontrol function is what runs during the driver portion of the match. For now, just get the chassis driving with the controller — you'll add lift and claw logic in the next section.
Upload, hit B on the controller (or whichever activates opcontrol on your team's setup). Drive the robot around. Confirm tank steering feels correct — left stick controls left wheel, right stick controls right wheel.
Press a button, the motor runs. Release the button, the motor brakes. Simple, predictable, no internal state to debug. This is the right starting pattern for the lift before sensors are added.
The brake() call when no button is pressed is what stops the lift from sagging under its own weight (or gravity pulling a held game piece down). It's the V5 motor's hardware brake mode, more reliable than just setting voltage to 0.
lift_motor.set_brake_mode(MOTOR_BRAKE_HOLD); in initialize(). This makes the motor actively resist motion when stopped — better than COAST (free-spinning) or BRAKE (passive resistance) for a lifting mechanism.One button. Each press flips between "open" and "closed". This is what the Clawbot guide used for its claw — same pattern works on Flex.
get_digital_new_press, not get_digital? get_digital returns true the whole time the button is held — if you used it for toggle, holding the button for 0.5s would toggle the claw 50 times in the 10ms loop. get_digital_new_press returns true once per press, false until the button is released and pressed again. Always use it for toggles.If the claw is closed on a block and you keep pushing voltage at 90, the motor stalls (the rotor stops rotating but current keeps flowing). Stalled motors heat up fast — a 30-second stall can permanently damage the motor.
The right fix: set a current limit. The motor will be allowed up to that current and no more — if it hits the limit while stalled, the motor backs off automatically.
The default current limit on a V5 smart motor is 2500mA (2.5A). Setting it lower limits the force the motor can apply. For the claw at 1800mA, the motor will physically be unable to crush a block — it stalls out at a safe pressure level.
The complete opcontrol with chassis + lift + claw:
Without a potentiometer, you can't tell the lift to go to "scoring height" by angle. You CAN tell it to run for 1.2 seconds. That's not as good, but it works:
lift_motor.brake() when no button is pressed. What's the most likely fix?initialize() so brake() actively resists motionUse the built-in drive_test auton from EZ-Template. Place the robot with a tape mark at the front bumper. Run it. Measure where the front bumper lands.
Goal: Confirm the chassis configuration in Section 3 is correct. Acceptable error on a first run: ±2 inches. If it goes wildly wrong (wrong direction, crashes), check polarities and IMU calibration before continuing.
Write an auton: chassis.pid_turn_set(90, 110); chassis.pid_wait(); then chassis.pid_turn_set(0, 110); chassis.pid_wait();. The robot should turn right then return to its starting heading.
Goal: Confirm the IMU is reading correctly and turn PID is tuned acceptably. Mark the front of the robot with tape. After turn 1, the tape should point right of where it started. After turn 2, it should point back toward the start.
Drive a 24" × 24" square. Four sides, four 90° turns. Use tape on the floor to mark the corners. Measure how far off the robot is when it returns to corner 1.
Goal: Expose accumulated PID error. A well-tuned chassis returns within ~2". A poorly-tuned one spirals outward by 6"+ over the four sides. Record the closing-error distance in the engineering notebook. See PID Diagnostics for what the symptom means.
Write an auton step: lift up for 1.0 seconds, then back down for 1.0 seconds. Watch the lift. Is 1.0s enough to reach the scoring height? Adjust the time. Document what value worked.
Goal: Get comfortable with timed motion control before sensor-based control. Identify the failure modes — battery state matters, gravity matters, friction matters. This is the motivation for adding the potentiometer in Section 6.
Multi-step auton: drive forward 18", lift to scoring height (timed), drive forward 6" more (now near the goal), open the claw, drive backward 12". Time it. Run it 3 times. Record the spread (best vs. worst time, best vs. worst final position).
Goal: Practice coordinating chassis + mechanism in an auton. Discover what's consistent (chassis PID) vs. what isn't (timed lift, claw release timing). The variation between runs IS the data — it tells you what to sensorize.
Auton: grab block 1 (drive to A, close claw, drive back). Score block 1 (drive to goal, lift, open claw). Grab block 2 from a different location. Score block 2. Try to fit it all in 15 seconds (typical V5RC auton period).
Goal: Real auton complexity. You'll discover the lift timing varies between runs (battery). You'll discover the claw doesn't always grab cleanly. These are the problems Section 6's sensors solve.
Failed exercises aren't setbacks — they're the most useful data you'll generate this season. After every failure, do this:
That four-step pattern is what the engineering notebook scores you on. Judges aren't impressed by "we built a robot." They're impressed by "we ran an experiment, here's what we learned, here's what we did next."
For each sensor below, follow the universal 5-step workflow — pick a port, declare it, verify, calibrate, use. The notes below are Flex-specific add-ons to that universal pattern.
The ability to zero the lift on boot. When the robot powers on, run the lift down at low power until the bottom switch triggers, then call lift_motor.tare_position(). Now position 0 = "bottom" in code, every match, every robot.
Any ADI (3-wire) port — A, B, C, ... H. Pick one that's physically close to the brain. Conventionally A for "first switch added."
get_value() typically returns 0 when pressed (active-low), 1 when released. Test on the bench — if the loop runs forever with the switch pressed, you need !lift_bottom.get_value() instead of lift_bottom.get_value().A hard upper safety stop. Without it, an enthusiastic lift command can crash the mechanism into its mechanical stop — eventually that breaks chains, sprockets, or the motor's gearbox.
Absolute lift position, in degrees. Now "go to scoring height" can mean "go to pot reading 1850" — same value every match, same accuracy regardless of battery state. This is the upgrade that makes timed lift control obsolete.
Any ADI port — C is conventional after A and B are used for limit switches.
Find the actual pot values by hand-moving the lift to each named position and reading lift_pot.get_value() from the terminal. Write the numbers in the code AND in the engineering notebook.
Auto-detect when a block is in the claw. Now the driver can press "intake" and the claw will close automatically when a block enters — no need to time it perfectly by eye.
Any Smart Port. Pick one near the claw mechanism. Conventionally 3 or 5.
claw_optical.get_hue() to confirm "yes, this is a block, not just my own hand by mistake." Returns 0-360. Read the hue values for actual game blocks during calibration.End-game parking. The Override game rewards parking near walls or goals in the final seconds. A distance sensor at the back lets the robot back up until it's a specific distance from a wall — no driving over it, no falling short.
Any Smart Port. 7 or 8 work well, away from the drive motors.
rear_distance.get() returns 9999 instead of a real distance. The loop above happens to work either way (9999 > 100 keeps the robot backing up), but if you write code that subtracts distances, guard against the 9999 case explicitly.After all five sensors are integrated, the Flex looks like:
| Port | Device | Purpose | Status |
|---|---|---|---|
| 4 | Smart Motor | Right drivetrain | Day-one |
| 6 | Smart Motor | Left drivetrain | Day-one |
| 13 | Inertial Sensor | Heading | Day-one |
| 15 | Smart Motor | Claw | Day-one |
| 17 | Smart Motor | Lift | Day-one |
| 3 | Optical | Claw block-detect | Sensor 4 |
| 7 | Distance | Rear parking | Sensor 5 |
| A | Limit Switch | Lift bottom (zero) | Sensor 1 |
| B | Limit Switch | Lift top (safety) | Sensor 2 |
| C | Potentiometer | Lift position | Sensor 3 |
A bot that can:
This is what makes Flex a complete training platform. By the time the team's competition robot is built, every student has touched all five sensor patterns on a robot that doesn't break things during practice.
By the time a student has completed all six sections of this guide, they're ready for:
opcontrol, so it doesn't pause your driving. Used for the dashboard, rumble feedback, and continuous sensor monitoring.| L1 | Smart grab (auto-close if optical confirms block) |
| L2 (held) | Claw open — manual override |
| D-Pad ↑ | Slow-mode toggle (50% drivetrain) |
| D-Pad ← | Precise 90° left turn (IMU) |
| D-Pad → | Precise 90° right turn (IMU) |
| D-Pad ↓ | Park-against-wall (distance sensor) |
| L Stick | Left drivetrain (analog) |
| R1 (held) | Lift UP (soft-limit aware) |
| R2 (held) | Lift DOWN (soft-limit aware) |
| A | Pickup preset (lift GROUND + claw OPEN) |
| Y | Score preset (lift SCORE height) |
| X | Travel preset (lift CARRY + claw CLOSED) |
| B | Score sequence combo (drive + lift + release) |
| R Stick | Right drivetrain (analog) |
This map assumes all five sensors from Section 6 are installed. With fewer sensors, some macros downgrade gracefully — smart grab becomes blind grab, soft limits become hard-limit-only, the park macro stops working. Layer the macros as you layer the sensors.
Sensors used: Pot on lift; no others.
Why it matters: One button = a coordinated lift + claw state. Driver thinks "score mode," not "press lift-up for 1.2s then release claw." Cuts driver cognitive load by ~40% in field practice. Especially valuable on Flex because the lift travel range is large — eyeballing scoring height by stopwatch is unreliable.
Driver feel: Press A for pickup, Y for score, X for travel. Each takes ~0.5–1.5s to execute depending on lift travel distance. Faster and more reliable than manual sequencing.
Sensors used: Optical (proximity-gated).
Why it matters: Driver presses L1; claw closes only if the optical sensor confirms a block is actually within range. Saves motor wear on empty-grabs, prevents accidental closes during defensive matches, and prints the detected color to the dashboard for confirmation.
Driver feel: "Grab" becomes a one-button action that just works. L2 stays as manual override (held = open) so you're never trapped if optical fails.
Sensors used: Pot (continuous lift angle); limit switches stay as backup.
Why it matters: Section 6 already added reactive limit switches that stop the lift when it hits the limit. This adds proactive deceleration as the lift approaches its safe range. Difference: the chain mechanism survives 8 matches instead of breaking at lunch. With the lift's chain drive, slamming into the top stop transmits shock directly into sprocket teeth — that's where chain skips and broken sprockets come from.
Driver feel: R1/R2 work normally in the safe zone. Near the limits, the lift slows to a graceful stop instead of slamming. Driver doesn't notice it most of the time — that's the point.
Sensors used: IMU (via EZ-Template's pid_turn_set).
Why it matters: The biggest pure driver-experience win in any V5RC robot. Humans are terrible at 90° turns under match pressure. The IMU + EZ-Template makes them perfect. Drivers go from "guessing" to "exactly 90° every time." Even more important on omni-wheel Flex because pivot-turning on omnis amplifies any inconsistency in stick input.
Driver feel: D-pad left or right, robot rotates exactly 90°, brief rumble confirms completion. Used constantly during matches for intersection navigation and goal alignment.
Sensors used: none.
Why it matters: 50% drivetrain speed for precision scoring. Toggle off for travel between scoring zones. Flex with omni wheels actually accelerates faster than the team's competition robot will — slow-mode is the only way to do fine positioning at goal posts without overshoot. Tap on, score, tap off, drive away.
Driver feel: Tap D-pad up to enter slow-mode (rumble pattern confirms). Tap again to exit. The drivetrain feels "heavy" in slow-mode — intentional.
Sensors used: Optical (block detected), IMU (turn complete), Pot (lift at preset).
Why it matters: Driver knows what's happening without looking at the brain screen. Subtle but huge. During a tense match, eye contact with the field is everything — rumble lets sensors talk to the driver through their hands.
Driver feel: Brief buzz on grab, double-tap on macro completion, long buzz on collision. Drivers tune their map based on what feels useful vs noisy.
Sensors used: All of them — Pot, Optical, Distance, IMU.
Why it matters: The bridge from macros to auton. Press B with a block in the claw → robot drives forward toward the goal, lifts to scoring height, opens claw, backs up. A 4-second sequence in one button. The same logic that powers your auton, but driver-triggered. Override's match flow rewards repeated scoring cycles; this macro turns a 6-second manual cycle into a 4-second one-button cycle.
Driver feel: Get the robot roughly in front of a goal with a block in the claw, press B, robot does the rest. You can override with the stick at any time (failsafe). Aggressive teams use this constantly; it's the difference between scoring 3 blocks and 5 blocks in a match.
src/main.cpp (alongside lift_to_position from Sec 6). The button-press checks go inside opcontrol()'s while loop. The background tasks (haptic, soft limits) get started once at the top of opcontrol() via pros::Task task_name(task_fn);. Order matters: drivetrain first, one-shot macros next, manual mechanisms last.The full team training arc:
The team will rebuild many things for the custom robot. Some things shouldn't be rebuilt — they already work and they generalize. Specifically:
| Transfers | What it means in practice |
|---|---|
| EZ-Template chassis structure | The ez::Drive chassis(...) constructor pattern. Only the port numbers, wheel diameter, and gear ratio change. |
| opcontrol() architecture | The Section 7 ordering: drivetrain → one-shot macros → D-pad macros → manual overrides. Works for any robot. |
| Sensor wiring patterns | How limit switches zero a mechanism, how a potentiometer enables position presets, how an optical sensor proximity-gates a grab. The patterns transfer; only the mounting locations change. |
| Macro architecture | Smart grab, position presets, soft limits, precise turn, slow mode, rumble feedback, sequential combo. Drop them in, change the named constants, done. |
| Auton phase pattern | "drive to A, do X, drive to B, do Y" structured as a sequence of pid_drive_set / pid_wait / mechanism call. Identical on every robot. |
| Engineering notebook templates | The decision-matrix structure, calibration tables, before/after data formats. Transfer 1:1. |
| Doesn't transfer | Why | What to do |
|---|---|---|
| Tuned PID constants | Different mass, motor count, wheel size | Rerun the tuning procedure from PID Diagnostics |
| Named position constants (LIFT_SCORE etc.) | Different geometry, different pot mounting | Re-measure on the bench, update the constants |
| Mechanism-specific code | If the custom robot has e.g. a launcher instead of a claw, the actuation logic is different | Write new code following the same patterns |
| Port map | Custom motor count, custom sensor placement | Update subsystems.hpp |
| Mechanical design choices | Hero Bot is one possible design, not the right one for every team | Design intentionally; document decisions in the notebook |
When the team's custom robot is built, layer sensors in the same order Flex used (matches the priority stack):
Each sensor adds value if and only if the prior tier is reliable. Don't skip ahead — this is the same advice as Flex, scaled up. The order applies to every robot the team will ever build.
The strongest notebook entry from this whole curriculum is the before/after comparison between Flex and the team's custom robot. Specifically:
That comparison is exactly what Design Award judges look for — it shows the team intentionally iterated, learned, and applied lessons. See engineering-notebook for the full Design Award rubric.