Running 2 steppers at the same time but not simultaneously

Robin2:
Please always post a complete program.

The way I would move two stepper is something like this

void loop() {

if (stepper1pos < stepper1destination) {
      myStepper1.step(1);
      stepper1pos ++;
  }
 if (stepper2pos < stepper2destination) {
      myStepper2.step(1);
      stepper2pos ++;
  }
  delay(intervalBetweenSteps);
}




Obviously you also need code to set the initial value for stepper1pos and the value for stepper1destination. For testing you could set those in setup()

And for a working program you will probably not want to use delay() and you may wish to have separate step intervals for each motor.

...R

Thank you for your suggestions! :slight_smile: Following your example i tryed to modify the code once again..

What do you think about it? may it be correct?

#include <Stepper.h>

const int stepsPerRevolution = 1600;  // change this to fit the number of steps per revolution
int stepperXpos = 0; // How far we've traveled on X
int stepperYpos = 0; // How far we've traveled on Y

int stepperXdestination = 67200;
int stepperYdestination = 88;

// for your motor

// initialize the stepper library on pins
Stepper myStepperX(stepsPerRevolution, 8, 5, 2);
Stepper myStepperY(stepsPerRevolution, 8, 6, 3);
void setup() {
  // set the speed at 60 rpm:
  myStepperX.setSpeed(60);
  myStepperY.setSpeed(60);
  // initialize the serial port:
  Serial.begin(9600);
}

void loop() {
 
  stepperXpos = stepperXpos +1;
  stepperYpos = stepperYpos +1;
  
  Serial.println("clockwise");
  myStepperX.step(stepperXdestination);
  
  if (stepperXpos < stepperXdestination) {
       myStepperX.step(1);
       stepperXpos ++;
   }
   
  if (((stepperxpos + 88) / 1600) == 0) {
    Serial.println("clockwise");
    myStepper.step(stepperYdestination);
  }
  
  if (stepperYdestination == stepperYpos) {
    stepperYpos = 0;
  }
  
    if (((stepperxpos + 88) / 3200) == 0) {
    Serial.println("clockwise");
    myStepper.step(stepperYdestination);
  }
  
  if (stepperYdestination == stepperYpos) {
    stepperYpos = 0;
  }
  
    if (((stepperxpos + 88) / 4800) == 0) {
    Serial.println("clockwise");
    myStepper.step(stepperYdestination);
  }
  
  if (stepperYdestination == stepperYpos) {
    stepperYpos = 0;
  }
  
    if (((stepperxpos + 88) / 6400) == 0) {
    Serial.println("clockwise");
    myStepper.step(stepperYdestination);
  }
  
  if (stepperYdestination == stepperYpos) {
    stepperYpos = 0;
  }
  
    if (((stepperxpos + 88) / 8000) == 0) {
    Serial.println("clockwise");
    myStepper.step(stepperYdestination);
  }
  
  if (stepperYdestination == stepperYpos) {
    stepperYpos = 0;
  }
}

There are 2 things witch i'm not sure: is the pins' order correct here?
Pin 8 is for Enable, 5 and 6 for direction and 2 and 3 for step)

Stepper myStepperX(stepsPerRevolution, 8, 5, 2);
Stepper myStepperY(stepsPerRevolution, 8, 6, 3);

And the second thing is: here what value i have to insert? the full step option of my steppers (200 step/rev) or 1600 steps per revolution i am using because of 1/8 microstep i have setted on the driver?

const int stepsPerRevolution = 1600;  // change this to fit the number of steps per revolution

Thank you a lot for your help, i really appreciate!

Sere:
Thank you for your suggestions! :slight_smile: Following your example i tryed to modify the code once again..

What do you think about it? may it be correct?

It does not look anything like my suggestion.

What happens when you run it?

...R

Robin2:
It does not look anything like my suggestion.

What happens when you run it?

...R

xD Ok sorry, i think i misunderstand your example.
Now I'm home and the arduino stuff is at my boyfriend's, so I'll try later to run it and i'll let you know.

Robin2:
It does not look anything like my suggestion.

What happens when you run it?

...R

Ok i tryed to run this code:

#include <Stepper.h>

const int stepsPerRevolutionX = 1600;  // change this to fit the number of steps per revolution
const int stepsPerRevolutionY = 1600;  // change this to fit the number of steps per revolution
int stepperXpos = 0; // How far we've traveled on X
int stepperYpos = 0; // How far we've traveled on Y

