Problems with Arduino Mega and four 8 Channel Relays

Wiring Diagram.pdf (579.2 KB)

Bowling Arcade Game Manual.pdf (3.5 MB)

I am building a half scale bowling game and in the process of automating the string pin setter. I am using a linear actuator (hereafter called actuator) for each pin (10 total) as well as 3 additional linear actuators (ball gate, sweep, and ball elevator).

I have elected to use a total of four 5V, 8 channel relay modules to isolate the Arduino Mega signals from the 12 volt (<5 amp) power requirements for each actuator. I have attached a wiring diagram of how I built the control panel. I have also attached the start of a manual that shows all the equipment specifications if needed.

When I first started, i wired all 13 actuators directly to the power supply and they worked great. However, when i built the control panel and hooked the actuators to the relays, I can only get two actuators to work at a time (and all 13 work but only 2 at a time) but no more than that. I’m lookng for a way to get as many as 13 actuators to work at the same time.

Note I have a 25 amp, 12 vdc power supply. Also note I use another power supply for all the lighter duty power requirements which provides 5, 12, and 24 vdc rated for 8 amps. I am using two relays to control the movement for each actuator (see page 12 of manual for that wiring schematic).

On the input side of each 8 channel relay, i am using 5 vdc from the power supply (not the Arduino). I am sharing the ground. On the output side of the relays i am powering from one of the power supplies to get the right voltage to each component. The Arduino Mega sends the input trigger as instructed per the Arduino code.

I have read the 3 to 4 forums on this topic as well as have done some online research. A single coil can draw 70-100mA; 8 relays activated simultaneously can exceed 600-800m; 32 relays activated simulataneously 2400 to 3200 mAmps which greatly exceeds the 500 mAmp capacity of the Mega. However, I understood that if the input side of the relays were powered directly from a power supply, this would address this problem. What am i doing wrong?

Several forums suggest adding a separate DC power supply to the GND/VCC/JD_VCC pins per the sketch below.

However, the relays i am using (shown below) do NOT have the GND/VCC/JD-VCC pins. The relays i am using look like this with the only pins being jumpers for high/low level trigger signals.

Should i change out my relays to this type of module with the GND/VCC/JD-VCC pins?

Arduino Sketch follows but let’s please focus on the potential wiring issues stated above and not on the sketch please. Let’s also not focus on the fact that transistors or solid state relays may have been a better choice please. Thanks in advance for your help.

// //////////////////////////////////////////////////////////// //
//                                                              //
//                Arduino Sketch for Bowling Game               //
//                           Rev 1.0                            //
//                       January 19.2025                        //
//                         Deron Butler                         //
//                dbutler@josephdouglashomes.com                //
//                                                              //
// /////////////////////////////////////////////////////////// ///


// *********************************************************************** //
// Libraries
// *********************************************************************** //

  #include <FastLED.h> // Library for LED controls (future use)
  #include <SerialMP3Player.h>

// *********************************************************************** //
// Definitions for LED Lighting
// *********************************************************************** //

  #define NUM_STRIPS 2
  #define NUM_LEDS_PER_STRIP 60
  #define NUM_LEDS NUM_LEDS_PER_STRIP * NUM_STRIPS

  CRGB leds[NUM_STRIPS * NUM_LEDS_PER_STRIP];

// *********************************************************************** //
// Definitions for MP3 Player
// *********************************************************************** //
  
  #define TX 0
  #define RX 1
  SerialMP3Player mp3(RX, TX);
  // NOTE: format micro SD cards as FAT16 or FAT32  
  // NOTE: label folders on micro SD "01", "02", etc
  // NOTE: label files "001xxx.mp3" and "002xxx.mp3" where xxx can be anything
  // NOTE: do not use files 008xxx.mp3 or 009xxx.mp3 as these result in errors

  // Connect the Serial MP3 Player to the Arduino board
  // YX5300 → Mega 
  // GND → GND
  // VCC → 5V
  // TX → RX (pin 2)
  // RX → TX (pin 1)

// *********************************************************************** //
// Constants/Variables for Set Up
// *********************************************************************** //

  int Mode = 1;
  bool ball1 = HIGH;
  bool ball2 = LOW;
  int result =0;
  bool split = LOW;
  const int solenoidExtend[14] = {0, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47}; // Defines pinout for extending solenoid
  const int solenoidRetract[14] = {0, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48}; // Defines pinout for retracting solenoid
  const int pinDesignation[11] = {0, 8, 2, 3, 4, 5, 9, 10, 11, 12, 13}; // Defines pinout for bowling pin status
  // NOTE:  1st position of an index is intentionally not used in this sketch

  unsigned long laneResetTime = 0; // Assigns value of relative time in milliseconds

  unsigned long currentTime = 0; // Assigns value of relative time in milliseconds
  bool bowlPinState[] = {LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW}; // LOW = pin standing; HIGH = pin has fallen
  // NOTE:  1st position of an index is position 0 which is purposely chosen to be ignored in this sketch

  bool data[10] = {LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW}; // Variable to toggle (0 = OFF, 1 = ON)
  unsigned long lastTime = 0;

