I know this has been solved (generally) for RetroPie, but I'm hoping to have a generic solution I can use for other purposes--like controlling robotics. And RetroPie dominates the conversation.

Is it possible to connect an Xbox One controller to a Pi? If so, does anyone have a complete tutorial? USB or Bluetooth would be options, though neither seem to work so far for me.


Yes, you can connect an XboxOne controller to a Raspberry Pi.

If you want to connect over bluetooth, you will need to have a model of controller that supports bluetooth.

See https://en.wikipedia.org/wiki/Xbox_One_controller#Models to identify your model.

If you do have bluetooth, then follow this tutorial https://www.makeuseof.com/tag/connect-xbox-one-controller-to-raspberry-pi/

If you don't have bluetooth, make sure you have the latest Raspbian image installed on your Pi SD card. Also make sure your controller has the latest firmware installed on it using USB - see https://beta.support.xbox.com/help/hardware-network/controller/update-xbox-wireless-controller .

Connect your controller using a usb to micro usb to the Raspberry Pi.

Open a terminal, and type lsusb and check it is there. You should something similar in the following output:

Bus 001 Device 004: ID 045e:02d1 Microsoft Corp. Xbox One Controller

If this has worked successfully, then open a terminal and install the following:

$ sudo apt-get install python-dev python-pip gcc
$ pip install approxeng.input

create a file called app.py with the following content:

from approxeng.input import CentredAxis, TriggerAxis, Button, Controller, BinaryAxis
from approxeng.input.selectbinder import ControllerResource
from approxeng.input.controllers import ControllerRequirement, print_devices

class WirelessXBoxOnePad(Controller):
    Wireless XBox One controller, tested with the older controller that do not use bluetooth and are supplied with the
    XBox One 2014 through USB wire connection.

    def __init__(self, dead_zone=0.1, hot_zone=0.05):
        Create a new xbox one controller instance
        :param float dead_zone:
            Used to set the dead zone for each :class:`approxeng.input.CentredAxis` and
            :class:`approxeng.input.TriggerAxis` in the controller.
        :param float hot_zone:
            Used to set the hot zone for each :class:`approxeng.input.CentredAxis` and
            :class:`approxeng.input.TriggerAxis` in the controller.
        super(WirelessXBoxOnePad, self).__init__(
                Button("BTN_NORTH", 307, sname='square'),
                Button("BTN_WEST", 308, sname='triangle'),
                Button("BTN_B", 305, sname='circle'),
                Button("BTN_A", 304, sname='cross'),
                Button("BTN_THUMBR", 318, sname='rs'),
                Button("BTN_THUMBL", 317, sname='ls'),
                Button("BTN_SELECT", 314, sname='select'),
                Button("BTN_START", 315, sname='start'),
                Button("BTN_MODE", 316, sname='home'),
                Button("BTN_TL", 310, sname='l1'),
                Button("BTN_TR", 311, sname='r1'),
                CentredAxis("ABS_X", -32768, 32767, 0, sname='lx'),
                CentredAxis("ABS_Y", -32768, 32767, 1, invert=True, sname='ly'),
                CentredAxis("ABS_RX", -32768, 32767, 3, sname='rx'),
                CentredAxis("ABS_RY", -32768, 32767, 4, invert=True, sname='ry'),
                TriggerAxis("ABS_Z", 0, 1023, 2, sname='lt', button_sname='l2', button_trigger_value=0.2),
                TriggerAxis("ABS_RZ", 0, 1023, 5, sname='rt', button_sname='r2', button_trigger_value=0.2),
                BinaryAxis("ABS_HAT0X", 16, b1name='dleft', b2name='dright'),
                BinaryAxis("ABS_HAT0Y", 17, b1name='dup', b2name='ddown')

    def registration_ids():
        :return: list of (vendor_id, product_id) for this controller
        return [(0x45e, 0x2d1)]

    def __repr__(self):
        return 'Microsoft X-Box One pad'

print('DEBUG: list controllers found')

# Get a joystick
with ControllerResource(ControllerRequirement(require_class=WirelessXBoxOnePad)) as joystick:
    # Loop until we're disconnected
    while joystick.connected:
        # This is an instance of approxeng.input.ButtonPresses
        left_y = joystick['ly']
        if left_y != 0:
            print('left x is %s' % left_y)
        if left_y == 1:
            print('left x is %s' % left_y)
        elif left_y == -1:
            print('left x is %s' % left_y)
            print('left x is %s' % left_y)
        presses = joystick.check_presses()
        if presses['square']:
            print('SQUARE pressed since last check')
        # We can also use attributes directly, and get at the presses object from the controller:
        if joystick.presses.circle:
            print('CIRCLE pressed since last check')
        # Or we can use the 'x in y' syntax:
        if 'triangle' in presses:
            print('TRIANGLE pressed since last check')

        # If we had any presses, print the list of pressed buttons by standard name
        if joystick.has_presses:

Run the file with Python 3 and you are good to go!

Use this wonderful library https://approxeng.github.io/approxeng.input/index.html and refer to their docs for more information on what to do.

For an example of it being used to power motors - see this youtube video I did with code on GitHub in the description.


Tips, if debugging, make sure that the registration ids match up on what is found in the output on the print statement for print_devices() as this needed to be converted to hex code in the class.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.