This is an extended project of LEGO MindStorms – Znap with a remote controller, please refer it for the Dog movement and communication between EV3 Bricks.
Thanks for Anton’s Mindstorms Hacks, evdev and Linux Input drivers v1.0 (c) 1999-2001 Vojtech Pavlik, they gave us good idea how Linux deal with inputs.
Since ev3dev is Linux based, when PS4 controller connected to the EV3 Brick via Bluetooth, we can identify the handler from a directory call /dev/input. As shown below, event2, event3 and event4 are created when the PS4 controller is connected.
When we looked into the device detail from /proc/bus/input/devices, we can get the following details,
- Handler Event 0 = Input0 – LEGO Mindstorms EV3 Speaker
- Handler Event 1 = Input1 – EV3 Brick Buttons
- Handler Event 2 = Input2 – Wireless Controller Touchpad
- Handler Event 3 = Input3 – Wireless Controller Motion Sensors
- Handler Event 4 = Input4 – Wireless Controller
We are going to use the Wireless Controller to control the Dog, event4 is the target handler to get all inputs information. Based on the information we reviewed, we learnt that event4 contains 16 bytes of data as shown below,
- tv_sec (long unsigned value) : Time in seconds since epoch at which event occurred.
- tv_usec (long unsigned value) : Microsecond portion of the timestamp.
- ev_type (unsigned short) : Event type
- code (unsigned short) : Event code
- value (signed long) : Event value
We are using ev_type, code and value to monitor the PS4 controller inputs. It updates real time for any status change, such as button press, button release, joystick movement. Keep in mind, if a button is being held, it will generate a value ‘1’ for once but no additional update until the button is released, then a value ‘0’ will be generated.[This part was created by Adam]
PS4 Controller mapping with EV3DEV
# Open the PS4 Controller file at /dev/input/event4 in binary mode infile_path = "/dev/input/event4" in_file = open(infile_path, "rb") # Format of the event contains - unsigned long int, unsigned long int, # unsigned short, unsigned short, signed int, i.e. LLHHi FORMAT = 'LLHHi' EVENT_SIZE = struct.calcsize(FORMAT) . . . # Read from the file and unpack into five variable based on the format event = in_file.read(EVENT_SIZE) (tv_sec, tv_usec, ev_type, code, value) = struct.unpack(FORMAT, event)
This part is to open the file event4 to import the PS4 Controller values into 5 variables based on the predefined format – ‘LLHHi’. We use ev_type, code and value to identify the action from PS4 Controller.
- ev_type : There are two main type, type 1 = buttons, type 3 = joystick, dpad and analog trigger
- code : Which button or joystick being pressed / moved
- value : The action done, button pressed = 1, released = 0, or analog value from joystick and analog trigger
So, we wrote a small program to identify each codes and values from the PS4 Controller. The result is shown below,
Key mapping as shown below Type = 1, code & possible value L1 - 310 (0,1) L2 - 312 (0,1) L3 - 317 (0,1) R1 - 311 (0,1) R2 - 313 (0,1) R3 - 318 (0,1) Triangle - 307 (0,1) Square - 308 (0,1) Cross - 304 (0,1) Circle - 305 (0,1) Share - 314 (0,1) Option - 315 (0,1) PS - 316 (0,1) Type = 3, code & possible value Left Stick Y - 1 (Up 0 - Down 255) Left Stick X - 0 (Left 0 - Right 255) Right Stick Y - 4 (Up 0 - Down 255) Right Stick X - 3 (Left 0 - Right 255) L2 - 2 (0 - 255) R2 - 5 (0 - 255) dpad Up & Down - 17 (-1, 0, 1) dpad Left & Right- 16 (-1, 0, 1)
How does the program work
def PS4_Controller(): global pressed global trigger_dog global speed global speed_backwards global speed_forwards global turning global out while True: # Read from the file and unpack into five variable based on the format event = in_file.read(EVENT_SIZE) (tv_sec, tv_usec, ev_type, code, value) = struct.unpack(FORMAT, event) if ev_type == 1 and code == 311 and value == 1: trigger_dog = 45 out = 1 if ev_type == 1 and code == 311 and value == 0: trigger_dog = 0 out = 0 if ev_type == 1 and code == 310 and value == 1 and out == 0: trigger_dog = 35 if ev_type == 1 and code == 310 and value == 0 and out == 0: trigger_dog = 0 if ev_type == 1 and code == 305 and value == 1: pressed = True if ev_type == 1 and code == 305 and value == 0: pressed = False if ev_type == 3 and code == 5: speed_forwards = value * 6 elif ev_type == 3 and code == 2: speed_backwards = value * -6 if ev_type == 3 and code == 0: turning = (value*360-(180*255))/255 PS4_Controller_Thread = threading.Thread(target = PS4_Controller) PS4_Controller_Thread.setDaemon = True PS4_Controller_Thread.start() bite = 0 while True: speed = speed_forwards + speed_backwards print(speed) combo(pressed) forward(speed,turning) bite = Dog_bite(trigger_dog, bite) in_file.close()
Since we didn’t want to change the program of ‘the Dog’, we replaced the LEGO Controller part, i.e. receiving LEGO Controller result, with a new function to detect the action from the PS4 Controller buttons and joysticks. When corresponding action done on the PS4 Controller, the function will update the variable for ‘the Dog’ to action.
For example, when we press the circle, the function will detect a value of ev_type = 1 , code = 305 and value = 1. Then, it changes the variable ‘Pressed ‘ to True so that ‘the Dog’ will do combo. If we keep pressing the button, the variable ‘Pressed’ will stay True until we released the button.
We made the function parallel processing because it can detect all the status changes from the PS4 Controller. If we use normal function, the function will only read the latest actions from the controller that may result missing some of the actions. Especially, if we want to detect button pressed or released.
When we use global variable, the variable change by the parallel progressing function can be read by the program outside. For the PS4_Controller function detects any actions from the controller, it will change the corresponding variable for ‘the Dog’ to respond, just like the LEGO Controller sending message to ‘the Dog’.
Build instruction and the program
We created the program from scratch without referring any example, you can download from below.
Official Build Instruction from LEGO
Moreover, you may try to learn more about event2 & event3 for how to use the controller touchpad and the motion sensor.