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:
controller API: https://wiki.libsdl.org/SDL3/CategoryGamepad
libSDL2:
Python: https://pysdl2.readthedocs.io/
controller API: https://wiki.libsdl.org/SDL2/CategoryGameController
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:
Xbox Control USB, a generic wired XBox controller sold under the amazonbasics label. Note: this might not work under macOS.¶
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()