Nema 17 can't run faster than 40 rpm

Hello everyone,

i’ve got a problem with the programmation of 2 stepper motors Nema 17 with 200 step/rev.
I need one to run at a continuous speed, and the other to run slower for a precise period of time and then faster for the same amount of time.
My problem is that I can’t turn the motors faster than a bit less than 40 rpm, even after I simplifyed mw programm to just turn both motors at the same speed.
If I put a number higher than 40, both motors turn but at around 40 rpm.
I’m using an Arduino Uno and an Adafruit Motor Shield v2.3 with a 12V 1A power supply.
There is almost no torque on the motors.
What is even stranger is that a few days ago I could run these motors at least at 120 rpm (I didn’t try faster a the time).

// STEUERUNG ZWEIER SCHRITTMOTOREN

//Einbindung der Bibliotheken
#include <Wire.h>
#include <AccelStepper.h>
#include <Adafruit_MotorShield.h>

//Initialisierung der Variablen
long N2=0;

//Standardadresse (0x60), Kommunikation mit Motor Shield
Adafruit_MotorShield AFMStop(0x60);

// M1/M2-Port1; M3/M4-Port2; 200 Schrittfolgen entspricht eine Umrundung bei einem Schrittwinkel von 1.8 Grad
Adafruit_StepperMotor *myStepper1 = AFMStop.getStepper(200, 1);
Adafruit_StepperMotor *myStepper2 = AFMStop.getStepper(200, 2);

// Schritttypen:SINGLE, DOUBLE, INTERLEAVE oder MICROSTEP!
// 1.Motor (kuerze Welle)
void forwardstep1() {  //Objekt für Vorwährts
  myStepper1->onestep(FORWARD, DOUBLE);
}
void backwardstep1() {  //Objekt für Rückwärts
  myStepper1->onestep(BACKWARD, DOUBLE);
}
// 2.Motor (laenge Welle)
void forwardstep2() {
  myStepper2->onestep(FORWARD, DOUBLE);
}
void backwardstep2() {
  myStepper2->onestep(BACKWARD, DOUBLE);
}


// Motorobjekte für das Beschleunigen erstellen
AccelStepper stepper1(forwardstep1, backwardstep1);
AccelStepper stepper2(forwardstep2, backwardstep2);

void setup()
{
  AFMStop.begin(); // Motor Shield aktivieren
  Serial.begin(9600);
  stepper1.setAcceleration(500);
  stepper2.setAcceleration(500);
}

void geschwindigkeit() 
{
      stepper2.setMaxSpeed(3.3333*N2); //setMaxSpeed z.b 100 Schritte pro Sekunde
      stepper2.move(200); // Motor soll z.B 25 Schritte machen
      
      stepper1.setMaxSpeed(3.3333*N2);
      stepper1.move(200);
}

void loop()
{
  while (Serial.available() > 0) {

    N2 = Serial.parseInt(); //Einlesen der Zahlen
       
     Serial.end();
     Serial.begin(9600);
   }
  geschwindigkeit();
  stepper1.run();
  stepper2.run();
}

Thanks for your help

What happens if you comment out this line

N2 = Serial.parseInt();

Serial.parseInt() is a blocking function. Have a look at the examples in Serial Input Basics - simple reliable non-blocking ways to receive data. There is also a parse example to illustrate how to extract numbers from the received text.

...R

One problem is that you are trying to setMaxSpeed() and move() everytime round loop() - this is not the way to do things.

Call setMaxSpeed() and move() only after reading a new N2 command from Serial.

Call run() everytime round loop() as you are doing.

Thank you for your help.
I successfully wrote a program to turn the motors at a constant speed, but without asking for a speed, it was defined during the variable declaration.
Unfortunately I couldn’t find an easy way to ask for multiple variables in one entry.
Also, I need one motor to speed up and then slow down.
I coded something, but the motors don’t turn as fast as I would like, even though I defined the speed of the first motor only every time I need to change its speed. (see below)
What am I doing wrong

#include <Wire.h>
#include <AccelStepper.h>
#include <Adafruit_MotorShield.h>

Adafruit_MotorShield AFMStop(0x60);
Adafruit_StepperMotor *myStepper1 = AFMStop.getStepper(200, 1);
Adafruit_StepperMotor *myStepper2 = AFMStop.getStepper(200, 2);
void forwardstep1() {
  myStepper1->onestep(FORWARD, DOUBLE);
}
void backwardstep1() {
  myStepper1->onestep(BACKWARD, DOUBLE);
}
void forwardstep2() {
  myStepper2->onestep(FORWARD, DOUBLE);
}
void backwardstep2() {
  myStepper2->onestep(BACKWARD, DOUBLE);
}
AccelStepper stepper1(forwardstep1, backwardstep1);
AccelStepper stepper2(forwardstep2, backwardstep2);

long N2=0;
int T=1;
int i=1;
long timer=0;
void setup()
{
  AFMStop.begin();
  Serial.begin(9600);
  stepper1.setAcceleration(500);
  stepper2.setAcceleration(500);
}

