AccelStepper serial inputs not working

Stepper isn't moving once it has activated the home switch. The problem appears to be that the moveTo value is being rewritten somehow. My guess is because serial is empty it's reading 0, but I'm not having any luck.

I want to be able to give a motor a typed command and it move that far. The motor and A4988 both work great with my other code commanding it to a hard coded angle.

/*  Motor Homing code using AccelStepper and the Serial Monitor unedited code

Created by Yvan / https://Brainy-Bits.com
This code is in the public domain...
You can: copy it, use it, modify it, share it or just plain ignore it!
Thx!

Mega interrupt pins: 2, 3, 18, 19, 20, 21
 */

#include <AccelStepper.h>
// AccelStepper Setup
AccelStepper theta1 = AccelStepper(AccelStepper::DRIVER, 22, 24);  

// Define the Pins used
#define home_switch 10 // Pin 10 connected to Home Switch (MicroSwitch)


// Stepper Travel Variables
int TravelX;  // Used to store the X value entered in the Serial Monitor
bool move_finished = false;  // Used to check if move is completed
int initial_homing = -1;

void setup() {
   Serial.begin(115200);  
   pinMode(home_switch, INPUT_PULLUP); // uses internal pullup resistor 
   
   //  Set Max Speed and Acceleration of each Steppers at startup for homing
  theta1.setMaxSpeed(50.0);      // Set Max Speed of Stepper (Slower to get better accuracy)
  theta1.setAcceleration(50.0);  // Set Acceleration of Stepper
 

// Start Homing procedure of Stepper Motor at startup

  Serial.println("Stepper is Homing");
  Serial.println(digitalRead(home_switch));

  while (digitalRead(home_switch)) {  // Make the Stepper move CCW until the switch is activated   
    theta1.moveTo(initial_homing);  // Set the position to move to
    initial_homing--;  // Decrease by 1 for next move if needed
    theta1.run();  // Start moving the stepper

}

  theta1.setCurrentPosition(0);  // Set the current position as zero for now
  theta1.setMaxSpeed(100.0);      // Set Max Speed of Stepper (Slower to get better accuracy)
  theta1.setAcceleration(100.0);  // Set Acceleration of Stepper
  initial_homing=1;
  delay(5); 

  while (!digitalRead(home_switch)) { // Make the Stepper move CW until the switch is deactivated
    theta1.moveTo(initial_homing);  
    theta1.run();
    initial_homing++;
    delay(5);
  }
  move_finished = true; 
  theta1.setCurrentPosition(0);
  Serial.println("Homing Completed");
  Serial.println("");
  theta1.setMaxSpeed(1000.0);      // Set Max Speed of Stepper (Faster for regular movements)
  theta1.setAcceleration(1000.0);  // Set Acceleration of Stepper

// Print out Instructions on the Serial Monitor at Start
  Serial.println("Setup: Enter Travel distance (Positive for CW / Negative for CCW and Zero for back to Home): ");
  // delay(10000);  
}

void loop() {

 while (Serial.available()>0)  { // Check if values are available in the Serial Buffer
  TravelX = Serial.parseInt();  // Put numeric value from buffer in TravelX variable
  Serial.print("Moving stepper into position: ");
  Serial.println(TravelX);
  theta1.moveTo(TravelX);  // Set new moveto position of Stepper
  Serial.print("distance.toGo(TravelX) = ");
  Serial.println(theta1.distanceToGo());
  break;
  // delay(1000);  // Wait 1 seconds before moving the Stepper
  }

if ((theta1.distanceToGo() != 0)) { // Check if the Stepper has reached desired position  
  theta1.run();  // Move Stepper into position
  Serial.println("statement 2");
  }

// If move is completed display message on Serial Monitor
  if (theta1.distanceToGo() == 0) {
    Serial.println("COMPLETED!");
    Serial.println("");
    Serial.println("Loop: Enter Travel distance (Positive for CW / Negative for CCW and Zero for back to Home): ");
    delay(10000);
  }
}



Serial looks like this.


It appears most of it is working, it would help us to help you if you posted an annotated schematic showing exactly how you built it and be sure to show all power sources. Also post links to technical information on the hardware items.

The reason is the software is highly dependent on the hardware configuration.

Absolutely.

Note: the momentary switch isn't connected, only the lever switch which is read into pin 10


