Sunday, April 19, 2009

Light Source Tracking in Two Dimensions

This project was a proof-of-concept for the idea of tracking the sun throughout the day in order to optimize the efficiency of solar panels. As a proof-of-concept, there aren't any solar panels, so this particular implementation doesn't do much other than follow a flashlight. The project was built around the BASIC Stamp II (BS2) and some simple components.

Components
1. Light level detection
2. Repositioning of surface
3. I/O processing

1. Light Level Detection
This was done using three photoresistors positioned at right angles to each other:The photoresistors were mounted in LED holders for the sake of convenience. In case you're not familiar with how they work, they decrease resistance with increasing light magnitude. After measuring the light at each of the three points, the values are compared by the BS2 and the servos reposition the array accordingly. The left and top-right values are compared to determine the x position, and the top-right and bottom values are compared to determine the y position. When the values in question are equal, it simply assumes it's facing the light source and stops moving.

2. Repositioning of Surface
So say we know where the light source is relative to the surface; now we need a way to reposition this surface such that it's normal to (directly facing) the light source. I happened to have a couple continuous-rotation servos, so I used these and they worked fine. (In hindsight, regular servos would probably have been a better option.) The servos received power from an old computer power supply I had laying around.
Here's a picture of the whole setup where you can see how the servos are positioned:


3. I/O Processing
As mentioned before, the processing was done with a Basic Stamp II. The light levels could be detected using the RCTIME function in combination with a capacitor. First, the pin the photoresistor is connected to is set as an output and set to high (+5V), charging the capacitor. After a fraction of a second, the capacitor is discharged and the pin is set to an input. The function then returns the amount of time it takes for the pin to measure a 0V, indicating the capacitor has been discharged. More resistance means more time to discharge, so a lower number means more light.
In addition to the autonomous mode, I wired up a switch to toggle the manual mode. There are four momentary switches on the breadboard which control the sensor array. (This is mainly in case the wires coming from the photoresistors get tangled up.)
The three LEDs on the breadboard indicate the status. One turns on when it's in manual mode and off otherwise; the other two light up when the x and y axes are locked on, respectively.


PBASIC Source Code (Email me if you want a copy with indentation; it removes it when I post it on here.)
' {$STAMP BS2}
' {$PBASIC 2.5}

LSensor VAR Word
RSensor VAR Word
BSensor VAR Word

XRot VAR Nib '0: left 1: stationary 2: right
YRot VAR Nib '0: lower 1: atationary 2: raise
Mode VAR Bit

'Set up pin configuration
LRes CON 0 'left photoresistor
RRes CON 1 'right photoresistor
BRes CON 2 'bottom photoresistor
XServo CON 3
YServo CON 4
XSpeed CON 10
YSpeed CON 10
XDeadzone CON 20
YDeadzone CON 20

Main:
Mode = IN8
IF Mode = 1 THEN
GOSUB Autonomous
ELSE
GOSUB Manual
ENDIF
GOSUB SetOutput
GOTO Main

Autonomous:
'Get analog inputs from photoresistors
HIGH LRes
HIGH RRes
HIGH BRes
PAUSE 1 'let capacitors charge
RCTIME LRes, 1, LSensor
RCTIME RRes, 1, RSensor
RCTIME BRes, 1, BSensor
IF ABS (LSensor - RSensor) > XDeadzone THEN
IF LSensor < RSensor THEN
XRot = 2
ELSE
XRot = 0
ENDIF
LOW 6
ELSE
XRot = 1
HIGH 6 'Light up LED when locked on
ENDIF
IF ABS (RSensor - BSensor) > YDeadzone THEN
IF RSensor < BSensor THEN
YRot = 2
ELSE
YRot = 0
ENDIF
LOW 5
ELSE
YRot = 1
HIGH 5 'Light up LED when locked on
ENDIF
LOW 7
RETURN

Manual:
13 of 14
IF IN15 = 1 THEN
YRot = 0
ELSEIF IN14 = 1 THEN
YRot = 2
ELSE
YRot = 1
ENDIF
IF IN13 = 1 THEN
XRot = 0
ELSEIF IN12 = 1 THEN
XRot = 2
ELSE
XRot = 1
ENDIF
LOW 5
LOW 6
HIGH 7 'Indicate mode
RETURN

SetOutput:
IF XRot = 0 THEN
PULSOUT XServo, (750 + XSpeed) '750: do nothing
ELSEIF XRot = 2 THEN
PULSOUT XServo, (750 - XSpeed)
ELSE
PULSOUT XServo, 750
ENDIF
IF YRot = 0 THEN
PULSOUT YServo, (750 + YSpeed)
ELSEIF YRot = 2 THEN
PULSOUT YServo, (750 - YSpeed)
ELSE
PULSOUT YServo, 750
ENDIF
PAUSE 20
RETURN

No comments:

Post a Comment