View on GitHub

pxt-gamepad-ex

A MakeCode project for a Gamepad with micro:bit to broadcast to another micro:bit

Gamepad Extension for micro:bit

A powerful extension to add wireless gamepad/controller support to your micro:bit projects. Transmit and receive gamepad input including button states, joystick positions, and device orientation over the micro:bit radio.

Features

Hardware Setup

Supported Gamepads

Pin Configuration by Type

Component DFRobot Gamepad joystick:bit
Joystick X P1 (Analog) P1 (Analog)
Joystick Y P2 (Analog) P2 (Analog)
Green Button P13 P12
Yellow Button P14 P13
Red Button P15 P14
Blue Button P16 P15
Stick Button P8 ✖️
Button.A Onboard Onboard
Button.B Onboard Onboard
Logo Button Onboard Onboard

Installation

  1. Open https://makecode.microbit.org/
  2. Create a New Project
  3. Click the Extensions button (gear icon)
  4. Search for https://github.com/immostyn/pxt-gamepad-ex
  5. Select and import the extension

Quick Start Examples

Basic Broadcasting (Gamepad sends data)

// Initialize the gamepad broadcaster
Gamepadex.startBroadcast(1, Frequencies.TwoFiftyHz)

// Show LED when A button is pressed locally
input.onButtonPressed(Button.A, function () {
    led.plot(0, 0)
})

// Stop broadcasting
Gamepadex.stopBroadcast()

Basic Receiving (micro:bit receives gamepad data)

// Start listening for gamepad messages
Gamepadex.startReceiving(1)

// React to remote button press
Gamepadex.onGamepadButtonPressed(ButtonFlag.AButton, function () {
    basic.showString("A!")
})

// React to button click (brief press/release)
Gamepadex.onGamepadButtonClicked(ButtonFlag.AButton, function () {
    basic.showString("Click")
})

// React to double-click
Gamepadex.onGamepadButtonDoubleClicked(ButtonFlag.AButton, function () {
    basic.showString("Double")
})

// Stop receiving
Gamepadex.stopReceiving()

Reading Joystick Input

Gamepadex.startReceiving(1)

// Read joystick position (0-255, 128=center)
let x = Gamepadex.joystickX()
let y = Gamepadex.joystickY()

// Check if button is currently pressed
if (Gamepadex.isPressed(ButtonFlag.GreenButton)) {
    basic.showNumber(x)
}

Configuration

// Set double-click time window (100-1000ms, default 300ms)
Gamepadex.setDoubleClickWindow(250)

// Adjust joystick deadzone (0-20, default 4)
Gamepadex.setJoystickDeadzone(5)

// Enable debug output to serial port
Gamepadex.setDebugMode(true)

Feedback System

The gamepad can now receive feedback messages from games to display images, play sounds, and trigger vibration. This creates a more immersive gaming experience with visual and haptic feedback.

Enabling Feedback

On the gamepad (sender), enable feedback reception:

// Enable feedback with vibration motor on P0
Gamepadex.enableFeedback(DigitalPin.P0)

// Enable/disable sound feedback
Gamepadex.setFeedbackSound(true)

// Start broadcasting as usual
Gamepadex.startBroadcast(1, Frequencies.TwoFiftyHz)

Sending Feedback from Game

On the receiver (game micro:bit), send feedback messages:

// Send grayscale image (25 chars, 0-9 brightness)
radio.sendString("IMG:0090009090999990909000900")

// Send text message
radio.sendString("TXT:Level Up!")

// Play sound (frequency:duration)
radio.sendString("SND:1046:200")

// Trigger vibration (duration in ms)
radio.sendString("VIB:100")

// Clear display
radio.sendString("CLR")

// Interrupt current message (prefix with !)
radio.sendString("!TXT:Game Over!")

Grayscale Image Format

Images are 5x5 LED matrices with brightness levels 0-9:

Example - Target crosshair:

  0 9 0     00900
  9 9 9  =  99999  = "0090099999999990090000000"
0 9 9 9 0    99999
  9 9 9     99999
  0 9 0     00900

Animation Support

Send multiple frames separated by | with delay:

// Spinner animation (3 frames, 100ms delay)
radio.sendString("ANI:9000000000000000000000000|0900000000000000000000000|0090000000000000000000000:100")

Message Queue System

Feedback Protocol Reference

Command Format Description Example
IMG IMG:<25-chars> Display grayscale image IMG:0090009090999990909000900
TXT TXT:<message> Display scrolling text TXT:Score: 100
SND SND:<freq>:<ms> Play tone SND:1046:200
VIB VIB:<ms> Vibrate motor VIB:100
CLR CLR Clear display CLR
ANI ANI:<frames>:<ms> Play animation ANI:frame1\|frame2:200

Hardware Requirements for Feedback

Gamepad Type Configuration

This extension supports multiple hardware types. You must configure the gamepad type before broadcasting or reading input:

Supported Types

Selecting the Gamepad Type

Call this function at the start of your program:

// For DFRobot Gamepad (default, no need to call unless switching)
Gamepadex.setGamepadType(GamepadType.DFRobot)

// For ELECFREAKS joystick:bit
Gamepadex.setGamepadType(GamepadType.JoystickBit)

Capabilities by Type

Feature DFRobot Gamepad joystick:bit
Button.A ✔️ ✔️
Button.B ✔️ ✔️
Logo Button ✔️ ✔️
Green Button ✔️ ✔️
Yellow Button ✔️ ✔️
Red Button ✔️ ✔️
Blue Button ✔️ ✔️
Stick Button ✔️ ✖️
Joystick X/Y ✔️ ✔️

Pin Initialization

The extension automatically configures the correct pins for the selected hardware type. No additional setup is required.

API Reference

Sender Functions

startBroadcast(radioGroup?: number, frequency?: Frequencies)

stopBroadcast()

isPressedLocal(button: ButtonFlag): boolean

packedGamepadState(): uint32

Receiver Functions

startReceiving(radioGroup?: number)

stopReceiving()

joystickX(): number

joystickY(): number

isPressed(button: ButtonFlag): boolean

isOrientated(gesture: GestureFlags): boolean

gamepadStatus(): uint32

Event Handlers

onGamepadButtonPressed(button: ButtonFlag, handler: () => void)

onGamepadButtonReleased(button: ButtonFlag, handler: () => void)

onGamepadButtonClicked(button: ButtonFlag, handler: () => void)

onGamepadButtonDoubleClicked(button: ButtonFlag, handler: () => void)

Configuration Functions

setDoubleClickWindow(ms: number)

setJoystickDeadzone(value: number)

setDebugMode(enabled: boolean)

Feedback Functions

enableFeedback(vibratePin?: DigitalPin)

disableFeedback()

setFeedbackSound(enabled: boolean)

Architecture

Data Format

Gamepad data is packed into a single 32-bit integer for efficient transmission:

Event Processing

  1. Radio Message Arrivesradio.onReceivedNumber() callback updates _gamepadStatus
  2. Background Click Detector (runs every 5ms) → Analyzes button transitions
  3. State Transitions → Raises appropriate events (pressed, released, clicked, double-clicked)

Single Radio Handler

The extension uses a singleton pattern for the radio receiver to prevent multiple registrations. Only one radio.onReceivedNumber() handler is registered regardless of how many times startReceiving() is called.

Troubleshooting

No messages received

Buttons not responding

Double-click not working

Joystick values jumping around

Feedback not working

Vibration not working

Images not displaying correctly

Messages seem delayed

Radio interference

Version History

License

MIT

Contributing

Issues and pull requests welcome at GitHub


Edit this project at https://makecode.microbit.org/