Day/Night LDR sensing code. What is the correct approach to sampling day/night.

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.

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.

trouble:
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:

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
}

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?

/*
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);
}

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

Boy this coding is hard, but FUN!

A million ways to do something...

/*
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);
}

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

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

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.

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

I realize this is an old post, but I hope you still participate. these questions are along the line of the same thing I would like to accomplish. and I "may" be able to afford you. we'll see! I build analog components, I am new to the arduino forum. I am looking for help in respect to turning an arduino nano ON, using a LDR. basically, on at night, off at day light. if you are still alive and participating please post.

Fredric58:
I realize this is an old post, but I hope you still participate. these questions are along the line of the same thing I would like to accomplish. and I "may" be able to afford you. we'll see! I build analog components, I am new to the arduino forum. I am looking for help in respect to turning an arduino nano ON, using a LDR. basically, on at night, off at day light. if you are still alive and participating please post.

Well, I am alive. But you are hijacking the thread. Please start your own thread, and explain in more detail what you are trying to accomplish. Since you haven't started yet, it would be better to use the "project guidance" section.