4-motor drivetrain, position-controlled arm, manipulator (single or dual grip), scuff controls, macros, and pneumatics — built around Override 2026-27 constraints.
Write down your ports before touching the code. A 4-motor tank drive looks like this:
| Port | Motor | Reversed? | Notes |
|---|---|---|---|
| 1 | Left Front | Yes (-1) | Left motors face opposite direction |
| 2 | Left Back | Yes (-2) | |
| 3 | Right Front | No (3) | Right motors face forward |
| 4 | Right Back | No (4) | |
| 10 | IMU (Inertial) | N/A | Used for turning accuracy |
3.25, 1.0. If you have a 36:48 external gear ratio (common speed-up), use 3.25, (48.0/36.0).set_drive_brake() in the right places. Check the EZ Template docs for ez::as::exit_condition for advanced brake control.Override has goals at three distinct heights (per the v0.1 manual glossary). Plus a ground position for picking pins up off the field. That gives 4 arm presets:
| Preset | Goal Type | Height | D-pad Button |
|---|---|---|---|
| ARM_GROUND | Pin pickup from field | 0″ | LEFT |
| ARM_LOW | Alliance goal | 3.25″ (82.5mm) | DOWN |
| ARM_MID | Short neutral goal (in quadrants) | 5.8″ (146.5mm) | RIGHT |
| ARM_HIGH | Tall center goal (midfield) | 8.7″ (222.7mm) | UP |
arm.get_position() from the V5 Brain screen.The most reliable arm control method for beginners uses the motor's built-in position PID. You set a target, it holds there:
arm.get_position() with printf, and replace the placeholders with your robot's real values.Sometimes you want direct joystick control instead of presets. Add a manual mode using a button hold:
One manipulator motor that picks up either a pin or a cup, depending on what your gripper is currently approaching. This matches the simplest hardware path (one universal manipulator). Code is just "intake on/off" with a toggle.
A toggle means: first press turns it on, second press turns it off. You need to track both the current state and the previous button state to detect the moment of the press:
r1Now && !lastR1State means "button is pressed NOW but was NOT pressed last loop" — that's the exact moment of a press. Without this, the toggle would flip every 20ms while you hold the button!If you have multiple toggles (like the dual-grip pattern below), make a helper so you're not duplicating the pattern everywhere:
Two separate grippers, one tuned for pins (small, narrow) and one for cups (large, hourglass). Each has its own motor and its own toggle. The robot can hold one pin AND one cup simultaneously (within the SG6 limit) and place both in one trip to the goal. Faster cycle but more motor budget — uses 22W of Subsystem 3 instead of 11W.
R1 toggles the pin grip, L1 toggles the cup grip. R2 / L2 reverse (drop) the corresponding gripper. Using the helper function from above keeps this clean:
Both patterns are Override-legal under SG6. The choice depends on your mechanism:
| Pattern | Motor Budget | Cycle Time | Mechanical Complexity |
|---|---|---|---|
| A — Single-Grip | 11W (1 motor) | 2 trips per stack (pin trip + cup trip) | Lowest |
| B — Dual-Grip | 22W (2 motors) | 1 trip per stack | Higher; two grippers to tune |
The Hero Bot baseline uses Pattern A. Pattern B is a worthwhile upgrade if your team has the motor budget headroom (within the 88W total cap) and the mechanism design has matured.
Scuff controls (named after Scuf Gaming controllers) remap actions to buttons accessible with your index fingers while keeping thumbs on the joysticks. In VRC this usually means putting high-use actions on the bumpers (L1, L2, R1, R2) so your thumbs never have to leave the sticks.
A proven Override competition layout for the Hero Bot baseline (4-motor drive, arm, single-grip manipulator):
| Button | Finger | Action | Why |
|---|---|---|---|
| Left Stick | Left Thumb | Left drive side | Tank drive |
| Right Stick | Right Thumb | Right drive side | Tank drive |
| R1 | Right Index | Manipulator grab (toggle) | Most-used action |
| R2 | Right Index | Manipulator release | Drop pin or cup |
| L1 | Left Index | Arm up (manual) | Fine-tune scoring height |
| L2 | Left Index | Arm down (manual) | Reset arm |
| D-pad UP | Left Thumb (off stick) | Arm HIGH preset (tall center) | Quick score height |
| D-pad RIGHT | Left Thumb (off stick) | Arm MID preset (short neutral) | Quad-goal scoring |
| D-pad DOWN | Left Thumb (off stick) | Arm LOW preset (alliance) | Alliance-goal scoring |
| D-pad LEFT | Left Thumb (off stick) | Arm GROUND preset | Pin pickup |
| A | Right Thumb (off stick) | Macro: Score-stack sequence | Automated pin + cup scoring |
| B | Right Thumb (off stick) | Cup-flip pneumatic toggle | Cup orientation correction |
DIGITAL_XX constant maps to which action. Scuff is a design decision about which physical button you assign to each piece of code. If you went with the dual-grip manipulator pattern from Chapter 03, swap the manual arm controls (L1/L2) onto the right joystick Y-axis and use L1/L2 for cup-grip toggle/release.A macro is an automated sequence triggered by a single button during driver control. The most useful Override macro is score-stack: drive driver-side already aligned with a goal, press A, and the robot raises the arm, drops the pin, then drops the cup — all without taking your thumbs off the sticks.
pros::delay() inside opcontrol, the entire robot freezes — no driving while the macro runs. Tasks let both run simultaneously.get_digital_new_press() is a built-in PROS shortcut that detects rising edge automatically — it only triggers once per press, which is perfect for macros and toggles. Use it instead of tracking lastButtonState manually when you don't need to track state across the loop.A natural Override use for a single-acting piston is a cup-orientation flipper: a small piston that rotates the cup gripper 180° between transparent-side-up and opaque-side-up. This matters for scoring because of rule SC3 — each pin scores per half, and a pin nested inside the transparent half of a cup still scores while the opaque-half pin does not. Flipping the cup before placement can swing scoring outcomes if your strategy depends on which half is exposed.
Two solenoids — one to extend, one to retract. Both on ADI ports. You can't have both true at the same time — that fights against itself.
pros::ADIDigitalOut({{smartPort, 'A'}}) syntax.move_absolute(900, 100). What layer of abstraction does this represent?