In this article I’m sharing step by step instructions for connecting a PS3 gamepad to an EV3 brick over Bluetooth. It includes Python code to control a simple LEGO MINDSTORMS EV3 robot with a tank steering mechanism. The Python code uses the analog sticks as an input and controls motor voltages. There is also MicroPython code.
Setting up the EV3 to run Python
The easiest way to get started is to follow my guide for installing VS Code and creating the MicroPython SD Card image. Do it and come back here, when you’re set up. It takes about 10 minutes if you have an SD card laying around. LEGO Education has released an easy-to-use version of ev3dev with VS Code integration. That’s what we’ll be using.
Connect the PS3 gamepad
I have an original PS3 Sixaxis controller. They are not for sale anymore, but you can find them second hand. I get many reports that only the original PS3 controllers will work.
Connecting the PS3 controller is a little tricky. Here are the steps.
Time needed: 5 minutes
How to connect a PS3 Sixaxis Gamepad to a LEGO EV3 brick.
- Boot your LEGO MINDSTORMS EV3 brick in ev3dev
If you don’t have a Micro SD card to do so, read the guide to running Python on your EV3 brick.
- Select ‘Wireless and Networks’.
Once the brick has booted from the ev3dev image this item will show up in the menu. Use the up and down buttons on the brick to navigate to it. Use the middle button to select.
- Select ‘Bluetooth’
If the EV3 Brick says ‘Bluetooth not available’, reboot the ev3 brick and start at step 2. To reboot repeatedly press the escape button (on the left bottom side of the screen) until a menu with the options ‘restart’, ‘shut down’ and ‘cancel’ appears.
- Set ‘Visible’ and ‘Bluetooth’ to ‘on’
Navigate to the visibility option and use the middle button to switch between on and off. The square should be filled.
- Connect your PS3 gamepad with the EV3 brick using your regular EV3 USB cable.
Use the small connector in the game pad and the big one in the brick. Wait until the lights on the PS3 gamepad are flashing.
- DON’T PRESS ANY BUTTONS ON THE GAMEPAD
Don’t press any buttons on the brick either. This is really important. So don’t try to pair!
- Remove the USB Cable
Just action of plugging the cable in and waiting for the discovery is enough.
- Press the center Playstation button on the gamepad
It’s the button between ‘start’ and ‘select’.
- Authorize Service HID
On the brick, you see a message: ‘Authorize Service HID?’. Choose Accept. You’re done. It’s connected!
- When reconnecting the PS3 gamepad later, after reboot, start at step 8.
The USB cable is not necessery anymore. Do make sure the EV3 brick is visible in Bluetooth.
A simple robot for Gamepad control
Just build a simple robot, slam to large motors on a brick and add a tracking wheel. Make sure the left motor is in port B and the right motor is in port C. Here is a picture of my design.
Programming the EV3 in python for remote control
Once you have set up VS Code and the LEGO and ev3dev extensions you can run the code below. Make a new empty project with the EV3 extension if you haven’t yet done so. Remove all of the text from the main.py file and replace it with the program below.
The first line – the shebang – tells the software not to use MicroPython, but Python 3. This is awesome if you want to do Internet of Things, Multithreading and Video stream overlays. Python takes 20 seconds to start however. So for simple robots I advise you to use my MicroPython code for remote control with a PS3 controller. MicroPython starts in mere seconds!
#!/usr/bin/env python3 __author__ = 'Anton Vanhoucke' import evdev import ev3dev.auto as ev3 import threading ## Some helpers ## def scale(val, src, dst): """ Scale the given value from the scale of src to the scale of dst. val: float or int src: tuple dst: tuple example: print(scale(99, (0.0, 99.0), (-1.0, +1.0))) """ return (float(val - src) / (src - src)) * (dst - dst) + dst def scale_stick(value): return scale(value,(0,255),(-100,100)) def clamp(value, floor=-100, ceil=100): """ Clamp the value within the floor and ceiling values. """ return max(min(value, ceil), floor) ## Initializing ## print("Finding ps3 controller...") devices = [evdev.InputDevice(fn) for fn in evdev.list_devices()] for device in devices: if device.name == 'PLAYSTATION(R)3 Controller': ps3dev = device.fn gamepad = evdev.InputDevice(ps3dev) # Initialize globals speed = 0 turn = 0 running = True # Within this thread all the motor magic happens class MotorThread(threading.Thread): def __init__(self): # Add more sensors and motors here if you need them self.left_motor = ev3.LargeMotor(ev3.OUTPUT_B) self.right_motor = ev3.LargeMotor(ev3.OUTPUT_C) threading.Thread.__init__(self) def run(self): print("Engine running!") # Change this function to suit your robot. # The code below is for driving a simple tank. while running: right_dc = clamp(-speed-turn) left_dc = clamp(-speed+turn) self.right_motor.run_direct(duty_cycle_sp=right_dc) self.left_motor.run_direct(duty_cycle_sp=left_dc) self.motor.stop() # Multithreading magics motor_thread = MotorThread() motor_thread.setDaemon(True) motor_thread.start() for event in gamepad.read_loop(): #this loops infinitely if event.type == 3: #One of the sticks is moved # Add if clauses here to catch more values for your robot. if event.code == 4: #Y axis on right stick speed = scale_stick(event.value) if event.code == 3: #X axis on right stick turn = scale_stick(event.value) if event.type == 1 and event.code == 302 and event.value == 1: print("X button is pressed. Stopping.") running = False break
Now pressing F5 on the keyboard runs this code on the brick. Neat, huh? If the gamepad is connected well you should be able to steer your robot around.
If you want to change the control layout, here’s an overview of the different codes you can use. So if you need the left stick wait for event type 3 and event codes 0 and 1.