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);
}
}
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.
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.
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.
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/
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
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.
/* 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);
}
}
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.
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");
}
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
}
}
}
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.
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').