Help to write Program for Single Stepper motor with 2 momentary switches, 2 limit switches

Summary:
I need to run a Nema23 stepper motor with 2 momentary switches, and 2 limit switches.

I'm try to accomplish: :large_blue_circle:

  1. Stepper Motor rotate in CW direction when a momentary switch is pressed, go indefinitely.
    Hit a limit switch and stop. Back off enough to disengage the switch.

  2. Press Second switch to rotate motor in CCW direction to return to home position which is again detected by second limit switch.
    Back off enough to disengage the switch.

  3. Motor has to decelerate when it reaches near to the limit switch. (This is required to avoid hitting the limit switch and damage)

  4. Potentiometer to vary the speed of stepper as per requirement.

The Hardware: :hammer_and_wrench:
NEMA 23 Stepper (4 wire)
Microstep Driver - SEA5045
24V DC Power Unit
Arduino UNO R3
Limit switches- 2 no’s
Momentary push button/ Toggle switch

My Problem: :no_entry:
I am mechanical engineer, I'm totally new to programming

I saw many other posts and tried to run my hardware but I am not getting success. I saw many of them using AccelStepper, ezButton libraries. But I have no clue what to change to resolve the issues and therefore decide to post a new thread here to get a complete new programme from experts. The hardware connections will be done as per your consideration in programme.

Output I am looking :trophy:
A complete programme which will run the hardware I mentioned as per my requirement.
If you can add the comments in the programme to understand the function of the codes used it will be of great help (but not compulsory).

Hope that this community will help me to run the setup.
I might have missed some inputs to write code, Pls comment if you need anything, I will provide immediately.

Thank you for going through my requirement.
:pray:
Regards
Praveen

2 Likes

this seems like a fairly simple program. Once triggered by a switch, a motor can be moved one step at a time until a limit switch become active.

however, it is more common to use a single limit switch and initially "home" the system to determine a "zero" position and then use the motor step count to position the motor and limit it's travel.

once the position of the motor is known, its speed can be controlled to reach a specified position at a desired rate. However, i have no experience with the AccelStepper library that supports accelleration

if the motor just needs to move between 2 end-points, i don't see a need for 2 switches.

on start-up, the motor would "home" by moving in a known direction toward the limit switch and stop. Once "homed", pressing a button could cause the motor to move towards one end-position, knowing the # of steps. pressing the button again would reverse its movement which should return it to the home position with the limit switch active. The code would know the motor position and direction to travel

a pot can be read to determine speed. Presumably the AccelStepper library can decelerate from some specified speed when approaching a desired target position.

please read the AccelStepper Tutorial and post an attempt at writing the code

1 Like

Hello @shenolkar. Your inquiry does not look like a request for help, but you want someone to do all the work for you. Better try ask the paid consulting section of the forum.

Thanks for your quick reply.

I have this code which is working for me to go run clockwise and counterclockwise. But there is no limit switch in this program.
The motor will travel from one end to another end : 1500mm. How can I add this travel length in below code?

// input pin for the potentiometer
int read_potentiometer = A0;

const byte directionPin = 8;
const byte stepPin = 9;
const byte buttonCWpin = 2;
const byte buttonCCWpin = 3;

boolean buttonCWpressed = false;
boolean buttonCCWpressed = false;


unsigned long curMicros;
unsigned long prevStepMicros = 0;
//unsigned long MicrosBetweenSteps = 1; // Microseconds
unsigned long delay_time = 200;

//float MicrosBetweenSteps;
int value_potentiometer = 0;

void setup()
{
   Serial.begin(115200);
   Serial.println("Starting Stepper Demo with micros()");

   pinMode(directionPin, OUTPUT);
   pinMode(stepPin, OUTPUT);

   pinMode(buttonCWpin, INPUT_PULLUP);
   pinMode(buttonCCWpin, INPUT_PULLUP);
}

void loop()
{
   curMicros = micros();
   readButtons();
   actOnButtons();
   readPot();
}

