🔬 Diagnostic Procedures

PID Tuning
Diagnostics

Identify exactly what's wrong with your robot's movement — and know exactly which constant to change. Symptom → diagnosis → fix.

1
Basics
2
Symptoms
3
EZ Tuner
4
Drive PID
5
Turn PID
6
Checklist
// Section 01
What PID Is Actually Doing 🎯
Before diagnosing problems, you need to understand what each constant controls — in plain English.
💡
PID stands for Proportional, Integral, Derivative. It's a feedback loop that continuously corrects the robot's movement to hit a target. Think of it like adjusting a car's steering — the further off course you are, the more you correct.
What Each Term Controls
kP PROPORTIONAL "How hard to push based on how far away you are" ↑ = faster/stronger ↓ = slower/weaker kI INTEGRAL "Extra push if stuck just short of target for a long time" Usually kept near 0 Can cause oscillation kD DERIVATIVE "Brakes as you approach the target to prevent overshoot" ↑ = less overshoot Too high = sluggish

The Tuning Sequence — Always Follow This Order

📋
Never tune kI or kD before kP is roughly correct. Set kI and kD to 0 first. Get kP to a usable range. Then add kD to reduce oscillation. Only add kI if you have a persistent steady-state error that kP and kD can't fix.
  1. Set kI = 0, kD = 0. Start with only kP.
  2. Increase kP until the robot reaches the target but overshoots. Note the value.
  3. Back kP off 20–30% from the overshoot value. The robot should now be close but slow at the end.
  4. Increase kD slowly until oscillation (wobbling at the target) stops.
  5. Only if needed: add a tiny kI (0.001–0.01) if the robot consistently stops 1–2" short.
// Section 02
Symptom → Diagnosis → Fix 🔬
Watch your robot run, find the symptom below, and follow the fix. Click each symptom to expand.

Drive PID Symptoms

🐢
Robot moves very slowly and barely reaches target
kP too low

The robot creeps toward the target with very little force. It might time out before reaching it, or crawl in at less than walking speed.

Diagnosis
kP is too small. The proportional term isn't generating enough power to move the robot meaningfully. The robot sees "error = 24 inches" but kP is so small the output voltage is almost nothing.
Fix
Double kP. Keep doubling until the robot overshoots, then back off 20–30%. A typical starting range for EZ Template drive kP is 5–15.
🏎️
Robot shoots past the target and keeps going
kP too high / kD too low

The robot reaches the target but continues past it by several inches before stopping (or coming back).

Diagnosis
kP is generating too much momentum. The robot is moving so fast that it can't stop in time. kD is too small to apply enough braking force as it approaches.
Fix — try in order
1. First increase kD — this applies braking as the robot approaches. Try doubling it.
2. If still overshooting, reduce kP by 20%.
3. Also check that your exit conditions aren't too loose — a wide exit window can let the robot exit the PID loop before it fully settles.
〰️
Robot wobbles or oscillates around the target
kD too low / kI too high

The robot reaches the approximate target but keeps rocking back and forth, over-correcting, unable to settle.

Diagnosis
Insufficient damping. The derivative term (kD) is the "shock absorber" — it should slow the corrections as the robot nears the target. If kD is too small, the robot keeps correcting past the target in both directions. If kI is non-zero, it can also amplify this behavior.
Fix
1. Increase kD in steps of 10–20. This is your primary tool against oscillation.
2. If kI is non-zero, set it to 0 temporarily to see if that's contributing.
3. If oscillation persists even with high kD, kP may also be too high — try reducing it 10–15%.
📍
Robot stops consistently 1–2 inches short of target
Steady-state error / kI needed

The robot reliably stops just short of the target — always the same distance short. It's not oscillating, just slightly under.

Diagnosis
Steady-state error. The kP output at close range is too small to overcome friction. The robot slows down proportionally, and near the target the motor output isn't enough to move anymore. Check exit conditions first — the robot might be exiting the PID loop before settling.
Fix — try in order
1. First: Try slightly increasing kP — a higher proportional output at close range may be enough.
2. Second: Add a very small kI (0.001–0.005). This slowly builds force when stuck near the target.
3. Third: Check your exit conditions in EZ Template — tighten pid_exit_condition_set() so the robot doesn't exit too early.
🐍
Robot drifts sideways or curves while driving straight
Heading PID / mechanical

When commanded to drive straight, the robot arcs to the left or right instead of going in a straight line.

Diagnosis
Could be mechanical OR heading PID. Check mechanical first — an unbalanced robot or different wheel pressures will drift regardless of PID. If mechanical is fine, EZ Template uses a separate heading correction PID to keep the robot going straight.
Fix
Mechanical checks first: Are all wheels spinning freely? Is the robot's weight centered? Are tread wheels on one side and omnis on the other (this causes drift)? Use all omni wheels for straight driving.

If mechanical is OK: Increase pid_heading_constants_set() kP. Default is around 11.0 — try 13–15 if drifting. The heading PID runs in the background during drives to keep the robot pointed correctly.

Turn PID Symptoms

🌀
Robot overshoots turns and keeps spinning
Turn kP too high

