Docs FTC Integration

GamepadAdaptor

Publishes every gamepad button and axis onto topics at 60 Hz.

GamepadAdaptor

GamepadAdaptor reflects an SDK Gamepad onto the bus. One line gives every button and axis a topic:

GamepadAdaptor.attach(orchestrator, gamepad1, "g1");

After this, gamepad 1’s state flows onto the bus at 60 Hz — no polling code, no edge-detection code, nothing else.

Topics published

Every public non-static boolean field becomes a button with three topics:

TopicTypeMeaning
g1/<button>Booleancurrent state, published every poll
g1/<button>/risingBooleanfires (value true) on press (0→1)
g1/<button>/fallingBooleanfires (value true) on release (1→0)

Every public non-static float field becomes an axis topic:

TopicTypeMeaning
g1/<axis>Floatcurrent value, published every poll

The real SDK Gamepad (v11.2) yields 27 button fields — including a, b, x, y, circle, cross, square, triangle, the four dpad_* keys, left_bumper, right_bumper, start, back, guide, options, share, ps, the stick buttons, touchpad, touchpad_finger_1/2, and left_trigger_pressed / right_trigger_pressed — and 10 axis fields: left_stick_x, left_stick_y, right_stick_x, right_stick_y, left_trigger, right_trigger, and the four touchpad coordinates. Non-boolean/float fields (id, timestamp, nextRumbleApproxFinishTime) are skipped, and any field a future SDK adds is picked up automatically by the reflection.

Reading the values

Edges — subscribe (fires once per press):

@SubscribedTo(topic = "g1/right_bumper/rising")
@OnHardwareThread
public void grab(Boolean v) {
    claw.run(s -> s.setPosition(GRAB));
}

Axes — poll (inside a loop):

double y = -orchestrator.getLatestValue("g1/left_stick_y", Float.class)
                         .map(Float::doubleValue).orElse(0.0);

Axes are Float. The SDK stores them as float, so getLatestValue(name, Double.class) returns an empty Optional — always fetch with Float.class and map to double for math.

Details worth knowing

  • attach registers a node named GamepadAdaptor:g1 and returns that name; it is cleaned up automatically when the orchestrator closes.
  • All topics are pre-created at attach time, so subscriptions made right after attach (in the same onSafeInit) never miss values.
  • The adaptor polls on the scheduler pool — gamepad reads never need the hardware thread.
  • The base <button> topic publishes current state every tick, so it also works as a “held” input; /rising and /falling publish only on the transition.

Two gamepads

GamepadAdaptor.attach(orchestrator, gamepad1, "g1");
GamepadAdaptor.attach(orchestrator, gamepad2, "g2");

Each adaptor is independent; the parent prefix keeps their topics apart. See the two-controller recipe for the robot-validated driver/operator split.

Next steps