Stepper motor run / position issues

Hi all, can you help?

I'll detail my setup in a sec, but in summary, I'm having great issues trying to get a stepper motor to run into a limit switch, stop and reverse a known number of steps to a new zero position. The code structure i've written works in another program perfectly, but for some reason, it's stopping in the current one.

I have:

Integrated Nema17 (from Zapp Automation) with their UIM240L02T controller. Sparkfun 16x2 LCD shield Arduino Uno 12VDC supply

The wiring is all correct as confirmed by much simpler code!

In detail, I want:

My stepper is part of a linear bed that needs to be able to zero itself before starting a program of movements. To do this, I use an initialisation loop (void Init) to send the stepper moving toward the switch with a number of steps far greater than those available in the range it has to move. To do this I use the following code (I'll post the loop code at the end and if needed the whole program in a later post)

while (digitalRead(datumPin) == LOW){
      stepper.run();
    }

When the switch goes high, the position is set to zero and the stepper is reversed by a known number of steps.

    Serial.println(stepper.currentPosition());
    stepper.setCurrentPosition(0);
    Serial.println("current position is now zero");    
    Serial.println(stepper.currentPosition());
    delay(500);
    stepper.moveTo(-100);
    stepper.setMaxSpeed(1000);
    while (stepper.distanceToGo() != 0)
    {
      stepper.run();
      Serial.println(stepper.distanceToGo());
    }

The new position is reset to zero and this becomes the home point for all future movements.

What happens:

The stepper runs until the switch goes high, but then stops dead. I've placed a number of "println"'s in the code and it seems as though the position is set to zero, but the "distanceToGo" doesn't decrease to the -100 target.

This is particularly annoying as the original code (minus all the debugging and attempts to get it to work) is working perfectly in another rig.

Any help would be greatly appreciated as I'm close to tearing my hair out!

Here's the loop...

void Init(){                         //run into datum switch, set zero, return to start position
  if (digitalRead(datumPin) == LOW){
    Serial.println("DATUM PIN OFF");    
    digitalWrite(sleep, HIGH);  
    delay(100);
    stepper.move(10000);            
    stepper.setMaxSpeed(1000);
    while (digitalRead(datumPin) == LOW){
      stepper.run();
    }
    stepper.stop();
    Serial.println(stepper.currentPosition());
    stepper.setCurrentPosition(0);
    Serial.println("current position is now zero");    
    Serial.println(stepper.currentPosition());
    delay(500);
    stepper.moveTo(-100);
    stepper.setMaxSpeed(1000);   
    while (stepper.distanceToGo() != 0)
    {
      stepper.run();
      Serial.println(stepper.distanceToGo());
    }
    stepper.setCurrentPosition(0);
    digitalWrite(sleep, LOW);
    Serial.println("init complete");        
  }
  else {
    digitalWrite(sleep, HIGH); 
    Serial.print("init limit pressed"); 
    delay(100);
    stepper.move(-400);
    stepper.setMaxSpeed(1000);
    while (stepper.distanceToGo() != 0)
    {
      stepper.run();
    }    
    stepper.move(1000);
    stepper.setMaxSpeed(400);
    while (digitalRead(datumPin) == LOW){
      stepper.run();
    }
    stepper.setCurrentPosition(0);
    stepper.moveTo(homePos);  
    stepper.setMaxSpeed(1000);
    while (stepper.distanceToGo() != 0){
      stepper.run();
    }
    stepper.setCurrentPosition(0);
    digitalWrite(sleep, LOW);
  }

  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print(" INITIALISATION ");
  lcd.setCursor(0,1); 
  lcd.print("    COMPLETE     ");
  delay(2000);
  if (currentMenuItem == 0)  {
    clearPrintTitle();
  }
  else  {
    displayMenu(currentMenuItem);
  }
}

Post a complete program. I have no idea what stepper library you are using.

The usual way to run to a limit switch is

   are we there yet ?
   if not
      move one step
   repeat

Post links to the datasheet for your stepper motor and the stepper motor controller.

...R Stepper Motor Basics

I’ll have to send the code in two posts to get round the 9000 character limit…

#include <LiquidCrystal.h>
#include <AccelStepper.h>

AccelStepper stepper(1, 11, 12);
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);  

const int initPin = A4;  
const int datumPin = A3;  
const int sleep = 13;  
const int homePos = -1750;  

int lastState = 0;
int dist = 0;
int returnPos = 0;
int testSpeed = 0;
int runs = 0;
int final = 0;
int progType = 1;
int startTime = 0;
int endTime = 0;
int elapsedTime = 0;
int tDelay = 890;  
int initial = 475;
int totalStops = 5;
int selCheck = 0;

byte currentMenuItem = 0;             

void setup() {
  pinMode(initPin, INPUT);
  pinMode(datumPin, INPUT);
  pinMode(sleep, OUTPUT);

  lcd.begin(16, 2);                   
  Serial.begin(9600);

  clearPrintTitle();
}

void loop() {
  mainMenu(); 
}

void mainMenu() {
  int state = 0;
  int x = analogRead (0); 
  lcd.setCursor(0,0); 

  if (x < 100) {  
    state = 4;                        //Right
  } 
  else if (x < 200) {                 
    state = 1;                        //Up
  } 
  else if (x < 400){
    state = 2;                        //Down
  } 
  else if (x < 600){
    state = 5;                        //Left
  } 
  else if (x < 800){
    state = 3;                        //Select
  }

  if (state != lastState) { 
    if (state == 1) {                 //If Up
      if(currentMenuItem < 9) {
        currentMenuItem = currentMenuItem + 1; 
        displayMenu(currentMenuItem);
      }
      else(currentMenuItem = 0);
      selCheck = 0;
      Serial.println("UP Pressed");
    } 
    else if (state == 2) {            //If Down
      if (currentMenuItem > 0) {
        currentMenuItem = currentMenuItem - 1;  
        displayMenu(currentMenuItem);
      }
      else(currentMenuItem = 10);
      selCheck = 0;
      Serial.println("DOWN Pressed");
    } 
    else if (state == 3) {            //If Selected
      selectMenu(currentMenuItem); 
      Serial.println("SELECT Pressed");
      selCheck = 1;
    } 
    else if (state == 4) {            //If Right 
      Serial.println("INIT Pressed");
      initRunTitle();                
      Init();                        
      delay(1000);
      displayMenu(currentMenuItem);   /
    } 
    else if (state == 5) {            //If Left 
      if (selCheck == 1) { 
        Serial.println("RUN Pressed");
        testRunTitle();                 // Run selected
        setVar(currentMenuItem);
        Serial.println(progType);
        Serial.println(dist);
        Serial.println(returnPos);
        Serial.println(testSpeed);
        Serial.println(runs);
        test(progType);  
        displayMenu(currentMenuItem);
      }
      else {
        selErrorTitle(); 
      }
    }
    lastState = state;  
  } 
  delay(5);                           
}

void displayMenu(int x) { 
  Serial.println(x);
  switch (x) {
  case 1:
    clearPrintTitle();
    lcd.print ("-> Program 1");
    break;
  case 2:
    clearPrintTitle();
    lcd.print ("-> Program 2");
    break;
  case 3:
    clearPrintTitle();
    lcd.print ("-> Program 3");
    break;
  case 4:
    clearPrintTitle();
    lcd.print ("-> Program 4");
    break;
  case 5:
    clearPrintTitle();
    lcd.print ("-> Program 5");
    break;
  case 6:
    clearPrintTitle();
    lcd.print ("-> Program 6");
    break;
  case 7:
    clearPrintTitle();
    lcd.print ("-> Program 7");
    break;
  case 8:
    clearPrintTitle();
    lcd.print ("-> Program 8");
    break;
  case 9:
    clearPrintTitle();
    lcd.print ("-> Program 9");
    break;
  }
}

void clearPrintTitle() { 
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("  RIG  CONTROL  ");
  lcd.setCursor(0,1); 
}

void initRunTitle() {
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print(" INITIALISATION ");
  lcd.setCursor(0,1); 
  lcd.print("    RUNNING     ");
} 

void testRunTitle() {
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("     CAUTION    ");
  lcd.setCursor(0,1); 
  lcd.print("TEST IN PROGRESS");
}

void completeTitle()  { 
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("     TEST     ");
  lcd.setCursor(0,1); 
  lcd.print("    COMPLETE    ");
}

void selErrorTitle()  { 
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print(" PLEASE  SELECT ");
  lcd.setCursor(0,1); 
  lcd.print("   A  PROGRAM   ");
  delay(2000);
  clearPrintTitle();
  displayMenu(currentMenuItem);
}

