Tuesday, 2 February 2016

Microbit - a Bop-it game in Python

I wanted to create a simple game for the Microbit and after bring brought an R2D2 Bop-it game I thought I would make one whereby you have to press the A and B buttons in time.

Lets start by importing the micropython library:
from microbit import *
Create some constants, one for the SPEED which is the amount of time in between each bop for each level, and one for the LEVELUP's which is the amount of points at each level:
SPEED = {0: 1000, 1: 750, 2: 650, 3: 600, 4: 550, 5: 500}
LEVELUP = (5, 10, 15, 20, 25, 30)
Create 4 functions which when caused will show A, B, a tick and a cross:
def show_a():
    display.clear()
    display.show("A")

def show_b():
    display.clear()
    display.show("B")

def show_tick():
    display.clear()
    display.set_pixel(0, 3, 9)
    display.set_pixel(1, 4, 9)
    display.set_pixel(2, 3, 9)
    display.set_pixel(3, 2, 9)
    display.set_pixel(4, 1, 9)
    
def show_cross():
    display.clear()
    display.show("X")
Create a function which will wait for the button to be pressed, returning True if it is and False if it isn't:
def wait_for_button(rightbutton, wrongbutton):
    rightpressed = False
    wrongpressed = False
    
    started = running_time()
    now = running_time()
    
    while now - started < SPEED[level]:
        if rightbutton.is_pressed():
            rightpressed = True
        if wrongbutton.is_pressed():
            wrongpressed = True
        now = running_time()
        
    if rightpressed == True and wrongpressed == False:
        return True
    else:
        return False
Set 3 variables for the level, the score and one which will be set to True when the game is over:
level = 0
score = 0
gameover = False
Scroll "BopBit" on the screen to show its the start of the game:
display.scroll("BopBit")
Loop until the game is over:
while gameover == False:
Randomly pick an action (either A or B), show it on the screen and wait for a button to be pressed:
    success = False
    
    #randomly pick an A or B button
    action = random(2)
    
    #wait for the button to be pressed
    if action == 0:
        show_a()
        success = wait_for_button(button_a, button_b)
    elif action == 1:
        show_b()
        success = wait_for_button(button_b, button_a)
If the player pressed the right button in time show a tick and increase the score or show a cross:
    if success:
        show_tick()
        score = score + 1
        #if the score is a levelup score increase the level 
        if score in LEVELUP:
            level = level + 1
    else:
        show_cross()
        gameover = True
Wait for a small amount of time (half the current speed):
    sleep(int(SPEED[level] / 2))
After the game is over, sleep for 1 second, and display the players score on a loop:
sleep(1000)
while True:
    display.scroll("{} points".format(score))
You can view the complete code in my Microbit MicroPython examples repository on github.

How about taking it further by adding new actions such as shaking or a connecting up a speaker and adding a sound track,

Monday, 18 January 2016

Pocket PiGRRL - Battery Monitor

I recently made myself an Adafruit Pocket PiGRRL and I wanted to modify it so it would warn me when the battery was running low - there is a small red LED but its hidden inside the case!


The plan was to create a program which would sense the battery getting low and put a warning icon on the top left of screen giving me time to shutdown the Pi properly or plug it in.



TLDR - just scroll down to install Grrl Battery Monitor.

I started with the software as I, foolishly, thought this would be the hardest part, the problem with creating an icon is that is has to go over the top of everything regardless of what is on the screen (command prompt, emulators, emulation station, everything) regardless of what was rendering it.

My first plan was that I could use Picamera's overlay function which I knew used the GPU to output directly to the screen, and with a bit of help from Dave Jones who put together a prototype, it was looking good, but while the icon appeared on top of emulators and the command prompt, it didnt write over emulation station.

I came across Low Level Graphics on Raspberry Pi which walks you through writing graphics directly to the Linux framebuffer using C, this was a lot lower level than I hoped to get into but it would definitely write my icon over anything that was on the screen - using this I wrote a program to create an icon on the screen when a GPIO pin was triggered.

Next I needed to be able to read from the power booster when the battery was running low, my original plan was to use the LBO (low battery output) pin, but this proved to be way more difficult than I expected, read this post on Adafruit's forum if your really interested.

I ended up connecting a wire to the low battery warning led (red) on the power booster and using this to switch a transistor which connected a GPIO to ground.


Its been frustrating but I am really pleased with how it worked out - if you want to add the batter monitor to your own Pocket PiGRRL follow the instructions below.

Install Grrl Battery Monitor