void readPot()
{
   static unsigned long timer = 0;
   unsigned long interval = 200;
   if (micros() - timer >= interval)
   {
      timer = micros();
      value_potentiometer = analogRead(read_potentiometer);
      if (value_potentiometer >  0   )
      {
         delay_time = 210 - ((value_potentiometer / 5));
      }
      else
      {
         delay_time = 0;  // Minumum speed when it is 0
      }
      Serial.print("delay time = ");
      Serial.println(delay_time);
   }
}

void readButtons()
{

   buttonCCWpressed = false;
   buttonCWpressed = false;

   if (digitalRead(buttonCWpin) == LOW)
   {
      buttonCWpressed = true;
   }
   if (digitalRead(buttonCCWpin) == LOW)
   {
      buttonCCWpressed = true;
   }
}

void actOnButtons()
{
   if (buttonCWpressed == true)
   {
      digitalWrite(directionPin, LOW);
      singleStep();
   }
   if (buttonCCWpressed == true)
   {
      digitalWrite(directionPin, HIGH);
      singleStep();
   }
}

void singleStep()
{
   if (curMicros - prevStepMicros >= delay_time)
   {
      //prevStepMicros += delay_time;
      prevStepMicros = curMicros;
      digitalWrite(stepPin, HIGH);
      digitalWrite(stepPin, LOW);
   }
}

Hi, @shenolkar
Welcome to the forum.

Why do you need to back off the limit switch and disengage after each end of travel detection?

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

not sure this is applicable. Your code "steps" the motors while the button is pressed. You presumably release the button when you want the motor to stop or near the end-points.

if you're exactly at an end-point and know the # of steps to reach the other end-point, instead of single-stepping you would step that # of steps. The motor would stop exactly at the other end-point.

when you use a motor library function to specify a # of steps, it doesn't return until that # of steps has been completed. So you would press a button to start the motor and releasing the button wouldn't stop it.

this works because of positioning the motor at the "home" position and setting the motor position to zero at the start of the program.

look this over

const byte PinPot  = A0;
const byte PinBut  = 2;
const byte PinLmt  = 3;

const byte PinDir  = 8;
const byte PinStep = 9;

// -----------------------------------------------------------------------------

const unsigned long StepDelayMax = 50000;
const unsigned long StepDelayMin =  1000;
      unsigned long stepDelayUsec    = StepDelayMax;
      unsigned long stepDelayUsecLst = stepDelayUsec;

const unsigned long PosMax  =   1000;
const unsigned long PosMin  =      0;

long  motorPos;

enum { Forward = LOW, Reverse = HIGH };
long  motorDir;

// -----------------------------------------------------------------------------
// move motor when button pressed, update step delay using pot
void loop ()
{
    if (LOW == digitalRead (PinBut))  {
        if (0 == motorPos)
            step (PosMax);
        else
            step (-PosMax);
    }

    stepDelayUsec = map(analogRead(PinPot), 0, 1023, StepDelayMin, StepDelayMax);
    if (abs(stepDelayUsecLst - stepDelayUsec) > 200)  {
        stepDelayUsecLst  = stepDelayUsec;
        Serial.print   ("stepDelayUsec = ");
        Serial.println (stepDelayUsec);
    }
}

// -----------------------------------------------------------------------------
// step motor specified # of steps in direction specified by sign
void step (
    long nStep)
{
    Serial.print   ("step: ");
    Serial.print   (nStep);

    if (0 < nStep) {
        Serial.println (" forward");
        digitalWrite (PinDir, Forward);
    }
    else  {
        Serial.println (" reverse");
        digitalWrite (PinDir, Reverse);
    }

    motorPos += nStep;

    nStep = abs(nStep);

    while (nStep--) {
        digitalWrite      (PinStep, HIGH);
        delayMicroseconds (stepDelayUsec);
        digitalWrite      (PinStep, LOW);
        delayMicroseconds (stepDelayUsec);
    }

    Serial.print   ("    step complete, motorPos = ");
    Serial.println (motorPos);
}