void selectMenu(int x) {.
  switch (x) {
  case 1:
    clearPrintTitle();
    lcd.print ("Selected Opt 1");
    break;
  case 2:
    clearPrintTitle();
    lcd.print ("Selected Opt 2"); 
    break;
  case 3:
    clearPrintTitle();
    lcd.print ("Selected Opt 3"); 
    break;
  case 4:
    clearPrintTitle();
    lcd.print ("Selected Opt 4"); 
    break;
  case 5:
    clearPrintTitle();
    lcd.print ("Selected Opt 5");
    break;
  case 6:
    clearPrintTitle();
    lcd.print ("Selected Opt 6"); 
    break;
  case 7:
    clearPrintTitle();
    lcd.print ("Selected Opt 7");  
    break;
  case 8:
    clearPrintTitle();
    lcd.print ("Selected Opt 8");   
    break;    
  case 9:
    clearPrintTitle();
    lcd.print ("Selected Opt 9");
    break;    
  }
}

Second half…

void Init(){                         //run into datum switch, set zero, return to start position
  if (digitalRead(datumPin) == LOW){
    Serial.println("DATUM PIN OFF");    
    digitalWrite(sleep, HIGH);  
    delay(100);
    stepper.move(10000);            
    stepper.setMaxSpeed(1000);
    while (digitalRead(datumPin) == LOW){
      stepper.run();
    }
    stepper.stop();
    Serial.println(stepper.currentPosition());
    stepper.setCurrentPosition(0);      
    Serial.println("current position is now zero");    
    Serial.println(stepper.currentPosition());
    delay(500);
    stepper.moveTo(-100);        
    stepper.setMaxSpeed(1000);
    while (stepper.distanceToGo() != 0)
    {
      stepper.run();
      Serial.println(stepper.distanceToGo());
    }
    stepper.setCurrentPosition(0);
    digitalWrite(sleep, LOW);
    Serial.println("init complete");        
  }
  else {
    digitalWrite(sleep, HIGH); 
    Serial.print("init limit pressed"); 
    delay(100);
    stepper.move(-400);              
    stepper.setMaxSpeed(1000);
    while (stepper.distanceToGo() != 0)
    {
      stepper.run();
    }    
    stepper.move(1000);              
    stepper.setMaxSpeed(400);
    while (digitalRead(datumPin) == LOW){
      stepper.run();
    }
    stepper.setCurrentPosition(0);
    stepper.moveTo(homePos);          
    stepper.setMaxSpeed(1000);
    while (stepper.distanceToGo() != 0){
      stepper.run();
    }
    stepper.setCurrentPosition(0);
    digitalWrite(sleep, LOW);
  }

  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print(" INITIALISATION ");
  lcd.setCursor(0,1); 
  lcd.print("    COMPLETE     ");
  delay(2000);
  if (currentMenuItem == 0)  {
    clearPrintTitle();
  }
  else  {
    displayMenu(currentMenuItem);
  }
}

void setVar(int x)  {
  Serial.println(x);
  switch (x)  {
  case 1:            
    Serial.println("case 1");
    progType = 1;
    dist = 2000;
    returnPos = 2000;
    testSpeed = 195;  
    runs = 1;
    break;
    
  case 2:            
    progType = 2;
    dist = 240;
    returnPos = 244; 
    testSpeed = 1200;  
    runs = 1;
    break;
    
  case 3:            
    progType = 3;
    dist = 244;
    returnPos = -200;
    testSpeed = 4000;   
    final = 1600;
    runs = 1;
    break;

  case 4:            
    progType = 1;
    dist = 1600;
    returnPos = 0;
    testSpeed = 195; 
    runs = 1;
    break;
    
  case 5:            
    progType = 1;
    dist = 1600;
    returnPos = 0;
    testSpeed = 130;
    runs = 1;
    break;
    
  case 6:            
    progType = 1;
    dist = 1600;
    returnPos = 0;
    testSpeed = 130;
    runs = 1;
    break;
    
  case 7:            
    progType = 1;
    dist = 1600;
    returnPos = 0;
    testSpeed = 195;
    runs = 1;
    break;
    
  case 8:           
    progType = 1;
    dist = 1600;
    returnPos = 0;
    testSpeed = 195;
    runs = 2;
    break;
    
  case 9:          
    progType = 1;
    dist = 1600;
    returnPos = 0;
    testSpeed = 195;
    runs = 3;
    break;
  }
}

