Gamepads in Python

New for 2025.

Teleoperation using a physical game controller is a convenient way to puppet a robotic system. The following examples demonstrate basic Python interfaces for reading game controllers on a laptop or Raspberry Pi.

The sample code included here may be browsed in Python/gamepad.

libSDL

The samples use the Python wrappers for libSDL, the cross-platform Simple DirectMedia Layer library used by many games. Examples for both SDL2 and SDL3 are provided as both are still in use on different platforms.

libSDL3:

libSDL2:

This library was chosen due to its popularity and high level of support. It is the foundation for the pygame library.

The SDL gamepad API uses the joystick API for I/O but adds a logical name-based interface for retrieving input values.

libSDL Installation Notes

We will only use the Python API for libSDL. The current installation instructions can be found on the PySDL3 or PySDL2 pages linked above. The simplest way to install it is using pip:

pip install PySDL3

On most platforms this will import efficient pre-compiled binaries and install all required package dependencies.

The specifics of this process may vary with your installation. Note that the recommended practice is to set up a virtual environment so the package and its dependencies can be kept locally, but that is outside the scope of these instructions.

If PySDL3 is not available, then SDL2 is fine:

pip install PySDL2

IDeATe Gamepads

IDeATe Lending has two devices available for borrowing under the ‘Virtual Reality’ subcollection:

../_images/xboxControlUsbWhite.png

Xbox Control USB, a generic wired XBox controller sold under the amazonbasics label. Note: this might not work under macOS.

../_images/xboxControlWireless.png

Xbox Control Wireless, a Bluetooth XBox controller. Note: this has been confirmed with work under macOS.

To pair the Bluetooth controller, hold the large ‘X’ button near the top of the front to turn the controller on, then press and hold the small pairing button on the front (near the charging port).

Gamepad Identification in libSDL3

 1# Gamepad identification using the Python bindings for libSDL3.
 2
 3import sdl3
 4import ctypes
 5
 6sdl3.SDL_Init(sdl3.SDL_INIT_GAMEPAD)
 7
 8print("SDL version:", sdl3.SDL_GetVersion())
 9print("SDL revision", sdl3.SDL_GetRevision())
10
11if not sdl3.SDL_HasGamepad():
12    print("no gamepad found.")
13
14else:
15    count = ctypes.c_int()
16    pads = sdl3.SDL_GetGamepads(count)
17    print("number of gamepads:", count.value)
18    first_id = pads[0]
19    print("first joystick ID:", first_id)
20    controller = sdl3.SDL_OpenGamepad(first_id)
21    print("connected:",  sdl3.SDL_GamepadConnected(controller))
22    print("name:",       sdl3.SDL_GetGamepadName(controller))
23    print("product:",    sdl3.SDL_GetGamepadProduct(controller))
24    print("type:",       sdl3.SDL_GetGamepadType(controller))
25    print("vendor:",     sdl3.SDL_GetGamepadVendor(controller))
26
27sdl3.SDL_Quit()

Gamepad Identification in libSDL2

 1# Gamepad identification using the Python bindings for libSDL2.
 2
 3import sdl2
 4
 5sdl2.SDL_Init(sdl2.SDL_INIT_GAMECONTROLLER)
 6print("SDL revision", sdl2.SDL_GetRevision())
 7
 8if sdl2.SDL_NumJoysticks() == 0:
 9    print("no joysticks found.")
10
11else:
12
13    controller = sdl2.SDL_GameControllerOpen(0)
14    print("name:",       sdl2.SDL_GameControllerName(controller))
15    print("type:",       sdl2.SDL_GameControllerGetType(controller))
16    print("vendor:",     sdl2.SDL_GameControllerGetVendor(controller))
17
18sdl2.SDL_Quit()

Show Inputs in libSDL3

The following will continuously print input values to console until interrupted with control-C.

 1# Show several gamepad inputs using the Python bindings for libSDL3.
 2
 3import sdl3
 4import ctypes
 5
 6sdl3.SDL_Init(sdl3.SDL_INIT_GAMEPAD)
 7
 8if not sdl3.SDL_HasGamepad():
 9    print("no gamepad found.")
10
11else:
12    count = ctypes.c_int()
13    pads = sdl3.SDL_GetGamepads(count)
14    controller = sdl3.SDL_OpenGamepad(pads[0])
15
16    try:
17        while True:
18            sdl3.SDL_UpdateGamepads()
19            # for the axis identifiers, see https://wiki.libsdl.org/SDL3/SDL_GamepadAxis
20            lx = sdl3.SDL_GetGamepadAxis(controller, sdl3.SDL_GAMEPAD_AXIS_LEFTX)
21            ly = sdl3.SDL_GetGamepadAxis(controller, sdl3.SDL_GAMEPAD_AXIS_LEFTY)
22
23            # button identifiers: https://wiki.libsdl.org/SDL3/SDL_GamepadButton
24            lt = sdl3.SDL_GetGamepadButton(controller, sdl3.SDL_GAMEPAD_BUTTON_LEFT_SHOULDER)
25
26            print("left stick:", lx, ly, "left button:", lt)
27
28    except KeyboardInterrupt:
29        print("User interrupt...")
30
31sdl3.SDL_Quit()

Show Inputs in libSDL2

The following will continuously print input values to console until interrupted with control-C.

 1# Show several gamepad inputs using the Python bindings for libSDL2.
 2
 3import sdl2
 4
 5sdl2.SDL_Init(sdl2.SDL_INIT_GAMECONTROLLER)
 6
 7if sdl2.SDL_NumJoysticks() == 0:
 8    print("no joysticks found.")
 9
10else:
11    controller = sdl2.SDL_GameControllerOpen(0)
12
13    try:
14        while True:
15            sdl2.SDL_GameControllerUpdate()
16            # for the axis identifiers, see https://wiki.libsdl.org/SDL2/SDL_GameControllerAxis
17            lx = sdl2.SDL_GameControllerGetAxis(controller, sdl2.SDL_CONTROLLER_AXIS_LEFTX)
18            ly = sdl2.SDL_GameControllerGetAxis(controller, sdl2.SDL_CONTROLLER_AXIS_LEFTY)
19
20            # button identifiers: https://wiki.libsdl.org/SDL2/SDL_GameControllerButton
21            lt = sdl2.SDL_GameControllerGetButton(controller, sdl2.SDL_CONTROLLER_BUTTON_LEFTSHOULDER)
22
23            print("left stick:", lx, ly, "left button:", lt)
24
25    except KeyboardInterrupt:
26        print("User interrupt...")
27
28sdl2.SDL_Quit()