Am trying to write Arduino code to control few stepper motors from my c++ app through serial communication. the code i wrote seems to be ok but it gives strange type of output when i send serial command from my c++ app or Arduino IDE serial monitor.
code
#include <AccelStepper.h>
// BaudRate
#define BAUD 9600
#define NO_OF_STEPPERS 3 // total # of stepper motors + 1 , as our motor count star from 1 not from 0 ,
struct steppers_struct {
int stepper_id = 0; // stepper no
bool status = false; // status bool
int steps_2_move = 0; // steps the motor needs to move.
};
steppers_struct steppers_rack[NO_OF_STEPPERS]; // init structure
// Step and Dir pins Array
int step_pin_m[NO_OF_STEPPERS];
int dir_pin_m[NO_OF_STEPPERS];
int enable_pin_m[NO_OF_STEPPERS];
// AcceStepper Stepper Array
AccelStepper stepper_m[NO_OF_STEPPERS];
// Driver A4988
#define motorInterfaceType 1
// Buffer
char buf[80];
// Readline funtion load buffer
int readline(int readch, char *buffer, int len) {
static int pos = 0;
int rpos;
if (readch > 0) {
switch (readch) {
case '\r': // Ignore CR
break;
case '\n': // Return on new-line
rpos = pos;
pos = 0; // Reset position index ready for next time
return rpos;
default:
if (pos < len-1) {
buffer[pos++] = readch;
buffer[pos] = 0;
}
}
}
return 0;
}
// Setup
void setup() {
Serial.begin(BAUD); // init serial
// stepper dir and step pins.
step_pin_m[1] = 2;
dir_pin_m[1] = 5;
enable_pin_m[1] = 8; // on CNC shield v3 its pin 8
step_pin_m[2] = 3;
dir_pin_m[2] = 6;
enable_pin_m[2] = 8; // on CNC shield v3 its pin 8
for(int i=1; i<=NO_OF_STEPPERS; i++)
{
stepper_m[i] = AccelStepper(motorInterfaceType, step_pin_m[i], dir_pin_m[i]);
stepper_m[i].setMaxSpeed(1000);
stepper_m[i].setSpeed(1000);
pinMode(enable_pin_m[i], OUTPUT); // Enable Motors
Serial.print("AccelStepper initalized..");Serial.print("\n");
}
// Some LED
// pinMode(53, OUTPUT); // Red LED it D53
// pinMode(52, OUTPUT); // Green LED it D52
}
void loop() {
// Serial Read Start
if (readline(Serial.read(), buf, 80) > 0) {
// command format 1:100;2:200;3:300
// Read each command pair
char* command = strtok(buf, ";");
while (command != 0)
{
// Split the command in two values
char* separator = strchr(command, ':');
if (separator != 0)
{
// Actually split the string in 2: replace ':' with 0
*separator = 0;
int stepperId = atoi(command);
++separator;
int stepperSteps = atoi(separator);
// Steppers id stars from 1
if(stepperId != 0){
steppers_rack[stepperId].stepper_id = stepperId;
steppers_rack[stepperId].steps_2_move = stepperSteps;
if(stepperSteps != 0){
steppers_rack[stepperId].status = true;
}else{
steppers_rack[stepperId].status = false;
}
// Serial.print(" stepper id: "); Serial.print(steppers_rack[stepperId].stepper_id); Serial.print(" stepper steps: "); Serial.print(steppers_rack[stepperId].steps_2_move); Serial.print("\n"); // output OK.
}
} // if end
// Find the next command in input string
command = strtok(0, ";");
} // while end
} // Serial Read End
// Problems start here when i try to use or change stepper structure data.
// Loop on Stepper_Struct
for(int i=1; i<=NO_OF_STEPPERS; i++)
{
if(steppers_rack[i].steps_2_move != 0 && steppers_rack[i].status == true){
Serial.print(" stepper id : "); Serial.print(steppers_rack[i].stepper_id); Serial.print(" Steps to move : "); Serial.print(steppers_rack[i].steps_2_move); Serial.print(" status : "); Serial.print(steppers_rack[i].status); Serial.print("\n"); // Output not OK
delay(500);
// Lets move stepper motor one step it time so that all motors looks moving it same time , sync
stepper_m[i].move(1); // this states to move one step ahead
stepper_m[i].runToPosition();
steppers_rack[i].steps_2_move -- ; // deducted one step from the total step motors is told to take
if(steppers_rack[i].steps_2_move == 0){
steppers_rack[i].status = false;
}
} // if end
} // for end
} // loop end
so here are few known issues am experiencing with it
first when i send command (1:3;2:3) from Arduino Serial Monitor then it not display any output , i have to send it two times then i see output in serial Monitor.
another main issue is strange output i get when i sent command : 1:3;2:3 ( mean stepper 1 move 3 steps and stepper 2 also move 3 steps )
stepper id : 14897 Steps to move : 14848 status : 51
stepper id : 14897 Steps to move : 59 status : 51
stepper id : 14897 Steps to move : 12858 status : 51
stepper id : 14897 Steps to move : 12857 status : 51
stepper id : 14897 Steps to move : 12856 status : 51
stepper id : 1 Steps to move : 372 status : 1
stepper id : 49 Steps to move : 12855 status : 51
stepper id : 1 Steps to move : 371 status : 1
stepper id : 49 Steps to move : 12854 status : 51
so am not sure from where these big numbers 14897 , 51 , 49 etc are coming ?
so any idea what am doing wrong and to make the code working so that i can sync multiple stepper motors.
sorry i had to add all code in case someone try to run and debug it
zelda546:
now one another issue raised that Stepper loop is very slow
You need to post the complete program.
If you use delay() you can expect things to be slow because it blocks the Arduino so that nothing else is done during the delay(). Have a look at how the timing is managed without blocking in the SECOND example in this Simple Stepper Code
ok sorry about it , that i have added working code in my 2nd reply, i have not used Delay function anywhere in code , but the loop on stepper_rack structure where am trying to move motors by single steps so that they look all sync is very very slow ,
can you please check if that due to Accellib or some other issue because i checked code it other points its ok and fast but it slow down it that one place where id do
stepper_m[i].move(1); // this states to move one step ahead
stepper_m[i].runToPosition();
zelda546:
ok sorry about it , that i have added working code in my 2nd reply,
I can't figure which code you are referring to. Please just post the complete program in your next Reply so the Thread can be read from top to bottom without the reader needing to back track.
#include <AccelStepper.h>
// BaudRate
#define BAUD 9600
#define NO_OF_STEPPERS 3 // total # of stepper motors + 1
struct steppers_struct {
int stepper_id = 0; // stepper no
bool status = false; // status bool
int steps_2_move = 0; // steps the motor needs to move.
};
steppers_struct steppers_rack[NO_OF_STEPPERS]; // init structure
// Step and Dir pins Array
int step_pin_m[NO_OF_STEPPERS];
int dir_pin_m[NO_OF_STEPPERS];
int enable_pin_m[NO_OF_STEPPERS];
// AcceStepper Stepper Array
AccelStepper stepper_m[NO_OF_STEPPERS];
// Driver A4988
#define motorInterfaceType 1
// Buffer
char buf[80];
// Readline funtion load buffer
int readline(int readch, char *buffer, int len) {
static int pos = 0;
int rpos;
if (readch > 0) {
switch (readch) {
case '\r': // Ignore CR
break;
case '\n': // Return on new-line
rpos = pos;
pos = 0; // Reset position index ready for next time
return rpos;
default:
if (pos < len-1) {
buffer[pos++] = readch;
buffer[pos] = 0;
}
}
}
return 0;
}
// Setup
void setup() {
Serial.begin(BAUD); // init serial
// stepper dir and step pins.
step_pin_m[1] = 2;
dir_pin_m[1] = 5;
enable_pin_m[1] = 8; // on CNC shield v3 its pin 8
step_pin_m[2] = 3;
dir_pin_m[2] = 6;
enable_pin_m[2] = 8; // on CNC shield v3 its pin 8
for(int i=1; i<NO_OF_STEPPERS; i++)
{
stepper_m[i] = AccelStepper(motorInterfaceType, step_pin_m[i], dir_pin_m[i]);
stepper_m[i].setMaxSpeed(1000);
stepper_m[i].setSpeed(1000);
pinMode(enable_pin_m[i], OUTPUT); // Enable Motors
Serial.print("AccelStepper initalized..");Serial.print("\n");
}
// Some LED
// pinMode(53, OUTPUT); // Red LED it D53
// pinMode(52, OUTPUT); // Green LED it D52
}
void loop() {
//Serial.print("it top ");
// Serial Read Start
if (readline(Serial.read(), buf, 80) > 0) {
// command format 1:100;2:200;3:300
// Read each command pair
char* command = strtok(buf, ";");
while (command != 0)
{
// Split the command in two values
char* separator = strchr(command, ':');
if (separator != 0)
{
// Actually split the string in 2: replace ':' with 0
*separator = 0;
int stepperId = atoi(command);
++separator;
int stepperSteps = atoi(separator);
// Steppers id stars from 1
if(stepperId != 0){
steppers_rack[stepperId].stepper_id = stepperId;
steppers_rack[stepperId].steps_2_move = stepperSteps;
if(stepperSteps != 0){
steppers_rack[stepperId].status = true;
}else{
steppers_rack[stepperId].status = false;
}
// Serial.print(" stepper id: "); Serial.print(steppers_rack[stepperId].stepper_id); Serial.print(" stepper steps: "); Serial.print(steppers_rack[stepperId].steps_2_move); Serial.print("\n"); // output OK.
}
} // if end
// Find the next command in input string
command = strtok(0, ";");
} // while end
} // Serial Read End
// Loop on Stepper_Struct
for(int i=1; i<NO_OF_STEPPERS; i++)
{
if(steppers_rack[i].steps_2_move != 0 && steppers_rack[i].status == true){
//Serial.print(" stepper id : "); Serial.print(steppers_rack[i].stepper_id); Serial.print(" Steps to move : "); Serial.print(steppers_rack[i].steps_2_move); Serial.print(" status : "); Serial.print(steppers_rack[i].status); Serial.print("\n"); // Output not OK
unsigned long StartTime = millis();
stepper_m[i].move(1); // this states to move one step ahead
stepper_m[i].runToPosition();
steppers_rack[i].steps_2_move --;
if(steppers_rack[i].steps_2_move == 0){
steppers_rack[i].status = false;
}
unsigned long CurrentTime = millis();
unsigned long ElapsedTime = CurrentTime - StartTime;
Serial.print("\n loop time : "); Serial.print(ElapsedTime); Serial.print(" stepper id : "); Serial.print(steppers_rack[i].stepper_id); Serial.print("\n \n");
} // if end
} // for end
} // loop end
from Arduino Serial Monitor you will have to send commands in format like , motor # : no of steps to take
1:5;2:5
the above command mean stepper motor # 1 take 5 steps ; stepper motor # 2 take 5 steps too
you can increase it like 1:10;2:5;3:10 etc ...
Issue : problem is the stepper motor takes steps very slow , probably take one sec to take one step , so not sure its problem is Accelstepper library or something else
It is very hard to figure out what's going on because you have all the code bundled into loop().
My guess is that reading the commands is getting in the way of the step process.
As far as I can see you have three separate concepts within your program
reading data from the serial port
parsing the data
making the steppers move according to the parsed data.
Put each of those concepts into a separate function and then you will be able to test each one separately and identify where there may be a bottleneck.
Also I can't figure out in macro terms how the program is supposed to work. Is it the case that normally the motors lie idle. Then someone sends a command and the motors execute that command and return to the idle state (keeping in mind that the idle state may only last for a few millisecs). OR, are new commands supposed to be read while the motors (perhaps only some of them) are moving and the reading process should not interfere with the motion?
A few of thoughts come to mind. I assume you have less than 26 stepper motors so just send a single character as the ID and you can convert it to a number much faster than using atoi().
Use a higher baud rate.
If every message can contain a number of steps for every motor (even if it is 0) then you don't need any ID numbers - the order of the numbers will suffice. But you might need to balance that Arduino convenience against the time taken to transmit longer messages.
The Arduino Serial Input Buffer is 64 bytes long and life will be simpler if the maximum command length is below that.
For greater reliability add start- and end-markers to your messages so that there is no risk of the Arduino either missing something or confusing something. Have a look at the 3rd example in Serial Input Basics
You don't seem to be using the AccelStepper library so why reference it at the top of your program?
zelda546:
am using AccelStepper Lib , you can check the for loop
Sorry, I missed that. As I said earlier your program is hard to follow.
The function runToPosition() blocks the Arduino until it completes. It is not suitable if you want multiple motors to move at the same time. You need to use the function run() and it cannot be used in the same way. Study the examples that come with the Accelstepper library.
You have not commented on the other suggestions I made in Reply #8
Robin2:
Sorry, I missed that. As I said earlier your program is hard to follow.
The function runToPosition() blocks the Arduino until it completes. It is not suitable if you want multiple motors to move at the same time. You need to use the function run() and it cannot be used in the same way. Study the examples that come with the Accelstepper library.
...R
yes you were right runtoposition() function block arduino , i found example which is helpful i will implement to see how it goes :: AccelStepper: AFMotor_MultiStepper.pde
You have not commented on the other suggestions I made in Reply #8
yes thanks for the great info i updated my code earlier it was blocking code , now it not block arduino while reading commands from serial. am studying the material you provided in your comments very helpful . thanks for it