// *********************************************************************** //
// Variables for Ball Return
// *********************************************************************** //
  int ballReturnState = LOW; // Current reading from the button
  int lastBallReturnState = LOW; // Previous reading from the button
  bool ballReturn = LOW;

  unsigned long ballReturnStartTime  = 0; // Assigns value of relative time in milliseconds
  unsigned long lastDebounceTime1 = 0; // Last time the button state changed
  unsigned long debounceDelay1 = 500;   // Debounce time in milliseconds

// *********************************************************************** //
// Variables for Service Button
// *********************************************************************** //
  bool serviceButtonPressed = false;
  int serviceButtonState = LOW;     // Current reading from the button
  unsigned long pressStartTime = 0;

// *********************************************************************** //
// Variables for Current Sensing
// *********************************************************************** //

  float voltageOut[13] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  float current[13] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  int currentMax = 2;
  bool maxCurrentEvent[13] = {false,false,false,false,false,false,false,false,false,false,false,false,false};
  unsigned long currentMaxTime[13] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // time when max current limit exceeded
  unsigned long lastCurrentDebounceTime[13] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // Last time the current state changed
  unsigned long currentDebounceDelay = 350;   // Debounce time in milliseconds

// *********************************************************************** //
// Variables for Modes
// *********************************************************************** //

  unsigned long ballRolledTime = 0;
  int ballRolledState = HIGH;
  int lastBallRolledState = HIGH;

