Project tutorial
Control games using arduino, mpu6050 and python

Control games using arduino, mpu6050 and python © GPL3+

I am controlling my asphalt 8 game using my old upgraded bicycle. So let's see how it works

  • 8 views
  • 0 comments
  • 0 respects

Components and supplies

Apps and online services

About this project

Hello Everyone,

This Controller can be used as gaming controller for playing games. I was thinking to make something from MPU6050 and then I decided to make this project.

So Let's see how it works

In this project ardiono uno reads the button state of the throttle button, brake button and the data provide by the MPU6050 sensor then prints a character on the serial monitor and then a python program reads the character to simulate a keyboard input to a program(Game).

So How to make this thing ?

Step 1

Initially you have to do some basic wiring to connect the arduino with the mpu6050 and two Buttons one for throttle another for brake.

Now you have to set the hardware on bicycle so that it feels more real(you may skip this or install where you want)

Install the MPU6050 sensor tightly. place its Z axis similar to my setup(you may change but then you have do some changes in the code)

Step 3

Now in the Software portion, I am using a library <MPU6050_tockn.h> and <wire.h>.

Now I am using some key code for every motion.

Event Action

If throttle button is pressed write 'w' on the Serial port

if brake button is pressed write 's' on the Serial port

if right position observed write 'd' on the Serial port

if left position is observed write 'a' on the Serial port

if throttle button is pressed and right position observed write 'e' on the Serial port

If throttle button is pressed and left position is observed write 'q' on the Serial port

if brake button is pressed and right position observed write 'c' on the Serial port

if brake button is pressed and left position observed write 'z' on the Serial port

so for doing this we have to use the following code

if(mpu6050.getAngleZ()>25 && digitalRead(A0))  
  Serial.println('q');
 else if(mpu6050.getAngleZ()<-25 && digitalRead(A0))
  Serial.println('e');
 else if(mpu6050.getAngleZ()>25 && digitalRead(A1))
  Serial.println('z');
 else if(mpu6050.getAngleZ()<-25 && digitalRead(A1))
  Serial.println('c');
 else if(digitalRead(A0))
  Serial.println('w');
 else if(digitalRead(A1))
  Serial.println('s');
 else if(mpu6050.getAngleZ()>25)
 Serial.println('a');
 else if(mpu6050.getAngleZ()<-25)
 Serial.println('d');

Note - if you are using another axis then you can use mpu6050.getAngleX() or mpu6050.getAngleY().

mpu6050.getAngleZ()>25

here I will consider the left move when the mpu6050.getAngleZ() gives value greater than 25(threshold point), you can change and set you own threshold point, for finding your own threshold point you can use this example code of getAngle to check the value your sensor at every position then you can select Sthe value at your desired position.

See my Serial monitor

Till now we are getting our value at serial port, now we will scan the serial port using python and then simulate the input, in this I will give two python code one of them generate input using pyautogui But sometime this will not work on Direct X games so I will also give the second python code(port2.py) that will hopefully work, So try both the python codes (port1.py and port2.py) one by one and see which works. you can also select an notepad after running the python program an if you see it prints w on notepad on pressing the throttle button or giving any other moves, then everything is fine from this hardware and arduino side.

I have given the complete code below. [Note- inside python program change port name to your arduino port, for me this is 'COM3']

Step 4- running it

1st- At first connect the arduino open serial monitor if everything is working fine you are seeing the correct output in serial monitor then close the serial monitor

2nd - open the game

3rd - run the python script go to the gaming window

4th - Enjoy, now you are done

Now see how this work on real-time I am using this in asphalt 8 - Airborne

See how this controller work, ignore my driving skill inside the game I am not a pro in games

So Hope you Like it.

Code

directkey.pyPython
this is additional program required for port2.py so place them in same folder while running port2.py but don't run this, Only run port2.py that will automatically import the requirement from this program file
import ctypes
import time

SendInput = ctypes.windll.user32.SendInput


W = 0x11
A = 0x1E
S = 0x1F
D = 0x20

NP_2 = 0x50
NP_4 = 0x4B
NP_6 = 0x4D
NP_8 = 0x48

# C struct redefinitions 
PUL = ctypes.POINTER(ctypes.c_ulong)
class KeyBdInput(ctypes.Structure):
    _fields_ = [("wVk", ctypes.c_ushort),
                ("wScan", ctypes.c_ushort),
                ("dwFlags", ctypes.c_ulong),
                ("time", ctypes.c_ulong),
                ("dwExtraInfo", PUL)]

