Tuesday, 12 April 2016

Mayhem, Amiga game, ported to Raspberry Pi

I had a Commodore Amiga and a game I played, a lot, was Mayhem, its a multiplayer (2-4) shooter - imagine multiplayer asteroids, with gravity, fuel and shields!

It was ported to the PC in 2002 by devpack who released the code in 2011 on github and google code which is where I picked it up and ported it to the Raspberry Pi.

This is the port, but check out the original Amiga game.

I got some help from the Raspberry Pi forums in getting it to compile then it was case of sorting out a few case sensitive filename bugs (it was original written for Windows!) and tracking down a bug in the original code which was causing a memory access error and segmentation fault.

The code is on github.com/martinohanlon/mayhem-pi.

Install
sudo apt-get install liballegro4.4 liballegro4-dev
git clone https://github.com/martinohanlon/mayhem-pi

Run
cd mayhem-pi
./start

Keys
Player 1 - z, x, c, v, g
Player 2 - left, right, pad del, pad 0, pad enter
Player 3 - b, n, 'comma', m, l
Player 4 - y, u, o, i, 0
Change level - 1, 2, 3

Compile
If you want to modify the game, I've got a couple of things on my list, you can recompile it with.
cd mayhem-pi
make


Sunday, 27 March 2016

Raspberry Pi - Take screenshots of Minecraft

If you going to take a screenshot of Minecraft: Pi edition (or anything else for that matter), I really like a command line utility called raspi2png, its simple and screenshots images which have been created using the GPU (like games) as well.


Download
Open a terminal and clone the repository from github:
cd ~
git clone https://github.com/AndrewFromMelbourne/raspi2png

Use
Change directory to raspi2png and run the program's help to show all the options:
cd ~/raspi2png
./raspi2png --help
Usage: raspi2png [--pngname name] [--width ] [--height ] [--compression ] 
[--delay ] [--display ] [--stdout] [--help]

    --pngname,-p - name of png file to create (default is snapshot.png)
    --height,-h - image height (default is screen height)
    --width,-w - image width (default is screen width)
    --compression,-c - PNG compression level (0 - 9)
    --delay,-d - delay in seconds (default 0)
    --display,-D - Raspberry Pi display number (default 0)
    --stdout,-s - write file to stdout
    --help,-H - print this usage information

To take screenshot you have to use the -p option and pass an image filename:
./raspi2png -p myscreenshot.png
Another really useful option is -d to delay when to take the picture, this enables you to get the screen ready for a shot - to take a picture delayed by 10 seconds:
./raspi2png -p mydelayedshot.png -d 10
The image files will be created in the ~/raspi2png directory - if you want them in a different directory use a full path:
./raspi2png -p /home/pi/mydir/myscreenshot.png
If you use a filename which already exists raspi2png will overwrite the file without warning and the old image will be lost.

Fyi - I wrote this blog post using a Raspberry Pi 3...  First time I've used a Pi to write about a Pi - thats progress!

Friday, 25 March 2016

Microbit - get data from USB

As part of my Minecraft, a Microbit and an X-Wing project, I used the USB to read data from the Microbit's accelerometer and buttons to make the X-Wing move.

@NCSComputing on twitter has started re-using the code to make other things happen, so thought it would be a good idea to write up how it works, so others can do the same.


To make this work you need one program which runs on the Microbit and prints data and a second runs on your computer (a Raspberry Pi, PC, Mac, anything with a USB port) which reads the data via a serial connection.


See github.com/martinohanlon/microbit-serial for the code for both of these programs.

The Microbit
The microbitreaddata.py python program runs on the Microbit, gets the data and prints it to the output, which in this case is the USB serial connection, and should be flashed to your computer using the Python editor:
from microbit import *

REFRESH = 500

def get_data():
    x, y, z = accelerometer.get_x(), accelerometer.get_y(), accelerometer.get_z()
    a, b = button_a.was_pressed(), button_b.was_pressed()
    print(x, y, z, a, b)

def run():
 while True:
  sleep(REFRESH)
  get_data()

display.show('M')
run()

Your Computer
The clientreaddata.py python program runs on the computer and reads the data using pyserial:
import serial

#the port will depend on your computer
#for a raspberry pi it will probably be /dev/ttyACM0
#PORT = "/dev/ttyACM0"
#for windows it will be COM(something)
PORT = "COM3"