void test(int x)  {
  Serial.println("Entering test loop");
  Serial.println(x);
  switch (x)  {
  case 1:
    digitalWrite(sleep, HIGH);
    delay(100);
    for (int i=0; i < runs; i++)
    {
      stepper.setMaxSpeed(testSpeed);
      stepper.moveTo(dist);  
      while (stepper.distanceToGo() != 0)
      {
        stepper.run();
        Serial.println("Running");
      }
      stepper.moveTo(returnPos);  
      while (stepper.distanceToGo() != 0)
      {
        stepper.run();
      }
    }
    digitalWrite(sleep, LOW);
    completeTitle();
    delay(1000);
    break;
    
  case 2:
    startTime = millis();
    digitalWrite(sleep, HIGH);
    delay(100);
    stepper.setMaxSpeed(testSpeed);
    Serial.println(testSpeed);
    for (int i=0; i < runs; i++)
    {
      stepper.move(initial);  
      Serial.println(initial);
      while (stepper.distanceToGo() != 0)
      {
        stepper.run();
        Serial.println("running");
      }
      endTime = millis();
      elapsedTime = (endTime - startTime)+5;
      Serial.println(elapsedTime);
      delay (tDelay);
      for (int Stops=0; Stops < 3; Stops++)
      {
        stepper.move(dist);  
        while (stepper.distanceToGo() != 0)
        {
          stepper.run();
        }
        endTime = millis();
        elapsedTime = (endTime - startTime)+5;
        Serial.println(elapsedTime);
        delay (tDelay);
      }
      stepper.move(450);  
      while (stepper.distanceToGo() != 0)
      {
        stepper.run();
      }
      endTime = millis();
      elapsedTime = (endTime - startTime)+5;
      Serial.println(elapsedTime);
    }
    digitalWrite(sleep, LOW);
    completeTitle();
    delay(1000);
    break;
    
  case 3:
    digitalWrite(sleep, HIGH);
    delay(100);
    for (int i=0; i < runs; i++)
    {
      stepper.setMaxSpeed(testSpeed);
      stepper.moveTo(initial);
      Serial.println("moving to initial Stop");
      while (stepper.distanceToGo() !=0)
      {
        stepper.run();
      }
      for (int p=0; p < totalStops; p++)
      {         
        Serial.print(p);
        startTime = millis();
        while (millis() < startTime+tDelay)
        {
          stepper.setSpeed(1200);
          stepper.move(10);
          while (stepper.distanceToGo() != 0)
          {
            stepper.run();
          }
          stepper.move(-10);
          while (stepper.distanceToGo() != 0)
          {
            stepper.run();
          }  
        }
        stepper.setSpeed(1200);
        stepper.move(244);
        while (stepper.distanceToGo() != 0)
        {
          stepper.run();
        }
      }
    }
    stepper.setSpeed(1200);
    stepper.move(50);
    Serial.println("moving to final");
    while (stepper.distanceToGo() !=0)
    {
      stepper.run();
    }
    digitalWrite(sleep, LOW);
    completeTitle();
    delay(1000);
    break;
  }
}

Links to the datasheets as I can't upload files from here...

Motor - Nema17 Base

Controller - Miniature Controller

The motor cannot stop instantly, how far does it coast after "stepper.setCurrentPosition(0)"? Try a small delay after "stepper.stop;", maybe 500 mS.

Hi jcallen,

Thanks for trying!

I've added a 500ms delay directly after the stop command but nothing changes.

Here's the output from the serial monitor:

INIT Pressed DATUM PIN OFF 1102 current position is now zero 0 -100 -100 -100 -100 (repeats until the board is reset)

Also, Don't like this:

    while (stepper.distanceToGo() != 0)
    {
      stepper.run();
      Serial.println(stepper.distanceToGo());
    }

Try:

while (stepper.distanceToGo() >= -100)

Nope, no effect on the motor. The serial output is the same too.

Whats the diff between stepper.move & stepper.moveTo?

Move gives a number of steps to move. stepper.move(50); will travel 50 steps regardless of where it is.

