Relay sequencing program doubts

Hi all,

I'm new to the world of microelectronics and arduino. Over the course of last week, I've learnt basic programming and operating various devices using arduino uno. It never fails to amaze me.

I'm working on a process automation in my factory. I wish to turn relays ON and OFF in sequence for the operation to go on. Let me describe the sequence in the best manner I can.

Start of cycle: Relay1 is activated for (15 seconds). In the meanwhile relay3 needs to be activated for 7 seconds and go OFF.

After Relay1 is switched off, Relay2 needs to go wait for 5 seconds and get ON for 5 seconds and switch itself OFF. After which relay4 needs to go ON immediately and operate for 3 seconds and go OFF.

After all the operations, the entire cycle needs to be repeated.

I've made connections to the relay board using my arduino and was trying to setup the program using delay() command. I can not however, get it to work as the described sequence. I was also trying to use the millis() command but didn't quite understand it.

Please go easy on me, I'm very new to this.

Regards,

Sahil

no one will code for you unless you post your sketch, showig what you tried so far

Make a little table and put the steps in there with the states of the relays at given times based on what you described.

        relay1  relay2  relay3  relay4
 0      on      off     on      off   
 7      on      off     off     off   
15      off     off     off     off   
20      off     on      off     off   
25      off     off     off     on    
28      off     off     off     off

So do a step, delay, do the next step,delay, etc. The delays that you need are the differences between the times in the left column.

Delays are often frowned upon, but if this is the only thing that needs to happen and the times do not have to be 100% accurate (controlling the relays takes a tiny bit of time), it will do the job.

KASSIMSAMJI:
no one will code for you unless you post your sketch, showig what you tried so far

Thanks for pointing it out. Below is my code. It doesn't work too well. Please read it and let me know how can I improve.

int R1 = 9;
int R2 = 10;
int R3 = 11;
int R4 = 12;
unsigned long previousMillis = 0;
long OnTime = 7000; // milliseconds of on-time
long OffTime = 750; // milliseconds of off-time

void setup()
{
// set the digital pin as output:
pinMode(R1, OUTPUT);
pinMode(R2, OUTPUT);
pinMode(R3, OUTPUT);
pinMode(R4, OUTPUT);
}

void loop()
{

unsigned long currentMillis = millis();
digitalWrite(R1,LOW); // Turn it ON
delay(1500);
if((R1 == LOW) && (currentMillis - previousMillis >= OnTime))
{
R3 = LOW; // Turn it ON
previousMillis = currentMillis;
digitalWrite(R3, LOW);
}
digitalWrite(R2, LOW);
delay(5000);
digitalWrite(R2, HIGH);
digitalWrite(R4, LOW);
delay(3000);
digitalWrite(R4, HIGH);
}

if((R1 == LOW) && (currentMillis - previousMillis >= OnTime))

LOW equals 0, R1 equals 9. Will the condition ever be true? Maybe a digitalRead(R1) will be a better option :slight_smile:

With the intent ofyour code, why would you check if R1 is actually LOW; after all, you just have set it LOW.

As I pointed out, you don't need millis() for this. If you want to go the millis() way, you need to be consistent and read up on state machines.

sahilsahni:
Start of cycle: Relay1 is activated for (15 seconds). In the meanwhile relay3 needs to be activated for 7 seconds and go OFF.

After Relay1 is switched off, Relay2 needs to go wait for 5 seconds and get ON for 5 seconds and switch itself OFF. After which relay4 needs to go ON immediately and operate for 3 seconds and go OFF.

After all the operations, the entire cycle needs to be repeated.

Okay, this really should be in "gigs and collaborations" if you want someone to write it for you. But … try this:

/**
 * Start of cycle: Relay1 is activated for (15 seconds). 
 * In the meanwhile relay3 needs to be activated for 7 seconds and go OFF. 
 *
 * After Relay1 is switched off, Relay2 needs to go wait for 5 seconds and get 
 * ON for 5 seconds and switch itself OFF. 
 * 
 * After which relay4 needs to go ON immediately and operate for 3 seconds and go OFF. 

After all the operations, the entire cycle needs to be repeated. 

 */

const byte relay1Pin = 4;
const byte relay2Pin = 5;
const byte relay3Pin = 6;
const byte relay4Pin = 7;