// ________________________________________________________________________ //
// -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ //
void setup() {
// -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ //
// ________________________________________________________________________ //

  Serial.begin(9600); // Opens the serial port at 9600 bps

  // tell FastLED there's 60 NEOPIXEL leds on pin 51, starting at index 0 in the led array
  FastLED.addLeds<NEOPIXEL, 51>(leds, 0, NUM_LEDS_PER_STRIP);

  // tell FastLED there's 60 NEOPIXEL leds on pin 52, starting at index 15 in the led array
  FastLED.addLeds<NEOPIXEL, 52>(leds, NUM_LEDS_PER_STRIP, NUM_LEDS_PER_STRIP);

  
  mp3.begin(9600); // start mp3-communication
  delay(500); // wait for init

  mp3.sendCommand(CMD_SEL_DEV, 0, 2); //select sd-card
  delay(500); // wait for init
  
  // Mega Arduino Pin Assignments

    // pin 0 is set up for TX above
    // pin 1 is set up for RX above
    pinMode(2, INPUT_PULLUP); // monitors **UNO** pin A0 for bowling pin 2 status
    pinMode(3, INPUT_PULLUP); // monitors **UNO** pin D2 for bowling pin 3 status
    pinMode(4, INPUT_PULLUP); // monitors **UNO** pin D3 for bowling pin 4 status
    pinMode(5, INPUT_PULLUP); // monitors **UNO** pin D4 for bowling pin 5 status
    pinMode(6, INPUT_PULLUP); // monitors **UNO** pin D7 for auto reset in 10th frame
    pinMode(7, INPUT); // monitors **UNO** pin D8 (uses external pullup) for detecting ball roll
    pinMode(8, INPUT_PULLUP); // monitors **UNO** pin D5 for bowling pin 1 status
    pinMode(9, INPUT_PULLUP); // monitors **UNO** pin A1 for bowling pin 6 status
    pinMode(10, INPUT_PULLUP); // monitors **UNO** pin A2 for bowling pin 7 status
    pinMode(11, INPUT_PULLUP); // monitors **UNO** pin A3 for bowling pin 8 status
    pinMode(12, INPUT_PULLUP); // monitors **UNO** pin A4 for bowling pin 9 status
    pinMode(13, INPUT_PULLUP); // monitors **UNO** pin A5 for bowling pin 10 status
    pinMode(14, INPUT_PULLUP); // monitors **UNO** pin D9 for spare
    pinMode(15, INPUT_PULLUP); // monitors **UNO** pin D10 for strike
    pinMode(16, INPUT_PULLUP); // monitors **UNO** pin D11 for ball 1
    pinMode(17, INPUT_PULLUP); // monitors **UNO** pin D12 for ball 2
    pinMode(18, INPUT_PULLUP); // monitors reset button  NOTE:  this may need an external pullup
    pinMode(19, OUTPUT); // relay 1 (ball 1 light)
    pinMode(20, OUTPUT); // relay 2 (ball 2 light)
    pinMode(21, OUTPUT); // relay 3 (spare light)
    pinMode(22, OUTPUT); // relay 4 (strike light)
    pinMode(23, OUTPUT); // relay 5 (pin 1 raise)
    pinMode(24, OUTPUT); // relay 6 (pin 1 lower)
    pinMode(25, OUTPUT); // relay 7 (pin 2 raise)
    pinMode(26, OUTPUT); // relay 8 (pin 2 lower)
    pinMode(27, OUTPUT); // relay 9 (pin 3 raise)
    pinMode(28, OUTPUT); // relay 10 (pin 3 lower)
    pinMode(29, OUTPUT); // relay 11 (pin 4 raise)
    pinMode(30, OUTPUT); // relay 12 (pin 4 lower)
    pinMode(31, OUTPUT); // relay 13 (pin 5 raise)
    pinMode(32, OUTPUT); // relay 14 (pin 5 lower)
    pinMode(33, OUTPUT); // relay 15 (pin 6 raise)
    pinMode(34, OUTPUT); // relay 16 (pin 6 lower)
    pinMode(35, OUTPUT); // relay 17 (pin 7 raise)
    pinMode(36, OUTPUT); // relay 18 (pin 7 lower)
    pinMode(37, OUTPUT); // relay 19 (pin 8 raise)
    pinMode(38, OUTPUT); // relay 20 (pin 8 lower)
    pinMode(39, OUTPUT); // relay 21 (pin 9 raise)
    pinMode(40, OUTPUT); // relay 22 (pin 9 lower)
    pinMode(41, OUTPUT); // relay 23 (pin 10 raise)
    pinMode(42, OUTPUT); // relay 24 (pin 10 lower)
    pinMode(43, OUTPUT); // relay 25 (close ball gate)
    pinMode(44, OUTPUT); // relay 26 (open ball gate)
    pinMode(45, OUTPUT); // relay 27 (raise ball elevator)
    pinMode(46, OUTPUT); // relay 28 (lower ball elevator)
    pinMode(47, OUTPUT); // relay 29 (raise sweep)
    pinMode(48, OUTPUT); // relay 30 (lower sweep)
    pinMode(49, OUTPUT); // relay 31 (service light)
    pinMode(50, OUTPUT); // relay 32 (spare)
    pinMode(51, OUTPUT); // LED strip #1
    pinMode(52, OUTPUT); // LED strip #2
    // 53 not used  
    pinMode (A0, INPUT); // Analog signal for current sensor on linear actuator #1 (bowling pin 1)
    pinMode (A1, INPUT); // Analog signal for current sensor on linear actuator #2 (bowling pin 2)
    pinMode (A2, INPUT); // Analog signal for current sensor on linear actuator #3 (bowling pin 3)
    pinMode (A3, INPUT); // Analog signal for current sensor on linear actuator #4 (bowling pin 4)
    pinMode (A4, INPUT); // Analog signal for current sensor on linear actuator #5 (bowling pin 5)
    pinMode (A5, INPUT); // Analog signal for current sensor on linear actuator #6 (bowling pin 6)
    pinMode (A6, INPUT); // Analog signal for current sensor on linear actuator #7 (bowling pin 7)
    pinMode (A7, INPUT); // Analog signal for current sensor on linear actuator #8 (bowling pin 8)
    pinMode (A8, INPUT); // Analog signal for current sensor on linear actuator #9 (bowling pin 9)
    pinMode (A9, INPUT); // Analog signal for current sensor on linear actuator #10 (bowling pin 10)
    pinMode (A10, INPUT); // Analog signal for current sensor on linear actuator #11 (ball gate)
    pinMode (A11, INPUT); // Analog signal for current sensor on linear actuator #12 (ball elevator)
    pinMode (A12, INPUT); // monitors ball at elevator sensor  NOTE:  this may need an external pullup
    // pins A13-A15 not used  
  
}


