Python + Arduino Diffuser control

Assignment: Digital I/O with Arduino Boards + Diffuser

Collaborators:

 

Components Used:

  • Light Emitting Diodes (LED)--red, green, and blue
  • 220 ohm resistors (3)
  • Arduino board
  • Bread board
  • Wires
  • Foam cube

Description:

I made a diffuser by taking a big chunk of foam, cutting out a cube, making an incision and hollowing out a cavity in the middle, and inserting the LEDs.

I used the default Arduino code to handle info sent over the serial connection (plus two lines to fix a bug in the default code). I then wrote a Python script that operates in two modes:

Mode 1:

User presses the R, G, or B keys. Each keypress causes a 10% increase in the corresponding LED's brightness. If the value would exceed 255, it drops back down to 0. Note that with the Python code you don't need to press enter or wait for a prompt, every time you press a key in this mode you get instantaneous feedback.

Press the 'Q' key to quit.

Mode 2:
User is prompted to enter a 6 digit hexidecimal value - the same format as specifying colors in HTML. After the user presses enter, the program updates the LEDs to match the hex code. The user is the prompted to enter a new code.

Type 'q' or 'quit' to quit.

Arduino Code:

This is almost the vanilla code (plus a bug fix), I do my customization through Python.

/*
* Serial RGB LED
* ---------------
* Serial commands control the brightness of R,G,B LEDs
*
* Command structure is "<colorCode><colorVal>", where "colorCode" is
* one of "r","g",or "b" and "colorVal" is a number 0 to 255.
* E.g. "r0"   turns the red LED off. 
*      "g127" turns the green LED to half brightness
*      "b64"  turns the blue LED to 1/4 brightness
*
* Created 18 October 2006
* copyleft 2006 Tod E. Kurt <tod@todbot.com
* http://todbot.com/
*/

char serInString[100];  // array that will hold the different bytes of the string. 100=100characters;
// -> you must state how long the array will be else it won't work properly
char colorCode;
int colorVal;

int redPin   = 9;   // Red LED,   connected to digital pin 9
int greenPin = 10;  // Green LED, connected to digital pin 10
int bluePin  = 11;  // Blue LED,  connected to digital pin 11

void setup() {
pinMode(redPin,   OUTPUT);   // sets the pins as output
pinMode(greenPin, OUTPUT);  
pinMode(bluePin,  OUTPUT);
Serial.begin(9600);
analogWrite(redPin,   127);   // set them all to mid brightness
analogWrite(greenPin, 127);   // set them all to mid brightness
analogWrite(bluePin,  127);   // set them all to mid brightness
Serial.println("enter color command (e.g. 'r43') :"); 
}

void loop () {
//read the serial port and create a string out of what you read
readSerialString(serInString);
colorCode = serInString[0];
if( colorCode == 'r' || colorCode == 'g' || colorCode == 'b' ) {
colorVal = atoi(serInString+1);
Serial.print("setting color ");
Serial.print(colorCode);
Serial.print(" to ");
Serial.print(colorVal);
Serial.println();
serInString[0] = 0;                   // indicates we've used this string
if(colorCode == 'r')
analogWrite(redPin, colorVal);
else if(colorCode == 'g')
analogWrite(greenPin, colorVal);
else if(colorCode == 'b')
analogWrite(bluePin, colorVal);
serInString[3]=0; //This line (and the one below it) solve a bug where Arduino behaves badly if you follow a three digit color value with a 1 or two digit color value.
serInString[2]=0;
}

delay(100);  // wait a bit, for serial data

}

//read a string from the serial and store it in an array
//you must supply the array variable
void readSerialString (char *strArray) {
int i = 0;
if(!Serial.available()) {
return;
}
while (Serial.available()) {
strArray[i] = Serial.read();
i++;
}
}

Python Code:

#This is also attached since the posting form doesn't seem to preserve spacing.

import time
import serial #serial is a python wrapper for serial communication
import sys, tty, termios

def getch():
""" getch reads keypresses and returns the character"""
fd = sys.stdin.fileno()
old = termios.tcgetattr(fd)
try:
tty.setraw(fd)
return sys.stdin.read(1)
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, old)

class Color():
""" Color defines a color class that holds RGB values and methods for setting them"""
def __init__(self):
""" init sets RGB values all to 127, a middle color"""
self.rval=127
self.bval=127
self.gval=127
def increase_blue(self, percent=10):
""" increase_blue takes an optional percentage and increases the blue value by that much (default 10%)"""
self.bval += 255/percent
if self.bval > 255:
self.bval = 0
def increase_red(self, percent=10):
""" increase_red takes an optional percentage and increases the red value by that much (default 10%)"""
self.rval += 255/percent
if self.rval > 255:
self.rval = 0

def increase_green(self, percent=10):
""" increase_green takes an optional percentage and increases the green value by that much (default 10%)"""
self.gval += 255/percent
if self.gval > 255:
self.gval = 0

def set_color(self, red=0, blue=0, green=0):
""" set_color allows you to manually specify decimal values for red, blue, and green. Ommitted colors default to 0"""
self.rval = red
self.bval = blue
self.gval = green

def set_hex_color(self, hex='000000'):
""" set_hex_color takes a 6 digit hex code and converts it to appropriate RGB values, then sets them. See your favorite web-color via LED!"""
red = hex[0:2]
blue = hex[2:4]
green = hex[4:6]
self.rval = int(red,16)
self.bval = int(blue,16)
self.gval = int(green,16)

if __name__ == '__main__':
ser = serial.Serial('/dev/cu.usbserial-A9007LR8', 9600) # initialize the serial connection to arduino
myColor = Color()
mode = raw_input("""Pick your mode:
1: Increase lights using RGB keys
2: Input hex codes to change lights
""")
if mode =='1':
"""mode 1 allows users to press the r, b, or g keys to increment the red, blue, or green LEDs in 10% increments.
If the value would exceed 250, it instead resets to 0"""
while 1:
try:
c = getch()
except:
c = 0
if c:
if c == 'r':
myColor.increase_red()
ser.write('r%s' % myColor.rval) #write the new red
print "r%s" % myColor.rval
if c == 'b':
myColor.increase_blue()
ser.write('b%s' % myColor.bval) #write the new blue
print "b%s" % myColor.bval
if c == 'g':
myColor.increase_green()
ser.write('g%s' % myColor.gval) #write the new green
print "g%s" % myColor.gval
if c == 'q':
break;
if mode=='2':
"""Mode 2 allows users to implement a six digit hex code of the kind used to specify colors for websites.
The LEDs are then updated to correspond to that code."""
while 1:
hex = raw_input("What's your hex code (leave off the '#')\n")
hex = hex.upper()
if hex == 'Q' or hex == 'QUIT':
break
myColor.set_hex_color(hex)
#perform a series of writes to update all LEDs with their new colors. The sleep is to make sure Arduino keeps up.
ser.write('r %s' % myColor.rval)
time.sleep(.1)
ser.write('g %s' % myColor.gval)
time.sleep(.1)
ser.write('b %s' % myColor.bval)
print "cool, you set it to #%s, which is red: %s, blue: %s, green:%s" % (hex, myColor.rval, myColor.bval, myColor.gval)
ser.close() #close the serial connection when we're done, otherwise it holds the lock.

Image:

Diffuser in Dark

Circuit/diffuser