Dual stepper, different step rates

Hi everyone,

What i’m trying to do is control two stepper motors at the same time, but in different directions, and different step rates.

For example, I want:

Motor 1 = 248 steps forward
Motor 2 = 36 steps backward

I have no problems controlling them in different directions with the following code, but it does not work with different step rates as stated above.

Double Step Function:

void doubleStep(int steps, boolean dir)
{
    while (steps--)
    {
      // Motor 1
      motorStep(1, M1stepPin, dir);
      
      // Motor 2
      motorStep(1, M2stepPin, dir);
    }
}
[/code]

Motor Step Function:
[code]void motorStep(int steps, int motor, boolean dir)
{
  
  // Check which direction we want the stepper to run
  if (dir == forward && motor == M1stepPin)
  {
    
    digitalWrite(M1dirPin, LOW);
    
  } else {
    
    digitalWrite(M1dirPin, HIGH);
  }
  
  if (dir == forward && motor == M2stepPin)
  {
     digitalWrite(M2dirPin, LOW);
     
  } else {
    
     digitalWrite(M2dirPin, HIGH);
     
  }
  
   // Set enable pin(s) to low so we can use the drivers.
   digitalWrite(M1enablePin, LOW);
   digitalWrite(M2enablePin, LOW);
   
   delayMicroseconds(2);
   
   // Start stepping
   for (int step_counter = 0; step_counter <= steps; step_counter++)
   {
     digitalWrite(motor, LOW);
     delay(stepperSpeed);
     digitalWrite(motor, HIGH);
   }
} 

I’m using an Arduino Uno Rev3 with two A4988 (The A4988 was SUPER easy to hook up by the way for a first timer with steppers)

That being said, is their any way to do what I need to do? I’m not new to programming at all, which is why it’s irritating me so much. I’ve been trying for a couple of days now with no luck. All help is greatly appreciated. :sunglasses:

Thanks, Tom.

Ok, so maybe I spoke too soon. Turns out I didn’t exactly figure out how to do what I want (I thought I could do it another way…)

Can anyone show me an example on how to make the code I posted above non - blocking? I’m building a CNC machine and need one of my motors to move for example, 200 steps forward, and the other to move 36 steps backwards at the same time.

I appreciate any and all help, thanks.

- Tom

Hello, Tom.

To do what you want, you will not be able to use blocking functions like delay(). Instead, you will have to poll the system timer and perform your I/O manipulation at the appropriate times. For example:

const unsigned int M1_STEP_PERIOD_MS = 100;
const unsigned int M2_STEP_PERIOD_MS = 300;

unsigned long m1NextStepTime;
unsigned long m2NextSteptime;

void setup()
{
  pinMode(M1_STEP_PIN, OUTPUT);
  digitalWrite(M1_STEP_PIN, LOW);
  pinMode(M1_DIR_PIN, OUTPUT);
  digitalWrite(M1_DIR_PIN, LOW);
  pinMode(M2_STEP_PIN, OUTPUT);
  digitalWrite(M2_STEP_PIN, LOW);
  pinMode(M2_DIR_PIN, OUTPUT);
  digitalWrite(M2_DIR_PIN, LOW);
  m1NextStepTime = millis();
  m2NextStepTime = millis();
}

void loop()
{
  unsigned long time = millis();
  if ((long)(m1NextStepTime - time) < 0)  // basically "if (time > m1NextStepTime)"
  {
    m1NextStepTime = time + M1_STEP_PERIOD_MS;
    digitalWrite(M1_STEP_PIN, HIGH);
    delayMicroseconds(2);  // very short delays are okay
    digitalWrite(M1_STEP_PIN, LOW);
  }
  if ((long)(m2NextStepTime - time) < 0)  // basically "if (time > m2NextStepTime)"
  {
    m2NextStepTime = time + M2_STEP_PERIOD_MS;
    digitalWrite(M2_STEP_PIN, HIGH);
    delayMicroseconds(2);  // very short delays are okay
    digitalWrite(M2_STEP_PIN, LOW);
  }
}

