Skip to content

Color Sensor

The most important sensor in FLL, period. Line following, line detection and mat-mark recognition all depend on it.

What it measures

ModeReadingNotes
Color8 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 eachDiscrete color recognition
Reflected Light0-100%Sensor shines light and measures the reflection. Line following uses this
Ambient Light0-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

wordblocks
<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

wordblocks
when program starts
set movement motors [A+E]
start moving [forward]
wait until <color sensor [C] reflected light < [30]>
stop moving

Example 2: count lines

wordblocks
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 moving

Python

python
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:

  1. Write a loop that shows reflected light on the matrix: forever → write (reflected light).
  2. Read a value on the black line (say 12) and one on white mat (say 85).
  3. 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.

FunctionReturnsNotes
color_sensor.color(port.F)int color constantCompare against the color module constants; color.UNKNOWN / -1 when nothing is detected
color_sensor.reflection(port.F)int, 0-100Reflected light intensity - the line-following workhorse
color_sensor.rgbi(port.F)(R, G, B, I) tuple, each 0-1024Raw 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.

python
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.

python
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:

python
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.

© 2026 FLL Knowledge Base · All rights reserved