VEX V5 PYTHON | 06.2 WHEEL TRAVEL CONVERSION
Guide objective
Convert signed sensor changes into millimetres, account for gearing and calibrate the distance scale against measured physical travel.
01 | FROM ROTATION TO LINEAR TRAVEL
A Rotation Sensor reports shaft rotation. To estimate wheel travel, you need the signed sensor change, the wheel’s effective circumference and the relationship between sensor and wheel turns.
Wheel travel = sensor turn change × wheel turns per sensor turn × wheel circumference.
The result describes travel along the tracking wheel’s rolling direction. It is not automatically robot-centre movement or field displacement.
02 | ONE WHEEL TURN COVERS ONE CIRCUMFERENCE
For a wheel rolling without slip, one complete turn covers its circumference:
Circumference = π × diameter.
| Wheel diameter | Circumference | Direct-coupled travel for 2 turns |
|---|---|---|
| 69.85 mm (2.75 inches) | Approximately 219.44 mm | Approximately 438.88 mm |
| 100 mm | Approximately 314.16 mm | Approximately 628.32 mm |
Use consistent units. A diameter of 2.75 entered into a millimetre formula means 2.75 mm, not 2.75 inches. Convert inches to millimetres by multiplying by 25.4.
Wheel compression and contact conditions can make the effective rolling circumference differ from the nominal value.
03 | USE TURNS OR CONVERT DEGREES
One turn is 360 degrees. Divide a degree change by 360 before multiplying by circumference.
| Signed sensor change | Equivalent turns | Direct-coupled travel with 69.85 mm wheel |
|---|---|---|
| +360 degrees | +1 | +219.44 mm |
| +900 degrees | +2.5 | +548.60 mm |
| -180 degrees | -0.5 | -109.72 mm |
Use multi-turn position(TURNS) or position(DEGREES). The sensor’s single-turn angle wraps every revolution, so it cannot by itself distinguish one turn from several turns.
Using degrees directly as turns makes the result 360 times too large.
04 | SUBTRACT THE STARTING READING
You do not need to reset sensor position for every measurement. Capture a start reading and subtract it from the current reading.
start_turns = tracking.position(TURNS) # After the measured movement: end_turns = tracking.position(TURNS) delta_turns = end_turns - start_turns
If the sensor starts at 12.4 turns and ends at 14.9 turns, the change is +2.5 turns. If it ends at 11.9 turns, the change is -0.5 turns.
Resetting a sensor while another task is using its previous reading creates a false jump. Establish one owner for measurement state and document any reset.
05 | DEFINE THE GEAR RATIO EXPLICITLY
The variable in this guide is wheel turns per sensor turn. Ask: when the sensor makes one turn, how many turns does the wheel make?
| Arrangement | Sensor turns for 1 wheel turn | Wheel turns per sensor turn |
|---|---|---|
| Same shaft / direct coupling | 1 | 1.0 |
| Sensor rotates twice per wheel turn | 2 | 0.5 |
| Sensor rotates half a turn per wheel turn | 0.5 | 2.0 |
If a 48-tooth gear on the wheel shaft drives a 24-tooth gear on the sensor shaft, the sensor turns twice per wheel turn. The conversion ratio is 24/48 = 0.5.
Gear mesh can reverse shaft direction. Keep the ratio magnitude positive and configure the sensor sign so the intended positive wheel movement produces positive readings.
For compound gearing, verify the final relationship physically. Rotate the wheel one marked turn and observe the sensor change rather than relying on an unexplained label such as 2:1.
06 | WORK THROUGH A GEARED EXAMPLE
A 69.85 mm wheel turns through a sensor ratio of 0.5 wheel turns per sensor turn. The sensor changes by +5 turns:
- Wheel turns = 5 × 0.5 = 2.5.
- Circumference = π × 69.85 ≈ 219.44 mm.
- Wheel travel = 2.5 × 219.44 ≈ 548.60 mm.
The same sensor change of -5 turns gives approximately -548.60 mm.
If you accidentally use the reciprocal ratio of 2.0, the estimate becomes approximately 2194.40 mm, four times too large. Check the ratio before trying to calibrate away a large error.
07 | SMALL REUSABLE CONVERSION FUNCTIONS
import math
def turns_to_mm(delta_turns, diameter_mm, wheel_turns_per_sensor_turn):
return delta_turns * math.pi * diameter_mm * wheel_turns_per_sensor_turn
def degrees_to_mm(delta_degrees, diameter_mm, wheel_turns_per_sensor_turn):
return turns_to_mm(delta_degrees / 360.0, diameter_mm,
wheel_turns_per_sensor_turn)
def fit_mm_per_sensor_turn(trials):
# Each trial is (signed sensor turn change, signed known distance mm).
# Least-squares scale through zero; does not correct slip or bad geometry.
if len(trials) < 3:
raise ValueError("Collect at least three accepted trials")
numerator = denominator = 0.0
for turns, distance in trials:
if not math.isfinite(turns) or not math.isfinite(distance):
raise ValueError("Non-finite trial")
if abs(turns) < 0.05 or abs(distance) < 100:
raise ValueError("Trial too short for this calibration policy")
if turns * distance <= 0:
raise ValueError("Sensor sign disagrees with physical direction")
numerator += turns * distance
denominator += turns * turns
scale = numerator / denominator
if not math.isfinite(scale) or scale <= 0:
raise ValueError("Invalid scale")
return scale
The first two functions use diameter and gearing explicitly. The fitting function instead derives a combined millimetres-per-sensor-turn scale from measured trials.
The fit assumes a proportional relationship through zero. Capture actual start/end differences for every trial so an arbitrary sensor starting value is not treated as a distance offset.
A good numerical fit cannot repair wheel slip, changing contact or incorrect trial measurements.
08 | CALIBRATE AGAINST PHYSICAL DISTANCE
- Verify wheel contact, sensor sign and gear ratio.
- Mark a measured straight course on the normal operating surface.
- Use a repeatable chassis reference mark for both start and finish.
- Capture the start reading while stationary.
- Move straight along the tracking wheel’s measurement direction without appreciable turning.
- Stop at the measured endpoint and capture the finish reading.
- Repeat at least three times, including reverse trials.
Use a sufficiently long course to reduce endpoint measurement error, while keeping the movement controlled. Repeat under normal load.
A sideways tracker needs travel along its own rolling direction. Do not calibrate it from forward movement. Use an appropriate test fixture if the drivetrain cannot translate sideways without scrubbing.
09 | CORRECT A CONSISTENT SCALE ERROR
Suppose nominal conversion reports 970 mm for a physically measured 1000 mm movement:
Correction factor = actual distance / estimated distance = 1000 / 970 ≈ 1.03093.
If the ratio is already verified, an old diameter of 69.85 mm becomes an effective diameter of approximately 72.01 mm when multiplied by that factor.
This is an effective conversion parameter, not a claim that the wheel physically grew. Check several trials before accepting the adjustment.
Alternatively calculate millimetres per sensor turn directly as known distance divided by sensor turn change, or fit the scale across multiple trials. This combined scale already includes gearing: do not multiply by the ratio again.
10 | MOTOR-FREE CAPTURE AND FIT PROJECT
This complete VEXcode example uses a forward Rotation Sensor on Smart Port 17. It commands no motors. Paste below # Begin project code with VEX imports and generated Brain setup above it, and avoid duplicate device declarations.
Set KNOWN_LENGTH_MM to the physically measured course length. A captures the start, B saves the endpoint, Y selects forward/reverse while idle, and X prints a fit after at least three accepted trials.
# =============================================================================
# TEAM [MY TEAM NAME / NUMBER] | TRACKER DISTANCE CALIBRATION
# =============================================================================
# No motor commands. Move the robot along a measured straight line.
# Forward tracker: Rotation Sensor Smart Port 17.
# Keep generated VEX imports and brain above '# Begin project code'.
# Do not duplicate this declaration in Devices.
# A rising edge: capture start; B rising edge: finish/save trial.
# Y rising edge while idle: toggle forward/reverse known distance sign.
# X rising edge while idle: print fitted scale and residuals.
# Re-run project to clear trials. B is a capture button in this motor-free lab.
tracking = Rotation(Ports.PORT17, False)
controller = Controller(PRIMARY)
NOMINAL_DIAMETER_MM = 69.85
WHEEL_TURNS_PER_SENSOR_TURN = 1.0
KNOWN_LENGTH_MM = 1000.0 # Measure the actual marked course; change as needed.
known_sign = 1
start_turns = None
trials = []
import math
def turns_to_mm(delta_turns, diameter_mm, wheel_turns_per_sensor_turn):
return delta_turns * math.pi * diameter_mm * wheel_turns_per_sensor_turn
def degrees_to_mm(delta_degrees, diameter_mm, wheel_turns_per_sensor_turn):
return turns_to_mm(delta_degrees / 360.0, diameter_mm,
wheel_turns_per_sensor_turn)
def fit_mm_per_sensor_turn(trials):
# Each trial is (signed sensor turn change, signed known distance mm).
# Least-squares scale through zero; does not correct slip or bad geometry.
if len(trials) < 3:
raise ValueError("Collect at least three accepted trials")
numerator = denominator = 0.0
for turns, distance in trials:
if not math.isfinite(turns) or not math.isfinite(distance):
raise ValueError("Non-finite trial")
if abs(turns) < 0.05 or abs(distance) < 100:
raise ValueError("Trial too short for this calibration policy")
if turns * distance <= 0:
raise ValueError("Sensor sign disagrees with physical direction")
numerator += turns * distance
denominator += turns * turns
scale = numerator / denominator
if not math.isfinite(scale) or scale <= 0:
raise ValueError("Invalid scale")
return scale
# =============================================================================
# DISPLAY / CAPTURE ONLY
# =============================================================================
previous_a = controller.buttonA.pressing()
previous_b = controller.buttonB.pressing()
previous_x = controller.buttonX.pressing()
previous_y = controller.buttonY.pressing()
print("Motor-free calibration: A start, B finish, Y direction, X fit")
while True:
a = controller.buttonA.pressing()
b = controller.buttonB.pressing()
x = controller.buttonX.pressing()
y = controller.buttonY.pressing()
try:
now_turns = tracking.position(TURNS)
if not math.isfinite(now_turns):
raise ValueError("Invalid sensor reading")
if a and not previous_a and start_turns is None:
start_turns = now_turns
print("Start captured; signed known distance:", known_sign * KNOWN_LENGTH_MM)
elif b and not previous_b and start_turns is not None:
delta = now_turns - start_turns
known = known_sign * KNOWN_LENGTH_MM
start_turns = None
if abs(delta) < 0.05 or abs(known) < 100 or delta * known <= 0:
print("Trial rejected: check direction and measured length")
else:
trials.append((delta, known))
nominal = turns_to_mm(delta, NOMINAL_DIAMETER_MM,
WHEEL_TURNS_PER_SENSOR_TURN)
print("Trial", len(trials), "turns", delta,
"known mm", known, "nominal mm", nominal)
elif y and not previous_y and start_turns is None:
known_sign *= -1
print("Next direction:", "forward" if known_sign > 0 else "reverse")
elif x and not previous_x and start_turns is None:
scale = fit_mm_per_sensor_turn(trials)
effective_diameter = scale / (math.pi * WHEEL_TURNS_PER_SENSOR_TURN)
print("Fitted mm per sensor turn:", scale)
print("Effective diameter mm for configured ratio:", effective_diameter)
for index, (turns, known) in enumerate(trials):
predicted = turns * scale
print("Trial", index + 1, "residual mm", predicted - known)
print("Validate on new trials before copying the scale into odometry.")
except Exception as error:
start_turns = None
print("Capture/fit error:", error)
previous_a, previous_b, previous_x, previous_y = a, b, x, y
wait(50, MSEC)
The program assumes you reached the marked endpoint. It cannot verify the actual course length or straightness. Select reverse before a reverse trial so signed physical distance and sensor change agree.
The fit weights longer sensor-travel trials more strongly. It does not automatically update the conversion settings. Validate the result on new trials before copying it to your movement or odometry project.
11 | USE ONE CONVERSION METHOD AT A TIME
# Method A: effective diameter plus verified gear ratio. travel_mm = delta_turns * math.pi * effective_diameter_mm * ratio # Method B: directly calibrated combined scale. travel_mm = delta_turns * calibrated_mm_per_sensor_turn
Choose one method. Applying both the corrected diameter and a combined calibrated scale double-corrects the measurement.
Calibrate each tracking wheel separately. Identical nominal wheels can have different contact, gearing or effective scale.
This conversion is still raw wheel travel. Remove the offset-related rotational component from 06.1 before using it as robot-reference translation during a turn. Do not tune wheel diameter using a turning trial that mixes these effects.
12 | VALIDATE ON NEW TRIALS
| Trial | Known signed distance | Predicted distance | Residual |
|---|---|---|---|
| Forward test | +1000 mm | Record | Predicted - known |
| Reverse test | -1000 mm | Record | Predicted - known |
| Different-length test | Measured length | Record | Predicted - known |
Residuals growing consistently with distance suggest a scale issue. Variable errors suggest slip, contact changes or inconsistent endpoint measurement. Different forward/reverse behaviour can reveal backlash or mechanical effects.
Record the wheel, gearing, load, surface and date with the scale. Recheck after changing the mount, tyre or transmission.
CHALLENGES | CONVERT, CALIBRATE AND JUSTIFY
- Convert: find travel for +720 and -540 sensor degrees with a 69.85 mm direct-coupled wheel.
- Define: explain wheel turns per sensor turn for a sensor that rotates three times per wheel turn.
- Measure: verify your ratio with one marked wheel revolution.
- Capture: collect three straight trials with signed start/end readings.
- Fit: calculate a combined millimetres-per-sensor-turn scale.
- Validate: compare the fit against new forward and reverse trials.
- Diagnose: distinguish a constant scale error from inconsistent slip.
- Document: explain why gearing must not be applied twice to a combined scale.
Success evidence
A verified ratio, conversion calculations, calibration log and independent validation results. State the chosen conversion method, units and direction convention.
OFFICIAL REFERENCE
The calibration method, worked examples and capture project are independently written learning material. VEX and VEXcode are trademarks of their respective owners.