void loop(){
  while (Serial.available() > 0){
    N2 = Serial.parseInt();
    Serial.read();

    stepper2.setMaxSpeed(N2*200/60);
    stepper1.setMaxSpeed((N2+i*N2/2)*200/60);
    stepper1.move(400);
    stepper2.move(400);
    
    timer=millis();
   }
  if (millis()-timer > T*1000 && N2>0){
    i=-i;
    stepper1.setMaxSpeed((N2+i*N2/2)*200/60);
    timer=millis();
    stepper1.move(400);
    stepper2.move(400);
  }
  if(N2>0){
  stepper1.run();
  stepper2.run();
}
}

hesponge:
What am I doing wrong

The first problem I see is that you have your Serial code and your stepper code mixed up in loop(). It would much better to have the code for each of those in separate functions so you can test them separately.

That will allow you to check that motor will go at the speed you require without any Serial input.

Secondly, the function Serial.parseInt() is a blocking function so it’s going to slow everything down.

Have a look at the examples in Serial Input Basics - simple reliable non-blocking ways to receive data. There is also a parse example to illustrate how to extract numbers from the received text.

The technique in the 3rd example will be the most reliable. It is what I use for Arduino to Arduino and Arduino to PC communication. It also illustrates how you can receive several values in a single message.

You can send data in a compatible format with code like this (or the equivalent in any other programming language)

Serial.print('<'); // start marker
Serial.print(value1);
Serial.print(','); // comma separator
Serial.print(value2);
Serial.println('>'); // end marker

