Pages: [1]   Go Down
Author Topic: Day/Night LDR sensing code. What is the correct approach to sampling day/night.  (Read 1221 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 3
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi everyone.  Have never asked for help on a forum yet, but I am trying to become better at coding.  So i have decided to try to seek advice on the best way to approach coding problems.

I have made a day/night movement activated light.  http://tobyrobb.com/wordpress/?p=397

I of course have kept the code simple. If the LDR is below a set value,, check the movement sensor if HIGH, turn on the light.

SO the problem is as it starts to go from light to dark the LDR value floats around the right amount, and turns the light on, but then back off , then on etc oscillating a few times as it darkens.

I know I should sample, then wait and sample again, then when its clear that it's ACTUALLY dark, move onto the movement sensing routine.

SO then what? DO i periodically check if it is still dark or now light? and if so, the delay involved means the light wont be working whiles its doing that.  And if its a routine that waits a bit between samples then the problem is exacerbated.

So can anyway tell me the right way to do it in software of course..

Thanks in advance..

Toby.
Logged

Sydney, Australia
Offline Offline
Edison Member
*
Karma: 33
Posts: 1287
Big things come in large packages
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Posting your code would help.

In general I would say that you want to include some lag or dampening in the way that the software wants to react to sensor changes.

One way is to use an averaged value for the sensor reading (say n seconds worth of data, or x readings). Alternatively only add on some fraction (say 30%) of the difference between the current sensor reading and the previous one. Both of these will dampen the changes and should provide smoother changes.

Once you have done this, then set a limit (HI) when the light will switch on and a limit (LO) when the light will switch off, with LO < HI (ie, don't use the same value). This difference will make sure that once the light is on it will need to get a lot less dark before it switches off avoiding the problem that you are seeing with it coming on and off.
Logged

Arduino libraries http://arduinocode.codeplex.com
Parola hardware & library http://parola.codeplex.com

UK
Offline Offline
Shannon Member
****
Karma: 223
Posts: 12630
-
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

So can anyway tell me the right way to do it in software of course..

I suggest you add some hysteresis to your dawn / dusk thresholds. Your current code doesn't record whether it's currently 'dark' or 'light' so I suggest you add a state variable to record that and only change state when the light level cross the threshold by some margin.

For example:

Code:
boolean dark = false;
const int DAWN = 510;
const int DUSK = 490;

if(light)
{
  if(analogRead(ldr) < DUSK)
  {
    dark = true;
    // stuff to do when it changes from light to dark
  }
}
else
{
  if(analogRead(ldr) > DAWN)
  {
    dark = false;
    // stuff to do when it changes from dark to light
  }
}
if(dark)
{
  // stuff to do while it's dark
}
else
{
  // stuff to do while its light
}
Logged

I only provide help via the forum - please do not contact me for private consultancy.

Offline Offline
Newbie
*
Karma: 0
Posts: 3
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks guys that was great. I'm glad i asked.

 I went with an integer value that increments when the test shows the light is bright, and decrements when the light is low.  It is held within an upper and lower limit.

The main  problem was that while testing the light value there needs to be a delay before testing again. During this delay i wanted to be able to continue to function.

So i chose to use the millis() function to test every few seconds or so and then increment or decrement the value.

Then the code loops through different scenarios based on the current value.

Pretty messy probably..



So i take it most of you use a BOOLEAN type logic state that you flip during the day/night testing function? Then when looping through the other code, make decisions based on the current BOOLEAN state?

I think I went overboard and i really have a double HYSTERISIS going on, i will probably drop the integer value in favour of the BOOLEAN type state?


Code:




/*
Day night IR sensor shield 11/08/12 Trobb
 
 Please enjoy my dodgy code!
 
 I am not a programmer by any means!
 
 Feel free to improve on it!
 
 Check out http://www.tobyrobb.com
 
 Written with Arduino IDE V.1.0.1

 DEBUG VERSION!!!!
 
 */

#include <avr/wdt.h>

#define ldr A0    // LDR light sensor
#define ir A1      // IR movement sensor pin 
#define timerPot A2  // Pin the timer potentiometer is connected to

#define watchdogPin 3  // Uncomment this line to have a pin blink to let us know the code is running

#define led 3     // Output for LED

#define gain 10  // the amount of gain to add to the timerPot 10 is a normal value


int luxVal = 150;    // Value to trigger the low light condition
float timerValue;   // A variable to hold the value of the delay on time
float timerDelay;
int dark = 0;
long previousMillis = 0;        // will store last time LED was updated

long interval = 1000;           // interval at which to check the LDR (milliseconds)



void setup() {

  // initialize the IO.

//  pinMode(watchdogPin, OUTPUT);  //      Uncomment this line to have a different pin blink to let us know the code is running

  pinMode(led, OUTPUT);     
  pinMode(ir, INPUT);
  pinMode(ldr, INPUT);     


  digitalWrite(led, LOW);   // start with LED off

  Serial.begin(9600);

  wdt_reset();    //make sure we reset watchdog timer to prevent endless resetting

  //  Uncomment this section to have a pin blink to let us know the code is running
  // blink some morse code OK

  digitalWrite(watchdogPin, HIGH);   // blink watchdog led
  delay(500);
  digitalWrite(watchdogPin, LOW); 
  delay(500);
  digitalWrite(watchdogPin, HIGH);   // blink watchdog led
  delay(500);
  digitalWrite(watchdogPin, LOW); 
  delay(500);
  digitalWrite(watchdogPin, HIGH);   // blink watchdog led
  delay(500);
  digitalWrite(watchdogPin, LOW);
  delay(1500);
  digitalWrite(watchdogPin, HIGH);   // blink watchdog led
  delay(500);
  digitalWrite(watchdogPin, LOW); 
  delay(500);
  digitalWrite(watchdogPin, HIGH);   // blink watchdog led
  delay(250);
  digitalWrite(watchdogPin, LOW); 
  delay(500);
  digitalWrite(watchdogPin, HIGH);   // blink watchdog led
  delay(500);
  digitalWrite(watchdogPin, LOW); 



  Serial.println("Setup complete");


}

void loop() {

  wdt_reset();    //make sure we reset watchdog timer to prevent endless resetting

  // Lets print some debugging values to the console

  Serial.print("Current ldr reading is ");
  Serial.println(analogRead(ldr));
  Serial.print("Current sensor value ");
  Serial.println(digitalRead(ir));
  Serial.print("Current timer value is ");
  Serial.println(analogRead(timerPot));
  wdt_reset();    //make sure we reset watchdog timer to prevent endless resetting

  // Now check for darkness or daylight and movement

  checkLdr();

    // so long as its dark
 
  while(dark <=0){   
 

    Serial.println("Its dark");

    // and movement is detected
    if(digitalRead(ir) == 1){
      Serial.println("Movement detected");
      digitalWrite(led, HIGH);       // turn led on
      Serial.println("LED is ON");
   
      // now leave light on for a predetermined time
       
     timerValue = analogRead(timerPot);     
     timerDelay = timerValue * (timerValue / gain);  // times the value by itself divided by gain
     
     Serial.println(timerDelay);
 
     
      float i = timerDelay;            // set timer variable
      while(i >=0){         
        i --;
        Serial.print("Timing out ");
        Serial.println(i);
        checkLdr();                    // run the the check LDR routine to see if it is still dark.
        if(dark<=0){
          return;
        }
        wdt_reset();    //make sure we reset watchdog timer within the loop to prevent endless resetting
      }
    }

    else{ 
      Serial.println("No movement");                             // no movement detected so turn led off
      digitalWrite(led, LOW);       // turn led off
      checkLdr();
      wdt_reset();    //make sure we reset watchdog timer to prevent endless resetting
    }

  }


  // not dark enough yet

    Serial.println("still not dark enough");

  digitalWrite(led, LOW);       // turn led off
  wdt_reset();    //make sure we reset watchdog timer to prevent endless resetting
}



void checkLdr(){
 
  // check to see if it's time to read the LDR;
 
  // difference between the current time and last time
 
  unsigned long currentMillis = millis();
 
  if(currentMillis - previousMillis > interval) {
    // save the last time you checked the LDR
    previousMillis = currentMillis;   

  Serial.println("Checking LDR");
   
  if(analogRead(ldr)>=luxVal){
   
    dark++;
   
    }
if(analogRead(ldr)<=luxVal){
   
    dark--;
   
    }
if(dark>=5){
  dark = 5;
   
    }
if(dark <=-5){
  dark = -5;
}
}
Serial.print("Current dark reading is ");
Serial.println(dark);
}
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 3
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

OK gone to a logic type switching, hopefully a little smarter.

Boy this coding is hard, but FUN!

A million ways to do something...

Code:


/*
Day night IR sensor shield 11/08/12 Trobb
 
 Please enjoy my dodgy code!
 
 I am not a programmer by any means!
 
 Feel free to improve on it!
 
 Check out http://www.tobyrobb.com
 
 Written with Arduino IDE V.1.0.1

 DEBUG VERSION!!!!
 
 */

#include <avr/wdt.h>

#define ldr A0    // LDR light sensor
#define ir A1      // IR movement sensor pin 
#define timerPot A2  // Pin the timer potentiometer is connected to

#define watchdogPin 3  // Uncomment this line to have a pin blink to let us know the code is running

#define led 3     // Output for LED

#define gain 10  // the amount of gain to add to the timerPot 10 is a normal value

boolean running = false;  // BOOLEAN value to decide wether we are dark and running

int DUSK = 150;    // Value to trigger the low light condition
int DAWN = 170;    // Value to trigger the bright light condition

float timerValue;   // A variable to hold the value of the delay on time
float timerDelay;
int dark = 0;
long previousMillis = 0;        // will store last time LED was updated

long interval = 3000;           // interval at which to check the LDR (milliseconds)



void setup() {

  // initialize the IO.

//  pinMode(watchdogPin, OUTPUT);  //      Uncomment this line to have a different pin blink to let us know the code is running

  pinMode(led, OUTPUT);     
  pinMode(ir, INPUT);
  pinMode(ldr, INPUT);     


  digitalWrite(led, LOW);   // start with LED off

  Serial.begin(9600);

  wdt_reset();    //make sure we reset watchdog timer to prevent endless resetting

  //  Uncomment this section to have a pin blink to let us know the code is running
  // blink some morse code OK

  digitalWrite(watchdogPin, HIGH);   // blink watchdog led
  delay(500);
  digitalWrite(watchdogPin, LOW); 
  delay(500);
  digitalWrite(watchdogPin, HIGH);   // blink watchdog led
  delay(500);
  digitalWrite(watchdogPin, LOW); 
  delay(500);
  digitalWrite(watchdogPin, HIGH);   // blink watchdog led
  delay(500);
  digitalWrite(watchdogPin, LOW);
  delay(1500);
  digitalWrite(watchdogPin, HIGH);   // blink watchdog led
  delay(500);
  digitalWrite(watchdogPin, LOW); 
  delay(500);
  digitalWrite(watchdogPin, HIGH);   // blink watchdog led
  delay(250);
  digitalWrite(watchdogPin, LOW); 
  delay(500);
  digitalWrite(watchdogPin, HIGH);   // blink watchdog led
  delay(500);
  digitalWrite(watchdogPin, LOW); 



  Serial.println("Setup complete");


}

void loop() {

  wdt_reset();    //make sure we reset watchdog timer to prevent endless resetting

  // Lets print some debugging values to the console

  Serial.print("Current ldr reading is ");
  Serial.println(analogRead(ldr));
  Serial.print("Current sensor value ");
  Serial.println(digitalRead(ir));
  Serial.print("Current timer value is ");
  Serial.println(analogRead(timerPot));
  wdt_reset();    //make sure we reset watchdog timer to prevent endless resetting

  // Now check for darkness or daylight and movement

  checkLdr();

    // so long as its dark
 
  while(running){   
 

    Serial.println("Its dark");

    // and movement is detected
    if(digitalRead(ir) == 1){
      Serial.println("Movement detected");
      digitalWrite(led, HIGH);       // turn led on
      Serial.println("LED is ON");
   
      // now leave light on for a predetermined time
       
     timerValue = analogRead(timerPot);     
     timerDelay = timerValue * (timerValue / gain);  // times the value by itself divided by gain
     
   
      float i = timerDelay;            // set timer variable
      while(i >=0){         
        i --;
       
        Serial.println(i);
        checkLdr();                    // run the the check LDR routine to see if it is still dark.
        if(!running){
          return;
        }
        wdt_reset();    //make sure we reset watchdog timer within the loop to prevent endless resetting
      }
    }

    else{ 
      Serial.println("No movement");                             // no movement detected so turn led off
      digitalWrite(led, LOW);       // turn led off
      wdt_reset();    //make sure we reset watchdog timer to prevent endless resetting
    }

  }


  // not dark enough yet

    Serial.println("still not dark enough");

  digitalWrite(led, LOW);       // turn led off
  wdt_reset();    //make sure we reset watchdog timer to prevent endless resetting
}



void checkLdr(){
 
  // check to see if it's time to read the LDR;
 
  // difference between the current time and last time
 
  unsigned long currentMillis = millis();
 
  if(currentMillis - previousMillis > interval) {
    // save the last time you checked the LDR
    previousMillis = currentMillis;   

  Serial.println("Checking LDR");
   
  if(analogRead(ldr)>=DAWN){
   
     running = false;
   
    }
if(analogRead(ldr)<=DUSK){
   
    running = true;
   
    }

}
Serial.print("Current dark reading is ");
Serial.println(running);
}
Logged

Offline Offline
Faraday Member
**
Karma: 62
Posts: 3080
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Once you have decided that it is night,   don't even consider making it "day" again,  until 8 hours have passed.
Logged

Pakistan
Offline Offline
Sr. Member
****
Karma: 6
Posts: 357
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

haha,... provided there are no clouds or no bird stands on the sensor eye;)
Logged


Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 653
Posts: 50881
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I think that what you are looking for is hysteresis. The dark/light threshold might be a single value, but you want to avoid the oscillation about that value.

Think about how a thermostat works. The temperature in the room falls below the setpoint. The thermostat turns the furnace on. The temperature starts to rise again. But, the thermostat does not shut the furnace off as soon as the temperature gets to the setpoint. Instead, it waits for the temperature to get a small amount above the setpoint before turning the furnace off.

You probably want to do the same. If the light level is dropping, and triggers the dark action, you don't want to trigger the light action until the light level is slightly above the setpoint, unless, perhaps, it has been awhile since the dark/light transition occurred.
Logged

Venezuela
Offline Offline
Jr. Member
**
Karma: 2
Posts: 81
The less You explain, the more I understand
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi, Khilid; I appreciate your sincerity " Simply... You can´t afford me " smiley-grin
Logged

Pages: [1]   Go Up
Jump to: