Arduino Acting Weird With Relay

Hello all, I am in need of some help ASAP.

I am trying to make an automated "Blower/Cleaner" for our assembly line. I am running into a problem where whenever 24V is supplied to the circuit, the Arduino acts weird. in the code i have it set so that when the button is held, the relay will turn on, then off, then on, then off again and will wait until the button has been released for 750ms before allowing the cycle to be repeated.

when the pneumatic solenoid is supplied power however, the cycle is as follows: relay turns on, waits, turns off, then the cycle repeats without needing to release the button.

Even if you start with the power supply off and turn it on while its running, as soon as the power is turned on, it skips the second delay.

We have tried this on both a genuine Arduino Uno r3 and a knock off Arduino Nano with identical results.

I have been scratching my head at this for close to a week now so any help is mighty appreciated.

worth noting:

  • currently I am using a separate power supply for the Arduino and the solenoid for ease however the problem persist with the circuit assembled as in the diagram.

  • I will not be able to pull up the exact relay from online as I wasn't here when it was ordered.

  • I initially tried with no kickback diode, then just a diode, then what you see on the diagram.

  • The solenoid is a Festo cpe14-M1CH-3GLS-1/8 24v pneumatic solenoid.

everything seems to work ok when 24v supplied during the first half of the cycle, however every time the second cycle messes up.

Its my first time posting here so if I missed something lmk.
Any help is appreciated, so thanks in advance.

Edit:
I ended up replacing the relay with a BS170 Mosfet. I did end up running into another issue but someone on reddit helped me out.

In conclusion I believe it was the relay causing issues, even with the kickback diode. Not sure why I and my coworker have both had no issues previously using relays with Arduino's but hey. The problem is solved so I'm not complaining. the only thing I can think of is that, 2 inductive loads is better (worse) than one.

Anyways, thanks all for the help.

/*****************************************************************************
******************************************************************************

        A short script to activate a solenoid in a specific pattern
           to remove foreign debris from part# 22.60.055.028-00.
        Uses a potentiometer to control the timing of the relay.
     Iluminates LED's to inform the operator of the machine's operation.

******************************************************************************
*****************************************************************************/

// Declaring the pins for IO:
const byte relay = 8;
const byte ready_led = 9;
const byte working_led = 7;
const byte limit_switch = 2;
const byte potentiometer = A0;

// Variables to keep track of the states of outputs:
int relay_state = HIGH;
int working_state;
int ready_state = HIGH;

// Variables to declare how long to open the pneumatic solenoid:
int delay1 = 1000;
int delay2 = (delay1 + 1000);
int delay3 = delay2;
int wait = 750;

// Variables to keep track of time:
int start;
int wait_start;
int current;
int difference;

// Variables to keep track of what is happening globally:
bool e_stop = false;
bool done = false;

void setup() {

  Serial.begin(9600);

  // Declaring pins as either inputs or outputs:
  pinMode(relay, OUTPUT);
  pinMode(ready_led, OUTPUT);
  pinMode(working_led, OUTPUT);
  pinMode(limit_switch, INPUT);

  // Declaring an interupt on the pin corresponding to the limit switch:
  attachInterrupt(digitalPinToInterrupt(limit_switch), emergency_stop, RISING);
}

void loop() {

  current = millis();

  // Updating each pin every time the programe loops:
  digitalWrite(relay, relay_state);
  digitalWrite(ready_led, ready_state);
  digitalWrite(working_led, working_state);

  // Using the potentiometer_map() function to determine the time to wait during delay3:
  delay3 = (potentiometer_map() + delay2);

  // If an E stop even has been triggered, wait a moment before resetting:
  if (e_stop == true) {
    digitalWrite(ready_led, LOW);
    digitalWrite(working_led, HIGH);
    delay(2000);  // wait 2 seconds
    digitalWrite(working_led, LOW);
    done = false;    // Set "done" to false so that we can continue cleaning parts
    e_stop = false;  // set "e+stop" to false so we don't enter this loop again unless anouther E stop is called
    ready_state = HIGH;
    working_state = LOW;
    digitalWrite(ready_led, ready_state);
    digitalWrite(working_led, working_state);
  }

  wait_start = millis();  // Keep track of time so we know how much has passed

  while (done && digitalRead(limit_switch)) {  // while we have completed the the timed loop and the switch is released

    ready_state = HIGH;

    if (current - wait_start >= wait) {  // If the current time - the time when we started is the amount of time we want to wait, then set done to false to start anouther loop
      done = false;
    }
    current = millis();
  }

  if (!digitalRead(limit_switch)) {  // If the switch is pressed

    delay(1000);  // Wait briefly

    start = millis();  // start keeping strack of time

    while (!done && !digitalRead(limit_switch)) {  // while not done and the switch is held a part is in the nest

      // Set the lights to "working status":
      working_state = HIGH;
      ready_state = LOW;

      // Figure out how much time has elapsed:
      current = millis();
      difference = (current - start);

      if (difference < delay1 && !e_stop) {  // If the diffence in time is less than delay1 and no E stop has been declared
        relay_state = LOW;  // Relay on
        Serial.println("\nON 1");
        Serial.println(difference);
      }

      else if (difference > delay1 && difference < delay2 && !e_stop) {  // If the diffence in time is greater than delay1, less than delay2, and no E stop has been declared
        relay_state = HIGH;  // Relay off
        Serial.println("\nOFF 2");
        Serial.println(difference);
      }

      else if (difference > delay2 && difference < delay3 && !e_stop) {  // If the diffence in time is greater than delay2, less thean delay3, and no E stop has been declared
        relay_state = LOW;  // Relay on
        Serial.println("\nON 3");
        Serial.println(difference);
      }

      else {  // Otherwise wait in a ready state
        Serial.println("\nOFF 4");
        relay_state = HIGH;
        working_state = LOW;
        ready_state = HIGH;
        start = current;
        wait_start = current;
        done = true;
      }

      // Update the outputs every time this loop cycles to make sure everything shows correctly:
      digitalWrite(relay, relay_state);
      digitalWrite(ready_led, ready_state);
      digitalWrite(working_led, working_state);
    }
  }
}