struct CycleStep {
  uint32_t durationMs;
  byte relay1;
  byte relay2;
  byte relay3;
  byte relay4;
};

const CycleStep sequence[] = 
{
  {7000, HIGH,  LOW, HIGH,  LOW}, // Relay1 is activated for (15 seconds), relay3 needs to be activated for 7 seconds and go OFF
  {8000, HIGH,  LOW,  LOW,  LOW}, // Relay1 is activated for (15 seconds)
  {5000,  LOW,  LOW,  LOW,  LOW}, //  Relay2 needs to go wait for 5 seconds
  {5000,  LOW, HIGH,  LOW,  LOW}, // Relay2 get ON for 5 seconds and switch itself OFF
  {3000,  LOW,  LOW,  LOW, HIGH}, // relay4 needs to go ON immediately and operate for 3 seconds
};

const int STEPS = sizeof(sequence) / sizeof(sequence[0]);
uint32_t stepStartMs;
int currentStep = 0;

void setup() {
  pinMode(relay1Pin, OUTPUT);
  pinMode(relay2Pin, OUTPUT);
  pinMode(relay3Pin, OUTPUT);
  pinMode(relay4Pin, OUTPUT);

  currentStep = 0;
  doStep();
  stepStartMs = millis();
}

void loop() {
  if(millis() - stepStartMs >= sequence[currentStep].durationMs) {
    currentStep ++;
    if(currentStep >= STEPS) currentStep = 0;
    doStep();
    stepStartMs = millis();
  }

}

void doStep() {
  digitalWrite(relay1Pin, sequence[currentStep].relay1);
  digitalWrite(relay2Pin, sequence[currentStep].relay2);
  digitalWrite(relay3Pin, sequence[currentStep].relay3);
  digitalWrite(relay4Pin, sequence[currentStep].relay4);
}

Pay attention:
For Arduino all variables are variables, it doesn’t know if they are pins. You have to use digitalRead (pinnumber) function to know the state of a pin

PaulMurrayCbr:
Okay, this really should be in "gigs and collaborations" if you want someone to write it for you. But … try this:

/**
  • Start of cycle: Relay1 is activated for (15 seconds).
  • In the meanwhile relay3 needs to be activated for 7 seconds and go OFF.
  • After Relay1 is switched off, Relay2 needs to go wait for 5 seconds and get
  • ON for 5 seconds and switch itself OFF.
  • After which relay4 needs to go ON immediately and operate for 3 seconds and go OFF.

After all the operations, the entire cycle needs to be repeated.

*/

const byte relay1Pin = 4;
const byte relay2Pin = 5;
const byte relay3Pin = 6;
const byte relay4Pin = 7;

struct CycleStep {
  uint32_t durationMs;
  byte relay1;
  byte relay2;
  byte relay3;
  byte relay4;
};

const CycleStep sequence =
{
  {7000, HIGH,  LOW, HIGH,  LOW}, // Relay1 is activated for (15 seconds), relay3 needs to be activated for 7 seconds and go OFF
  {8000, HIGH,  LOW,  LOW,  LOW}, // Relay1 is activated for (15 seconds)
  {5000,  LOW,  LOW,  LOW,  LOW}, //  Relay2 needs to go wait for 5 seconds
  {5000,  LOW, HIGH,  LOW,  LOW}, // Relay2 get ON for 5 seconds and switch itself OFF
  {3000,  LOW,  LOW,  LOW, HIGH}, // relay4 needs to go ON immediately and operate for 3 seconds
};

const int STEPS = sizeof(sequence) / sizeof(sequence[0]);
uint32_t stepStartMs;
int currentStep = 0;

void setup() {
  pinMode(relay1Pin, OUTPUT);
  pinMode(relay2Pin, OUTPUT);
  pinMode(relay3Pin, OUTPUT);
  pinMode(relay4Pin, OUTPUT);

currentStep = 0;
  doStep();
  stepStartMs = millis();
}

void loop() {
  if(millis() - stepStartMs >= sequence[currentStep].durationMs) {
    currentStep ++;
    if(currentStep >= STEPS) currentStep = 0;
    doStep();
    stepStartMs = millis();
  }

}

