Help with Stepper Motor-Serial Control Code-Accelstepper Library

I found some basic code I modified to control a stepper motor via serial commands.
My problem is the current code below works almost exactly as required except for one thing. I am only a few months into programming so any help is greatly appreciated. Its also 100 degrees right now where I am working so maybe that's melting my brain power :slight_smile:

Currently:
The stepper motor moves clockwise until it hits a limit switch (min), sets position to 0, then moves the opposite direction (counter clockwise) until hitting a second limit switch (max). Here the stepper motor stops moving. ALL IS AS REQUIRED UP TO THIS POINT aka the setup code is working as desired. Then I send it a command via serial to move to a position within the 0 to stepper1_pos_new aka the max and rather than moving to this position it continues moving counter clockwise against the limit switch/or past it (terminology?) for a small amount then reverses and goes to its assigned position. Then all future serial positions sent go to their correct positions and never move past the limit switches unless I reset power to the Arduino. I feel like this is something simple in my code I am missing.

Any ideas what is causing the slight movement past the limit switch before reversing to the desired position? Is Serial monitor interfering? I read a fair number of forum posts about stepper motors but couldn't find something specific to this so it makes me think it is something in my code or the way the Accelstepper library works. Like there is a delay in the loop when receiving the serial info before it gets to the position command or something.

#include "AccelStepper.h"

AccelStepper stepperX(1, 5, 6);  //Pin 1 for driver mode, pin 5 for PUL and pin 6 for DIR

// Pins for limit switches
#define min_switch 14   // Pin 14 connected to limit switch 1
#define max_switch 15  // Pin 15 connected to limit switch 2

// Stepper Movement Variables
long TravelX = 0;            // Used to store the X value entered in the Serial Monitor
int move_finished = 1;    // Used to check if move is completed
long initial_homing = -1; // Used to Home Stepper at startup

float stepper1_pos_new = 0;


void setup() {

  Serial.begin(9600);  // Start the Serial monitor with speed of 9600 Bauds

  pinMode(min_switch, INPUT_PULLUP);
  pinMode(max_switch, INPUT_PULLUP);

  //Set Max Speed and Acceleration of each Steppers at startup
  stepperX.setMaxSpeed(100.0);        // Set Max Speed of Stepper
  stepperX.setAcceleration(100.0);    // Set Acceleration of Stepper

  //Serial.println("Moving to limit switch");

  while (digitalRead(min_switch))
  {
    stepperX.moveTo(initial_homing);
    initial_homing--;
    stepperX.run();
    delay(5);
  }

  stepperX.setCurrentPosition(0);
  Serial.println("Limit switch reached");
  stepperX.setMaxSpeed(100.0);      // Set Max Speed of Stepper (Faster for regular movements)
  stepperX.setAcceleration(100.0);   // Set Acceleration of Stepper

  initial_homing = 0;

  while (digitalRead(max_switch))
  {
    stepperX.moveTo(initial_homing);
    initial_homing++;
    stepperX.run();
    delay(5);
  }

  Serial.println("complete");
  stepper1_pos_new = stepperX.currentPosition();
  Serial.print("limit switch position ending is: ");
  Serial.println(stepper1_pos_new);
}


void loop() {

  while (Serial.available() > 0)  { // Check if values are available in the Serial Buffer

    move_finished = 0; // Set variable for checking move of the Stepper

    TravelX = Serial.parseInt();           // Put numeric value from buffer in TravelX variable
    if (TravelX < 0 || TravelX > stepper1_pos_new) {  
      Serial.println("");
      Serial.print("Please enter a value greater than zero and smaller or equal to ");
      Serial.print(stepper1_pos_new);
      Serial.println("");
    } else {
      Serial.print("Moving stepper into position: ");
      Serial.println(TravelX);
      stepperX.moveTo(TravelX);  // Set new moveto position of Stepper
      //delay(1000);  // Wait 1 seconds before moving the Stepper
    }
  }

  if (TravelX >= 0 && TravelX <= stepper1_pos_new) {

    // Check if the Stepper has reached desired position
    if ((stepperX.distanceToGo() != stepper1_pos_new))
    {
      stepperX.setMaxSpeed(1000.0);      // Set Max Speed of Stepper (Faster for regular movements)
      stepperX.setAcceleration(100.0);  // Set Acceleration of Stepper
      stepperX.run();  // Move Stepper into position
    }
    //Serial.print("position ending 3 is: ");
    //Serial.println(stepperX.currentPosition());
    // If move is completed display message on Serial Monitor

    if ((move_finished == 0) && (stepperX.distanceToGo() == 0)) {
      Serial.println("COMPLETED!");
      Serial.println("");
      Serial.println("Enter distance to move stepper motor");
      move_finished = 1; // Reset move variable
    }
  }
}
TravelX = Serial.parseInt();

I don't know if it is the cause of your problem, but parseInt() blocks (like delay()). It will wait for a valid integer to be entered or a timeout (default 1 second, I believe). The serial input basics tutorial shows how to do serial input without blocking.

Hey groundFungus,

Thank you for that. I didn't realize parseInt() was a blocking function. I have removed it and integrated code from the serial basics link.

Unfortunately, that didn't solve the problem but does help me avoid blocking functions in the code which I was trying to do.

Thank you.

zebrawolf:
I have removed it and integrated code from the serial basics link.

Please post the latest version of your program and tell us in detail what it actually does and what you want it to do that is different. Then we can focus on the parts you need help with rather than wasting time on things that you can do.

...R

Hi Robin2,

Let me try and explain better. The code below is the latest. It removed the parseInt() function as well as only asking the user for a percent value from 0 to 100 instead of a number.

