Intro: Using an RPi to Control an RGB LED
As rahulkar mentioned in his tutorial, LED control seems to be the "Hello World" of electronics. It's easy to set up, you learn a lot about how electronics work, and in the end, you've got a nifty little piece of hardware to show off to your friends - and it's pretty cool!
This tutorial will be bare-basics, the idea being that you could use this tutorial as your first project in order to get a basic understanding of the Raspberry Pi, circuits, and programming. In particular, I will explain the code behind the program line-by-line for those of you who are new to Python. After this tutorial, you should have a grasp on how basic programs operate and be able to modify our code.
In this tutorial, we're going to be using an RGB LED. The R, G, and B stand for red, green, and blue, respectively, and the single RGB LED actually contains three LEDs within the single bulb. These are the primary colors for light; that is, you can theoretically create any color of light using some combination of these three. Mixing pure red with pure blue will result in magenta, blue and green in cyan, while red and green make yellow and all three make white. Different hues can be made by mixing different intensities of the three primary colors. In reality, we will find that honing in on a particular hue with the Pi will take a bit of finessing and might not always work.
Step 1: Introduction - RGB LED
Before we get started, some quick notes on circuits and how LEDs behave. When you buy an LED, you should see a bunch of writing on the back of the package showing technical specs. If you can't seem to locate any specs, try running a google search on the part's serial number. We are concerned with forward voltage (VF, measured in volts) and forward current (IF, measured in milliamps). Typical LEDs (that burn one color) will have one value for each of these variables. You may notice, however, that different color LEDs have different values. In particular, red seems to drop the lowest forward voltage while blue drops the highest. Likewise, your RGB LED will most likely have different values for the three colors. When buying your materials, you'll need to keep these values in mind so that you'll be able to choose the right resistors -- don't worry, we'll get there!
You'll also notice that RGB LEDs have four leads instead of two. As I mentioned before, the RGB LED is actually a very small circuit consisting of three different LEDs. Now, this is where things can get a bit tricky. RGB LEDs come in two types: common anode and common cathode. On the common anode type, the longest lead is attached to the positive terminal and allows current to flow to all three LEDs inside while leads 1, 3, and 4 are are the ground leads for red, green, and blue respectively. On the other hand, common cathode types share a ground lead; the three shorter leads are each individually hooked up to the positive terminal in the same order. So, which should you use? As a beginner, I would stick with the common cathode types. Common cathodes will give you a better understanding of how the Raspberry handles outputs and of how circuits work, and while common anode types will still work with current sinking, it's a little bit more advanced.
Step 2: Materials
- Raspberry Pi, I'll be using the 2 Model B
- Solderless breadboard (yum!) (this is the one I use)
- One RGB LED
- 3 resistors
- Jumper wires
Resistors are important because they prevent the LED from sending too much current through your Pi, something that they will do if given the opportunity. This could result in you blowing your LED, frying a GPIO pin, and/or destroying your Pi. ALWAYS use a resistor when connecting outputs to the Pi, even if they are low-level. Typically, these LEDs can each handle up to 30mA of current, but we're going to keep them under 17mA. Why can't we go that high? The Pi can only supply so much current to the GPIO pins, and, again, drawing too much can cause serious damage. So how high can we go? The answer isn't super straight forward, but it can be deduced. According to eLinux, the GPIO pins are connected to the 3.3v rail, which is capable of supplying a maximum of 50mA at a time. This does not, however, mean that the rail has a regulator limiting it to 50mA. If allowed to do so, a circuit connected to this rail will continue to draw current past 50mA until something short circuits. Keeping all three pins at least below 17mA will ensure that our Pi will be sufficiently protected, even when all three colors are burning at once.
The resistors you buy will depend on your individual LEDs. You'll need three resistors, one for each color. To calculate resistance, head on over to LEDCalculator.net. This website uses Ohm's law so you don't have to. Simply enter the supplied voltage (3.3v), the voltage drop (the forward voltage for the individual color), the current rating (stay at or below 16mA), and number of LEDs (in this case, treat each color as an individual LED). Do this for each color, changing the voltage drop appropriately. Now you've got the values for your resistors! Get one of each in the 1/4 watt size (wattage in this case measures the amount of heat the resistor will absorb before failing). Now we have everything we need. Let's get started!
Step 3: Breadboard Setup
Technically, a solderless breadboard isn't required, but it makes things much quicker and easier. If you do choose to solder, however, I am going to assume that you have at least some basic knowledge of circuits and that the following diagrams will be more than enough to get you going.
A solderless breadboard is used in prototyping because it allows you to easily move components around a circuit without having to solder and desolder. Believe me when I say that a solderless board can shave hours off even a simple project. On solderless boards, the positive and negative columns, called buses, can both connected to the positive and negative terminals on the supply. Using jumper wires, we can connect to these buses to form circuits. The columns between the two sets of buses, labeled A-E and F-J, are connected by rows, but these connections do not cross the middle divider. For example, columns A-E on row 1 make one rail, columns F-J on row 1 make another rail, and columns A-E on row 2 make a separate rail. Now that we understand that, let's talk a little bit about circuits. For this circuit, we need to connect the common cathode to a ground pin, and each of the three anodes to a different programmable pin through a resistor. In this case, we'll be using GPIO pins number 9, 11, 13, and 15 (there are two different naming conventions for the Pi's GPIO pins - this is using the "board" convention). Pin number 9 is a ground, so we'll connect our cathode to that, and then connect red, green, and blue to pins 11, 13, and 15.
Once this is all setup, we can go ahead and test our circuit - we don't want a faulty circuit making us think that our code is wrong. To do this, disconnect the circuit from your Pi except for the ground connection and turn the Pi on. Once the OS has booted, start by taking the red wire from the breadboard and attaching it to pin number 1. This pin is not programmable and is always set to 3.3v, so when the red wire is connected, the red LED should come on. Do this for all three colors.
Step 4: Writing the Program
Before we get into it, it's important to note that indentation is important in the Python language. Other languages use punctuation like brackets to tell the program the order to run things; Python uses indentation. Because of this, you may not be able to simply copy and paste the code from this page to your program as the formatting may not be completely preserved. Please feel free to follow along and write your own code as you go, or simply download my sample code here.
If you're new to coding, then it's important to mention that there is no one way to write a program. People have their own style, but it mostly comes down to how you think about solving a problem. I will provide sample code and explain it line-for-line, but please know that this is not the only way to achieve the exact same result.
import sys, time
Here, we import two built-in libraries - functions, variables, etc. that have already been defined and that we can call on.
import RPi.GPIO as GPIO
This is a Raspbian library that allows us to use Python to control GPIO pins.
redPin = 11 greenPin = 13 bluePin = 15
Now, we define some variables - which pins we'll be connecting to which RGB lead. This step isn't necessary, but it makes it easier to change pins if you need to.
Here, we define a function. A function is a set of steps that the computer will execute in the order that we give to it. This particular function will require one variable in order to run: the number of the pin that we want to light up.
We start our function off by referencing one of our libraries, GPIO. Then, we tell it that we want to choose a naming convention for the GPIO pins (of which there are two), so that the program knows which ones we're referring to. Then, we tell it to use the "board" convention (rather than the BMC convention), again using the GPIO library.
Now, once again using the GPIO library, we tell the Pi that we want to use a pin. But first, we need to specify which pin and how we want to use it - input or output. Here, "pin" is the variable that will be plugged into blink(pin).
Now that the pin has been set up, this line turns it on. You should recognize the syntax by now; here we're using the same variable "pin" and using the GPIO library to set the pin to a value of "high". In the case of GPIO pins, a "high" value results in 3.3v being passed, or "on", whereas a "low" value results in 0v being passed, or "off".
Now we're going to define a function to turn lights off. It's going to look almost identical to the previous function, only we'll be setting the pins back to low.
def turnOff(pin): GPIO.setmode(GPIO.BOARD) GPIO.setup(pin, GPIO.OUT) GPIO.output(pin, GPIO.LOW)
We need to define some functions specific to color using the functions we just made. Recall that we're using pins 11, 13, and 15 for red, green, and blue. We'll start with functions that turn lights on. With this type of function, we won't require any parameters, so the brackets stay empty; calling this function later in the program will simply execute it.
def redOn(): blink(redPin)
Here, we give the "blink" function a pin number to use, 11. When we call redOn(), our blink function will begin executing with "pin" replaced by "redPin". Recall that, earlier, we set redPin equal to 11.
Now we do the same thing for the rest of the colors.
def greenOn(): blink(greenPin) def blueOn(): blink(bluePin)
Remember that when dealing with light, yellow is made by mixing red with green, cyan using green and blue, magenta with red and blue, and white by combining all three.
def yellowOn(): blink(redPin) blink(greenPin) def cyanOn(): blink(greenPin) blink(bluePin) def magentaOn(): blink(redPin) blink(bluePin) def whiteOn(): blink(redPin) blink(greenPin) blink(bluePin)
Finally, we write the functions to turn lights off. Again, the syntax will be similar to the functions above.
def redOff(): turnOff(redPin) def greenOff(): turnOff(greenPin) def blueOff(): turnOff(bluePin) def yellowOff(): turnOff(redPin) turnOff(greenPin) def cyanOff(): turnOff(greenPin) turnOff(bluePin) def magentaOff(): turnOff(redPin) turnOff(bluePin) def whiteOff(): turnOff(redPin) turnOff(greenPin) turnOff(bluePin)
Now we're ready to define our main function; a loop that will constantly ask for user input and react by calling various functions. In this case, the user will be able to turn colors on and off. This program is written so that it will only accept a few pre-specified inputs. Otherwise, it will do nothing and display a message to that effect.
Again, we're not asking for any variables with this function, so the brackets stay empty. "while True" essentially says "while the program is running, do this", so it will run constantly until we quit.
def main(): while True: cmd = raw_input("Choose an option:")
We define a new variable "cmd" to use later and set it equal to the user's input. It will also constantly prompt the user to choose an option.
Now an "if" statement that will run only if the user input exactly matches the text within the quotation marks. Note that here we use two "equal to" symbols. In Python, and indeed most languages, a single "equal to" is used to change the value of a variable while doubles are used to compare whether or not variable values match each other.
if cmd == "red on": redOn()
"elif" stands for "else, if". This tacks onto the earlier "if" statement and adds new parameters, allowing us to create a chain of "else, if" statements easily.
elif cmd == "red off": redOff() elif cmd == "green on": greenOn() elif cmd == "green off" greenOff() elif cmd == "blue on": blueOn() elif cmd == "blue off": blueOff() elif cmd == "yellow on": yellowOn() elif cmd == "yellow off": yellowOff() elif cmd == "cyan on": cyanOn() elif cmd == "cyan off": cyanOff() elif cmd == "magenta on": magentaOn() elif cmd == "magenta off": magentaOff() elif cmd == "white on": whiteOn() elif cmd == "white off": whiteOff() else: print("Not a valid command.") return
With our last "else" statement, if the user attempts to input anything other than one of the commands specified above, it will tell the user that it is an invalid command. The last thing the function needs is that "return" so the program knows when to loop.
This is the last line of our code. When the program is run, this line will call the main function that we just defined and the loop will be set.
Step 5: Run the Program
And that's it! Now it's time to run the program. Navigate to the top menu bar and select Run -> Run Module, or press F5. You'll be asked to save your work before IDLE will run your program. Go ahead and type "red on" after the prompt and hit enter. The red light should come on!
Note that before you exit your program, at the very least you should make sure that all of the colors have been turned off. I would recommend, however, that you run the GPIO.cleanup() function before you quit. This is a built in function that comes with the RPi.GPIO library and resets any pins that were used in the program. You can either modify this code to include a command that runs the GPIO.cleanup(), or you can press CTRL+C to interrupt the program and then type GPIO.cleanup() directly into the user input.
Please, feel free to ask any questions! I would be happy to help.