Re: [accelstepper] Issue With Changing Directions Using Easy Stepper Driver

2,691 views
Skip to first unread message
Message has been deleted

Sergi Valls

unread,
Jan 22, 2014, 7:50:33 AM1/22/14
to accels...@googlegroups.com
The problem is that the micro is detecting the limit switch. For example: when you reach the left limit switch and you try to move right, it detects the left limit.
To solve there are many ways, for example each limit switch can have its own input in the micro, when you move right disable the left limit detection, and when you move left disable the right limit. This way you can move right

El dia dimecres, 22 gener de 2014, Jack <malaka...@gmail.com> va escriure:
Hi

Currently im running an 2 phase stepper motor connected to an Easy Stepper Driver with two limit switches on either ends of a rail. A platform moves up and down the rail until it hits one of the limit switches. 

The problem i currently have is that when it reaches a limit switch the stepper motor stop as it should, then when i tell it to move  backwards to the other limit switch, the stepper moves forward a few steps and then goes backwards. It does this  all my functions. I found that reducing the difference between the moveTo() distance and the limit switch position reduces the number of steps that it takes forward. Is there a way of removing this permanently. Like to set the stepper motor has arrived at its destination when a limit switch is pressed. 

Thanks 

Jack


//-------------------------INCLUDED LIBRARIES--------------------------//

//Make sure all librarys are installed on computer before running.
//Default save to this folder "C:\Users\[USER NAME]\Documents\Arduino\libraries\"
#define DEBUG                   //Comment out this to remove debug print out 
#include <DebugUtils.h>
#include <AccelStepper.h>

//------------------------INITIALISATION OF VARIABLES--------------------//

// Define a stepper and the pins it will use
//name(using driver, step pin, direction pin)
AccelStepper stepper(1, 23, 25);

const int mS1Pin = 29;                  //MS1 pin on the stepper motor driver that controls step size
const int mS2Pin = 31;                  //MS2 pin on the stepper motor driver that controls step size

//Stepper motor enable PIN
const int stepperEnablePin = 27;

//Limit Switch Pin
const int limitSwitchR = 20;      //PIN on Arduino to which limit switch rear connected to
const int limitSwitchF = 21;      //PIN on Arduino to which limit switch front connected to
//LED on Audrino
const int led = 13;               //PIN on Arduino of built in LED


//Hair hook pins
const int hook1 = 8;      //input pin for hook 1.

//Variables
long maxDistance = 7670;    //Number of microsteps from limit switch to limit switch, half step 2000steps
int i = 0;
int s4DistanceMM = 0;       //Holds the user input for stage 4 distance of the hair to cut
int dcMotorCount = 10;
int frontLimitState = 0;    //front limit switch state
int rearLimitState = 0;     //rear limit switch state
int hairState = 0;          //varaible to store the state of the hair hook (hair in hook or not)
int cutterHeadPos = 0;      //position of the cutter head at the front of the device
long hairLength = 0;        //stores the position of the cutter head for hair length calculations
float hairCal = 0;          //variable for hair length calculations
float hairCalMM = 0;        //calculated hair length in cm for the hair length function
long cutterPostion = 0;
long currentStep = 0;


//variables used in the interrupt service routine
volatile int stage = 0;            //variable to set which event the user wants
//volatile boolean loopBreak = 0;    //variable to break loop in the initialise function when limit switch pressed