MoveTo gives a position to reach. stepper.moveTo(50); will travel as many steps as needed to reach the absolute position of 50 from the current zero point.

OK, like CNC incremental & absolute moves.

Well, I'm stumped as well. :confused:

If I could suggest a different zero method, drive toward the LS at a fairly low speed, after making the LS, reverse & creeeep away just until the LS resets, stop and call that zero. That method has very good repeatability. Good luck.

@jipper,

I have had a quick look at the code in Replies #2 and #3.

There is too much other stuff to be able to focus on the problem.

Can you just write a short program with a simple function that gets the motor to the home position. It will make it much easier to help you. And just do the output to the Serial Monitor as that way I can try the code myself.

When your function works you can then copy and paste it into the rest of your program.

While it may not be directly relevant to your problem I see that you have stepper.run() repeated all over the place. Normally it is only necessary once in loop().

...R

@jcallen

I’m not sure it’s to do with the zero-ing method, but I’ll definitely give it a try!

@Robin2

I’ll see what I can do. I was planning on trying to condense the code a bit to weed out the problem anyway, so I’ll try to build in your suggestions as I go. Might be a while, I’m not great at this!

I’m calling the stepper.run() multiple times as I want the motor to move with various instructions. I’d happily reduce the usage, if i knew how!

Will post code later on.

Cheers.

Ok, here’s the simplified version of the code

#include <AccelStepper.h>

AccelStepper stepper(1, 11, 12);

const int initPin = 6;  
const int datumPin = A3;
const int sleep = 13;  
const int homePos = -1750;

void setup() {
  pinMode(initPin, INPUT);
  pinMode(datumPin, INPUT);
  pinMode(sleep, OUTPUT);

  Serial.begin(9600);
}

void loop() {
  if (digitalRead(initPin) == HIGH){
    Init();
  }    
}

void Init(){                         //run into datum switch, set zero, return to start position
  if (digitalRead(datumPin) == LOW){
    Serial.println("DATUM PIN OFF");    
    digitalWrite(sleep, HIGH);  
    delay(100);
    stepper.move(10000);            
    stepper.setMaxSpeed(1000);
    while (digitalRead(datumPin) == LOW){
      stepper.run();
    }
    stepper.stop();
    delay(500);
    Serial.println(stepper.currentPosition());
    stepper.setCurrentPosition(0);      
    Serial.println("current position is now zero");    
    Serial.println(stepper.currentPosition());
    delay(500);
    stepper.moveTo(-100);        
    stepper.setMaxSpeed(1000);
    while (stepper.distanceToGo() != 0)
    {
      stepper.run();
      Serial.println(stepper.distanceToGo());
    }
    stepper.setCurrentPosition(0);
    digitalWrite(sleep, LOW);
    Serial.println("init complete");        
  }
  else {
    digitalWrite(sleep, HIGH); 
    Serial.print("init limit pressed"); 
    delay(100);
    stepper.move(-400);              
    stepper.setMaxSpeed(1000);
    while (stepper.distanceToGo() != 0)
    {
      stepper.run();
    }    
    stepper.move(1000);              
    stepper.setMaxSpeed(400);
    while (digitalRead(datumPin) == LOW){
      stepper.run();
    }
    stepper.setCurrentPosition(0);
    stepper.moveTo(homePos);          
    stepper.setMaxSpeed(1000);
    while (stepper.distanceToGo() != 0){
      stepper.run();
    }
    stepper.setCurrentPosition(0);
    digitalWrite(sleep, LOW);
  }
}

Not entirely sure how to “And just do the output to the Serial Monitor as that way I can try the code myself.”

My serial monitir is saying the same as before…

DATUM PIN OFF
507
current position is now zero
0
-100
-100
-100

I was thinking of something much simpler - like this

void stepperGoHome() {
   byte homeSwitchVal = digitalRead(homeSwitchPin);
   stepper.move(5000);   // assumes it will get to the home position well within 5000 steps 
   while (homeSwitchVal == HIGH) {    // assumes LOW == pressed
        stepper.run();
        homeSwitchVal = digitalRead(homeSwitchPin);
    }
    stepper.setCurrentPosition(0);
}

I have not tested it. And it has the downside that it blocks the Arduino from doing other things - but that could be changed.

Once you have established the 0 position you can go anywhere with confidence.

...R