Tri-Colour LED Controller

Contents

Introduction
Design and Implimentation
Considerations for LED Uses
Demo
Source Code (Python)
Comments

Introduction

This is a proof of concept for basic electronics and a home project just for a bit of fun. To demonstrate some simple LED concepts with microcontrollers. In this case, it is a microprocessor on a microcomputer board with a Linux operating system but the LED control principles are basically the same. I have written a program in python that runs on a Raspberry Pi to control a tri-colour light-emitting diode (LED). Technically it is actually three diodes in one package. This includes red, green and blue. I brought the tri-colour LED from CPC which was designed for Raspberry Pi (with pin connectors and built-in resistors). I am using an easier Pi and at some point, I will try this on the latest available.

Design and Implimentation

The LED colour is varied by flashing the LED at a high frequency with varying duty. This is known as pulse width modulation (PWM). In the context of my project this provides for a dimming effect on each of the red, green and blue colours and therefore, changes the colour appearance of the LED. To improve this flashing a timer interrupt would be an interesting route forward. This will stabilise the flashing a bit better as delays in processing other parts of the program will cause gaps in the flash effect.

The PWM method can be used to dim a LED on microcontrollers to provide optional brightnesses and to reduce power consumption. Many microcontrollers have a PWM output and there are chipsets available to provide multi-channel PWM outputs. My PWM is a software implementation rather than a hardware one. The LED has four wires that include, common ground and the red, green and blue lines with resistors in-line and connected to the I/O header of the Raspberry Pi embedded microcomputer. PWM can be used in audio too along with numerous other applications.

Considerations for LED Uses

It is important to note, an LED that is being used to indicate data being passed through a device should not be directly connected into the data line. This is because as it is possible to create a device that can read the LED and gather the data straight from it! This is one consideration of many for using an LED so you can imagine the amount of design that has to go into an electronic device!

Demo

Warning: Video contains flashing images that might cause problems for some individuals.

Note that the flashing may be more obvious in the video because the frame rate of the camera is not synchronised with the LED and the camera works differently from the human brain.

Note also, that this is running on a slower earlier version of a Pi computer. The newer versions have faster processing.

Source Code (Python)

# This is a very basic piece of code just to strobe three combined LEDs to produce different colours.
# I should look to use a timer interrupt instead as this would be more effective.
# There is an intention to provide control of the LED via TCP/IP.  But not implemented yet.
import RPi.GPIO as GPIO
import time
import threading
import Queue
import random
import signal, os

# The strober will strobe the LED at high frequency which causes the dimming effect.
class LED_Strober():
	STROBE_ON = 0.0001
	STROBE_OFF = 0.003

	def __init__(self,name,pin):
		self.name = name
		self.halt = False
		self.pin = pin
		self.on = 0
		self.strobe = self.STROBE_OFF
		self.thread = threading.Thread(target=self.run,name=self.name)
		self.thread.start()

	def setStrobe(self,value):
		self.strobe = value

	def setValue(self,value):
		if value > 0:
			self.on = 1
			# if the value has been set to 1 this overrides the strobe value if strobe is 0 led is on all the time
			if value >= 1:
				self.strobe = 0
			else:
				self.strobe = value
		else:
			self.on = 0

	def run(self):
		while not self.halt:
			# if strobe is greater than 0, strobe the LED else led always on
			if self.strobe > 0:
                # LED strobe
				GPIO.output(self.pin,self.on)
				time.sleep(self.STROBE_ON)
				GPIO.output(self.pin,0)
				time.sleep(self.strobe)
			else:
                # LED on
				GPIO.output(self.pin,self.on)
				time.sleep(0.01) # allow some sleep time giving 10ms response time

	def stop(self):
		self.halt = True

# Tri-Colour LED controller that controls the colour to display.
class LED_Controller():

	# GPIO (General-purpose input/output)
	RED_PIN = 17
	GREEN_PIN = 18
	BLUE_PIN = 27

	# RGB Timers for soft PWM
	resetR = 0
	resetG = 0
	resetB = 0

	thread = None
	name = ""
	red = 0
	green = 0
	blue = 0
	STROBE_ON = 0.0001
	STROBE_OFF = 0.04
	halt = False

	def __init__(self):
		# Set the control mode to use GPIO numbers (not pinout numbers)
		GPIO.setmode(GPIO.BCM)
		GPIO.setwarnings(False)

		# Enable outputs for GPIO
		self.enable()

		# Just give this object a name
		self.name = "LED Controller"

		# Provide a strober (software PWM) controller for RED, GREEN and BLUE leds
		self.red_LED = LED_Strober("Red",self.RED_PIN)
		self.green_LED = LED_Strober("Green",self.GREEN_PIN)
		self.blue_LED = LED_Strober("Blue",self.BLUE_PIN)

		print "Init Complete"

	# Method stops LED strobers and waits for threads to end
	def stop(self):
		self.red_LED.stop()
		self.green_LED.stop()
		self.blue_LED.stop()
		self.red_LED.thread.join()
		self.green_LED.thread.join()
		self.blue_LED.thread.join()
	
	# Sets color by setting up strobers PWM low time
	def setColor(self,array):
		self.red = array[0]
		self.green = array[1]
		self.blue = array[2]
		# I've been a bit lazy here and just put calibration values directly in :)
		if self.red > 0:
			self.resetR = (0.005 - (0.005 * self.red))
			if self.resetR == 0:
				self.resetR = 1
		else:
			self.resetR = 0
		if self.green > 0:
			self.resetG = (0.0390 - (0.0390 * self.green)) + 0.0010
		else:
			self.resetG = 0
		if self.blue > 0:
			self.resetB = (0.0395 - (0.0395 * self.blue)) + 0.0005
		else:
			self.resetB = 0
		self.red_LED.setValue(self.resetR)
		self.green_LED.setValue(self.resetG)
		self.blue_LED.setValue(self.resetB)
		

	# Sets led output (use setColor instead)
	def leds(self, red, green, blue):
		GPIO.output([self.RED_PIN,self.GREEN_PIN,self.BLUE_PIN],(red,green,blue))

	# Enable outputs
	def enable(self):
		GPIO.setup(self.RED_PIN,GPIO.OUT,initial=GPIO.LOW)
		GPIO.setup(self.GREEN_PIN,GPIO.OUT,initial=GPIO.LOW)
		GPIO.setup(self.BLUE_PIN,GPIO.OUT,initial=GPIO.LOW)

	# Set outputs back to inputs
	def disable(self):
		GPIO.setup(self.RED_PIN,GPIO.IN)
		GPIO.setup(self.GREEN_PIN,GPIO.IN)
		GPIO.setup(self.BLUE_PIN,GPIO.IN)

# Class holds color names
class Color():
	black = [0,0,0]
	red = [1,0,0]
	orange = [1, 0.5, 0]
	yellow = [1,1,0]
	green = [0,1,0]
	cyan = [0,1,1]
	blue = [0,0,1]
	purple = [0.5,0,1]
	magenta = [1,0,1]
	white = [1,1,1]
	colors = [black,white,red,green,blue,yellow,cyan,magenta,orange,purple]

# Class holds test patterns for LED. Fun!
class LED_Test():
	def __init__(self):
		self.led = LED_Controller()

	# Show rainbow
	def rainbow(self, delay):
		color = Color()
		# Only uses solid colours (no dimming)
		sequence = [color.red, color.yellow, color.green, color.cyan, color.blue, color.purple]
		# Run the sequence
		self.doSequence(sequence, delay)

	# Show extended rainbow
	def rainbowEx(self, delay):
		color = Color()
		sequence = []
		sequence.append(color.red)
		sequence.append(color.orange)
		sequence.append(color.yellow)
		sequence.append([0.5, 1, 0])
		sequence.append(color.green)
		sequence.append([0, 1, 0.5])
		sequence.append(color.cyan)
		sequence.append([0, 0.5, 1])
		sequence.append(color.blue)
		sequence.append(color.purple)
		sequence.append(color.magenta)
		sequence.append([1, 0, 0.7])
		# Run the sequence
		self.doSequence(sequence, delay)
	
    # Execute a sequence
	def doSequence(self, sequence, delay):
		for newColor in sequence:
			self.led.setColor(newColor)
			time.sleep(delay)

    # Set random color
	def random(self):
		red = random.random()
		green = random.random()
		blue = random.random()
		if red < 0.5:
			red = 0
		if green < 0.5:
			green = 0
		if blue < 0.5:
			blue = 0
		self.led.setColor([red,green,blue])

    # Loop random color
	def randomForever(self, delay):
		while 1:
			self.random()
			time.sleep(delay)

    # Loop rainbow effect
	def rainbowExForever(self, delay):
		while 1:
			self.rainbowEx(delay)

    # Set a color by color array.
	def setColor(self,color):
		self.led.setColor(color)

    # Set a color on the LED controller.
	def leds(self, rgb):
		self.led.leds(rgb[0], rgb[1], rgb[2])

    # Stop and reset I/O and stop thread
	def cleanUp(self):
		self.led.stop()
		self.led.disable()

# Get LED tester
led = LED_Test()
# Get color table
color = Color()

# Do a custom sequence
#s = [[1,1,1],[1,0.95,1]]
#while 1:
#	led.doSequence(s,0.5)

# Do rainbow sequence continously
led.rainbowExForever(0.1)

# Clean up I/O (never gets here on loop forever)
led.cleanUp()

..

3 thoughts on “Tri-Colour LED Controller

  1. James says:

    Thinking more about the video demo, I think I could change the video to extend selected frames to provide a simulation of what this might look like to the human eye. I might come back to this when I have more time.

  2. James says:

    I’ve been thinking a bit more about the timer interrupt and think that I would have to use C instead because the python may have too much code behind it and not be efficient enough. So I will have to transfer the concept over to C instead.

Leave a Reply

Privacy Overview

This website uses cookies so that we can provide you with the best user experience possible. Cookie information is stored in your browser and performs functions such as recognising you when you return to our website and helping our team to understand which sections of the website you find most interesting and useful.