Friday, January 29, 2016

Zero Ball - a game using Raspberry Pi, GPIO Zero some LDRs and very little building skills

Update: 3rd March 2017.  I resurrected ZeroBall today in preparation for Guildford Innovate on Saturday and did a video.

Trivia: Previously ZeroBall ran from a Raspberry Pi A+.  With the new PiZero W I thought it would be perfect to pair with the NexDock.  The NexDock has Bluetooth keyboard and trackpad and the PiZero W now has Bluetooth, so can be paired to the keyboard easily.  Making a nice compact solution.

On with the actual blog post.

For the recent Egham Raspberry Jam that I organised the theme was Gamification.
I already posted about sensecave a Raspberry Pi Sense Hat game  but I wanted to do something a bit more physical and real world.

That got me thinking about Fairgrounds and the kinds of games you play there.
The final decision was a ball throwing game.  Get the ball in the cups and you get points.  For those who watch US teen movies the principle is similar to beer pong, but without the beer and with points and scores....

Next exercise was to figure out how to detect a ping pong ball going into a cup.
I spent a lovely afternoon trying out PIR (Passive Infrared Sensor) sensors at  HackWimbledon. If you're near Wimbledon in the UK check them out. Great bunch of people and the events are every 2 weeks on a Saturday.

After an enjoyable day I figured out the PIR sensors are great for detecting movement of animals including people, but no use for my requirement as they even  tripped if the ball passed over the cup since the amount of infra-red light changed.  Tweeted when it failed. Luckily there was still a month to the Jam.

I now have six PIR that I can use for a different project. ;-)

With PIR out of the question the alternatives I considered were a switch or an LDR (Light Dependent Resistor) .  Both had their advantages and disadvantages.
Switch digital and easy to read and wire up, but most switches would need more force than a ping pong ball would provide.
LDR would give a great reading but is an analogue device which the Raspberry Pi cannot handled without additional circuitry

In the end despite needing extra circuitry I went with the LDR.
To get a reading from an LDR you have to create a voltage divider circuit so you can get a different voltage depending on the relative resistance values of the 2 resistors used.

Here's a great guide on voltage dividers and using an LDR

The next thing was to get the analogue reading from the voltage divider into a the Raspberry Pi in a format that it could use.  My initial thoughts were to use the analog inputs on an Arduino and then send the data over serial to the Raspberry Pi.  Considered Arduino as I have used them a bunch and knew what to do, but in the end I decided this would be over kill.  Why use a microcontroller to read analogue when there is a nice little chip that can do the same and people way smarter than me have already got it working with the Raspberry Pi.

May I introduce you to the MCP3008. An 8 channel, 10 bit analog to digital converter which communicates with the host over SPI.

Since SPI and the MCP3008 were all new to me I did the Google and found an great article by Raspberry Pi Spy. This guide explains exactly how to wire up the MCP3008/Pi and also RPI.GPIO code.
Using this I tested the LDR and it worked perfectly.  Looks like all systems are go on the project.

Then I saw that gpiozero has built in support for the MCP3008 and decided for the final project to take advantage of the ease of use brought by gpiozero.
A little test and it all worked again.  :-)

So, electronically everything works.  I can use voltage dividers with an LDR and resistor along with an MCP3008 to read the sensors and then using gpiozero read the values over SPI.

So, I began construction.

Firstly, soldering the Raspberry side headers from the MCP3008 on a strip board.

When I did this I made a mistake.  I should have left more room on the Pi wiring side of the MCP3008.  There is no need for the chip to be this close to the edge, with only one hole for the wire to be attached.  This will come back and cause me problems later...

Once this was done I moved on to creating the voltage dividers.  Since there are 6 cups, 6 resistors and LDRs are needed.

In the picture above the left side is VCC (3V3 from the Raspberry Pi), right side is GND.  Each 10k Ohm resistor is soldered to VCC on the left and then to one of the MCP3008 input pins.  The LDRs will then be connected from the MCP3008 input pin to GND to create the divider.

I did a quick test using one LDR to make sure I did this right. Image below shows it wired to the Raspberry Pi.  I used a model A+ as there isn't a requirement for network or more power. Yes, I wired it all up to power and stuff for testing.

After this the need was to add the wiring for the LDRs.  That's 6 connections with 2 wires for each.

This is already starting to look a bit more complicated than the small breadboard projects I've done before.  Looking at the image above you will see 6 black wires from the top edge (GND) and 6 orange wires tied to each MCP3008 input line.

All that was missing for the voltage dividers to be complete was to add the LDR for each line.

Since this is a physical build the LDRs need to be embedded in a plastic cup.  I also needed the LDRs to be flat against the cup to make it register a passing ball without obstructing the path of the ball.

This is the first time the sensor is actually in a cup so I can check if the ping pong ball passing is detected  correctly for the purpose. More testing of a single cup.

It worked and it worked amazing well.  That's 1 cup wired up.  Now just the other 5.

All wired up.  A bit fiddly  keeping the other cups out of the way while soldering and working with all wires the same colours to make sure I wired the correct ones for each LDR.

I had great fun at this time setting the cups up and throwing balls into them.  My kids loved it too. The fact they wanted to keep doing it even when all that happened was the number on a terminal screen updated when it happened made me think the build would actually result in a compelling game.

With the electronics sorted it was onto the bit that was new to me. The physical build.  I heard foam board was easy to work with and sturdy so went with that. Another new thing for me.

I cut holes in the foam board and inserted the cups. Using tape to hold them in place.

top, pretty side
bottom, business side.

As I mentioned the physical build is not something I do regularly, so I didn't have a lot of tools to hand to finesse the build.  My main tools were a sharp knife, glue and tape.

Once built I again did some testing and it all worked.

The top is sloped, so the balls roll back to the player. A layer is underneath, again to have the balls roll back to the player.

In the picture below you can I see a piece on the top to direct the ping pong balls to the bottom right so the returned balls will always be in the same place.  For the layer underneath the same happens. Balls return to the bottom right.

Last requirement of course was the software. I mentioned it used gpiozero for the MCP3008.  For SPI to work you have to run your code as root using sudo.
I wanted the game to feel like a fairground, so music and sound effects were essential as well as a score board.   All coded in Python.  To make this easy (for me) I used Pygame for the display, keyboard input to start a new game and also to play the background music and sound effects when a ball goes in a cup.  If you haven't used Pygame on the Raspberry Pi before then check out their recently released Make Games with Python Essentials book that is available in print, PDF, iOS and Android app.

Electronics sorted, physical build done, programming all completed.  Ready for the Egham Raspberry Jam on the 17th of January. 
As I was packing the night before I thought it best to test my projects as usually for me something goes wrong on the day and since I had the time (rare for me) doing some testing seemed like a good idea.  Ahhhh!!!!.  It didn't work.  I was checking the code and the terminal output.  No readings from any of the sensors. 
On looking at the circuit board a couple of the wires had broken off.  Remember I mentioned my thing about not leaving enough space on the Raspberry Pi side of the stripboard.  

I again went to Twitter an got some some great advise from Alan O'Donohoe and Pete Lomas

You have to love the Raspberry Pi Community. Within a few hours I had exactly the advise I needed to get my project fixed perfectly.  But I had 1 day left and didn't leave enough room to do what they advised so I ignore their advice this time. Soldered the wires back on and crossed my fingers that it would all hold together.

On the day of the Jam the game was very popular.  Great write up from Richard Savill who is well worth following as he does some great Raspberry Pi projects and Kickstarters. With lots of kids and adults playing with it.  When a few kids gathered around the game they would just drop the ball straight in the cups to get the points and hear the sound effects.

Overall, I'm very happy with the final game.  The build is a bit rough around the edges but works great.  The code held up and the kids played it all afternoon which was the desired outcome.   I also had a number of conversations with adults and kids about the code and the electronics involved, so hopefully helped a few of them to learn something new and consider their own Raspberry Pi projects.