// ________________________________________________________________________ //
// -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ //
void loop() {
// -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ //
// ________________________________________________________________________ //
  
  // currentTime = millis(); // future use

  // ________________________________________________________________________
  // Mode 1: Lane Idle Until Next Ball is Rolled
  // ________________________________________________________________________

    if (Mode == 1) {
      
      ballRolledState = digitalRead(7); // Monitors **UNO** ball lane sensor (trigger)
        
      if (ballRolledState == !lastBallRolledState) { // if state changes to LOW, ball has been rolled
        ballRolledTime = millis(); // sets time ball was rolled
        Mode = 2;
      }
  
    lastBallRolledState = ballRolledState;
    
    }


  // ________________________________________________________________________
  // Mode 2: Determine How Many Pins are Left
  // ________________________________________________________________________

    if (Mode == 2) {

      unsigned long time = millis() - ballRolledTime; // Keeps track of how much time has passed since the ball was rolled
      
      if (time > 3250 && data[2] == LOW) { 
        // NOTE:  After ball sensor is triggered, computer has camera take photo of bowling pin deck.  Computer determines what bowling
        // pins have been knocked down and, in turn, sends data to UNO.  Uno releases this data 3 seconds after ball sensor is triggered 
        // through the Uno pins defined as pinDesignation(ii)

        for (int ii = 1; ii < 11; ii++) {
          bowlPinState[ii] = digitalRead (pinDesignation[ii]); //Read **UNO** pins; High/LOW = Bowling pin has fallen/still standing
          result = result + bowlPinState[ii];
        }

        if (result == 2) { // test for a split
          if ((bowlPinState[7] + bowlPinState[10] == 2) || (bowlPinState[3] + bowlPinState[10] == 2) || (bowlPinState[4] + bowlPinState[5] == 2) || (bowlPinState[5] + bowlPinState[6] == 2)) {
            split = HIGH; 
          }
        }

        if (result == 0) { // gutter ball
          mp3.playF(01); // play from 01 file folder
          mp3.play(01,15); // plays specifically mp3 001.xxx at volume 15
        }

        if (split == HIGH) { // split
          mp3.playF(01); // play from 01 file folder
          mp3.play(02,15); // plays specifically mp3 002.xxx at volume 15
        }
        
        bool spare = digitalRead(9);
        if (spare == HIGH){
          digitalWrite (20, HIGH); // turn on spare light
          mp3.playF(01); // play from 01 file folder
          mp3.play(03,15); // plays specifically mp3 003.xxx at volume 15
        }


        bool strike = digitalRead(10);
        if (strike == HIGH){
          digitalWrite (20, HIGH); // turn on spare light
          digitalWrite (21, HIGH); // turn on strike light
          mp3.playF(01); // play from 01 file folder
          mp3.play(04,15); // plays specifically mp3 004.xxx at volume 15
        }
        
        ball1 = digitalRead(11);
        if (ball1 == HIGH) {
          digitalWrite (18, HIGH); // turn on ball 1 light
        }
        
        ball2 = digitalRead(12);
        if (ball1 == HIGH) {
          digitalWrite (19, HIGH); // turn on ball 2 light
        }

        data[2] = HIGH; // Insures this loop runs once
      }
      
      if (time > 4000) {
        Mode = 3;
        data[2] = LOW; // resets variable for Mode 2
        result = 0;
        split = LOW;
        digitalWrite (20, LOW); // turn off spare light
        digitalWrite (21, LOW); // turn off strike light
      }

    }


  // ________________________________________________________________________
  // Mode 3: Prepare Lane for Next Ball
  // ________________________________________________________________________

    if (Mode == 3) {

      if(data[3] == LOW) {
        laneResetTime = millis(); // Determines the start time of Mode 3

        mp3.playF(01); // play from 01 file folder
        mp3.play(05,15); // plays specifically mp3 005.xxx at volume 15

        data[3] = HIGH; //Insures millis() read just one time for this mode
      }
  
      unsigned long time = millis() - laneResetTime;

      if (time < 50) {
        resetPinActuators(); // assures pin actuators not moving
        resetSweepActuator(); // assures sweep actuator not moving
      }

      if (time >= 1500 && time < 8000) {
        lowerBallSweep(); // 6 seconds required to lower sweep
      }
  
      if (time >= 4000 && time < 8000) {
        raisePins(); //3 seconds required to raise pins which can overlap sweep operation
      }
        
      if (time >= 8000 && time < 8500) {
        // pause for 1/2 second to allow pins to settle/untangle
        resetPinActuators(); // Ensures actuators for bowling pins are off
        resetSweepActuator(); // Ensures actuator or ball sweep is off
      }
  
      if (time >= 8500 && time < 15500) {
        raiseBallSweep(); // allow 6 seconds to open
      }

      if (time >= 8500 && time < 12000) {
        lowerPins(); // 3 seconds required to lower pins
      }
      
      if (time >= 15500) {
        Mode = 1;
        data[3] = LOW; //resets time variable for Mode 3
      }
    }

 
  // ________________________________________________________________________
  // Mode 4: Manual Service Required
  // ________________________________________________________________________

  if (Mode == 4) {
    delay(50);
    lowerBallSweep(); //
    digitalWrite(49, LOW); // turns on service light as elevator or sweep needs attention from attendant

    while (digitalRead(18) == LOW) {
    // Do nothing, just wait for manual reset
    }
  }


// ________________________________________________________________________
// LED Lights
// ________________________________________________________________________

  theaterChaseRainbow(50); //Subroutine for LED's with value of xx for SpeedDelay
  
// ________________________________________________________________________
// Ball Return Mode // Note:  may run concurrently with any Mode
// ________________________________________________________________________
  
  if (ballReturn == false) { //Ball return is not in use = false
  int reading = digitalRead(A12);  // read switch at ball return

    if (reading != lastBallReturnState) { // Check to see if ball is at ball return sensor
      lastDebounceTime1 = millis(); // Reset debounce timer
    }

    if ((millis() - lastDebounceTime1) > debounceDelay1) { // If enough time has passed, confirm the change
      if (reading != ballReturnState) {
        ballReturnState = reading;

        if (ballReturnState == LOW) { // Only toggle when ball sensor actually detects the ball (LOW with INPUT_PULLUP)
          ballReturn = true; // Ball return now active
          ballReturnStartTime = millis();
          // Serial.print("Status variable changed to: ");
          // Serial.println(data[1]);
        }
      }
    }  

    lastBallReturnState = reading;
  }

  if (ballReturn == true) { // Ball elevator = true when operating
    unsigned long time = millis() - ballReturnStartTime; // keeps track of how long ball elevator has been running

    if (time < 500) {
      resetBallGateActuator(); // assures ball gate actuator not moving
      resetBallElevatorActuator(); // assures ball elevator actuator not moving
    }
      
    if (time >= 500 && time < 3500) { // allows ball gate 3 seconds to close
      closeBallGate();
    }
          
    if (time >= 3500 && time < 21000) {
      raiseBallElevator(); //17 seconds required for full up stroke
      resetBallGateActuator(); // stops ball gate actuator mid stroke
    }
        
    if (time >= 21000 && time < 22500) {
      // pause for 1.5 seconds to allow ball to exit ball elevator
      resetBallElevatorActuator(); // assures ball elevator actuator not moving
    }
            
    if (time >= 22500 && time < 38500) {
      lowerBallElevator(); //15 seconds required for full down stroke
    }
            
    if (time >= 37500 && time < 40500) {
      openBallGate(); // allow 3 seconds to open
    }

    if (time >= 40500) {
      resetBallGateActuator(); // stops ball gate actuator mid stroke
      resetBallElevatorActuator();
      ballReturn = false; // changes ball return status to off after 40.5 seconds      
    }
  }
  
  // ________________________________________________________________________
  // Service Mode // Note: Will Interrupt any Mode
  // ________________________________________________________________________
  
  int serviceButtonState = digitalRead(18); // Check if the service button has been pushed

  if (serviceButtonState == LOW && serviceButtonPressed == false) { // conditions when button just pressed
    pressStartTime = millis();
    serviceButtonPressed = true;
    Serial.println("button pressed");
  }

  if (serviceButtonState == HIGH && serviceButtonPressed == true) { // conditions when pressed button just released
    if(millis() - pressStartTime > 500) {
      if (millis() - pressStartTime >= 2500) { // request made to reset all pins if service button held for > 2.5 seconds
        for (int ii = 1; ii < 11; ii++) {
          bowlPinState[ii] = LOW; // resets all pins to standing if service button pushed longer than 2.5 seconds
        }
      }
    }

    Mode = 3; // re-rack bowling pins
    data[3] = LOW;
    serviceButtonPressed = false;
    digitalWrite(49, HIGH); // turns off service light if on from Mode 4
  }

  
  // ________________________________________________________________________
  // Detect High Current in Actuators // Note: may interrupt any Mode
  // ________________________________________________________________________
  
  for (int ii = 0; ii < 12; ii++) {

    if(maxCurrentEvent[ii] == false) {
      voltageOut[ii] = analogRead(ii); // read analog pins 0 to 11 to detect high current in linear actuators
      int jj = ii + 1; // variable to match 0-12 with 1-13 instead
      current[jj] = (voltageOut[ii] - 2.5) / 0.066; // formula to convert sensor reading to amps
  
      if (current[jj] > currentMax) { // detects high current on linear actuator jj
        lastCurrentDebounceTime[jj] = millis();
      }

      if (millis() - lastCurrentDebounceTime[jj] > currentDebounceDelay) { // overlooks actuator start up current
        if (current[jj] > currentMax) {
          maxCurrentEvent[jj] = true;  // linear actuator #jj has exceeded max current
        }

        if (data[0] == LOW) {
          currentMaxTime[jj] = millis(); // keeps track when this event starts
          data[0] = HIGH; // runs this loop once
        }

        unsigned long time = millis() - currentMaxTime[jj];
        
        if (jj < 11) {
          if (time < 50) {
            digitalWrite(49, HIGH); // turns on service light
            digitalWrite(solenoidExtend[jj], LOW); // stop linear actuator with high current
            digitalWrite(solenoidRetract[jj], LOW); 
          }
        
          if (time >= 50 && time < 1500) {
            digitalWrite(solenoidExtend[jj], LOW); // raise linear actuator with high current
            digitalWrite(solenoidRetract[jj], HIGH);
          }
  
          if (time >= 1500 && time < 1550){
            digitalWrite(solenoidExtend[jj], LOW); // stop linear actuator with high current
            digitalWrite(solenoidRetract[jj], LOW);
          }

          if (time >= 1550 && time < 4500) {
            digitalWrite(solenoidExtend[jj], HIGH); // lower linear actuator with high current
            digitalWrite(solenoidRetract[jj], LOW);
          }
  
          if (time >=4500) {
            maxCurrentEvent[ii] = false;
            data[0] = LOW; // runs this loop once
          }
        }

        else {
          digitalWrite(solenoidExtend[jj], LOW); // stops movement of linear actuator for ball gate or elevator
          digitalWrite(solenoidRetract[jj], LOW);
          Mode = 4; // operator asistance is required for ball jam at ball gate or elevator
          maxCurrentEvent[ii] = false;
          data[0] = LOW; // resets loop variable
        }     
      }
    }
  }  
}

  
// ________________________________________________________________________ //
// -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ //
// void subroutines
// -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ //
// ________________________________________________________________________ //

