Control of 4-stepper motor + 1-servo motor

Hello. What would be the best setup to control 4-Nema 17 stepper motors and 1-servomotor. I want to create a user interface which will allow the user to control the movement of the motors clockwise and counterclowise. I have arduino uno, cnc shield, 4x a4988 drives, but have no idea how to get there. Any links for useful tutorials? Is there any software besides PROCESSING that can make the project easier?

No real problem. Why do You tell about the mechanical "interface", NEMA17, the mounting of the stepper, and not giving a link to the electrical data sheet?
Hope You've got a real 4 stepper driver. Usual drivers only have 3 channels meaning that one channel runs 2 steppers on the same command.

Start by looking up how to adjust the driver board to use the correct current for the steppers.
Then make a temporary sketch exercising the stepper.
Do the same for the servo.
By then You've gained knowledge to merge that knowledge into one sketch.
Reading Your question, don't think about any easy solution. You have a learning curve in front of You. There's no easy quick fix available.

As You don't provide links to the steppers, nor to the servo, I can't tell what power supply You will need.

You may have more luck trying to control a ‘servo’ rather than a servomotor. Big difference.

A servo is a self-contained ‘system’, while the latter is only the driven component of a ‘servo’. It still needs feedback.

This image shows how the CNC pins map to the Uno pins.
cnc shield Uno pins

This shows how to set the jumpers to control the 4th stepper (A) with pins 12 (step) and 13 (dir).

In the diagram, your servo control pin is connected to ground. All of the pins on the black header connect to ground.

1 Like

Based on this arduino code, how do I connect servo to make it work?

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

#define limitSwitch1 11
#define limitSwitch2 10
#define limitSwitch3 9
#define limitSwitch4 A3

// Define the stepper motors and the pins the will use
AccelStepper stepper1(1, 2, 5); // (Type:driver, STEP, DIR)
AccelStepper stepper2(1, 3, 6);
AccelStepper stepper3(1, 4, 7);
AccelStepper stepper4(1, 12, 13);

Servo gripperServo;  // create servo object to control a servo


double x = 10.0;
double y = 10.0;
double L1 = 228; // L1 = 228mm
double L2 = 136.5; // L2 = 136.5mm
double theta1, theta2, phi, z;

int stepper1Position, stepper2Position, stepper3Position, stepper4Position;

const float theta1AngleToSteps = 44.444444;
const float theta2AngleToSteps = 35.555555;
const float phiAngleToSteps = 10;
const float zDistanceToSteps = 100;

byte inputValue[5];
int k = 0;

String content = "";
int data[10];

int theta1Array[100];
int theta2Array[100];
int phiArray[100];
int zArray[100];
int gripperArray[100];
int positionsCounter = 0;

void setup() {
  Serial.begin(115200);

  pinMode(limitSwitch1, INPUT_PULLUP);
  pinMode(limitSwitch2, INPUT_PULLUP);
  pinMode(limitSwitch3, INPUT_PULLUP);
  pinMode(limitSwitch4, INPUT_PULLUP);

  // Stepper motors max speed
  stepper1.setMaxSpeed(4000);
  stepper1.setAcceleration(2000);
  stepper2.setMaxSpeed(4000);
  stepper2.setAcceleration(2000);
  stepper3.setMaxSpeed(4000);
  stepper3.setAcceleration(2000);
  stepper4.setMaxSpeed(4000);
  stepper4.setAcceleration(2000);

  gripperServo.attach(A0, 600, 2500);
  // initial servo value - open gripper
  data[6] = 180;
  gripperServo.write(data[6]);
  delay(1000);
  data[5] = 100;
  homing();
}