Sunday, January 17, 2016

Raspberry Pi SenseHat Game - sensecave

For Christmas I received a lovely Sense HAT from my in-laws. I gave my wife a list of items I would like to have and the Sense HAT was one of them.

The Sense HAT is a great little accessory for the Raspberry Pi.  It includes an 8x8 RGB LED matrix, a joystick and a great range of sensors
Barometric pressure

With the Sense HAT I gave myself the goal of creating a game and also learning a bit about git/GitHub.  Up until now I have never used git for my projects and just pasted code into the blog posts (if I remembered) otherwise the code is gone forever.

To that here is the link the GitHub page:

Thinking on the game I wanted it to be a bit more than an single 8x8 and be a decent challenge.
I was reminded of the old school text cave exploring games where you went from one room to another and decided I liked this idea.

The game is sensecave.
64 rooms in an 8x8 arrangement.  Not because the screen is 8x8, just because it looks like a decent size to play. To make things more interesting instead of all rooms being connected up to 10 entrance/exits are blocked off at random each time you play giving different paths through the maze.

With the cave and the rooms sorted there has to be a quest.
The quest is to find the 7 emeralds hidden in the cave and then get out of the cave.
Just like the walls the 7 emeralds are randomly scattered around the cave making the game different every time.

We now have a location, a challenge and a quest.
Finally we needed a control method.  For the Sense Hat there are two options. Either the small joystick that emulates the cursor keys, with the push button being RETURN or the gyroscope. Realistically there was only one choice it had to be the gyroscope.
Meaning you navigate from room to room and within a room by tilting you Raspberry Pi/Sense Hat.

I love this way of navigating as once you pick up the Pi and the players dot moves the control method is completely intuitive.

In the image below you can see one of the rooms in the cave.
Red dots are the wall with, in this instance exits on all sides.
Green dot is one of the emerald
Blue dot is you.

Each time you find an emerald the screen changes to tell you how many you have found.
After all 7 have been found you're directed to go the exit.  The exit is a white dot.

Once you have exited there is a nice congratulations message and a new maze if created to start all over again.

Some of the fun challenges in programming this game were.
The list for the individual cells/rooms is y,x while the co-ordinates for the players position on the is x,y (as it should be).  This required some mental gymnastics to remember which type I was modifying to get the right result.  A few events were less than productive because of this.

I wanted to store the details for each room in a single number, so I used bitwise data

For the rooms if a side is blocked off then the number included:

top = 128
right = 64
bottom = 32
left = 16

Meaning a room with all exists blocked would equal 240.
If the top and bottom exists were blocked the room would equal 192
Then using Boolean logic the code figured out where the wall were to go.

A diamond = 1, again a room with a diamond had 1 added to it's value.
Diamonds are always drawn in the same place in a room, so that was straightforward.

Finally the exist is always in the bottom right corner and if that room is the current one a white dot is place in the room.

Finally as it can even with 8x8 get a bit disorientating a dot is added to the corners of the corner rooms.  So, you'll know when you've hit a corner and not look for the route to get to the rooms beyond.

One of the goals for this game was to run it headless and the code I found before the Egham Jam on the 17th Jan 2016 used Pygame to access the joystick.  Unfortunately, I could not get Pygame to read the joystick (which is really a keyboard) if no display was attached.  Pygame used SDL and from my reading this expects a display to enable inputs.  So, for now the joystick is not used.  I did see an alternative method for reading the joystick not using Pygame and this will be the next stage...
I really want to add difficulty levels, variable maze sizes and also variable number of emeralds.
This could be a good way for someone the extend the code.

Here's a short video.  Not the best as the lighting was too bright.  It shows the player being controlled by tilting and going from room to room.  When I work out how to do a better video I will update.

Special thanks to the Foundation and specifically Dan Fisher for this game/tutorial that I used to understand how to read the gyroscope and also how to get pixles onto the Sense HAT