class HardwareInput(ctypes.Structure):
    _fields_ = [("uMsg", ctypes.c_ulong),
                ("wParamL", ctypes.c_short),
                ("wParamH", ctypes.c_ushort)]

class MouseInput(ctypes.Structure):
    _fields_ = [("dx", ctypes.c_long),
                ("dy", ctypes.c_long),
                ("mouseData", ctypes.c_ulong),
                ("dwFlags", ctypes.c_ulong),
                ("time",ctypes.c_ulong),
                ("dwExtraInfo", PUL)]

class Input_I(ctypes.Union):
    _fields_ = [("ki", KeyBdInput),
                 ("mi", MouseInput),
                 ("hi", HardwareInput)]

class Input(ctypes.Structure):
    _fields_ = [("type", ctypes.c_ulong),
                ("ii", Input_I)]

# Actuals Functions

def PressKey(hexKeyCode):
    extra = ctypes.c_ulong(0)
    ii_ = Input_I()
    ii_.ki = KeyBdInput( 0, hexKeyCode, 0x0008, 0, ctypes.pointer(extra) )
    x = Input( ctypes.c_ulong(1), ii_ )
    ctypes.windll.user32.SendInput(1, ctypes.pointer(x), ctypes.sizeof(x))

def ReleaseKey(hexKeyCode):
    extra = ctypes.c_ulong(0)
    ii_ = Input_I()
    ii_.ki = KeyBdInput( 0, hexKeyCode, 0x0008 | 0x0002, 0, ctypes.pointer(extra) )
    x = Input( ctypes.c_ulong(1), ii_ )
    ctypes.windll.user32.SendInput(1, ctypes.pointer(x), ctypes.sizeof(x))

if __name__ == '__main__':
    PressKey(0x11)
    time.sleep(1)
    ReleaseKey(0x11)
    time.sleep(1)
Arduino_game_code.inoArduino
Upload this code to your arduino uno
#include <MPU6050_tockn.h>
#include <Wire.h>

MPU6050 mpu6050(Wire);

void setup() {
  Serial.begin(9600);   //start the serial communication
  Wire.begin();         // start I2C communication for comunicating with MPU6050
  mpu6050.begin();
  mpu6050.calcGyroOffsets(true);
  pinMode(A1,INPUT);            // throttle button signal pin
  pinMode(A0,INPUT);            // brake button signal pin
}

void loop() {
  mpu6050.update();
  if(mpu6050.getAngleZ()>25 && digitalRead(A0))   // check if forward(throttle) and left
   Serial.println('q');                           // print 'q' on the serial port
  else if(mpu6050.getAngleZ()<-25 && digitalRead(A0))   // check if forward(throttle) and right
   Serial.println('e');                                 // print 'e' on the Serial Port
  else if(mpu6050.getAngleZ()>25 && digitalRead(A1))    // check if backward(brake) and left 
   Serial.println('z');                                 // print 'z' on the Serial Port
  else if(mpu6050.getAngleZ()<-25 && digitalRead(A1))   // check if backward(brake) and right 
   Serial.println('c');                                 // print 'c' on the Serial Port 
  else if(digitalRead(A0))                              // check if forward(throttle)
   Serial.println('w');                                 // print 'w' on the serial port
  else if(digitalRead(A1))                              // check if backward(brake)
   Serial.println('s');                                 // print 's' on the Serial 
  else if(mpu6050.getAngleZ()>25)                       // check if left 
  Serial.println('a');                                  // print 'a' on the Serial Port
  else if(mpu6050.getAngleZ()<-25)                      // check if right
  Serial.println('d');                                  // print 'd' on the Serial Port
}
port1.pyPython
before trying this install pyautogui by the command "pip install pyautogui", try this first if doesn't then try port2.py
# this is port1.py, first python program if this doesn't work on your game then use port2.py

import time
import pyautogui as pg
import serial

print("i wil give input after 5s so")
for i in range(5):
    print(i, end = "\n")
    time.sleep(1)
