BBR Digital Expander Documentation

Colour sensors#

The board doesn’t just hand you raw red, green, and blue numbers and leave you to work out what they mean. You teach it the colours you care about, and then ask it a direct question: am I looking at colour 1?

Teaching a colour#

Hold the target in front of the sensor and teach it:

exp.teachColor(0, 1);   // sensor port 0, this is now "colour 1"

That takes a moment, and it saves to the board’s flash automatically. You do not need to call saveConfigToFlash() afterwards — the teach helpers do it for you.

Each port remembers up to 7 colours, numbered 1 to 7.

exp.teachColor(0, 1);   // hold red    → colour 1
exp.teachColor(0, 2);   // hold blue   → colour 2
exp.teachColor(0, 3);   // hold yellow → colour 3

Because it is stored in flash, teaching survives power cycles and applies to everything that reads the board afterwards — a different program, a different language, a different host entirely. Teach at the start of the day, use all day.

When teaching refuses#

Teaching fails rather than storing a colour the board doesn’t believe in — if the target is too dark, if the sensor is saturated, or if there is no sensor on that port.

This is on purpose. A badly taught colour is worse than no colour at all: it either never fires or always fires, and both look like a code bug rather than a calibration problem. Better to find out while you’re standing at the robot holding the target.

If it refuses, the usual fixes are more light, less light, or holding the target closer.

Reading colours#

int which = exp.getColorClass(0);       // 0 = no match, 1-7 = which colour
boolean isRed = exp.seesColor(0, 1);    // just asking about colour 1

seesColor() is usually the one you want — it reads as the question you are actually asking:

if (exp.seesColor(0, 1)) {
    telemetry.addLine("over red");
}

Both fail safe. A dark, saturated, stale or unplugged sensor reads 0 — “none of the colours I know” — rather than confidently naming the wrong one.

Teaching at the field, not in code#

Rather than hard-coding a teach call, let a person do it at the robot:

if (gamepad1.a && !prevA) {
    try {
        exp.teachColor(0, 1);
        status = "learned colour 1";
    } catch (BBRDigitalExpander.BBRException e) {
        status = "teach failed: " + e.getMessage();
    }
}
prevA = gamepad1.a;

Catching the exception and showing it in telemetry turns a failed teach into something the driver can immediately react to, instead of a stack trace.

The edge detection matters as much as the error handling. Teaching writes to flash, and the board accepts at most one save per second — so a held button teaching on every loop would stall you to a crawl. One press, one teach. See Set up once.

Letting the board watch for you#

Once a colour is taught, the board can drive a digital output whenever it sees it — with no I2C traffic and no code in your loop at all:

exp.triggerOnColor(0, 0, 1);   // output 0 high while port 0 sees colour 1

This also saves automatically. Your match code then reads a stock DigitalChannel.

See Digital outputs and triggers.

Raw values#

If you need the underlying numbers — for tuning, or for a classifier of your own — they are in the telemetry block:

BBRDigitalExpander.TelemetryBlock t = exp.readTelemetry();
int[] rgbip = t.rawColor[0];             // r, g, b, ir, proximity
int confidence = t.classConfidence[0];   // 0-255

Classification uses normalized chromaticity rather than raw brightness, which is why a taught colour keeps working as the lighting changes between your workshop and the competition venue.

Worked example#

BBRTeachColorExample and BBRThreeColorExample both teach from a gamepad button properly. BBRColorClassExample covers reading. See Example OpModes.