BAUD = 115200

s = serial.Serial(PORT)
s.baudrate = BAUD
s.parity   = serial.PARITY_NONE
s.databits = serial.EIGHTBITS
s.stopbits = serial.STOPBITS_ONE

try:
    while True:
        #read a line from the microbit, decode it and
        # strip the whitespace at the end
        data = s.readline().rstrip()

        #split the accelerometer data into x, y, z
        data_s = data.split(" ")
        x, y, z = data_s[0], data_s[1], data_s[2]
        a, b = data_s[3], data_s[4]
        print(x,y,z)
        print(a,b)

finally:
    s.close()
The values of the accelerometer will be put into the variables x, y, z and the buttons in a & b.

Setting the PORT
You will have to change the PORT variable in the clientreaddata.py program to the comm port that the Microbit is connected to on your computer.

For a Raspberry Pi it is probably "/dev/ttyACM0", in the event it isn't, unplug the Microbit and run:
ls /dev/tty*

Then plug the Microbit and run the command again, the new device which appears will be the port of your Microbit.

For Windows it will be "COM#", the # being a number, the easiest way is to look in Device Manager for the "mBed Serial Port (COM#)"


Raspberry Pi gpiozero holdable button

The current release of gpiozero doesn't have the support to hold a button down e.g. when a button is pressed and then held down for 1 second something happens.

This is really useful when building hardware projects and you want 1 button to do 2 things, say turn something on when pressed, and turn off when held down.

I needed this for a project so I thought I would create a new HoldableButton class using gpiozero. Hopefully this will be incorporated into gpiozero, but until then you can use the class below.

The code is also available here as a gist.

You will need to add the HoldableButton class to your Python program:
from gpiozero import Button
from threading import Timer

class HoldableButton(Button):
    def __init__(self, pin=None, pull_up=True, bounce_time=None, 
                 hold_time=1, repeat=False): 

        super(HoldableButton, self).__init__(pin, pull_up, bounce_time)

        # Set Button when_pressed and when_released to call local functions
        # cant use super() as it doesn't support setters
        Button.when_pressed.fset(self, self._when_button_pressed)
        Button.when_released.fset(self, self._when_button_released)

        self._when_held = None
        self._when_pressed = None
        self._when_released = None
        self._is_held = False

        self.hold_time = hold_time
        self.repeat = repeat
        self._held_timer = None

    #override button when_pressed and when_released
    @property
    def when_pressed(self):
        return self._when_pressed

    @when_pressed.setter
    def when_pressed(self, value):
        self._when_pressed = value

    @property
    def when_released(self):
        return self._when_released

    @when_released.setter
    def when_released(self, value):
        self._when_released = value

    @property
    def when_held(self):
        return self._when_held

    @when_held.setter
    def when_held(self, value):
        self._when_held = value

    @property
    def is_held(self):
        return self._is_held

    def _when_button_pressed(self):
        self._start_hold()
        if self._when_pressed != None:
            self._when_pressed()

    def _when_button_released(self):
        self._is_held = False
        self._stop_hold()
        if self._when_released != None:
            self.when_released()

    def _start_hold(self):
        self._held_timer = Timer(self.hold_time, self._button_held)
        self._held_timer.start()

    def _stop_hold(self):
        if self._held_timer != None:
            self._held_timer.cancel()

    def _button_held(self):
        self._is_held = True
        if self._when_held != None:
            if self.repeat and self.is_pressed:
                self._start_hold()
            self._when_held()
Using the HoldableButton class is pretty simple, similar to the gpiozero Button class and can be swapped for the Button class with no other changes.
holdbutton = HoldableButton(pin, hold_time = 1, repeat = False)
You have to pass a pin number and optional hold_time and repeat values:
  • hold_time - is the number of seconds after the button is pressed before the button is consider 'held'
  • repeat - is a boolean and if set to True will occur 'button held' events to be repeated after each hold_time
You can use all the same methods and properties of the Button class, when_pressed, when_released, is_pressed, etc.

There are 2 additional properties is_held, which will return a boolean stating whether the button has been held down for the 'hold_time' and when_held which when assigned a function will cause the function to be called when the button is held down.
def myheldfunction():
    print("button held")

holdbutton.when_held = myheldfunction
Now when a button is held down, the function will be called and "button held" printed.

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) or what hardware 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>%ROM%</command>
    <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 &