Activate relays in sequence

I want to learn Arduino and achieve the following.

Perform multiple actions in sequence:

Input switch closes (debounce input)

activate output relay 1
Delay 500ms
Activate output relay 2
Delay 500ms
Activate output relay 3
Delay 1500ms
Deactivate output relay 3
Delay 2500ms
Deactivate output relay 2

When input switch opens deactivate output relay 1
Then wait for new input to start over

  • What is this project for ?

  • Show us your proposed schematic.

  • Show us your attempt at writing the sketch.

The project is for activating and deactivating relays in a sequence after a switch is closing. Then deactivate the last relay when switch opens and standby for new sequence.

I have no schematics. I assume 4 pins, 1 for input and 3 for output.

I have no sketch either, as I have not understood at all how to make more things happen from one input.

  • But what is the purpose of this, what will it be used for ?

  • What relays are you using ?

  • What Arduino are you using ?

  • What hardware experience do you have ?

  • To start with you need to draw a schematic.

  • Have you written any Arduino C++ code before ?

Are you serious? The purpose is to activate and deactivate 2 outputs after defined delays, and to hold the third when input is closed. Then deactivate the third and standby when input opens.

To make it simple I use a 4ch relay board and an Arduino nano.

Why do I need to make a schematics? It's really simple: Input wired to one pin, output wired to three pins.

I haven't written much code before. That's why I ask here....

While this might be your first project, and the delay() function is very appealing…

It’s ok to start learning with delay(), but for a project like this, you REALLY need to look at millis() timing.

The reason in this case, is the program won’t know the button has been released until after the last delayed event has completed.

This is called ‘blocking’, or ‘non-blocking’ execution of code.

It also allows you to add other time critical actions easily when you understand how it works.

Correct. I want to avoid using delay.

If we weren't serious we would not have asked the questions, why not just give the answers.

For example my project will be used to operate a drilling machine.


A schematic is so we can communicate effectively; volunteers here are trying to help you with your project.

Maybe you need MOSFETs to drive the relays, we don't know what your intensions are.

Maybe you are using a N.C. switch.

A schematic should only take you 5 minutes to draw.

what should happen when the input switch gets deactivated before the other relays got activated?
Break the sequence or let it run and switch of relay 1 with relay2?

Good question!

I only considered debouncing on the input to avoid clapping relays. If, for some reason input gets deactivated, all relays should be deactivated no matter where in the sequence.

I had something from a similar question, so I adopted it

/*
  Solenoid cycle

  activate output relay 1
  Delay 500ms
  Activate output relay 2
  Delay 500ms
  Activate output relay 3
  Delay 1500ms
  Deactivate output relay 3
  Delay 2500ms
  Deactivate output relay 2

  The circuit:
   pushbutton attached to the pin 2 and to the ground
   solenoid #1 attached to pin 4
   solenoid #2 attached to pin 5
   solenoid #3 attached to pin 6

  https://forum.arduino.cc/t/activate-relays-in-sequence/1061969
  older Version:
  https://forum.arduino.cc/t/anyone-know-of-a-good-youtube-tutorial-on-how-to-make-a-code-repeat/1027637/3

*/

// constants won't change. They're used here to
const unsigned long solenoid_1_OffDelay = 0;
const unsigned long solenoid_2_OnDelay = 500;
const unsigned long solenoid_2_OffDelay = 2500;
const unsigned long solenoid_3_OnDelay = 500;
const unsigned long solenoid_3_OffDelay = 2500;
// set pin numbers:
const int buttonPin = 2;        // the number of the pushbutton pin
const int solenoid1Pin = 4;     // solenoid 1 pin
const int solenoid2Pin = 5;     // solenoid 2 pin
const int solenoid3Pin = 6;     // solenoid 3 pin


unsigned long debounceDelay = 50;    // the debounce time; increase if the output flickers
uint8_t state = 0;              // a global state for the state machine
uint32_t previousMillis = 0;

void start(uint32_t currentMillis = millis())
{
  digitalWrite(solenoid1Pin, HIGH);
  previousMillis = currentMillis;
  state = 1;
}

void stop()
{
  digitalWrite(solenoid1Pin, LOW);
  digitalWrite(solenoid2Pin, LOW);
  digitalWrite(solenoid3Pin, LOW);
  state = 0;
}

