1

I am trying to run two stepper motor at same time with different RPM. I decided to use two rotary encoder for change the RPM separately.

But, I am in problem with driving stepper at same time due to the delay time of the step pulse.

How can I generate separate(different duty cycle) step pulses for stepper motors? It's the main problem that I faced.

I have used some Arduino libraries and all of that library has same system for step pulse generation. But, I couldn't understand those well.

void AH_EasyDriver::setSpeedRPM(long RPM)
{
   float DIV = RPM*this->MOTOR_RESOLUTION;  
    this->STEP_DELAY =  60000000.0L/DIV;
 }

This function calculate the step time for given specific RPM

void AH_EasyDriver::move(int NUMBER_OF_STEPS)
{  
   while(STEPS > 0) {
    if (micros() - this->LAST_STEP_TIME >= this->STEP_DELAY) {
      this->LAST_STEP_TIME = micros();
      STEPS--;
      stepMotor();
}
}

}

This function rotate the motor the motor in STEP_DELAY using stepMotor() function.

void AH_EasyDriver::stepMotor()
{
  digitalWrite(this->STEP_pin, HIGH);
  delayMicroseconds(100);
  digitalWrite(this->STEP_pin, LOW);
  delayMicroseconds(100);
}

This function makes CONSTANT step pulses.

I removed some lines in the function. This is the link for original .cpp file. All of stepper controlling libraries has this functions. I couldn't understand how this functions can change the RPM. Can someone explain this?

1
  • 1
    This is a complex task; if you want to see an example of multi-motor coordinated movement, look at an open-source Arduino based 3d printer or light duty CNC machine firmware. Commented Apr 2, 2018 at 17:52

2 Answers 2

3

When using a normal stepper driver, you say the driver to do one step, by sending him one pulse. The length of these pulses does not have a meaning. they are constructed, so that the driver can sense them. The driver does not make smaller steps than 1 full step, if you don't tell him on extra pins (The library you use can utilize those pins too). So the stepMotor() function is correct. You can drive the motors with different speeds by doing a step for each motor in different intervals (different number of steps per time).

Your move() function blocks the execution of other code, until the motion is completed. You are doing this with the while( STEPS > 0 ) loop. You need to modify your code to be non-blocking. This is normally done in the way, that is shown by the BlinkWithoutDelay example of the Arduino IDE. You are using it too: You have to use the millis() or micros() function, to check if it is time to do a step.

Replace the while with an ´if´-statement:

if( STEPS > 0 )

and make the STEPS variable a member variable of the class instance. Then make sure you execute the function often enough, so that it will not miss the time to do a step. Do the same with the second motor. For example something that looks like this:

void setup(){
  ...
  stepper1.doSteps(100);
  stepper2.doSteps(200);
}

void loop(){
  stepper1.move();
  stepper2.move();
}

Here in the setup function the steppers are told to move 100 and 200 steps. (You would have to write the function doSteps(int number_of_steps) yourself). The motion is then done by the move() functions, when it is time to do so. Since these two functions are looped very fast, they shouldn't miss the time for a step.

This is also the way the AccelStepper library works, which is also a common stepper library.

5
  • While the width of a step pulse might not matter within limits, the time between pulses is extremely important, and not trivial to achieve for multiple motors. You don't seem to be explaining a viable mechanism for accomplishing that. Commented Apr 2, 2018 at 17:51
  • I'm not sure how you mean this. In my understanding the driver goes one step, when it counts one pulse. You do pulses in a slow or faster series, depending on how fast the stepper should run. Surely it this not a method for high speed/high precision, but a way you can go, if the circumstances aren't too tough. Maybe I have misunderstood something how the driver works. Please correct me. I can then edit or remove my answer if it is wrong
    – chrisl
    Commented Apr 2, 2018 at 19:39
  • In the real world it is often necessary to make coordinated moves between two motors, for example imagine a circle in X and Y axis. Commented Apr 2, 2018 at 19:44
  • For doing such a motion you would have to modulate the speed of the motors (essentially making the time between the pulses depending on a function). But the OP used it in a more simple way. I think the more complex functionality of drawing circles or anything else is out of the scope of this question.
    – chrisl
    Commented Apr 2, 2018 at 19:56
  • Though it can also be done with my method by varying the speed of the motors during the motion. But the used function of this library are not good for this, I think
    – chrisl
    Commented Apr 2, 2018 at 19:57
2

The method to produce simultaneous pulses is simple, but requires a different approach similar to Direct Digital Synthesis (DDS).

  1. Keep one counter variable per motor
  2. Increment each counter variable by a set amount in a fixed time loop
  3. When a counter variable reaches a threshold value, generate a very short step pulse
  4. When a threshold is met, subtract the threshold value from the corresponding counter

The amount that each counter variable is incremented sets the generated pulse rate, reaching the threshold faster or slower, therefore setting the motor speed. A value of 0 stops the motor, a value equal to the threshold generates a step pulse for each iteration of the loop, reaching the highest speed. An arbitrary number of motors may be controlled simultaneously as long as the code can run within the fixed loop time. Since a step can only occur at fixed intervals, the rate of the timed loop should be several times the fastest step rate you intend to use to minimize timing jitter.

This style of control is often implemented using a timed interrupt service routine (ISR) which is a short function set to repeat at a several kHz frequency, interleaving with the rest of the program. This allows a slower loop to run a control algorithm simultaneous to the step generation.

If not using a timed interrupt function, the step generation loop must busy-wait until a set time has elapsed before repeating again. This means you cannot do much else than drive the motors until you stop and break out of the loop.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.