AccelStepper code: How to control two motors simultaneously

Hi there

I'm looking to write what should be a fairly simple bit of code for two stepper motors using accelstepper.

Basically I want to be able to move the two motors simultaneously and repeating the same pattern. left to right. So the both start at the same time. Move to set position eg. '50'. Then move to opposite position '-50' and have this process looped. Basically working in a pendulum like motion.

I know I need to use the run() as it's the non blocking function. So here is the initial code. Please excuse the current code in the 'void loop()' I know it's completely rubbish. But you can get the idea of what I'm trying to do.


// Define the stepper motor and the pins that is connected to
AccelStepper stepper1(1, 2, 5); // (Typeof driver: with 2 pins, STEP, DIR)
AccelStepper stepper2(1, 3, 6);

void setup() {

  stepper1.setMaxSpeed(1200); // Set maximum speed value for the stepper
  stepper1.setAcceleration(400); // Set acceleration value for the stepper
  stepper1.setCurrentPosition(0); // Set the current position to 0 steps

  stepper2.setMaxSpeed(1200);
  stepper2.setAcceleration(400);
  stepper2.setCurrentPosition(0);
}

void loop() {
  stepper1.moveTo(50);
  stepper1.run();
  stepper2.moveTo(50)
  stepper2.run()

  stepper1.moveTo(-50); 
  stepper1.run();
  stepper2.moveTo(-50)
  stepper2.run()
}

Thanks

If the two steppers have identical movements, you can take common step/dir wires to two different drivers.

So they won't have identical movements (sorry I know it seems that way from the code). But the plan is to have the speed slightly different from one another so they appear to be moving in phase but in fact start to drift out of sync.

made a sim for you..

easier to see if it does what you want..
looks like they get stuck??
have fun.. ~q

1 Like

Start with the BlinkWithoutDelay example but using two blocks with slightly different intervals.

Or give them slightly different speeds, and condition changing direction on reaching the destination with distanceToGo()==0


loop(){
 stepper1.run();
 stepper2.run();
 if (stepper1.distanceToGo() == 0){
   stepper1.moveTo(-stepper1.currentPosition);
  }
 if (stepper2.distanceToGo() == 0){
   stepper2.moveTo(-stepper2.currentPosition);
  }
}

ETA: Modding @qubits-us (thanks) sim code:

#include <AccelStepper.h>

// Define the stepper motor and the pins that is connected to
AccelStepper stepper1(1, 2, 5); // (Typeof driver: with 2 pins, STEP, DIR)
AccelStepper stepper2(1, 3, 6);

void setup() {

  stepper1.setMaxSpeed(1200); // Set maximum speed value for the stepper
  stepper1.setAcceleration(400); // Set acceleration value for the stepper
  stepper1.setCurrentPosition(0); // Set the current position to 0 steps

  stepper2.setMaxSpeed(1200);
  stepper2.setAcceleration(300);
  stepper2.setCurrentPosition(0);
  stepper1.moveTo(50);
  stepper2.moveTo(50);
}

void loop() {
  stepper1.run();
  stepper2.run();
  if(stepper1.distanceToGo()==0){
    stepper1.moveTo(-stepper1.currentPosition()); 
  }
  if(stepper2.distanceToGo()==0){
    stepper2.moveTo(-stepper2.currentPosition()); 
  }
}
1 Like

lol, faster than me..
halls some butt now and doesn't stop.. :slight_smile:

1 Like

Hey @qubits-us -- try this attribute line on your steppers per

   "attrs": { "size": "8" ,"arrow":"orange"}

Oh, I see you edited your sim code. You should change this line:

  stepper2.moveTo(-stepper1.currentPosition());;

to

  stepper2.moveTo(-stepper2.currentPosition());;
1 Like

lol, thanks i didn't see that..
still just goes back and forth..
now it's transmitting morse codes as it move the motors..

I was modding acceleration to try to get them out of sync, and it kept re-synchronizing.

change just one of the motors first move to's by one less..
and maybe alternate this when switching direction..