If you know a browser based breadboard diagram tool I can post a clean version.

edit to add.

12v power supply into the A4988 pins with a capacitor and other wiring per the dronebot workshop guide. Difference being the step and drive pins but otherwise the same.

Nice pictures but they are not much help to me, I do not have those exact parts. I will wait on the schematic.

Unfortunately I don't know a way to make a schematic. If you can recommend a website I"m happy to make a clean version.

The setup is the same as the dronebot workshop schematic except the step pin is going to pin 22 and the direction is going to pin 24.

The switch pulls from the 5V and goes to pin 10 when triggered. that all works great. The motor operates fine without the homing code also.

A piece of paper, a pencil and a ruler should be good enough. A rectangle with a la el can represent a module or board, list the used pins, and draw connections in between modules . Don’t forget the power supply.

Then take a picture - copy the jpeg or png and paste into your post.

Or use any drawing software on your Mac / PC

(This one lacks the power)

1 Like

If you want a good computer program there is Kicad, it is free for downloading but they will ask for a donation but that is not required. A lot of people on this forum use it. It is not a weekend learn but it will take you from schematic capture (making the schematic) to a finished printed circuit board. You send the Gerber files it makes to a printed circuit board house and will make a board from the files. Here is the link: https://www.kicad.org/

Here is a video, I have not watched it but looks like a starting point. https://www.youtube.com/watch?v=35YuILUlfGs

1 Like

My assumption was there existed a quick visual Arduino layout tool given the number of tutorials I see using the same graphics.

Downloaded kicad and made this schematic.

Any help with the code is greatly appreciated.

Edit to add: Thank you gilshultz. Just saw your post as well. I'll check out great scott for more practice. in mechatronics at university we were told to draw schematics but never learned a program to do so and I had to hound my prof & TA to give me any kind of style guide.

Edit again: schematic was wrong initially. limit switch is connected to ground

1 Like

Is there a PULLDOWN resister at pin 10? If not, the input is floating while the swirch is open and you may read anything. Your KiCad schemtaic doesn't show this resister either, but its mandatory!
Another possibility is, to connect the switch to Gnd and use INPUT_PULLUP at pin 10. This needs changes in the sketch, as now the input is LOW when the switch closes.

[EDIT] II just noticed that you are already using INPUT_PULLUP. In that case, the switch must be connected to Gnd.

I had a mistake in the schematic. its fixed now.

Updated the original post so the correct schematic is present.

current code:

/*  Motor Homing code using AccelStepper and the Serial Monitor unedited code

Created by Yvan / https://Brainy-Bits.com
This code is in the public domain...
You can: copy it, use it, modify it, share it or just plain ignore it!
Thx!

Mega interrupt pins: 2, 3, 18, 19, 20, 21
 */

#include <AccelStepper.h>
// AccelStepper Setup
AccelStepper theta1 = AccelStepper(AccelStepper::DRIVER, 22, 24);  

// Define the Pins used
#define home_switch 10 // Pin 10 connected to Home Switch (MicroSwitch)


// Stepper Travel Variables
int TravelX;  // Used to store the X value entered in the Serial Monitor
bool move_finished = false;  // Used to check if move is completed
int initial_homing = -1;

void setup() {
   Serial.begin(115200);  
   pinMode(home_switch, INPUT_PULLUP); // uses internal pullup resistor 
   
   //  Set Max Speed and Acceleration of each Steppers at startup for homing
  theta1.setMaxSpeed(50.0);      // Set Max Speed of Stepper (Slower to get better accuracy)
  theta1.setAcceleration(50.0);  // Set Acceleration of Stepper
 

// Start Homing procedure of Stepper Motor at startup

  Serial.println("Stepper is Homing");
  Serial.println(digitalRead(home_switch));

  while (digitalRead(home_switch)) {  // Make the Stepper move CCW until the switch is activated   
    theta1.moveTo(initial_homing);  // Set the position to move to
    initial_homing--;  // Decrease by 1 for next move if needed
    theta1.run();  // Start moving the stepper

}

  theta1.setCurrentPosition(0);  // Set the current position as zero for now
  theta1.setMaxSpeed(100.0);      // Set Max Speed of Stepper (Slower to get better accuracy)
  theta1.setAcceleration(100.0);  // Set Acceleration of Stepper
  initial_homing=1;
  delay(5); 

  while (!digitalRead(home_switch)) { // Make the Stepper move CW until the switch is deactivated
    theta1.moveTo(initial_homing);  
    theta1.run();
    initial_homing++;
    delay(5);
  }
  move_finished = true; 
  theta1.setCurrentPosition(0);
  Serial.println("Homing Completed");
  Serial.println("");
  theta1.setMaxSpeed(1000.0);      // Set Max Speed of Stepper (Faster for regular movements)
  theta1.setAcceleration(1000.0);  // Set Acceleration of Stepper

// Print out Instructions on the Serial Monitor at Start
  Serial.println("Setup: Enter Travel distance (Positive for CW / Negative for CCW and Zero for back to Home): ");
  // delay(10000);  
}

