Skip to content

Instantly share code, notes, and snippets.

@artpoz
Last active December 22, 2023 03:33
Show Gist options
  • Save artpoz/d66f72a6092b580b9903d088dd6d1262 to your computer and use it in GitHub Desktop.
Save artpoz/d66f72a6092b580b9903d088dd6d1262 to your computer and use it in GitHub Desktop.
Lego vehicle controlled by ps4 gamepad (DualShock 4)
#!/usr/bin/env python3
__author__ = 'Artur Poznanski'
import evdev
import ev3dev.auto as ev3
import threading
import time
## Some helpers ##
def clamp(n, minn, maxn):
return max(min(maxn, n), minn)
def scale(val, src, dst):
return (float(val - src[0]) / (src[1] - src[0])) * (dst[1] - dst[0]) + dst[0]
def scale_stick(value):
return scale(value,(0,255),(-1000,1000))
def dc_clamp(value):
return clamp(value,-1000,1000)
## Initializing ##
print("Finding ps4 controller...")
devices = [evdev.InputDevice(fn) for fn in evdev.list_devices()]
ps4dev = devices[0].fn
gamepad = evdev.InputDevice(ps4dev)
forward_speed = 0
side_speed = 0
running = True
class MotorThread(threading.Thread):
def __init__(self):
self.right_motor = ev3.LargeMotor(ev3.OUTPUT_C)
self.left_motor = ev3.LargeMotor(ev3.OUTPUT_B)
threading.Thread.__init__(self)
def run(self):
print("Engine running!")
while running:
self.right_motor.run_forever(speed_sp=dc_clamp(forward_speed+side_speed))
self.left_motor.run_forever(speed_sp=dc_clamp(-forward_speed+side_speed))
self.right_motor.stop()
self.left_motor.stop()
motor_thread = MotorThread()
motor_thread.setDaemon(True)
motor_thread.start()
for event in gamepad.read_loop(): #this loops infinitely
if event.type == 3: #A stick is moved
if event.code == 0: #X axis on left stick
forward_speed = -scale_stick(event.value)
if event.code == 1: #Y axis on left stick
side_speed = -scale_stick(event.value)
if side_speed < 100 and side_speed > -100:
side_speed = 0
if forward_speed < 100 and forward_speed > -100:
forward_speed = 0
if event.type == 1 and event.code == 305 and event.value == 1:
print("X button is pressed. Stopping.")
running = False
time.sleep(0.5) # Wait for the motor thread to finish
break
@ninoguba
Copy link

How to detect if the d-pad buttons (up, down, left, right) are pressed? They don't seem to register when event.type == 1 like the rest of the buttons. Does anyone know if there is a reference somewhere that maps out all the event types, codes and values? I would like to find out too if the trackpad can also be used. Thanks!

@ninoguba
Copy link

Figured out that connecting the PS4 controller registers as 3 input devices. Using this code:

devices = [evdev.InputDevice(fn) for fn in evdev.list_devices()] for device in devices: print(device.name)

It will output:

Wireless Controller
Wireless Controller Motion Sensors
Wireless Controller Touchpad

So the first is the gamepad (the buttons and the joysticks), the second is the accelerometer, and the third is the touchpad (touch and click).

What I haven't figured out still is how to capture the events for when the D-pad buttons (up,down,left,right) are pressed. They seem to be not registering from any of these three inputs of the PS4 controller connected with Bluetooth to the EV3. Anyone figured this out yet?

@Quantum357
Copy link

Quantum357 commented Aug 31, 2020 via email

@ninoguba
Copy link

ninoguba commented Sep 1, 2020

@Quantum357 if you can already confirm, let us know what is the exact event type, code, and value for the d-pad buttons. thanks!

@Quantum357
Copy link

Quantum357 commented Sep 10, 2020 via email

@roachdaniel
Copy link

Sorry for a dumb question but, I am using your code with the ev3dev os with a Pistorms-V2 module. I have everything set up correctly and can run the OS and I have paired the ps4 controller successfully but I am not getting any response when I run your program. Any suggestions? The error log is below if that is helpful.

_**Exception in thread Thread-1:
Traceback (most recent call last):
File "/usr/lib/python3.5/threading.py", line 914, in _bootstrap_inner
self.run()
File "/home/robot/ps4explor3r.py", line 42, in run
self.right_motor.run_forever(speed_sp=dc_clamp(forward_speed+side_speed))
File "/usr/lib/python3/dist-packages/ev3dev/core.py", line 799, in run_forever
setattr(self, key, kwargs[key])
File "/usr/lib/python3/dist-packages/ev3dev/core.py", line 589, in speed_sp
self._speed_sp = self.set_attr_int(self._speed_sp, 'speed_sp', value)
File "/usr/lib/python3/dist-packages/ev3dev/core.py", line 223, in set_attr_int
return self._set_attribute(attribute, name, str(int(value)))
File "/usr/lib/python3/dist-packages/ev3dev/core.py", line 216, in _set_attribute
raise Exception("%s is not connected" % self)
Exception: LargeMotor(outC) is not connected

Traceback (most recent call last):
File "/home/robot/ps4explor3r.py", line 51, in
for event in gamepad.read_loop(): #this loops infinitely
File "/usr/lib/python3/dist-packages/evdev/device.py", line 254, in read_loop
r, w, x = select([self.fd], [], [])
KeyboardInterrupt**_

@Quantum357
Copy link

Quantum357 commented Jan 28, 2021 via email

@roachdaniel
Copy link

roachdaniel commented Jan 28, 2021 via email

@DuckingtonThe3rd
Copy link

There's a little problem in the stopping code. 305 is the O button, not the X button.

@Suwin11
Copy link

Suwin11 commented Dec 22, 2023

Is there a micropython version of this code? I wanted to the ps4 controller for a robot competition and waiting 20 whole seconds is not great. Can anyone help? (it will be great if i can control the motor separately with each joystick on my ps4)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment