Simultaneous Stepper motor

Hi, I've write this code for a robot arm with 4 stepper and 3 servo:
1 NEMA23
3 NEMA17
3 MG996R
All of these are connected with a 24V external PS and a 5V PS.

#include <MobaTools.h>
#include <Servo.h>
#include <AccelStepper.h>

#define dirPin 5
#define stepPin 2
#define motorInterfaceType 1

byte ang1A = 65;
byte ang2A = 50;
byte ang3A = 10;


byte ang1R = 140;
byte ang2R = 120;
byte ang3R = 105;



int time1 = 500;
int time2 = 200;

int val;
long steppos1 = 130;
long steppos2 = 500;
long steppos3 = 500;
long steppos4 = 500;

const byte enablePin = 8;  // for my CNC shield stepper enable

const byte servoPin1 = 9;
const byte servoPin2 = 10;
const byte servoPin3 = 11;

//  Define stepper motor
AccelStepper StepperX = AccelStepper(motorInterfaceType, stepPin, dirPin);
MoToStepper StepperY(steppos1, STEPDIR);  //Braccio 2 rotazione
MoToStepper StepperZ(steppos2, STEPDIR);  //braccio 2
MoToStepper StepperA(steppos3, STEPDIR);  //Base
//  MoToStepper StepperA(steppos, STEPDIR);


// DEFINISCO I SERVO
Servo servo1;  //Servo pinza
Servo servo2;  //Servo rotazione testina
Servo servo3;  //Servo 180 iniziale


void setup() {


  //Define Pin Stepper
  pinMode(enablePin, OUTPUT);
  pinMode(12, OUTPUT);
  pinMode(13, OUTPUT);
  Serial.begin(9600);

  //Define servo pin
  servo1.attach(servoPin1);
  servo2.attach(servoPin2);
  servo3.attach(servoPin3);


  //Define servo initial angle
  servo1.write(ang1R);
  servo2.write(ang2R);
  servo3.write(ang3R);


  //Define stepper motor
  StepperY.attach(3, 6);
  StepperZ.attach(4, 7);
  StepperA.attach(12, 13);

  StepperX.setMaxSpeed(50000);
  StepperX.setAcceleration(1600);

  StepperY.setSpeed(600);
  StepperZ.setSpeed(600);
  StepperA.setSpeed(600);
}

void loop() {
  if (Serial.available()) {
    val = Serial.read();

    //ANDATA

    if (val == 'y') {
      Serial.println('y');

      StepperX.moveTo(-steppos4);
      StepperX.runToPosition();
      StepperZ.doSteps(-steppos2);

      StepperA.doSteps(steppos3);
      delay(time1);


      StepperY.doSteps(-steppos1);
      delay(time2);



      // SERVOMOTORI

      servo2.write(ang2A);
      delay(time1);

      servo3.write(ang3A);
      delay(time1);

      servo1.write(ang1A);
      delay(2000);
    }



    //RITORNO

    if (val == 'b') {
      Serial.println('y');

      StepperX.moveTo(0);
      StepperX.runToPosition();
      StepperA.doSteps(-steppos3);
      delay(time1);

      StepperY.doSteps(steppos1);
      delay(time2);

      StepperZ.doSteps(steppos2);

      // SERVOMOTORI


      servo2.write(ang2R);
      delay(time1);

      servo3.write(ang3R);
      delay(time1);

      servo1.write(ang1R);
      delay(time1);
    }
  }
}

My question is, can I move for example two of these motor simultaneos? Like while A motor go right B motor go left.
I drive that motor with an arduino 1 with a cnc shield V3.0, Driver DM556 for NEMA23 and A4988 for NEMA17.

Thank you so much :slight_smile:

What does the AccelStepper documentation say?

Have you tested the code above with one stepper?

Why do you mixup MobaTools, Servo.h and Accelstepper.? You should decide:
MobaTools.h or Servo.h/AccelStepper.h.

MobaTools and Servo.h will not run together, because both use the same timer on Arduino UNO. MobaTools can control servos too, so you don't need Servo.h if you use MobaTools

If you want to move several steppers in parallel, you must not use the blocking methods of AccelStepper.

MobaTools has no blocking calls for stepper movement, so you can always run several steppers in parallel.

That's way to fast. You cannot reach that speed on an Arduino UNO.

I know but It work, I've no problem with speed.
I use accel stepper and moba because moba with DM556 doesn't work and the only way I found is that.
Mobatools for servo doesn't work very well like servo.h

Then you did something wrong.

But it makes no sense. You will get an arbitrary speed.