void runFSM(uint32_t currentMillis = millis())
{

  switch (state)
  {
    case 0 : break;
    case 1:
      if (currentMillis - previousMillis > solenoid_2_OnDelay)
      {
        previousMillis = currentMillis;
        digitalWrite(solenoid2Pin, HIGH);
        state++;
      }
      break;
    case 2:
      if (currentMillis - previousMillis > solenoid_3_OnDelay)
      {
        previousMillis = currentMillis;
        digitalWrite(solenoid3Pin, HIGH);
        state++;
      }
      break;
    case 3:
      if (currentMillis - previousMillis > solenoid_3_OffDelay)
      {
        previousMillis = currentMillis;
        digitalWrite(solenoid3Pin, LOW);
        state++;
      }
      break;
    case 4:
      if (currentMillis - previousMillis > solenoid_2_OffDelay)
      {
        previousMillis = currentMillis;
        digitalWrite(solenoid2Pin, LOW);
        state++;
      }
      break;
    case 5:
      // do nothing, just wait for switch off
      break;
  }
}

void readSwitch(uint32_t currentMillis = millis())
{
  static uint32_t previousMillis = 0;
  if (currentMillis - previousMillis > debounceDelay)
  {
    previousMillis = currentMillis;
    if (state > 0 && digitalRead(buttonPin) == HIGH)
    {
      stop();
    }
    else if (state == 0 && digitalRead(buttonPin) == LOW )
    {
      start();
    }
  }
}

void setup() {
  pinMode(buttonPin, INPUT_PULLUP);
  pinMode(solenoid1Pin, OUTPUT);
  pinMode(solenoid2Pin, OUTPUT);
  pinMode(solenoid3Pin, OUTPUT);

  // set initial outputs state
  digitalWrite(solenoid1Pin, LOW);
  digitalWrite(solenoid2Pin, LOW);
  digitalWrite(solenoid3Pin, LOW);
}

void loop() {
  uint32_t currentMillis = millis();
  readSwitch(currentMillis);
  runFSM(currentMillis);
}

simulation

read here about finite state machines

1 Like

This looks really nice, I see millis is even more complicated than I first thought. Just the look of it is still terrifying, but your example looks clean and understandable. I will give it a go on the breadboard after work today and post back. Thanks!

Agree we need a schematic - at least to show how you are powering things - get that wrong and you could damage the processor .
Have a lot at the ide examples - digital input , output, blink for guidance

see what the IDE Example "Blink Without Delay" is doing. It explains very well how to deal with millis.

it summarizes to

  uint32_t current Millis = millis();                   // get the current internal "time"
  static uint32_t previousMillis = 0;                   // the time of last execution
  if (currentMillis - previousMillis >interval)         // check if interval is over
      {
        previousMillis = currentMillis;                 // remember "now" as last exececution
        // do somthing
      }

once you have learned that "Blink Without Delay" pattern, you can use this over and over again.

If not already mentioned, have a look at the IDE Example "Blink Without Delay" example.

Hi, @Eirik78
Have you written some basic code to prove you can control a relay?
This is important as some relay arrays are ACTIVE on LOW input and some are ACTIVE on high input.

So before chasing the various ways of configuring your project.

Just get a basic bit of code, a button and a relay connected to your Arduino.

  1. What model Arduino are you using?
  2. Can you please post a link to data/specs of your relay assembly, or at least some images of your relay assembly.
  3. Can you please post link to, or image of your button?

These are the basic things we need to know.

So get your hardware out, your PC stoked up and start..

Tom.. :smiley: :+1: :coffee: :australia:
PS. post #14 and no basic information.

2 Likes

@Eirik78 I understand your frustration with the questions, but I also have to ask you - When were you going to tell us this? This information only came out through questioning, yet is central to the design of the code. Your 'tormentors' have long experience of having this kind of detail pop up after 20 or more postings, leading to considerable frustration all around. That's why the questions get asked.

Schematics are a communication tool, they greatly inform the discussion and lead to either great improvements in the design, or quick resolution of the original problem, and often both happen. A schematic isn't a tortuous exercise, a pencil sketch on a piece of paper, and a photo of it taken with a phone or camera, is all that's necessary most of the time.
Cheers, and hopefully you'll have a quick answer!

2 Likes

@Eirik78
how is it going. Are you ready for the next step?

Hi! I only had time to wire for a quick test at lunchtime today, so I won't have time to look closer at it before tomorrow. But so far it looked good. Think I'll have two questions, but will look at it properly first :grin:

@noiasca

It looks good, and at this moment I'm not sure there is any more than to play with it and the code to better understand the millis-function, since my goal with this was to learn how to perform sequences and repeats. I appreciate how someone replies directly to questions asked with knowledge.

When first testing it on an Uno, the delays was as expected. But when putting it on a Nano, the times did not correspond with milliseconds. I have no idea of why, I haven't used Nano much.

So far so good! :grin:

I don't know the issue with your Nano. The timings shouldn't be off.

Test with a short sketch. Print every 1000ms to the serial monitor. Does the Serial monitor respond at the defined speed every 1000ms?