Chapter 5

The Sauce Bottle Game

In This Chapter

arrow Making a sauce bottle simulator

arrow Reading a digital input

arrow Creating realistic graphics

arrow Understanding the beginnings of the Pygame framework

The project in this chapter is just about the most fun you can have with a single contact input. Whether you call it catsup, ketchup, or sauce, it’s a thixotropic fluid, which means it changes its viscosity (runniness) according to the agitation of the fluid.

The Game

The game is simply an interactive sauce bottle where shaking can be sensed by the Raspberry Pi. This is mirrored on the screen by a graphic of the same bottle. However, on the screen, the sauce bottle can be seen to slowly empty in response to the shaking. The idea is to get the bottle emptied in the shortest possible time.

This game is a great introduction to the interaction of hardware and software. Figure 5-1 shows the hardware bottle next to a monitor showing the graphic bottle.

image

Figure 5-1: The finished game.

Parts

The parts you need for this project are simple, and you can substitute a wide variety of objects if you don’t have exactly the same parts we use. Here are the parts you need:

  • Plastic sauce bottle: We used a Heinz Tomato Ketchup bottle, but you could use another similar plastic bottle.
  • 6½ feet (2 meters) of twin core cable: We used microphone shielded cable.
  • Tilt switch: The tilt switch consists of a metal ball in a small tube. When the ball rolls down one end, it shorts out the two wires leading into it.
  • 2 single-pin header sockets: You can use any method of connecting to the general-purpose input/output (GPIO) pins.
  • Hot melt glue: You’ll need a hot melt glue gun to apply this.
  • Silicon sealant

Schematic

The schematic of this circuit (shown in Figure 5-2) is almost trivial, so it’s easy to follow.

image

Figure 5-2: The sauce bottle schematic.

remember Always make a schematic whenever you make anything electronic, so you have something to check your construction against.

tip It doesn’t matter which way around you wire the connections on the switch. They just connect and disconnect the GPIO pin 2 to ground. This pin is normally used for the I2C interface. On the board, it’s connected to a resistor connected to the 3V3 supply. This is known as a pull-up resistor. It ensures that the logic level on this pin is normally a logic 1, unless the pin is connected to ground, in which case it becomes a logic 0.

Construction

To build this project, follow these steps:

  1. Drill a hole in the top of the bottle for the wire to go in.

    Our wire was 1.5mm in diameter so we drilled a 2mm hole.

  2. Push the wire through the hole into the bottle.

    This step is critical. Pushing in the wire from the outside of the bottle is easy. Pushing the wire through the hole from the inside of the bottle is impossible.

  3. With silicon sealant, glue the tilt switch onto the small flexible membrane on the bottle lid, which normally holds back the sauce.

    Allow the sealant to set.

  4. After the sealant sets, wire the screened cable to the tilt switch, as shown in Figure 5-3 .

    tip If you haven’t used screened cable before, just know that you need to strip off the outer insulation and twist the screen wires together between your fingers. Then tin them by applying a touch of solder, and watch it soak in between the wires. Then trim off the screen a bit to make it tidy. Now strip the inner insulation off the core, twist the wires together, and tin them again. Then make the soldered joints with the switch.

  5. Apply some hot glue over the tilt switch and run it around the base of the cap.

    warning Don’t overfill it or you’ll never get the screw bottle back on the cap.

  6. Screw the cap back onto the bottle and then put a blob of hot glue where the cable comes out of the bottle to fix it.

    Make sure you leave enough slack in the bottle to remove the cap if any repairs are needed.

  7. Attach the other end of the cable to your Raspberry Pi.

    You can do this in a variety of different ways with various breakout boards. Because there are only two wires, we used two single-pin sockets and shells and connected them directly to the GPIO connector, as shown in Figure 5-4. We soldered the end of the cables to these two wires and covered the joint with some heat-shrink cable, but you can use insulating tape if you prefer. Then we carefully placed them on the GPIO connectors before booting up the Raspberry Pi.

    remember As a rule, you should never connect anything to your Raspberry Pi while it’s powered up.

image

Figure 5-3: Wiring the screened cable to the tilt switch.

image

Figure 5-4: Connection to the GPIO pins.

Testing

