The EV3 brick has a regular Bluetooth chip inside, the PS4 controller too. In this article, I’ll show you how you can connect the two to build remote-controlled robots. The example I’ll be using is a race car with a proportional steering mechanism. I will provide a python code, a step by step guide and building instructions.
The PS4 controller is a ubiquitous device. Many kids and teens have a few. Let’s get creative and use the controller for something else than virtual running and gunning.
Connecting the controller to the brick
The default LEGO software does not allow full access to hardware in your EV3 brick. The good news is that you can boot your brick with different software – a Debian Linux distribution – that gives full access to the hardware. We have to thank the people behind ev3dev and Pybricks for that. It also allows you to program the brick in Python. How to download this other firmware and boot your brick with it is the subject of a different article. To keep this article simple, I will assume you have succeeded in doing that.
Time Needed : 5 minutes
How to connect a Sony PS4 Dualshock 4 controller to a LEGO MINDSTORMS EV3 Intelligent Brick.
- Boot the brick
Use the official LEGO education Python SD card image
- Go to 'Wireless and Networks'
- Go to 'Bluetooth'
- Enable 'Powered'
- Enable 'Visible'
- Select 'Start scan'
- Put the PS4 controller into pairing mode
Press the Playstation and the Share buttons at the same time until the white light in front of the controller starts blinking.
- Select 'Wireless Controller'
It should appear in the list after a few seconds.
- Select 'pair' or 'connect'
- Verify the connection
Check if the light on the PS4 controller has turned blue. On the EV3 brick, a black Bluetooth icon should be visible.
- Windows, macOS or Linux computer with Microsoft Visual Studio Code
- LEGO MINDSTORMS EV3 brick
- Original Sony PS4 controller
- MicroSD card with LEGO Education Python
Building the race car
The race car is a fun model to control with the gamepad. You can find the building instructions on my Patreon site. It is a simple model, available to $1 subscribers. You will need three EV3 large motors to build it. You can, of course, look for another race car model online or invent one yourself.
Programming the EV3 brick to respond to the PS4 controller
Now that the controller is connected, we have to read joystick events from it and control motors. In Debian Linux, this is as simple as reading a file. The file contains byte data and is not human legible. We have to unpack the data with a C struct. Python makes that easy for us. The program below opens the right file and reads gamepad events from it in a continuous loop. When you connect joystick events to motors, you have to keep in mind that the loop doesn’t run with regular intervals. It blocks at the read statement until there is a new gamepad event. The blocking means you can not run motor control feedback loops in it. Luckily for us, Pybricks has a track_target() method that does all the control magic in the background.
# from pybricks import ev3brick as brick
from pybricks.ev3devices import (Motor, TouchSensor, ColorSensor,
InfraredSensor, UltrasonicSensor, GyroSensor)
from pybricks.parameters import (Port, Stop, Direction, Button, Color,
SoundFile, ImageFile, Align)
from pybricks.tools import print, wait, StopWatch
# Declare motors
left_motor = Motor(Port.B)
right_motor = Motor(Port.C)
steer_motor = Motor(Port.A)
forward = 0
left = 0
# A helper function for converting stick values (0 - 255)
# to more usable numbers (-100 - 100)
def scale(val, src, dst):
Scale the given value from the scale of src to the scale of dst.
val: float or int
example: print(scale(99, (0.0, 99.0), (-1.0, +1.0)))
return (float(val - src) / (src - src)) * (dst - dst) + dst
# Find the PS3 Gamepad:
# /dev/input/event3 is the usual file handler for the gamepad.
# look at contents of /proc/bus/input/devices if it doesn't work.
infile_path = "/dev/input/event4"
# open file in binary mode
in_file = open(infile_path, "rb")
# Read from the file
# long int, long int, unsigned short, unsigned short, unsigned int
FORMAT = 'llHHI'
EVENT_SIZE = struct.calcsize(FORMAT)
event = in_file.read(EVENT_SIZE)
(tv_sec, tv_usec, ev_type, code, value) = struct.unpack(FORMAT, event)
if ev_type == 1:
# Type 1 event - buttons
# Code 304 - X
# Code 308 - Square
# Code 307 - Triangle
# Code 305 - Circle
# Code 318 - right stick pressed
# Code 317 - l stick pressed
# Code 310 - L1 trigger
# Code 311 - R1 trigger
# Code 314 - Share button
# Code 315 - Options button
# Code 316 - PS button
elif ev_type == 3:
# Type 3 event - sticks
# Code 3 - right stick horizontal
# Code 2 - L2 trigger
# Code 5 - R2 trigger
# Code 0 - left stick horizontal (left is 0)
# Code 1 - left stick vertical (forward is 0)
# Code 4 - r stick vertical
# Code 17 - dpad vertical
# Code 16 - dpad horizontal
if code == 0:
left = scale(value, (0,255), (40, -40))
if code == 4: # Righ stick vertical
forward = scale(value, (0,255), (100,-100))
# Set motor voltages.
# Track the steering angle
# Finally, read another event
event = in_file.read(EVENT_SIZE)
This should be enough for a lot of fun while driving a race car with proportional steering control. The steering is not perfect, however, because there’s no differential. How would you program an electronic differential? And wouldn’t it be cool to have a video stream from the car? Stay tuned for the expanded version of the race car. You can support me on Patreon to get notified, subscribe to my Youtube channel or like my page on Facebook. I would also appreciate it if you’d browse my T-shirt designs!