It would also be a help if you can explain what these lines of code are doing with the value in N2 and give examples of the values that can be expected for N2.

  if (millis()-timer > T*1000 && N2>0){
    i=-i;
    stepper1.setMaxSpeed((N2+i*N2/2)*200/60);

By the way, N2 is a meaningless name for a variable - code is much easier to understand if you give meaningful names to variables and functions.

Finally, for now, why is stepper.run() only called if N2 > 0 ?

  if(N2>0){
    stepper1.run();
    stepper2.run();
  }

It would be more normal to call stepper.run all the time.

…R

I modified the example 3 in Serial Input Basics because I couldn’t find a way to easily extract numbers in decimal, but it seams to work as intended, and it is in a separate function, and it doesn’t use Serial.parseInt().
The way my program reads values, it allows to enter only the first value to change only the first variable (here N2).

I added commentaries to make the program easier to understand.

The goal of it is to turn a motor 2 constantly at N2 rpm, and another motor 1 should run faster by DN rpm during T seconds and then slower also by DN rpm also for T seconds. In mathematical terms:
For 0<t<T, N1 = N2 + DN, for T<t<2T, N1 = N2 - DN

If the variable nz = 0, DN is also 0 but T is infinite, so I added a special case for that.

But I can’t get my motors to turn faster than 40 rpm, and it’s not a torque issue, because I can try to stop it wih my hands and it still turns at around 40rpm.

#include <Wire.h>
#include <AccelStepper.h>
#include <Adafruit_MotorShield.h>

Adafruit_MotorShield AFMStop(0x60);
Adafruit_StepperMotor *myStepper1 = AFMStop.getStepper(200, 1);
Adafruit_StepperMotor *myStepper2 = AFMStop.getStepper(200, 2);
void forwardstep1() {
  myStepper1->onestep(FORWARD, DOUBLE);
}
void backwardstep1() {
  myStepper1->onestep(BACKWARD, DOUBLE);
}
void forwardstep2() {
  myStepper2->onestep(FORWARD, DOUBLE);
}
void backwardstep2() {
  myStepper2->onestep(BACKWARD, DOUBLE);
}
AccelStepper stepper1(forwardstep1, backwardstep1);
AccelStepper stepper2(forwardstep2, backwardstep2);

int N2=0; //Motor 2 speed (U/min)
int nz=0;   //number of cycles
int A=0;    //Amplitude (mm)
int Data=0;
float T=1;  //half period
int i=1;
float DN;    //DeltaN (N1 = N2 +/- DN)
float dr=18;  //roller diameter (mm)
double timer=0;
char receivedInt;
boolean newData = false;
int index=0;

void setup()
{
  AFMStop.begin();
  Serial.begin(9600);
  stepper1.setAcceleration(500);
  stepper2.setAcceleration(500);
  Serial.print("Ready \n");
}

void receiveData() {
    char endMarker = '\n';
    char rc;
   
    while (Serial.available() > 0 && newData == false) {
        rc = Serial.read();

        if (rc != endMarker && rc != ',') {
          Data*=10;
          Data = Data+rc-'0';
        }
        else {
          index++;
          if(index==1){
              N2=Data;
              Data=0;
              if(N2==0){DN=0;}
              Serial.print("N2= ");
              Serial.println(N2, DEC);
              if(rc==endMarker){index=0;}
          }
          if(index==2){
            nz=Data;
            Data=0;
            T=450/(nz*N2*3.14159*dr);           
            Serial.print("nz= ");
            Serial.println(nz,DEC);
            Serial.print("T= ");
            Serial.println(T,DEC);
            if(rc==endMarker){index=0;}
          }
          if(index==3){
            A=Data;
            Data=0;
            DN=60*A*nz*N2/450;
            Serial.print("A= ");
            Serial.println(A,DEC);
            Serial.print("DN= ");
            Serial.println(DN,DEC);
            index=0;
          }
          newData = true;
          }
}
}

void NewData() {
    if (newData == true) {
      stepper1.move(400);
      stepper2.move(400);
      timer=millis();
      newData = false;
      timer=0;
      stepper1.setMaxSpeed((N2+i*DN)*200/60);
      stepper2.setMaxSpeed(N2*200/60);
    }
}

void loop(){
  receiveData();
  NewData();
  if(N2>0){
    if(millis()-timer >= T*1000){
      stepper1.move(400);
      stepper2.move(400);
      timer=millis();
      stepper1.setMaxSpeed((N2+i*DN)*200/60);   //N1 = N2 + i*DN
      i=-i;                                     //i is to add or substract DeltaN to N2 to get N1
      }
    if(nz==0 && stepper1.distanceToGo()<= 10){    //if nz=0, I want both motors to turn at the same speed
        stepper1.move(400);
        stepper2.move(400);
      }  
    }
  stepper1.run();
  stepper2.run();
}

EDIT: I tried the example from Adafruit and just modified the setMaxSpeed to 400 to try to reach 120 rpm, but I couldn’t get past 40 rpm…

// Shows how to run three Steppers at once with varying speeds
//
// Requires the Adafruit_Motorshield v2 library 
//   https://github.com/adafruit/Adafruit_Motor_Shield_V2_Library
// And AccelStepper with AFMotor support 
//   https://github.com/adafruit/AccelStepper

// This tutorial is for Adafruit Motorshield v2 only!
// Will not work with v1 shields

#include <Wire.h>
#include <AccelStepper.h>
#include <Adafruit_MotorShield.h>

Adafruit_MotorShield AFMSbot(0x61); // Rightmost jumper closed
Adafruit_MotorShield AFMStop(0x60); // Default address, no jumpers

// Connect two steppers with 200 steps per revolution (1.8 degree)
// to the top shield
Adafruit_StepperMotor *myStepper1 = AFMStop.getStepper(200, 1);
Adafruit_StepperMotor *myStepper2 = AFMStop.getStepper(200, 2);

// Connect one stepper with 200 steps per revolution (1.8 degree)
// to the bottom shield
//Adafruit_StepperMotor *myStepper3 = AFMSbot.getStepper(200, 2);

// you can change these to DOUBLE or INTERLEAVE or MICROSTEP!
// wrappers for the first motor!
void forwardstep1() {  
  myStepper1->onestep(FORWARD, SINGLE);
}
void backwardstep1() {  
  myStepper1->onestep(BACKWARD, SINGLE);
}
// wrappers for the second motor!
void forwardstep2() {  
  myStepper2->onestep(FORWARD, DOUBLE);
}
void backwardstep2() {  
  myStepper2->onestep(BACKWARD, DOUBLE);
}

// Now we'll wrap the 3 steppers in an AccelStepper object
AccelStepper stepper1(forwardstep1, backwardstep1);
AccelStepper stepper2(forwardstep2, backwardstep2);

void setup()
{  
  AFMSbot.begin(); // Start the bottom shield
  AFMStop.begin(); // Start the top shield
   
  stepper1.setMaxSpeed(400);
  stepper1.setAcceleration(1000.0);
  stepper1.move(100000);
    
  stepper2.setMaxSpeed(400);
  stepper2.setAcceleration(1000.0);
  stepper2.move(100000);
}

void loop()
{
    // Change direction at the limits
    if (stepper1.distanceToGo() == 0)
	stepper1.moveTo(-stepper1.currentPosition());

    if (stepper2.distanceToGo() == 0)
	stepper2.moveTo(-stepper2.currentPosition());

    stepper1.run();
    stepper2.run();
}

hesponge: I modified the example 3 in Serial Input Basics because I couldn't find a way to easily extract numbers in decimal,

Don't modify it. The 5th example shows how to parse the data to extract numbers.

...R

Could it be the motor shield that is causing the limitation?

wildbill: Could it be the motor shield that is causing the limitation?

I don't see any other explanation, so I guess...

Could it be that the chips get to hot? I have a fan blowing on them, but they get to hot to be touched when the motors are on.

wildbill:
Could it be the motor shield that is causing the limitation?

That Adafruit shield has brushed DC motor drivers, NOT stepper motor drivers.
You can sort-off get away with that if you use a high impedance stepper motor.
But since you didn’t tell us which motor…

Don’t expect high speed with that motor driver.
Leo…