Arduino hangs/freeze when using SSR

Hello,

I have been having an issue with a electro mechanical system I have been developing. I am using an Arduino Mega 2560 to run a few dc motors, a load cell, a stepper motor and control and solid state relay (SSR). The SSR is connected to a air pop popcorn machine (Amazon.com: Dzmb quick and easy hot air popcorn machine with measuring cup, oil-free popcorn machine with on/off switch is suitable for family movie night parties. (Red): Home & Kitchen). The issue I am having is, whenever I run the system with the airpopper plugged in the Arduino will hang and stop running. Without the popper everything is running perfectly fine. Does anyone have any idea why the Arduino would hang whenever the popper is plugged in?

A separate, but maybe related issue, I noticed that if i run the popcorn machine with an extension cord separate from the circuit. If the extension cord plug is close the the arduino the system will shut down as well. I attempted to cover the electronics in a grounded metal box but that did not solve the issue.

Components

  • 24 V power supply
  • Arduino mega 2560
  • 2 x #2516 Pololu Dual G2 High-Power Motor Driver 24v14 Shield
  • 3 DC Motors
  • 1 Stepper motor
  • DRV8825 stepper motor driver
  • Adafruit NAU7802

(I left out of the motors and a few limit switches from this circuit diagram)

Code

include <AccelStepper.h>
#include "DualG2HighPowerMotorShield.h"
#include <Adafruit_NAU7802.h>

// Create instance of the Pololu Dual G2 motor driver
// Uncomment the version corresponding with the version of your shield.
DualG2HighPowerMotorShield24v14 md;

// Use your custom pin configuration
DualG2HighPowerMotorShield24v14 md2(41, 43, 45, 39, A2, 40, 42, 44, 38, A3);  

// Stepper Motor Pin Definitions
const int dirPin = 2;
const int stepPin = 3;
const int enablePin = 8;  // Pin to control ENABLE on DRV8825
const int limitSwitchForward = 4;
const int limitSwitchReverse = 5;

// Microstepping control pins
const int M0 = 9;
const int M1 = 10;
const int M2 = 11;

// Popper control pin definition
const int popperPin = 22;  // Pin to control the popper SSR relay

// Define motor interface type
#define motorInterfaceType 1

// DC Motor Settings
const int motorSpeed = 300;  // Motor speed (0-400 range)

// Create instances
AccelStepper myStepper(motorInterfaceType, stepPin, dirPin);
Adafruit_NAU7802 nau;

// Load Cell Constants and Variables
const int weightIncrement = 5;       // Weight increment to trigger motors (g)
const int weightThreshold = 45;      // Final weight threshold (g)
int32_t loadcellTare = 0;            // Load cell tare value
int32_t currentBaseline = 0;         // Baseline weight for triggering motors
bool dCommandActive = false;         // Flag for "D" command activation

// Load Cell Timeout Duration (milliseconds)
const unsigned long loadCellTimeout = 1800000; // Default is 30 minutes
unsigned long lastWeightIncreaseTime = 0; // Tracks the last time a weight increase was detected

// Popper Timer Variables
const unsigned long popperTimeout = 300000;  // 5 minutes (300,000 ms)
unsigned long popperStartTime = 0;           // When popper was turned on
bool popperActive = false;                   // Flag for popper active state

// Motor Cycle Timing
unsigned long stepperDuration = 455;  // Stepper motor run time (ms)
unsigned long dcMotor1Duration = 1121; // DC motor 1 run time (ms)
unsigned long dcMotor2Duration = 1462; // DC motor 2 run time (ms) - New variable for second motor

// State variables for DC motors
bool isDCMotor1Running = false;
bool isDCMotor2Running = false;
unsigned long dcMotor1StartTime = 0;
unsigned long dcMotor2StartTime = 0;

// Timing for reverse motion in "F" command
// For dispensing 30mL with small syringe 
unsigned long reverseStepCount = 8500;

// Encoder Pin Definitions
#define ENCODER_A 19  // Encoder Channel A
#define ENCODER_B 18  // Encoder Channel B

// Encoder Configuration
volatile long encoderCount = 0;  
const int pulsesPerRevolution = 64 * 150;  // Adjust based on your encoder and gearing

// Auger Motor Settings
const int augerSpeed = 150;  // Default motor speed (0-400 range)
unsigned long augerMotorTimeout = 180000;  // Safety timeout (30 seconds)

