RGB-LED Lesson 1 – Creating Python Libraries (& Colours)

This lesson will introduce creating and using your own library to provide low level control of the GPIO, while hiding away the detail inside.

Plus, you can have a Disco and even touch the Rainbow!

If you don’t have the kit don’t worry since much of the information in this lesson can be applied to other GPIO control projects and using Python generally, you just miss out on the beautiful colours…

LED Pink is the NEW Red! (well RGB_MAGENTA)

LED Pink is the NEW Red! (well RGB_MAGENTA)

Set-up:

For details about the assumed hardware and software set-up, please see “Lesson 0″ or the RGB-LED User Manual.

Be Structured:

When developing code it is useful to split your project into clear logical sections, so that you can easily separate and test each component individually before combining into a more complex and difficult to test system.  Each component should be self-contained as much as possible, with clearly defined interfaces, so that the module can be used without needing to worry about the details contained within.

By structuring your system into logical layers, you can separate your application specific actions from your hardware implementation.

By structuring your system into logical layers, you can separate your application specific actions from your hardware implementation to aid development and testing.

Easy Testing:

When you have well designed components, it is easy to replace some of the modules with test versions, which can contain extra debugging messages, logging or even simulate hardware being attached.  This can be particularly useful when writing code for development projects, where not all of the system is not available (still being developed) or when expensive hardware is being used.

As an example, we shall create the following script which will allow us to develop and test our RGB-LED python scripts without the hardware, and even develop them on a windows machine without any GPIO (if required).

Script: testRPiGPIO.py

#!/usr/bin/python
BOARD = "board"
BCM = "bcm"
OUT = "out"
IN = "in"

def output(pin,value):
  print pin, ":", value

def setmode(mode):
  print mode

def setup(pin,value):
  print pin, ":", value

def cleanup():
  print "clean-up"

#End

With the above script, we can replace the import of the RPi.GPIO library with this “test” library.

import RPi.GPIO as GPIO

with:

#import RPi.GPIO as GPIO #Use for Raspberry Pi GPIO
import testRPiGPIO as GPIO #Use for Debugging GPIO

Using our previous script from lesson 0, we get the following result.

board
12 : out
16 : out
18 : out
22 : out
7 : out
11 : out
13 : out
15 : out
12 : 1
16 : 1
18 : 1
22 : 1
7 : 1
11 : 0
13 : 0
15 : 0
12 : 0
11 : 1
12 : 1
11 : 0
12 : 1
16 : 1
18 : 1
22 : 1
7 : 1
11 : 0
13 : 0
15 : 0
clean-up

While it may just look like a series of numbers, looking closer we can see the sequence of operations from our program from before.

Lines 1-9 – We setup the GPIO and output pins.

Lines 10-18 – We put the pins to their default values.

Lines 19-20 – We activate the RED LED.

Lines 21-22 – We deactivate the RED LED.

Lines 23-31 – Finally we set the pins to default and release the GPIO.

If you are using the Kit and a Raspberry Pi, just move the # mark to enable the RPi.GPIO and comment out the test library to access the GPIO again.

Creating Our Library:

We can make our previous rgbledtest.py script more useful by turning it into a library.

Take a copy of it and name it rgbled.py, this will be our new library.  The file still contains the original main() function which runs some simple tests, we can keep this, but we do not want it to run if we import it into another file.

By adding the following line, before the call to main() our previous test code will now only be called if the script is run directly from the command line (like before).

if __name__=='__main__':
  main()
#End

While we updating our file, we can tidy a few things up by adding a small function to clean up led_cleanup(), and move the call to led_clear() into led_setup().

def led_setup():
 #Set up the wiring
 GPIO.setmode(GPIO.BOARD)
 # Setup Ports
 for val in LED:
   GPIO.setup(val, GPIO.OUT)
 for val in RGB:
   GPIO.setup(val, GPIO.OUT)
 led_clear()
…
…
def led_cleanup():
 led_clear()
 GPIO.cleanup()

def main():
 led_setup()
 led_activate(LED1,RGB_RED)
 time.sleep(5)
 led_deactivate(LED1,RGB_RED)
 led_cleanup()

Now, we can create a new file to use our library, instead of importing RPi.GPIO (for direct GPIO control) we now import rgbled.py (for GPIO control through our library).

rgbledcontrol.py:

#!/usr/bin/python

# rgbledcontrol.py
# Test program to show the use of libraries
import time
import rgbled as RGBLED

