Not Your Ordinary Hello World Tutorial
I don't know about you, but as I've been teaching myself how to program, I keep coming across the same types of tutorials in every language: 'Hello World' and 'How to Make an Address Book'. While these are both great for learning the fundamentals, I don't enjoy arbitrary projects, even if it is teaching me.
When I got my Raspberry Pi 2 last year, I decided I was going to learn Python with it and I certainly wasn't going to just do 'Hello World' tutorials. The result of my project is a game that takes user input from buttons on my breadboard using the GPIO pins. In this tutorial, we will recreate this game and try to learn what exactly we are doing with each line of code, instead of just copying and pasting and playing a simple game in the end.
Let's get started.
I'm doing this all on a Raspberry Pi 2 running Raspbian Jessie. The Pi is connected to my local network via ethernet cable (if you have the WIFI adapter, that'll work just as well) and I am ssh'd into it from my MacBook Pro. You can do this all locally on the Pi if you have it connected to a monitor, keyboard and mouse.
The Breakout Board
Let's get our breakout board all set up. If you don't know, the board goes top to bottom the long way. Each horizontal row is the same connection, so anything next to one another horizontally, will have power at the same time.
I've included an image of my actual breakout board and a digital rendition of the general idea. The digital design was made in Fritzing software. It is not a perfect rendition as it did not offer the option to include the cobbler, but it gets the point across.
The LED's are connected as follows. Red is connected positive to pin 27 and negative to 3V negative through a 220 Ω (Red, Red, Brown, Gold color code) resistor. Be sure you use a resistor or you'll likely blow out your LED. Green is connected positive to pin 22 and negative to 3V negative through a 220 Ω resistor. The top button is connected positive to 17 and negative to ground. The bottom button is connected positive to 18 and negative to ground.
The Code: Big Picture
Let's start by talking about what our end goal is. When the game is started, it will show a paragraph on the terminal screen telling the story of coming across a time bomb. As the only person around, it falls to the player to decide if they should cut the red wire or the blue wire (in this case the wires are the buttons on the breakout board). When the user pushes a button, it flashes either a red or green light and a congratulations or failure message on the screen.
In order to make this game truly random, we use a random number generator and some basic math in order to determine which button is the correct one and which one will result in the death of many innocent bystanders.
The Code: Imports
OK, let's get to the fun stuff.
First we need to import the frameworks we will use in this game: random, time and gpio.
I always include comments to make sure that when I go back later (or if anyone ever sees this), I remember what each block does.
In order to limit the size and computing requirements, we only import the randint portion of the random framework. This isn't that big of a deal in a program as small as this one will be, but a good practice to get into.
To make interaction with the GPIO framework easier, we import it as GPIO. GPIO is now a variable that prevents us from writing RPi.GPIO every time; you could change the variable name to anything you want.
We need to have a few seconds where we delay or wait during this game, so we import time.
The Code: GPIO Setup
Now we have to tell the Pi what pins we will be using for this project. Remember, for this project we are not connecting direct to the components, but are mapping it through a breakout board by a CanaKit 40-pin T-shaped cobbler.
First off, we disable the GPIO warnings. The code will work without this line, but you'll get a warning every time you run it, so it's best just to ignore it.
Now we have to tell the code that we are mapping it to the breakout board. I'll be honest, I don't fully understand this part, I just no we need to include this line of code to help our numbers line up.
The last 4 lines all do the same thing, they tell the Pi what pins we are using and what time of device is on the other end of the pin's circuit: input or output.
The Code: Game Function
Now we get to create a function. Let's talk about functions for a minute. Functions take a lot of instructions and turn them into a single 'variable' (not the right terminology, but go with me on this) that you can call later. In this case, we tell the program what the game is, but we don't let it run until we are ready for it. This also allows us to stop the game or add extra functionality if we want to later.
As this function is really long, I'm going to break the code segments out into shorter segments. Remember is all part of the game function. I'll include the full function code as well as the full program code later. But I don't want to overwhelm anyone with a bunch of code all at once.
First we define our function and give it a name. I chose to be really creative here and name it game.
Now we choose a number. Because we used randint, the number will be an integer (that means no decimals for those of you who hate math) and in the parenthesis, we pass 0, 9 as the arguments. In this case, that makes the range of integers 0-9. Realistically, we could do (1, 2) and limit the integer to 1 or 2, but we're doing this to increase our learning so let's go with 0-9.
Now we have to get it down to a 50/50 option. I chose to do this by determining if the number was even or odd. To do this we use a function called modulo, represented by %. Again, for you non-math folks, modulo returns the remainder of a division problem so 27 / 5 = 5 remainder 3 and 27 % 5 = 3. This can determine odd or even because we know that if any even number divided by 2 has no remainder, therefore any even number modulo 2 is 0.
In this case x is our random integer, so we'll make y our equation to determine odd or even. So y is x % 2, meaning the only possible results y could yield are 0 or 1. Now we have our 50/50 option.
Every good game needs a story. Here we just output the story through plain text to the terminal window. Then we wait 1 second and then tell the user to choose wisely.
Now the code for the buttons. Keep in mind that when a button is pushed it returns false. When not pushed, it is true. To me it seems a little backwards, but it was designed by someone smarter than me.
This game will run in a while loop that says while one of the buttons are un-pushed, the Pi will continue to wait for input.
To make the code easier, I've declared each GPIO button input as an english named variable so it don't have to remember which number is which. The variables 'topbutton' and 'bottombutton' correspond to their location on the breakout board.
Now we use an if/elif statement. I've broken it out between 2 segments here to make it easier to read. The top button will win if the user pushes it and the random number from earlier is odd. If they push the top button and the number is even, they lose. So we say if the user touches the top button, then we check if y is equal to 0 (random number was even) then it prints out the losing message and turns on the red light. Otherwise (so y is 1 or random number was odd) it displays the winning message and turns on the green light.
This is the first time we've used the GPIO.output feature. In the case of LED's, we either output HIGH for on or LOW for off. Since we set up GPIO as a variable earlier, we can just say GPIO.output(pin number, HIGH or LOW) to turn the light on or off.
The time.sleep(.3) stops the computer from filling your screen with thousands of victory or failure messages. It gives you enough time to get your finger off the button.
Now we do the same calculation, except for the bottom button. This section is ignored if the top button is pushed and the previous section is ignored if the bottom button is pressed. That's the beauty of if statements.
Notice we are using an elif statement instead of just and else. Else would accept any input except pushing the top button, so it would run if nothing was pushed. We however want it to only run if we have pushed one button or the other, thus we use elif.
After the calculations to determine if the player won or lost and the .3 second wait time, the Pi will shut off both LED's. There should only be 1 LED on, either red or green depending on if the game is won or lost, but it doesn't hurt to shut off one that is already off, the Pi will make no change. This just guarantees a light isn't left on after the game is done.
Remember I said this was a loop that ran as long as at least 1 button was not pushed? Well when you push both buttons, that will exit the loop and end the program. Here we print to the terminal window that the game is closing. The return command actually ends the program.
The Full Game Function
The Code: Call the Function
Now that the function is finally written, we can call it and play the game. There are no arguments needed for this function. We just call it so that the Pi knows it is time to play.
The Whole Code
Below I've included a video that shows both the Terminal screen and the LED's and buttons. There is one extra feature on this that is not covered in our tutorial. There is a blinking light that is a countdown limiting the time that the player has to make a choice. At some point, I may make a tutorial on how to add this feature, but as it is not working perfectly yet, I'm just going to leave that part out for now.
This article is accurate and true to the best of the author’s knowledge. Content is for informational or entertainment purposes only and does not substitute for personal counsel or professional advice in business, financial, legal, or technical matters.
eembee on September 19, 2018:
Even if it was created for Jessie, the tutorial still works well. I just wanted to say how useful and fun it is. I referred someone here again last week, and they loved it. Thanks again Colton!