Notice that loop is just constantly executing “if” statements, and the only blocking functions are 2us delays, which should be fine. I haven’t actually compiled or tested the above code (and you will need to define the step and direction pin constants), but it should give you some idea what the logic of timer-polling can be like (assuming I didn’t screw something up). You will need to surround this code with higher-level logic that decides when to start the stepper motors moving and when to stop them, but first maybe you can test it to verify that it will simultaneously step your two motors at different rates determined by the STEP_PERIOD constants.

Please let me know if you have any trouble getting the sample code to work or if you have any questions about it.

- Ben

Hi Ben,

Thanks so much for your reply! The code you posted works just fine, but delayMicroSeconds(2); was causing my motors to chatter quite a bit, and not move. The lowest I can go and have my steppers move reliably is about 1100 Microseconds, however they will run at lower speeds like 800 microseconds, but if one of the motors stall it will not resume stepping, it just chatters.

Some info about my steppers just incase:

Steppers: 2 x Vexta PK-266-02A (1.4 A/Phase)

Drivers: 2 x A4988 Stepper drivers with the pot limited to 0.7 times the rated current. Both are heatsinked, along with a fan running.

Power Supply: 2 x 24 Volt 3.6A Max Output.

What do you mean by higher-level logic? I assume you mean I need to use timers in my logic code as well.

Basically all I need to do is…

if (step_counter == steps)
{
    // Step motor one 200 steps backward and motor two 35 steps forward
    // at the same time (or close too it).

}

Thanks for taking the time help. :sunglasses:

- Tom.

From what you’re describing, it sounds like my code does not work properly. The point of delayMicroseconds(2) is to make sure the positive pulse on the step pin is long enough to reliably trigger a step. You should not need to change the value of this delay, and it should not be used to control the stepper motor speed (it is a blocking function).

You should be able to control the motor speed by changing the Mx_STEP_PERIOD_MS constants. If M1_STEP_PERIOD_MS is 1000, does stepper motor 1 take one step per second? If not, the code is not doing what it’s supposed to, but maybe you can figure out where it is going wrong. I suggest you simplify it so that you’re just trying to step a single motor at a rate you can set without blocking. I’m not seeing a problem, but maybe I have a sign wrong somewhere. I am not currently set up to easily test it, so I’m hoping you will be able to debug it by understanding the logic and observing how it behaves.

By higher-level logic, I mean that you can put the code I give you (once it works) into a function and then do something with that function. I was’t talking about timers.

If you keep having trouble with it, please let me know. And if you get it working, I’d love to see the final code!

- Ben

Hi Ben,

Sorry I have not responded in a few days, i’ve been having internet issues.

I did get your code to work, i’m not really sure what I did differently (maybe my pins were declared wrong?)

Here’s the working code with a speed that works for me.

int M1_STEP_PIN   =   7;   
int M1_DIR_PIN    =   6;
int M1_EN_PIN =   8;

int M2_STEP_PIN   =   2;
int M2_DIR_PIN    =   3;
int M2_EN_PIN =   4;

const unsigned int M1_STEP_PERIOD_MS = 2;
const unsigned int M2_STEP_PERIOD_MS = 3;

unsigned long m1NextStepTime;
unsigned long m2NextStepTime;

void setup()
{
  pinMode(M1_STEP_PIN, OUTPUT);
  digitalWrite(M1_STEP_PIN, LOW);
  pinMode(M1_DIR_PIN, OUTPUT);
  digitalWrite(M1_DIR_PIN, LOW);
  pinMode(M2_STEP_PIN, OUTPUT);
  digitalWrite(M2_STEP_PIN, LOW);
  pinMode(M2_DIR_PIN, OUTPUT);
  digitalWrite(M2_DIR_PIN, HIGH);
  
  digitalWrite(M1_EN_PIN, LOW);
  digitalWrite(M2_EN_PIN, LOW);
  
  unsigned long m1NextStepTime = millis();
  unsigned long m2NextStepTime = millis();
}