Currently what program does:

  1. Stepper moves clockwise to min limit switch.
  2. Code sets position to 0.
  3. Stepper moves until it hits max limit switch.
  4. Code records position (aka number of steps taken). This defines the min and max of the stepper motors movements from here forward.
  5. Code waits for serial input from user to move stepper from 0 to 100 percent within the min and max limit switches.
  6. User sends value via serial monitor and motor continues moving beyond max limit switch for x number of steps (I don't know how many but would guess like 25) before reversing and going to the proper step position.

What I want it to do:
I don't want it to move beyond the max limit switch (step 6) x number of steps and then reverse. I just want it to reverse and go to the steps position based on the serial monitor input from the user.

Not sure if this picture will help. See attached.

#include "AccelStepper.h"

AccelStepper stepper1(1, 5, 6);  //Pin 1 for driver mode, pin 5 for PUL and pin 6 for DIR

// Pins for limit switches
#define min_switch 14  // Pin 14 connected to limit switch 1
#define max_switch 15  // Pin 15 connected to limit switch 2

// Stepper Movement Variables
long TravelX = 0;         // Used to store the X value entered in the Serial Monitor
int move_finished = 1;    // Used to check if move is completed
long initial_homing = -1; // Used to Home Stepper at startup

float stepper1_pos_new = 0;
float temp_a = 0;


//Serial read variables and for serial functions
const byte numChars = 32;
char receivedChars[numChars];   // an array to store the received data
boolean newData = false;
int dataNumber = 0;
static byte ndx = 0;
char endMarker = '\n';
char rc;




void setup() {

  Serial.begin(9600);  // Start the Serial monitor with speed of 9600 Bauds

  pinMode(min_switch, INPUT_PULLUP);
  pinMode(max_switch, INPUT_PULLUP);

  //Set Max Speed and Acceleration of each Steppers at startup
  stepper1.setMaxSpeed(100.0);        // Set Max Speed of Stepper
  stepper1.setAcceleration(100.0);    // Set Acceleration of Stepper



  //Serial.println("Moving to limit switch");

  while (digitalRead(min_switch))
  {
    stepper1.moveTo(initial_homing);
    initial_homing--;
    stepper1.run();
    delay(5);
  }

  stepper1.setCurrentPosition(0);
  Serial.println("Limit switch reached");
  stepper1.setMaxSpeed(100.0);      // Set Max Speed of Stepper (Faster for regular movements)
  stepper1.setAcceleration(100.0);  // Set Acceleration of Stepper

  initial_homing = 0;

  while (digitalRead(max_switch))
  {
    stepper1.moveTo(initial_homing);
    initial_homing++;
    stepper1.run();
    delay(5);
  }

  Serial.println("complete");
  stepper1_pos_new = stepper1.currentPosition();
  Serial.print("limit switch position ending is: ");
  Serial.println(stepper1_pos_new);


  calculate_range();


}


void loop()
{

  if (Serial.available() > 0)
  {
    rc = Serial.read();

    if (rc != endMarker)
    {
      receivedChars[ndx] = rc;
      ndx++;
      if (ndx >= numChars)
      {
        ndx = numChars - 1;
      }
    }
    else
    {
      receivedChars[ndx] = '\0'; // terminate the string
      ndx = 0;
      newData = true;
    }
    dataNumber = atoi(receivedChars);   // new for this version
    TravelX = dataNumber;

    move_finished = 0;              // Set variable for checking move of the Stepper
    // Put numeric value from buffer in TravelX variable
    if (TravelX < 0 || TravelX > 100)
    { // Make sure the position entered is not beyond the HOME or MAX position
      Serial.println("");
      Serial.print("Please enter a percent value from 0 to 100 ");
      //Serial.print(100);
      Serial.println("");
    } else
    {
      Serial.print("Moving stepper to: ");
      Serial.print(TravelX);
      Serial.println(" percent position");

      TravelX = temp_a * TravelX;
      stepper1.moveTo(TravelX);  // Set new moveto position of Stepper
      //delay(1000);  // Wait 1 seconds before moving the Stepper
    }
  }

  if (TravelX >= 0 && TravelX <= stepper1_pos_new) {

    // Check if the Stepper has reached desired position
    if ((stepper1.distanceToGo() != stepper1_pos_new))
    {
      stepper1.setMaxSpeed(1000.0);      // Set Max Speed of Stepper (Faster for regular movements)
      stepper1.setAcceleration(100.0);   // Set Acceleration of Stepper
      stepper1.run();  // Move Stepper into position
    }
    //Serial.print("position ending 3 is: ");
    //Serial.println(stepperX.currentPosition());
    // If move is completed display message on Serial Monitor

    if ((move_finished == 0) && (stepper1.distanceToGo() == 0)) {
      Serial.println("COMPLETED!");
      Serial.println("");
      Serial.println("Enter distance to move stepper motor");
      move_finished = 1; // Reset move variable
    }
  }
}



//Function to take max range position (limit switch max) and divide by 100
void calculate_range()
{
  float max_limit = stepper1_pos_new;
  temp_a = max_limit / 100;
}

It makes things much easier if you leave the code from Serial Input Basics in a function and call the function from loop() as in my examples. It means that the code in loop() is much simpler.

Also, your code to process the incoming data should only happen when the variable (from my example) newData == true. Your code is not testing for that.

Save yourself trouble and use the example as it comes.

From this piece of code

      stepper1.setMaxSpeed(1000.0);      // Set Max Speed of Stepper (Faster for regular movements)
      stepper1.setAcceleration(100.0);   // Set Acceleration of Stepper
      stepper1.run();  // Move Stepper into position

the first two lines should go into setup() as they are only needed once

And the third line should be the last item in loop() outside any IF clauses

...R