Color Sensor
The most important sensor in FLL, period. Line following, line detection and mat-mark recognition all depend on it.
What it measures
| Mode | Reading | Notes |
|---|---|---|
| Color | 8 colors (black, white, red, yellow, green, blue, ...) plus no-color; note the Word Blocks dropdown and the Python color constants use slightly different name sets (Python has AZURE, ORANGE), check the official references for each | Discrete color recognition |
| Reflected Light | 0-100% | Sensor shines light and measures the reflection. Line following uses this |
| Ambient Light | 0-100% | Passive brightness, rarely used in FLL |
Mounting
- Facing down, about 16 mm above the mat (the official optimal reading distance, roughly 5 LEGO plates). Too high = noisy readings, too low = scraping.
- Mount at the front of the chassis, ahead of the wheel axle - the further forward, the earlier the correction.
- For two-sensor line following, mount them side by side about one line-width apart.
- Shield it: surround the sensor with LEGO pieces to block ambient light. Venue spotlights are brutal.
Word Blocks
<color sensor [C] color = [black]> ← Sensors category condition
(color sensor [C] reflected light) ← reporter block (round value block)
wait until <color sensor [C] color = [black]>Example 1: drive to the black line
when program starts
set movement motors [A+E]
start moving [forward]
wait until <color sensor [C] reflected light < [30]>
stop movingExample 2: count lines
set [lines] to [0]
start moving [forward]
repeat until <(lines) = [3]>
wait until <color sensor [C] reflected light < [30]>
change [lines] by [1]
wait until <color sensor [C] reflected light > [60]> ← key: wait to EXIT the line, or one line counts many times
stop movingPython
import runloop, color_sensor, color
from hub import port
async def main():
# read color (returns constants like color.BLACK)
if color_sensor.color(port.F) == color.BLACK:
pass
# read reflected light 0-100
value = color_sensor.reflection(port.F)
runloop.run(main())Threshold calibration: not optional
The 30 in "reflected light < 30 means black" cannot be copied - measure it on your mat under your lighting:
- Write a loop that shows reflected light on the matrix:
forever → write (reflected light). - Read a value on the black line (say 12) and one on white mat (say 85).
- Threshold = middle: (12 + 85) / 2 ≈ 48. Black is
< 48, white is> 48.
Recalibrate at every new venue
Lighting, mat wear and sensor height all shift readings. First thing on competition day: re-measure black and white. Store thresholds in variables so there's one place to edit.
Common pitfalls
- Color mode is unreliable at speed: readings flicker when moving fast. Line following always uses reflected light.
- Colored artwork on the mat fools "find the black line": dark blue and dark green reflect little light too. Combine with position (drive a known distance before arming line detection).
- Two sensors reading differently is normal: calibrate each separately.
Python API quick reference
All functions live in the color_sensor module and take a port from from hub import port.
| Function | Returns | Notes |
|---|---|---|
color_sensor.color(port.F) | int color constant | Compare against the color module constants; color.UNKNOWN / -1 when nothing is detected |
color_sensor.reflection(port.F) | int, 0-100 | Reflected light intensity - the line-following workhorse |
color_sensor.rgbi(port.F) | (R, G, B, I) tuple, each 0-1024 | Raw color channels plus overall intensity, for custom color logic |
Python color constants (import color): BLACK, MAGENTA, PURPLE, BLUE, AZURE, TURQUOISE, GREEN, YELLOW, ORANGE, RED, WHITE, UNKNOWN. The name set differs from the Word Blocks dropdown - check the official references when porting programs.
More examples
Calibration helper: capture black and white with the hub buttons
Put the sensor on the line, tap LEFT; put it on white mat, tap RIGHT. The hub beeps on each capture and shows the suggested threshold.
import runloop, color_sensor
from hub import port, button, light_matrix, sound
black = None
white = None
async def main():
global black, white
while black is None or white is None:
if button.pressed(button.LEFT):
black = color_sensor.reflection(port.F)
sound.beep(330, 150, 100)
await runloop.until(lambda: not button.pressed(button.LEFT))
if button.pressed(button.RIGHT):
white = color_sensor.reflection(port.F)
sound.beep(660, 150, 100)
await runloop.until(lambda: not button.pressed(button.RIGHT))
await runloop.sleep_ms(50)
threshold = (black + white) // 2
print("black", black, "white", white, "threshold", threshold)
await light_matrix.write(str(threshold))
runloop.run(main())Stop at the Nth line
Counts line entries by waiting for black then back to white, so one line is never counted twice. Stops just after leaving line number n.
import runloop, motor_pair, color_sensor
from hub import port
BLACK = 40
WHITE = 60
motor_pair.pair(motor_pair.PAIR_1, port.A, port.E)
async def stop_at_line(n, velocity=360):
motor_pair.move(motor_pair.PAIR_1, 0, velocity=velocity)
for _ in range(n):
await runloop.until(lambda: color_sensor.reflection(port.F) < BLACK)
await runloop.until(lambda: color_sensor.reflection(port.F) > WHITE)
motor_pair.stop(motor_pair.PAIR_1)
async def main():
await stop_at_line(3)
runloop.run(main())Custom color logic with rgbi
When color() flickers between two similar colors, raw channels let you write your own rule. Watch the console while holding different objects under the sensor:
import runloop, color_sensor
from hub import port
def is_reddish(sample):
r, g, b, i = sample
return i > 80 and r > 2 * g and r > 2 * b
async def main():
while True:
sample = color_sensor.rgbi(port.F)
print(sample, "reddish:", is_reddish(sample))
await runloop.sleep_ms(200)
runloop.run(main())FAQ
My thresholds stopped working at the venue - what happened?
Venue lighting, mat wear and sensor height all shift readings. First thing on competition day: re-measure black and white on site. Keep thresholds in variables so there is one place to edit.
Color mode or reflected light mode?
Always reflected light for line following and line detection - color mode flickers when the robot moves fast. Use color mode only for discrete color checks at rest or low speed.
My two color sensors read differently - are they broken?
No - unit variation is normal. Calibrate black/white thresholds for each sensor separately.
Applications continue in Line Following. Next sensor: Distance Sensor.