// Function to turn on the popper and start its timer
void turnPopperOn() {
    digitalWrite(popperPin, HIGH);
    popperActive = true;
    popperStartTime = millis();
    Serial.println("Popper turned ON - Timer started (5 minutes)");
}

// Function to turn off the popper
void turnPopperOff() {
    digitalWrite(popperPin, LOW);
    popperActive = false;
    Serial.println("Popper turned OFF");
}

// Function to monitor popper timer
void monitorPopperTimer() {
    if (popperActive && (millis() - popperStartTime >= popperTimeout)) {
        turnPopperOff();
        Serial.println("Popper timeout reached (5 minutes)");
    }
}

// Helper function to check for motor driver faults
void stopIfFault()
{
  if (md.getM1Fault())
  {
    md.disableDrivers();
    delay(1);
    Serial.println("M1 fault");
    turnPopperOff();  // Turn off popper on motor fault
    while (1);
  }
  if (md.getM2Fault())
  {
    md.disableDrivers();
    delay(1);
    Serial.println("M2 fault");
    turnPopperOff();  // Turn off popper on motor fault
    while (1);
  } 
}

// Helper function to configure the stepper motor
void configureStepper(float maxSpeed, float acceleration) {
    myStepper.setMaxSpeed(maxSpeed);
    myStepper.setAcceleration(acceleration);
}

void setup() {
    // Initialize serial communication for debugging
    Serial.begin(9600);
    Serial.println("Starting system initialization...");

    // Initialize popper control pin
    pinMode(popperPin, OUTPUT);
    digitalWrite(popperPin, LOW);  // Ensure popper starts in OFF state
    Serial.println("Popper control initialized (OFF)");

    // Initialize Pololu motor driver
    Serial.println("Initializing main motor driver (md)...");
    md.init();
    md.calibrateCurrentOffsets();
    delay(10);
    
    // Initialize the md2 motor driver for auger control - THIS WAS MISSING
    Serial.println("Initializing auger motor driver (md2)...");
    md2.init();
    md2.calibrateCurrentOffsets();
    delay(10);
    
    // Enable drivers
    Serial.println("Enabling motor drivers...");
    md.enableDrivers();
    md2.enableDrivers();
    delay(10);  // Give more time for drivers to initialize
    
    // Start with motors stopped
    md.setM1Speed(0);
    md.setM2Speed(0);
    md2.setM1Speed(0);
    md2.setM2Speed(0);

    // Initialize stepper motor pins
    pinMode(enablePin, OUTPUT);
    digitalWrite(enablePin, HIGH); // Disable the motor by default
    pinMode(limitSwitchForward, INPUT_PULLUP);
    pinMode(limitSwitchReverse, INPUT_PULLUP);
    pinMode(M0, OUTPUT);
    pinMode(M1, OUTPUT);
    pinMode(M2, OUTPUT);

    // Set microstepping mode to 1/8 step
    digitalWrite(M0, HIGH);
    digitalWrite(M1, HIGH);
    digitalWrite(M2, LOW);

    // Set stepper motor parameters
    configureStepper(1000, 500);

    // Initialize encoder for auger control
    setupEncoder();
    
    // Initialize the load cell
    setupLoadCell();

    // User prompt
    Serial.println("System ready.");
    Serial.println("Commands:");
    Serial.println("  Home - Move to home position");
    Serial.println("  F - Move fixed steps in reverse");
    Serial.println("  D - Start load cell monitoring and popper");
    Serial.println("  A<turns> - Rotate auger (e.g., A2.5 for 2.5 turns)");
    Serial.println("  Status - Show system status");
}

void setupLoadCell() {
    Serial.println("NAU7802 Load Cell Setup");
    if (!nau.begin()) {
        Serial.println("Failed to find NAU7802");
        while (true); // Halt if load cell initialization fails
    }
    Serial.println("Found NAU7802");

    nau.setLDO(NAU7802_3V0);
    nau.setGain(NAU7802_GAIN_128);
    nau.setRate(NAU7802_RATE_10SPS);

    // Flush initial readings
    for (uint8_t i = 0; i < 10; i++) {
        while (!nau.available()) delay(1);
        nau.read();
    }

    while (!nau.calibrate(NAU7802_CALMOD_INTERNAL)) {
        Serial.println("Failed to calibrate internal offset, retrying!");
        delay(1000);
    }

    while (!nau.calibrate(NAU7802_CALMOD_OFFSET)) {
        Serial.println("Failed to calibrate system offset, retrying!");
        delay(1000);
    }
    Serial.println("Calibration complete");

    // Collect tare readings
    int32_t tareSum = 0;
    const int tareReadings = 25;
    for (uint8_t i = 0; i < tareReadings; i++) {
        while (!nau.available()) delay(1);
        tareSum += nau.read();
    }
    loadcellTare = tareSum / tareReadings;
    Serial.print("Load Cell Tare Value: ");
    Serial.println(loadcellTare);

    // Initialize baseline
    currentBaseline = 0;
}