void resetPinActuators() { // stops linear actuators for bowling pins 1-10
  for (int ii = 1; ii < 11; ii++) {
    digitalWrite(solenoidExtend[ii], LOW);
    digitalWrite(solenoidRetract[ii], LOW); 
  }
    Serial.println("Reset all bowling pin actuators"); // Prints text
}   

void resetBallGateActuator() { // stops linear actuators for ball gate
  digitalWrite(solenoidExtend[11], LOW); // pin 43
  digitalWrite(solenoidRetract[11], LOW); // pin 44
  Serial.println("Reset ball gate actuator"); // Prints text
}  

void resetBallElevatorActuator() { // stops linear actuator for ball elevator
  digitalWrite(solenoidExtend[12], LOW); //pin 45
  digitalWrite(solenoidRetract[12], LOW); // pin 46
  Serial.println("Reset ball elevator actuator"); // Prints text
}  

void resetSweepActuator() { // stops linear actuator for sweep
  digitalWrite(solenoidExtend[13], LOW); // pin 47
  digitalWrite(solenoidRetract[13], LOW);  // pin 48
  Serial.println("Reset sweep actuator"); // Prints text
}  

void raisePins() {
  for (int ii = 1; ii < 11; ii++) {
  digitalWrite(solenoidExtend[ii], LOW);
  digitalWrite(solenoidRetract[ii], HIGH); 
  delay(50);
  }
  Serial.println("Raise Pins"); // Prints text
}

