Luminosity sensor activate relay only once

Hello !

I’ve got a luminosity sensor and I’ve got a problem…
I want to open and close a door with the luminosity of the outside.
I’d like to activate a relay only one time and for 2 seconds (it’s for a motor) when the value is >512.
And I want to activate another relay one time and for 2 seconds too (for the same motor in the other direction) when it’s <512.

The wiring is good but the programmation… Hum hum… I tried whith “if” and “for (int i = 1; i< 1; i++)” but it doesn’t work…
Any advices ?

Have a nice day !

CAUTION: LONG ANSWER!

For the first case…

There are several ways to do this.

One way is to have an additional variable to keep the previous value of luminosity. You want to activate the relay when the previous value of luminosity is <=512 and the current value of luminosity is >512. This is a state change and there are examples in the Arduino IDE of doing something like this.

Another way is to have an additional variable that tracks whether the relay has been activated yet. Then:
if the luminosity is >512 and the relay has not been activated, activate it.
if the luminosity is >512 and the relay has been activated, do nothing.

There may be additional ways.

The second case is similar.

There are pros and cons to these methods. It depends upon how the luminosity could vary. For example, it might go >512 and then less than 512 and then >512 during the 2 second period. What should happen then? How fast does the luminosity change? By how much?

You may want to use two thresholds with the first being larger (say, 524) than the second (say, 500) so that there are no open/close/open/close/open/close… problems like there could be with a single threshold. This is called hysteresis.

You will get additional help once your non-working code is properly posted.

To post code and/or error messages:

  1. Use CTRL-T in the Arduino IDE to autoformat your code.
  2. Paste the autoformatted code between code tags (the </> button)
    so that we can easily see and deal with your code.
  3. Paste the complete error message between code tags (the </> button)
    so that we can easily see and deal with your messages.

Before posting again, you should read the three locked topics at the top of the Programming Questions forum, and any links to which these posts point.

If your project involves wiring, please provide a schematic and/or a wiring diagram and/or a photograph of the wiring.

Good Luck!

Hi,

Can you please post a copy of your circuit, in CAD or a picture of a hand drawn circuit in jpg, png?

Can you please post a copy of your sketch, using code tags?
They are made with the </> icon in the reply Menu.
See section 7 http://forum.arduino.cc/index.php/topic,148850.0.html

What code you have will help us assist you.

Tom… :slight_smile:

I tried whith “if” and “for (int i = 1; i< 1; i++)” but it doesn’t work…

for (int i = 1;  i< 1; i++) {
// in theory do something, but will NEVER happen here
}

is guaranteed to do nothing. You initialize i to 1, then you check if it is strictly inferior to 1 - which is always false - so you don’t execute anything.

Thanks for your answers !

J-M-L I made a mistake, I mean "int i = 0".

Vaj4088, thank you for your advices, I have downloaded a tutorial "State change detection" but it doesn't really work because it's really hysteric ! :D Because has you said, the value is always different (584, 582, 590...). I wanted to put a percent of the last value of light but it won't work because the sunset is not really quick... :D

I try to translate my code with english comments and I will send a photo too. (sorry for my poor english too...)

don't worry about the comments, the code is in english - we can probably follow what you are trying to do

#define left 7 //pin of the 1st relay (motor counterclockwise)
#define right 8 // pin of the 2nd relay (motor clockwise)

int input = A0; //pin of the photoresistor
int light = 0;
int lastlight = 0;

void setup() {
  pinMode(left, OUTPUT);
  pinMode(right, OUTPUT);
  Serial.begin(9600);
  }

void loop() {
  light = analogRead(input);
  Serial.print("value =");
  Serial.print(light);

  if (light != lastlight) {
    if (light > 512)
    {
      digitalWrite(left, HIGH);
      delay(2000);
      digitalWrite(left, LOW);
    } 
    
    else if (light < 512)
    {
      digitalWrite(right, HIGH);
      delay(2000);
      digitalWrite(right, LOW);
    }
  }
  lastlight = light; //save the last value of light
}

As discussed previously you should not do

    if (light > 512)
..
    else if (light < 512)

because your relay will constantly be triggered when you are close to 512.

if would be better to do

    if (light > 530)
...
    else if (light < 500)

and in between 500 and 530 just don’t do anything, keep whatever was there before. so if light goes below 500, you close the door and if it moves to 501 just after you don’t open it again.

You don’t really want to keep the lastLight value because it will jiggle a bit. What you want to memorize is probably the status of your door.

boolean doorIsClosed;

You probably want to initialize your door open for example and set LOW your motor controls just for sanity

in setup()

      digitalWrite(right, LOW);

      digitalWrite(left, HIGH);
      delay(2000);
      digitalWrite(left, LOW);
      doorIsClosed = false;

