📏 Hardware · Intermediate Autonomous

Distance Sensor Positioning

Use the VEX V5 distance sensor with EZ Template to align precisely to field walls. Consistent autonomous starts, repeatable skills cycles, and reliable scoring positions — without guessing.

// Section 01
What It Does & When to Use It
The distance sensor measures exactly how far the robot is from an object. Walls don't move — which makes them perfect reference points for consistent positioning.

What the Distance Sensor Measures

The VEX V5 distance sensor uses ultrasonic and optical principles to measure the gap between the sensor face and the nearest surface in front of it. It returns a value in millimeters (mm) by default, with a usable range of roughly 20 mm to 2000 mm.

Unlike encoders — which measure how far the robot has moved — the distance sensor measures how far the robot currently is from a surface. That distinction matters: motor slip, carpet variation, and starting position errors all corrupt encoder-based placement. A wall does not move.

Consistency beats precision. A robot that positions at exactly 310 mm from the wall every single time will outscore a robot that averages 300 mm but varies by ±40 mm. Use the sensor to lock in repeatable positioning, then tune scoring from there.

When to Use a Distance Sensor

✅ Good Use Cases
  • Aligning flush to a field wall before scoring
  • Stopping at a fixed scoring distance from a goal
  • Resetting position mid-skills run at a wall
  • Recovering from encoder drift after a collision
  • Ensuring identical starting position every match
  • Pre-score alignment for high-cycle routines
❌ Not Ideal For
  • Navigating mid-field with no wall reference
  • Sensing mobile game objects (inconsistent surface)
  • Continuous long-range tracking (use odometry)
  • Readings through transparent or mesh surfaces
  • Very fast approaches (needs speed limiting near target)
🏆
Skills runs or head-to-head matches? Both — with different priorities.
In skills, the distance sensor is most valuable: position resets every 3–4 cycles eliminate 60-second drift accumulation. In autonomous head-to-head, include it when your routine scores from a fixed wall-adjacent position — battery level and tile surface variation affect encoder accuracy in matches too. In driver control, skip it: a 0.3–0.5 second stop costs more than the alignment gain in a 1:45 match.
Default rule: use it in auton and skills, not in driver-controlled repositioning.

Why Walls Work as Reference Points

Field perimeter walls are fixed, flat, and reflective enough for accurate distance readings. A robot that drives forward until distance == 280mm from the back wall will stop at the same physical position regardless of:

This is why top skills programs build explicit wall-touch or wall-approach steps into their routines — not because they need the wall, but because the wall gives them a known position to reset from.

// Section 02
Hardware Setup
Mounting position determines accuracy. A sensor that's angled, obstructed, or mounted too high will give unreliable readings — fix this in hardware before writing a line of code.

Mounting Position

📚 Front-Mounted
  • Best for wall-approach and stop-before-goal
  • Measures distance during the drive move
  • Can conflict with intake mechanism clearance
  • Most common position on Spartan Design robots
📚 Side-Mounted
  • Useful for lateral alignment to a side wall
  • Good for correcting parallel parking approaches
  • Requires the robot to be travelling parallel to the wall
  • Needs a separate sensor or a second port
⚠️
Test your mounting before competition day. Rotate the robot so the sensor faces each field wall. Read the values on the Brain screen. All four walls should give consistent readings at the same physical distance. If one wall reads 50 mm different from the others, the sensor may be angled.

Wiring

Assign a named constant for the port number. Write const int DIST_PORT = 3; at the top of robot-config.cpp rather than hardcoding 3 everywhere. One port change = one edit.
// Section 03
EZ Template Setup & Positioning Code
Declare the sensor, read its value in a loop, and stop when you hit your target distance. The pattern is simple — the tuning is where it gets precise.

1. Declare the Sensor

Add the sensor declaration to robot-config.cpp and expose it in the header so it's accessible from autons.cpp.

src/robot-config.cpp
// Distance sensor — Smart Port 3 pros::Distance dist_sensor(3);
include/robot-config.hpp
extern pros::Distance dist_sensor;

2. Read the Value

The distance sensor returns its reading in millimeters. Calling .get() returns the current distance as an integer.

