Reading PS3 SixAxis using Python 2.7

Reading time ~3 minutes

I have been thinking about a remote controlled drone project for quite some time. Together with this I also have a small Arduino controlled car which I bought to get started from DealExtreme.

The problem with these remote controlled projects has always been getting a good remote control! My plan has always been NOT GETTING a RC remote. So there must be a different way!

How about using my PS3 SixAxis controller for this?

PlayStation PS3 SixAxis Controller

I tried different approaches using bluetooth and different strange program packages downloaded from different places, but none of these seemed to work.

Linux Devices

I have some experience in using python 2.7 on a linux platform, so I started out trying to find the actual device for the PS3 controller. And after connecting the USB cable to my computer it showed up as the following:

$ /dev/input/js0

Or even better: Using the symlink so that the device number does not matter.

$ /dev/input/by-id/usb-Sony_PLAYSTATION_R_3_Controller-joystick

This will work on most Linux systems, and has been tested on Ubuntu and RasperyPi (Raspbian). Not working in OS X

Reading binary data from the device

Python uses the binascii library to binary code and decode text. So using this to read from the device actually makes the data understandable.

from binascii import hexlify

Decoding the data

After finding a similar example on GitHub by @urbanzim i found that each message from the PS3 SixAxis controller is a 8 char long message with different types of data with a set definition for each of these characters.

Some of these characters are incrementing counters and things I did not care about at first, but i found that char 8 (string[7]) has the channel identifier, and that char 6 (string[5]) has the actual analog signal value from that channel.

After some research I got this list of analog signals amd digital signals:

Signal Reference Analog Binary
00 L-Stick LR A L3
01 LeftStick UD A Select
02 RightStisk LR A R3
03 RightStick UD A Start
04 Up Pad   B
05 Right Pad   B
06 Down Pad   B
07 Left Pad   B
08 Up Pad A L2
09 Right Pad A R2
0a Down Pad A L1
0b - - R1
0c L2 A -
0d R2 A -
0e L1 A -
0f R1 A -
10 Triangle A -
11 Rond A -
12 Cross A -
13 Square A -
17 Rotation Axis ? A -
18 Rotation Axis ? A -
19 Rotation Axis ? A -
1a Rotation Axis ? A -

This might seem a bit confusing, and it was but the same identifier was used for different buttons (binary and analog). In my python approach i focus only on the analog datastream, and filter out the digital (0 value) digital signals.

Putting the data to use

When looking at the data streaming from the PS3 controller, it is obvious that these are event based, and are only updated when there is a change to any one of the sensors. Because of this the datastream will be asynchronous.

Simple usage

When reading from any file or device it is importsnt that you are able to cleanly close the file or device after use. python has a nice solution to this using the keyword with()

from binascii import hexlify

path = "/dev/input/by-id/usb-Sony_PLAYSTATION_R_3_Controller-joystick"

sdata = []
num = []

with open(path, 'r') as filestream:

    signals = [0]*27

    while True:
        read_data = filestream.read(1)
        sdata += [hexlify(read_data)]

    if len(sdata) == 8:

        # Analog button signals
        if (int(sdata[7], 16) > 3) and (int(sdata[5], 16) != 0):
            signals[int(sdata[7], 16)] = int(sdata[5], 16) ^ 0x80

        # Stick Signals
        elif(int(sdata[7], 16) <= 3):
            signals[int(sdata[7], 16)] = (int(sdata[5], 16) ^ 0x80) - 128

    print signals

The resulting printout of this simple function will be a 27 char long list of analog values according to the table shown above. (All values have been normalized so that center stick, or no button press will have the default value 0).

The List values will only be updated when the actual signal is changing from the PS3 remote itself (All signals show up on first run, so the list will allways be complete after initiating).

This is still a work in progress, but I will make a python package for this in the future and host it on GitHub

Getting started with MAVLink for Arduino

How to get started with MAVLink using Convenience Functions on Arduino Continue reading

Starting this blog using Jekyll

Published on December 09, 2015