BBR Button Board Documentation

Changing legends in a match#

A screen key, or a disp2 colour display, can show a different legend or picture as the match goes on — INTAKE while you are collecting, SCORE while you are lined up, CLIMB in the endgame. This page is how the robot tells it to.

This is the only part of the board that needs code on the robot.

It has not yet been confirmed that the FTC Driver Station forwards a rumble call to this board. Test it with your Driver Station before relying on it in a match.

How it works#

In FTC mode the board is an Xbox-style gamepad with no config channel, so during a match the only way to reach it is a gamepad rumble command. The rumble carries a number, and that number selects a stored legend.

Load the legends before the match; switch them during it with one call.

The number is a legend code, not a key#

showLegend(3) does not mean “key 3”. It means “whatever the config app has bound to code 3” — see Binding legend codes.

Name the codes in your OpMode for what they mean:

static final int LEGEND_INTAKE = 1;
static final int LEGEND_SCORE  = 2;
static final int LEGEND_CLIMB  = 3;

The panel can then be rearranged — a different key, a different picture — without changing the robot code.

Adding the library#

Copy the files into your project; there is no dependency to add beyond the SDK. From the repository:

cp -r robot/ftc/src/org      TeamCode/src/main/java/
cp -r robot/ftc/src-ftc/org  TeamCode/src/main/java/

That leaves three files in org/firstinspires/ftc/teamcode/buttonboard/. Do not copy test/ — it is for a desktop JDK and Android Studio will try to build it. If your team uses a different package root, change the package line in all three files to match.

Requires FTC SDK v7.0 or newer.

A minimal OpMode#

@TeleOp(name = "Button Board legends")
public class LegendDemo extends LinearOpMode {

    static final int LEGEND_INTAKE = 1;
    static final int LEGEND_SCORE  = 2;
    static final int LEGEND_CLIMB  = 3;

    @Override
    public void runOpMode() {
        // gamepad1 must be the pad the Button Board bound as.
        ButtonBoard board = new ButtonBoard(new GamepadRumbleSink(gamepad1));

        waitForStart();

        while (opModeIsActive()) {
            // Safe to call every loop: it sends only when the code changes.
            if (gamepad1.right_trigger > 0.5) {
                board.showLegend(LEGEND_CLIMB);
            } else if (gamepad1.a) {
                board.showLegend(LEGEND_SCORE);
            } else {
                board.showLegend(LEGEND_INTAKE);
            }

            telemetry.addData("legend", board.lastLegend());
            telemetry.update();
        }
    }
}

The config app writes this call out for you: the Legend codes section has an In the OpMode block with the exact line for every code you have bound, and a Copy button.

The API#

Call Does
showLegend(int code) Show the legend bound to code — unless it is already the last one sent. Returns whether it sent anything. Throws on anything outside 1–15.
refresh() Send the last code again regardless. Use it after the board was power-cycled.
forget() Drop the remembered code without sending. The next showLegend sends whatever it is given.
lastLegend() The last code sent — not what the board is known to be showing.
stopRumble() Send zero power. Stops a real gamepad buzzing; does not clear the key.

Call it every loop#

showLegend() suppresses repeats, so call it every loop with the legend that should be showing right now. Use it rather than calling rumble() yourself.

Don’t gate legend changes on isRumbling(). It reads true for the length of each step even though the board has no motors, so you would suppress real changes.

There is no way to blank a key#

Zero is the SDK’s stop, so the board ignores it. To show nothing, store a blank picture in a slot, bind a code to it, and show that code.

If the board is unplugged mid-match#

Nothing tells you. A board in FTC mode cannot answer.

If it is power-cycled it comes back showing whatever its map starts with, while your OpMode still holds the last code it sent — so the next showLegend() of that same code is suppressed and the panel stays wrong. Wire refresh() to a button you can reach.

Do not use it as an animation#

The SDK sends one rumble about every 50 ms and drops any earlier call in that window. The panel always ends on the latest code, but an intermediate one may never appear: flick A → B → C inside 50 ms and B may be skipped. If a legend needs to be seen, leave it up for at least a tenth of a second.

Rumble goes to one gamepad. Whichever position the Driver Station gave the board — gamepad1 or gamepad2 — is the one to construct GamepadRumbleSink with. Send to the other and nothing happens, with no error.

Changing a key’s colour the same way#

A code can also recolour keys. In the config app, select a key on an RGB tile, and under Robot colour pick a code, an effect and a colour. When the robot sends that code, the key takes that colour. If the same code also has a legend bound, one showLegend() call changes both, so a key can turn red and read CLIMB at the same moment.

There are two special colours. ∅ turns the LED off. normal puts the key back on the colour it has in your saved configuration.

A code changes only the keys it names. A code followed by another within 50 ms may never arrive, so don’t rely on it. If code 5 means “back to normal”, give code 5 a normal entry for every key your other codes recolour.

These colours live on the board’s live LED layer, the same one the Driver Station app writes. They are not saved, and a power cycle or led reset clears them. As with an unplugged board above, call refresh() to put them back.

The map holds up to 32 robot colours in total.

Setting the board up first#

Load the pictures and bind the codes before you switch to FTC mode. Neither can be done in FTC mode.

  1. Put the board in a mode that has the config channel: frc in the config app’s Connect screen. Save, then unplug and plug back in.
  2. Load the pictures into slots and bind the codes. Add any robot colours. Save.
  3. Switch back to xinput, save, unplug and plug back in.
  4. Check which gamepad position the Driver Station gives it.

Your pictures and bindings are kept when you switch back in step 3.

The config app offers a “bind the next code” button that waits for a rumble and binds whichever code arrives. Against a real board it will wait forever, because a board that can receive a rumble has no config channel to report it on. It works against the fake board. Bind by picking the number instead; that works everywhere.