then in the code instead of doing if (light != lastlight) {

you check

    if (light > 530 && doorIsClosed)
...
    else if (light < 500 && !doorIsClosed)

of course don’t forget to set doorIsClosed to the right value once you have moved the motor.

as a side comment for your code - you should define your pins as const because they don’t change

const int input = A0; //pin of the photoresistor

and to be consistent with the other pin declarations you could #define it (or const int the others)

#define input A0  //pin of the photoresistor

Also best is to use meaningful variable names, so I would call them lightSensorPin and counterclockwiseMotorPin and clockwiseMotorPin for the others

There is an implicit convention that variables start with a lower case and following words start with an upper case so lastlight would be better as lastLight

Wow ! Thank you for this big answer !

I will try !

But I have found another trick and it works, I’ve put a limit switch but With the status “boolean doorIsClosed;” I don’t need a limit switch isn’t it ?

Here is my new code but I will try with the status door

int left = 7; //pin of the 1st relay (motor counterclockwise)
int right = 8; // pin of the 2nd relay (motor clockwise)

int input = A0; //pin of the photoresistor
int light = 0;
const int buttonPin = 4;
int buttonState = 0;
int seuil = 512; // I have to put it in place of all "512" below

void setup() {
  pinMode(left, OUTPUT);
  pinMode(right, OUTPUT);
  pinMode(buttonPin, INPUT);
  Serial.begin(9600);
}

void loop() {
  buttonState = digitalRead(buttonPin);
  light = analogRead(input);
  Serial.print("value =");
  Serial.print(light);

  if ((light > 512) && (buttonState == HIGH))
  {
    delay(20);
  }
  else if ((light < 512) && (buttonState == LOW))
  {

    delay(20);

  }
  else if ((light > 512) && (buttonState == LOW))
  {
    digitalWrite(left, HIGH);
    delay(2000);
    digitalWrite(left, LOW);
  }

  else if ((light < 512) && (buttonState == HIGH))
  {
    digitalWrite(right, HIGH);
    delay(2000);
    digitalWrite(right, LOW);
  }

}

Hey your code works ! But I don’t why, the 2 red leds of the relay module work when nothing happen…

int left = 7; //pin of the 1st relay (motor counterclockwise)
int right = 8; // pin of the 2nd relay (motor clockwise)

int input = A0; //pin of the photoresistor
int light = 0;
boolean doorIsClosed;

void setup() {
  pinMode(left, OUTPUT);
  pinMode(right, OUTPUT);
  Serial.begin(9600);
  digitalWrite(right, LOW);
  digitalWrite(left, LOW);
}

void loop() {

  light = analogRead(input);
  Serial.print("value =");
  Serial.print(light);

  if ((light > 512) && (!doorIsClosed))      //clair et porte ouverte
  {
    digitalWrite(right, LOW);
    digitalWrite(left, LOW);
  }
  else if ((light < 512) && (doorIsClosed))  //noir et porte fermée
  {
      
    digitalWrite(right, LOW);
    digitalWrite(left, LOW);
  }
  else if ((light > 512) && (doorIsClosed))   //clair et porte fermée
  {
    digitalWrite(right, LOW);
    digitalWrite(left, HIGH);
    delay(2000);
    digitalWrite(left, LOW);
    doorIsClosed = false;
  }

  else if ((light < 512) && (!doorIsClosed))   {
    digitalWrite(left, LOW);
    digitalWrite(right, HIGH);
    delay(2000);
    digitalWrite(right, LOW);
    doorIsClosed = true;
  }

}

I repeat a lot but i want to be sure that the 2 relays are not activated at the same time but they are always red…

if you use a limit switch that’s even better… then you don’t need to get the motor to work for 2 seconds which is probably an approximation, you know it’s closed when the switch activates.

My boolean is just a trick to memorize the state, which you forgot to initialize in the set up as I had suggested :slight_smile:

the

  if ((light > 512) && (!doorIsClosed))      //clair et porte ouverte
...
  else if ((light < 512) && (doorIsClosed))  //noir et porte fermée

are useless, they do nothing but just wait… it’s not necessary… get rid of them

Why do you insist on maintaining just 512… we have explained a couple times already, and you will find out soon enough, that the value you will get from analogRead will fluctuate around 512 when it’s about time to open or close the door… if you don’t keep a gap between the 2 values, your door will constantly open/close open/close for a while until it’s real dark or real day… that’s why we suggest to close the door if <500 and open it if >530 for example. the 30 units difference won’t be tested for in your code so the door will stay wherever it has been set while the value oscillate around 512

you should trust your code, that the left and right pins will always end up LOW when the code executes, so there is no need to set the one that is not used to LOW when you start operating the relay.

You should use the const int type for the pins definition

const int left = 7; //pin of the 1st relay (motor counterclockwise)
const int right = 8; // pin of the 2nd relay (motor clockwise)
const int input = A0; //pin of the photoresistor

(and as suggested above, use better variable names)

Your LEDs stay on because you wired your relay incorrectly - aren’t you intrigued by all the cables at the output of the 2 relays… Why are you connecting both the Normally Open and the Normaly Closed terminals?

(not sure my indications are for the right relay, but this is the idea of a relay. when the command is HIGH the normally Open socket is connected to the central wire, when it’s low it’s disconnected - just like an interruptor. on the other side, the normally closed one, when the command is LOW the socket is connected to the center wire, and when it is HIGH it’s disconnected)

Only one side of the connector should be used otherwise your relay is always connecting the central wire to a wire on the side and thus your LED is ON.

So I’m unsure what is at the end of those cables, but BE SUPER CAREFUL. it’s not wired the right way and current might go through your system all the time depending on what is at the end of those cables on both sides… Don’t touch those wires (And they seem a little small for high power compared to the thickness of the one connected to the motor. What V / I are you needing for the motor??)

Hi,

[u]Can you please post a copy of your circuit, in CAD or a picture of a hand drawn circuit in jpg, png?[/u]

PLEASE!! ! So we can see ALL your connections and how you have powered the project.

Tom.... :)