After you’ve assembled your project, it’s time to test the switch. In order to access the GPIO pins, you need a special library. There are a few of these around, but one of our favorites is WiringPi, by Gordon Henderson. There is a Python front end, and it’s easy to install.

From the desktop open up a command-line prompt, and type the following:

sudo apt-get install python-dev python-pip
sudo pip install wiringpi2

That should be it. You can test that it’s installed correctly by typing the following:

sudo python
import wiringpi2
wiringpi2.piBoardRev()

You should see the revision number of your board. However, notice that you have to use the sudo command to access things as the root user. You can still program in the IDLE environment by opening it up and typing the following from a command-line prompt:

gksudo idle

Then everything you do is as a root user. Get into IDLE like this, open up a new window from the file menu and then type the program in Listing 5-1.

Listing 5-1: Switch Test

#!/ #!/usr/bin/env python
"""
Sauce bottle switch test
"""
import wiringpi2 as io

print "if program quits here start IDLE with 'gksudo idle' from command line"
io.wiringPiSetup()
io.pinMode(8,0) # Physical Pin P1,3 GPIO 2
print "Pin test - Ctrl C to quit"
lastPin = 0
while True :
     pin = io.digitalRead(8)
     if pin != lastPin:
         print "Pin now ", pin
           lastPin = pin

This is a very simple program and shows the basis of reading a GPIO pin. It starts off by importing an instance of the wiringpi2 library. Then there is a little warning about being a root user. (If the program crashes on the next instruction, it shows that you aren’t the root user.) Then the io.wiringPiSetup() function is called, which initializes the library. This sets up the pins to use some pin mapping that automatically takes care of the swapping about of pins on this header, which has occurred in the different editions of the board.

Here, GPIO 2 (or GPIO 0 on a Raspberry Pi 1 board) is on connector P1 on pin 3, but it’s referred to as pin 8 in the software. It may sound complex, but the point is that pin 8 will access the same pin on the GPIO connector no matter what board revision of the Raspberry Pi you have.

Then the io.pinMode(8,0) call makes this pin an input and finally io.digitalRead(8) returns the logic value on this pin. A variable called lastPin holds the previous value on the pin and prevents it from being printed out if it hasn’t changed. Run the code and see how the pin state changes with the tilt of the switch. If you don’t see any changes, check the wiring and chase down your fault.

The Software

What makes this project really exciting is the combination of good graphics and hardware. In the early days of computers, you had to write code for every line and pixel displayed, but today you can work wonders with digital photographs and image manipulation packages.

In this section, we describe how you can make your own graphics — but there is no need to do this if you don’t want to. You can simply download our graphics from the book’s companion website (www.dummies.com/go/raspberrypiprojects) if you want to copy exactly what we have.

The idea is that there is a picture of the empty sauce bottle and the software fills it with sauce and then slowly empties it according to how you shake the bottle. You do this by drawing a rectangle of translucent sauce over the bottle and then removing or masking out areas where the sauce should not go. Finally, the label and cap of the bottle are layered over the top to give the illusion that the sauce is actually inside the bottle.

Preparing the graphics

If you want to go it alone and make your own graphics to match your bottle, you have to do a bit of playing about with a graphics application, like Adobe Photoshop (on your desktop or laptop computer) or Gimp (on the Raspberry Pi).

Here are the steps to preparing the graphics yourself:

  1. Using the best digital camera you have access to, take a photograph of your bottle against a white background.

    Make sure the bottle is at an angle of about 60 degrees.

  2. Save the picture as a high-resolution PNG file.

    Many cameras create JPGs, so you may have to export the image from your camera and import it onto your computer and then save the image as a PNG using an application like Photoshop.

    technicalstuff All images in the following steps should be saved as PNGs because the JPG image format does not support transparent masks. Also, working at high resolution means any mistakes are minimized when you reduce the picture size later.

  3. Remove any background surrounding the image and replace it with a uniform flat gray.
  4. Save this image as your base image and call it Bottle.png.
  5. Make a copy of Bottle.png, and select the gray background.
  6. Invert the selection and make the selection transparent.
  7. Save the image and call it Mask.png.
  8. Make another copy of Bottle.png and paint the same color gray as the background for all of the bottle except the label and the cap.
  9. Select the gray area and make it transparent.
  10. Save the resulting image as Label.png.
  11. Make copies of Bottle.png, Label.png, and Mask.png and place them in another folder called Graphics.
  12. Reduce the image size of all three of the images in the Graphics folder so that all three pictures are exactly 500 pixels wide.
  13. Copy the Graphics folder to the folder you want to have the game in on the Raspberry Pi.

