🎦 Driver-Focused

Tailoring the Robot to Your Driver

In Formula One, the car is configured around the driver — not the other way around. EZ Template and PROS give you the same tools. Every setting here directly changes how the robot feels in your driver's hands.

1
F1 Principle
2
Control Scheme
3
Joystick Curves
4
Brake & Feel
5
Macros
6
Scuff Ctrls
7
Tank vs Arcade
// Section 01
The Formula One Principle
In F1, the engineers do not give the driver a car and say "get used to it." They adjust brake bias, throttle mapping, steering weight, and differential settings until the car responds exactly the way that specific driver needs it to. You can do the same thing in VRC.
🏎
The programmer's job during driver development: interview your driver, understand their preferences, implement the settings that match them, and tune iteratively until the robot feels like an extension of their hands — not a machine they are fighting against.

What You Can Actually Change

Every one of these settings changes how the robot responds to the same physical controller input. None of them require hardware changes — only code changes.

EZ Template Built-In
Control Scheme
Tank, split arcade, single arcade, standard or flipped
5 distinct layouts
EZ Template Built-In
Joystick Curves
Input curve from 0 (linear) to ~10 (heavy exponential)
Independently set per stick
EZ Template Built-In
Active Brake
P-loop holds position when joystick released
kP 0 = coast, kP 2+ = firm hold
EZ Template Built-In
Motor Brake Mode
Coast (freewheels), Brake (resists), Hold (locks position)
Per session, set in opcontrol
Custom Code
Deadband
Ignore inputs below a threshold — eliminates stick drift
Typically 5–15 of 127
Custom Code
Speed Scaling / Turbo
Hold a button to unlock full speed
Default 60%, Turbo 100%
Custom Code
Button Remapping
Any button triggers any mechanism
Claw grip, thumbs-only, custom layouts
Custom Code
One-Button Macros
Single press executes multi-step sequences
Score, intake, climb, flip-out

The Driver Interview — Ask These Questions First

Before changing anything, sit with your driver and ask them directly. Their answers tell you exactly where to start.

📝
Log preference changes in the notebook. Every control tuning change you make based on driver feedback is engineering design process evidence — exactly what judges want to see. Date, what changed, why, and what improved.
// Section 02
Control Scheme — How the Sticks Map to Drive
The most fundamental preference decision. This alone changes which muscles the driver uses and what mental model they apply. Get this right before tuning anything else.

The Five Options in EZ Template

Tank Drive
Left stick = left wheels. Right stick = right wheels. Each side controlled independently.
Most common in VRC
Arcade Split — Standard
Left stick = forward/back. Right stick = turning. Most intuitive for video-game drivers.
Good for beginners
Arcade Split — Flipped
Right stick = forward/back. Left stick = turning. Preferred by some experienced drivers for right-hand dominance.
Driver preference
Single Arcade — Standard
Left stick controls both forward and turning — push diagonally to turn while moving. Frees the right hand for mechanisms.
Mechanism-heavy robots
Single Arcade — Flipped
Right stick controls both forward and turning. Frees the left hand for mechanisms.
Mechanism-heavy robots
src/main.cpp — inside opcontrol() while loop
// Select a scheme by clicking a card above chassis.opcontrol_tank(); // Tank control — default // chassis.opcontrol_arcade_standard(ez::SPLIT); // Standard split arcade // chassis.opcontrol_arcade_standard(ez::SINGLE); // Standard single arcade // chassis.opcontrol_arcade_flipped(ez::SPLIT); // Flipped split arcade // chassis.opcontrol_arcade_flipped(ez::SINGLE); // Flipped single arcade

Which Should Your Driver Use?