You will need a few parts:
  • Some wire
  • 2N3904 NPN transistor
  • 47k resistor
  • Strip board
1. Open up your Pi GRRL and connect a small length of wire to the red (low power) led on the power booster.



2. Solder the components to the strip board. including 2 lengths of wire which will connect to GPIO 19 and GND.




3. Flip over your Pi and solder the GPIO and GND wires to the underside of the Pi's GPIO header.


The yellow wire is for my mute / un-mute amp function.

4, Solder the wire from the low power (red) led to the strip board.


5. Stick the strip board to the case in-between the power booster and the amp with a bit of glue and put your PiGRRL back together.

6. Download the program from github.com/martinohanlon/grrl-bat-monitor
cd ~
git clone https://github.com/martinohanlon/grrl-bat-monitor
7. Make the program run at boot by editing /etc/rc.local
sudo nano /etc/rc.local
Scroll down and add the command under '/usr/local/bin/retrogame &' but before 'exit 0':
/home/pi/grrl-bat-monitor/grrl_bat_mon &
8. Reboot and test!

Sunday, 10 January 2016

Pocket PiGRRL - adding a mute

I recently made myself a Pocket PiGRRL based on Adafruit's tutorial - it really is a great machine and a brilliant learning experience.


There was one aspect though that I didn't like, the speaker hisses, not particularly loud and when your playing a game its not that noticeable but if you have got the volume down it is really annoying. Its all down the Raspberry Pi's noisy analogue audio out so there isn't a great deal you can do to clean it up.

My solution was to add the ability to shutdown the amp, effectively muting it when I didn't want any sound.

The PAM8302A amp breakout board has a shutdown (SD) pin which when a ground (logic zero) is connected it puts the amp into idle mode, muting the amp and reducing power consumption.


I soldered a piece of wire between GPIO 26 on the bottom of the A+ and the shutdown pin on the PAM8302A ampl.



This gave me a way of triggering the shutdown pin next I needed some software and a way of running it.

Using this tutorial as the basis I added an 'Apps' tab to emulation station where I could run 2 scripts to mute and unmute the amp.

If you want to configure your Pocket PiGRRL to do the same, you can follow the instructions below.

Configure emulation station
Copy the emulation station default settings file to the pi user's emulation station configuration:
cp /etc/emulationstation/es_systems.cfg ~/.emulationstation/
Add the 'apps' tab to the settings file:
nano ~/.emulationstation/es_systems.cfg
Scroll down to the bottom and add the following before the </systemList> text:
  <system>
    <fullname>Applications</fullname>
    <name>Apps</name>
    <path>~/RetroPie/roms/apps</path>
    <extension>.sh .SH .py .PY</extension>
    <command></command>%ROM%
    <platform>apps</platform>
    <theme>esconfig</theme>
  </system>
Save and exit using Ctrl X.

Make a directory in roms to hold the scripts:
mkdir ~/RetroPie/roms/apps
Create a script to mute the amp by setting GPIO 26 to low (0):
nano ~/RetroPie/roms/apps/mute_amp.sh

gpio -g mode 26 out
gpio -g write 26 0
And an unmute script:
nano ~/RetroPie/roms/apps/unmute_amp.sh

gpio -g mode 26 out
gpio -g write 26 1
Make the scripts executable:
chmod +x ~/RetroPie/roms/apps/mute_amp.sh
chmod +x ~/RetroPie/roms/apps/unmute_amp.sh
You can now test the scripts by running them:
~/RetroPie/roms/apps/mute_amp.sh
~/RetroPie/roms/apps/unmute_amp.sh
Reboot and the Apps tab will appear in emulation station with 2 options to mute and unmute the amp.

I wanted the amp to be muted by default, so I added the script to be run at boot by editing /etc/rc.local:
sudo nano /etc/rc.local
Scroll down and add the unmute command under '/usr/local/bin/retrogame &' but before 'exit 0':
/home/pi/RetroPie/roms/apps/mute_amp.sh &

Friday, 18 December 2015

Minecraft, a Microbit and an X-Wing

I was having a chat with David Whale, my co-author of Adventures in Minecraft and he remarked that wouldn't it be cool if you could control something in Minecraft using the Microbit. (Btw - you should definitely check out David's virtual Minecraft Microbit.)

I settled on the idea of using the Microbit's accelerometer to control an object flying through Minecraft. What object, well it had to be the X-Wing, from my previous Minecraft - Star Wars project.