//---------------------------SETUP------------------------------//
void setup()
{  
  //Setup of the serial communication 
  Serial.begin(9600);                        //make sure the value in the brackets matches the baud rate on the
                                             //serial monitor and "No line ending" is selected
    //interrupt setup for limit switchs
  //attachInterrupt(2, motorStopISR, RISING);  //Limit Switch 1 limitSwitchR
  //attachInterrupt(3, motorStopISR, RISING);  //Limit Switch 2 limitSwitchL
  
  stepper.setMaxSpeed(12000);                //Max Speed for stepper motor
  stepper.setAcceleration(12000);           //Max acceleration for stepper motor
  
  //Limit Switch
  pinMode(limitSwitchF, INPUT);              //Limit switch front
  pinMode(limitSwitchR, INPUT);              //Limit switch rear
  //pin13 LED
  pinMode(led, OUTPUT); 
   
  //Stepper Motor Enable
  pinMode(stepperEnablePin, OUTPUT);        //Enable pin of stepper motor to turn on and off
  pinMode(mS1Pin, OUTPUT);                  //Pins to control step size
  pinMode(mS2Pin, OUTPUT);
  
  //Hair pins
  pinMode(hook1, INPUT);                     //SET PIN for hair hook 1 as an INPUT
  
    
  //Run initialisation of device at the very beginning
  //initialisation();
  
  digitalWrite(mS1Pin, HIGH);                //Writes both MS1 and MS2 pins to low  to full step stepper motor
  digitalWrite(mS2Pin, HIGH);
  
  //Instructions
  Serial.println("Instructions: Enter one of the following numbers ");
  Serial.println("1: Initialise");
  Serial.println("2: Grab hair");
  Serial.println("3: Move Back");
  Serial.println("4: 2 & 3 together");
  
  stage = 0;

}

void loop()
{
   
  //Opens the ability for serial terminal sending and recieving
  // reads data only when you receive data:
  if (Serial.available())
  {
        // read the incoming byte:
        //converts the ASCII keyboard input through the serial monitor
        //to an integer
        stage = Serial.parseInt();
        Serial.print("I received: ");
        Serial.print(stage);
        Serial.print('\n'); 
        //time delay of half a second
        delay(500);
        
  }
  
  //wait for next commard and turn off the stepper motor
  if (stage == 0)
  {
    digitalWrite(stepperEnablePin, HIGH);
    //Serial.print("Please enter the desired stage");
  }
  
  //initialise 
  //if stage variable is equal to 1 then this statement is true
  if (stage == 1){
     
    //Enables the stepper motor
    digitalWrite(stepperEnablePin, LOW);
    
    //reads the current state of the rear limit switch, LOW means not been activated
     rearLimitState = digitalRead(limitSwitchR);
     
     //checks to see if the rear limit switch isn't ready pressed. If not, then it's ok
     // to move back (calls the initialise function)
     if (rearLimitState == LOW){
       //restores value of the loop break variable when limit switch pressed
     
     //calls the initialise fucntion
     initialise();
     }
     
     //reset the postion counter
     positionReset();
     
     //If already at rear limit, you want it to return to waiting mode.
     stage = 0;
                
  }
  
  //move to the font of the device
  if (stage == 2)
  {
    //Enables the stepper motor
    digitalWrite(stepperEnablePin, LOW);
    
    delay(500);
    
    grabHair();
    
    stage = 0;
    
  }
  
  if (stage == 3)
  {
     //Enables the stepper motor
    digitalWrite(stepperEnablePin, LOW);
    
    delay(500);
    
    moveBack();
    
    stage = 0;
  }
  
}


//------------------------POSITION RESET-------------------------//

//Resets the stepper counter so current position is step 0. Called in the 
//initialise function
void positionReset(){
  DEBUG_PRINT("Inside positionRest Function");
  stepper.setCurrentPosition(0);
}


//------------------------INITIALISATION FUNCTION--------------------//