int stepperXdestination = 67200;
int stepperYdestination = 88;

// for your motor

// initialize the stepper library on pins
Stepper myStepperX(stepperXdestination, 5, 2);
Stepper myStepperY(stepperYdestination, 6, 3);
void setup() {
  // set the speed at 60 rpm:
  myStepperX.setSpeed(60);
  myStepperY.setSpeed(60);
  // initialize the serial port:
  Serial.begin(9600);
}

void loop() {
 
  stepperXpos = stepperXpos +1;
  stepperYpos = stepperYpos +1;
  
  Serial.println("clockwise");
  myStepperX.step(stepperXdestination);
  
  if (stepperXpos < stepperXdestination) {
       myStepperX.step(1);
       stepperXpos ++;
   }
   
  if (((stepperXpos + 88) / 1600) == 0) {
    Serial.println("clockwise");
    myStepperY.step(stepperYdestination);
  }
  
  if (stepperYdestination == stepperYpos) {
    stepperYpos = 0;
  }
  
    if (((stepperXpos + 88) / 3200) == 0) {
    Serial.println("clockwise");
    myStepperY.step(stepperYdestination);
  }
  
  if (stepperYdestination == stepperYpos) {
    stepperYpos = 0;
  }
}

but nothing happens, steppers doesn't even move. I never used the stepper.h library, so i don't know if i defined correctly pins outputs in the code.. Can you please let me also see the upper part of your program so i can understand more? You are using the stepper.h library right?

Sere:
I never used the stepper.h library, so i don't know if i defined correctly pins outputs in the code.

You had your stepper moving earlier without using the Stepper library so why are you bothering with it now if you don't know how to use it?

This seems to have crept into the picture with the code you showed in Reply #16. But if you have your own code for moving the motor one step there is no need to use the library.

...R

Robin2:
You had your stepper moving earlier without using the Stepper library so why are you bothering with it now if you don't know how to use it?

This seems to have crept into the picture with the code you showed in Reply #16. But if you have your own code for moving the motor one step there is no need to use the library.

...R

Ok, maybe i found the right way..but not the solution.. i made this code:

#define EN        8  

//Direction pin
#define X_DIR     5
#define Y_DIR     6

//Step pin
#define X_STP     2
#define Y_STP     3


int StepperPosX = 0; // How far we've traveled on X
int StepperPosY = 0; // How far we've traveled on Y

int delayTime = 200;
int StepperDestinationX = 67200;
int StepperDestinationY = 88;

int voidloop_count = 0;


void setup(){

pinMode(X_DIR, OUTPUT); pinMode(X_STP, OUTPUT);

pinMode(Y_DIR, OUTPUT); pinMode(Y_STP, OUTPUT);

pinMode(EN, OUTPUT);

digitalWrite(EN, LOW);


Serial.begin(9600);
}

void loop(){


voidloop_count++;
if(voidloop_count < 6) {
digitalWrite(2, HIGH);
delayMicroseconds(delayTime);
digitalWrite(2, LOW);
delayMicroseconds(delayTime);
StepperPosX = StepperPosX +1;                // Record X step
if (((StepperPosX + 88) / 1600) == 0) {
 digitalWrite(3, HIGH);
 delayMicroseconds(delayTime);
 digitalWrite(3,LOW);
 delayMicroseconds(delayTime);
 StepperPosY = StepperPosY +1;              // Record Y step
 if (StepperPosY == StepperDestinationY) {
   StepperPosY = 0;                        // Reset Y Position Counter                   
 }
 
}

}
}

And the result is NOT the result i expected (xD) but it is so near what i need that i am so excited!!
So the result is: first motor start running for (it seems 35 full rotations) then, simultaneously the second motor starts to make 1,5 full rotations. When the second starts his movements both steppers were at lower speed then before (could it be because of too low power?)..

The speed of a stepper motor is determined by the interval between steps. The reason things are slower when both motors are running is because you have all those delayMicroseconds() adding together.

Your program seems to be much too complicated for a simple requirement. For example, what is the purpose of this line