Can you explain? I have never heard of it and I know many users use MobaTools with servos.

I guess @mariorossi26088 tries to use the MobaTools as a drop in replacement or in parallel with servo.h which of course does not work

I gave an arbitrary speed to the motor, i can try to use only mobatools, but can it drive various motor simultaneously?

Using moba my servo goes jerky, instead with servo goes very good.

By the way, in the next days I'll try to use only moba and I'll re-send my code to you

Thank you so much

It can control up to 6 motors completely independent from each other - they all can move at the same time if you wish. Be aware that all MoToStepper calls are not blocking - your sketch moves on while the motors are moving. So you can change the moving of one motor while the others are still moving as you have specified. And you can change motor data ( speed, targetposition, ramplength ) at any time - wether the motor is still moving or not.

Did you include Servo.h, when trying this? And did you define a speed for the servo?
Which Arduino Board are you using?

At the moment I only have limited possibilities to really try something out. But I will have a look at it and also try to test a little bit as is possible.

ok thank you so much, I'm still working on the code. I use Arduino Uno with CNC SHIELD V3.0. If I use do step like in the code It don't run simultaneously, there is a particulary code tu use?
Yes I write the speed of servo.

I use servo.h because with moba pins 9 and 10 are not able to use and i don't have pin for every servo. (I think Groundfungus tell me in another topic)
I try to write a code to use dm556 with my nema but it not works, I don't now why. The code is the following, if you have an idea please tell me. And how to use the motor in simultaneous?
thank you so much for your advice and your time.

#include <MobaTools.h>
#include <Servo.h>

byte ang1A = 65;
byte ang2A = 50;
byte ang3A = 10;

byte ang1R = 140;
byte ang2R = 120;
byte ang3R = 105;

int time1 = 500;
int time2 = 200;

int val;
long steppos1 = 500;
long steppos2 = 130;
long steppos3 = 500;
long steppos4 = 500;

const byte enablePin = 8;  // for my CNC shield stepper enable

const byte servoPin1 = 9;
const byte servoPin2 = 10;
const byte servoPin3 = 11;

//  Define stepper motor
MoToStepper StepperX(steppos1, FULLSTEP);
MoToStepper StepperY(steppos2, STEPDIR);  //Braccio 2 rotazione
MoToStepper StepperZ(steppos3, STEPDIR);  //braccio 2
MoToStepper StepperA(steppos4, STEPDIR);  //Base
//  MoToStepper StepperA(steppos, STEPDIR);


// DEFINISCO I SERVO
Servo servo1;  //Servo pinza
Servo servo2;  //Servo rotazione testina
Servo servo3;  //Servo 180 iniziale


void setup() {


  //Define Pin Stepper
  pinMode(enablePin, OUTPUT);
  pinMode(12, OUTPUT);
  pinMode(13, OUTPUT);
  Serial.begin(9600);

  //Define servo pin
  servo1.attach(servoPin1);
  servo2.attach(servoPin2);
  servo3.attach(servoPin3);

  //Define servo initial angle
  servo1.write(ang1R);
  servo2.write(ang2R);
  servo3.write(ang3R);


  //Define stepper motor
  StepperX.attach(2, 5);
  StepperY.attach(3, 6);
  StepperZ.attach(4, 7);
  StepperA.attach(12, 13);

  //Set speed stepper motor
  StepperX.setSpeed(600);
  StepperY.setSpeed(600);
  StepperZ.setSpeed(600);
  StepperA.setSpeed(600);
}

void loop() {
  if (Serial.available()) {
    val = Serial.read();

    //ANDATA

    if (val == 'y') {
      Serial.println('y');

      StepperX.setZero();
      StepperY.setZero();
      StepperZ.setZero();
      StepperA.setZero();

      StepperX.move(-steppos1);
      StepperZ.doSteps(-steppos3);

      StepperA.doSteps(steppos4);
      delay(time1);

      StepperY.doSteps(-steppos2);
      delay(time2);

      // SERVOMOTORI

      servo2.write(ang2A);
      delay(time1);

      servo3.write(ang3A);
      delay(time1);

      servo1.write(ang1A);
      delay(2000);
    }



    //RITORNO

    if (val == 'b') {
      Serial.println('b');

      StepperX.move(steppos1);
      StepperA.doSteps(-steppos4);
      delay(time1);

      StepperY.doSteps(steppos2);
      delay(time2);

      StepperZ.doSteps(steppos3);

      // SERVOMOTORI


      servo2.write(ang2R);
      delay(time1);

      servo3.write(ang3R);
      delay(time1);

      servo1.write(ang1R);
      delay(time1);
    }
  }
}

