|
| 1 | +--- |
| 2 | +title: Bluetooth PS3 gamepad in Python |
| 3 | +subject: Hardware - Gamepads and remote controls |
| 4 | +author: Anton Vanhoucke |
| 5 | +--- |
| 6 | + |
| 7 | +* Table of Contents |
| 8 | +{:toc} |
| 9 | + |
| 10 | +The cool thing about the PS3 gamepad is that it's a normal Bluetooth device and connects directly to the Ev3. You can easily run programs in brickman and use the pad without another computer or laptop. |
| 11 | + |
| 12 | +# What you need |
| 13 | +- A PS3 gamepad (also known as Sixaxis controller or Dualshock 3) |
| 14 | +- A mini-usb / usb cable |
| 15 | +- A working ssh and internet connection to the Ev3 (or other ev3dev device) |
| 16 | +- ev3-ev3dev-jessie-2015-12-30.img or later |
| 17 | + |
| 18 | +# Connection |
| 19 | +The PS3 pairing process in Brickman is a little strange, but works fine. Stick exactly to these steps: |
| 20 | + |
| 21 | +1. On the Ev3 brick go to 'Wireless and Networks' > 'Bluetooth' |
| 22 | +2. Make sure Bluetooth is Powered and the brick is Visible. |
| 23 | +3. Connect the gamepad via a mini usb cable to the Ev3. I used the large usb port next to the micro SD slot. |
| 24 | +4. Under Devices a 'PLAYSTATION(R) 3 controller' should show up. But don't pair! |
| 25 | +4. Remove the USB cable again. |
| 26 | +5. Press the PS3 button on the gamepad. |
| 27 | +6. The brick now asks "Authorize service HID?" Press "Accept" |
| 28 | + |
| 29 | +You're done! Whenever you press the PS3 button on the gamepad now, it will try to connect to the ev3 brick. Nice! |
| 30 | + |
| 31 | +If brickman doesn't work or if you don't have a display, like on a BrickPi, `bluetoothctl` is the way to go. The gentoo linux guys wrote [a nice tutorial](https://wiki.gentoo.org/wiki/Sony_DualShock) |
| 32 | + |
| 33 | + |
| 34 | +# Running motors with a PS3 sixaxis controller |
| 35 | +Now on to Python. In python we need the evdev (without a 3) to read gamepad events. Here's a quick program that will take the right stick Y axis and use it to set the speed of a motor in port A. Note that motor control is in a separate thread. That's because controlling the motors is much slower than reading the gamepad. Multithreading synchronizes both. |
| 36 | + |
| 37 | +{% highlight python %} |
| 38 | +#!/usr/bin/env python |
| 39 | +__author__ = 'Anton Vanhoucke' |
| 40 | + |
| 41 | +import evdev |
| 42 | +import ev3dev.auto as ev3 |
| 43 | +import threading |
| 44 | + |
| 45 | +## Some helpers ## |
| 46 | +def scale(val, src, dst): |
| 47 | + """ |
| 48 | + Scale the given value from the scale of src to the scale of dst. |
| 49 | + |
| 50 | + val: float or int |
| 51 | + src: tuple |
| 52 | + dst: tuple |
| 53 | + |
| 54 | + example: print scale(99, (0.0, 99.0), (-1.0, +1.0)) |
| 55 | + """ |
| 56 | + return (float(val - src[0]) / (src[1] - src[0])) * (dst[1] - dst[0]) + dst[0] |
| 57 | + |
| 58 | +def scale_stick(value): |
| 59 | + return scale(value,(0,255),(-100,100)) |
| 60 | + |
| 61 | +## Initializing ## |
| 62 | +print "Finding ps3 controller..." |
| 63 | +devices = [evdev.InputDevice(fn) for fn in evdev.list_devices()] |
| 64 | +for device in devices: |
| 65 | + if device.name == 'PLAYSTATION(R)3 Controller': |
| 66 | + ps3dev = device.fn |
| 67 | + |
| 68 | +gamepad = evdev.InputDevice(ps3dev) |
| 69 | + |
| 70 | +speed = 0 |
| 71 | +running = True |
| 72 | + |
| 73 | +class MotorThread(threading.Thread): |
| 74 | + def __init__(self): |
| 75 | + self.motor = ev3.LargeMotor(ev3.OUTPUT_A) |
| 76 | + threading.Thread.__init__(self) |
| 77 | + |
| 78 | + def run(self): |
| 79 | + print "Engine running!" |
| 80 | + while running: |
| 81 | + self.motor.run_forever(duty_cycle_sp=speed) |
| 82 | + |
| 83 | + self.motor.stop() |
| 84 | + |
| 85 | +motor_thread = MotorThread() |
| 86 | +motor_thread.setDaemon(True) |
| 87 | +motor_thread.start() |
| 88 | + |
| 89 | + |
| 90 | +for event in gamepad.read_loop(): #this loops infinitely |
| 91 | + if event.type == 3: #A stick is moved |
| 92 | + if event.code == 5: #Y axis on right stick |
| 93 | + speed = scale_stick(event.value) |
| 94 | + |
| 95 | + if event.type == 1 and event.code == 302 and event.value == 1: |
| 96 | + print "X button is pressed. Stopping." |
| 97 | + running = False |
| 98 | + break |
| 99 | +{% endhighlight %} |
| 100 | + |
| 101 | +Copy this code into a file on the Ev3 brick to run it. If you do `sudo chmod +x your_file_name.py`, you can even run it from the brickman interface! |
| 102 | + |
| 103 | +# The complete event type and code mapping of the ps3 controller |
| 104 | +I mapped out all codes for you! Here they are: |
| 105 | +{% include screenshot.html source="/images/Website/sixaxis_event_codes.png" %} |
| 106 | + |
| 107 | +# The result: a remote controlled robot |
| 108 | +How cool! No computer needed. Just a gamepad and the ev3 brick. |
| 109 | + |
| 110 | +{% include youtube-embed.html youtube_video_id="brfgF3D5c4k" %} |
0 commit comments