Driver ProfileRecommended SchemeReason
New to VRC, plays video gamesArcade Split — StandardMatches the mental model from most games. Left stick = movement, right stick = camera/turn.
Experienced VRC driverTankGives the most precise independent side control. Skilled tank drivers can out-maneuver arcade drivers in tight spaces.
Robot with many mechanisms, needs free right handSingle Arcade — StandardDriving on left stick leaves the right thumb on face buttons for mechanism control without coordination penalty.
Driver with strong right-hand preferenceArcade Split — FlippedSome drivers feel more precise with the dominant hand on the forward/back axis rather than turning.
⚠️
Change scheme early in the season, not the week before competition. Control scheme is deeply tied to muscle memory — switching schemes takes 2–3 weeks of consistent practice to feel natural. Experiment in Phase 2, commit to one by Phase 3, and never change it in Phase 5.
// Section 03
Joystick Input Curves
A linear joystick gives equal speed change per millimeter of stick movement across the entire range. A curved joystick gives fine control at low speeds and explosive power at high deflection — the F1 throttle map equivalent.
ℹ️
EZ Template's curve equation is based on the one originally designed by team 5225A. Curve value 0 = perfectly linear. Higher values push more of the joystick range toward low speeds. The curve applies independently to each stick.

Live Curve Visualizer

🆕 Joystick Curve Preview
Curve value: 2.0
Move the slider to see how different curve values change the joystick response. The x-axis is joystick deflection (0 to full). The y-axis is motor output.

Setting Curves in Code

Curves are set in initialize(). For tank drive, one value sets both sticks. For arcade, the first value is the forward/back axis and the second is the turn axis.

src/main.cpp — inside initialize()
// Tank — both sticks get the same curve chassis.opcontrol_curve_default_set(2.1); // Arcade — independent curve for each axis // First value: forward/back. Second value: turn. chassis.opcontrol_curve_default_set(2.1, 4.3); // ↑ Higher turn curve = more of the turn stick controls fine rotation

The SD Card Method — Live Adjustment During Practice

This is the most powerful workflow for driver-focused tuning. With a MicroSD card installed in the Brain, the driver can adjust their own curve value live during practice — no re-uploading needed.