// -----------------------------------------------------------------------------
// drive motor toward limit switch and stop when switch active
void
home ()
{
    Serial.println ("home ...");

    digitalWrite (PinDir, Reverse);
    while (HIGH == digitalRead (PinLmt))
        step (-1);
    motorPos = PosMin;

    Serial.println ("   ... home complete");
}

// -----------------------------------------------------------------------------
void setup ()
{
    Serial.begin (115200);
    Serial.println ("Starting Stepper Demo with micros ()");

    pinMode (PinDir,  OUTPUT);
    pinMode (PinStep, OUTPUT);

    pinMode (PinBut, INPUT_PULLUP);
    pinMode (PinLmt, INPUT_PULLUP);

    home ();
}

Commercial CNCs position the limit switches so they can develerate the machine before damage. Better commercial CNCs have two systems of limit switches -- one that directly cuts the power, and another set that provides positioning information to the computer software. The positioning sensors are often set to activate somewhere within the range of travel. Both systems of sensors are placed to avoid damage.

The deceleration is often targeted at the internal numerical idea of limits, rather than the limit switch itself. The device might go through a homing cycle to determine position and numerical limits, then operate to those numerical limits.

so if a limit switch were for example 2" from an end position, a homing function would recognize when it reaches the limit switch and initialize position relative to the swith and during operation, it would always verify its position when it reaches a limit switch.

but position, including end-points would be based on the # of steps and deceleration would be based on steps, not limit switches

seems that an end-point limit switch that cuts off power would act more as a fail-safe rather than prevent damage

1 Like

The maintenance folks like the power-cutting limit switches to keep the machine from breaking. Marketing might try to advertise the largest possible physical limits of travel. Users might want to know the size of the usable envelope.

Other advantages of not making the physical positioning limit switch be at the actual limits of travel is that you don't have to precisely position the switch actuation at the limit, and that you get different actuation signals depending on the speed you approach the switch. You can handle all the offsets in software. If there's hysteresis in position between making the connection and breaking the connection, or a difference in triggering between moving at minimum speed and moving at high speed, you can program that into the homing process.

You could eyeball a 50mm offset for the physical assembly, and then in software you could start with a conservative 0 or 25mm past the limit for testing and then fine tune it up to maximum travel with a line like

#define X_MIN_POS -52  // mm, measured 2024-08-16

Here's an example of a random bit of Marlin 3d printer configuration where the limit switches are offset from the machine coordinates and within the workspace:

1 Like

Hi Jackson, thanks for going through my requirement.
I need motor to move back a little so that the limit switch will not remain pressed all the time till I move the motor in reverse direction by pressing the switch.
If you have any suggestion pls let me know.

1 Like

Position the limit switch far enough from the physical end stop to give the motor time to decelerate and stop before hitting the dead end.

Hi gcjr, thanks for your efforts. I will try this code and share the feedback.
Do I need to connect the limit switches for this code?
If YES, which pins of Arduino board I need to connect them.

1 Like

Diagram of wiring connection's

All hardwares are connected as per this diagram.

You need to detect the limit switches changing state, from ON to OFF or from OFF to ON, to stop the motor.
Not a limit switch state, ON or OFF.

You can hold a limit switch on physically for as long as you like, that's what they are built for.
Thanks for the diagram
I have edited you diag, you need gnd connections to the two inputs on the stepper driver.

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

home() uses PinLmt

1 Like

Hi TomGeorge & gcjr,

This is my micro step driver settings. Pls check the dip switch (SW1 ~ SW8) settings. Is it correct?


I am using GT3 belt and pulley. And the head has to move from one side to another by 1500mm

This is how the setup is running. :

The motor is running CW for 1 second and than CCW for 1 sec and again going forward-reverse. This cycle is continuously running.

When I press push button connected to Pin 2, the motor stops. Again when the button is pressed the motors starts.

The limit switch connected to Pin 3 doesn’t stop the motor.

What mistake I am doing?
I have sent the driver image for your ref.

1 Like

The motor current is set to 2.8 Amps, microsteps to 2 or 400 steps per revolution (for a 200 step motor).
Assuming GT3 means the tooth pitch is 3mm, how many teeth on the pully?

20 Teeth on pulley