How to use a PS3 Gamepad with MicroPython on the EV3 brick

| |

MicroPython is the new kid on the block for programming the LEGO MINDSTORMS EV3 Intelligent Brick. It’s lightning fast because it’s so lightweight. Python 3 takes up to 20 seconds to start and is a little overkill for just driving a robot around. MicroPython starts in mere seconds. I will assume you are set up with VS Code, ev3dev and MicroPython.

EV3 MicroPython program for using the bluetooth gampad

Let’s start with the complete program for reading the PS3 gamepad stick positions in MicroPython. Below I will and dissect how it works below it. You can just go to VS Code, connect to your EV3 brick and paste this code in the main.py file. Press F5 to run it. If the gamepad is connected you will be able to steer a simple tank-like robot.

How the PS3 gamepad program works in MicroPython

Device input without evdev

In python 3 there’s a handy library called evdev which connects to the Linux device events system. There’s no such thing in MicroPython. We’re lucky however that Debian Linux uses a file based access system for usb devices. So we can just read a file and decode the bytes inside with python struct.

After connecting the PS3 gamepad, you could open an SSH terminal to your EV3 brick and check which file handler is for your gamepad. On my brick it looked like this:

Near the end of the file you can see the file handler for the playstation controller. It contains a few bits and bytes with encoded event values. I use python struct to unpack those bytes and make some sense of them.

Controlling the robot from the main loop without Threading

In my regular python 3 code I used threading to have a neat 60Hz motor control loop. The MicroPython program on the other hand waits for an event from the gamepad to pop up. These events come fairly often, so you get the feeling of real-time. However it is probably not suited for a closed control loop. Such loop would be needed with a rack gear and 4-link steering mechanism. In MicroPython there are coroutines and asyncio. They are tough to program with for beginners. So that’s stuff for another article.

Previous

Installation guide: EV3 brick with Python and MicroPython