void doStep() {
  digitalWrite(relay1Pin, sequence[currentStep].relay1);
  digitalWrite(relay2Pin, sequence[currentStep].relay2);
  digitalWrite(relay3Pin, sequence[currentStep].relay3);
  digitalWrite(relay4Pin, sequence[currentStep].relay4);
}

Hey Paul,
I did post my code in a comment later. I'm a total newbie with no experience in coding and micro controllers. I'm glad to have found this forum where I can expand my knowledge and my mind. That being said, I thank you for that code you sent me. It worked wonderfully. I could easily understand the code and got many ideas on how to use certain commands through your code.

Thanks,
Sahil

sahilsahni:
Thanks for pointing it out. Below is my code. It doesn't work too well. Please read it and let me know how can I improve.

Not too bad. A few common beginner mistakes:

////  Common beginner error (caused by bad examples provided with the IDE)
//// For pin numbers, use 'const' so they can't be accidentally changed.
//// Use byte since that is a smaller size that will still hold any pin number (0-255)
//// Style hint: Use a name that ends in Pin to remind you to pinMode, read, and write.
const byte R1Pin = 9;  //// int R1 =  9;
const byte R2Pin = 10;  //// int R2 = 10;
const byte R3Pin = 11;  //// int R3 = 11;
const byte R4Pin = 12;  //// int R4 = 12;
unsigned long previousMillis = 0;


 ////  Common beginner error.  Always use 'unsigned long' for millis and micros.  Negative times cause problems.
unsigned long OnTime = 7000;  //// long OnTime = 7000;           // milliseconds of on-time
unsigned long OffTime = 750;  //// long OffTime = 750;          // milliseconds of off-time


void setup()
{
  // set the digital pin as output:
  pinMode(R1Pin, OUTPUT);
  pinMode(R2Pin, OUTPUT);
  pinMode(R3Pin, OUTPUT);
  pinMode(R4Pin, OUTPUT);
}


void loop()
{
  unsigned long currentMillis = millis();
  digitalWrite(R1Pin, LOW); // Turn it ON
  delay(1500);


  ////  Note: It is uncommon to mix millis() and delay().  If your sketch does nothing else but a sequence of actions
  ////  it is safe to use delay().  If you need more than one sequence interleaved you will need to get rid of ALL
  ////  delay() and use only millis().


  ////  Common beginner error.  You have to READ and WRITE pins.
  //// if ((R1 == LOW) && (currentMillis - previousMillis >= OnTime))
  if ((digitalRead(R1Pin) == LOW) && (currentMillis - previousMillis >= OnTime))
  {
    //// Common beginner error.  You have to READ and WRITE pins.
    //// Note: Adding the 'const' above lets the compiler tell you this was a mistake
    digitalWrite(R3Pin, LOW);  //// R3Pin = LOW;  // Turn it ON
    previousMillis = currentMillis;
    digitalWrite(R3Pin, LOW);
  }


  digitalWrite(R2Pin, LOW);
  delay(5000);
  digitalWrite(R2Pin, HIGH);
  digitalWrite(R4Pin, LOW);
  delay(3000);
  digitalWrite(R4Pin, HIGH);
}

sahilsahni:
Hey Paul,
I did post my code in a comment later. I'm a total newbie with no experience in coding and micro controllers. I'm glad to have found this forum where I can expand my knowledge and my mind. That being said, I thank you for that code you sent me. It worked wonderfully. I could easily understand the code and got many ideas on how to use certain commands through your code.

Happy to help.

There are several improvements that could be made, of course. Those places where there there's a pin1, pin2, pin3 and so on could be put into an array. Alternatively, give these variables meaningful names. sifterPin, armHorizontalPin, armVerticalPin, fluidValvePin and so on - whatever is appropriate.

So I'm working with your code and made a few minor adjustments. I want to know a thing, when I plug in all the connections with the relays and the coil, the series of operations work perfectly. However, I want the cycle to start immediately after the end of last step but then the system waits for a long time to start again. Can you point out what's wrong with the loop setup? I'd really like some help. :slight_smile:

const byte relay1Pin = 10;//loader
const byte relay2Pin = 11;//exit gate
const byte relay3Pin = 10;//sequencer
const byte relay4Pin = 9;//entry gate
int sensor =6; //proximity sensor