The trick is to layer these three images along with a rectangle of sauce to build up the image of the half-full sauce bottle, as shown in Figure 5-5.

image

Figure 5-5: Building up the bottle image.

You start with the picture Bottle.png, which is the first to be drawn. Then a rectangle of semitransparent sauce is drawn; the height of this rectangle corresponds to how full the bottle is. This rectangle will cover areas outside the bottle image, so in order to remove this, Mask.png is drawn on top of it. This mask has a transparent area in the shape of the bottle, so it removes any sauce outside this area. Finally, Label.png is drawn so it looks like it isn’t being covered by the sauce, which gives the impression that the sauce is inside the bottle. Drawing the sauce as a semitransparent color also adds to this illusion because things like the light reflections off the bottle can still be partly seen through the sauce on the bottom layer, and they’re fully seen when the sauce retreats from those reflections. This gives the strong illusion that the sauce is in the bottle.

The rules

The game itself is simple: The bottle starts off full of sauce, and on each shake, a certain amount of sauce is removed and the picture is redrawn. When the bottle is empty, that round of the game is over, and the time it took to empty the bottle is displayed, with a record being kept of the fastest score. There is one more feature that, although it sounds simple, does add quite a bit of code: the game reset, which is triggered by pressing the spacebar. The game reset abandons any current run and refills the bottle.

The game uses the Pygame framework, which allows for easy handling of the keyboard, pictures, and windows. It’s included in the standard Raspberry Pi distribution. The code for the game is shown in Listing 5-2.

Listing 5-2: The Sauce Bottle Game

#!/usr/bin/env python
"""
Sauce bottle game by Mike Cook
"""
import time, pygame, os, sys
import wiringpi2 as io

print "if program quits here start IDLE with 'gksudo idle' from command line"
io.wiringPiSetup()
io.pinMode(8,0) # Physical Pin P1,3
pygame.init() # initialise graphics interface
os.environ['SDL_VIDEO_WINDOW_POS'] = 'center'
pygame.display.set_caption("The Sauce Bottle")
pygame.event.set_allowed(None)
pygame.event.set_allowed([pygame.KEYDOWN,pygame.QUIT,pygame.MOUSEBUTTONDOWN])

screenWidth = 500
screenHeight = 542
screen = pygame.display.set_mode([screenWidth,screenHeight],0,32)

sBottle = pygame.image.load("Graphics/Bottle.png").convert_alpha()
sLabel = pygame.image.load("Graphics/Label.png").convert_alpha()
sMask = pygame.image.load("Graphics/Mask.png").convert_alpha()

# define the colors to use
cBack =(60,60,60)
pygame.draw.rect(screen, cBack, (0,0,screenWidth, screenHeight),0)
cSauce = (166,30,0) # color of the sauce
returnKey = False ; restart = False

def main():
    global returnKey,restart
    print "Sauce bottle game by Mike Cook"
    full = 100.0 # percent the bottle is full
    highScore = 60.0 # Record time
    while True:
       drawScreen(full)
       print "shake when ready"
       start = time.time()
       while full > 0 :
       while io.digitalRead(8) == 0 and restart == False:
          checkForEvent()
       while io.digitalRead(8) !=0 and restart == False:
          checkForEvent()
       if restart == True :
          full = 0
          print "Reset"
       else :
          full = full - 5.0 #change this number for a faster / slower game
          if full < 0:
             full = 0
          drawScreen(full)
     drawScreen(full) # empty
     if restart == False:
        runTime = time.time() - start
        print"You took ",runTime," to empty the bottle"
        if runTime < highScore:
           print "A new record!"
           highScore = runTime
        print "The record is ",highScore
     else:
       drawScreen(100)
     print "return key for a new game"
     returnKey = False
     while returnKey == False :
        checkForEvent()
     returnKey = False
     restart = False
     full = 100.0

