For this project, I keep the same controller as in the previous post but, instead of controlling a servo motor through a second Arduino, I will use it as a game controller.
The game will be played on my desktop computer. Since I am not very good at writing games, I downloaded the PyGame library. This framework comes with tons of samples so I decided to hack one of these samples and replace the keyboard input with my controller. You move the tank left and right by turning the game controller in the vertical position. You can fire bombs by switching the controller horizontally.
The code and the circuit of the game controller are the exact same setup as in my previous post. What I’ll demonstrate here is how to implement a receiver in this Python game.
You will need to connect an XBee wireless module to your computer using a USB adapter board. This will create a new communication port, in our case COM8.
The idea is to replace the keyboard with the data coming from the controller through the serial port. To maintain compatibility with the original version, I decided to simply override the keyboard values with the wireless controller commands.
The first step is to load the proper modules and open a connection through the serial port. I will use two global variables to replace the keyboard commands: one for the firing command and the other for the tank direction.
# # Serial port communication with the Arduino/XBee # import serial import thread arduinoFiring = 0 arduinoDirection = 0 ser = serial.Serial('COM8', 19200, timeout=0) # Change COM[number] for ttyUSB[number]
Once this is defined, we need to override the keyboard values. To replace the spacebar fire command, we override the value with:
firing = keystate[K_SPACE] firing = arduinoFiring # <-- Override the keyboard with the game controller data
To replace the arrows direction commands, we are add the following lines:
direction = keystate[K_RIGHT] - keystate[K_LEFT] direction = arduinoDirection # <-- Override the keyboard with the game controller value
Finally, we have to feed these two values with the data received from the game controller. The best way to do this is by starting a new thread to listen on the serial port, read incoming data and convert it to game usable values.
def processArduino(buffer): global arduinoFiring global arduinoDirection if len(buffer) == 0: return if buffer[0] != '<': return if buffer[len(buffer)-1] != '>': return tokens = buffer[1:len(buffer)-1].split(':') if len(tokens) < 4: return for i in range(4): if len(tokens[i]) == 0: return #print(buffer) c = int(tokens[0]) x = int(tokens[1]) y = int(tokens[2]) z = int(tokens[3]) if y > 550: arduinoDirection = 1 elif y < 450: arduinoDirection = -1 else: arduinoDirection = 0 if z > 575: arduinoFiring = 1 else: arduinoFiring = 0 def readArduino(): buffer = '' while 1: b = ser.read() while b: if b == '<': buffer = '' buffer += b if b == '>': processArduino(buffer) b = ser.read(); def main(winstyle = 0): ... thread.start_new_thread(readArduino, ())
We have two functions here. The readArduino() function is the thread entry point that contains the code reading on the serial port. A buffer is built of bytes received from the game controller. When the ‘<’ character is read, the buffer is cleared to receive a new command. When the character ‘>’ is received, the command stored in the buffer is processed.
The data is processed in the function processArduino(buffer). The data buffer is received as a parameter. The function reads the three axis and the compass values. Then, it determines if the direction is -1, 0 or 1 and if the tank fires a bomb. The values of the axis range from 400 to 600. The constants used in the function to determine the position of the controller can be adjusted to match your game requirements.