Update - I've taken Mayhem forward to create Mayhem 2.
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.
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.
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.
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
Note - if you are doing this on a PiGRRL 2 with a Pi 3, be sure to check out Christian's comments about the pin to use and wiring-pi install before starting.
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.
It was difficult because while you can note the time the data was captured, you don't know what the 'time' will be in the video because you get drift (e.g. if you specify 30 frames a second, it isn't always 'exactly' 30 frames a second, sometimes its more, sometimes its less, sometimes frames are dropped) and the longer the video the more 'drift'.
After investigating several ways of doing this I decided what I need was a way of 'asking' raspivid while it was running "where it was", that way I could tag that information alongside the data and use it to sync it to video later.
To do this I had to answer a number of questions:
What data in the video encoding process could I use? I settled on current frame number
How could I find the frame number? By modifying raspivid to 'count frames'
How could I count frames? By examining the contents of a 'buffer' before it was written to disk to see if it contained an end frame and if it did increment a count
How could I get the frame count out while it was running? By using a shared memory segment and semaphore
I have forked the raspberrypi/userland repository (which contains raspivid), https://github.com/martinohanlon/userland, the raspivid code is in /host_applications/linux/apps/raspicam/RaspiVid.c and all my changes are commented with the heading MaOH. View my custom raspivid code here.
I created a really simple demo, which recorded the screen and noted the frame number and key pressed before formatting it as a subtitle file which I then encoded to the movie file, to test the synchronisation. The quality is terrible but it does work.
Compile userland fork
Clone my userland fork
mkdir ~/code cd ~/code git clone git://github.com/martinohanlon/userland.git
See this post to on how to compile userland, if you want to keep the original raspivid software (probably a good idea!), dont run the command sudo make install.
My custom raspivid program will be compiled in the ~/code/userland/build/bin directory.
Using my custom raspivid
The custom version of raspivid I created works exactly the same as the original, but if the program is outputting the video to a file, it also outputs the frame count at run time to shared memory.
~/code/userland/build/bin/raspivid -o test.h264
Reading the frame count
To get the frame count while raspivid is running, you need to read the value from system V shared memory and to protect the value from corruption while reading it, you need to use a semaphore.
The process works like this:
Acquire the semaphore, which will stop raspivid updating it
Read the frame count from shared memory
Release the semaphore
In order to use the shared memory and semaphore you need the keys:
shared memory - 20130821
semaphore - 20130822
Any programming language which can read from shared memory and use semaphores should be able to do this. The frame count is written to the shared memory as a string to make it easier to consume, messing about with integer types can be bit painful.
Example Python code
The following code reads the frame count from shared memory 100 times, pausing for 0.5 seconds between each read. It used a great python module, sysv_ipc, which greatly simplifies the interaction with shared memory, see http://semanchuk.com/philip/sysv_ipc/ for more information, download and install instructions.
To install sysv_ipc:
sudo apt-get install python-dev wget http://semanchuk.com/philip/sysv_ipc/sysv_ipc-0.6.5.tar.gz tar -xf sysv_ipc-0.6.5.tar.gz cd sysv_ipc-0.6.5 sudo python setup.py install
Python code:
import sysv_ipc import time # Open shared memory object memory = sysv_ipc.SharedMemory(20130821) # Open semaphore semaphore = sysv_ipc.Semaphore(20130822) for count in range(0,100): print "acquiring semaphore" # Acquire the semaphore using a 2 second timeout semaphore.acquire(2) # Read value from shared memory frameCount = memory.read() # Release the semaphore semaphore.release() print "released semaphore" # Find the 'end' of the string and strip i = frameCount.find('\0') if i != -1: frameCount = frameCount[:i] print "value is " + frameCount # wait time.sleep(0.5)
Remember to run raspivid before running this code, otherwise you will be presented with an error saying the shared memory / semaphore doesn't exist.
I would welcome any improvements to this and would actively encourage you to download my code and "have a go".
I've been working on a few changes to the RaspiVid program which controls the raspberry pi camera board.
The first step was to get the code from github, https://github.com/raspberrypi/userland and compile it. The raspberry pi camera programs (RaspiVid and RaspiCam) are part of the 'userland' repository and as such I needed to compile the whole repository.
I had a problem whereby I needed to use a C program to capture video, in this case RaspiVid (the raspberry pi camera capture program), but I wanted to sync the video with data being capture by a Python program; in order to get the sync right I need to grab data about the video capture as it was running.
To do this I had to find a method of doing Inter Process Communication (IPC), very quickly, with a very low performance impact on the C program. I explored several IPC options between C and Python (stdin/stdout, named pipes, tcp, shared memory) and found that using Shared Memory was the only way to deliver the performance I needed.
I pulled together a quick proof of concept to learn the basics.
C - Writing to Shared Memory
I created a C program which writes data into a shared memory segment and then waits (to allow me time to run the python program to read it out). See http://www.cs.cf.ac.uk/Dave/C/node27.html for a description of how to use shared memory and this video http://www.youtube.com/watch?v=QPxcOwMmpnw for a tutorial.
shmwriter.c
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> int main(int argc, const char **argv) { int shmid; // give your shared memory an id, anything will do key_t key = 123456; char *shared_memory; // Setup shared memory, 11 is the size if ((shmid = shmget(key, 11, IPC_CREAT | 0666)) < 0) { printf("Error getting shared memory id"); exit(1); } // Attached shared memory if ((shared_memory = shmat(shmid, NULL, 0)) == (char *) -1) { printf("Error attaching shared memory id"); exit(1); } // copy "hello world" to shared memory memcpy(shared_memory, "Hello World", sizeof("Hello World")); // sleep so there is enough time to run the reader! sleep(10); // Detach and remove shared memory shmdt(shmid); shmctl(shmid, IPC_RMID, NULL); }
Compile using:
gcc -o shmwriter shmwriter.c
Python - Reading from Shared Memory
I found a great module for python, sysv_ipc, which greatly simplifies the interaction with shared memory, see http://semanchuk.com/philip/sysv_ipc/ for more information, download and install instructions.
shmreader.py
import sysv_ipc # Create shared memory object memory = sysv_ipc.SharedMemory(123456) # Read value from shared memory memory_value = memory.read() # Find the 'end' of the string and strip i = memory_value.find('\0') if i != -1: memory_value = memory_value[:i] print memory_value