void loop() {

 while (Serial.available()>0)  { // Check if values are available in the Serial Buffer
  TravelX = Serial.parseInt();  // Put numeric value from buffer in TravelX variable
  Serial.print("Moving stepper into position: ");
  Serial.println(TravelX);
  theta1.moveTo(TravelX);  // Set new moveto position of Stepper
  Serial.print("distance.toGo(TravelX) = ");
  Serial.println(theta1.distanceToGo());
  break;
  // delay(1000);  // Wait 1 seconds before moving the Stepper
  }

if ((theta1.distanceToGo() != 0)) { // Check if the Stepper has reached desired position  
  theta1.run();  // Move Stepper into position
  Serial.println("statement 2");
  }

// If move is completed display message on Serial Monitor
  if (theta1.distanceToGo() == 0) {
    Serial.println("COMPLETED!");
    Serial.println("");
    Serial.println("Loop: Enter Travel distance (Positive for CW / Negative for CCW and Zero for back to Home): ");
    delay(10000);
  }
}

current serial response


Do you expect, that the stepper always moves 100 steps as long as you enter 100 again?
Than you have to use move and not moveTo.

I want it to move to position 100. from home it would move 180 degrees with the motor I have.

The code goes into the this statement once, then the TravelX is reset to 0 and distance.toGo(TravelX) is set to -1.

if ((theta1.distanceToGo() != 0)) { // Check if the Stepper has reached desired position  
  theta1.run();  // Move Stepper into position
  Serial.println("statement 2");
  }

I think it's because serial is available again but there's no input. The while statement is triggered and TravelX is set to 0 since serial is empty.

I don't know if that's the problem or how to only check serial if the stepper has finished moving.

do you send CRLF at the end of the command line ?

Serial.parseInt() skips non-digit characters until it finds digits, but it stops parsing at the first non-digit character and It also leaves any remaining characters in the buffer.