void lowerPins() {
  for (int ii = 1; ii < 11; ii++) {
    if (bowlPinState[ii] == LOW) {
      digitalWrite(solenoidExtend[ii], HIGH);
      digitalWrite(solenoidRetract[ii], LOW);
      Serial.print("This pin still standing: ");
      Serial.println(ii);
    }
    if (bowlPinState[ii] == HIGH) {
      digitalWrite(solenoidExtend[ii], LOW);
      digitalWrite(solenoidRetract[ii], HIGH); 
      Serial.print("This pin has fallen: ");
      Serial.println(ii);
    }  
    Serial.println("Lower Some Pins"); // Prints text
  }
}

void openBallGate() {
    digitalWrite(solenoidExtend[11], LOW);
    digitalWrite(solenoidRetract[11], HIGH);
    Serial.println("Open Ball Gate"); // Prints text
}

void closeBallGate() {
    digitalWrite(solenoidExtend[11], HIGH);
    digitalWrite(solenoidRetract[11], LOW);
    Serial.println("Close ball gate"); // Prints text
}

void raiseBallElevator() {
    digitalWrite(solenoidExtend[12], LOW);
    digitalWrite(solenoidRetract[12], HIGH); 
    Serial.println("Raise Elevator"); // Prints text
}

void lowerBallElevator() {
    digitalWrite(solenoidExtend[12], HIGH);
    digitalWrite(solenoidRetract[12], LOW); 
    Serial.println("Lower Elevator"); // Prints text
}