int32_t readLoadCell() {
    while (!nau.available()) delay(1);
    return 0.0025 * (nau.read() - loadcellTare); // Convert to grams
}

void resetLoadCell() {
    Serial.println("Resetting Load Cell Tare...");

    // Recalculate tare value
    int32_t tareSum = 0;
    const int tareReadings = 25;
    for (uint8_t i = 0; i < tareReadings; i++) {
        while (!nau.available()) delay(1);
        tareSum += nau.read();
    }
    loadcellTare = tareSum / tareReadings;
    Serial.print("New Load Cell Tare Value: ");
    Serial.println(loadcellTare);

    // Reset baseline
    currentBaseline = 0;
}

void loop() {
    // Continuously monitor the reverse limit switch
    monitorReverseLimitSwitch();

    // Monitor popper timer if active
    monitorPopperTimer();

    if (Serial.available() > 0) {
        String input = Serial.readStringUntil('\n');
        input.trim();

        if (input.equalsIgnoreCase("Home")) {
            Serial.println("Homing: Moving forward until the limit switch is triggered...");
            moveHome();
        } else if (input.equalsIgnoreCase("F")) {
            Serial.println("Moving reverse for fixed steps...");
            moveReverseFixedSteps();
        } else if (input.equalsIgnoreCase("D")) {
            // Reset for new "D" command activation
            resetLoadCell();  // Reset the load cell to fresh tare value
            dCommandActive = true;
            configureStepper(1000, 500); // Reconfigure stepper for D command
            
            // Reset the timeout timer
            lastWeightIncreaseTime = millis();
            
            // Reset cycle count
            resetCycleCount();

            // Turn on the popper
            turnPopperOn();

            Serial.println("Load Cell Monitoring Started...");
        } else if (input.startsWith("A")) {
            // Now process the command
            if (input.length() > 1) {
                // Extract the number of turns from command (e.g., "A2.5")
                float turns = input.substring(1).toFloat();
                
                if (turns != 0) {
                    Serial.print("Auger command received. Turning ");
                    Serial.print(turns);
                    Serial.println(" rotations.");
                    
                    // Set a shorter timeout for first test
                    unsigned long originalTimeout = augerMotorTimeout;
                    augerMotorTimeout = 15000; // 15 second timeout for safety
                    
                    bool result = auger(turns);
                    
                    // Restore original timeout
                    augerMotorTimeout = originalTimeout;
                    
                    if (!result) {
                        Serial.println("Auger operation failed. Motor has been stopped.");
                        emergencyStopAuger(); // Extra safety measure
                    }
                } else {
                    Serial.println("Invalid rotation value. Please specify a non-zero number (e.g., A1.5)");
                }
            } else {
                // Default behavior for just "A"
                Serial.println("Auger test mode. Performing 1/4 rotation test.");
                auger(0.25); // Just do a quarter turn for testing
            }
        } else if (input.startsWith("Set1:")) {
            // Set DC Motor 1 duration
            dcMotor1Duration = input.substring(5).toInt();
            Serial.print("DC Motor 1 duration set to: ");
            Serial.println(dcMotor1Duration);
        } else if (input.startsWith("Set2:")) {
            // Set DC Motor 2 duration
            dcMotor2Duration = input.substring(5).toInt();
            Serial.print("DC Motor 2 duration set to: ");
            Serial.println(dcMotor2Duration);
        } else if (input.equalsIgnoreCase("Status")) {
            // Print current status
            Serial.println("Current status:");
            Serial.print("DC Motor 1 duration: ");
            Serial.println(dcMotor1Duration);
            Serial.print("DC Motor 2 duration: ");
            Serial.println(dcMotor2Duration);
            
            // Report motor currents
            Serial.print("M1 current: ");
            Serial.print(md.getM1CurrentMilliamps());
            Serial.println(" mA");
            
            Serial.print("M2 current: ");
            Serial.print(md.getM2CurrentMilliamps());
            Serial.println(" mA");
            
            // Report popper status
            Serial.print("Popper status: ");
            Serial.println(popperActive ? "ON" : "OFF");
            if (popperActive) {
                unsigned long timeRemaining = (popperTimeout - (millis() - popperStartTime)) / 1000;
                Serial.print("Popper time remaining: ");
                Serial.print(timeRemaining);
                Serial.println(" seconds");
            }
        }
    }

    if (dCommandActive) {
        monitorLoadCell();
    }

    // Monitor DC Motors state - non-blocking
    monitorDCMotors();
    
    // Check for motor driver faults
    stopIfFault();  
}