Thanks again for all these advices and details.

For the 512, I haven’t change yet because I wanted to test quickly with the shadow of my hand. I agree and I understand that light won’t change quickly so I think that 30 (between 530 and 500) is a good idea and i will test it)

I have to change the variable names too.

I think that the limit switch is a better idea too.

The 2 big green wires are for the 12 v DC motor (an old motor of a garage door). It’s powered by a 12v 500mA power supply (don’t worry ! :D). I have made a sort of H-bridge with my 2 relay. Is the wiring correct ?
(as you can see on the new picture)

Thanks again !!!

Oh - i see - I already feel a little bit better about it but still… :slight_smile:

are those yellow-ish cables on the NC side of the relay? → the NC part of the relays should be bringing both motor leads to ground and not the 12v rail to deal with gently sending to ground the counter current generated by the magnetic field of the motor not wanting to collapse when the motor is told to stop spinning suddenly. A Freewheel or Fly back diode across the motor poles would also be a good idea to protect the relays

Another thing is that 6W in a small breadboard is a risk (depending on the quality of your breadboard but yours looks like the basic type - would not go more than 3 o 4W especially on adjacent rows). You should probably just connect into Non-Fused Terminal Block - that will be safer and use wires with size similar to those attached to the motor. Stick together the 2 NC side wires from the relay on one end a terminal block and the GND of your 12V power supply on the other side and similarly with the live wire (and have a switch for quick shut off)

And the reason the LEDs are always on is that you have something connected on both sides which is unusual.

Yes the limit switch is the way to go - you probably need 2, one when door is open and one when door is closed.

The drawback of this approach is that Relays don’t allow for speed adjustment (like MOSFETs would do) and are less durable. Such relays are rated for a certain number of on/off cycles because breaking load current causes undesired arcing between the contacts, eventually leading to contacts that weld shut or contacts that fail due erosion by the arc. But worse in your case: manufacturers specify how long their relays will last, but the expected lifetime will vary depending on the loads they are subjected to. For resistive loads, manufacturers’ specifications are typically accurate but driving capacitance or inductance, your relay life span will be shorter than the manufacturers specification. How much shorter depends on the type of loads you are switching. In the industry they “de-rate” to get a realistic expectation of how long your relay will last and motors are the worst… When an electric motor starts up, it has very low impedance and requires a large in-rush current to begin building a magnetic field and begin rotating. Once it is running, it generates a back electromagnetic force (emf), which can cause a large inductive spike when the switch is opened. The result is a large in-rush current at “turn-on” and arcing at “turn-off.” ==> When you are switching a motor load, typical industry practice is to derate to 20 percent of the manufacturer rating…(the good news is that this is still probably many ten thousands times :slight_smile: )

Terminal Block is a “bornier domino” in French (just in case :slight_smile: )

tryptophane:
I’d like to activate a relay only one time and for 2 seconds (it’s for a motor) when the value is >512.
And I want to activate another relay one time and for 2 seconds too (for the same motor in the other direction) when it’s <512.

Well, that’s going to cause problems when the luminosity is about exactly around 512. Fluctuations will make your door open-close-open.

It’s better to have some hysteresis. Door opens when liminosity is > 520, closes when it’s < 504 for instance.

10 000 times ! My chickens will already be eaten ! Christmas isn't so far... :D

I have chosen the relay solution because I fear that a driver "L298N H-bridge" could heat. No ?

I didn't know that it was only for 3 - 4 W... I will change the wires and take a terminal block.

For the diode, which one can I use ? I've got a 1N4001. Is it OK ? I have to wire like this I suppose... (to block the current in the other direction)

|500x473