//Initialise function takes the cutter head to the back of the device
//then sets the stepper counter to zero.
void initialise(){
    
    stepper.moveTo(-maxDistance);
    //If the speed and the acceleration of the stepper was to be slowed during intialise
    //stepper.setMaxSpeed(10000);
    //stepper.setAcceleration(5000);
        
    DEBUG_PRINT("Entering initialise function");
    //Moves the cutter head to the rear of the device so it hits the limit switch
    stepper.moveTo(-maxDistance);
    
    //While the stepper hasnt reach the distance, move stepper at full speed
    while (rearLimitState == LOW)
      //if limit switch is pressed, the cutter has reached the end of the device
    {
      stepper.run();
      
      rearLimitState = digitalRead(limitSwitchR);
     }
    
      DEBUG_PRINT("loop break started");
      //Stop the stepper motor
      stepper.stop(); 
      

      DEBUG_PRINT(stepper.distanceToGo());
       
      
      stage = 0;
    
    
    DEBUG_PRINT("Out of initialise function");
    
    
}

//
void grabHair(){
  
  DEBUG_PRINT("Grab Hair");
   //Moves the cutter head to the rear of the device so it hits the limit switch
   stepper.moveTo(maxDistance);
   
   frontLimitState = digitalRead(limitSwitchF);
   
   stepper.moveTo(maxDistance);
   
   while (frontLimitState == LOW)
      //if limit switch is pressed, the cutter has reached the end of the device
    {
      stepper.run();
      
      frontLimitState = digitalRead(limitSwitchF);
    }
    
      DEBUG_PRINT("Hit front limit switch");
      //Stop the stepper motor
      stepper.stop(); 
             
     DEBUG_PRINT(stepper.distanceToGo());     
      
          
}

void moveBack(){
  
   stepper.moveTo(0);
   
   DEBUG_PRINT(stepper.distanceToGo());
  
  DEBUG_PRINT("Move Back");
  
  i = 0;
  
  cutterHeadPos = stepper.currentPosition();
  
  rearLimitState = digitalRead(limitSwitchR);
  
  stepper.moveTo(0);
  
  DEBUG_PRINT(stepper.distanceToGo());
  
  while (rearLimitState == LOW)
  {
    if (i == 0){
      
      hairState = digitalRead(hook1);
      
      if (hairState == HIGH){
      
      hairLength = stepper.currentPosition();
      
      DEBUG_PRINT("hair length recorded");
      
      i = 1;
      
      }
    }
    
    stepper.run();
    
    rearLimitState = digitalRead(limitSwitchR);
  }
  
  stepper.stop();
    
  if (i == 0)
  {
    
    Serial.println("Hair too long");
    
    return;
    
  }
         
}
    
    
  

--
You received this message because you are subscribed to the Google Groups "accelstepper" group.
To unsubscribe from this group and stop receiving emails from it, send an email to accelstepper...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Jack

unread,
Jan 22, 2014, 3:01:48 PM1/22/14
to accels...@googlegroups.com
Thanks for the quick reply. But isn"t that what im ready doing when i only digitalRead the limit switch i require in the function i call. I don't think im reading the other switch while im executing the function. 

I thought the issue was that the moveTo function holds the previous value that it was unable to achieve due to the limit switch stopping the motor. So it completes the remain moveTo steps before it does the moveTo i request it to do.  

Sandy Noble

unread,
Jan 22, 2014, 6:36:58 PM1/22/14
to accels...@googlegroups.com
Jack, I think the few extra forward steps must be the motors decelerating as fast as possible. Remember, as the docs say, calling stepper.stop() does not stop dead, it sets a moveTo() target that is as close as possible, but that would still allow the proper deceleration. So .stop() still needs to be followed by a bunch of .run()s for it to make sense.

If you need an absolute dead stop as in the case of limit switches, then you need to manually override the speed calculation. I've done it with

stepper.moveTo(stepper.currentPosition()); // sets the target to be where the motor already is
stepper.setSpeed(0);

Unless that's not the issue, and I've got the wrong end of the stick.

sn


--
You received this message because you are subscribed to the Google Groups "accelstepper" group.
To unsubscribe from this group and stop receiving emails from it, send an email to accelstepper...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.



--
Sandy Noble

Jack