Robot spins past the target angle by 10–30° or more. Sometimes comes back, sometimes just keeps going.

Fix
Reduce turn kP. Turn PID is much more sensitive than drive PID — typical values are 1–5. Start at 3.0 and adjust. Also increase turn kD to add damping.
🐌
Robot turns very slowly and takes forever to settle
Turn kP too low / kD too high

The robot creeps to the target angle or gets very close but then takes 2–3 seconds of tiny adjustments to finally settle.

Fix
1. Increase turn kP slightly — more proportional force near the end helps it settle faster.
2. If kD is very high, reduce it — over-damping causes exactly this slow creep near the target.
3. Check exit conditions: pid_turn_exit_condition_set() might be too strict, causing it to wait unnecessarily.
📉
Turns are accurate in testing but drift at competitions
IMU drift / surface difference

Tuned on your practice field but doesn't hit the same angles at the competition venue.

Diagnosis
Competition tiles may be slightly different, the robot may not have calibrated properly, or the IMU was disturbed. Also: motors behaving differently under battery charge level changes.
Fix
1. Always let the robot fully calibrate before each match (3 seconds still after turning on).
2. Use the auton selector's built-in delay to ensure calibration finishes.
3. Test on a fully charged battery — dead batteries change motor behavior significantly.
4. Add a distance sensor wall correction (see Odometry guide) to reset position before critical movements.
// Section 03
EZ Template Built-In PID Tuner 🎛️
Adjust constants live on the controller without re-uploading — the fastest way to tune.
This is the biggest time-saver in EZ Template. Instead of editing code → saving → building → uploading → testing (60+ seconds per iteration), you adjust constants on the controller and test instantly. A full PID tuning session that used to take an hour takes 10 minutes.

Setup — Enable the Tuner in opcontrol()

📄 src/main.cpp — opcontrol() — already included in example project
void opcontrol() { chassis.drive_brake_set(MOTOR_BRAKE_COAST); while (true) { if (!pros::competition::is_connected()) { if (master.get_digital_new_press(DIGITAL_X)) chassis.pid_tuner_toggle(); if (master.get_digital_new_press(DIGITAL_B)) autonomous(); chassis.pid_tuner_iterate(); } chassis.opcontrol_tank(); pros::delay(ez::util::DELAY_TIME); } }

How to Use the Tuner — Step by Step

1
Turn on the tuner
Press X on the controller. The Brain screen will show the current PID constants and which one is selected (highlighted).
2
Choose which PID to tune
Press Left/Right on the d-pad to cycle between Drive, Turn, Swing, Heading, and any custom PIDs you added. The selected PID is shown on screen.
3
Choose which constant to change
Press Up/Down on the d-pad to move between kP, kI, kD, and Start-I. The selected row is highlighted on the Brain screen.
4
Adjust the value
Press A to increase the value, Y to decrease. Hold the button to change faster. The increment size can be adjusted — by default it changes in small steps.
5
Run the autonomous test
Press B to run your current autonomous routine with the new constants. Watch the robot. Adjust. Repeat.
6
Save your values to code
When satisfied, write the values shown on screen into your default_constants() function in autons.cpp. The tuner does NOT save automatically — you must copy the numbers into code manually.
⚠️
The tuner values are lost when you turn off the Brain! After every tuning session, immediately copy the constants from the Brain screen into your code before shutting down. Many teams have lost a full session of tuning by forgetting this step.

Add Custom PIDs to the Tuner

You can add your own subsystem PIDs (arm, lift, etc.) to the tuner so you can tune them the same way:

📄 src/main.cpp — in initialize()
// Create your PID object ez::PID liftPID(0.45, 0.0, 2.0, 0, "Lift"); // Add it to the tuner in initialize() chassis.pid_tuner_pids.push_back({"Lift PID", &liftPID.constants});
// Section 04
Drive PID — Tuning Procedure 🚗
A repeatable, step-by-step process for tuning your robot's forward/backward movement.

Test Autonomous for Drive Tuning

Always tune with a repeatable test — don't use your actual autonomous. Write a dedicated tuning routine:

📄 src/autons.cpp — drive tuning test
void drive_tune_test() { // Simple out-and-back: 36 inches forward, 36 inches back // Easy to see overshoot and settling on both ends chassis.pid_drive_set(36_in, 110); chassis.pid_wait(); pros::delay(500); chassis.pid_drive_set(-36_in, 110); chassis.pid_wait(); }

Drive PID Tuning Procedure

  1. Start: Set drive constants to (0.0, 0.0, 0.0). Run test — robot does nothing (expected).
  2. kP only: Set kP = 5.0. Run test. Robot should move but undershoot.
  3. Increase kP in steps of 2–3 until the robot reliably overshoots (goes past 36 inches). Note the overshoot kP value.
  4. Back off kP to about 70–75% of the overshoot value. Robot should now stop near target.
  5. Add kD: Set kD = 50. Run test. Increase kD in steps of 20–30 until oscillation stops.
  6. Verify: Run 5 repetitions. Measure where the robot stops each time. Variance should be under 0.5 inches.
  7. Only if needed: Add kI = 0.003 if robot consistently stops short.

Typical Starting Values for EZ Template

// In default_constants() — autons.cpp // These are starting points — tune for YOUR robot chassis.pid_drive_constants_set( 10.0, // kP — typical range 5–20 0.0, // kI — start at 0, add only if needed 100.0 // kD — typical range 50–200 ); chassis.pid_heading_constants_set( 11.0, // kP — keeps robot straight while driving 0.0, // kI 20.0 // kD );
💡
Test on the actual competition surface. A robot tuned on concrete will behave very differently on VRC foam tiles. Tile friction is lower, which means less motor force is needed — your kP may need to come down when moving from hard floor to tiles.
// Section 05
Turn PID — Tuning Procedure 🔄
Turn PID needs separate tuning — turns behave very differently from straight driving.

Test Autonomous for Turn Tuning

📄 src/autons.cpp — turn tuning test
void turn_tune_test() { // Turn right 90°, turn back left 90° — repeat this to spot drift // Use tape on floor to mark the start heading direction chassis.pid_turn_set(90_deg, 90); chassis.pid_wait(); pros::delay(500); chassis.pid_turn_set(0_deg, 90); chassis.pid_wait(); }

Turn PID Tuning Procedure

  1. Start: Set turn constants to (0.0, 0.0, 0.0).
  2. kP only: Set kP = 2.0. Robot should turn but not reach 90° fully.
  3. Increase kP in steps of 0.5 until robot overshoots. Turn kP values are much lower than drive — usually 2–6.
  4. Back off kP to 70% of overshoot value.
  5. Add kD: Start at 10.0. Increase in steps of 5 until wobbling at the end stops.
  6. Accuracy test: Turn right 90°, measure with a protractor or phone compass. Should be within ±2°.
  7. Repeatability test: Run 5 right turns from the same starting point. All should end within ±1° of each other.

Typical Turn PID Starting Values

// In default_constants() — autons.cpp chassis.pid_turn_constants_set( 3.0, // kP — typical range 1–6 (MUCH lower than drive kP!) 0.05, // kI — small amount often needed for turns 20.0 // kD — typical range 10–40 );
💡
Why is turn kP so much lower than drive kP? Turning involves two wheels fighting each other (one forward, one backward). This generates much more effective force per unit of PID output. A kP of 10 for driving would make the robot spin out of control when turning — the math is different for each motion type.

Swing PID (One-Side Turn)

Swing turns pivot using only one side of the drive. EZ Template supports these with pid_swing_set(). They need their own constants:

chassis.pid_swing_constants_set( 5.0, // kP — between drive and turn kP 0.0, // kI 30.0 // kD );
// Section 06
Pre-Competition PID Checklist ✅
Run through this before every competition. PID problems that go unnoticed in practice will always show up in a match.
📋
This checklist takes about 10 minutes. Do it the day before competition, not the morning of. If you find a problem the morning of, you need time to fix it.

Mechanical Pre-Checks (Do These First)

⚠️
PID cannot fix mechanical problems. Loose axles, worn gears, uneven wheel pressure, and motor slop will all make PID tuning impossible. Fix the hardware first, then tune.

Software Verification

What "Good Enough" Looks Like

DRIVE ACCURACY
± 0.5"
Over 36 inches. Competition ready.
TURN ACCURACY
± 1–2°
Per 90° turn. Excellent for competition.
REPEATABILITY
< 1"
Variation between 5 identical runs. More important than raw accuracy.
Repeatability beats accuracy. A robot that consistently stops 0.5" short is better than one that sometimes hits perfectly and sometimes misses by 3". Write your autonomous paths around predictable behavior, not perfect behavior.
📓
Log your constants in your engineering notebook after every tuning session. Record the date, surface type, battery level, and constants used. If something changes between events, you have a history to reference and revert to.
⚙ STEM Highlight Mathematics: Differential Equations & Dynamic Systems
A PID controller is a linear differential equation in disguise. The plant (your drive) is a second-order dynamic system; the PID adds derivative and integral feedback to achieve desired behavior. Overdamped (large kD): slow but no overshoot. Underdamped (small kD): fast but oscillates. Critically damped: fastest response with no overshoot — the tuning target. The settling time and overshoot are analytically predictable from the system’s characteristic equation — the same math as spring-mass-damper systems in physics.
🎤 Interview line: “PID tuning is applied control theory. We target critical damping — the mathematical optimum between underdamped oscillation and overdamped sluggishness. We diagnose our system by classifying the step response: no overshoot but slow means overdamped, oscillating means underdamped. The data logging graphs make this classification visual.”
🔬 Check for Understanding
Your drive PID reaches the target 36-inch command, overshoots to 38 inches, then oscillates between 35 and 37 inches before settling. This behavior indicates:
kP is too low — the system is not responsive enough
kI is accumulating too much — steady-state error is growing
The system is underdamped — kD is too low to damp the oscillation, or kP is too high
The drive motors are overheating
Related Guides
📍 Odometry →⚡ Exit Conditions →🤖 Full Robot Code →📊 Data Logging →
← ALL GUIDES