You still use both. And I told you already, you cannot use both in one sketch, that will not work.

What makes you think so? MoToServo works fine on pins 9 and 10.

What driver do you use for StepperX? FULLSTEP mode will not work with a DM556

How did you wire all that? The cnc shield V3.0 isn't really meant to be used together with a DM556.

The first parameter when creating a stepper object is the number of steps per revolution. So I don't think that's correct here.

thank you so much but I won't disturb you and I wont you waste your time.

I don't know, before I use moba and servo on pin 9 and 10 doesn't work, with servo.h they work instead.

For stepper X I use DM556, with STEPDIR it didn't work so I try to use fullstep. I read the manual but maybe I do a mistake

I know but I don't have a special pcb for that, on Y Z and A I connect 3 A4988 to use 3 NEMA 17, X driver was disconnected and I have connected only pin 2 and 5 to DM556 tu use a NEMA 23.
servo 1, 2 and 3 are on pins 9, 10, 11 like in the code. With my code all work goo but can be better than now and I hope to improve it.

I'm a little bit confused what you are really doing. Did you ever try to use ONLY MobaTools, and not including Servo.h at all? Both libs use timer 1 on an Arduino UNO. Therefore, they get in each other's way, and it is more of a coincidence what works and what does not. You must not use both!

Yes I've already tried to use mobatools only and the servo doesn't run good. Now I'm writing a new code with mobatools only and I try another time with moba. I trust you. I'm sure you are much experienced than me.
Thank you so much, when I've finished to write the code I'll send it there.

Whenever you encounter problems on the way writing a new code you can ask here in the forum.
I guess if you ask in the forum the experience of the others users here will help to finish your code faster.

best regards Stefan

#include <MobaTools.h>


byte ang1A = 65;
byte ang2A = 50;
byte ang3A = 10;

byte ang1R = 140;
byte ang2R = 120;
byte ang3R = 105;


int time1 = 500;
int time2 = 200;

int val;

long step1 = 1600;
long step2 = 200;
long step3 = 200;
long step4 = 200;

long steppos1 = 474;  //dovrebbero essere 474 gradi in e output 90 gradi
long steppos2 = 130;  //
long steppos3 = 500;  //
long steppos4 = 500;  //

const byte pinStepX = 2;
const byte pinDirX =  5;
const byte pinStepY = 3;
const byte pinDirY =  6;
const byte pinStepZ = 4;
const byte pinDirZ =  7;
const byte pinStepA = 12;
const byte pinDirA =  13;

const byte enablePin = 8;  // for my CNC shield stepper enable

const byte servoPin1 = 9;
const byte servoPin2 = 10;
const byte servoPin3 = 11;



//  Define stepper motor
MoToStepper StepperX(step1, STEPDIR);  //ARM1
MoToStepper StepperY(step2, STEPDIR);  //ARM2 ROTATION
MoToStepper StepperZ(step3, STEPDIR);  //ARM2
MoToStepper StepperA(step4, STEPDIR);  //BASE
//  MoToStepper StepperA(steppos, STEPDIR);


// DEFINISCO I SERVO
MoToServo servo1;  //SERVO GRIPPER
MoToServo servo2;  //SERVO GRIPPER JOINT
MoToServo servo3;  //SERVO JOINT


void setup() {


  //Define Pin Stepper
  pinMode(enablePin, OUTPUT);
  pinMode(12, OUTPUT);
  pinMode(13, OUTPUT);
  Serial.begin(9600);

  //Define servo pin
  servo1.attach(servoPin1, ang1R);
  servo2.attach(servoPin2, ang2R);
  servo3.attach(servoPin3, ang3R);

  //Define stepper motor
  StepperX.attach(pinStepX, pinDirX);
  StepperY.attach(pinStepY, pinDirY);
  StepperZ.attach(pinStepZ, pinDirZ);
  StepperA.attach(pinStepA, pinDirA);

  //Set speed stepper motor
  StepperX.setSpeed(600);
  StepperY.setSpeed(600);
  StepperZ.setSpeed(600);
  StepperA.setSpeed(600);

  servo1.setSpeed(20);
  servo2.setSpeed(20);
  servo3.setSpeed(20);  
}