def main():
  print "Setup the RGB module"
  RGBLED.led_setup()
  print "Switch on LED1 RED"
  RGBLED.led_activate(RGBLED.LED1,RGBLED.RGB_RED)
  time.sleep(5)
  RGBLED.led_deactivate(RGBLED.LED1,RGBLED.RGB_RED)

  print "Finished"
  RGBLED.led_cleanup()

main()
#End

You may be thinking at this stage, why should we split the RGB-LED methods into another file, it worked fine as it was?  Now imagine that we have 10 different programs which we want to run at different times or on different computers, so we have 10 different python files with each of our programs in.  Now imagine we decide we want to change the wiring around, or perhaps we brought different RGB LEDs (common anode) – causing the LED_ENABLE and RGB_ENABLE to change.  Because we have “abstracted” out all the low level detail, we would only need to update the library file while leaving all the other programs alone.  This means we can do all our detailed tested focused on the one file we have changed, and only perform “integration” testing on the files we haven’t (to ensure nothing has been broken).

Improving Our Library:

We will now add some more functions to our library, so that any program which includes it has some extra functionality available.  First we shall improve our led_activate() and led_deactivate() functions to provide some additional flexibility:

Add led_gpiocontrol() function to rgbled.py:

#This function will control the state of
#a single or multiple pins in a list.
def led_gpiocontrol(pins,state):
  #determine if "pins" is a single integer or not
  if isinstance(pins,int):
    #Single integer - reference directly
    GPIO.output(pins,state)
  else:
    #if not, then cycle through the "pins" list
    for i in pins:
      GPIO.output(i,state)

led_activate() and led_deactivate() can now be updated to use the function:

#Enable the selected led(s) and set the required colour(s)
#Will accept single or multiple values
def led_activate(led,colour):
  #Enable led
  led_gpiocontrol(led,LED_ENABLE)
  #Enable colour
  led_gpiocontrol(colour,RGB_ENABLE)

#Deactivate the selected led(s) and set the required colour(s)
#Will accept single or multiple values
def led_deactivate(led,colour):
  #Disable led
  led_gpiocontrol(led,LED_DISABLE)
  #Disable colour
  led_gpiocontrol(colour,RGB_DISABLE)

We can also add a function led_time() to switch on an LED for a specific time period:

# Switch on the led and colour selected for the timeon period
def led_time(led, colour, timeon):
  led_activate(led,colour)
  time.sleep(timeon)
  led_deactivate(led,colour)

The above code allows us to call the led_time()/led_activate()/led_deactivate() functions with either a single LED or COLOUR specified, or we can call using a list of values.  This allows us to set one or more LEDs, and one or COLOURs using the same function.  By running the file directly, we can also confirm we haven’t broken the previous functionality and any existing programs will work the same as before (as our “test” main function makes calls to these functions).

We can now add some new arrays (with the other defined arrays) to create some extra colours:

RGB_CYAN = [RGB_GREEN,RGB_BLUE]
RGB_MAGENTA = [RGB_RED,RGB_BLUE]
RGB_YELLOW = [RGB_RED,RGB_GREEN]
RGB_WHITE = [RGB_RED,RGB_GREEN,RGB_BLUE]
RGB-LED Colours Table

RGB-LED Colours Table

Now we can update our control program rgbledcontrol.py to use the updated functions (and use some additional arrays – some_leds and sequence_leds):

# rgbledcontrol.py
# Test program to show the use of libaries
import time
import rgbled as RGBLED

some_leds = [RGBLED.LED1,RGBLED.LED3,RGBLED.LED5]
sequence_leds = [RGBLED.LED1,RGBLED.LED2,RGBLED.LED3,RGBLED.LED4,RGBLED.LED5,RGBLED.LED4,RGBLED.LED3,RGBLED.LED2]

def main():
  print "Setup the RGB module"
  RGBLED.led_setup()
  print "Switch on LED1 RED"
  RGBLED.led_time(RGBLED.LED1,RGBLED.RGB_RED,1)
  time.sleep(0.5)
  print "Switch on LED2 MAGENTA"
  RGBLED.led_time(RGBLED.LED2,RGBLED.RGB_MAGENTA,1)
  time.sleep(0.5)
  print "Switch on 1,3,5 WHITE"
  RGBLED.led_time(some_leds,RGBLED.RGB_WHITE,1)

  print "Finished"
  RGBLED.led_cleanup()

main()
#End

Time for a D.I.S.C.O:

