Dynamic Speed with MultiStepper

Hello all,

I'm trying to move four steppers a different number of steps during the same time interval. I.E. when I set stepper A to run 40 steps at 400 steps/second, and stepper B to run 20 steps at 200 steps/second, both motors should complete their motion in 0.1 seconds.

I'm running the code "virtually", i.e. without the steppers actually powered, just to cement my understanding of how the AccelStepper and MultiStepper libraries work.

When I use "setMaxSpeed" in setup and "setSpeed" later in the program, my steppers all run at an extremely slow speed. Using "setMaxSpeed" all the time gets me closer to the result I'm expecting, but seems wrong. Even in this scenario, my movements are not completing in the same time increment, but rather the completion time slows down as one speed goes lower, even though the slow motor has proportionally fewer steps to complete.

Is there something missing in how I'm approach this library? I really can't figure out what I'm doing wrong.

Here's the code I'm using:

Changing "setSpeed" to "setMaxSpeed" at the bottom is getting my "half-working" solution

#include <AccelStepper.h>
#include <MultiStepper.h>

AccelStepper RightFrontWheel(1, 40, 41); // Stepper1
AccelStepper RightBackWheel(1, 20, 21);   // Stepper2
AccelStepper LeftFrontWheel(1, 44, 45);  // Stepper3
AccelStepper LeftBackWheel(1, 16, 17);  // Stepper4

MultiStepper steppers;

long positions[4] = {0,0,0,0};
int wheelSpeed = 400;

float MovementCommand [4] = {-45,-45,45,45};
bool Running = true;

void setup() 
{

    
  LeftFrontWheel.setMaxSpeed(wheelSpeed);
  RightFrontWheel.setMaxSpeed(wheelSpeed);
  RightBackWheel.setMaxSpeed(wheelSpeed);
  LeftBackWheel.setMaxSpeed(wheelSpeed);

  steppers.addStepper(LeftFrontWheel);
  steppers.addStepper(LeftBackWheel);
  steppers.addStepper(RightFrontWheel);
  steppers.addStepper(RightBackWheel);

  Serial.begin(9600);

}

void loop() 
{
  if (Running)
  {
    Running = steppers.run();
  }
  else
  {
    Serial.println("step complete");
    RecalculateIntervals();
    CalculateMotions(MovementCommand);
  }
}

void RecalculateIntervals()
{
  Serial.print("position updates");
  Serial.print(" || ");
  Serial.print(MovementCommand[0]);
  Serial.print(";");
  MovementCommand[1] += 1;
  Serial.print(MovementCommand[1]);
  Serial.print(";");
  MovementCommand[2] -= 1;
  Serial.print(MovementCommand[2]);
  Serial.print(";");
  Serial.println(MovementCommand[3]);
}


void CalculateMotions(float Command[4]) 
{
  Running = true;
  positions[0] += Command[0];
  positions[1] += Command[1];
  positions[2] += Command[2];
  positions[3] += Command[3];

  int LargestStep = 0;
  for (int i = 0; i < 4; i++)
  {
    LargestStep = max(LargestStep,abs(Command[i]));
  }
  
  float Speed0 = wheelSpeed*(Command[0]/LargestStep);
  float Speed1 = wheelSpeed*(Command[1]/LargestStep);
  float Speed2 = wheelSpeed*(Command[2]/LargestStep);
  float Speed3 = wheelSpeed*(Command[3]/LargestStep);
  steppers.moveTo(positions);
  LeftFrontWheel.setSpeed(Speed0);
  RightFrontWheel.setSpeed(Speed1);
  RightBackWheel.setSpeed(Speed2);
  LeftBackWheel.setSpeed(Speed3);
  Serial.print("new speeds : ");
  Serial.print(Speed0);
  Serial.print(";");
  Serial.print(Speed1);
  Serial.print(";");
  Serial.print(Speed2);
  Serial.print(";");
  Serial.println(Speed3);
}

The beauty of the MultiStepper library is that you do not have to calculate speeds. All you need to do is specify a maximum speed and populate the positions array with the ending positions of each motor.

Here is an example using MultiStepper and an array of positions.

#include <AccelStepper.h>
#include <MultiStepper.h>

int xPositions[] = {-100, 2000, -5000, 0, 5000, 0};
int yPositions[] = {-500, 3000, -10000, 0, 1000, 0};

// EG X-Y position bed driven by 2 steppers
// Alas its not possible to build an array of these with different pins for each :-(
AccelStepper stepper1(AccelStepper::DRIVER, 2, 5);
AccelStepper stepper2(AccelStepper::DRIVER, 3, 6);

const byte enablePin = 8;  // necessary for my CNC shield V3.
long positions[2]; // Array of desired stepper positions
int numSteps = 0;

// Up to 10 steppers can be handled as a group by MultiStepper
MultiStepper steppers;

void setup()
{
   Serial.begin(9600);
   pinMode(enablePin, OUTPUT);
   digitalWrite(enablePin, LOW);

   // Configure each stepper
   stepper1.setMaxSpeed(1000);
   stepper2.setMaxSpeed(1000);

   // Then give them to MultiStepper to manage
   steppers.addStepper(stepper1);
   steppers.addStepper(stepper2);
   numSteps = sizeof(xPositions) / sizeof(xPositions[0]);
}

void loop()
{
   static int index = 0;
   if (steppers.run() == 0)
   {
      //Serial.print("run  ");
      //Serial.println(index);
      positions[0] = xPositions[index];
      positions[1] = xPositions[index];
      steppers.moveTo(positions);
      index++;
      if(index > numSteps)
      {
         index = 0;
      }
   }
}

Note that MultiStepper does not use acceleration so the motor speeds are limited.

Thanks for the reply. I found the problem with my original code - I was specifying speeds in the wrong order. That problem will never happen if I do things your way though. I'm not sure if I should delete this post, but maybe I'll leave it to possibly help future learners.

I say to leave it. It may be helpful to others. And deleting the content of a post that has answers is, I believe, considered vandalism.

AccelStepper is a position based library in which you can set the max speed to travel at between given positions.

For speed control you should look at my modified library that controls speed Stepper Speed Control Library project with plotting

Also look at my Multi-tasking in Arduino which has a complete stepper example with notes on how to keep your steppers running faster.