// Reset cycle count function
const int maxCycleCount = 8;
int totalCyclesRun = 0;

void resetCycleCount() {
    totalCyclesRun = 0; // Reset cycle count at start of D command
}

// Updated monitorLoadCell function with timeout and forward limit switch detection
void monitorLoadCell() {
    int32_t loadCellValue = readLoadCell();
    Serial.print("Load Cell Value: ");
    Serial.println(loadCellValue);

    // Check forward limit switch
    if (digitalRead(limitSwitchForward) == LOW) {
        Serial.println("Forward limit switch triggered. Stopping D command.");
        stopDCommand();
        turnPopperOff(); // Turn off popper when limit switch is triggered
        return;
    }

    // Timeout logic
    if (millis() - lastWeightIncreaseTime > loadCellTimeout) {
        Serial.println("Timeout: No weight increase detected within the timeout duration. Stopping D command.");
        stopDCommand();
        return;
    }

    // Calculate the number of cycles needed
    int additionalWeight = loadCellValue - currentBaseline;
    int cyclesNeeded = additionalWeight / weightIncrement;

    // Adjust cyclesNeeded to not exceed maxCycleCount
    if (totalCyclesRun + cyclesNeeded > maxCycleCount) {
        cyclesNeeded = maxCycleCount - totalCyclesRun;
    }

    if (cyclesNeeded > 0) {
        currentBaseline += cyclesNeeded * weightIncrement; // Update baseline
        totalCyclesRun += cyclesNeeded; // Increment total cycle count

        Serial.print("Additional weight detected: ");
        Serial.print(additionalWeight);
        Serial.print("g. Running ");
        Serial.print(cyclesNeeded);
        Serial.println(" additional cycles.");

        // Reset timeout timer on weight increase
        lastWeightIncreaseTime = millis();

        // Trigger motor cycles and stop if limit switch is triggered
        for (int i = 0; i < cyclesNeeded; i++) {
            if (digitalRead(limitSwitchForward) == LOW) {
                Serial.println("Forward limit switch triggered during cycle. Stopping motor.");
                stopDCommand();
                turnPopperOff(); // Turn off popper when limit switch is triggered
                return;
            }
            executeMotorCycle();  // The cycle logic is handled in this function
        }
    }

    // Final threshold check
    if (loadCellValue > weightThreshold) {
        Serial.println("Final weight threshold reached. Executing final motor cycles.");
        executeMotorCycle(); // First motor cycle
        delay(5000);         // Wait 5 seconds
        executeMotorCycle(); // Second motor cycle
        stopDCommand();      // Stop load cell monitoring
        turnPopperOff();     // Turn off popper when weight threshold is reached
    }
}

// Helper function to stop D command
void stopDCommand() {
    dCommandActive = false;          // Disable D command monitoring
    lastWeightIncreaseTime = 0;      // Reset timeout tracking
    currentBaseline = 0;             // Reset baseline for new command
    Serial.println("D command stopped. Ready for a new command.");
}