def drawScreen(p) : # draw to the screen
    screen.blit(sBottle,(0,0))
    sauce = pygame.Surface((425,p*4.53)) # maximum sauce
    sauce.set_alpha(170) # transparency of sauce
    sauce.fill(cSauce)
    screen.blit(sauce,(61,11+((100.0-p)*4.53)))
    screen.blit(sMask,(0,0))
    screen.blit(sLabel,(0,0))
    pygame.display.update()

def terminate(): # close down the program
    print ("Closing down please wait")
    pygame.quit() # close pygame
    sys.exit()

def checkForEvent(): # see if we need to quit
    global returnKey,restart
    event = pygame.event.poll()
    if event.type == pygame.QUIT :
       terminate()
    if event.type == pygame.KEYDOWN :
    if event.key == pygame.K_ESCAPE :
       terminate()
    if event.key == pygame.K_RETURN :
       returnKey = True
    if event.key == pygame.K_SPACE :
       restart = True
    if event.type == pygame.MOUSEBUTTONDOWN :
       print pygame.mouse.get_pos()


if __name__ == '__main__':
    main()

The best way to understand this is to look at the functions individually, starting with the last one, checkForEvent, which looks to see if anything has happened that the Pygame framework has picked up in the background. For example, a QUIT event can be the user clicking the close box of the window; if this occurs, the terminate function is called, shutting down everything. Next are the KEYDOWN events, which are picked up if a key is pressed. For example, the Escape key calls the same terminate function as the close box click. The other keys that are of interest simply set variables to indicate that they’ve been pressed. The way the code works is that this checkForEvent function should be called constantly, as often as possible. If you were in a loop and not calling it, then the program might have thought to have hung. The last event is just for debugging, but we’ve left it in in case you’re adding your own graphics. It simply prints out the x- and y-coordinates of where the mouse is clicked, which you need to know in order to align and size the sauce rectangle correctly.

The drawScreen function is where all the graphics magic happens, it draws the elements of bottle, sauce, mask, and label just as we describe in the preceding section. It takes in a variable, p, which is the percentage of how full the bottle is, and uses this variable to calculate the size of the sauce rectangle’s height. The width is fixed by the maximum extent of the visible area of the bottle. The transparency is set as a value of 170; this is where 255 is fully opaque. You may want to change this value and see how it looks. The rectangle is then drawn with the top representing the top level of the sauce.

tip Note that in Pygame’s windows, the (0,0) coordinate is at the top-left corner and the y value increases as you move down the window, which is the opposite of more conventional systems.

The lines at the start of the listing initialize various aspects of the program. It first sets up the hardware GPIO input. Then it sets up the Pygame system and defines the window size. The window size must match your photographs’ size. Next the photos are loaded in and the colors are defined. Again, this is an opportunity to change them if you like.

Finally, the main function actually plays the game. After setting initial variables and printing out the title, it enters an infinite loop with the while True: line. It then draws the picture of the bottle, prints out an invitation to start, and makes a note of the current time so it can calculate the time taken to empty the bottle. The code enters another loop, which repeats as long as the bottle is not full with the while full > 0: line. This loop waits for the input to be low and then to be high before removing a bit of the sauce. You can change the amount it removes per shake to make the game longer or shorter. When the bottle is empty, the run is over. The time taken is printed out and checked to see if it’s a new fastest score. You can press Return to start again.

Note that the feedback is given in the Python console window, but the game window must have the focus (be the top window) in order for the program to “see” any key presses.

Taking It Farther

You can do even more with this project if you like. Here are some examples:

  • You can add sound effects (maybe a squelch for each shake and a fanfare for finishing, with a special one for a new high score). Chapter 13 has a project that uses sound with Pygame so you can see how it’s done.
  • You can make it so that the timing begins on the first shake of the bottle.
  • You can add graphics of the sauce actually squirting out of the bottle.
  • You can make the game a two-player game where the players race each other. To do this, you need two bottles and a bigger window.
  • You can make the high score permanent by writing it to a file.
  • When you get more advanced with handling hardware, you may want to add some flashing red LEDs in the bottle that match the shaking.

What ever you do, there will be a whole lotta shakin’ goin’ on!

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.128.78.41