So if you send 100 followed by CRLF, parseInt() reads 100 and discards the CR because it’s ignored, but the LF remains in the buffer. You exit the while loop with break (weird, why don't you just use a if statement ??) and the loop loops.

On the next iteration of loop(), parseInt() sees the LF, finds no digits, times out and returns 0. That’s why your stepper jumps back to 0 unexpectedly.

you could try with

void loop() {
  if (Serial.available() > 0) {
    String input = Serial.readStringUntil('\n');
    int value;
    if (sscanf(input.c_str(), "%d", &value) == 1) {
      TravelX = value;
      Serial.print("Moving stepper into position: ");
      Serial.println(TravelX);
      theta1.moveTo(TravelX);
    } else {
      Serial.println("Invalid input, please enter an integer.");
    }
  }
...

and if you want to ensure there were the CR and LF right after the number

int value;
if (sscanf(input.c_str(), "%d\r\n", &value) == 1) {
  TravelX = value;
  theta1.moveTo(TravelX);
} else {
  Serial.println("Invalid input, must be integer followed by CRLF");
}
1 Like

That was it. I changed the IDE to 'no line ending' and now it works exactly as expected.

the break was there because I was trying things. It's not necessary.

Code is updated. added a while condition inside the if statement to make it wait for an input.

Thank you for your help everyone.

current code:

#include <AccelStepper.h>
// AccelStepper Setup
AccelStepper theta1 = AccelStepper(AccelStepper::DRIVER, 22, 24);  

// Define the Pins used
#define home_switch 10 // Pin 10 connected to Home Switch (MicroSwitch)


// Stepper Travel Variables
int TravelX;  // Used to store the X value entered in the Serial Monitor
bool move_finished = false;  // Used to check if move is completed
int initial_homing = -1;

void setup() {
   Serial.begin(115200);  
   pinMode(home_switch, INPUT_PULLUP); // uses internal pullup resistor 
   
   //  Set Max Speed and Acceleration of each Steppers at startup for homing
  theta1.setMaxSpeed(50.0);      // Set Max Speed of Stepper (Slower to get better accuracy)
  theta1.setAcceleration(50.0);  // Set Acceleration of Stepper
 

// Start Homing procedure of Stepper Motor at startup

  Serial.println("Stepper is Homing");
  Serial.println(digitalRead(home_switch));

  while (digitalRead(home_switch)) {  // Make the Stepper move CCW until the switch is activated   
    theta1.moveTo(initial_homing);  // Set the position to move to
    initial_homing--;  // Decrease by 1 for next move if needed
    theta1.run();  // Start moving the stepper

}

  theta1.setCurrentPosition(0);  // Set the current position as zero for now
  theta1.setMaxSpeed(100.0);      // Set Max Speed of Stepper (Slower to get better accuracy)
  theta1.setAcceleration(100.0);  // Set Acceleration of Stepper
  initial_homing=1;
  delay(5); 

  while (!digitalRead(home_switch)) { // Make the Stepper move CW until the switch is deactivated
    theta1.moveTo(initial_homing);  
    theta1.run();
    initial_homing++;
    delay(5);
  }
  move_finished = true; 
  theta1.setCurrentPosition(0);
  Serial.println("Homing Completed");
  Serial.println("");
  theta1.setMaxSpeed(1000.0);      // Set Max Speed of Stepper (Faster for regular movements)
  theta1.setAcceleration(1000.0);  // Set Acceleration of Stepper

// Print out Instructions on the Serial Monitor at Start
  Serial.println("Setup: Enter desired location (Positive for CW / Negative for CCW and 0 for Home): ");
  // delay(10000);  
}

void loop() {

 while (Serial.available()>0)  { // Check if values are available in the Serial Buffer
  TravelX = Serial.parseInt();  // Put numeric value from buffer in TravelX variable
  Serial.print("Moving stepper into position: ");
  Serial.println(TravelX);
  theta1.moveTo(TravelX);  // Set new moveto position of Stepper
  Serial.print("distance.toGo(TravelX) = ");
  Serial.println(theta1.distanceToGo());
  // delay(1000);  // Wait 1 seconds before moving the Stepper
  }

if ((theta1.distanceToGo() != 0)) { // Check if the Stepper has reached desired position  
  theta1.run();  // Move Stepper into position
  }

// If move is completed display message on Serial Monitor
  if (theta1.distanceToGo() == 0) {
    Serial.println("COMPLETED!");
    Serial.println("");
    Serial.println("Loop: Enter desired location (Positive for CW / Negative for CCW and 0 for Home): ");
    while(Serial.available() == 0) {
      // wait
    }    
  }
}

Glad you solved it !

If you don’t send any end market, you rely on parseInt() built in timeout to get the result. This timeout is 1s by default, meaning your command gets delayed for a full second while the information has already arrived to the Arduino.

I would suggest you change it to just sending 1 end marker (just CR or preferably just LF as its usual to see ‘\n’ as an end marker) and parseInt() will see this marker discard it and return immediately after ➜ less latency in your commands.

You might also want to change

into just a if (..) so that you unpack only one command per loop and give a chance to the code that is after that loop to execute for each command.

Changed while to if.

What is LF? I know CR is carriage return, and NL is new line.

How do I modify my input to only send 1 end marker? The IDE doesn't seem to respond to me typing '/n' into the field. Stepper retains the delay.

Here is the test I ran.

  • Set position to 0
  • Type 20000 into the IDE and hit enter. The stepper starts making 20000 steps.
  • Before completion I enter 100/n into the IDE.
  • The stepper pauses, then moves to 0


If I understand correctly it's reading the n as a non integer, serial returns false, and it sets TravelX to 0.

I tried this a few times by adding /n to the end of the typed command but the latency remained. This may be a good thing for steppers in the SCARA but I'd like to understand whats going on for when I add feedback to the system.

“LF” stands for Line Feed, and it is the official name for the control character represented by '\n' in C or C++ and most programming languages.

It originates from old teletype terminology, where a line feed physically moved the print head down to the next line without returning to the beginning (that was carriage return, or CR, '\r').