We can further demonstrate the extra functionality we have added, by creating another little function in rgbled.py called led_rgbrandom() and an array of colours RGB_LIST[] to pick from.

RGB_LIST = [RGB_RED,RGB_GREEN,RGB_BLUE,RGB_CYAN,RGB_MAGENTA,RGB_YELLOW,RGB_WHITE]

# Light up the selected led, for period in seconds, in one of the possible colours.
# The colours can be 1 to 3 for RGB, or 1-6 for RGB plus combinations, 1-7 includes white.
# Anything over 7 will be determined as OFF (larger the number more chance of OFF).
def led_rgbrandom(led,period,colours):
 value = randint(1,colours)
 if value < 8:
  led_time(led,RGB_LIST[value-1],period)

led_rgbrandom() allows us to specify an LED (or even several LEDs) and an on period, and a range of possible colours.  It will randomly pick a colour from the list (randint() will pick a whole number between 1 and the given “colours”).  The random number is then used to select a colour out of our table (remember arrays are always indexed starting with 0).  We then light the LED for the required time (or if the value is beyond the colour range, we switch it off for that time period).

We now have our rgbled.py library ready to use:

#!/usr/bin/python
import time
from random import randint
import RPi.GPIO as GPIO  #Use real GPIO
#import testRPiGPIO as GPIO  #Use test GPIO

# RGB LED Module (TEST)

#Setup Active states
#Common Cathode RGB-LEDs (Cathode=Active Low)
LED_ENABLE = 0
LED_DISABLE = 1
RGB_ENABLE = 1
RGB_DISABLE = 0

#LED CONFIG - Set GPIO Ports
LED1 = 12 #B4
LED2 = 16 #B18
LED3 = 18 #B23
LED4 = 22 #B24
LED5 = 7 #B25
LED = [LED1,LED2,LED3,LED4,LED5]
RGB_RED = 11 #B22
RGB_GREEN = 13 #B21 Rev1 B27 Rev2
RGB_BLUE = 15 #B17
RGB = [RGB_RED,RGB_GREEN,RGB_BLUE]
RGB_CYAN = [RGB_GREEN,RGB_BLUE]
RGB_MAGENTA = [RGB_RED,RGB_BLUE]
RGB_YELLOW = [RGB_RED,RGB_GREEN]
RGB_WHITE = [RGB_RED,RGB_GREEN,RGB_BLUE]
RGB_LIST = [RGB_RED,RGB_GREEN,RGB_BLUE,RGB_CYAN,RGB_MAGENTA,RGB_YELLOW,RGB_WHITE]

#Setup the RGB-LED module pins and state.
def led_setup():
  #Set up the wiring
  GPIO.setmode(GPIO.BOARD)
  # Setup Ports
  for val in LED:
    GPIO.setup(val, GPIO.OUT)
  for val in RGB:
    GPIO.setup(val, GPIO.OUT)
  led_clear()

#This function will control the state of
#a single or multiple pins in a list.
def led_gpiocontrol(pins,state):
  #determine if "pins" is a single integer or not
  if isinstance(pins,int):
    #Single integer - reference directly
    GPIO.output(pins,state)
  else:
    #if not, then cycle through the "pins" list
    for i in pins:
      GPIO.output(i,state)

#Enable the selected led(s) and set the required colour(s)
#Will accept single or multiple values
def led_activate(led,colour):
  #Enable led
  led_gpiocontrol(led,LED_ENABLE)
  #Enable colour
  led_gpiocontrol(colour,RGB_ENABLE)

#Deactivate the selected led(s) and set the required colour(s)
#Will accept single or multiple values
def led_deactivate(led,colour):
  #Disable led
  led_gpiocontrol(led,LED_DISABLE)
  #Disable colour
  led_gpiocontrol(colour,RGB_DISABLE)

# Switch on the led and colour selected for the timeon peroid
def led_time(led, colour, timeon):
  led_activate(led,colour)
  time.sleep(timeon)
  led_deactivate(led,colour)

# Light up the selected led, for period in seconds, in one of the possible colours.
# The colours can be 1 to 3 for RGB, or 1-6 for RGB plus combinations, 1-7 includes white.
# Anything over 7 will be determined as OFF (larger the number more chance of OFF).
def led_rgbrandom(led,period,colours):
  value = randint(1,colours)
  if value < 8:
    led_time(led,RGB_LIST[value-1],period)

