/********* Pleasedontcode.com ********** Pleasedontcode thanks you for automatic code generation! Enjoy your code! - Terms and Conditions: You have a non-exclusive, revocable, worldwide, royalty-free license for personal and commercial use. Attribution is optional; modifications are allowed, but you're responsible for code maintenance. We're not liable for any loss or damage. For full terms, please visit pleasedontcode.com/termsandconditions. - Project: Dual-Mode Control - Source Code NOT compiled for: Arduino Mega - Source Code created on: 2025-09-27 14:44:33 ********* Pleasedontcode.com **********/ /****** SYSTEM REQUIREMENTS *****/ /****** SYSTEM REQUIREMENT 1 *****/ /* help refine the code. want to run the code */ /* smoothly both in auto mode and manual mode. */ /****** END SYSTEM REQUIREMENTS *****/ /* START CODE */ /****** DEFINITION OF LIBRARIES *****/ /****** FUNCTION PROTOTYPES *****/ void setup(void); void loop(void); // Merged content from USER CODE, adapted to fit the PRELIMINARY CODE structure for Arduino Mega //Last Updated 12092025 // Define stepper motor1 of Linear guide @ Spinning Motor driver pins const int DRIVER1_DIR = 28; // Direction pin for stepper motor1 const int DRIVER1_STEP = 18; // Step pin for stepper motor1 const int DRIVER1_ENA = 29; // Enable pin for stepper motor1 // Define stepper motor2 of Linear guide @ Feeder Motor driver pins const int DRIVER2_DIR = 30; // Direction pin for stepper motor2 const int DRIVER2_STEP = 6; // Step pin for stepper motor2 const int DRIVER2_ENA = 31; // Enable pin for stepper motor2 // Proximity Sensor for Induction Motor CW and CCW const int PROXY_POS = 10; // Proxy POS Sensor for Linear Motor Position const int PROXY_A = 11; // Proxy A Sensor for CW const int PROXY_B = 12; // Proxy B Sensor for CCW // const int PROXY_RUNFEED = 13; // Proxy Feed Run Sensor // Define BTS7960B motor driver pins for Feeder motor const int EN_FEEDER = 20; // Enable pin for feeder motor const int LPWM_FEEDER = 3; // Left PWM pin for feeder motor const int RPWM_FEEDER = 4; // Right PWM pin for feeder motor // Define Limit switchs of Linear drive @ Spinning motor const int LIMIT_SWITCH1 = 15; // 32; // Limit switch 1 pin (Bottom) const int LIMIT_SWITCH2 = 33; // Limit switch 2 pin (Up) // Define Limit switchs of Linear drive @ Feeder motor const int LIMIT_SWITCH3 = 35; // Limit switch 3 pin (Reverse) const int LIMIT_SWITCH4 = 16; // Limit switch 4 pin (Forward) // Define relay pins const int RELAY1 = A0; // Relay for const int RELAY2 = A1; // Relay for Air-Nipper Cutter const int RELAY3 = A12; // Relay for Gripper 1 const int RELAY4 = A3; // Relay for Gripper 2 const int RELAY5 = A4; // Relay for CW direction const int RELAY6 = A5; // Relay for CCW direction const int RELAY7 = A6; // Relay for Feeder Linear Drive const int RELAY8 = A7; // Relay for Label Vaccum pad Forward/Backward const int RELAY9 = 43; // Relay for Spinning Linear Drive const int RELAY10 = 45; // Relay for Cutter-up & Cutter-down Cylinder const int RELAY11 = 46; // Relay for const int RELAY12 = 47; // Relay for const int RELAY13 = 48; // Relay for const int RELAY14 = 49; // Relay for const int RELAY15 = 50; // Relay for const int RELAY16 = 51; // Relay for // Flags and variables bool autoMode = false; // Flag for Auto Mode bool manualMode = false; // Flag for Manual Mode int numCycles = 0; // Variable to store number of cycles bool feederRunning = false; // Flag to indicate if the feeder is running bool isForward = false; int targetCounts = 0; // Stores the required counts for current operation volatile int countA = 0; // Count for Proxy A volatile int countB = 0; // Count for Proxy B bool motorRunning = false; // Flag to indicate if the motor is currently running bool countingEnabled = false; // Flag to enable counting based on relay state bool isClockwise = false; // Global variable to track motor direction bool countProxyAEnabled = true; // Flag to enable/disable counting for Proxy A bool countProxyBEnabled = true; // Flag to enable/disable counting for Proxy B bool countProxyPOSEnabled = true; // Flag to enable/disable counting for Proxy POS volatile bool isMoving1 = false; // Flag to indicate if the linear guide is currently moving volatile bool isMoving2 = false; // Flag to indicate if the linear guide is currently moving unsigned long feederStartTime = 0; // When feeder started unsigned long feederDuration = 0; // How long to run (ms) bool linearGuide1Complete = false; bool linearGuide2Complete = false; bool feederComplete = false; bool motorComplete = false; // Command enumeration enum Command { START, STOP, G1, G2, G3, G4, VC, VO, VF, VR, PU, PD, OG, CW, CCW, LU, LD, LF, LR, CU, CD, CX, X, FD, RD, AUTO, MANUAL, NONE, UNKNOWN }; // Debounce variables const unsigned long DEBOUNCE_TIME = 1000; // 1 second debounce time unsigned long lastCommandTime = 0; // Variable to store the last command execution time // Auto mode state machine variables enum AutoState { AUTO_IDLE, AUTO_CHECK_POS, AUTO_LU, AUTO_LF, AUTO_VF, AUTO_FD, AUTO_G3, AUTO_LR, AUTO_G1, AUTO_CU, AUTO_CX, AUTO_CD, AUTO_LD, AUTO_VR, AUTO_CW, AUTO_CCW, AUTO_OG, AUTO_COMPLETE, AUTO_CW_RUNNING, AUTO_CCW_RUNNING, AUTO_STOPPED }; AutoState autoState = AUTO_IDLE; int currentCycle = 0; unsigned long autoStepStartTime = 0; const unsigned long STEP_DELAY = 100; // 100ms delay between steps // Completion check functions bool isLinearGuide1Complete() { return linearGuide1Complete; } bool isLinearGuide2Complete() { return linearGuide2Complete; } bool isFeederComplete() { return feederComplete; } bool isMotorComplete() { return motorComplete; } // Function declarations void stopMotor(); // To Stop Linear Motor, Feeder Motor, Spinning Motor void moveLinearGuide1(String direction); // To move Linear UP and Down void moveLinearGuide2(String direction); // To move Linear Right and Left void moveStepper1(bool direction, int stopPin); // To Execute Linear & Spinning in sequence void moveStepper2(bool direction, int stopPin); // To Execute Linear & Feeder in sequence void runFeeder(bool forward, unsigned long durationMillis = 0, int speed = 25); // To activte Feeder motor void setFeederMotorSpeed(int speed, bool forward); void runOpenGripper(); // To deactivate Gripper Relay 3 & 4 void runMotor(bool clockwise); // Combined CW and CCW motor function void handleCommand(Command cmd); // To handle and execute Manual Input Command bool runAutoMode(int numCycles); // To execute Auto Input Command sequence void resetSerialBuffer(); // To reset Command line bool checkStopCommand(); // To check for STOP command during process void resetMode(); void CutterSensor(); void proxyA(); void proxyB(); // Subsystem wrappers to isolate auto/manual control (new) void Subsystem_AutoStart(int cycles) { // Initialize and start Auto mode for a fixed cycle count numCycles = cycles; autoMode = true; autoState = AUTO_IDLE; currentCycle = 0; Serial.print("Subsystem Auto Start: "); Serial.println(cycles); } void Subsystem_AutoTick() { updateAutoMode(); } void Subsystem_AutoStop() { stopAutoMode(); } void Subsystem_ManualActivate() { manualMode = true; resetMode(); Serial.println("Subsystem Manual Mode Activated"); } void Subsystem_ManualDeactivate() { manualMode = false; Serial.println("Subsystem Manual Mode Deactivated"); } bool Subsystem_AutoRunning() { return autoMode; } Command parseCommand(String command); Command currentMode = NONE; // Helper functions to set completion flags void setLinearGuide1Complete() { linearGuide1Complete = true; Serial.println("Linear Guide 1 operation complete"); } void setLinearGuide2Complete() { linearGuide2Complete = true; Serial.println("Linear Guide 2 operation complete"); } void setFeederComplete() { feederComplete = true; Serial.println("Feeder operation complete"); } void setMotorComplete() { motorComplete = true; Serial.println("Motor operation complete"); } void setup() { // Set pin modes for motors and relays pinMode(RPWM_FEEDER, OUTPUT); pinMode(LPWM_FEEDER, OUTPUT); pinMode(EN_FEEDER, OUTPUT); pinMode(PROXY_POS, INPUT_PULLUP); // Set proxy POS as input pinMode(PROXY_A, INPUT_PULLUP); // Set proxy A as input pinMode(PROXY_B, INPUT_PULLUP); // Set proxy B as input // pinMode(PROXY_RUNFEED, INPUT); // Set proxy Feed Run as input pinMode(RELAY1, OUTPUT); pinMode(RELAY2, OUTPUT); pinMode(RELAY3, OUTPUT); pinMode(RELAY4, OUTPUT); pinMode(RELAY5, OUTPUT); pinMode(RELAY6, OUTPUT); pinMode(RELAY7, OUTPUT); pinMode(RELAY8, OUTPUT); pinMode(RELAY9, OUTPUT); pinMode(RELAY10, OUTPUT); pinMode(RELAY11, OUTPUT); pinMode(RELAY12, OUTPUT); pinMode(RELAY13, OUTPUT); pinMode(RELAY14, OUTPUT); pinMode(RELAY15, OUTPUT); pinMode(RELAY16, OUTPUT); pinMode(LIMIT_SWITCH1, INPUT_PULLUP); pinMode(LIMIT_SWITCH2, INPUT_PULLUP); pinMode(LIMIT_SWITCH3, INPUT_PULLUP); pinMode(LIMIT_SWITCH4, INPUT_PULLUP); pinMode(DRIVER1_STEP, OUTPUT); pinMode(DRIVER1_DIR, OUTPUT); pinMode(DRIVER1_ENA, OUTPUT); pinMode(DRIVER2_STEP, OUTPUT); pinMode(DRIVER2_DIR, OUTPUT); pinMode(DRIVER2_ENA, OUTPUT); // Initialize relays to LOW (off state) digitalWrite(RELAY1, LOW); digitalWrite(RELAY2, LOW); digitalWrite(RELAY3, LOW); digitalWrite(RELAY4, LOW); digitalWrite(RELAY5, LOW); digitalWrite(RELAY6, LOW); digitalWrite(RELAY7, LOW); digitalWrite(RELAY8, LOW); digitalWrite(RELAY9, LOW); digitalWrite(RELAY10, LOW); digitalWrite(RELAY11, LOW); digitalWrite(RELAY12, LOW); digitalWrite(RELAY13, LOW); digitalWrite(RELAY14, LOW); digitalWrite(RELAY15, LOW); digitalWrite(RELAY16, LOW); digitalWrite(DRIVER1_ENA, LOW); // Enable stepper motor1 digitalWrite(DRIVER2_ENA, LOW); // Enable stepper motor2 Serial.begin(9600); // Start serial communication resetSerialBuffer(); // Clear serial buffer on startup } Command parseCommand(String command) { command.trim(); // Parse incoming command strings and return corresponding Command enum if (command == "START") return START; if (command == "STOP") return STOP; if (command == "G1") return G1; if (command == "G2") return G2; if (command == "G3") return G3; if (command == "G4") return G4; if (command == "VC") return VC; if (command == "VO") return VO; if (command == "VF") return VF; if (command == "VR") return VR; if (command == "PU") return PU; if (command == "PD") return PD; if (command == "OG") return OG; if (command == "CW") return CW; if (command == "CCW") return CCW; if (command == "LU") return LU; if (command == "LD") return LD; if (command == "LF") return LF; if (command == "LR") return LR; if (command == "CU") return CU; if (command == "CD") return CD; if (command == "CX") return CX; if (command == "X") return X; if (command == "FD") return FD; // Forward command if (command == "RD") return RD; // Reverse command if (command == "AUTO") return AUTO; // Auto mode if (command == "MANUAL") return MANUAL; // Manual mode return UNKNOWN; // Return UNKNOWN if command is not recognized } void handleCommand(Command cmd) { // Handle commands based on the parsed Command enum switch (cmd) { case START: Serial.println("Process started."); break; case STOP: stopMotor(); Serial.println("MOTORS STOPPED"); break; case G1: digitalWrite(RELAY3, HIGH); // Activate RELAY3 for G1 Close Serial.println("RELAY3 ON"); break; case G2: digitalWrite(RELAY3, LOW); // Deactivate RELAY3 for G2 Open Serial.println("RELAY3 OFF"); break; case G3: digitalWrite(RELAY4, HIGH); // Activate RELAY4 for G2 Close Serial.println("RELAY4 ON"); break; case G4: digitalWrite(RELAY4, LOW); // Deactivate RELAY4 for G2 Open Serial.println("RELAY4 OFF"); break; case VC: // Removed as on 28082025 digitalWrite(RELAY11, HIGH); // Activate RELAY10 for Vaccum pad Pick Serial.println("RELAY11 ON"); break; case VO: // Removed as on 28082025 digitalWrite(RELAY11, LOW); // Deactivate RELAY10 for Vaccum pad Eject Serial.println("RELAY11 OFF"); break; case VF: digitalWrite(RELAY8, HIGH); // Activate RELAY8 for Vaccum pad Forward Serial.println("RELAY8 ON"); break; case VR: digitalWrite(RELAY8, LOW); // Deactivate RELAY8 for Vaccum pad Reverse Serial.println("RELAY8 OFF"); break; case PU: digitalWrite(RELAY11, HIGH); // Activate RELAY11 for Push Up Load Serial.println("RELAY11 ON"); break; case PD: digitalWrite(RELAY11, LOW); // Deactivate RELAY11 for Push Down Load Serial.println("RELAY11 OFF"); break; case OG: runOpenGripper(); Serial.println("Gripper 1 & 2 OPEN..."); break; case CW: runMotor(true); Serial.println("Starting CW motor..."); break; case CCW: runMotor(false); Serial.println("Starting CCW motor..."); break; case LU: moveLinearGuide1("LU"); Serial.println("Linear Guide1 Moving Up"); break; case LD: moveLinearGuide1("LD"); Serial.println("Linear Guide1 Moving Down"); break; case LF: moveLinearGuide2("LF"); Serial.println("Linear Guide2 Moving Forward"); break; case LR: moveLinearGuide2("LR"); Serial.println("Linear Guide2 Moving Reverse"); break; case CX: digitalWrite(RELAY2, HIGH); delay(1000); digitalWrite(RELAY2, LOW); Serial.println("Air-Nipper Cutter Operated."); break; case CU: digitalWrite(RELAY10, HIGH); // Activate RELAY10 for Cutter Up Load Serial.println("RELAY10 ON"); break; case CD: digitalWrite(RELAY10, LOW); // Deactivate RELAY10 for Cutter Down Load Serial.println("RELAY10 OFF"); break; case X: stopMotor(); Serial.println(" All motors stopped."); break; case FD: runFeeder(true, 2150); // Move feeder forward Serial.println("Feeder moving forward."); break; case RD: runFeeder(false, 2150); // Move feeder reverse Serial.println("Feeder moving reverse."); break; case AUTO: if (!autoMode) { // Only prompt if not already in Auto mode resetMode(); // Reset mode before starting Auto Mode autoMode = true; // Set Auto mode flag autoState = AUTO_IDLE; currentCycle = 0; Serial.println("Auto mode activated."); // delay(2000); Serial.println("Please enter the number of cycles:"); unsigned long startWaitTime = millis(); while (millis() - startWaitTime < 10000) { if (Serial.available() > 0) { numCycles = Serial.parseInt(); if (numCycles > 0) { Serial.print("Starting Auto Mode for " ); Serial.print(numCycles); Serial.println(" cycles."); break; } else { Serial.println("Invalid input. Please entre a positive number:"); } } } if (numCycles == 0) { Serial.println("Timeout! Auto mode cancelled."); autoMode = false; } } break; case MANUAL: if (!manualMode) { // Only prompt if not already in Manual mode resetMode(); // Reset mode before starting Manual Mode manualMode = true; // Set Manual mode flag Serial.println("Manual mode activated."); } break; default: Serial.println("UNKNOWN COMMAND"); break; } } void loop() { // Process serial commands non-blockingly if (Serial.available() > 0) { String command = Serial.readStringUntil('\n'); command.trim(); // Remove any trailing spaces or newlines Serial.flush(); // Clear buffer after reading Serial.println("Received: " + command); // Debugging // Check if enough time has passed since the last command if (millis() - lastCommandTime >= DEBOUNCE_TIME) { Command cmd = parseCommand(command); lastCommandTime = millis(); if (cmd == STOP || cmd == X) { // Handle stop command immediately if (autoMode) { stopAutoMode(); } handleCommand(cmd); } else if (cmd == AUTO) { handleCommand(cmd); } else if (cmd == MANUAL) { handleCommand(cmd); } else { // Handle other commands (START, STOP, Q, etc.) handleCommand(cmd); } // Clear serial buffer after mode changes or commands resetSerialBuffer(); } } // If in Auto mode, run the auto sequence incrementally if (autoMode) { updateAutoMode(); } // State monitoring (no more proxy function calls) updateFeeder(); if (motorRunning) { if (isClockwise) { // Check if the motor is running CW proxyA(); // Check Proxy A } else { // Otherwise, it must be CCW proxyB(); // Check Proxy B } } } void updateAutoMode() { static unsigned long lastUpdateTime = 0; static bool firstTimeInState = true; unsigned long currentTime = millis(); // Update at 100ms intervals for responsiveness if (currentTime - lastUpdateTime < 100) { return; } lastUpdateTime = currentTime; // Check for stop commands continuously if (checkStopCommand()) { stopAutoMode(); return; } switch (autoState) { case AUTO_IDLE: if (firstTimeInState) { Serial.print("AUTO_IDLE - Starting cycle "); Serial.println(currentCycle + 1); firstTimeInState = false; autoStepStartTime = currentTime; } if (currentTime - autoStepStartTime > 500) { if (currentCycle < numCycles) { currentCycle++; Serial.print("Starting cycle "); Serial.println(currentCycle); autoState = AUTO_CHECK_POS; firstTimeInState = true; autoStepStartTime = currentTime; } else { autoState = AUTO_COMPLETE; } } break; case AUTO_CHECK_POS: if (firstTimeInState) { int sensorState = digitalRead(PROXY_POS); Serial.print("Proxy POS Sensor State: "); Serial.println(sensorState); if (sensorState == LOW) { Serial.println("Proxy POS not active! Cannot proceed."); autoState = AUTO_STOPPED; } else { Serial.println("Proxy POS active. Proceeding to LU..."); autoState = AUTO_LU; firstTimeInState = true; } autoStepStartTime = currentTime; } break; case AUTO_LU: if (firstTimeInState) { linearGuide1Complete = false; moveLinearGuide1("LU"); Serial.println("Executing LU command..."); firstTimeInState = false; autoStepStartTime = currentTime; } if (isLinearGuide1Complete()) { autoState = AUTO_LF; firstTimeInState = true; autoStepStartTime = currentTime; break; } // Timeout safety if (currentTime - autoStepStartTime > 15000) { Serial.println("LU operation timeout!"); autoState = AUTO_STOPPED; } break; case AUTO_LF: if (firstTimeInState) { linearGuide2Complete = false; moveLinearGuide2("LF"); Serial.println("Executing LF command..."); firstTimeInState = false; autoStepStartTime = currentTime; delay(1000); } if (isLinearGuide2Complete()) { autoState = AUTO_VF; firstTimeInState = true; autoStepStartTime = currentTime; break; } if (currentTime - autoStepStartTime > 15000) { Serial.println("LF operation timeout!"); autoState = AUTO_STOPPED; } break; case AUTO_VF: digitalWrite(RELAY8, HIGH); Serial.println("Executing VF command..."); autoState = AUTO_FD; autoStepStartTime = currentTime; delay(1000); break; case AUTO_FD: if (firstTimeInState) { feederComplete = false; runFeeder(true, 2150); Serial.println("Executing FD command..."); firstTimeInState = false; autoStepStartTime = currentTime; } if (isFeederComplete()) { autoState = AUTO_G3; firstTimeInState = true; autoStepStartTime = currentTime; break; } if (currentTime - autoStepStartTime > 5000) { Serial.println("FD operation timeout!"); autoState = AUTO_STOPPED; } break; case AUTO_G3: digitalWrite(RELAY4, HIGH); Serial.println("Executing G3 command..."); autoState = AUTO_LR; autoStepStartTime = currentTime; break; case AUTO_LR: if (firstTimeInState) { linearGuide2Complete = false; moveLinearGuide2("LR"); Serial.println("Executing LR command..."); firstTimeInState = false; autoStepStartTime = currentTime; } if (isLinearGuide2Complete()) { autoState = AUTO_G1; firstTimeInState = true; autoStepStartTime = currentTime; break; } if (currentTime - autoStepStartTime > 15000) { Serial.println("LR operation timeout!"); autoState = AUTO_STOPPED; } break; case AUTO_G1: digitalWrite(RELAY3, HIGH); Serial.println("Executing G1 command..."); autoState = AUTO_CU; autoStepStartTime = currentTime; delay(1000); break; case AUTO_CU: digitalWrite(RELAY10, HIGH); Serial.println("Executing CU command..."); autoState = AUTO_CX; autoStepStartTime = currentTime; delay(1000); break; case AUTO_CX: digitalWrite(RELAY2, HIGH); Serial.println("Executing CX command..."); autoState = AUTO_CD; autoStepStartTime = currentTime; delay(1000); break; case AUTO_CD: digitalWrite(RELAY2, LOW); digitalWrite(RELAY10, LOW); Serial.println("Executing CD command..."); autoState = AUTO_LD; autoStepStartTime = currentTime; delay(1000); break; case AUTO_LD: if (firstTimeInState) { linearGuide1Complete = false; moveLinearGuide1("LD"); Serial.println("Executing LD command..."); firstTimeInState = false; autoStepStartTime = currentTime; } if (isLinearGuide1Complete()) { autoState = AUTO_CW; firstTimeInState = true; autoStepStartTime = currentTime; break; } if (currentTime - autoStepStartTime > 15000) { Serial.println("LD operation timeout!"); autoState = AUTO_STOPPED; } break; case AUTO_CW: if (firstTimeInState) { motorComplete = false; runMotor(true); Serial.println("Executing CW command..."); firstTimeInState = false; autoStepStartTime = currentTime; autoState = AUTO_CW_RUNNING; // Move to intermediate state } break; case AUTO_CW_RUNNING: // Check if motor has completed its operation if (isMotorComplete()) { Serial.println("CW operation completed."); autoState = AUTO_VR; // Move to next main state firstTimeInState = true; } // Timeout safety if (currentTime - autoStepStartTime > 30000) { Serial.println("CW operation timeout!"); stopMotor(); autoState = AUTO_STOPPED; } break; case AUTO_VR: digitalWrite(RELAY8, LOW); Serial.println("Executing VR command..."); autoState = AUTO_OG; autoStepStartTime = currentTime; break; case AUTO_OG: if (firstTimeInState) { runOpenGripper(); Serial.println("Executing OG command..."); firstTimeInState = false; autoStepStartTime = currentTime; } // Wait 3000ms for OG delay if (currentTime - autoStepStartTime >= 3000) { autoState = AUTO_CCW; firstTimeInState = true; autoStepStartTime = currentTime; } break; case AUTO_CCW: if (firstTimeInState) { motorComplete = false; runMotor(false); // Start CCW motor Serial.println("Executing CCW command..."); firstTimeInState = false; autoStepStartTime = currentTime; autoState = AUTO_CCW_RUNNING; // Move to intermediate state } break; case AUTO_CCW_RUNNING: // Check if motor has completed its operation if (isMotorComplete()) { Serial.println("CCW operation completed."); // Move to whatever state comes after CCW, or back to IDLE autoState = AUTO_IDLE; firstTimeInState = true; } // Timeout safety if (currentTime - autoStepStartTime > 30000) { Serial.println("CCW operation timeout!"); stopMotor(); autoState = AUTO_STOPPED; } break; case AUTO_COMPLETE: Serial.println("Auto mode completed all cycles."); resetMode(); autoMode = false; break; case AUTO_STOPPED: // Do nothing until reset default: break; } } void stopAutoMode() { // Stop all ongoing operations stopMotor(); digitalWrite(RELAY2, LOW); digitalWrite(RELAY3, LOW); digitalWrite(RELAY4, LOW); digitalWrite(RELAY8, LOW); digitalWrite(RELAY9, LOW); digitalWrite(RELAY10, LOW); digitalWrite(DRIVER1_ENA, HIGH); digitalWrite(DRIVER2_ENA, HIGH); digitalWrite(EN_FEEDER, LOW); autoState = AUTO_STOPPED; Serial.println("Auto mode stopped by command."); } bool checkStopCommand() { while (Serial.available() > 0) { String command = Serial.readStringUntil('\n'); command.trim(); if (command == "STOP" || command == "X") { Serial.println("Stop command received: " + command); return true; } // Put the command back into the buffer for normal processing // for (int i = 0; i < command.length(); i++) { // Serial.print(command[i]); // } } return false; } void setFeederMotorSpeed(int speed, bool forward) { analogWrite(RPWM_FEEDER, forward ? map(speed, 0, 100, 0, 255) : 0); analogWrite(LPWM_FEEDER, forward ? 0 : map(speed, 0, 100, 0, 255)); } void runFeeder(bool forward, unsigned long durationMillis, int speed) { feederComplete = false; if (feederRunning) { Serial.println("Feeder is already running."); return; // Return the current direction if already running } // Start the feeder motor setFeederMotorSpeed(speed, forward); digitalWrite(EN_FEEDER, HIGH); // Enable feeder motor delay (100); feederRunning = true; // set feeder running flag to true isForward = forward; // Set duration if provided (0 means run indefinitely) if (durationMillis > 0) { feederStartTime = millis(); feederDuration = durationMillis; } else { feederDuration = 0; // Run until manually stopped } Serial.print(forward ? "FEEDER MOTOR FD STARTED" : "FEEDER MOTOR RD STARTED"); if (durationMillis > 0) { Serial.print(" for "); Serial.print(durationMillis / 1000.0); Serial.println(" seconds"); } else { Serial.println(" (indefinite run)"); } } void updateFeeder() { if (feederRunning && feederDuration > 0 && (millis() - feederStartTime >= feederDuration)) { // Time's up - stop the motor digitalWrite(EN_FEEDER, LOW); stopMotor(); feederRunning = false; Serial.println("Feeder motor stopped (time elapsed)"); // SET COMPLETION FLAG HERE setFeederComplete(); } } void moveLinearGuide1(String direction1) { linearGuide1Complete = false; if (direction1 == "LU") { // Forward Direction (Linear motor up) int sensorState = digitalRead(PROXY_POS); Serial.print("Proxy POS Sensor State: "); Serial.println(sensorState); // Print the actual state of the sensor // Check if proxyPOS is active if (sensorState == LOW) { // Assuming HIGH means the sensor is inactive Serial.println("Cannot move up. Proxy POS is not active."); return; // Exit the function if proxyPOS is not active } // Check if already at upper limit (like LF/LR does) if (digitalRead(LIMIT_SWITCH2) == LOW) { Serial.println("Already at Limit Switch 2"); setLinearGuide1Complete(); // ADD THIS - was missing! return; } Serial.println("LU"); digitalWrite(DRIVER1_ENA, HIGH); delay(100); digitalWrite(RELAY9, HIGH); // Turn ON Relay 1 Serial.println("RELAY9 ON"); // Notify Python delay(100); digitalWrite(DRIVER1_DIR, HIGH); // Set direction forward delay(100); digitalWrite(DRIVER1_ENA, LOW); // Enable motor delay(200); Serial.print("Limit States - 1: "); Serial.print(digitalRead(LIMIT_SWITCH1)); Serial.print(" & Limit States - 2: "); Serial.println(digitalRead(LIMIT_SWITCH2)); // Direct stepper movement (similar to LF/LR) unsigned long startTime = millis(); const unsigned long timeout = 15000; // 15 second timeout while (digitalRead(LIMIT_SWITCH2) == HIGH) { digitalWrite(DRIVER1_STEP, HIGH); delayMicroseconds(40); digitalWrite(DRIVER1_STEP, LOW); delayMicroseconds(45); // Check for timeout if (millis() - startTime > timeout) { Serial.println("LU movement timeout! Stopping."); break; } if (checkStopCommand()) { Serial.println("Emergency Stop Triggered"); stopMotor(); digitalWrite(RELAY9, LOW); return; } } digitalWrite(RELAY9, LOW); Serial.println("RELAY9 OFF"); Serial.println("Motors stopped at Limit Switch 2 or Emergency Stop."); setLinearGuide1Complete(); } else if (direction1 == "LD") { // Linear motor down // Check if already at lower limit if (digitalRead(LIMIT_SWITCH1) == LOW) { Serial.println("Already at Limit Switch 1"); setLinearGuide1Complete(); return; } Serial.println("LD"); digitalWrite(DRIVER1_ENA, HIGH); delay(100); digitalWrite(RELAY9, HIGH); Serial.println("RELAY9 ON"); delay(100); digitalWrite(DRIVER1_DIR, LOW); // Set direction for DOWN movement delay(100); digitalWrite(DRIVER1_ENA, LOW); delay(200); Serial.print("Limit States - 1: "); Serial.print(digitalRead(LIMIT_SWITCH1)); Serial.print(" & Limit States - 2: "); Serial.println(digitalRead(LIMIT_SWITCH2)); // Direct stepper movement (similar to LF/LR) unsigned long startTime = millis(); const unsigned long timeout = 15000; // 15 second timeout while (digitalRead(LIMIT_SWITCH1) == HIGH) { digitalWrite(DRIVER1_STEP, HIGH); delayMicroseconds(40); digitalWrite(DRIVER1_STEP, LOW); delayMicroseconds(45); // Check for timeout if (millis() - startTime > timeout) { Serial.println("LD movement timeout! Stopping."); break; } if (checkStopCommand()) { Serial.println("Emergency Stop Triggered"); stopMotor(); digitalWrite(RELAY9, LOW); return; } } digitalWrite(RELAY9, LOW); Serial.println("RELAY9 OFF"); Serial.println("Motors stopped at Limit Switch 1 or Emergency Stop."); delay(100); setLinearGuide1Complete(); } else { Serial.println("Invalid direction for moveLinearGuide."); } } void moveLinearGuide2(String direction2) { linearGuide2Complete = false; if (direction2 == "LF") { // Linear motor forward if (digitalRead(LIMIT_SWITCH4) == LOW) { Serial.println("Already at Limit Switch 4"); setLinearGuide2Complete(); return; } Serial.println("LF"); digitalWrite(DRIVER2_ENA, HIGH); delay(100); digitalWrite(RELAY7, HIGH); // Turn ON Relay 7 Serial.println("RELAY7 ON"); // Notify Python delay(100); digitalWrite(DRIVER2_DIR, HIGH); // Set direction forward delay(100); digitalWrite(DRIVER2_ENA, LOW); // Enable motor delay(100); Serial.print("Limit States - 3: "); Serial.print(digitalRead(LIMIT_SWITCH3)); Serial.print(" & Limit States - 4: "); Serial.println(digitalRead(LIMIT_SWITCH4)); // Direct stepper movement (similar to LF/LR) unsigned long startTime = millis(); const unsigned long timeout = 15000; // 15 second timeout while (digitalRead(LIMIT_SWITCH4) == HIGH) { digitalWrite(DRIVER2_STEP, HIGH); delayMicroseconds(20); digitalWrite(DRIVER2_STEP, LOW); delayMicroseconds(25); // Check for timeout if (millis() - startTime > timeout) { Serial.println("LF movement timeout! Stopping."); break; } if (checkStopCommand()) { Serial.println("Emergency Stop Triggered"); stopMotor(); digitalWrite(RELAY7, LOW); digitalWrite(DRIVER2_ENA, HIGH); return; } } digitalWrite(DRIVER2_ENA, HIGH); delay(100); digitalWrite(RELAY7, LOW); // Turn OFF Relay 7 Serial.println("RELAY7 OFF"); // Notify Python Serial.println("Motors stopped at Limit Switch 4 or Emergency Stop."); delay (100); // SET COMPLETION FLAG HERE setLinearGuide2Complete(); } else if (direction2 == "LR") { // Move Reverse Direction (Linear motor reverse) // Check if already at lower limit if (digitalRead(LIMIT_SWITCH3) == LOW) { // Already at limit Serial.println("Already at Limit Switch 3"); setLinearGuide2Complete(); return; } Serial.println("LR"); digitalWrite(DRIVER2_ENA, HIGH); delay(100); digitalWrite(RELAY7, HIGH); // Turn ON Relay 7 Serial.println("RELAY7 ON"); // Notify Python delay(100); digitalWrite(DRIVER2_DIR, LOW); // Set direction reverse delay(100); digitalWrite(DRIVER2_ENA, LOW); // Enable motor delay(100); Serial.print("Limit States - 3: "); Serial.print(digitalRead(LIMIT_SWITCH3)); Serial.print(" & Limit States - 4: "); Serial.println(digitalRead(LIMIT_SWITCH4)); // Run BTS7960B motor forward at 5 speed digitalWrite(EN_FEEDER, HIGH); // Enable feeder motor setFeederMotorSpeed(35, true); // Use the helper function to set speed and direction // Direct stepper movement (similar to LF/LR) unsigned long startTime = millis(); const unsigned long timeout = 15000; // 15 second timeout while (digitalRead(LIMIT_SWITCH3) == HIGH) { digitalWrite(DRIVER2_STEP, HIGH); delayMicroseconds(20); digitalWrite(DRIVER2_STEP, LOW); delayMicroseconds(25); // Check for timeout if (millis() - startTime > timeout) { Serial.println("LD movement timeout! Stopping."); break; } if (checkStopCommand()) { Serial.println("Emergency Stop Triggered"); stopMotor(); digitalWrite(RELAY7, LOW); digitalWrite(DRIVER2_ENA, HIGH); return; } } // Stop both motors when Limit Switch 3 is triggered or X command is received digitalWrite(DRIVER2_ENA, HIGH); delay(100); digitalWrite(RELAY7, LOW); // Turn OFF Relay 7 digitalWrite(EN_FEEDER, LOW); Serial.println("RELAY7 OFF"); // Notify Python Serial.println("Motors stopped at Limit Switch 3 or Emergency Stop."); delay (100); // SET COMPLETION FLAG HERE setLinearGuide2Complete(); } else { Serial.println("Invalid direction for moveLinearGuide."); } } void moveStepper1(bool direction, int stopPin) { digitalWrite(DRIVER1_DIR, direction); digitalWrite(RELAY9, HIGH); digitalWrite(DRIVER1_ENA, LOW); // Enable stepper motor // Move stepper motor until limit switch is triggered or "X" command is received while (digitalRead(stopPin) == HIGH) { digitalWrite(DRIVER1_STEP, HIGH); delayMicroseconds(25); digitalWrite(DRIVER1_STEP, LOW); delayMicroseconds(30); if (checkStopCommand()) { Serial.println("Emergency Stop Triggered"); stopMotor(); // Stop when "X" command is received return; } } digitalWrite(RELAY9, LOW); // Turn off Relay 1 to stop stepper motor control } void runOpenGripper() { // Define the behavior for Opening Grippers 1 & 2 after tying digitalWrite(RELAY3, LOW); // Deactivate Gripper 1 (RELAY3) digitalWrite(RELAY4, LOW); // Deactivate Gripper 2 (RELAY4) delay(1000); } void stopMotor() { // Stop Feeder motor analogWrite(RPWM_FEEDER, 0); analogWrite(LPWM_FEEDER, 0); digitalWrite(EN_FEEDER, LOW); digitalWrite(DRIVER1_ENA, HIGH); digitalWrite(DRIVER2_ENA, HIGH); feederRunning = false; // Reset feeder running flag // Turn off relays digitalWrite(RELAY9, LOW); digitalWrite(RELAY5, LOW); // Disable both relays digitalWrite(RELAY6, LOW); motorRunning = false; Serial.println("Motor stopped"); } void resetSerialBuffer() { while (Serial.available()) { Serial.read(); // Clear serial input buffer } } void resetMode() { autoMode = false; // Reset Auto mode flag manualMode = false; // Reset Manual mode flag currentMode = NONE; // Reset the current mode to a default state resetSerialBuffer(); // Clear the serial buffer Serial.println("Enter next command (START, STOP, Q):"); // Prompt for the next command } void runMotor(bool clockwise) { motorComplete = false; if (motorRunning) { Serial.println("Motor is already running."); return isClockwise; // Return the current direction if already running } int relayPin = clockwise ? RELAY5 : RELAY6; // Choose correct relay digitalWrite(relayPin, HIGH); // Start motor motorRunning = true; // Set motor running flag to true countA = 0; // Reset count for Proxy A countB = 0; // Reset count for Proxy B countingEnabled = true; // Enable counting isClockwise = clockwise; // Set the direction // Disable counting for the opposite proxy and Proxy POS if (clockwise) { countProxyBEnabled = false; // Disable counting for Proxy B countProxyPOSEnabled = false; // Disable counting for Proxy POS countProxyAEnabled = true; // Enable counting for current direction } else { countProxyAEnabled = false; // Disable counting for Proxy A countProxyPOSEnabled = false; // Disable counting for Proxy POS countProxyBEnabled = true; // Enable counting for current direction } Serial.println(clockwise ? "INDUCTION MOTOR CW STARTED" : "INDUCTION MOTOR CCW STARTED"); return clockwise; // Return the direction } void proxyA() { static int lastStateA = LOW; // Remember previous state for Proxy A static unsigned long lastTriggerTimeA = 0; const unsigned long debounceDelay = 300; const unsigned long minCountInterval = 2600; // Minimum time between counts (1 second) int sensorStateA = digitalRead(PROXY_A); // Read the current state of the sensor unsigned long currentTime = millis(); // Status feedback Serial.print("Proxy A Status: "); Serial.println(sensorStateA == HIGH ? "Triggered (High)" : "Not Triggered (Low)"); // Check for Proxy A (CW) if (isClockwise && countProxyAEnabled) { // Only detect Rising edge (LOW to HIGH) if (lastStateA == LOW && sensorStateA == HIGH) { // Debounce check if ((currentTime - lastTriggerTimeA) > debounceDelay && (currentTime - lastTriggerTimeA) > minCountInterval) { countA++; // Increment count for Proxy A lastTriggerTimeA = currentTime; // Update last trigger time Serial.print("Proxy A Count: "); Serial.println(countA); // Stop relay 4 if count reaches 4 if (countA >= 4) { digitalWrite(RELAY5, LOW); // Stop relay 4 stopMotor(); motorRunning = false; // Set flag to stop motor countA = 0; // Reset count after stopping countProxyAEnabled = false; // Disable counting for Proxy A countProxyBEnabled = true; // Re-enable counting for Proxy B // SET COMPLETION FLAG HERE setMotorComplete(); } } } lastStateA = sensorStateA; // Update last state for Proxy A } } void proxyB() { static int lastStateB = LOW; // Remember previous state for Proxy B static unsigned long lastTriggerTimeB = 0; const unsigned long debounceDelay = 300; const unsigned long minCountInterval = 2600; // Minimum time between counts (1 second) int sensorStateB = digitalRead(PROXY_B); // Read the current state of the sensor unsigned long currentTime = millis(); // Status feedback Serial.print("Proxy B Status: "); Serial.println(sensorStateB == HIGH ? "Triggered (High)" : "Not Triggered (Low)"); // Check for Proxy B (CCW) if (!isClockwise && countProxyBEnabled) { // Only detect Rising edge (LOW to HIGH) if (lastStateB == LOW && sensorStateB == HIGH) { // Debounce check if ((currentTime - lastTriggerTimeB) > debounceDelay && (currentTime - lastTriggerTimeB) > minCountInterval) { countB++; // Increment count for Proxy B lastTriggerTimeB = currentTime; Serial.print("Proxy B Count: "); Serial.println(countB); // Stop relay 5 if count reaches 5 if (countB >= 4) { digitalWrite(RELAY6, LOW); // Stop relay 5 stopMotor(); motorRunning = false; // Set flag to stop motor countB = 0; // Reset count after stopping countProxyBEnabled = false; // Disable counting for Proxy B countProxyAEnabled = true; // Re-enable counting for Proxy A // SET COMPLETION FLAG HERE setMotorComplete(); } } } lastStateB = sensorStateB; // Update last state for Proxy B } } /* END CODE */