Paja

Icon

Rapid prototyping for music, art and design work

Colour Selector from UCIT course

Here are some details of the colour selector made by Jaakko Hakulinen.

The application maps data from accelerometer to colour and uses LEDs to display this colour. The x-y axis data is converted into polar coordinates and angle is then used as hue and distance as colour intensity. Brightness is always maximum. This HSB value is then converted to RGB values. In addition, touch sensor is used to switch between reading the accelerometer data and controlling the LEDs using PWM.

The system runs entirely on BS2. It does send some debug output, which can be read on PC side.

The colour selector from Jaakko Hakulinen on Vimeo.


The following contains first BASIC code for BS2 and then a small Python, which read the debug stream and displays the colour on PC screen.

—————————–

‘{$STAMP BS2}
‘{$PBASIC 2.5}

‘ —[ I/O Definitions ]—
rLED    PIN  15
gLED    PIN  14
yLED    PIN  13

pXin      PIN  1
pYin      PIN  0

touch      PIN  2

‘ —[ Variables ]—
‘ accelerometer variables
wXPulse      VAR  Word    ‘ raw data from accelerometer
wXGravity    VAR  Word    ‘ X axis gravity
wYPulse      VAR  Word    ‘ raw data from accelerometer
wYGravity    VAR  Word    ‘ Y axis gravity

‘ input variables for goPolar: wXGravity, wYGravity
‘ output variables for goPolar:
angle VAR Word    ‘ in degrees
d VAR Byte        ‘ distance from origo

‘ colour related variables
redDuty      VAR  Byte    ‘ brightness
greenDuty    VAR  Byte    ‘ brightness
blueDuty     VAR  Byte    ‘ brightness
highDuty     CON  255     ‘ constant max brightness
lowDuty      VAR  Byte    ‘ temp value for brighness
medDuty      VAR  Byte    ‘ temp value for brighness

‘ —[ Constants ]—
cPulseState  CON  1
cScale       CON  $200                    ‘ 2.0 us per unit
cBS2         CON  $100      ‘ x 1.0, cycle adjustment (for ms)
cCycle       CON  5      ‘Required Charge time (Cycle equation) = 5 * Resistance * Capacity
‘Charge time = 5 * 10KR(10000R) * 0.1µF(1/1000000F) = 0.005 seconds = 5ms
‘ must use short charge time to keep three leds reasonably stable
‘ with PWM. Must use 0.1uf (104) capasitators to get acceptable time

‘ —[ Main Code ]—
Main:
DEBUG “Colour flower”, CR
DO
GOSUB Read_Accelerometer
‘ convert x and y accelometer data points to polar coordinates, i.e.,
‘ angle (variable angle) AND distance (variable d). Angle is in degrees,
‘ distance is between 0 AND 128.
GOSUB goPolar
DEBUG “angle: “, DEC angle, ” d: “, DEC d, CR

‘ hue of final colour is mapped to angle, saturation to distance
‘ brightness of HSB model is alway max.

‘ one colour always has max intensity
‘ another one has lowest intensity, when saturation is
‘ maximum, low value is 0 and when saturation is minimum,
‘ LOW value is maximum intensity.
‘ Medium colour has intensity between max and low value,
‘ its intensity depends on hue and saturation
‘ which colour (r, g, b) is which, depends on hue

‘ calculate colours based on the polar coordinates