struct CycleStep {
  uint32_t durationMs;
  byte relay1;
  byte relay2;
  byte relay3;
  byte relay4;
};

const CycleStep sequence[] = 
{
  {3000, HIGH,  LOW, HIGH,  HIGH}, // exit opens for 3 seconds
  {3000, HIGH,  HIGH, HIGH, HIGH}, // All gates close
  {3100,  HIGH,  HIGH,  HIGH,  LOW}, //  entry opens after 100milli seconds when exit closes
  {4200,  HIGH, HIGH,  HIGH,  HIGH}, // entry closes after 1 second of opening
  {4300,  LOW,   HIGH,  HIGH, LOW}, // Loader is activated 300milliseconds after gate closes
  {5500, LOW, HIGH , LOW, HIGH}, //Sequencer opens 1 second after loader is started
  {7500, LOW, HIGH, HIGH, HIGH},// Sequencer close after 2 seconds of opening
  {19500,  LOW,   HIGH,  HIGH, HIGH},
  {19500,HIGH,HIGH,HIGH,HIGH}, // All gates close
};

const int STEPS = sizeof(sequence) / sizeof(sequence[0]);
uint32_t stepStartMs;
int currentStep = 0;

void setup() {
  pinMode(relay1Pin, OUTPUT);
  pinMode(relay2Pin, OUTPUT);
  pinMode(relay3Pin, OUTPUT);
  pinMode(relay4Pin, OUTPUT);
  pinMode(sensor, INPUT);

  currentStep = 0;
  doStep();
  stepStartMs = millis();
}

void loop() {
 
 if(millis() - stepStartMs >= sequence[currentStep].durationMs) {
    currentStep ++;
    if(currentStep >= STEPS) currentStep = 0;
    doStep();
    stepStartMs = millis();
  }

}

void doStep() {
  digitalWrite(relay1Pin, sequence[currentStep].relay1);
  digitalWrite(relay2Pin, sequence[currentStep].relay2);
  digitalWrite(relay3Pin, sequence[currentStep].relay3);
  digitalWrite(relay4Pin, sequence[currentStep].relay4);
}

Relay 1 is egual to relay 3

Silente:
Relay 1 is egual to relay 3

Didn't quite get that. Could you elaborate?

Relay1pin=10
Relay3pin=10

sahilsahni:
So I’m working with your code and made a few minor adjustments. I want to know a thing, when I plug in all the connections with the relays and the coil, the series of operations work perfectly. However, I want the cycle to start immediately after the end of last step but then the system waits for a long time to start again.

How long is a long time? You have added two 19.5 second steps in there. Furthermore, these two lines:

  {7500, LOW, HIGH, HIGH, HIGH},// Sequencer close after 2 seconds of opening
  {19500,  LOW,   HIGH,  HIGH, HIGH},

Have the same relay on/off pattern, so they will appear to be a single 27-second step where realy1 is low and the other 3 are high.

I mean, you stste that you want to restart “immediately after the last step”. Isn’t it starting immediately after those two 19-second steps that you added, like it is supposed to?

    if(currentStep >= STEPS) currentStep = 0;
    doStep();
    stepStartMs = millis();

You are re-starting the timer for each step. That means the values in the table are the duration of the step, not the end time. Your table should look more like this:

const CycleStep sequence[] = 
{
  {3000, HIGH,  LOW, HIGH,  HIGH}, // For 3 seconds, Open the exit.
  {3000, HIGH,  HIGH, HIGH, HIGH}, // For 3 seconds, All gates closed
  {100,  HIGH,  HIGH,  HIGH,  LOW}, // For 100 milliseconds, Open entry
  {1100,  HIGH, HIGH,  HIGH,  HIGH}, // For 1.1 seconds, All gates closed
  {100,  LOW,   HIGH,  HIGH, LOW},  // For 100 milliseconds. Run loader
  {1200, LOW, HIGH , LOW, HIGH}, // For 1.2 seconds, Run sequencer and continue loader
  {2000, LOW, HIGH, HIGH, HIGH}, // For 2 seconds,  Stop sequencer and continue loader
  {12000,HIGH,HIGH,HIGH,HIGH}, // For 12 seconds, All gates closed
};