void loop() {

  if (Serial.available()) {
    content = Serial.readString(); // Read the incomding data from Processing
    // Extract the data from the string and put into separate integer variables (data[] array)
    for (int i = 0; i < 10; i++) {
      int index = content.indexOf(","); // locate the first ","
      data[i] = atol(content.substring(0, index).c_str()); //Extract the number from start to the ","
      content = content.substring(index + 1); //Remove the number from the string
    }
    /*
     data[0] - SAVE button status
     data[1] - RUN button status
     data[2] - Joint 1 angle
     data[3] - Joint 2 angle
     data[4] - Joint 3 angle
     data[5] - Z position
     data[6] - Gripper value
     data[7] - Speed value
     data[8] - Acceleration value
    */
    // If SAVE button is pressed, store the data into the appropriate arrays
    if (data[0] == 1) {
      theta1Array[positionsCounter] = data[2] * theta1AngleToSteps; //store the values in steps = angles * angleToSteps variable
      theta2Array[positionsCounter] = data[3] * theta2AngleToSteps;
      phiArray[positionsCounter] = data[4] * phiAngleToSteps;
      zArray[positionsCounter] = data[5] * zDistanceToSteps;
      gripperArray[positionsCounter] = data[6];
      positionsCounter++;
    }
    // clear data
    if (data[0] == 2) {
      // Clear the array data to 0
      memset(theta1Array, 0, sizeof(theta1Array));
      memset(theta2Array, 0, sizeof(theta2Array));
      memset(phiArray, 0, sizeof(phiArray));
      memset(zArray, 0, sizeof(zArray));
      memset(gripperArray, 0, sizeof(gripperArray));
      positionsCounter = 0;
    }
  }
  // If RUN button is pressed
  while (data[1] == 1) {
    stepper1.setSpeed(data[7]);
    stepper2.setSpeed(data[7]);
    stepper3.setSpeed(data[7]);
    stepper4.setSpeed(data[7]);
    stepper1.setAcceleration(data[8]);
    stepper2.setAcceleration(data[8]);
    stepper3.setAcceleration(data[8]);
    stepper4.setAcceleration(data[8]);

    // execute the stored steps
    for (int i = 0; i <= positionsCounter - 1; i++) {
      if (data[1] == 0) {
        break;
      }
      stepper1.moveTo(theta1Array[i]);
      stepper2.moveTo(theta2Array[i]);
      stepper3.moveTo(phiArray[i]);
      stepper4.moveTo(zArray[i]);
      while (stepper1.currentPosition() != theta1Array[i] || stepper2.currentPosition() != theta2Array[i] || stepper3.currentPosition() != phiArray[i] || stepper4.currentPosition() != zArray[i]) {
        stepper1.run();
        stepper2.run();
        stepper3.run();
        stepper4.run();
      }
      if (i == 0) {
        gripperServo.write(gripperArray[i]);
      }
      else if (gripperArray[i] != gripperArray[i - 1]) {
        gripperServo.write(gripperArray[i]);
        delay(800); // wait 0.8s for the servo to grab or drop - the servo is slow
      }

      //check for change in speed and acceleration or program stop
      if (Serial.available()) {
        content = Serial.readString(); // Read the incomding data from Processing
        // Extract the data from the string and put into separate integer variables (data[] array)
        for (int i = 0; i < 10; i++) {
          int index = content.indexOf(","); // locate the first ","
          data[i] = atol(content.substring(0, index).c_str()); //Extract the number from start to the ","
          content = content.substring(index + 1); //Remove the number from the string
        }

        if (data[1] == 0) {
          break;
        }
        // change speed and acceleration while running the program
        stepper1.setSpeed(data[7]);
        stepper2.setSpeed(data[7]);
        stepper3.setSpeed(data[7]);
        stepper4.setSpeed(data[7]);
        stepper1.setAcceleration(data[8]);
        stepper2.setAcceleration(data[8]);
        stepper3.setAcceleration(data[8]);
        stepper4.setAcceleration(data[8]);
      }
    }
    /*
      // execute the stored steps in reverse
      for (int i = positionsCounter - 2; i >= 0; i--) {
      if (data[1] == 0) {
        break;
      }
      stepper1.moveTo(theta1Array[i]);
      stepper2.moveTo(theta2Array[i]);
      stepper3.moveTo(phiArray[i]);
      stepper4.moveTo(zArray[i]);
      while (stepper1.currentPosition() != theta1Array[i] || stepper2.currentPosition() != theta2Array[i] || stepper3.currentPosition() != phiArray[i] || stepper4.currentPosition() != zArray[i]) {
        stepper1.run();
        stepper2.run();
        stepper3.run();
        stepper4.run();
      }
      gripperServo.write(gripperArray[i]);

      if (Serial.available()) {
        content = Serial.readString(); // Read the incomding data from Processing
        // Extract the data from the string and put into separate integer variables (data[] array)
        for (int i = 0; i < 10; i++) {
          int index = content.indexOf(","); // locate the first ","
          data[i] = atol(content.substring(0, index).c_str()); //Extract the number from start to the ","
          content = content.substring(index + 1); //Remove the number from the string
        }
        if (data[1] == 0) {
          break;
        }
      }
      }
    */
  }

  stepper1Position = data[2] * theta1AngleToSteps;
  stepper2Position = data[3] * theta2AngleToSteps;
  stepper3Position = data[4] * phiAngleToSteps;
  stepper4Position = data[5] * zDistanceToSteps;

  stepper1.setSpeed(data[7]);
  stepper2.setSpeed(data[7]);
  stepper3.setSpeed(data[7]);
  stepper4.setSpeed(data[7]);

  stepper1.setAcceleration(data[8]);
  stepper2.setAcceleration(data[8]);
  stepper3.setAcceleration(data[8]);
  stepper4.setAcceleration(data[8]);

  stepper1.moveTo(stepper1Position);
  stepper2.moveTo(stepper2Position);
  stepper3.moveTo(stepper3Position);
  stepper4.moveTo(stepper4Position);

  while (stepper1.currentPosition() != stepper1Position || stepper2.currentPosition() != stepper2Position || stepper3.currentPosition() != stepper3Position || stepper4.currentPosition() != stepper4Position) {
    stepper1.run();
    stepper2.run();
    stepper3.run();
    stepper4.run();
  }
  delay(100);
  gripperServo.write(data[6]);
  delay(300);
}

