We were placing shelves in the office today and decided the trusty spirit level was a bit old fashioned, why not use a Raspberry Pi and XLoBorg instead.
We came up with XLoLevel, a script to turn your Raspberry Pi into a digital spirit level
There are some options you can configure from lines 5 to 10:
filterLengthis the amount of readings to average over, increase to reduce noisy readings
fpsis the rate we wish to run at, larger values will use more processor time
windowXis the width of the window drawn
windowYis the height of the window drawn
bubbleSizeis the diameter of the on screen "bubble"
sensitivityis how much the bubble moves for a movement, at 2.0 the window edges are a 45° tilt
Here's the code, you can download the XLoLevel script file as text here
Save the text file on your pi as XLoLevel.py, in the ~/xloborg directory
Make the script executable using
chmod +x ~/xloborg/XLoLevel.py
and run using
#!/usr/bin/env python # coding: latin-1 # User settings filterLength = 10 # Filter size, larger is smoother but slower to update fps = 30 # Frames to draw per second, larger values use more CPU windowX = 400 # Window width windowY = 400 # Window height bubbleSize = 20 # Width of the bubble on screen sensitivity = 2.0 # How much the bubble moves, at 1.0 the edges are full scale # Import library functions we need import time import pygame import XLoBorg XLoBorg.Init() # Setup pygame and key states global quit quit = False pygame.init() fpsClock = pygame.time.Clock() screen = pygame.display.set_mode((windowX, windowY)) pygame.display.set_caption("XLoLevel - Press [ESC] to quit") backColour = pygame.Color(255, 255, 255) guideColour = pygame.Color(0, 0, 0) bubbleColour = pygame.Color(255, 0, 0) # Function to handle pygame events def PygameHandler(events): # Variables accessible outside this function global quit # Handle each event individually for event in events: if event.type == pygame.QUIT: # User exit quit = True elif event.type == pygame.KEYDOWN: # A key has been pressed, see if it is one we want if event.key == pygame.K_ESCAPE: quit = True # Function used to provide a simple averaging window on a value def BoxFilter(value, filterStorage): if len(filterStorage) == 0: # Setup the filter for first use for i in range(filterLength): filterStorage.append(value) else: # Insert the new value into the filter and remove the oldest filterStorage.pop() filterStorage.insert(0, value) # Generate a new average value value = 0.0 divisor = float(len(filterStorage)) for raw in filterStorage: value += raw / divisor return value try: filterX =  filterY =  filterZ =  print 'Press [ESC] to quit' # Loop indefinitely while True: # Get the currently pressed keys on the keyboard PygameHandler(pygame.event.get()) if quit: # Exit the loop break # Read the accelerometer and filter the results x, y, z = XLoBorg.ReadAccelerometer() x = BoxFilter(x, filterX) y = BoxFilter(y, filterY) z = BoxFilter(z, filterZ) # Convert into screen positions x *= sensitivity y *= sensitivity x = int((1.0 + x) * (windowX / 2) + 0.5) y = int((1.0 - y) * (windowY / 2) + 0.5) # Limit positions to on-screen if x < 0: x = 0 elif x >= windowX: x = windowX - 1 if y < 0: y = 0 elif y >= windowY: y = windowY - 1 # Draw the screen screen.fill(backColour) pygame.draw.line(screen, guideColour, (windowX / 2, 0), (windowX / 2, windowY - 1), 1) pygame.draw.line(screen, guideColour, (0, windowY / 2), (windowX - 1, windowY / 2), 1) pygame.draw.circle(screen, guideColour, (windowX / 2, windowY / 2), bubbleSize / 2 + 1, 2) pygame.draw.circle(screen, bubbleColour, (x, y), bubbleSize / 2, 0) pygame.display.update() # Wait for the next frame (will not run faster than fps, but may run slower) fpsClock.tick(fps) except KeyboardInterrupt: # CTRL+C exit, terminate pass