12 thoughts on “How to use a PS3 Gamepad with MicroPython on the EV3 brick”

  1. Great Article, but what is the secret of connecting a PS4 controller. I managed to do a few months back, but cannot seem to repeat my success as I write this.

    Tried this code out with a PS4 directly connected and all hell broke loss. Wheels spinning at maximum power, no controls on the PS4 controller.

    • I have no PS4 controller, so I’m afraid I can’t help you. You could use the micropython script from my other article and print the codes from the PS4 controller. Maybe you can figure out the differences?

  2. OK, got the Sony PS4 Dual Shock paired, [You need to press playstation and sharing button and then go look on the brick for the connection] but still looking at pandemonium! There are three event areas in the devices. One for the touchpad, one for the motion and one for the controller. None of them work with this script.

    robot@ev3dev:/proc/bus/input$ more devices
    I: Bus=0000 Vendor=0000 Product=0000 Version=0000
    N: Name=”LEGO MINDSTORMS EV3 Speaker”
    P: Phys=
    S: Sysfs=/devices/platform/sound/input/input0
    U: Uniq=
    H: Handlers=kbd event0
    B: PROP=0
    B: EV=40001
    B: SND=6

    I: Bus=0019 Vendor=0001 Product=0001 Version=0100
    N: Name=”EV3 Brick Buttons”
    P: Phys=gpio-keys/input0
    S: Sysfs=/devices/platform/gpio_keys/input/input1
    U: Uniq=
    H: Handlers=kbd event1
    B: PROP=0
    B: EV=3
    B: KEY=1680 0 0 10004000

    I: Bus=0005 Vendor=054c Product=09cc Version=8100
    N: Name=”Wireless Controller Touchpad”
    P: Phys=40:bd:32:3e:56:97
    S: Sysfs=/devices/platform/soc@1c00000/serial8250.2/tty/ttyS2/hci0/hci0:1/0005:054C:09CC.0002/input/input6
    U: Uniq=dc:af:68:a5:ee:6e
    H: Handlers=event2
    B: PROP=5
    B: EV=b
    B: KEY=2420 0 10000 0 0 0 0 0 0 0 0
    B: ABS=2608000 0

    I: Bus=0005 Vendor=054c Product=09cc Version=8100
    N: Name=”Wireless Controller Motion Sensors”
    P: Phys=40:bd:32:3e:56:97
    S: Sysfs=/devices/platform/soc@1c00000/serial8250.2/tty/ttyS2/hci0/hci0:1/0005:054C:09CC.0002/input/input7
    U: Uniq=dc:af:68:a5:ee:6e
    H: Handlers=event3
    B: PROP=40
    B: EV=19
    B: ABS=3f
    B: MSC=20

    I: Bus=0005 Vendor=054c Product=09cc Version=8100
    N: Name=”Wireless Controller”
    P: Phys=40:bd:32:3e:56:97
    S: Sysfs=/devices/platform/soc@1c00000/serial8250.2/tty/ttyS2/hci0/hci0:1/0005:054C:09CC.0002/input/input5
    U: Uniq=dc:af:68:a5:ee:6e
    H: Handlers=event4
    B: PROP=0
    B: EV=20001b
    B: KEY=7fdb0000 0 0 0 0 0 0 0 0 0
    B: ABS=3003f
    B: MSC=10
    B: FF=1 7030000 0 0

  3. Ok,

    Managed to extract these values?

    Reading event4 Left/Right Stick Center/Forward/Back/Left/Right many events
    RSC ev_type 3 code 4 returns 128/129 {centre}
    RSF ev_type 3 code 4 returns 0 {forward}
    RSB ev_type 3 code 4 returns 255 {back}

    RSC ev_type 3 code 3 returns 123/122 {centre}
    RSL ev_type 3 code 3 returns 0 {left}
    RSR ev_type 3 code 3 returns 255 {right}

    LSC ev_type 3 code 0 returns 130/141
    LSL ev_type 3 code 0 returns 0
    LSR ev_type 3 code 0 returns 255
    LSC ev_type 3 code 1 returns 128/129
    LSF ev_type 3 code 1 returns 0
    LSB evtype 3 code 1 returns 255

  4. Bon,

    So this code produces forward/backward using the right stick.

    if ev_type == 3 and code == 1:
    right_stick_x = value
    if ev_type == 3 and code == 4:
    right_stick_y = value

    Your cpython version works better 🙂

  5. Sorry and finally this gives me all for directions, but it isn’t very clean.

    if ev_type == 3 and code == 3:
    right_stick_x = value
    if ev_type == 3 and code == 1:
    right_stick_x = value
    if ev_type == 3 and code == 0:
    right_stick_y = value
    if ev_type == 3 and code == 4:
    right_stick_y = value

    • So it works? Shouldn’t it be more like this?

      if ev_type == 3 and code == 3:
      LEFT_stick_x = value
      if ev_type == 3 and code == 1:
      right_stick_x = value
      if ev_type == 3 and code == 0:
      LEFT_stick_y = value
      if ev_type == 3 and code == 4:
      right_stick_y = value

  6. Hi, thanks I got my 8BitDo working with this code also.
    One thing is how to I tell motor to just rotate 45 deg left and right ?
    right = scale(rPad_x, (0, 255), (100, -100))
    left = scale(rPad_x, (0, 255), (100, -100))
    main_motor.dc(right – left).
    main_motor.dc(right + left)

    So if I trun the right pad to at the end of the pad 0 motor only goes 45 deg

  7. I received the following error when trying to execute the command:

    “Starting: brickrun –directory=”/home/robot/PS3_Controller_Redux” “/home/robot/PS3_Controller_Redux/main.py”
    Started.
    ———-
    Starting remote process failed: Failed to execute child process “/home/robot/PS3_Controller_Redux/main.py” (Permission denied)
    ———-
    Exited with error code 1.”

    Thoughts? I tried running the operation through VS with the EV3 plugged in.

Leave a Comment