void loop() {
  if (Serial.available()) {
    val = Serial.read();

    //ANDATA

    if (val == 'y') {
      Serial.println('y');

      StepperX.setZero();
      StepperY.setZero();
      StepperZ.setZero();
      StepperA.setZero();

      StepperX.write(-steppos1);
      StepperZ.write(-steppos3);

      StepperA.write(steppos4);
      delay(time1);

      StepperY.write(-steppos2);
      delay(time2);

      // SERVOMOTORI

      servo2.write(ang2A);
      delay(time1);

      servo3.write(ang3A);
      delay(time1);

      servo1.write(ang1A);
      delay(2000);
    }



    //RITORNO

    if (val == 'b') {
      Serial.println('b');

      StepperX.move(steppos1);
      StepperA.doSteps(-steppos4);
      delay(time1);

      StepperY.doSteps(steppos2);
      delay(time2);

      StepperZ.doSteps(steppos3);

      // SERVOMOTORI


      servo2.write(ang2R);
      delay(time1);

      servo3.write(ang3R);
      delay(time1);

      servo1.write(ang1R);
      delay(time1);
    }
  }
}

This is the code now, I've not try it yet but I think is good, how can I use servo speed?

@MicroBahner

I looked up the documentation and I don't get it:

setSpeed(int Speed);
Set the speed of movement of the servo. Speed' is the value by which the pulse length ( as
average value ) changes every 20ms when the servo moves.

What is the unit of this changement? microseconds?

You should add a formula to the documentation with examples
starting like this:

If you want the servo to move for 90 degrees
and this movement shall be finished after 5 seconds
then speed is calculated by ..........

by using easy to understand "variable-names" like
"angleToMove" , "SecondsToFinishMovement"

angleToMove = 90;
SecondsToFinishMovement = 5;

// forumula

##EDIT
I did some calculations:
The documentation says:
speed = 20 it needs 8 seconds = 8000 milliseconds
to change pulsewidth from 1000 microseconds to 2000 microseconds

speed = value that the pulsewidth changes once every 20 milliseconds

8 seconds = 8000 milliseconds
once every 20 milliseconds a change of the pulsewidth occurs
8000 / 20 = 400 steps (changing the pulsewidth)

overall-change is from 1000 microseconds to 2000 microseconds
so the sum-change is 1000 microseconds

This sum-change is done in 400 steps so in each step the change is
1000 microseconds / 400 steps = 2.5 microseconds per step.

The documentation says:
Speed' is the value by which the pulse length ( as
average value ) changes every 20ms when the servo moves.
Your example says speed = 20 microseconds.
My calculation resulted in 2.5 microseconds

another way of interpreting the description
speed = 20 means
change pulsewidth add/substract 20 microseconds once every 20 milliseconds
so changing from 1000 microseconds to 2000 microseconds which is 1000 microseconds
would take 1000 microseconds / 20 microseconds = 50 steps

where each step occurs after 20 milliseconds which would mean the overall time would be
20 milliseconds * 50 steps = 1 second

First version does not fit to saying "Speed is the value by which the pulse length ( as
average value ) changes every 20ms"

Second version does not fit to time 8 seconds.

So how does it really work?

best regards Stefan

finally I analysed the real behaviour of myservo.setspeed();

I tested this on an Arduino Uno. As other microcontrollers have other clock-speeds and other time-resolutions it might be that for other microcontrollers the values are different.

With testing with an Arduino Uno I came up with this approximation-formula:

value for parameter speed = 160 / (Time to turn 180 degrees)

As a table

seconds		speed
160			1
80			2
53			3
40			4
20			8
16			10
12			13
10			16
8			20
7			23
6			27
5,5			29
5			32
4,5			35
4			40
3,5			46
3			53
2,5			64
2			80
1,5			107

hm ... --- ... for defining anything with more precision how long a move for a given angle shall take
This must be done on the main-code-level with non-blocking timing.

As the servo-pulses only occur every 20 milliseconds there is a limitation caused by this time-interval for higher speeds of the turning.

For very slow turnings of the servo taking 10 seconds or more for 180 degrees this could be used

best regards Stefan

1 Like

Important is the base of the increment value. The documentation says:

On AVR and STM32 Speed is given in 0.5µs units (compatibility to older versions). On the
ESP processors it is 0.125µs units. If the optional parameter 'HIGHRES' is specified once, it
is also on AVR and STM generally 0.125µs ( for all instances ).

The example is computed for the HIGHRES state, because this is the same for all platforms ( ok, I should have mentioned this in the documentation ... )

That's correct. And 2.5 µs = 20*0.125µs ( with 0.125µs being the basic increment value ). So speed = 20 leads to 8sec from 1000 to 2000µs pulsewidth.

Of course on an AVR/STM32 without setting HIGHRES it's 4 times faster ( with 0.5µs being the basic increment value )