int dist = dist_sensor.get(); // distance in mm
ℹ️
Print to the Brain screen during testing. Add a pros::screen::print() line so you can watch the live value as you push the robot toward a wall. This is how you find your target distance without guessing.
src/main.cpp — in initialize() for testing
void initialize() { chassis.initialize(); // Live distance readout on Brain screen while (true) { pros::screen::print(pros::E_TEXT_MEDIUM, 1, "Dist: %d mm", dist_sensor.get()); pros::delay(50); } }

Push the robot to your desired position, note the reading, and use that as your target.

3. Basic Positioning Loop

Drive toward the wall at a moderate speed. Check the distance every loop cycle. Stop when you reach your target.

src/autons.cpp — basic stop-at-distance function
// Drive forward until dist_sensor reads ≤ target_mm // speed: motor voltage, 0–127 void drive_to_wall(int target_mm, int speed) { chassis.drive_set(speed, speed); // start driving while (dist_sensor.get() > target_mm) { pros::delay(10); // check every 10ms } chassis.drive_set(0, 0); // stop motors pros::delay(100); // brief settle }

4. Full Practical Example — Align to Wall, Then Score

This pattern is the most common skills use case: drive to a known wall distance, stop precisely, then score from a consistent position.

src/autons.cpp — skills alignment sequence
void skills_run() { // ── Step 1: drive toward back wall ───────────────────────────── chassis.drive_set(60, 60); // 60/127 — moderate approach speed while (dist_sensor.get() > 280) { // target: 280mm from wall pros::delay(10); } chassis.drive_set(0, 0); // stop pros::delay(150); // allow robot to settle // ── Step 2: reset chassis odometry to known position ─────────── // Now that we're at a known distance, reset tracking position chassis.drive_imu_reset(0); // reset heading // ── Step 3: score ─────────────────────────────────────────────── intake_run(127); // run intake/scorer pros::delay(600); intake_run(0); // ── Step 4: back away and continue routine ────────────────────── chassis.pid_drive_set(-24, 110); // back 24 inches via EZ PID chassis.pid_wait(); }
Combine distance-sensor stops with EZ Template PID moves. Use the sensor for the final alignment step, then use pid_drive_set() for all subsequent movements. The sensor gives you a reliable origin; EZ does the rest.
// Section 04
Skills Run Applications
Three practical patterns used in competitive skills runs. Each one uses a wall as a position reset to eliminate accumulated error before a critical move.

Pattern 1 — Pre-Score Alignment

Before every goal approach, drive to a fixed distance from the wall behind or beside the goal. This puts the robot in the same physical position every cycle regardless of where it came from in the previous one.

// Approach goal wall and align void align_to_goal_wall() { chassis.drive_set(50, 50); while (dist_sensor.get() > 300) pros::delay(10); chassis.drive_set(0, 0); pros::delay(100); // Robot is now at 300mm from wall — ready to score }

Pattern 2 — Mid-Run Position Reset

After 3–4 scoring cycles, encoder position has drifted. Drive into a corner or back wall briefly to reset the known position before the next sequence.

// Touch the back wall to reset position void wall_reset() { chassis.drive_set(40, 40); while (dist_sensor.get() > 80) pros::delay(10); chassis.drive_set(0, 0); // Near-wall — robot position is now known // Reset odometry or heading here if using EZ odom }

Pattern 3 — Repeatable Cycle Loop

Structure a full skills cycle as: approach → sensor stop → score → depart → repeat. Every cycle starts from the same position, so cycle 6 looks the same as cycle 1.

// Repeatable scoring cycle using distance sensor for alignment void score_cycle(int cycles) { for (int i = 0; i < cycles; i++) { // 1. Load ring from ground intake_run(127); chassis.pid_drive_set(12, 90); chassis.pid_wait(); // 2. Align to goal wall with distance sensor chassis.drive_set(50, 50); while (dist_sensor.get() > 300) pros::delay(10); chassis.drive_set(0, 0); pros::delay(100); // 3. Score score(); // 4. Back away to collect next ring intake_run(0); chassis.pid_drive_set(-20, 110); chassis.pid_wait(); } }
ℹ️
Notebook this. A distance-sensor alignment step is exactly the kind of engineering decision judges want documented: what problem did it solve, what did you test, what did you measure before and after. Include your target value and how you arrived at it.
🔬 Practice Drill
Stop Exactly 300 mm from the Wall — 10 Consecutive Reps

Run drive_to_wall(300, 60) from different starting positions: 6 feet out, 4 feet out, angled approach. Measure the actual stopping distance with a tape measure after each run. Log the result.

  • Target: stop within ±10 mm of 300 mm on all 10 reps
  • If you're outside ±10 mm: reduce approach speed from 60 → 45
  • If you're within ±5 mm consistently: you're competition-ready on this move
  • Log: starting distance, measured stop, pass/fail in your test notebook entry
Run this drill on both practice mat and competition tiles. If results differ, the surface friction is changing your stopping distance — adjust your target value for comp.
// Section 05
Common Mistakes & Advanced Tips
Four mistakes that cause inconsistent stops — and four upgrades that take distance positioning from good to reliable.

Common Mistakes

✖ Sensor Mounted at an Angle

A sensor that's 20° off perpendicular reads a longer distance than the true gap. Your robot stops physically farther from the wall than your target value expects.

Fix: Use a speed square or right-angle bracket to mount the sensor parallel to the robot frame, perpendicular to the target wall. Verify by observing that the reading decreases linearly as you push the robot straight toward the wall.
✖ Forgetting the Default Unit Is Millimeters

Setting a target of 12 when you mean 12 inches will stop the robot 0.5 inches from the wall, not 12 inches. Confusion between mm and inches wastes practice time and breaks routines at competitions.

Fix: Always work in mm. Confirm by printing the live value and physically measuring with a ruler. Add a comment next to every target value: 300 // 300mm ≈ 11.8 inches from wall
✖ Approaching Too Fast

At high speed (100+/127), the robot's momentum carries it past the target before the motors can respond. The sensor triggers the stop at the right moment, but the robot physically overshoots by several inches.

Fix: Use 40–70/127 for distance-sensor approaches. If you need a fast approach, use a two-phase drive: fast until ~200 mm away, then reduce to 40 for the final approach. See the advanced tip below.
✖ No Noise Filtering on the Reading

Distance sensors occasionally return a spurious value (999 mm when next to a wall, or 0 when far away). A single false reading can trigger an early stop or cause the loop to miss its exit condition entirely.

Fix: Add a simple averaging check: only exit the loop if two or more consecutive readings are below the target. See the filtered version below.

Advanced Tips

Tip 1 — Two-Phase Approach (Fast → Slow)

Drive fast until the sensor sees ~200 mm, then switch to a slow creep for the final approach. This gives you speed on the bulk of the move and precision at the end.

void drive_to_wall_smooth(int target_mm) { // Phase 1: fast approach until 200mm chassis.drive_set(90, 90); while (dist_sensor.get() > 200) pros::delay(10); // Phase 2: slow creep to target chassis.drive_set(35, 35); while (dist_sensor.get() > target_mm) pros::delay(10); chassis.drive_set(0, 0); pros::delay(100); }

Tip 2 — Filtered Reading (Two Consecutive Confirmations)

Require two consecutive readings below the target before stopping. This filters out a single bad sensor value without adding meaningful time.

void drive_to_wall_filtered(int target_mm, int speed) { chassis.drive_set(speed, speed); int confirm = 0; while (confirm < 2) { if (dist_sensor.get() <= target_mm) { confirm++; } else { confirm = 0; // reset on any bad reading } pros::delay(10); } chassis.drive_set(0, 0); pros::delay(100); }

Tip 3 — Combine with IMU for Heading Correction

Driving toward a wall while tracking heading with the IMU lets you stay perpendicular. If the robot drifts 5° during the approach, it arrives at the wall at an angle — which shifts the stopping position by 20–40 mm at a 300 mm target. Correct heading during the approach loop.

// Add heading correction during distance approach float target_heading = chassis.drive_imu_get(); // lock heading at start chassis.drive_set(55, 55); while (dist_sensor.get() > 300) { float heading_err = target_heading - chassis.drive_imu_get(); float correction = heading_err * 0.8; // small kP chassis.drive_set(55 + correction, 55 - correction); pros::delay(10); } chassis.drive_set(0, 0);

Tip 4 — Reusable Function Library

Don't copy the same while-loop throughout your auton file. Write it once, call it everywhere. This is also notebook-worthy — it shows systematic engineering, not just hacking a solution together.

// autons.hpp — add these declarations void drive_to_wall(int target_mm, int speed = 60); void drive_to_wall_smooth(int target_mm); void drive_to_wall_filtered(int target_mm, int speed = 50); // Usage in any auton: drive_to_wall_smooth(280); // fast then slow to 280mm drive_to_wall(300); // default speed, 300mm target
⚙ STEM Highlight
Technology: Sensor Feedback & Closed-Loop Control
The distance-sensor approach loop is a simple form of closed-loop control — the robot continuously reads a sensor, compares the output to a target, and adjusts behavior accordingly. This is the same fundamental principle used in industrial robot arms, autonomous vehicles, and CNC machining. The alternative — driving for a set time or encoder count — is open-loop and accumulates error because it ignores the actual physical state of the system.

Using a wall as a reference point is called landmark-based positioning. GPS satellites, AprilTag navigation, and warehouse robot systems all use variants of this: find a known, fixed reference, measure your distance to it, and use that to anchor your position in space.
🎤 Interview line: "We use the distance sensor as a closed-loop positioning system — the robot continuously reads its distance from the field wall and stops when it hits our target. This eliminates the open-loop error that accumulates with encoders alone, and gives us a consistent starting position for every scoring attempt."
🔬 Check for Understanding
Your robot stops at 340 mm from the wall when you target 300 mm. You're running at speed 100/127. What's the most likely cause?
The sensor is reading in inches, not mm
The robot is moving too fast and overshoots before motors respond to the stop command
The target value is too small
The sensor needs to be re-declared in the header file
Correct. At high speed, the robot's momentum carries it past the stop point before the motors can arrest motion. Reduce approach speed to 40–70/127, or use a two-phase approach — fast until 200 mm, then slow to target.

Key Takeaways

Related Guides
🔬 PID Diagnostics → 📍 Odometry → 🌍 GPS Sensor → ⚡ Exit Conditions → ⚡ Wiring & ESD →
📝
← ALL GUIDES