The A button starts and stops the X-Wing, by tilting the Microbit left and right you can turn and the B button drops blocks of TNT which create craters where they land.


There are 2 python programs:
  1. microbitreaddata.py - this runs on the Microbit and reads the status of the buttons and accelerometer 
  2. mcfly.py - this runs on your computer (I used a Windows PC running Raspberry Juice and full Minecraft, but it would work on a Raspberry Pi as well) which reads the data from the Microbit and makes all the calls to move the X-Wing in Minecraft.
You will find the full code and my other Microbit MicroPython examples at github.com/martinohanlon/microbit-micropython.

Monday, 30 November 2015

MicroBit Magic 8 Ball with MicroPython

I wanted to create something with the MicroBit which used the on-board accelerometer and I settled on a Magic 8 Ball, the fortune-telling pool ball which when shaken and asked a question it provides, a, often cryptic, response.


The program works out whether the MicroBit has been shaken by:
  • Reading the x, y, z values from the accelerometer in a loop and adding them together to get a total force exposed
  • Getting the difference between the last reading and the current reading
  • If the difference is greater than a threshold, you assume the MicroBit has been shaken
I wrapped this into a function wait_for_shake, which perhaps not unsurprisingly blocks until the MicroBit is shaken!
import microbit

TOLERANCE = 3000

def get_accel_total():
    x = microbit.accelerometer.get_x()
    y = microbit.accelerometer.get_y()
    z = microbit.accelerometer.get_z()
    return x + y + z

def wait_for_shake():
    shaken = False
    last = get_accel_total()
    while not shaken:
        this = get_accel_total()
        diff = last - this
        if diff < 0: diff = diff * -1
        if diff > TOLERANCE:
            shaken = True
        last = this
        microbit.sleep(50)
Its not 'very' sophisticated but it works.

Once I had this working it pretty simple to add a loop which waited for the MicroBit to be shaken and scrolled a random message on the LED screen.
MESSAGES = ["It is certain", "Dont count on it", "Ask again"]
while True:
    microbit.display.print("8")
    wait_for_shake()
    microbit.display.clear()
    microbit.sleep(2000)
    message = microbit.random(len(MESSAGES))
    microbit.display.scroll(MESSAGES[message])
If you want to add your own messages, just add them to the MESSAGES list.

You can find the code here and other examples in my microbit-micropython GitHub repository.


Thursday, 26 November 2015

Snake on MicroBit using MicroPython

I got my hands on one of the BBC's Microbit's as part of ntoll's Micro World Tour.

I used ntoll's upyed website to create my code and download the .hex file which I uploaded to the Microbit.

After a few tests to see if everything was working I decided to see if I could port the code I wrote to make Snake for Minecraft and Raspberry Pi Sense Hat.


I was pretty pleased. If you want to have a go yourself you will find the code here.

The code
import microbit