void lowerBallSweep() {
    digitalWrite(solenoidExtend[13], LOW);
    digitalWrite(solenoidRetract[13], HIGH);
    Serial.println("Lower Ball Sweep"); // Prints text
}

void raiseBallSweep() {
    digitalWrite(solenoidExtend[13], HIGH);
    digitalWrite(solenoidRetract[13], LOW);
    delay(50);
    Serial.println("Raise ball sweep"); // Prints text
}

void setPixel(int Pixel, byte red, byte green, byte blue) {
   leds[Pixel].r = red;
   leds[Pixel].g = green;
   leds[Pixel].b = blue;
}

void setAll(byte red, byte green, byte blue) { // Future use if LED strips need to be shut off
  for(int i = 0; i < NUM_LEDS; i++ ) {
    setPixel(i, red, green, blue);
  }
  FastLED.show();
}

void theaterChaseRainbow(int SpeedDelay) {
  byte *c;
  unsigned long currentTime = millis();

  if (currentTime - lastTime >= SpeedDelay) { 
    for (int j=0; j < 256; j++) { // cycle all 256 colors in the wheel
      for (int q=0; q < 3; q++) {
        for (int i=0; i < NUM_LEDS; i=i+3) {
          c = Wheel( (i+j) % 255);
          setPixel(i+q, *c, *(c+1), *(c+2)); //turn every third pixel on
        }
      
        FastLED.show();
       
        for (int i=0; i < NUM_LEDS; i=i+3) {
          setPixel(i+q, 0,0,0); //turn every third pixel off
        }
      }
    }
    lastTime = currentTime;
  }
}
byte * Wheel(byte WheelPos) {
  static byte c[3];
 
  if(WheelPos < 85) {
   c[0]=WheelPos * 3;
   c[1]=255 - WheelPos * 3;
   c[2]=0;
  } else if(WheelPos < 170) {
   WheelPos -= 85;
   c[0]=255 - WheelPos * 3;
   c[1]=0;
   c[2]=WheelPos * 3;
  } else {
   WheelPos -= 170;
   c[0]=0;
   c[1]=WheelPos * 3;
   c[2]=255 - WheelPos * 3;
  }

  return c;
}

If you do that, select 12V relay modules so that you don't need a 5V supply for them. They can be powered by the 12V supply for the actuators (EDIT: in this case you would need 4 flyback diodes per actuator to protect the rest of the circuit from reverse voltage from the motors). If you had done that in the first instance, things would have been much simpler.

I just checked your wiring diagram and I see an Uno in addition to the Mega you mentioned in the topic title. This will make the project significantly more difficult and now I am thinking it is more likely to be code problems. Using two Arduino in a project is a common beginner mistake that frequently results in problems.

Which Arduino is the code you posted for?

Do the LEDs on the relay board light up for the relays you think should be activated?

Should i change out my relays to this type of module with the GND/VCC/JD-VCC pins?

No.

The relays may not last long without some type of protection from the voltage spikes from the linear actuators. Been too long since I was in school to remember how to do this with a reversible motor.

Do you always have exactly two actuators that work, or does this vary at times?
Have you tried writing a simple sketch that just activates three or more of the actuators, to verify that it is not a code problem? I see a 50mS delay between actuator activation when raising pins, but there is no delay when lowering pins (except for any delays caused by a full buffer on Serial). The over-current protection might also be interfering with the operation of the actuators,

The module with the JD-VCC pins does have actual opto-isolation for the Arduino. The board currently being used seems to require a common ground, although I'm having trouble finding an actual schematic for an 8-channel board.

I’m currently testing an 8 channel relay board like the one you are using. The red circuit board model. I’m testing with a RPi Zero 2W

I have all jumpers set to HIGH, so a HIGH input activates the relay..

I have the relay board GND connected to the computer GND.

The inputs to the relay board go directly to the opto-isolator anodes.

The cathodes connect to the GND connector through a current limiting resistor. (1K?)

If I remove the GND connection, the relays fails to operate.

Your schematic shows no GND connection between the relays and the Arduino.

Just saying…

@jim-p @david_2018 @PaulRB

I spent the morning testing the actuator operation on the bowling game with the following Arduino sketch. This sketch was used to test the control panel (and relays) when I first built it. I had the same problem back then and was hoping to solve it with some creative code in the Arduino sketch (spacing out relay starting times).

