Control 4 channel relay with 4 IR sensors independently

const int relay1 = 3;
const int relay2 = 4;
const int relay3 = 5;
const int relay4 = 6;


const int sensor1 = 8;
const int sensor2 = 9;
const int sensor3 = 10;
const int sensor4 = 11;



void setup() {

  pinMode(relay1, OUTPUT);
  pinMode(relay2, OUTPUT);
  pinMode(relay3, OUTPUT);
  pinMode(relay4, OUTPUT);


  pinMode(sensor1, INPUT);
  pinMode(sensor2, INPUT);
  pinMode(sensor3, INPUT);
  pinMode(sensor4, INPUT);


  digitalWrite(relay1, LOW);
  digitalWrite(relay2, LOW);
  digitalWrite(relay3, LOW);
  digitalWrite(relay4, LOW);

}

void loop() {
  // read the state of the the input pin:
  int sensor1 = digitalRead(8);
  int sensor2 = digitalRead(9);
  int sensor3 = digitalRead(10);
  int sensor4 = digitalRead(11);



  if (sensor1 == HIGH)
    digitalWrite(relay1, HIGH);
  else digitalWrite(relay1, LOW);

  if (sensor2 == HIGH)
    digitalWrite(relay2, HIGH);
  else digitalWrite(relay2, LOW);

  if (sensor3 == HIGH)
    digitalWrite(relay3, HIGH);
  else digitalWrite(relay3, LOW);

  if (sensor4 == HIGH)
    digitalWrite(relay4, HIGH);
  else digitalWrite(relay4, LOW);

  delay(6000);

}

Arduino UNO
4 relay module 5V
IR sensor MH-8
``
I've got a fairly simple question here. The issue I am having is that I'm trying to trigger one relay at a time from an IR sensor for 6 seconds. I can get it to run in a loop just fine but only one relay triggers at a time. I would like to be able to trigger all 4 of the relays independently without it waiting for the last relay to finish its 6 second cycle. Can anyone help please?

Welcome to the forum

Your problem is caused by the use of the delay() function which stops anything else happening whilst the delay occurs. You need to use non blocking timing

See Using millis() for timing. A beginners guide, Several things at the same time and the BlinkWithoutDelay example in the IDE

1 Like

Do you know what happens when this executes ? delay(6000)

Thanks, yep copy that. I understand i needed something like millis but am not sure how to use it accordingly. The "BlinkWithoutDelay" doesn't really give much. Do millis go after each relay command? 1,2,3, and 4?

Although it's not the cause of your problem, I noticed that you declared the global variables sensor1 - sensor4 as the pin numbers, then redefined them as the local variables that hold the state of those pins.

As for your delay problem, I suggest using millis() instead of delay() as that doesn't stop everything.

There are quite a few examples on-line explaining how, like for example https://www.thegeekpub.com/276826/how-to-use-millis-instead-of-delay

try something like this:

define variables

unsigned long relay1start;
unsigned long relay2start;
unsigned long relay3start;
unsigned long relay4start;

then in your loop:

if (sensor1 == HIGH) {
digitalWrite(relay1, HIGH);
relay1start = millis(); }
else if ((relay1start + 6000) < millis())
digitalWrite(relay1, LOW);

and repeat for the other three.
And of course, remove the delay(6000);

The other thing I would do, although it won't change the functionality, is to delete these:

// read the state of the the input pin:
  int sensor1 = digitalRead(8);
  int sensor2 = digitalRead(9);
  int sensor3 = digitalRead(10);
  int sensor4 = digitalRead(11);

And replace the first line of each test with:

if digitalRead(sensor1) {

Yep I understand it stops the loop for however the amount of time set. I guess I need to use milliseconds instead….

This is good stuff! Thanks. So I'll remove the int sensor1 = digitalRead(8); 9, 10, and 11 as well since it is unnecessary. As far as replacing it with if digitalRead(sensor1) { . You mention replacing the first line of each test? Can you clarify where it goes. Forgive my beginner questions.
Thanks,

Instead of:

if (sensor1 == HIGH) {
digitalWrite(relay1, HIGH);
relay1start = millis(); }
else if ((relay1start + 6000) < millis())
digitalWrite(relay1, LOW);

Use:

if (digitalRead(sensor1)) {
digitalWrite(relay1, HIGH);
relay1start = millis(); }
else if ((relay1start + 6000) < millis())
digitalWrite(relay1, LOW);

Hi @imrunner ,

Welcome to the forum..
Looks like you're getting some great feedback already..
You know, maybe a good time to learn about arrays..
Give this a look over..



const byte relays[] = {3, 4, 5, 6};
const byte sensors[] = {8, 9, 10, 11};
unsigned long relayStart[4];


void setup() {
  for (int i = 0; i < sizeof(relays); i++) {
    pinMode(relays[i], OUTPUT);
    digitalWrite(relays[i], LOW);
    pinMode(sensors[i], INPUT);
  }
}

void loop() {

  for (int i = 0; i < sizeof(sensors); i++) {
    if  (digitalRead(sensors[i]) == HIGH) {
      digitalWrite(relays[i], HIGH);
      relayStart[i] = millis();
    } else {
      if ((relayStart[i] + 6000) < millis())
        digitalWrite(relays[i], LOW);
    }
  }
}

have fun.. ~q

1 Like

Gotcha, thanks. So with all corrections made, it compiles ok but the function is backwards. Once the IR sensor is triggered, the relay doesn't come on until 6 seconds. I would like the relay to come on immediately after the IR sensor is triggered and then stay on for 6 secs. While being able to trigger the other relays at the same time as well. Here's the updated code:

unsigned long relay1start;
unsigned long relay2start;
unsigned long relay3start;
unsigned long relay4start;

const int relay1 = 3;
const int relay2 = 4;
const int relay3 = 5;
const int relay4 = 6;


const int sensor1 = 8;
const int sensor2 = 9;
const int sensor3 = 10;
const int sensor4 = 11;



void setup() {

  pinMode(relay1, OUTPUT);
  pinMode(relay2, OUTPUT);
  pinMode(relay3, OUTPUT);
  pinMode(relay4, OUTPUT);


  pinMode(sensor1, INPUT);
  pinMode(sensor2, INPUT);
  pinMode(sensor3, INPUT);
  pinMode(sensor4, INPUT);


  digitalWrite(relay1, LOW);
  digitalWrite(relay2, LOW);
  digitalWrite(relay3, LOW);
  digitalWrite(relay4, LOW);

  int sensor1 = digitalRead(8);
  int sensor2 = digitalRead(9);
  int sensor3 = digitalRead(10);
  int sensor4 = digitalRead(11);

}

void loop() {

  if (digitalRead(sensor1) == HIGH) {
    digitalWrite(relay1, HIGH);
    relay1start = millis();
  }
  else if ((relay1start + 6000) < millis())
    digitalWrite(relay1, LOW);



  if (digitalRead(sensor2) == HIGH) {
    digitalWrite(relay2, HIGH);
    relay2start = millis();
  }
  else if ((relay2start + 6000) < millis())
    digitalWrite(relay2, LOW);



  if (digitalRead(sensor3) == HIGH) {
    digitalWrite(relay3, HIGH);
    relay3start = millis();
  }
  else if ((relay3start + 6000) < millis())
    digitalWrite(relay3, LOW);


  if (digitalRead(sensor4) == HIGH) {
    digitalWrite(relay4, HIGH);
    relay4start = millis();
  }
  else if ((relay4start + 6000) < millis())
    digitalWrite(relay4, LOW);


}

Hi thanks. Yeah this might be what I'm looking for too. Would millis work or better to use arrays?

You're welcome..
Actually only difference is using arrays..
but it does also use millis, should be functionally the same as your code..
Curious, I see that in your testing the relay operation is reversed??
If it does, sounds like the relays are LOW triggered, do they activate during setup??
If yes, then you need to reverse the relay logic, current assumption is HIGH activates relay..

good luck.. ~q


  if (digitalRead(sensor1) == HIGH) {
    digitalWrite(relay1, HIGH);
    relay1start = millis();
  }

As long as sensor1 is HIGH, relay1start is made equal to millis(); is this what you want ?

If you remove this from your setup, all should be okay:

int sensor1 = digitalRead(8);
  int sensor2 = digitalRead(9);
  int sensor3 = digitalRead(10);
  int sensor4 = digitalRead(11);

The problem here is that you are assigning the state of the sensor to the variable, whereas it should be the pin number. You check the value later in the loop in the - if (digitalRead(sensor1)) { - line.

Yes, that's correct. The time starts the last time the sensor was active.

if (digitalRead(sensor1) == HIGH) {  // checking the value of sensor 1 and processes the instructions between the curly brackets that follow.  By the way, since the results can only be 0 or 1, the "== HIGH" isn't really necessary.
    digitalWrite(relay1, HIGH);  // turns relay 1 on
    relay1start = millis();  // assigns the current "time" to the variable relay1start
  }
  else if ((relay1start + 6000) < millis()) // else means if the sensor input is not active, check to see if it has been more than 6 seconds past the "time" recorded in the variable relay1start.
    digitalWrite(relay1, LOW);  // if it has been more than 6 seconds, turn the relay off.

Assumption, a HIGH to a relay energizes that relay.

  • many relay modules need a LOW :thinking:

So we are extending the time the relay is energized by 6 seconds ?


OP

  • Always show us a good schematic of your proposed circuit.

  • Show us a good image of your ‘actual’ wiring.

  • Give links to components.

This should work

unsigned long relay1start;
unsigned long relay2start;
unsigned long relay3start;
unsigned long relay4start;

const int relay1 = 3;
const int relay2 = 4;
const int relay3 = 5;
const int relay4 = 6;

const int sensor1 = 8;
const int sensor2 = 9;
const int sensor3 = 10;
const int sensor4 = 11;

void setup() {
  pinMode(relay1, OUTPUT);
  pinMode(relay2, OUTPUT);
  pinMode(relay3, OUTPUT);
  pinMode(relay4, OUTPUT);

  pinMode(sensor1, INPUT);
  pinMode(sensor2, INPUT);
  pinMode(sensor3, INPUT);
  pinMode(sensor4, INPUT);

  digitalWrite(relay1, LOW);
  digitalWrite(relay2, LOW);
  digitalWrite(relay3, LOW);
  digitalWrite(relay4, LOW);
}

void loop() {
  if (digitalRead(sensor1)) {
    digitalWrite(relay1, HIGH);
    relay1start = millis();
  }
  else if ((relay1start + 6000) < millis())
    digitalWrite(relay1, LOW);

  if (digitalRead(sensor2)) {
    digitalWrite(relay2, HIGH);
    relay2start = millis();
  }
  else if ((relay2start + 6000) < millis())
    digitalWrite(relay2, LOW);

  if (digitalRead(sensor3)) {
    digitalWrite(relay3, HIGH);
    relay3start = millis();
  }
  else if ((relay3start + 6000) < millis())
    digitalWrite(relay3, LOW);

  if (digitalRead(sensor4)) {
    digitalWrite(relay4, HIGH);
    relay4start = millis();
  }
  else if ((relay4start + 6000) < millis())
    digitalWrite(relay4, LOW);
}

Hello imrunner

Welcome to the worldbest Arduino forum ever.

I´v made a small code review.

In general - Arrays and structs are your friends.
Don't duplicate code in your sketch. Write code once - use it multiple times.
You should not use magic numbers. The I/O pins love to have a functional name.

Do you have experience with programming in C++?

The task can easily be realised with an object.
A structured array contains all information, such as pin addresses for the I/O devices, as well as the information for the timing.
A single service takes care of this information and initiates the intended action.
The structured array makes the sketch scalable until all I/O pins are used up without having to adapt the code for the service.
It is cool stuff, isn´t it?

Have a nice day and enjoy coding in C++.

In setup you have this, what does this actually do ?

  digitalWrite(relay1, LOW);
  digitalWrite(relay2, LOW);
  digitalWrite(relay3, LOW);
  digitalWrite(relay4, LOW);

:woozy_face:

  • When a Sensor reads as a HIGH what does this mean ?

  • What does this actually do ? digitalWrite(relay1, HIGH);


When the Sensor reads as a LOW, what do you want to happen ?


  • Always show us a good schematic of your proposed circuit.
  • Show us a good image of your ‘actual’ wiring.
  • Give links to components.

Finally do not use HIGH or LOW

Use something like these:

#define OBSTACLE                    HIGH   
#define noOBSTACLE                  LOW

#define RELAYon                     LOW   
#define RELAYoff                    HIGH