class SnakeBit():
    UP = 0
    DOWN = 1
    RIGHT = 2
    LEFT = 3
    
    SNAKEBRIGHTNESS = 9
    APPLEBRIGHTNESS = 5
    SAMPLETIME = 50
    SAMPLESPERMOVE = 10
    
    def __init__(self):
        pass
    
    def startGame(self):
        microbit.display.clear()
        self.direction = self.UP
        self.length = 2
        self.tail = []
        self.tail.insert(0, [2, 4])
        self.createApple()
        self.score = 0
        
        playing = True
        
        samples = 0
        while(playing):
            #keep looping around, if the button is pressed, move the snake immediately, 
            #otherwise move it when the sample time is reached
            microbit.sleep(self.SAMPLETIME)
            buttonPressed = self._handle_buttons()
            samples = samples + 1
            if buttonPressed or samples == self.SAMPLESPERMOVE:
                playing = self.move()
                samples = 0
                
        microbit.display.scroll("Score = " + str(self.score), 100)
        microbit.display.clear()

    def _handle_buttons(self):
        buttonPressed = False
        
        #has a button been pressed
        if microbit.button_a.is_pressed():
            #wait for the button to be released
            while microbit.button_a.is_pressed():
                microbit.sleep(self.SAMPLETIME)
            self.left()
            buttonPressed = True
        
        if microbit.button_b.is_pressed():
            while microbit.button_b.is_pressed():
                microbit.sleep(self.SAMPLETIME)
            self.right()
            buttonPressed = True
            
        return buttonPressed

    def createApple(self):
        badApple = True
        #try and fnd a location for the apple
        while(badApple):
            x = microbit.random(5)
            y = microbit.random(5)
            badApple = self.checkCollision(x, y)
        self.apple = [x, y]
        microbit.display.set_pixel(x, y, self.APPLEBRIGHTNESS)

    def checkCollision(self, x, y):
        #is this outside the screen
        if x > 4 or x < 0 or y > 4 or y < 0:
            return True
        else:
            #or in the snakes tail
            for segment in self.tail:
                if segment[0] == x and segment[1] == y:
                    return True
            else:
                return False

    def addSegment(self, x, y):
        #create the new segment of the snake
        microbit.display.set_pixel(x, y, self.SNAKEBRIGHTNESS)
        self.tail.insert(0, [x, y])
        
        #do I need to clear a segment
        if len(self.tail) > self.length:
            lastSegment = self.tail[-1]
            microbit.display.set_pixel(lastSegment[0], lastSegment[1], 0)
            self.tail.pop()

    def move(self):
        #work out where the new segment of the snake will be
        newSegment = [self.tail[0][0], self.tail[0][1]]
        if self.direction == self.UP:
            newSegment[1] -= 1
        elif self.direction == self.DOWN:
            newSegment[1] += 1
        elif self.direction == self.LEFT:
            newSegment[0] -= 1
        elif self.direction == self.RIGHT:
            newSegment[0] += 1

        if self.checkCollision(newSegment[0], newSegment[1]):
            #game over
            snakehead = self.tail[0]
            for flashHead in range(0,5):
                microbit.display.set_pixel(snakehead[0], snakehead[1], self.SNAKEBRIGHTNESS)
                microbit.sleep(200)
                microbit.display.set_pixel(snakehead[0], snakehead[1], 0)
                microbit.sleep(200)
            
            return False
            
        else:
            self.addSegment(newSegment[0], newSegment[1])

            #has the snake eaten the apple?
            if newSegment[0] == self.apple[0] and newSegment[1] == self.apple[1]:
                self.length += 1
                self.score += 10
                self.createApple()

            return True

    def left(self):
        if self.direction == self.RIGHT:
            self.direction = self.UP
        elif self.direction == self.UP:
            self.direction = self.LEFT
        elif self.direction == self.LEFT:
            self.direction = self.DOWN
        elif self.direction == self.DOWN:
            self.direction = self.RIGHT

    def right(self):
        if self.direction == self.RIGHT:
            self.direction = self.DOWN
        elif self.direction == self.DOWN:
            self.direction = self.LEFT
        elif self.direction == self.LEFT:
            self.direction = self.UP
        elif self.direction == self.UP:
            self.direction = self.RIGHT

snake = SnakeBit()
snake.startGame()

Tuesday, 10 November 2015

Raspberry Pi PiAware Aircraft Radar

After creating the PiAware Flight Indicator LED I was keen to see what else I could do with the aircraft data my PiAware setup was retrieving for me.

I thought I would see if I could make an 'old fashioned' radar to show what aircraft were being picked up so I could have my own desk based radar.



I found an example of a radar written in pygame, which became the basis of my code (although I am pretty sure the original author wouldn't recognise it now) and created a radar class.

I plugged in the GPS coordinates of the aircraft using the PiAware flight data class I created to produce a pretty swanky, even if I say so myself, radar of all the aircraft I am picking up signals from.

Setup PiAware
If you want to have a go, first you need to setup a PiAware server to receive data - you don't need a lot of equipment and its really easy to do.

Download my project
The code is on github at github.com/martinohanlon/PiAwareRadar.
git clone https://github.com/martinohanlon/PiAwareRadar
Run the program
The program expects a number of command line parameters, the mandatory being the latitude and longitude of your PiAware server, which will be the centre of the radar.
cd PiAwareRadar/piawareradar
python3 piawareradar.py mylat mylon
You can set other parameters for the IP address of the PiAware server, if your radar is running on a different machine, whether you want it to run full screen and the layout of your screen (normal or touch).

Usage
    usage: piawareradar.py [-h] [--piawareip PIAWAREIP] [--screen SCREEN] [--fullscreen] lat lon
    
    PiAware Flight Radar
    
    positional arguments:
      lat                   The latitude of the receiver
      lon                   The longitude of the receiver

    optional arguments:
      -h, --help            show this help message and exit
      --piawareip PIAWAREIP The ip address of the piaware server
      --screen SCREEN       The screen config to use [normal / touch]
      --fullscreen          Fullscreen radar
The plus and minus buttons in the top right allow you to zoom in and out, if you click on a dot, the data about that flight will be display in the bottom right hand corner.