As promised, today we take care of the
photocell readings. If you have experimented with the photocell
before and you have done one of the basic Arduino tutorials reading
the analogue pin connected to it you may have noticed that the
reading are jumping quite a bit. In my case they are going up and
down 50 units with a constant light source and that is not very
helpful while we want to switch something on or off when the light
reaches a specific level. Trying to get a clear switching point
specially at dusk and dawn with variable cloud conditions make the
lights switch on and off a few times until the reading doesn't go
above ore below the switching point. Even programming a buffer didn't
help much it just moved the “not knowing what to do effect” to
the upper and lower limits of the buffer. Than I came across some
very useful Analogue Smoothing Algorithm by Tom Igoe which I liked a
lot and it nearly solved the problem but still there where a 2 to 3
kind of ghost switchings until the system was stable.
What I came up with next, was checking
the photocell reading, make sure they are within a predefined limit
and flag the effected rooms, meaning as long as they are set to 1 and
are within the time frame, the lights will switch on no matter of
change of light conditions or sensor readings. Soon as the time limit
is reached the lights will switch off and the light sensor flag will
reset to 0.
There where still some issues with time
delays in lights switching specially when we have more than 2 timers
for a room. Implementing the “Analogue Smoothing Algorithm” from
Tom Igoe finally brought enough accuracy to stop lights from coming
on and off a couple of times before everything got settled.
For normal operation where we also
partly depend on a photocell to determine if it's dark enough to
switch the lights ore not, implementing the smoothing algorithm gives
already enough accuracy since we are also using a time delay. 10 to
15 minutes should be enough to stabilize the light level either way
on or off, since we don't have to deal with a up to 50 points jumping
values.
Let's have a look at the sketch.
As usual, we start with a few
additional variables and there for we go to the declaration part at
the end of “//////////////all the other
variables/////////////////////”:
unsigned int outsideOnTime = 0;
//checking result if the time is within
//on or off time limits
byte room1Lights = 0;
byte room2Lights = 0;
byte room3Lights = 0;
byte room4Lights = 0;
byte room5Lights = 0;
byte room6Lights = 0;
byte room7Lights = 0;
byte room8Lights = 0;
byte room9Lights = 0;
byte currentHour = 0;
byte currentMinute = 0;
//>>>>>>>>>>>>addition
starts here<<<<<<<<<<<<<<<
byte lightLevel[17] ={0}; //array holding the light
//level flag value for each room
byte photocellSwitch = 0;
//check if the reading
//within a switching limit
int smoothed = 0; //var
for the smoothed analogue reading value
int alpha = 4; //the
number of past samples to average
int sensor = 0; //the
photocell reading
//>>>>>>>>>>>>>>addition
ends here<<<<<<<<<<<<<<<<<<<<<
void setup() {
//////////////Start Serial for
Debugging/////////////////////
From here we move down in to the main
loop and find “////checking the light status//////” where we add:
//////////////////checking the light
status//////////////////////
//>>>>>>>>>>>>>>addition
starts here<<<<<<<<<<<<<<<<<<<<<<<<<<
alpha = (analogRead(1) / 114) + 1;
//creating alpha by
//reading a trim pot
//on Arduino pin A1
sensor = analogRead(lightSensor);
//reading the photocell
sensorValue = smoothValue(sensor);
//function call to smooth the actual reading
//if you have some problems with
adjusting the light sensor,
//or you just want to know what's going
on,
//uncomment the following print
statements
//Serial.print("alpha, sensor,
Sensor value: "); //debug only
//Serial.print(alpha);
//debug only
//Serial.print(" : ");
//debug only
//Serial.print(sensor);
//debug only
//Serial.print(" : ");
//debug only
//Serial.println(sensorValue);
//debug only
//////////////////processing the
input/////////////////////
//Serial.print("Light level room
1: "); //debug only
//Serial.println(lightLevel[0]);
//debug only
//Serial.print("Light level room
4: "); //debug only
//Serial.println(lightLevel[3]); //debug only
photocellSwitch =
getSensorValue(sensorValue, //function call to check
photoCellCutOff); //if light level is within
//switching limits
//>>>>>>>>>addition
ends here<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
//////////////Holiday
lighting/////////////////////////
if(switchState[20] == 1) {
//check if the holiday switch
//is
activated
tmElements_t tm;
//initializing RTC
if(RTC.read(tm)) { //Reading the clock
currentHour = tm.Hour;
//passing the time into a var
currentMinute = tm.Minute;
//passing the time into a var
}
//>>>>>>>>>>>>addition
starts here again<<<<<<<<<<<<<<<<<
//Double check if we are within
permitted switching limits
//and flag the areas where lights
being switched,
//to prevent lights from switching
on and off when the
//light level is at the switching
limit
//covering the time from evening to
midnight
if(photocellSwitch == 1 &&
currentHour >= 17 && currentHour <= 23) {
for(int i=0; i<9; i++){
lightLevel[i] = 1;
}
lightLevel[15] = 1;
}
//covering the time from midnight
until morning
else if(photocellSwitch == 1 &&
currentHour >= 0 && currentHour <= 8){
for(int i=0; i<9; i++){
lightLevel[i] = 1;
}
lightLevel[15] = 1;
}
//if it's morning and the light
level comes above the limit
//we make sure, the lights switch
off
else if(photocellSwitch == 0 &&
currentHour >= 5 && currentHour <= 8){
for(int c=0; c<17; c++){
lightLevel[c] = 0;
}
}
//Again, if you would like to see
what's going on,
//just uncomment the following serial
print statements
//Serial.print("Light level
room 1 after: "); //debug only
//Serial.println(lightLevel[0]);
//debug only
//Serial.print("photocell
switch: "); //debug only
//Serial.println(photocellSwitch);
//debug only
//Serial.print("Light level
room 3 after: "); //debug only
//Serial.println(lightLevel[2]);
//debug only
//Serial.print("Light level
room 4 after: "); //debug only
//Serial.println(lightLevel[3]);
//debug only
//>>>>>>>>>>addition
ends here<<<<<<<<<<<<<<<<<<<<
///////Room 1 (Bed 1) /////////////
Now we need to implement the
lightLevel[n] value in the statements where we check if the lights
are to be switched on or not. There for we just go down a little
further to the single rooms. Let's have a look at room 1:
///////Room 1 (Bed 1) /////////////
if(room1MActive == 1 &&
currentHour >= room1OnM[0] &&
currentHour <= (room1OffM[0]
+ 1)){ //checking if we came passed
//the hour where the lights
//to be switched on
//checking the times
room1Lights =
checkOnTime(room1OnM[0], room1OnM[1],
room1OffM[0], room1OffM[1]);
}
if(room1O1Active == 1 &&
currentHour >= room1On1[0] &&
currentHour <= (room1Off1[0]
+1)){ //checking if we came passed
//the hour where the lights
//to be switched on
//checking the times
room1Lights =
checkOnTime(room1On1[0], room1On1[1],
room1Off1[0], room1Off1[1]);
}
if(room102Active == 1 &&
currentHour >= room1On2[0] &&
currentHour <= (room1Off2[0]
+ 1)){ //checking if we came passed
//the hour where the lights
//to be switched on
//checking the times
room1Lights =
checkOnTime(room1On2[0], room1On2[1],
room1Off2[0], room1Off2[1]);
}
//>>>>>>>>>>>>>>>>>>>>>>>>>>here
we have to add<<<<<<<<<<<<<<<<<<<<
//in the if-statement below we
currently check only
//if one of the timers is activated now
we need to check
//if we hit the defined light level to
switch on or off the lights.
//So we have to put that little
addition in the if-statement
//“ && lightLevel[0] == 1”
if(room1Lights == 1 ){ //if with
in the on time
lightOutput[0] =1;
//switch on the lights
}
else {
lightOutput[0] = 0;
//other keep them off
lightLevel[0] = 0;
}
//The above statement reads like that
after the addition:
if(room1Lights == 1 &&
lightLevel[0] == 1){ //if within the on time
lightOutput[0] =1;
//switch on the lights
}
else {
lightOutput[0] = 0;
//other keep them off
lightLevel[0] = 0;
//resetting the light level
}
////////Room 2 (Bed
2)//////////////
The same thing we have to do now for
every single room where we want to check for light levels. In that
process, I also modified the code for the outside lights a bit. Lets
just go down to the point “ ////////Outside
lights////////////////////” and there we need to change the
following statement
if(sensorValue <= photoOutsideOn
|
sensorValue <
(photoOutsideOn + 50) //checking if light is
//within photocell readings
&& outsideOnTime == 1){
lightOutput[15] = 32768;
//switching on the lights
}
else {
lightOutput[15] = 0;
//no matches, they switch off
}
to this:
if(outsideOnTime == 1 &&
lightLevel[15] == 1){
lightOutput[15] = 32768;
}
else {
lightOutput[15] = 0;
lightLevel[15] = 0;
}
You are still with me? Good, we are
nearly done for today. We just need to add a couple of functions to
make it work. Now we go all the way down to the bottom of our sketch:
//function to give the photo cell
reading a switching range
//and compare it with the preset switch
value
//returns 1 if within and 0 if not
byte getSensorValue(int sensorReading,
int switchValue) {
byte onStatus = 0;
if(sensorReading <= (switchValue +
25)){
onStatus = 1;
}
else if(sensorReading <
(switchValue + 50)){
onStatus = 0;
}
else {
onStatus = 0;
}
return onStatus;
}
The entry is the smoothed sensor
reading (sensorReading) and the preset switch value (switchValue).
The variable onStatus holds the final return value. In the first
if-statement we check if the reading hits the switch value and
switch on anyway even if the reading is 25 points higher. The next
if-statement covers the jumping around the limits and keeps the
lights off and finally if nothing else matches it is assumed that the
lights should be off.
Finally we look at the smoothing
function:
//the analog smoothing algorythm was original
//written by Tom Igoe
int smoothValue(int rawValue){
if(rawValue > smoothed) {
smoothed = smoothed + (rawValue - smoothed) / alpha;
}
else {
smoothed = smoothed - (smoothed - rawValue) / alpha;
}
return smoothed;
}
I know, it's a lot to update and I am
still working on the complete code with all the current updates to
make it a little easier to follow all the changes.
One thing is left to do. We need to add
a trim potentiometer to our breadboard to get a reference point for
smoothing of analogue readings. I used a 100K potentiometer with one
pin connected to 5V and the centre pin to pin 24 (A1) of the Atmega
chip. I adjusted the reading to approximately to the switching value
of the lights to get the best results.
No comments:
Post a Comment