Accelleration works. I'm not sure if they are moving long enought ot hit the max speed limit.

You can get a phase difference with this:

I have to change the acceleration by about 5 points to 390 to get a phase difference.

their only moving 100 steps..
kind of makes sense you would need at least 5 to visibly notice any difference..

Acceleration of 396 vs 400 works:

#include <AccelStepper.h>


//alphas A-Z
byte MorseChars[] = {34, 65, 69, 49, 16, 68, 51, 64, 32, 78, 53, 66, 35, 33, 55, 70, 75, 50, 48, 17, 52, 72, 54, 73, 77, 67,
                     31, 30, 28, 24, 16, 0, 1, 3, 7, 15
                    };
//digits 0-9

char morseBuff[80];
int mc_state = 0;
int mc_count = 0;
int mc_idx = 0;
int dd_state = 0;
int dd_idx = 0;
int dd_time = 0;
int dot_dur = 200;
int dd_dur = 200;
bool mc_done;
bool dd_done;
bool morse_done = true;
bool loop_morse = false;
unsigned long dd_start;

#define LED_PIN 8


// Define the stepper motor and the pins that is connected to
AccelStepper stepper1(1, 2, 5); // (Typeof driver: with 2 pins, STEP, DIR)
AccelStepper stepper2(1, 3, 6);

void setup() {
  Serial.begin(115200);
  pinMode(8, OUTPUT);

  stepper1.setMaxSpeed(1200); // Set maximum speed value for the stepper
  stepper1.setAcceleration(396); // Set acceleration value for the stepper
  stepper1.setCurrentPosition(0); // Set the current position to 0 steps

  stepper2.setMaxSpeed(1200);
  stepper2.setAcceleration(400);
  stepper2.setCurrentPosition(0);
  stepper1.moveTo(50);
  stepper2.moveTo(50);
  MorseString("ARDS ARE AWESOME", true);
}

void loop() {
  MorseLoop();
  stepper1.run();
  stepper2.run();

  if (stepper1.distanceToGo() == 0) {
    stepper1.moveTo(-stepper1.currentPosition());
    if (stepper1.currentPosition() > 0) {
      Serial.print(stepper2.currentPosition() - stepper1.currentPosition());
      Serial.print(' ');
    }
  }
  if (stepper2.distanceToGo() == 0) {
    stepper2.moveTo(-stepper2.currentPosition());
  }
}


void leds_on()
{
  digitalWrite(LED_PIN, HIGH);

}
void leds_off()
{
  digitalWrite(LED_PIN, LOW);

}

//clear out the old
void ZeroMorseBuff()
{
  for (int i = 0; i < sizeof(morseBuff); i++ ) {
    morseBuff[i] = 0;
  }
}


bool MorseString(char *text, bool looped) {
  loop_morse = looped;
  bool loaded = false;
  if (strlen(text) > 0) {
    mc_idx = 0;
    mc_done = false;
    mc_state = 0;
    dd_done = true;
    dd_idx = 0;
    dd_state = 0;
    ZeroMorseBuff();
    char ch = *text;
    int count = 0;
    while (ch != NULL)
    {
      morseBuff[count] = ch;
      count++;
      *text++;
      ch = *text;
    }
    loaded = true;
    mc_count = count;
    morse_done = false;
  }
  return loaded;
}



