Gyro Turns
What you'll learn
- Understand why timing-based turns fail in competition
- Calibrate and read the inertial sensor correctly
- Implement a simple gyro turn
- Build a PID gyro turn function
- Handle angle wrapping correctly
- Use turn_to_heading() as a reusable building block
The Problem With Timed Turns
Here is a scenario that every VEX competitor has experienced:
You program a 90-degree turn using drivetrain.turn_for(RIGHT, 1.2, SECONDS). It works perfectly in your garage. You get to the competition. Same program. The robot turns 82 degrees instead of 90. The entire routine falls apart.
What happened? The motors run at different speeds depending on battery charge. The field tiles have different grip than your floor. The robot was carrying a slightly different load. Any of these factors can throw off a timed turn by 5-15 degrees.
The inertial sensor measures actual rotation. It does not care about battery level, floor friction, or motor variation. It just asks: how many degrees has the robot rotated? That is a fact that cannot be argued with.
The Inertial Sensor
The VEX IQ Inertial Sensor is a combination gyroscope and accelerometer built into the Brain. You do not need an external sensor — just import it:
Heading vs Rotation
The inertial sensor has two modes:
inertial.heading()— returns 0 to 359.99, wraps around like a compassinertial.rotation()— returns total rotation, can go past 360 (e.g., 450 after 1.25 turns)
For most autonomous turns, use heading. It is easier to work with — just say “turn until heading equals 90°.”
Simple Gyro Turn (No PID)
The most basic gyro turn: spin the robot until the heading matches the target.
This works, but notice the problem: the robot turns at full speed until it is 2 degrees away, then abruptly stops. This overshoot and jerk is acceptable for practice but unreliable in competition. PID fixes this.
The Angle Wrapping Problem
Before implementing PID turns, you must understand angle wrapping. The heading goes from 0 to 359. What happens when you want to turn from 350° to 10°?
- The “naive” error is
10 - 350 = -340°(turn 340 degrees backward) - The correct error is
+20°(turn 20 degrees forward, crossing the 0/360 boundary)
This bug will make your robot spin in circles if you do not handle it. The fix is always:
error = target - current
if error > 180:
error -= 360 # Take the shorter path backward
elif error < -180:
error += 360 # Take the shorter path forward
This ensures error is always between -180 and +180 (shortest path to target).
PID Gyro Turn
The Settled Check
Notice the settled counter. Instead of stopping the moment error < 1.5°, the robot must stay within 1.5° for 5 consecutive loops (about 100ms). This prevents the robot from stopping when it momentarily passes through the target heading on its way to oscillating.
This is called a settle condition and is essential for reliable PID turns.
Tuning Gyro Turns
Turn tuning works the same as drive tuning, but the values are different:
- Start with kp=1.0, ki=0, kd=0 — run a 90° turn test
- If it oscillates: reduce kp. If it barely moves: increase kp
- Once stable: add kd=0.1 to smooth out the approach
- If still stopping short: add ki=0.002
Typical competition values:
- kp: 1.2 to 2.5
- ki: 0 to 0.005
- kd: 0.15 to 0.4
Note that turn tuning values are very robot-specific. A heavy robot needs different values than a light one. Always tune on your actual competition robot.
Setting Heading at the Start
Always tell the inertial sensor what heading to start at. If your robot begins facing 0° (toward the scoring goal), use:
inertial.set_heading(0)
Call this after inertial.calibrate() and before any movement. This anchors your coordinate system so turn_to_heading(90) always means “face 90° from where I started.”
Common Mistakes
Not waiting for calibration: inertial.calibrate() takes 2 full seconds. If you start moving before it finishes, the sensor gives garbage readings.
Relative vs absolute headings: turn_to_heading(90) is absolute — face 90°. There is no concept of “turn 90 degrees from wherever I am” in this function. If you want relative turns, calculate: turn_to_heading(inertial.heading() + 90 % 360).
Moving the robot during calibration: The inertial sensor must be stationary during the 2-second calibration period. Do not touch or move the robot.
Next Steps
You now have the two core building blocks of a competitive autonomous routine: pid_drive() and turn_to_heading(). With these, you can program any sequence of movements accurately.
VEX Tutorials