unread,
Jan 22, 2014, 6:46:14 PM1/22/14
to accels...@googlegroups.com
Hi Sandy, thanks for the reply. I will try implementing those few lines of code. About the deceleration. The motor stops well at the limit switch. The problem occurs when you order it to move in the opposite direction after it has stop completely. So it starts from a dead stop in the wrong direction for a few steps. Then it switches to the proper direction.

Jay Brown

unread,
Jan 11, 2016, 10:45:40 PM1/11/16
to accelstepper
Hi Jack,

Did that workaround end up working for you i'm having the same issue.

Jack

unread,
Jan 12, 2016, 4:11:32 AM1/12/16
to accelstepper
Hi Jay. I did this a while back and I cant completely remember the solution. I did implement Sandy's code and it did end up working. 

This was something else that Sandy mentioned that's  not shown in the replies for some reason

"Dead stop is only truly dead if distanceToGo is 0 and speed is also 0
- calling stepper.stop() does neither of those things. Otherwise you
can consider the spaces inbetween calls to .run() as dead stops too!


Precision devices like 3d printers use a double trigger routine when
they self-home, where it runs to the end stop full speed, stops as
quickly as possible, but then winds back and does the last few steps
again at a much gentler speed, in case the sudden first stop dropped
some steps (physical deceleration from motor or carriage inertia)."

Hope it helps in some way. 
Message has been deleted
Message has been deleted

Blake

unread,
Jun 28, 2017, 3:18:44 PM6/28/17
to accelstepper
Hey, my previous post was accidentally deleted, so I'll make this brief:

I had the same issue as Jack,  wherein the stepper would continue moving briefly in the wrong direction after a direction change after a hard stop. I found that restating the moveTo positions (the same positions as before) directly after Sandy's hard stop code but before any other commands corrected the issue. I'm not sure why it works, but it took some significant trial and error to find. I hope this saves someone the trouble a few years from now. See my code below. This code takes a serial command, parses it into a direction and speed, and then moves the stepper accordingly (arduino uno to big easy driver). Note the code in the "O" (off) case. I had to keep track of previous movement direction to give the stepper the correct moveTo position. 

This code allows for:
1. manual control of the stepper in both directions, accelerating from a dead stop
2. instant hard stop when commanded to stepper off
3. smooth deceleration as the stepper is coming close to the limit switches at either end of the travel length (a carriage on a linear rail).
4. the ability to change directions anywhere along this length including points that are within the deceleration range of the limit switches (the case Jack was describing).

#include <AccelStepper.h>

// Define a stepper and the pins it will use
AccelStepper stepper(AccelStepper::DRIVER, A4, A5);   // step is on pin A5 (atmega328 pin 28), direction is on pin A4 (atmega328 pin 27)

const int RIGHT_LIMIT = 11;                           // right limit switch pin, debounced with rc filter, atmega328 pin 17
const int LEFT_LIMIT = 12;                            // left limit switch pin, debounced with rc filter, atmega328 pin 18

const int RIGHT_SIDE = 5040;                          // position of right side limit switch, from stepper motors point of view
const int LEFT_SIDE = 0;                              // position of left side limit switch, distance of 5040 was found empirically on the actual raster, will be different with different rail

boolean startup = true;                               // this lets us do a nice little startup routine where we move to one side and find the position of the stepper relative to the limit switches

String input_string;                                  // a string to hold the incoming serial information, which we parse into movement type and speed

char move_type;                                       // 'L' for left, 'R' for right, 'A' for auto, 'O' for off, we get this from the input string

int move_speed;                                       // we get the speed from the input string as well

boolean auto_raster;                                  // while true, go back and forth at the move_speed

boolean first_hit = true;                             // used in auto mode
int previous = 0;                                     // denotes previous travel direction. 1 = left, 2 = right

void setup()
{
  Serial.begin(38400);
 
  stepper.setMaxSpeed(5000);
  stepper.setSpeed(0);
  stepper.setAcceleration(2000);
  
  pinMode(RIGHT_LIMIT, INPUT_PULLUP);
  pinMode(LEFT_LIMIT, INPUT_PULLUP);
 
}