void MorseLoop() {
  if (!morse_done) {
    if (mc_done) {
      if (mc_idx < mc_count) {
        mc_idx ++;
        if (mc_idx < mc_count) {
          mc_done = false;
          mc_state = 0;
          dd_done = true;
          dd_idx = 0;
          dd_state = 0;
          if (isalpha(morseBuff[mc_idx]))
          { if (isupper(morseBuff[mc_idx]))
            {
              MorseChar(MorseChars[morseBuff[mc_idx] - 'A'], false);
              //morse_char(letters[morseBuff[mc_idx] - 'A']);
            } else
            {
              MorseChar(MorseChars[morseBuff[mc_idx] - 'a'], false);
            }
          } else if (isdigit(morseBuff[mc_idx])) {
            MorseChar(MorseChars[morseBuff[mc_idx] - '1' + 27], true);
          } else if (morseBuff[mc_idx] == ' ') {
            mc_state = 1;
            dd_start = millis();
            dd_dur = dot_dur * 3;
          } else mc_done = true;//skip it
        } else {
          dd_start = millis();
          dd_dur = dot_dur * 6;
          morse_done = true;
        }
      } else {
        dd_start = millis();
        dd_dur = dot_dur * 6;
        morse_done = true;
      }
    } else
    {
      if (isalpha(morseBuff[mc_idx]))
      { if (isupper(morseBuff[mc_idx]))
        {
          MorseChar(MorseChars[morseBuff[mc_idx] - 'A'], false);
          //morse_char(letters[morseBuff[mc_idx] - 'A']);
        } else
        {
          MorseChar(MorseChars[morseBuff[mc_idx] - 'a'], false);
        }

      } else if (isdigit(morseBuff[mc_idx])) {
        MorseChar(MorseChars[morseBuff[mc_idx] - '1' + 27], true);
      } else if (morseBuff[mc_idx] == ' ') {
        MorseChar(MorseChars['B' - 'A'], false);
        //morse_char(letters['B' - 'A']);
      }
    }
  } else
  {
    if (loop_morse) {
      if (millis() - dd_start >= dd_dur) {
        mc_done = false;
        dd_done = true;
        dd_idx = 0;
        mc_idx = 0;
        mc_state = 0;
        dd_state = 0;
        morse_done = false;
      }
    }
  }
}




//starts a char morsing..
void MorseChar(byte morse_code, bool digit) {
  if (mc_state == 0) {
    byte dit = GetDit(morse_code, digit);
    if (dd_done) {
      if (dit != 99) {
        if (dd_idx == 0) dd_state = 0;//beginning
        dd_done = false;
        dd_state = 0;
        DitDat(dit);
        dd_idx ++;
      } else {
        // mc_done = true;
        dd_idx = 0;
        mc_state = 1;//inter char delay
        dd_start = millis();
        dd_dur = dot_dur * 3;
      }
    } else {
      DitDat(dit);
    }
  } else { //mc_state = 1 = inter char delay
    if (millis() - dd_start >= dd_dur) {
      mc_done = true;
    }
  }
}

byte GetDit(byte morse_code, bool digit) {
  byte dit = 99;// all done
  //digits are fixed count of 5
  int bits = 0;
  if (digit) bits = 5 ; else bits = morse_code >> 4;
  if (dd_idx == 0) dd_state = 0;//beginning
  if (bits > 0 && bits < 6 && dd_idx < bits) {
    dit = (morse_code >> dd_idx) & 0x1;
  }
  return dit;
}


void DitDat(byte dit) {
  if (dd_state == 0) {
    leds_on();
    dd_state = 1;
    dd_start = millis();
    if (dit == 0) {
      dd_dur = dot_dur;
    } else {
      dd_dur = dot_dur * 3;
    }
  } else if (dd_state == 1) {
    if (millis() - dd_start >= dd_dur) {
      dd_state = 2;
      leds_off();
      dd_start = millis();
      dd_dur = dot_dur;
    }
  } else if (dd_state == 2) {
    if (millis() - dd_start >= dd_dur) {
      dd_state = 3;
      dd_done = true;
    }

  }
}

so maybe it is a bit to drastic..
what about flip flopping the accel when changing dirs..
would the motors have time to re-sync or always be slightly off..

strange, always prints 0 but looks just a bit off to me now..
updated sim code..

Do you mean toggling the acceleration between 396 and 400 each time? That gets you to half the phase drift speed.

How slow a drift is the @Finn67 looking for?

As you say, discretizing into 100 steps isn't much to work with. One could use microstepping to get more position, speed and acceleration resolution.

yes, updated the orig sim with this and your changes..
very slight, i thought??

You could get more resolution/slighter drift with other fractions 1/3, 1/4 or 1/N fractions is easier than M/N.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.