Distance Sensor
An ultrasonic sensor that looks like a pair of eyes and measures the distance to objects ahead.
How it works, and range
It emits inaudible ultrasound and times the echo:
- Range 5-200 cm (official spec: 50-2000 mm, accuracy ±2 cm).
- The two "eyes" share 4 programmable LED segments (2 per eye) you can light up for status display.
- When there's no target (too far, too close, sound-absorbing surface) it returns an invalid reading.
What it detects well
| Target | Result |
|---|---|
| Flat hard surfaces (walls, model sides) | ✅ accurate |
| Surfaces facing the sensor | ✅ accurate |
| Angled surfaces (> ~30°) | ⚠️ echo bounces away, may miss |
| Thin poles, grids, soft fabric | ❌ unreliable |
Word Blocks
(distance sensor [D] distance in cm) ← reporter block (round value block)
<distance sensor [D] distance < [10] cm> ← condition
wait until <distance sensor [D] distance < [10] cm>Example 1: approach and slow down
Full speed toward the model, slow near it, avoid knocking it over:
when program starts
set movement motors [A+E]
set movement speed [80] %
start moving [forward]
wait until <distance sensor [D] distance < [20] cm>
set movement speed [25] %
start moving [forward]
wait until <distance sensor [D] distance < [6] cm>
stop movingExample 2: keep distance (follow)
forever
if <distance sensor [D] distance < [10] cm> then
start moving [backward]
else
if <distance sensor [D] distance > [15] cm> then
start moving [forward]
else
stop movingPython
import runloop, distance_sensor
from hub import port
async def main():
d = distance_sensor.distance(port.D) # millimeters; -1 when no target
if d != -1 and d < 100: # under 10 cm
pass
runloop.run(main())Python returns millimeters
Word Blocks show cm; Python's distance() returns mm and -1 when nothing is detected. Check for -1 first, otherwise "-1 < 100" is always true and the robot thinks it has arrived.
FLL uses
- Precise stops: more slip-proof than counting rotations, ideal for "stop 8 cm before the model".
- Crash guard: a parallel stack doing "distance < 10 cm → emergency stop" during long sprints. Keep the threshold well above the 5 cm range floor (too close returns invalid readings, so
< 5may never fire) and leave braking distance at speed. - Localization: measure square-on to a wall whose position you know, and you know the robot's position along that axis (one-dimensional; angled walls give unreliable readings).
Common pitfalls
- The sound cone spreads: the floor up close or a neighboring model can be "seen". Mount the sensor a bit higher, not at mat level.
- Two robots' distance sensors can interfere (rare but real on back-to-back tables).
- Sampling has latency - leave braking distance at high speed.
Python API quick reference
| Function | Returns | Notes |
|---|---|---|
distance_sensor.distance(port.D) | int, millimeters | -1 when no target (too far, too close, absorbing surface) - always check first |
The 4 LED segments around the eyes are also controllable from Python - see the distance_sensor light functions in the official API reference if you want status lights.
More examples
Two-stage approach, in Python
Fast toward the model, slow for the last stretch, stop at 8 cm. The closer_than helper builds a condition function that treats -1 as "not there yet". Note the timeouts are safety fallbacks, not distance triggers - if a stage times out, the program moves on without having reached that distance:
import runloop, motor_pair, distance_sensor
from hub import port
motor_pair.pair(motor_pair.PAIR_1, port.A, port.E)
def closer_than(mm):
def check():
d = distance_sensor.distance(port.D)
return d != -1 and d < mm
return check
async def main():
motor_pair.move(motor_pair.PAIR_1, 0, velocity=600)
await runloop.until(closer_than(200), 6000) # 20 cm: slow down (6 s safety timeout)
motor_pair.move(motor_pair.PAIR_1, 0, velocity=180)
await runloop.until(closer_than(80), 4000) # 8 cm: stop (4 s safety timeout)
motor_pair.stop(motor_pair.PAIR_1)
runloop.run(main())Crash guard running alongside the mission
Two coroutines: the mission drives while the guard polls the sensor and cuts the motors below 10 cm. A shared flag lets the guard exit on its own once the mission finishes:
import runloop, motor_pair, distance_sensor
from hub import port
motor_pair.pair(motor_pair.PAIR_1, port.A, port.E)
mission_done = False
async def mission():
global mission_done
await motor_pair.move_for_degrees(motor_pair.PAIR_1, 3600, 0, velocity=700)
mission_done = True
async def guard():
while not mission_done:
d = distance_sensor.distance(port.D)
if d != -1 and d < 100: # 10 cm emergency stop
motor_pair.stop(motor_pair.PAIR_1)
break
await runloop.sleep_ms(20)
runloop.run(mission(), guard())Next sensor: Force Sensor.