void serialFlush() {
  while (Serial.available() > 0) {  //while there are characters in the serial buffer, because Serial.available is >0
    Serial.read();         // get one character
  }
}

void homing() {
  // Homing Stepper4
  while (digitalRead(limitSwitch4) != 1) {
    stepper4.setSpeed(1500);
    stepper4.runSpeed();
    stepper4.setCurrentPosition(17000); // When limit switch pressed set position to 0 steps
  }
  delay(20);
  stepper4.moveTo(10000);
  while (stepper4.currentPosition() != 10000) {
    stepper4.run();
  }

  // Homing Stepper3
  while (digitalRead(limitSwitch3) != 1) {
    stepper3.setSpeed(-1100);
    stepper3.runSpeed();
    stepper3.setCurrentPosition(-1662); // When limit switch pressed set position to 0 steps
  }
  delay(20);

  stepper3.moveTo(0);
  while (stepper3.currentPosition() != 0) {
    stepper3.run();
  }

  // Homing Stepper2
  while (digitalRead(limitSwitch2) != 1) {
    stepper2.setSpeed(-1300);
    stepper2.runSpeed();
    stepper2.setCurrentPosition(-5420); // When limit switch pressed set position to -5440 steps
  }
  delay(20);

  stepper2.moveTo(0);
  while (stepper2.currentPosition() != 0) {
    stepper2.run();
  }

  // Homing Stepper1
  while (digitalRead(limitSwitch1) != 1) {
    stepper1.setSpeed(-1200);
    stepper1.runSpeed();
    stepper1.setCurrentPosition(-3955); // When limit switch pressed set position to 0 steps
  }
  delay(20);
  stepper1.moveTo(0);
  while (stepper1.currentPosition() != 0) {
    stepper1.run();
  }
}
/>

The servo will need an external power supply capable of providing the current required by the servo. See this Pololu page for a discussion on servo power requirements.