# Set the pins to default state.
def led_clear():
  for val in LED:
    GPIO.output(val, LED_DISABLE)
  for val in RGB:
    GPIO.output(val, RGB_DISABLE)

# Reset pins to default state and release GPIO
def led_cleanup():
  led_clear()
  GPIO.cleanup()

# Directly run test function.
# This function will run if the file is executed directly.
def main():
  led_setup()
  led_activate(LED1,RGB_RED)
  time.sleep(5)
  led_deactivate(LED1,RGB_RED)
  led_cleanup()

if __name__=='__main__':
  main()
#End

Returning to our control program rgbledcontrol.py, we will now have the following:

#!/usr/bin/python

# rgbledcontrol.py
# Test program to show the use of libaries

import time
import rgbled as RGBLED

some_leds = [RGBLED.LED1,RGBLED.LED3,RGBLED.LED5]
sequence_leds = [RGBLED.LED1,RGBLED.LED2,RGBLED.LED3,RGBLED.LED4,RGBLED.LED5,RGBLED.LED4,RGBLED.LED3,RGBLED.LED2]

def main():
 print "Setup the RGB module"
 RGBLED.led_setup()
 print "Switch on LED1 RED"
 RGBLED.led_time(RGBLED.LED1,RGBLED.RGB_RED,1)
 time.sleep(0.5)
 print "Switch on LED2 MAGENTA"
 RGBLED.led_time(RGBLED.LED2,RGBLED.RGB_MAGENTA,1)
 time.sleep(0.5)
 print "Switch on 1,3,5 WHITE"
 RGBLED.led_time(some_leds,RGBLED.RGB_WHITE,1)

 print "Random RGB over all LEDs"
 for i in range(10):
   for j in sequence_leds:
     RGBLED.led_rgbrandom(j,0.1,3) #Select from R/G/B
 print "Finished"
 RGBLED.led_cleanup()

main()

Extra Credit:

1. Try experimenting a little with your new led_rgbrandom() function, perhaps by changing the sequence or by increasing the colour value from 3 to 20 and observe the results.

2. As mentioned in the User Manual, we discussed using advanced control of the LEDs to allow us to produce different colours on different LEDs.  The solution is to use high speed switching, to command several LEDs ON and OFF very quickly after another.

Now that we have our new led_time() function, we can easily achieve this in a loop (LED ON period of around 0.001 seconds seems to work nicely).

Therefore, we can recreate the 1st 5 colours of the Rainbow, according to the song we know they are:

Red, and Yellow, and Pink, and Green, Orange…

Our very colourful RGB-LED Rainbow!

Our very colourful RGB-LED Rainbow!

I will let you have a try to do this, if you have any problems then please let me know.

Once you start with this, you may wonder about “Orange” since we haven’t defined RGBLED.RGB_ORANGE in our files.  However, with a little thought, I am sure you can produce Orange too!

Earn a Gold Star*!

If you are feeling real adventurous, you may even be able to get your RGB-LEDs to display the rest of the colours (or a smooth scale of colours) and scroll them across the LEDs.

This would look rather cool – so I will post a video from the first person to who manages it!

*Unfortunately you shall have to provide your own Gold Star (available from most supermarkets).

Comments
  1. [...] delal na nekem zelo učljivem dodatki za Pi. Njegov prikaz, kaj lahko naredite si lahko ogledate v tem vodiču, kjer boste ustvarili vašo Python knjižnico in jo uporabili pri upravljanju z GPIO pini. Za [...]

  2. [...] teaching add-ons for the Pi. He’s demonstrating what you can do with one of his little kits with this natty tutorial where you’ll be creating your own Python library, and using it to do some low-level control of [...]

  3. [...] This lesson will introduce creating and using your own library to provide low level control of the GPIO, while hiding away the detail inside. Plus, you can have a Disco and even touch the Rainbow! …  [...]

  4. [...] teaching add-ons for the Pi. He’s demonstrating what you can do with one of his little kits with this natty tutorial where you’ll be creating your own Python library, and using it to do some low-level control of [...]

  5. [...] A nice little lesson in making python libraries – they’ll keep your code tidy and reusable, from MELTWATER’S RASPBERRY PI HARDWARE: [...]

  6. [...] RGB-LED Lesson 1 – Creating Python Libraries (& Colours) [...]

  7. [...] This lesson will introduce creating and using your own library to provide low level control of the GPIO, while hiding away the detail inside. Plus, you can have a Disco and even touch the Rainbow! …  [...]

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s