src/main.cpp — SD card workflow
void initialize() { // Comment out the default set — let the SD card control it // chassis.opcontrol_curve_default_set(2.1); // Curves are now saved automatically whenever the driver changes them // The Brain remembers the value after power off chassis.initialize(); }

How the Driver Adjusts Curves Live (No Upload Required)

With SD card mode active, the driver uses controller buttons during practice to dial in their preference:

Drive TypeLeft/Right ButtonsY / A Buttons
TankLeft drive curveRight drive curve
Left Split ArcadeForward/back curveTurn curve
Right Split ArcadeTurn curveForward/back curve
Single ArcadeForward/back curveTurn curve

After each practice session, read the saved value from the Brain's SD card and hard-code it before competition — this ensures the curve is locked even if the SD card is removed or fails at an event.

Driver Profile Recommendations

New / Twitchy Driver
High Curve (3.5–6.0)
Most joystick range maps to low speeds. Precise positioning is easy. Reaching full speed requires deliberate full deflection.
Good for learning fine motor control
Experienced / Smooth Driver
Low Curve (1.5–2.5)
Nearly linear response. Speed is predictable across the full stick range. Aggressive driving feels natural.
Good for fast, confident drivers
Driver with Binary Stick Habits
Practice Mode + Curve
Enable opcontrol_joystick_practicemode_toggle(true) — this cuts drive power when joystick is maxed, training the driver to use the full range.
Removes binary habits within weeks
Different Turn vs Drive Feel
Asymmetric Curve (Arcade)
Set a higher curve on the turn axis than the forward axis. Turns feel more controlled without slowing down straight-line driving.
e.g. drive 2.0, turn 4.5
// Section 04
Brake Feel, Speed, and Deadband
How the robot decelerates and holds position when the driver releases the sticks — and how to eliminate stick drift and add speed modes. These settings define the robot's personality on the field.

Motor Brake Mode — The Foundation

Three modes control what happens to the motors when power is cut. Set this at the top of opcontrol() before the while loop.

src/main.cpp — top of opcontrol()
// Set once when opcontrol starts — affects all driving chassis.drive_brake_set(MOTOR_BRAKE_COAST); // freewheels to a stop // chassis.drive_brake_set(MOTOR_BRAKE_BRAKE); // resists motion, stops faster // chassis.drive_brake_set(MOTOR_BRAKE_HOLD); // locks wheels in place
ModeBehaviorBest ForAvoid When
Coast Motors disengage — robot glides to a stop by friction Fast driving, large robots, most VRC Robot needs to hold exact position after stop
Brake Motors resist motion — robot stops more crisply When coast feels too loose, driver wants crispness High-speed driving — can cause jerky deceleration
Hold Motors actively hold current position — resists being pushed Climbing, pushing games, goal interaction Normal driving — feels unnatural and fights the driver

Active Brake — Tunable Coast-to-Hold

Active brake is EZ Template's best-of-both-worlds option. When the joystick is released, a P-loop runs to hold the current position — but you tune exactly how aggressively it holds. kP 0 = coast. kP ~2 = gentle hold. kP 5+ = firm hold.

src/main.cpp — inside initialize()
// Active brake — runs a P-loop when joystick is released chassis.opcontrol_drive_activebrake_set(2.0); // 0 = disabled (pure coast) // 1.5 = light hold — stops drift, still feels natural // 2.0 = recommended starting point // 4.0 = firm hold — robot resists being pushed
💡
Active brake + coast is the most common competition setup. Set brake mode to coast, then add active brake kP 1.5–2.5. The robot still feels smooth during driving but stops cleanly and holds reasonably well when the driver pauses to score.

Custom Deadband — Eliminate Stick Drift

Every physical joystick has a small amount of drift — the stick reads a non-zero value when at rest. By default, this causes the robot to creep slowly. A deadband ignores inputs below a threshold value.

src/main.cpp — inside opcontrol() while loop
// Custom deadband — replace chassis.opcontrol_tank() with this int leftY = master.get_analog(ANALOG_LEFT_Y); int rightY = master.get_analog(ANALOG_RIGHT_Y); const int DEADBAND = 10; // ignore inputs below this — adjust 5–20 if (abs(leftY) < DEADBAND) leftY = 0; if (abs(rightY) < DEADBAND) rightY = 0; chassis.opcontrol_tank_set(leftY, rightY); // pass filtered values directly

Speed Scaling — Training Mode and Turbo

Two useful patterns: a training/precision mode that limits max speed by default, and a turbo button that unlocks full speed when held.

src/main.cpp — inside initialize() and opcontrol()
// In initialize() — set default max speed chassis.set_max_speed(70); // 55% — precise default, leaves room for turbo // In opcontrol() while loop — turbo when R2 held if (master.get_digital(DIGITAL_R2)) { chassis.set_max_speed(127); // full speed while R2 held } else { chassis.set_max_speed(70); // back to default when released }
⚠️
Speed scaling affects autonomous too if you call set_max_speed() anywhere and forget to reset it. Always reset to 127 at the start of your autonomous routines, or use set_max_speed(127) inside initialize() to ensure auton starts fresh.
// Section 05
Button Remapping & One-Button Macros
The most driver-focused programming work of all. Every button on the controller is yours to assign. Every repeated multi-step sequence is a macro candidate that can be reduced to a single press.
🎦
The F1 steering wheel principle: F1 drivers have 20+ buttons on the wheel, each mapped to exactly what they need at their fingertips. In VRC, the programmer decides which mechanism each button fires. If the driver's thumb has to leave the right side to reach a button, that is a mapping problem the programmer can fix.

Button Remapping — Any Action on Any Button

Every button on the V5 controller is accessible in PROS. Remap freely — there is no technical constraint on which button fires which mechanism.

src/main.cpp — opcontrol() — button reference
// All available digital buttons: // Face buttons: DIGITAL_A DIGITAL_B DIGITAL_X DIGITAL_Y // Bumpers: DIGITAL_L1 DIGITAL_L2 DIGITAL_R1 DIGITAL_R2 // D-Pad: DIGITAL_UP DIGITAL_DOWN DIGITAL_LEFT DIGITAL_RIGHT // Example — remap intake from R1 to L1 for this driver's preference: if (master.get_digital(DIGITAL_L1)) { intake.move(127); } else if (master.get_digital(DIGITAL_L2)) { intake.move(-127); } else { intake.move(0); }

One-Button Macros — Reduce Multi-Step Sequences to a Single Press

A macro runs a sequence of actions automatically when a button is pressed. The driver initiates it with one press and the robot handles the rest. This is the single highest-leverage code technique for driver efficiency.

Use a rising-edge check — the macro fires once on the press, not repeatedly while held:

src/main.cpp — opcontrol()
// Rising-edge detection — runs macro once per press if (master.get_digital_new_press(DIGITAL_Y)) { ScoreMacro(); // entire scoring sequence in one function } // The macro function — defined separately in your code void ScoreMacro() { arm.move_absolute(ARM_SCORE_HIGH, 200); // raise arm to score height pros::delay(600); // wait for arm to reach position intake.move(-127); // eject game element pros::delay(400); // eject for 400ms intake.move(0); // stop intake arm.move_absolute(ARM_STOWED, 200); // lower arm to stow }
⚠️
Macros with pros::delay() block the entire opcontrol loop while they run — the driver cannot drive during a blocking macro. For complex macros, use a pros::Task to run them in the background so the driver keeps control of the drivetrain. See the advanced pattern below.

Non-Blocking Macro with pros::Task

This pattern runs the macro in a separate thread — the driver keeps full drive control while the macro executes independently.

src/main.cpp — non-blocking macro pattern
// Global task handle — allows cancellation pros::task_t macroTask = nullptr; // Task wrapper — required signature for pros::Task void ScoreMacroTask(void* param) { arm.move_absolute(ARM_SCORE_HIGH, 200); pros::delay(600); intake.move(-127); pros::delay(400); intake.move(0); arm.move_absolute(ARM_STOWED, 200); } // In opcontrol() while loop — press Y to start, press again to cancel if (master.get_digital_new_press(DIGITAL_Y)) { if (macroTask != nullptr) { pros::task_delete(macroTask); // cancel running macro macroTask = nullptr; } else { macroTask = pros::c::task_create(ScoreMacroTask, nullptr, TASK_PRIORITY_DEFAULT, TASK_STACK_DEPTH_DEFAULT, "Score"); } }

What Macros Are Worth Building

💡
Work backwards from a match video. Record your driver practicing, watch it back, and count how many button presses each scoring cycle takes. Any sequence of more than 2–3 presses that happens more than 5 times per match is a macro candidate. One button instead of five is 4 fewer things that can go wrong under pressure.
// Section 06
Scuff Controllers — More Buttons, Thumbs Never Leave the Sticks
A scuff controller adds rear paddles that can press face buttons while the driver's thumbs stay on the joysticks. It is the single most impactful hardware upgrade available to a VRC driver.
🏆
Competition legal. 3D printed modifications to the controller are explicitly permitted under VRC game rules. Scuff paddles do not modify the controller's electronics — they are physical levers that press existing buttons. Teams at every level including Worlds use them.

What a Scuff Actually Does

The V5 controller has 12 buttons. By default, pressing any face button (A, B, X, Y) requires lifting the right thumb off the right joystick. Pressing L1/L2/R1/R2 requires the index fingers that are already on the bumpers — but the driver cannot simultaneously hold both bumpers and both joysticks at full deflection without awkward hand geometry.

A scuff adds 2–4 paddles on the back and underside of the controller. Each paddle presses one specific button through a mechanical linkage — the driver operates them with middle or ring fingers while their thumbs stay on the joysticks. The result: the driver can drive at full speed and operate mechanisms simultaneously with no coordination penalty.

The Gameplay Difference — Before and Without Scuffs

Without Scuffs
  • Thumb leaves joystick to press A — robot drifts
  • Drive slows or stops during mechanism operation
  • Cannot drive and score simultaneously
  • End-game maneuver requires stopping to use face buttons
  • Recovery from missed pickup requires coming to a stop
With Scuffs
  • Paddle fires A — thumbs never leave sticks
  • Full drive control during all mechanism operation
  • Drive and score in one continuous motion
  • End-game initiated with a paddle while still maneuvering
  • Cycle time drops significantly — no stop needed between actions
ℹ️
The cycle time impact is real and measurable. Run your driver's single-cycle drill from the Driver Practice guide — once without scuffs and once with — and time both. Teams consistently report 1–3 second reductions per cycle after adapting to scuffs. Across a 105-second match with 10+ cycles, that is 10–30 seconds of extra scoring time.

The EZ Robotics Scuff Designs — Recommended Starting Point

The EZ Template creator (ssejrog / Jess) has released two free 3D printable scuff body designs on Printables.com specifically built for the VEX V5 controller. Both include a cutout for the EZ Mini Competition Switch — so your competition switch mounts directly to the controller and you never forget it at a match.

Option 1
EZ Thin Body Scuffs
Lower profile body — less bulk, lighter weight. Uses MCEC top paddles and 2654P bottom paddles. Multiple bottom paddle lengths available. Good choice if the driver wants a more natural feel close to the stock controller.
↗ printables.com/model/1298001
Option 2
EZ Wide Body Scuffs
Wider profile — more grip surface and a sturdier feel for larger hands. Uses MCEC top paddles and the community-standard single lever bottom paddle. Same EZ Mini Competition Switch cutout.
↗ printables.com/model/1297902
💡
Also check: the 2654P design on Printables (model/697491) is a popular community design with improved durability and a more ergonomic lower paddle shape. The Nooz V2 (printables.com/model/392038) is another well-regarded option with a clamshell secured by zip ties — very durable. All are free downloads.

The EZ Mini Competition Switch

While not a scuff paddle, the EZ Mini Competition Switch (available at roboticsisez.com) is designed to mount directly into the EZ scuff body cutout. It attaches to the controller with a 6-inch ethernet cable and stays secure without the cable holding it. The practical benefit: you always have the competition switch on your controller. Teams that forget their competition switch cannot do a proper full-sequence test on match day — this eliminates that risk entirely.

Print Settings and Assembly Notes

Button Mapping with Scuffs

Once scuffs are installed, the programmer assigns the paddles to the most frequently used buttons for that driver's style. Common configurations:

Intake-Heavy Game
Top-left paddle → R1 (intake fwd)
Top-right paddle → R2 (intake rev)
Bottom paddle → A (score macro)
Arm + Claw Robot
Top-left paddle → L1 (arm up)
Top-right paddle → L2 (arm down)
Bottom paddle → B (claw toggle)
End-Game Focus
Top paddles → regular mechanism
Bottom paddle → Y (climb initiate)
Keeps climb on a dedicated thumb-free button
⚠️
Adaptation takes time. Most drivers need 2–3 weeks of regular practice before scuff paddles feel natural rather than distracting. Introduce scuffs during Phase 2 or 3 of the season — never the week before a competition. A driver who is still actively thinking about the paddles is slower, not faster.
// Section 07
Tank vs Split Arcade — The Full Comparison
The most debated question in VRC driver configuration. Here is the complete breakdown from both the driver and programmer perspective — not a preference, but an honest analysis of what each scheme does and does not do.
ℹ️
The short answer from the VEX community: a skilled tank driver generally outperforms a skilled arcade driver — but arcade is more intuitive for new drivers and produces faster initial improvement. The right choice depends on your driver's experience level and how much of the season remains for adaptation.

How Each Scheme Works Physically

Tank Drive
Independent side control
Left stick Y-axis → left drive motors
Right stick Y-axis → right drive motors

To drive forward: push both sticks up equally
To turn left: push right stick forward, left stick back (or hold left still)
To arc: push both forward but at different speeds
To spin in place: push one stick forward, one back
Split Arcade
Forward + turn abstraction
Left stick Y-axis → forward/backward speed
Right stick X-axis → turning rate

To drive forward: push left stick up
To turn left: push right stick left (while moving or stopped)
To arc: push left stick forward and right stick slightly
To spin in place: right stick only, left stick neutral

Driver Experience — Side by Side

SituationTankSplit Arcade
Driving perfectly straight Harder — requires both sticks perfectly synchronized. Slight asymmetry causes drift. Curves help but do not eliminate it. Easy — left stick straight up = straight drive. The code handles the synchronization.
Precise spot turns (180°) Excellent — push one stick fully forward and one fully back. Maximum turning authority at any speed. Good but slightly less direct. Right stick at full deflection while left stick is neutral turns in place.
Arcing turns (curved path) Excellent — independently adjust each side. Any arc radius is achievable with fine independent stick pressure. Good but constrained — the arc radius is coupled to both sticks together. Less independent control over each side.
Recovery from mechanical failure Can compensate — if one motor overheats or a side loses power, driver can apply more to compensate with the other stick. Limited compensation — arcade mixes both sides in code. Hardware failure causes unpredictable drift the driver cannot easily correct.
Learning curve for new drivers Steep — driving straight requires coordination practice. Initial sessions feel frustrating. Gentle — intuitive for anyone who has played video games. New drivers become functional much faster.
Operating mechanisms simultaneously Both thumbs on joysticks always — face buttons require lifting a thumb. Scuffs solve this. Single-stick arcade frees one thumb entirely for mechanisms without scuffs.
Defensive play (pushing, blocking) Superior — independent side control allows quick direction reversals and precise positioning for contact. Adequate but the abstraction layer can feel slow during rapid directional changes under pressure.

Programmer Perspective — What Changes in Code

ConcernTankSplit Arcade
EZ Template implementation One line: chassis.opcontrol_tank() One line: chassis.opcontrol_arcade_standard(ez::SPLIT)
Joystick curve application One curve value applies to both sticks symmetrically Two independent curve values — one for forward, one for turn axis. More tuning flexibility.
Custom deadband Apply to left Y and right Y independently Apply to left Y (forward) and right X (turn) — axes are different directions
Straight-line code assist Can write a "snap to straight" assist: if sticks are within 5 units of each other, average them. Reduces drift significantly. Not needed — arcade drives straight naturally when left stick is pushed vertically.
Custom arc controls Not needed — driver handles arc directly with independent sticks Can add turn rate scaling — reduce how aggressively the turn axis responds at high forward speed
Scuff mapping complexity Slightly simpler — both thumbs committed to sticks, scuffs replace face buttons cleanly Single arcade frees one thumb, reducing scuff need for mechanisms (drive frees the hand naturally)

The "Snap to Straight" Assist for Tank Drivers

This optional code assist helps tank drivers drive straight by detecting when both sticks are nearly identical and averaging them. It is the programmer helping the driver, not replacing them.

src/main.cpp — inside opcontrol() while loop (tank only)
// Snap-to-straight assist for tank drive // If both sticks are within SNAP_THRESHOLD of each other, average them const int SNAP_THRESHOLD = 8; // tune to driver preference — 5 to 15 int leftY = master.get_analog(ANALOG_LEFT_Y); int rightY = master.get_analog(ANALOG_RIGHT_Y); if (abs(leftY - rightY) < SNAP_THRESHOLD && abs(leftY) > 15) { int avg = (leftY + rightY) / 2; leftY = avg; rightY = avg; // both sides equal = perfect straight line } chassis.opcontrol_tank_set(leftY, rightY);

Which Should Your Team Choose?

Decision Framework
New driver, first season: Start with Split Arcade Standard. Get competitive fast. If they are still driving in year 2, consider transitioning to tank in the off-season.
Experienced driver, multiple seasons: Tank, with scuffs. The ceiling is higher and the adaptation investment has time to pay off.
Robot with many mechanisms, limited button count: Single Arcade Standard. Frees one full hand for mechanism control without scuffs.
Mid-season switch: Do not switch control schemes mid-season unless absolutely necessary. Muscle memory regression will cost more matches than the new scheme gains.
Two-person drive team: Driver uses preferred scheme. Operator (second controller) always benefits from having their mechanism buttons on front-accessible positions — scuffs help the operator too.
⚙ STEM Highlight Mathematics: Functions, Curves & Input Transformation
Joystick input curves are mathematical functions mapping input ‐1…1 to output ‐1…1. A linear curve is f(x)=x. A cubic curve is f(x)=x³ — gentle near zero, aggressive near maximum. An exponential curve is f(x)=eˆ(kx)−1 (normalized). The curve’s derivative at any point is the effective sensitivity: df/dx. A shallow curve (near-zero derivative near zero) gives fine control; a steep curve (high derivative) gives aggressive response. Choosing a curve is choosing how sensitivity varies across the input range.
🎤 Interview line: “Input curves are mathematical functions that transform joystick position to motor output. We chose a cubic curve because its derivative near zero is very small — giving fine control for small adjustments — while the derivative near maximum is large, giving full power when needed. We can describe this precisely because we understand the function’s shape.”
🔬 Check for Understanding
A driver complains the robot feels “too twitchy” at low speeds but “sluggish” at full speed. What type of input curve change would address this?
Increase the overall speed multiplier
Apply a curve with a lower slope near zero (gentler at small inputs) and steeper slope near maximum — like a cubic or exponential curve
Switch from arcade to tank drive
Reduce the deadband threshold
Related Guides
🏎 Curvature Drive →🎮 Driver Practice →🎮 Partner Controller →
← ALL GUIDES