void loop()
{

//******************************** STARTUP ROUTINE *********************************************************************************************************************
 while (startup)                                        // here we have a little startup routine which sends the motor over to the left side and zeroes out the position
 {                                                     
    if (!digitalRead(LEFT_LIMIT))                       // as long as we're not touching the left limit switch  
    {                         
      stepper.setSpeed(-2000);                          // we move left
      stepper.runSpeed();
    }
    else
    {
      stepper.stop();                                   // once it hits the left limit switch, we stop the motor,
      stepper.setCurrentPosition(LEFT_SIDE);            // set the far left side to be position "0"
      startup = false;                                  // and are now done with the startup routine
    }
  }

//************************** READ INCOMING SERIAL DATA *********************************************************************************************************************
  while (Serial.available())                            // this is serial info from control station, it comes in the form "Z1: XN" where the "Z1: " part identifies that
  {                                                     // it has to do with the raster, the "X" part tells us the move type, either 'L', 'R', 'A', or 'O', (left, right, auto, or off)
                                                        // and the N part is a number representing the move speed. we parse the serial information below.
                                                        // we need the "Z1: " identifier because this same serial line has other information not meant for us on it
   
    char inChar = Serial.read();                        // first get the new data byte
    Serial.print(inChar);
    input_string += inChar;                             // add it to the input_string
    if (inChar == '\n')                                 // a new line appears, string is done!
    {    
      if (input_string.startsWith("Z1: "))              // determine if this string is meant for us, things not meant for us start with "M1: ", "P1: " etc.
      {
        move_type = input_string.charAt(4);             // Check move type character at position 4:
        move_speed = input_string.substring(5).toInt(); // convert characters #5 to end into an integer      
      }   
      input_string = "";                                // reset string to nothing
    }                                                  
  }                                                     // bracket for serial available while loop

  stepper.setMaxSpeed(move_speed);                      // before we do anything else, set the move speed we recieved serially

//+++++++++++++++++++++++++++++ HERE IS WHERE WE ACTUALLY MOVE THE MOTOR ++++++++++++++++++++++++++++++++++++++++
 
  switch (move_type)                                     // check which movement type we're supposed to do and act accordingly
  {

//************************************ MOVE RIGHT *************************************************************************
    case 'R':                                           // if you are pressing the right arrow button
     
      if (!digitalRead(RIGHT_LIMIT))                    // and you are not hitting the right limit switch
      {
        stepper.moveTo(RIGHT_SIDE);                     // head towards the right side
        stepper.run();
        previous = 2;
      }
      else
      {
        stepper.setCurrentPosition(RIGHT_SIDE);         // but if you are hitting the right limit switch, set the current position and stop moving right
      }
     
      break;


//************************************ MOVE LEFT *************************************************************************
    case 'L':                                           // if you are pressing the left arrow button
     
      if (!digitalRead(LEFT_LIMIT))                     // and you are not hitting the left limit switch
      { 
        stepper.moveTo(LEFT_SIDE);                      // head towards the left side
        stepper.run();
        previous = 1;
      }
      else
      { 
        stepper.setCurrentPosition(LEFT_SIDE);          // but if you are hitting the left limit switch, set the current position and stop moving left
      }
     
      break;

//************************************ OFF *************************************************************************
    case 'O':                                           // here we want the stepper to be off


      stepper.moveTo(stepper.currentPosition()); // sets the target to be where the motor already is
      stepper.setSpeed(0);

      if(previous == 1){
        stepper.moveTo(5040);
      } else if(previous == 2){
        stepper.moveTo(0);
      }
                                                      
      break; 

  }                                                     // bracket for end of switch case
}                                                       // bracket for end of main loop


Reply all
Reply to author
Forward
0 new messages