Raspberry Pi motion controller
Use the accelerometer in PiBorg’s small and affordable XLoBorg device to turn your Pi into a game controller…
If you saw last issue you might remember the DoodleBorg, a massive remote-controlled tank of a vehicle designed and built by PiBorg, makers of add-ons for the Raspberry Pi. This month we’re looking at their XLoBorg, a board designed to help you measure movement and determine direction, among other things.
At under £10/$16, it’s a bargain too, because as well as featuring a three- axis accelerometer, it’s also kitted out with a three-axis magnetometer (digital compass). In this tutorial we’ll be using the accelerometer to turn our Pi into a tilt controller and mock up a simple demo to show how you could integrate it into your Pygame-powered games…
What you’ll need
Step 01 Install the XLoBorg
Installing the XLoBorg onto your Raspberry Pi really couldn’t be easier. It simply slots directly over your GPIO pins with the main body of the board facing over your Raspberry Pi. PiBorg has made the software side of the installation super easy too, by creating an installation script that automates the process of installing the required I2C drivers and library files on your Pi.
Step 02 Download the software
Make a new directory for the project files in your home folder by typing: mkdir ~/xloborg, enter the directory (with cd ~/xloborg) and download the package with:
$ wget www.piborg.org/downloads/xloborg/examples.zip
Now unzip the package with unzip examples.zip and make the install.sh script executable with chmod +x install.sh. Finally, run the script with ./install.sh and reboot your Pi once the installation has finished to finalise it.
Step 03 Inspect and test the library
Whenever you’re dealing with a new piece of hardware or a software library designed to abstract a particular process, it’s worth looking at the library directly to see how it works. The XLoBorg’s library is XLoBorg.py and it contains well- commented code that demonstrates the main functionality on the board well. The library is also executable with a simple routine to print the sensor results to the terminal. Run it with python XLoBorg.py from the terminal to ensure everything’s working properly. Move your Pi around to ensure the accelerometer readings change. If not, see the troubleshooting page.
Step 04 Start the script
All being well you’re seeing read-outs from running XLoBorg.py that change when you move the Raspberry Pi around. Now we know everything works, we can start our script with the core XLoBorg functionality. Open a new text editor file and save it as xloborg_app.py. First we need to initialise the XLoBorg in our script with XLoBorg.Init(), then we’re going to suppress the print function to save us wading through terminal output with a new line:
XLo.Borg.printprintFunction = XLoBorg.NoPrint
All we need to do now is create a variable that will carry the accelerometer readings. We’ve done this with the following line:
tilt = XLoBorg.ReadAccelerometer()
This will create a Tuple called tilt that containts x, y, z forces (in that order). We don’t need the z forces for this example, so we’ll inject the readings into a handy little function for our demo app by calling tilt and tilt for the x and y readings respectively.
Step 05 Pygame example app
Believe it or not, that’s all the XLoBorg code we need to turn our Raspberry Pi into a tilt controller. Next we’ll create a bare-bones graphical demo that could easily be turned into a marble tilt game or something similar. At the top of the script we’ve initiated some constants to cater for the screen size, ball size and colours. Then we initialise Pygame, creating a screen and setting a window caption. The main bulk of the program is a simple Ball class. The two methods update(x, y) and collide() ensure the ball position can be updated and the latter dictates what happens when the ball collides with the edge of the screen. We’ve constructed the update() method to take two variables – this is where we’ll inject our accelerometer values during the main loop of the script.
Step 06 The main loop
The main loop is designed to enter an infinite loop
using the variable game_over. While game_over is False everything after the while not game_over: line will be repeated 30 times every second until we quit it with the Escape key or CTRL+C. Before we start this loop, though, we ensure game_ over is indeed False and construct a ball. Once we enter the infinite loop we read the XLoBorg’s accelerometer, paint the screen black and call the ball.update(x, y) method using the tilt variable to pass the new readings to our ball. We then check the ball’s location to ensure it’s not trying to leave the screen, then we blit (or draw) the ball on the screen and redraw it using Pygame’s flip() function.
Once it’s complete, save the script and run it with python xloborg_app.py. Tilting your Raspberry Pi will move the ball on the screen – if the ball is moving in the wrong directions, simply ‘minus’ the respective reading as we’ve done in the example code on the right to flip them.
#!/bin/bash/env python import pygame import XLoBorg WIDTH = 800 HEIGHT = 600 REF_RATE = 30 BALL_SIZE = (24, 24) BLACK = (0, 0, 0) WHITE = (255, 255, 255) pygame.init() XLoBorg.Init() XLoBorg.printprintFunction = XLoBorg.NoPrint screen = pygame.display.set_mode([WIDTH, HEIGHT]) clock = pygame.time.Clock() pygame.display.set_caption('XLoBorg test - Press ESC to quit') class Ball(pygame.sprite.Sprite): def __init__(self, width, height): pygame.sprite.Sprite.__init__(self) self.size = (width, height) self.image = pygame.Surface([width, height]) self.image.fill(WHITE) self.rect = self.image.get_rect() self.rect.x, self.rect.y = WIDTH / 2, HEIGHT / 2 self.speed = (50, 50) self.tilt = [0, 0] def update(self, x, y): self.rect.x += x * self.speed self.rect.y += y * self.speed print 'X =', x, 'Y =', y def collide(self): if self.rect.x > WIDTH - self.size: self.rect.x = WIDTH - self.size elif self.rect.x < 0: self.rect.x = 0 if self.rect.y > HEIGHT - self.size: self.rect.y = HEIGHT - self.size elif self.rect.y < 0: self.rect.y = 0 def main_loop(): game_over = False ball = Ball(50, 50) while not game_over: for event in pygame.event.get(): if event.type == pygame.QUIT: game_over = True if event.type == pygame.KEYDOWN: if event.key == pygame.K_ESCAPE: game_over = True tilt = XLoBorg.ReadAccelerometer() screen.fill(BLACK) ball.update(-tilt, tilt) ball.collide() screen.blit(ball.image, ball.rect) pygame.display.flip() clock.tick(REF_RATE) pygame.quit() if __name__ == '__main__': try: main_loop() except KeyboardInterrupt: pygame.quit()