if (((StepperPosX + 88) / 1600) == 0) {

Dividing integer variables by 1600 is likely to give zero a lot of the time.

Have you studied the code in the second link I gave you in Reply #1? - especially the 2nd example which uses non-blocking timing as that is probably essential when you want to run two motors.

How many steps per second do you want your motors to make?

...R

Robin2:
The speed of a stepper motor is determined by the interval between steps. The reason things are slower when both motors are running is because you have all those delayMicroseconds() adding together.

Oh, ok... this make sense..

Robin2:
Your program seems to be much too complicated for a simple requirement. For example, what is the purpose of this line

if (((StepperPosX + 88) / 1600) == 0) {

Dividing integer variables by 1600 is likely to give zero a lot of the time.

Yes, i know.. but i still not understand a lot of coding, so i don't know how to make it simple. I can try..
Yes, i red the links you gave me.. do you think i should use that method to make what i need? Now i'm so close to the result.. it's just that - i don't know why - it makes the wrong number of steps (I set the steps to 1/8 on my cnc shield).

Robin2:
How many steps per second do you want your motors to make?

I think 200 step per second is enough.

You really need to slow down and take a deep breath.

Post a complete code listing, properly formatted, one instruction per line, in code tags. While you're doing that, have a look at some of the fundamentals. One example is that int StepperDestinationX = 67200;isn't going to give you the result you're expecting. This should have been a 20 minute exercise over a half cup of coffee.

Write two small functions to send pulses, one CW and one CCW. Get rid of all those digitalWrites and delays from loop(), replace them with simple calls to your new functions. Clean up the code and you'll more easily see how the logic flows. Right now it looks like a rat's nest.

DKWatson:
You really need to slow down and take a deep breath.

Post a complete code listing, properly formatted, one instruction per line, in code tags. While you're doing that, have a look at some of the fundamentals. One example is that int StepperDestinationX = 67200;isn't going to give you the result you're expecting. This should have been a 20 minute exercise over a half cup of coffee.

Write two small functions to send pulses, one CW and one CCW. Get rid of all those digitalWrites and delays from loop(), replace them with simple calls to your new functions. Clean up the code and you'll more easily see how the logic flows. Right now it looks like a rat's nest.

I know that it could seem a 20 minute exercise for you, but not for me.. that's why i asked for some help.. It's just i'm really new to coding, and all seems so difficult to me.. Anyway i tryed to make my best, and if it seems confused it's just because it's what i am..
Anyway i can try to make that more simple, but i don't know how to do it..

Do you mean i need to write CW and CCW functions before the setup or in there? Then how can i call them in the loop?

It's difficult to me to understand without an example, the poor work i did and the small i understood it was from examples i found.

Anyway i will try.. and i'll post results.. thank you for your suggestions

DKWatson:
You really need to slow down and take a deep breath.

Post a complete code listing, properly formatted, one instruction per line, in code tags. While you're doing that, have a look at some of the fundamentals. One example is that

int StepperDestinationX = 67200;

isn't going to give you the result you're expecting. This should have been a 20 minute exercise over a half cup of coffee.

Write two small functions to send pulses, one CW and one CCW. Get rid of all those digitalWrites and delays from loop(), replace them with simple calls to your new functions. Clean up the code and you'll more easily see how the logic flows. Right now it looks like a rat's nest.

I tryed to make it a function, and i called it in the loop:

#define EN        8  

//Direction pin
#define X_DIR     5
#define Y_DIR     6

//Step pin
#define X_STP     2
#define Y_STP     3


int StepperPosX = 0; // How far we've traveled on X
int StepperPosY = 0; // How far we've traveled on Y

int delayTime = 200;
int StepperDestinationX = 3200;
int StepperDestinationY = 88;

int voidloop_count = 0;

void pulseCW () {
for (int i = 0; i < StepperDestinationX; StepperPosX++) {
digitalWrite(X_STP, HIGH);
delayMicroseconds(delayTime);
digitalWrite(X_STP, LOW);
delayMicroseconds(delayTime);
StepperPosX = StepperPosX +1;                // Record X step
if (((StepperPosX + 88 ) % 1600) == 0) {
 digitalWrite(Y_STP, HIGH);
 delayMicroseconds(delayTime);
 digitalWrite(Y_STP, LOW);
 delayMicroseconds(delayTime);
 StepperPosY = StepperPosY +1;              // Record Y step
 }
 else{
   digitalWrite(Y_STP, LOW);
 if (StepperPosY == StepperDestinationY) {
   StepperPosY = 0;                        // Reset Y Position Counter    
   StepperPosX = 0;              
 }
 }
}
}

void pulseCCW () {
for (int i = 0; i < StepperDestinationX; StepperPosX++) {
digitalWrite(X_STP, HIGH);
delayMicroseconds(delayTime);
digitalWrite(X_STP, LOW);
delayMicroseconds(delayTime);
StepperPosX = StepperPosX +1;                // Record X step
if (((StepperPosX + 88 ) % 1600) == 0) {
 digitalWrite(Y_DIR, HIGH);                 //Y change direction to CCW
 digitalWrite(Y_STP, HIGH);
 delayMicroseconds(delayTime);
 digitalWrite(Y_STP, LOW);
 delayMicroseconds(delayTime);
 StepperPosY = StepperPosY +1;              // Record Y step
 }
 else{
   digitalWrite(Y_STP, LOW);
 if (StepperPosY == StepperDestinationY) {
   StepperPosY = 0;                        // Reset Y Position Counter    
   StepperPosX = 0;              
 }
 }
}
}



void pulseY ();

void step(boolean dir, byte dirPin, byte stepperPin, int StepperDestination)

{

digitalWrite(dirPin, dir);

delay(50);

for (int i = 0; i < StepperDestination; i++) {

  digitalWrite(stepperPin, HIGH);

  delayMicroseconds(delayTime);

  digitalWrite(stepperPin, LOW);

  delayMicroseconds(delayTime);

}

}

void setup(){

pinMode(X_DIR, OUTPUT); pinMode(X_STP, OUTPUT);

pinMode(Y_DIR, OUTPUT); pinMode(Y_STP, OUTPUT);

pinMode(EN, OUTPUT);

digitalWrite(EN, LOW);
digitalWrite(Y_STP, LOW);
digitalWrite(X_STP, LOW);

Serial.begin(9600);
}

void loop() {
 // put your main code here, to run repeatedly:
pulseCW ();
pulseCCW ();
}

Was that what you meant?

No.

void pulse_X_CW()
{
    digitalWrite(X_DIR, HIGH);
    digitalWrite(X_STP, HIGH);
    digitalWrite(X_STP, LOW);
}

void pulse_X_CCW()
{
    digitalWrite(X_DIR, LOW);
    digitalWrite(X_STP, HIGH);
    digitalWrite(X_STP, LOW);
}

void pulse_Y_CW()
{
    digitalWrite(Y_DIR, HIGH);
    digitalWrite(Y_STP, HIGH);
    digitalWrite(Y_STP, LOW);
}

void pulse_Y_CCW()
{
    digitalWrite(Y_DIR, LOW);
    digitalWrite(Y_STP, HIGH);
    digitalWrite(Y_STP, LOW);
}

Now each time you want to send a (singular, one pulse) simply call one of the four functions. Each of the digitalWrite calls takes about 4us which is plenty of time to maintain a pulse to the motor driver. There is no need for any delay. In your loop you can now now calculate the time intervals between pulses (which establishes speed) and transmit a pulse when the elapsed period has expired (see the sticky post about using millis/micros and the blink without delay example).

So your logic, which would look like;

if (is it time to send X pulse?)
{
send X pulse
increment X counter
set time of last X pulse = current time
}

if (is it time to send Y pulse?)
{
send Y pulse
increment Y counter
set time of last Y pulse = current time
}

Your "is it time to send pulse" calculation can then include all your counter comparisons and time checks. These are running around in loop() quite quickly so if both motors happen to be needed to run at the same time, it appears as though they do.

I addition to the very good advice from @DKWatson you never explained what this line of code is intended for

if (((StepperPosX + 88) / 1600) == 0) {

...R

DKWatson:
[Your "is it time to send pulse" calculation can then include all your counter comparisons and time checks. These are running around in loop() quite quickly so if both motors happen to be needed to run at the same time, it appears as though they do.

Ok, got it.. I tryed to read more and more times the sticky post about using Millis().. but how can i count my steps using time to tell when it's time to run? There are 3 variables to set to let millis() function work:

unsigned long startMillis;  
unsigned long currentMillis;
const unsigned long period = 1000;

The period is actually like the delay, right? So it will define my "speed".. And what defines the step count, currentMillis increment?

Robin2:
you never explained what this line of code is intended for

if (((StepperPosX + 88) / 1600) == 0) {

I don't know, i think i misunderstand DKWatson previous suggestions and i used that code in a different way as he intended.. I thought it was necessary to check if the Xpos = 1512 to let Y motor move.

Sere:
I don't know,

Don't include code in your program if you don't know what it does. That just creates deeper and deeper confusion because people like me assume you do know what it means.

If you don't understand something say so and then we can help before everything gets totally out of control.

...R

For each motor (example here for motor_A), as you send a pulse, you update the time_of_last_pulse_to_motor_A variable with current millis() or micros() and increment your motor_A_pulse_counter. As you zip around loop() at the speed of a really fast rabbit, you repeatedly check (for each motor) if currentMillis (which gets updated at the head of the loop to millis()) minus the time_of_last_pulse_to_motor_A has exceeded the pulse_gap_duration_for_motor_A. You of course calculate the pulse_gap_duration for a 1.8 degree stepper motor with the simple formula: 300,000/(microstep * RPM) which gives you a value in microseconds which is the period of the pulse train necessary to sustain that rotational velocity. Okay?

As for 'if (((StepperPosX + 88) / 1600) == 0)', I never once posted that equation. I suggested if (((StepperPosX + 88) % 1600) == 0) for tracking events to occur at 1600 step intervals and if (((StepperPosX + 88) / 1600) == 20) to signal a change in direction and if (((StepperPosX + 88) / 1600) == 41) to start all over.

Actually i don't understand how i should apply this "300,000/(microstep * RPM)" and what it is for.. I tryed to modify the code with some things i understood from your suggestions and some things that i think could make sense.. If something could be done in other simpler way or if something is completely wrong please let me know.

#define EN        8 

//Direction pin
#define X_DIR     5
#define Y_DIR     6

//Step pin
#define X_STP     2
#define Y_STP     3

unsigned long startMillis;
unsigned long currentMillis;
const unsigned long period = 200;

Ysteps = 88;
pulse_X_CW = 0;
pulse_Y_CW = 0;
pulse_Y_CCW = 0;

void pulse_X_CW()
{
    digitalWrite(X_DIR, HIGH);
    digitalWrite(X_STP, HIGH);
    digitalWrite(X_STP, LOW);
}

void pulse_Y_CW(int Ysteps)
{
  if (int i = 0; i < Ysteps; i++) {
    digitalWrite(Y_DIR, HIGH);
    digitalWrite(Y_STP, HIGH);
    digitalWrite(Y_STP, LOW);
  }
  }

void pulse_Y_CCW(int Ysteps)
{
  if (int i = 0; i < Ysteps; i++)
    digitalWrite(Y_DIR, LOW);
    digitalWrite(Y_STP, HIGH);
    digitalWrite(Y_STP, LOW);
}
}

void setup(){

Serial.begin(9600);

pinMode(X_DIR, OUTPUT); pinMode(X_STP, OUTPUT);

pinMode(Y_DIR, OUTPUT); pinMode(Y_STP, OUTPUT);

pinMode(EN, OUTPUT);

digitalWrite(EN, LOW);

startMillis = millis();

}

void loop() {

currentMillis = millis();

if (currentMillis - startMillis >= period) {
  pulse_X_CW ();
  pulse_X_CW = pulse_X_CW +1;
  startMillis = currentMillis;
}

if (pulse_X_CW >= 1512) {
  pulse_Y_CW (Ystep);
  pulse_Y_CW = pulse_Y_CW +1;
  startMillis = currentMillis;
}
}

Thank you again for your help!

DKWatson:
As for 'if (((StepperPosX + 88) / 1600) == 0)', I never once posted that equation. I suggested if (((StepperPosX + 88) % 1600) == 0) for tracking events to occur at 1600 step intervals

That makes a lot more sense but I suspect it is too complex for the OP at this stage of his learning.

...R

Sere:
Actually i don't understand how i should apply this "300,000/(microstep * RPM)" and what it is for.

We are now at Reply #39 and very little progress seems to have been made - if anything success seems to further away. I think the most productive thing now is to put all your existing code to one side and start again - seriously.

Write a very short program to make one stepper move at the speed you require - use the second example in the link I gave you in Reply #1 as your starting point.

When that is working (and only then) add the code for a second motor so it moves at a different speed - to prove that it is being controlled separately, but at the same time.

...R