ser = serial.Serial('COM3', baudrate=9600, timeout=1)   # change COM3 to your port in which arduino is connected
while True:
    portdata = ser.readline().decode('ascii')           # read the data comming from arduino
    if len(portdata) == 0:
        print("no data comming........", end = "\n")    # port is connected but no data is avaliable on serial port
        ser.flushInput()
    if len(portdata) != 0:                              # if data is avaliable on the serial port
        if portdata[0] == 'q':                          # check the data
            pg.keyDown('w')                             #simulate key input
            pg.keyDown('a')
            time.sleep(0.2)
            pg.keyUp('w')
            pg.keyUp('a')
            ser.flushInput()                            # clear the queues of data on Serial port that stored while simulating key input
        elif portdata[0] == 'e':
            pg.keyDown('w')
            pg.keyDown('d')
            time.sleep(0.2)
            pg.keyUp('w')
            pg.keyUp('d')
            ser.flushInput()
        elif portdata[0] == 'z':
            pg.keyDown('s')
            pg.keyDown('a')
            time.sleep(0.2)
            pg.keyUp('s')
            pg.keyUp('a')
            ser.flushInput()
        elif portdata[0] == 'c':
            pg.keyDown('s')
            pg.keyDown('d')
            time.sleep(0.2)
            pg.keyUp('s')
            pg.keyUp('d')
            ser.flushInput()
        elif portdata[0] == 'w':
            pg.keyDown('w')
            time.sleep(0.1)
            pg.keyUp('w')
            ser.flushInput()
        elif portdata[0] == 's':
            pg.keyDown('s')
            time.sleep(0.1)
            pg.keyUp('s')
            ser.flushInput()
        elif portdata[0] == 'a':
            pg.keyDown('a')
            time.sleep(0.1)
            pg.keyUp('a')
            ser.flushInput()
        elif portdata[0] == 'd':
            pg.keyDown('d')
            time.sleep(0.2)
            pg.keyUp('d')
            ser.flushInput()
port2.pyPython
this is port2.py, second python program use this if first one doesn't work, and this also need a additional program file so also place that on the same folder am also giving that additional program
# check this program if work then Enjoy , this will probably work on all high end games(Direct X games)

import serial
import time
from directkey import PressKey, ReleaseKey, W, A, S, D

ser = serial.Serial('COM3', baudrate=9600, timeout=1)   # change COM3 to your port in which arduino is connected
while True:
    portdata = ser.readline().decode('ascii')           # read the data comming from arduino
    if len(portdata) == 0:
        print("no data comming........", end = "\n")    # port is connected but no data is avaliable on serial port
        ser.flushInput()
    if len(portdata) != 0:                              # if data is avaliable on the serial port
        if portdata[0] == 'q':                          # check the data
            PressKey(W)                                 #simulate key input
            PressKey(A)
            time.sleep(0.2)
            ReleaseKey(W)
            ReleaseKey(A)
            ser.flushInput()                            # clear the queues of data on Serial port that stored while simulating key input
        elif portdata[0] == 'e':
            PressKey(W)
            PressKey(D)
            time.sleep(0.2)
            ReleaseKey(W)
            ReleaseKey(D)
            ser.flushInput()
        elif portdata[0] == 'z':
            PressKey(S)
            PressKey(A)
            time.sleep(0.2)
            ReleaseKey(S)
            ReleaseKey(A)
            ser.flushInput()
        elif portdata[0] == 'c':
            PressKey(S)
            PressKey(D)
            time.sleep(0.2)
            ReleaseKey(S)
            ReleaseKey(D)
            ser.flushInput()
        elif portdata[0] == 'w':
            PressKey(W)
            time.sleep(0.2)
            ReleaseKey(W)
            ser.flushInput()
        elif portdata[0] == 's':
            PressKey(S)
            time.sleep(0.2)
            ReleaseKey(S)
            ser.flushInput()
        elif portdata[0] == 'a':
            PressKey(A)
            time.sleep(0.2)
            ReleaseKey(A)
            ser.flushInput()
        elif portdata[0] == 'd':
            PressKey(D)
            time.sleep(0.2)
            ReleaseKey(D)
            ser.flushInput()

Schematics

Circuit Diagram
diagram is very easy and simple so connect wire, upload the program and enjoy
Circuit kxa7et1ngy

Comments

Similar projects you might like

Servo Control with TV Remote Control

Project showcase by eldo85

  • 16,807 views
  • 7 comments
  • 40 respects

Control an LED with the Remote Control

Project showcase by Nicholas_N

  • 17,339 views
  • 11 comments
  • 22 respects

Remote Bluetooth Light Control with Python

Project showcase by Noah Huber-Feely

  • 10,620 views
  • 1 comment
  • 14 respects

Chrome Dino Game "Revamped" with arduino and python

Project tutorial by YASH36

  • 1,663 views
  • 1 comment
  • 7 respects

Playing Smartphone Games with a Relay Touch Board

Project showcase by HomeMadeGarbage

  • 7,066 views
  • 6 comments
  • 11 respects
Add projectSign up / Login