// Updated executeMotorCycle function maintaining synchronized operation but non-blocking
void executeMotorCycle() {
    Serial.println("Starting Motor Cycle...");

    // Configure stepper motor with current settings
    configureStepper(1888, 2400); // Adjust these values as needed

    // Set step count for the stepper motor's movement
    int stepCount = 851; // Define how many steps to move per cycle
    myStepper.move(stepCount);

    // Enable stepper motor
    digitalWrite(enablePin, LOW); // Enable stepper motor
    bool stepperRunning = true;

    // Start DC motors
    startDCMotor1();
    delay(500);
    startDCMotor2();

    // Run the stepper motor until it completes its motion
    // This ensures proper sequencing while keeping DC motors non-blocking
    while (stepperRunning) {
        // Stepper motor control (step-based)
        if (myStepper.distanceToGo() == 0) {
            digitalWrite(enablePin, HIGH); // Disable stepper motor
            stepperRunning = false;
            Serial.println("Stepper Motor OFF");
        } else {
            if (digitalRead(limitSwitchForward) == LOW) { // Forward limit switch check
                Serial.println("Forward limit switch triggered during motor cycle. Stopping stepper motor.");
                myStepper.stop();
                digitalWrite(enablePin, HIGH); // Disable stepper
                stepperRunning = false;
                turnPopperOff(); // Turn off popper when limit switch is triggered
            } else {
                myStepper.run();
            }
        }
        
        // Still monitor DC motors even within this function
        monitorDCMotors();
    }
    
    // The DC motors will continue running and be monitored in the loop()
    Serial.println("Stepper cycle completed, DC motors may still be running");
}

// Non-blocking DC motor control functions
void startDCMotor1() {
    md.enableM1Driver();
    delay(1);
    md.setM1Speed(motorSpeed);
    isDCMotor1Running = true;
    dcMotor1StartTime = millis();
    Serial.println("DC Motor 1 ON");
}

void startDCMotor2() {
    md.enableM2Driver();
    delay(1);
    md.setM2Speed(motorSpeed);
    isDCMotor2Running = true;
    dcMotor2StartTime = millis();
    Serial.println("DC Motor 2 ON");
}   

void monitorDCMotors() {
    unsigned long currentTime = millis();
    
    // Check and update DC Motor 1
    if (isDCMotor1Running) {
        if (currentTime - dcMotor1StartTime >= dcMotor1Duration) {
            // Turn off DC motor 1 after the duration
            md.setM1Speed(0);
            isDCMotor1Running = false;
            Serial.println("DC Motor 1 OFF");
        }
    }
    
    // Check and update DC Motor 2
    if (isDCMotor2Running) {
        if (currentTime - dcMotor2StartTime >= dcMotor2Duration) {
            // Turn off DC motor 2 after the duration
            md.setM2Speed(0);
            isDCMotor2Running = false;
            Serial.println("DC Motor 2 OFF");
        }
    }
}
void encoderISR_A() {
  if (digitalRead(ENCODER_A) == digitalRead(ENCODER_B)) {
    encoderCount++;
  } else {
    encoderCount--;
  }
}

// Function to run when Encoder Channel B changes
void encoderISR_B() {
  if (digitalRead(ENCODER_A) == digitalRead(ENCODER_B)) {
    encoderCount--;
  } else {
    encoderCount++;
  }
}

// Add this to your setup() function after other initializations
// This configures the encoder pins and interrupts
void setupEncoder() {
  pinMode(ENCODER_A, INPUT_PULLUP);
  pinMode(ENCODER_B, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(ENCODER_A), encoderISR_A, CHANGE);
  attachInterrupt(digitalPinToInterrupt(ENCODER_B), encoderISR_B, CHANGE);
  
  Serial.println("Encoder setup complete");
}

// Emergency stop function for auger motor
void emergencyStopAuger() {
  // Try multiple approaches to ensure the motor stops
  
  // 1. Normal speed setting to zero
  md2.setM1Speed(0);
  
  // 2. Disable the driver
  md2.disableM1Driver();
  
  // 3. If possible, directly control the enable pin (if connected)
  // Uncomment if you have an enable pin connected for md2
  // digitalWrite(md2EnablePin, HIGH);  // HIGH typically disables the driver
  
  Serial.println("EMERGENCY STOP: Auger motor halted");
  
  // Turn off popper during emergency
  turnPopperOff();
  
  // Small delay to allow the motor to fully stop
  delay(100);
}