I can vary the number of actuators that operate by changing the values of yy1 and yy2. I can successfully run any 3 actuators at a time. When doing so, the relay board reacts normally with the proper relay lights coming on. When a 4th actuator is added to the mix, the relay board typically does not show lights for the 4 relays and/or does odd things. I have tested all 13 actuators and have confirmed they all work individually, in pairs, and in triplicate.

Given this information, doesn’t it seem like the relay board(s) are not getting enough power on the input side?

Let’s use the sketch below for any conversation about programming concerns.

const int solenoidExtend[14] = {0, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47}; // Mega pin assignments
const int solenoidRetract[14] = {0, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48}; // Mega pin assignments
// NOTE:  The first position of an index is actually "0".  To better align with this sketch's numbering system, the index size was increased by one so the first position of index can be ignored.

int yy1;
int yy2;

// XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
void setup() {
// XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

  for (int ii = 1; ii < 14; ii++) {
  pinMode(solenoidExtend[ii],OUTPUT);
  pinMode(solenoidRetract[ii],OUTPUT);
  }
  yy1=8; // first linear actuator to be tested
  yy2=9; // last linear actuator to be tested
}

// XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
void loop() {
// XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
  
  // ________________________________________
  // Mode 1: Reset actuators
  // ________________________________________

    for (int ii = yy1; ii < yy2+1; ii++) {
    digitalWrite(solenoidExtend[ii], LOW);
    digitalWrite(solenoidRetract[ii], LOW); 
    }
    
  delay(250);  
  
  // ________________________________________
  // Mode 2: Extend actuators
  // ________________________________________

    for (int ii = yy1; ii < yy2+1; ii++) {
    digitalWrite(solenoidExtend[ii], HIGH);
    digitalWrite(solenoidRetract[ii], LOW); 
    //delay(500);
    }
 
  delay(5000);
  
  // ________________________________________
  // Mode 3: Reset actuators
  // ________________________________________

    for (int ii = yy1; ii < yy2+1; ii++) {
    digitalWrite(solenoidExtend[ii], LOW);
    digitalWrite(solenoidRetract[ii], LOW);
      delay(250);
    }

  delay(250);
  
  // __________________________________
  // Mode 4: Retract actuators
  // ________________________________________

    for (int ii = yy1; ii < yy2+1; ii++) {
    digitalWrite(solenoidExtend[ii], LOW);
    digitalWrite(solenoidRetract[ii], HIGH); 
    //delay(500);
    }

  delay(5000);
      
}

@SurferTim Thanks for the reply. On the input side of the relay module, i am using a ground wire that is shared to both power supplies, both arduino processors, and all other components. Where would i add another ground connection to the Arduino?

The Mega. You and I discussed it in this previous post . I elected to keep the two processors.

Yes for up to 3 actuators at a time. The problems begin when i try to run 4 or more actuators at the same time. I added post #8 to discuss this more in detail

I just activated all relays simultaneously, and it worked fine.

I think the optocouplers are AC type like the H11AA1. Just a guess. That is how the jumpers work. There are 2 LEDs internally in parallel with one wired backwards

I use an 5v8a power supply for the RPi and the relay board. It has run fine for days now without a problem.

Are all the jumpers set to HIGH? My power supply shows the board uses almost 1/2 amp with all relays activated.

Yes all the relay boards have the signal settings set to “HIGH” via the jumper setting. I am using a secondary 12v25a power supply to power the actuators and also a 5v/12v/24v8a power supply for everything else including powering the input side of the relays.

Are the relays driving anything during your test? Looks like you are using the relays to control solenoids.

I am using 2 relays to control the operation of linear actuators (one for extending and one for retracting). So I have a total of 26 relays required to operate 13 linear actuators. The test conducted does have the linear actuators connected. Again i can operate no more than 3 actuators at a time. Once it goes to 4 or more, the relay board stops working properly

I suspect power, either sags or spikes.

Have you tried it without the actuators connected?

@SurferTim

I have not tried that. I would need to use a different Arduino sketch so i could better monitor the lights on the relay boards. As stated in Post 1 per my research, 32 relays activated simultaneously requires 2.4 to 3.2 amps. Perhaps my 8 amp power supply is not keeping up.

I calculate 1/2a per board with all on, which your setup should not encounter. Only max half at a time. Correct?

However, if you turn them on all at once, there is a bad surge current of about twice or more of the holding current.

Each relay only uses 72mA, four would be only 288mA.
Even if your 5V supply is only 1A it should work.

What is the current rating of the 5V supply?

Are you waiting long enough for the actuators to fully extend and retract before you reverse the direction?