int potentiometer_map() {  // Maps the value read from the potentiometer into a value between 500 and 10,000 milliseconds
  return (map(analogRead(potentiometer), 0, 1023, 500, 10000));
}

void emergency_stop() {  // This function is called by an interrupt every time the switch is released, and if the process wasn't completed it waits a moment to reset
  if (!done) {
    Serial.println("E STOP!");
    e_stop = true;
    done = true;
    relay_state = HIGH;
    digitalWrite(relay, HIGH);
    ready_state = LOW;
    digitalWrite(ready_led, ready_state);
  } else {
    return;
  }
}

I will try this. I also see I forgot to attach the pic of the relay. Now can you do it with a uno r3, as we got the same results from that.

You need an anti-kickback diode on the 24V solenoid coil as well as the relay.

Why have you connected Vin to the 3V3 output of your 12V to 3V buck converter? The Vin pin needs at least 6.5V to power the Arduino correctly.

I'm guessing the main issue is that white component.
The ground needs to be a star point with all supplies decoupled.
What is the purpose of R5?

https://www.festo.com/media/pim/896/D15000100121896.PDF
image
53mA doesnt seem much to cause a problem, but maybe the surge is an issue?

@sbs_logan
Your limit switch is wired incorrectly.
Connect Vcc to Nano 5V
Connect GND to Nano GND
Connect OUT directly to D2

the software I used to make the diagram seems very limited in options for components. like how I had to use a 3v battery and just name it 24v. it is in fact a variable buck converter. the Arduino is getting 12v. sorry i should have explained that better.

I was told having a resistor with the kickback diode was a good idea. it has since been removed.

I apologies for not saying it in the original post but the program I used to make the diagram was very limited for options. thus I used this switch. in reality, I am just using a simple limit switch, like one you would find on a 3d printer.

same as how the buck converter irl is a variable converter and the 24v isn't a 3v battery.

Then use a pencil and paper to draw your diagram. We don't care about a fancy computer program, we just care about having a diagram that is accurate with everything labeld correctly.

Next time

I thought you wanted it to work this time

As the final edit says I swapped out the relay for a mosfet and got it to work with some help from reddit. thanks for the help but it has been fixed.

Hi, @sbs_logan

In the spirit of this forum, can you please post your final code and final working schematic.
This is so the thread may be of assistance to others with a similar problem.

Thanks.. Tom... :smiley: :+1: :coffee: :australia:

1 Like

For sure. Just working on a couple last minute clean ups first.

@sbs_logan Then mark to topic as SOLVED, so we all don't continue to try to figure what's wrong

Below is the updated code. I replaced the relay with a BS170 Mosfet.

/*****************************************************************************
******************************************************************************

        A short script to activate a solenoid in a specific pattern
           to remove foreign debris from part# 22.60.055.028-00.
        Uses a potentiometer to control the timing of the relay.
     Iluminates LED's to inform the operator of the machine's operation.

******************************************************************************
*****************************************************************************/

// Declaring the pins for IO:
const byte relay = 8;
const byte ready_led = 9;
const byte working_led = 7;
const byte limit_switch = 2;
const byte potentiometer = A0;

// Variables to keep track of the states of outputs:
int relay_state = HIGH;
int working_state;
int ready_state = HIGH;

// Variables to declare how long to open the pneumatic solenoid:
int delay1 = 1000;
int delay2 = (delay1 + 1000);
int delay3 = delay2;
int wait = 750;

// Variables to keep track of time:
unsigned long start;
unsigned long wait_start;
unsigned long current;
unsigned long difference;

// Variables to keep track of what is happening globally:
bool e_stop = false;
bool done = false;

void setup() {

  Serial.begin(9600);

  // Declaring pins as either inputs or outputs:
  pinMode(relay, OUTPUT);
  pinMode(ready_led, OUTPUT);
  pinMode(working_led, OUTPUT);
  pinMode(limit_switch, INPUT_PULLUP);

  // Declaring an interupt on the pin corresponding to the limit switch:
  attachInterrupt(digitalPinToInterrupt(limit_switch), emergency_stop, RISING);
}

void loop() {

  current = millis();

  // Updating each pin every time the programe loops:
  digitalWrite(relay, relay_state);
  digitalWrite(ready_led, ready_state);
  digitalWrite(working_led, working_state);

  // Using the potentiometer_map() function to determine the time to wait during delay3:
  delay3 = (potentiometer_map() + delay2);

  // If an E stop even has been triggered, wait a moment before resetting:
  if (e_stop == true) {
    Serial.println("E STOP!");
    digitalWrite(ready_led, LOW);
    digitalWrite(working_led, HIGH);
    delay(2000);  // wait 2 seconds
    digitalWrite(working_led, LOW);
    done = false;    // Set "done" to false so that we can continue cleaning parts
    e_stop = false;  // set "e+stop" to false so we don't enter this loop again unless anouther E stop is called
    ready_state = HIGH;
    working_state = LOW;
    digitalWrite(ready_led, ready_state);
    digitalWrite(working_led, working_state);
  }

  wait_start = millis();  // Keep track of time so we know how much has passed

  while (done && digitalRead(limit_switch)) {  // while we have completed the the timed loop and the switch is released

    ready_state = HIGH;

    if (current - wait_start >= wait) {  // If the current time - the time when we started is the amount of time we want to wait, then set done to false to start anouther loop
      done = false;
    }
    current = millis();
  }

  if (!digitalRead(limit_switch)) {  // If the switch is pressed

    delay(1000);  // Wait briefly

    start = millis();  // start keeping strack of time

    while (!done && !digitalRead(limit_switch)) {  // while not done and the switch is held a part is in the nest

      // Set the lights to "working status":
      working_state = HIGH;
      ready_state = LOW;

      // Figure out how much time has elapsed:
      current = millis();
      difference = (current - start);

      if (difference < delay1 && !e_stop) {  // If the diffence in time is less than delay1 and no E stop has been declared
        relay_state = HIGH;  // Relay on
        Serial.println("\nON 1");
        Serial.println(difference);
      }

      else if (difference > delay1 && difference < delay2 && !e_stop) {  // If the diffence in time is greater than delay1, less than delay2, and no E stop has been declared
        relay_state = LOW;  // Relay off
        Serial.println("\nOFF 2");
        Serial.println(difference);
      }

      else if (difference > delay2 && difference < delay3 && !e_stop) {  // If the diffence in time is greater than delay2, less thean delay3, and no E stop has been declared
        relay_state = HIGH;  // Relay on
        Serial.println("\nON 3");
        Serial.println(difference);
      }

      else {  // Otherwise wait in a ready state
        Serial.println("\nOFF 4");
        relay_state = LOW;
        working_state = LOW;
        ready_state = HIGH;
        start = current;
        wait_start = current;
        done = true;
      }

      // Update the outputs every time this loop cycles to make sure everything shows correctly:
      digitalWrite(relay, relay_state);
      digitalWrite(ready_led, ready_state);
      digitalWrite(working_led, working_state);
    }
  }
}

int potentiometer_map() {  // Maps the value read from the potentiometer into a value between 500 and 10,000 milliseconds
  return (map(analogRead(potentiometer), 0, 1023, 500, 10000));
}

void emergency_stop() {  // This function is called by an interrupt every time the switch is released, and if the process wasn't completed it waits a moment to reset
  if (!done) {
    e_stop = true;
    done = true;
    relay_state = LOW;
    digitalWrite(relay, LOW);
    ready_state = LOW;
    digitalWrite(ready_led, ready_state);
  } else {
    return;
  }
}

Hi,
You need to look at the back emf diode on the relay, you have it drawn the wrong way.
Also the wiring of the limit switch is puzzling.

You would be better of hand drawing your circuit or using a switch symbol.
If you have INPUT_PULLUP for D2, R4 is not necessary and the way you have it configured, contributes nothing to the circuit function.

Thanks.. Tom... :smiley: :+1: :coffee: :australia:

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.