‘ calculate medium intensity initial value (pre saturation)
IF angle / 60 & 1 = 0 THEN rising
IF angle / 60 & 1 > 0 THEN lowering
rising:
‘ medium value is rising in this range
medDuty = (angle // 60)
GOTO riseandlow
lowering:
‘ medium value is decreasing in this range
medDuty = (60 – (angle // 60))
GOTO riseandlow
riseandlow:
‘ scale from 0-60 to 0-256, very roughly
medDuty = medDuty */ $0444 ‘ * 4.25 approx

‘ calculate the low and med values (from saturation)
‘ clamp distance
IF d > 127 THEN d = 127
lowDuty = 256 – (2 * d)
medDuty = medDuty+(255-medDuty)-((255-medDuty)*d/128)

‘ branch based on degrees, map low, med, hi to colours
BRANCH angle / 60, [case_rg, case_gr, case_gb, case_bg, case_br, case_rb]
‘ in case names, first letter refers to high value color, second to med
case_rg:
redDuty = highDuty
greenDuty = medDuty
blueDuty = lowDuty
GOTO overCases
case_gr:
redDuty = medDuty
greenDuty = highDuty
blueDuty = lowDuty
GOTO overCases
case_gb:
redDuty = lowDuty
greenDuty = highDuty
blueDuty = medDuty
GOTO overCases
case_bg:
redDuty = lowDuty
greenDuty = medDuty
blueDuty = highDuty
GOTO overCases
case_br:
redDuty = medDuty
greenDuty = lowDuty
blueDuty = highDuty
GOTO overCases
case_rb:
redDuty = highDuty
greenDuty = lowDuty
blueDuty = medDuty
GOTO overCases
overCases:
DEBUG “built color: “, DEC redDuty, ” “, DEC greenDuty, ” “, DEC blueDuty, “.”, CR
GOSUB illuminateLEDs
LOOP
END

‘ —[ Subroutines ]—
Read_Accelerometer:
DO
‘ PULSIN Pin, State, Variable
‘ Pin: Pin number (0 – 15)
‘ State: Specifies whether the puse to be mesured is low(0) or high(1)
‘ Variable: the measured pulse duration will be stored.
PULSIN pXin, cPulseState, wXPulse      ‘ read pulse output
wXPulse = wXPulse */ cScale            ‘ convert to uSecs for BS2
wXGravity = ((wXPulse / 10) – 500)     ‘ -127-128 scale when g <= 1

PULSIN pYin, cPulseState, wYPulse
wYPulse = wYPulse */ cScale
wYGravity = ((wYPulse / 10) – 500)
greenDuty = wYGravity

‘ check touch sensor to know if its time to light the leds again
IF touch = 1 THEN EXIT
LOOP
DEBUG “Broke out of sensor loop”, CR
RETURN

illuminateLEDs:
DO
‘ Pulse-width modulation (PWM)
‘ PWM Pin, Duty, Cycles
‘ Pin: Pin number (0-15)
‘ Duty: Specifies the analog output level (0-5v)
‘ Cycles: Specifies the duration of the PWM signal
PWM rLED, redDuty, cCycle*/cBS2  ‘PWM  Pin(0-15), Duty(0-255), Cycles(0-255)ms
‘Average Voltage = (Duty / 255) * 5 volts.
PWM gLED, greenDuty, cCycle*/cBS2  ‘PWM  Pin(0-15), Duty(0-255), Cycles(0-255)ms
PWM yLED, blueDuty, cCycle*/cBS2  ‘PWM  Pin(0-15), Duty(0-255), Cycles(0-255)ms
‘ Check touch sensor to see, if we need to start reading position again
IF touch = 0 THEN EXIT
LOOP
DEBUG “Broke out of led loop”, CR
RETURN

goPolar:
‘ calculate angle and distance from cartesian coordinates
angle = wXGravity ATN wYGravity
‘ from drads to degrees
angle = angle * 180 / 128
‘ distance
d = wXGravity HYP wYGravity
RETURN

—————————–

The following is a Python program, which reads serial port and parses the debug data to display the selected colour on screen.

This is very ugly python code, so don’t use it as a good example.

The program uses pySerial (http://pyserial.sourceforge.net/), which is not part of Python so it needs to be installed separately, for serial communication and the used serial port is hardcoded so this won’t most likely work without modifications for anybody else.

In addition, indentation, which is relevant inPython, is likely wrong.

—————————–

import serial
import threading
from Tkinter import *
import re

colourPattern = re.compile(“built color..(\d+).(\d+?).(\d+?)\.”)

ser = serial.Serial(10);
# ser.open()

def readNumber():
res = “”
while (True):
r = ser.read(1);
if (r != ‘\r’):
res += r
else:
print(res)
if (res.isdigit()):
return int(res)
res = “”

def readColour():
res = “”
while (True):
r = ser.read(1);
if (r != ‘\r’):
res += r
else:
print res
match = colourPattern.search(res)
if match != None:
print “found colour”
return (int(match.group(1)), int(match.group(2)), int(match.group(3)))
res = “”

class Application(Frame):
def say_hi(self, number):
if (number == 1):
self.txt[“bg”] = “white”
else:
self.txt[“bg”] = “black”

def setColour(self, colour):
print “in set colour”
red = hex(colour[0])[2:4]
if (len(red) == 1):
red = “0” + red
green = hex(colour[1])[2:4]
if (len(green) == 1):
green = “0” + green
blue = hex(colour[2])[2:4]
if (len(blue) == 1):
blue = “0” + blue
hexCol = “#” + red + green + blue
print colour, hexCol
self.txt[“bg”] = hexCol

def createWidgets(self):
self.txt = Text(self, width = 100, height = 20)
self.txt.pack({“side”: “top”})

self.QUIT = Button(self)
self.QUIT[“text”] = “QUIT”
self.QUIT[“fg”]   = “red”
self.QUIT[“command”] =  self.quit

self.QUIT.pack({“side”: “bottom”})

def __init__(self, master=None):
Frame.__init__(self, master)
self.pack()
self.createWidgets()

class Reader(threading.Thread):
def __init__(self, app):
threading.Thread.__init__(self)
self.app = app
def run(self):
current = -1
while (True):
col = readColour()
print “received colour ” + str(col[0]) + str(col[1]) + str(col[2])
if (col != None):
app.setColour(col)
print(col)

root = Tk()
app = Application(master=root)

background = Reader(app)
background.start()

app.mainloop()
root.destroy()

Facebook Twitter Email

Category: Graduate School in User-Centered Information Technology, Institutes and schools, Student Projects

Tagged:

Comments are closed.

Social links powered by Ecreative Internet Marketing