Connect the plus of the servo power supply to the servo +. Connect the ground of the servo power supply to the - (ground) of the servo and to the Uno ground (the black header is connected to ground). Connect the signal wire of the servo to the Abort pin (Uno A0) on the CNC shield.

Please edit your post to put the code in code tags and format the code for readability. Read the forum guidelines to see how to properly post code.
Use the IDE autoformat tool (ctrl-t or Tools, Auto format) before posting code in code tags.

1 Like

First of all. Thank you for your help answering questions. The CNC shield is supplied by 12V, 6A DC power supply. Is this enough power to be able to run 4x 17-Nema stepper motors and servo motor at the same time? Also, during playing with the code, my A4988 drive went on fire? Is there any particular reason for that? Also, I read that the A4988 have some sort of current limits that you adjust by the screws? Might this be the reason why the A4988 drive went on the fire?

Do you have data sheets for the stepper motors that list the coil current?

The A4988 stepper driver is good for about 1A without heat sink and active cooling (fan) and good for about 1.5A with a heat sink an active cooling. A DRV8825 will go the 1.5A with no heat sink and cooling and 2A with heat sink and active cooling. DRV8825 drivers will directly replace A4988 drivers. For over 2A there are other drivers.

It is vital (as you discovered) that the coil current on the stepper drivers be set properly.
The Pololu page on A4988 has instructions on setting the coil current., but be aware that the current sense resistors may be different than the ones on the Pololu version of the A4988 so you need to know the value of the sense resistors on your boards and use those values in the formula to calculate the Vref to set. This Reprap page has more information. It is important to set the coil current less than the max current on the stepper motor data sheet. You can set to much less if you want and the motors will handle the load without skipping steps. The less coil current the longer the motors will live and the cooler the motors and drivers will run.
The motors and drivers can get quite hot. That is normal.

1 Like

Thanks for the links. I will look into them once I have a minute :sleepy:
4x Nema17 59Ncm 2A 1.8°4-lead 48mm Stepper Motor For 3D Printer CNC:

**Specifications:**

- Material: Metal

- Dimensions: 42x42x48mm/1.65”x1.65”x1.88”

- Phase Number: 2

- Step Angle: 1.8°±5%

- Rated Voltage: 2.8V

- Holding Torque: ≧5 Kg-cm(70 Oz-in)

- Rated Current: 2.0A

- Resistance(20℃): 1.4±10%?/phase

- Max. Slewing PPS: 2500 PPS

- HI-POT: AC 600V/1mA/1S

- Rotor Inertia: 68g.cm2

- Inductance: 3.0±20%mH

- Detent Torque: 2.0Kg-cm

- Insulation Resistance: ≧100M?(DC 500V)

- Leads: 4

- Application: Use for3D printer, Linear actuators and CNC router for plastic&metal.

1x - MG996R digital servo

Dimension : 40 x 19 x 43mm
Weight : 55g
Operating Speed : 0.17sec / 60 degrees (4.8V no load)
Operating Speed : 0.13sec / 60 degrees (6.0V no load)
Stall Torque : 13 kg-cm (180.5 oz-in) at 4.8V
Stall Torque : 15 kg-cm (208.3 oz-in) at 6V
Operation Voltage : 4.8 - 7.2Volts
Gear Type: All Metal Gears
Connector Wire: 11.81"  (300mm)
Color: Black

4x BIQU A4988 Compatible StepStick Stepper Motor Diver Module with Heat Sink for 3D Printer Controller Ramps 1.4

B01FFGAKK8 - cant find data sheet

AccelStepper has a sample/demo for multiple steppers, and adding an R/C servo should be trivial.

I had another look at the code in reply #5. The CNC shield holds the stepper enable pin (Uno pin 8) high by default, disabling the steppers. You need to either place a jumper on the header labeled EN/GND (right next to the reset pin) or enable the steppers in code. In setup(), set the enable pin pinMode to OUTPUT and write a LOW to the enable pin to enable the steppers.