// https://wokwi.com/projects/404328671355451393 this sketch/sim
// https://wokwi.com/projects/399355387445360641
// for https://forum.arduino.cc/t/limit-switch-issue-for-stepper-motor-application/1265784/12
//
// based on sim https://wokwi.com/projects/388661915235241985
// and https://github.com/waspinator/AccelStepper/tree/master/examples/Bounce
// adding a state machine to have an un-balanced CW-CCW movement
// and a limited number of cycle counts for
//

//
// Bounce.pde -- adapted for state machine
// -*- mode: C++ -*-
//
// Make a single stepper bounce from one limit to another
//
// Copyright (C) 2012 Mike McCauley
// $Id: Random.pde,v 1.1 2011/01/05 01:51:01 mikem Exp mikem $

#include <AccelStepper.h> // https://www.airspayce.com/mikem/arduino/AccelStepper/index.html

// Define a stepper and the pins it will use
AccelStepper stepper(1, 10, 7); // Defaults to AccelStepper::FULL4WIRE (4 pins) on 2, 3, 4, 5

const byte LeftLimitSwitchPin = A1;
const byte RightLimitSwitchPin = A2;
const byte HomePin = A3;
const byte ledR = 2, ledL = 12;
enum States {IDLE, CCW, CW, CCW_HOMING, CW_SEEKING, BACK_OFF_CCW};
char *stateNames[] = {"Idle", "CCW", "CW", "CCW_HOMING", "CW_SEEKING", "BACK_OFF_CCW"};
int state = IDLE;
long leftPos = -50; // left end of planned motion relative to 0 in AccelStepper
long rightPos = 300; // right end of planned motion
long rightLimitSwitchPos_acc = 1e6;
int cycleCount = 2;
int currentCycle = 0;
bool homed = false;  // state variable for whether the endstops are known

const long X_LIM_POS = 0;  // limit switch location in accelStepper coord after homing
// for Simulation:
const long X_LIM_L_POS_boot = -25 ; // limit switch location in boot coord for sim
const long X_LIM_R_POS_boot = 300 ; // limit switch location in boot coord for sim
const int LIMIT_SWITCH_WIDTH = 500 ; // active length of switch in boot coordinates
long offsetAccToBoot = 0; // difference from bootup coordinates from accelStepper 0
bool simLeftSwitchTriggered = 0, simRightSwitchTriggered = 0;


void setup()
{
  Serial.begin(115200);
  pinMode(LeftLimitSwitchPin, INPUT_PULLUP);
  pinMode(RightLimitSwitchPin, INPUT_PULLUP);
  pinMode(HomePin, INPUT_PULLUP);
  stepper.setMaxSpeed(50); // increased after homed
  stepper.setAcceleration(100);
  stepper.moveTo(0); //CW
  state = 0;
  Serial.print("0cw:" );
  pinMode(ledR, OUTPUT);
  pinMode(ledL, OUTPUT);
  //Serial.print("Acceleration:");
  // Serial.print(stepper.getAcceleration());
}


void loop()
{
  simulateHardware();

  bool LeftLimitSwitchActive = digitalRead(LeftLimitSwitchPin) == LOW || simLeftSwitchTriggered;
  bool RightLimitSwitchActive = digitalRead(RightLimitSwitchPin) == LOW || simRightSwitchTriggered;

  // If at the end of travel go to the other end
  switch (state) {
    case IDLE: // IDLE
      ; // do nothing
      if (digitalRead(LeftLimitSwitchPin) == LOW) {
        currentCycle = 0;
        state = CCW;
        Serial.println();
      }
      if (digitalRead(HomePin) == LOW) {
        homed = false;
        stepper.setMaxSpeed(50);
        if (LeftLimitSwitchActive) {
          stepper.move(100);
          state = BACK_OFF_CCW;
        } else {
          stepper.move(-1000);
          state = CCW_HOMING;
        }
      }
      break;
    case CCW: // moving CCW
      if (stepper.distanceToGo() == 0 // finished motion?
          //|| limitSwitchActive // active limit switch
         )
      {
        currentCycle += 1;
        Serial.print(currentCycle);
        if (currentCycle <= cycleCount) {
          stepper.moveTo(rightPos);
          state = CW;
        } else {
          state = IDLE;
        }
      }
      break;
    case CW: // moving CW
      if (stepper.distanceToGo() == 0) {
        Serial.print(",");
        stepper.moveTo(leftPos);
        state = CCW;
      }
      break;
    case CCW_HOMING:
      if (LeftLimitSwitchActive) {
        homedLeft();
        stepper.moveTo(rightPos + 1000); // seek other limit
        state = CW_SEEKING;
      }
      break;
    case CW_SEEKING:
      if (RightLimitSwitchActive) {
        homedRight();
        stepper.moveTo(-10);
        state = CCW;
      }
      break;
    case BACK_OFF_CCW:
      if (LeftLimitSwitchActive) {
        homedLeft();
        stepper.moveTo(rightPos + 1000); // seek other limit
        state = CW_SEEKING;
      }
      break;
    default:
      break;
  }
  stepper.run(); // move stepper as needed

  // Output
  updateLeds();
  static int stateLast  = -1;
  if (state != stateLast) {
    posReport();
    stateLast = state;
  }
}

void posReport() {
  long here = stepper.currentPosition();
  Serial.print(millis());
  Serial.print(' ');
  Serial.print(stateNames[state]);
  Serial.print(" Pos_acc:");
  Serial.print(here);
  Serial.print(" Pos_boot:");
  Serial.print(here + offsetAccToBoot);
  Serial.print(homed ? " homed" : " not homed");
  Serial.println();

}

void homedLeft() {
  // Called after hit the LHS limit switch
  Serial.print("HomedLeft:");
  //homed = true;
  //stepper.setMaxSpeed(400);
  long here = stepper.currentPosition();
  stepper.setCurrentPosition(X_LIM_POS);
  long newHere = stepper.currentPosition();
  offsetAccToBoot = here - X_LIM_POS;
  Serial.print(" here_boot:"); Serial.print(here);
  Serial.print(" here_acc:"); Serial.print(newHere);
  Serial.print(" offsetActToBoot:"); Serial.print(offsetAccToBoot);
  Serial.print(" Pos_boot:"); Serial.print(newHere + offsetAccToBoot);
  Serial.println();
}

void homedRight() {
  // Called after hit the RHS limit switch
  Serial.print("HomedRight:");
  homed = true;
  stepper.setMaxSpeed(400);
  stepper.moveTo(0);
  long here = stepper.currentPosition();
  rightLimitSwitchPos_acc = here;
  Serial.print(" here_boot:"); Serial.print(here + offsetAccToBoot);
  Serial.print(" here_acc:"); Serial.print(here);
  Serial.print(" rightLimitSwitchPos_acc:"); Serial.print(rightLimitSwitchPos_acc);
  Serial.println();
}


//
// simulate the externals
//
void updateLeds(void) {
  const uint32_t interval = 10;
  static uint32_t last = 0;
  if (millis() - last >= interval) {
    digitalWrite(ledL, simLeftSwitchTriggered);
    digitalWrite(ledR, simRightSwitchTriggered);
  }
}
void simulateHardware(void) {
  const uint32_t interval = 10;
  const long left = X_LIM_L_POS_boot, right = X_LIM_R_POS_boot, width = LIMIT_SWITCH_WIDTH;

  static uint32_t last = 0;
  if (millis() - last >= interval) {
    long bootPos = stepper.currentPosition() + offsetAccToBoot;
    last += interval;
    simLeftSwitchTriggered = (bootPos <= left && bootPos > left - width)
                             || digitalRead(LeftLimitSwitchPin) == LOW ;
    simRightSwitchTriggered = (bootPos >= right && bootPos < right + width )
                              || digitalRead(RightLimitSwitchPin) == LOW;
  }
}
A4988
Loading chip...chip-scope