void loop()
{
  
  unsigned long time = millis();
  if ((long)(m1NextStepTime - time) < 0)  // basically "if (time > m1NextStepTime)"
  {
    m1NextStepTime = time + M1_STEP_PERIOD_MS;
    digitalWrite(M1_STEP_PIN, HIGH);
    delayMicroseconds(2);  // very short delays are okay
    digitalWrite(M1_STEP_PIN, LOW);
  }
  if ((long)(m2NextStepTime - time) < 0)  // basically "if (time > m2NextStepTime)"
  {
    m2NextStepTime = time + M2_STEP_PERIOD_MS;
    digitalWrite(M2_STEP_PIN, HIGH);
    delayMicroseconds(2);  // very short delays are okay
    digitalWrite(M2_STEP_PIN, LOW);
  }
}

Now to figure out how to get the code to do what I need it to do :smiley:

Thanks for the update. If you run into further trouble getting your code working, please let me know.

- Ben

You also mentioned that you are working on an arduino platform, and so I should mention the library “Accelstepper” is very useful for what you are doing.

Check out near the bottom of this page: schmalzhaus.com/EasyDriver/E … mples.html

Dear Ben,
when implement above Tom_W’s code both steppers move one direction. can you please explain with an example code if we want to move both steppers for both direction at the same time? with pre-defined different number of steps? i am using two nema17 stepper motors with two a4988 drivers.
thank you !

Hello, TECHLEARNER.

We do not have any specific examples for doing what you are describing, but we can try to help if you get stuck or have specific questions about how to achieve that.

In Tom_W’s code above, the direction of each motor is controlled by the state of the respective M1_DIR_PIN and M2_DIR_PIN. Those pins are both driven low in the setup() function, so to change the direction, you would just need to drive the pin high (e.g. digitalWrite(M1_DIR_PIN, HIGH); ).

To specify a certain number of steps to take, you will need to make sure to not use any blocking methods (like while or for loops) that would prevent the other motor from being stepped. For example, one way to do this would be to have a variable for each motor that keeps track of the number of steps it has taken. You can increase or decrease the variable each time the motor steps, depending on the direction it is moving. Then, you could use an if statement to only move each motor when it is not at the desired step count.

By the way, the “Accelstepper” library that Tomek mentioned would probably make this kind of control a lot simpler to program. I have not used it much personally, but it looks like the “MultipleSteppers” example from that library might do what you want (except with 3 motors).

Brandon

1 Like

Dear BrandonM,
Thank you for the kind reply.
I will try again to apply those modifications Brandon.
I am trying to make a code with Defined Number of steps for each motor also like “const unsigned int M1_STEP_PERIOD_MS = 2” above code. Then the steppers will move back and forth with defined number of steps indipendantly. I cant use EasyDriver code as it does not support 2A current.
When i use examples given for Accelstepper library, i have another problem converting the code defined for 4 wires which are directly connected like “AccelStepper stepper2(AccelStepper::FULL4WIRE, 6, 7, 8, 9)” into A4988 usable form. To be able to use we we need only define step, dir pins not all 4 wires. As i am using nema17 steppers they can’t power directly using arduino it is not the way to be used. And don’t know how to modify it. Any support appreciate.

Thanks.

I am not sure what you mean when you say that the code does not support 2A current; the library does not adjust the current limit set by the potentiometer on our A4988 carrier. Are you using a different board? Additionally, as we mention on our A4988 carrier product page, it can only deliver around 1A per phase without additional cooling. 2A per phase is the absolute maximum that the A4988 data sheet claims, but even with added cooling, I suspect it would be very difficult to get that kind of current from it continuously.

As I mentioned before, I am not very familiar with the Accelstepper library myself, but it looks like the constructor has options for the 2-pin interface used on the A4988 carrier. You can find more details about it in the Constructor & Destructor Documentation. From that, it looks like you can use something like AccelStepper stepper(AccelStepper::DRIVER, StepPin, DirPin);.

By the way, please note that the M1_STEP_PERIOD_MS in the code above does not specify a number of steps. It is used to set the delay between pulses (which adjusts the step rate).

Brandon

1 Like

Thanks for the support Brandon, I am sorry, i mean EasyDriver board does not support 2A (>1A) Current. I used Nema17 steppers and A4988 with heat sink. I will read about constructors and destructors.
Thanks again.
Have a good day