// Improved auger function to prevent overshooting
bool auger(float turns) {
  if (turns == 0) {
    Serial.println("Auger: Zero turns requested, no action needed");
    return true;
  }
  
  // Reset encoder at the start
  encoderCount = 0;
  delay(10); // Small delay to ensure the reset is processed
  
  Serial.print("Auger: Rotating for ");
  Serial.print(turns);
  Serial.println(" turns");
  
  // Calculate target encoder pulses
  long targetPulses = abs(turns) * pulsesPerRevolution;
  
  // Debug output
  Serial.print("Target pulses: ");
  Serial.println(targetPulses);
  
  // Get direction based on sign of turns
  int direction = (turns > 0) ? 1 : -1;
  
  // Set up timing variables
  unsigned long startTime = millis();
  unsigned long lastReportTime = startTime;
  unsigned long lastEncoderCheckTime = startTime;
  long lastEncoderCount = 0;
  
  // Start the motor with gradual acceleration
  md2.enableM1Driver();
  delay(20); // Small delay to ensure driver is enabled
  
  // Gradual speed ramp-up to avoid sudden current spikes
  for (int i = 50; i <= 200; i += 25) { // Lower max speed to 200 from 300
    md2.setM1Speed(i * direction);
    delay(20);
    
    // Check for faults during ramp-up
    if (md2.getM1Fault()) {
      Serial.print("Fault detected during speed ramp-up at speed ");
      Serial.println(i);
      emergencyStopAuger();
      return false;
    }
  }
  
  // Main control loop with multiple safety checks
  bool approachingTarget = false;
  int currentSpeed = 200 * direction; // Start at our max speed
  
  while (abs(encoderCount) < targetPulses) {
    // Begin deceleration when we're 75% of the way there
    if (!approachingTarget && abs(encoderCount) > (targetPulses * 0.75)) {
      approachingTarget = true;
      Serial.println("Approaching target: starting deceleration");
      
      // Reduce speed for more precise stopping
      currentSpeed = 100 * direction;
      md2.setM1Speed(currentSpeed);
    }
    
    // Further reduce speed when we're 90% of the way there
    if (approachingTarget && abs(encoderCount) > (targetPulses * 0.9)) {
      currentSpeed = 75 * direction;
      md2.setM1Speed(currentSpeed);
    }
    
    // Final slow approach at 95%
    if (approachingTarget && abs(encoderCount) > (targetPulses * 0.95)) {
      currentSpeed = 50 * direction;
      md2.setM1Speed(currentSpeed);
    }
    
    // PRIMARY SAFETY CHECK: Maximum runtime exceeded
    if (millis() - startTime > augerMotorTimeout) {
      Serial.println("SAFETY: Timeout reached! Emergency stop.");
      emergencyStopAuger();
      return false;
    }
    
    // SAFETY CHECK: Motor fault detected
    if (md2.getM1Fault()) {
      Serial.println("SAFETY: M1 fault detected! Emergency stop.");
      emergencyStopAuger();
      return false;
    }
    
    // SAFETY CHECK: Encoder not responding (check every 500ms)
    if (millis() - lastEncoderCheckTime > 500) {
      if (encoderCount == lastEncoderCount) {
        Serial.println("SAFETY: Encoder not updating! Emergency stop.");
        emergencyStopAuger();
        return false;
      }
      lastEncoderCount = encoderCount;
      lastEncoderCheckTime = millis();
    }
    
    // SAFETY CHECK: If we're overshooting, stop immediately
    if (abs(encoderCount) >= targetPulses + 100) {
      Serial.println("SAFETY: Overshooting target! Emergency stop.");
      emergencyStopAuger();
      return false;
    }
    
    // Progress reporting (every second)
    if (millis() - lastReportTime > 1000) {
      lastReportTime = millis();
      // Show motor current before position
      Serial.print("M1 current: ");
      Serial.print(md2.getM1CurrentMilliamps());
      Serial.println(" mA");
      
      Serial.print("Auger: Position ");
      Serial.print(encoderCount);
      Serial.print(" / ");
      Serial.print(targetPulses);
      Serial.print(" (");
      Serial.print((float)abs(encoderCount) / targetPulses * 100);
      Serial.println("%)");
    }
  }
  
  // As soon as we reach or exceed the target, stop immediately
  Serial.print("Target reached at position ");
  Serial.println(encoderCount);
  
  // Immediate stop - don't use gradual deceleration here to prevent overshooting
  md2.setM1Speed(0);
  delay(10);
  md2.disableM1Driver();
  
  // Final position report
  Serial.print("Auger: Final position: ");
  Serial.print(encoderCount);
  Serial.print(" / ");
  Serial.println(targetPulses);
  
  return true;
}

