MBC PS2 / PS4 Controller receiver × Pybricks

Read the PS2 / PS4 Controller receiver with MicroPython in three steps

A Pybricks program always goes in this order: first import the library, then create an object and give the receiver a name, and only then use that name to call a function. Work through the steps on the left and the program on the right grows with you. Click the buttons on the gamepad simulator and drag the sticks to see what the program prints.

Your hub:
1

Import the library

The first thing in the program tells Pybricks "I want to use the Controller library". Without this line the hub does not know what MBC_GAMEPAD means, and you get a NameError.

Pick one library (both work exactly the same; only the import line is different):

  1. Download the library (save the file and keep its name): MBC_gamepad.py (only this sensor) or MBC_sensors.py (the all-in-one library). You picked MBC_gamepad.py.
  2. In Pybricks Code, press "Import a file" in the file area on the left and import it into the same project.
  3. Do not rename the file, and do not put it in a subfolder.
  4. Go back to your main program and type the lines below at the very top (marked ① in the program on the right).
2

Create an object: give the receiver a name

A robot can have several sensors, so you "create an object": you tell the program which port the receiver is plugged into, and you give it a name. After that, every time you read a button or a stick, you use this name.

Which port is the receiver plugged into?

Turn on multitasking?

The 3 in the program is the port number: SPIKE 1~6 = A~F. You can also write Port.C, but then you also need from pybricks.parameters import Port.

3

Use the functions

Every function is written as "pad.function_name()": the name, a dot, then the function. To read buttons or sticks, start every loop with pad.update(). It reads the gamepad once, so the functions after it get new values. Click a function and the program and output change to its example.

Gamepad simulator: click the buttons, drag the sticks, and watch the output on the right

The simulator is only a sketch: click a button once to hold it, click it again to let go. Drag the dot on a stick to move it (it stays where you let go; press "Release all" to centre it). Sticks go from 1 to 9, 5 = centre, and the number gets bigger to the right and up. The PS4 gamepad battery is fixed at 80 in this demo.

An example for every function

14 functions, each with an example you can put straight into a loop. Press "Try it" to jump to step 3; the program and output on the right change to that example.

Complete examples

Two-stick tank drive (SPIKE, left wheel E, right wheel F)

        

!Only change the "settings to change" at the top. The left stick drives the left wheel and the right stick drives the right wheel. A tiny push does nothing: that is the "dead zone" (4 to 6 counts as centre). Too fast to control? Make GAIN smaller. Pushing up drives backward? Move Direction.COUNTERCLOCKWISE to the other motor.

Multitasking (advanced)

        

!When you create the object, the 2nd parameter is True, and the object goes outside run_task(). Every function needs await in front of it, update() too.

Together with other MBC sensors

        

!Switch to the shared library: change only the import line and import MBC_sensors.py. Do not import both libraries at the same time.

Tips

  1. Call update() at the start of every loop. buttons(), pressed(), any_pressed(), stick(), stick_centered(), buttons_psx() and pressed_psx() all read the snapshot taken by the last update(). If you forget update(), the values stay the way they were the first time, and nothing changes when you press a button.
  2. Unplugging does not stop the program. When the receiver cannot be read, each function returns the last value it read (or None if it never read anything), and the computer prints one warning line. Plug it back in and it works again by itself. Use sensor_ok() to check the connection. Tick "Unplug the sensor" under the gamepad simulator to see this. If you unplug while driving with a stick, the robot keeps driving with the last stick position. (The warning line is in Chinese and English.)
  3. Read the status functions outside the loop, or only now and then. connected() and battery() are one set of data; kind(), device_id() and firmware_version() are another set, separate from the buttons and sticks. Each time you switch sets, the receiver has to switch once (a few tens of ms more on SPIKE, about 0.5 s on EV3). connected() and battery() need receiver firmware from 2026-10 or later.
  4. When you use a stick as a switch, use 7 or more and 3 or less. With a small push, left and down become 4 almost right away, but right and up need about half a push to become 6, so the two sides are not equally sensitive. Treat 4 to 6 as "centre" and both sides feel the same. Direction: standing behind the robot and looking forward, left and down are negative (stick_centered()), right and up are positive.
  5. Write button names as strings in capital letters. For example pressed('CROSS'). On a PS4 / PS5 gamepad, SHARE (Create) = 'SELECT' and OPTIONS = 'START'; you can also write 'SHARE' and 'OPTIONS'. The PS button and the touchpad cannot be read. A misspelt name gives a ValueError.