// Function for "Home" command
void moveHome() {
    digitalWrite(enablePin, LOW);  // Enable the motor
    myStepper.setSpeed(400);

    // Move forward until the forward limit switch is triggered
    while (digitalRead(limitSwitchForward) == HIGH) {
        monitorReverseLimitSwitch();
        myStepper.runSpeed();
    }
    // Stop the motor
    Serial.println("Forward limit switch reached. Homing complete.");
    myStepper.stop();
    digitalWrite(enablePin, HIGH); // Disable the motor
}

// Function for "F" command
void moveReverseFixedSteps() {
    digitalWrite(enablePin, LOW);  // Enable the motor
    configureStepper(200, 500);
    // Move reverse for reverseStepCount steps
    myStepper.move(-reverseStepCount);
    while (myStepper.distanceToGo() != 0) {
        monitorReverseLimitSwitch();
        myStepper.run();
    }
    // Stop the motor
    Serial.println("Reverse motion complete.");
    myStepper.stop();
    digitalWrite(enablePin, HIGH); // Disable the motor
}

// Function to monitor the reverse limit switch
void monitorReverseLimitSwitch() {
    if (digitalRead(limitSwitchReverse) == LOW) {
        Serial.println("Reverse limit switch triggered. Stopping motion.");
        stopAllMotion();
        turnPopperOff(); // Turn off popper when reverse limit switch is triggered
        while (true); // Halt program until reset
    }
}

// Stop all motion
void stopAllMotion() {
    myStepper.stop();
    md.setM1Speed(0);   // Turn off DC motor 1
    md.setM2Speed(0);   // Turn off DC motor 2
    digitalWrite(enablePin, HIGH); // Disable the stepper motor
    isDCMotor1Running = false;
    isDCMotor2Running = false;
    turnPopperOff();
}```

Does this translate to: If you run the setup with extension cord far from arduino, everything works without problems?

Are you sure the SSR is wired correctly? It sounds like it isn't since normal operation would have NO affect on the 2560.

Yes if i run it with the extension cord maybe 2 ft away it works fine. When i move the extension cord closer eventually it will freeze. But if i run it with the relay plugged in, but 2 ft way, it still freezes.

Yeah the SSR is wired correctly.If i run this test code for the SSR it turns on and off the popper with no issues.

// SSR Relay Control via Serial Input
// Controls a Solid State Relay connected to pin 22
// 'G' turns the relay ON (high signal)
// 'S' turns the relay OFF (low signal)

const int relayPin = 22;  // SSR control pin
char serialInput;        // Variable to store serial input

void setup() {
  // Initialize serial communication at 9600 baud
  Serial.begin(9600);
  
  // Set the relay pin as output
  pinMode(relayPin, OUTPUT);
  
  // Ensure relay starts in OFF state
  digitalWrite(relayPin, LOW);
  
  // Print instructions to serial monitor
  Serial.println("SSR Relay Control");
  Serial.println("Send 'G' to turn ON the relay (high signal)");
  Serial.println("Send 'S' to turn OFF the relay (low signal)");
}

void loop() {
  // Check if data is available to read from serial
  if (Serial.available() > 0) {
    // Read the incoming byte
    serialInput = Serial.read();
    
    // Process the input
    if (serialInput == 'G' || serialInput == 'g') {
      digitalWrite(relayPin, HIGH);  // Turn ON the relay
      Serial.println("Relay ON - Power enabled");
    }
    else if (serialInput == 'S' || serialInput == 's') {
      digitalWrite(relayPin, LOW);   // Turn OFF the relay
      Serial.println("Relay OFF - Power disabled");
    }
  }
}

I don't know what's going on with your popcorn machine. I would expect a heating element and maybe small fan to blow popcorns out. Maybe yours have some dirty triac circuit to regulate heating power. Anyway I suggest you to add a RC snubber on your circuit.

Would posting some photos of the machine circuit help? You have the right idea though. There is a dc motor, a fan, a on off switch and something that detects when the system gets too hot and turns things off.

Can you explain how i would add a RC Subber/what that is? My background is mechanical engineering so a lot of this is unfamiliar to me.

In that case, there is a bug in the control circuit that makes the popcorn machine turn on. It sounds like more than one, in fact. I would add some noise suppression and maybe shield the control line.

If you don't want to tear down the whole machine and inspect what is causing interferences you can add snubber across the relay output to give a try.

Anyway, these problems are tricky to source, for example some spaghetti wiring is likely to cause problems. Keep your arduino signal wiring short and far from power wires.