Problem with Nema EasyDriver

Hi,

I have a problem with a stepper motor.
This motor is controlled via EasyDriver and encoder.
The encoder also functions as a button (by pressing the button the motor returns to the starting point).
Example:
I turn the encoder to the left, the engine has problems and it turns badly. jerky.
i turn the encoder to the right, the engine runs very well.
I press the encoder to return the engine (which has made many turns to the right) to the starting point, the engine turns to the left very well.

// EasyDriver connections
#define step_pin 9  // Pin 9 connected to Steps pin on EasyDriver
#define dir_pin 8   // Pin 8 connected to Direction pin
#define MS1 10       // Pin 10 connected to MS1 pin
#define MS2 11      // Pin 11 connected to MS2 pin
#define SLEEP 12     // Pin 12 connected to SLEEP pin
                    
volatile boolean TurnDetected;  // need volatile for Interrupts
volatile boolean rotationdirection;  // CW or CCW rotation

// Rotary Encoder Module connections
const int PinCLK=2;   // Generating interrupts using CLK signal
const int PinDT=3;    // Reading DT signal
const int PinSW=4;    // Reading Push Button switch

int StepperPosition=0;    // To store Stepper Motor Position
int StepsToTake=4;      // Controls the speed of the Stepper per Rotary click

int direction;   // Variable to set Rotation (CW-CCW) of stepper


// Interrupt routine runs if CLK goes from HIGH to LOW
void rotarydetect ()  {
delay(4);  // delay for Debouncing
if (digitalRead(PinCLK))
rotationdirection= digitalRead(PinDT);
else
rotationdirection= !digitalRead(PinDT);
TurnDetected = true;
}


void setup ()  {

   pinMode(MS1, OUTPUT);
   pinMode(MS2, OUTPUT);
   pinMode(dir_pin, OUTPUT);
   pinMode(step_pin, OUTPUT);
   pinMode(SLEEP, OUTPUT);   
   digitalWrite(SLEEP, HIGH);  // Wake up EasyDriver
   delay(5);  // Wait for EasyDriver wake up
   
 /* Configure type of Steps on EasyDriver:
 // MS1 MS2
 //
 // LOW LOW = Full Step //
 // HIGH LOW = Half Step //
 // LOW HIGH = A quarter of Step //
 // HIGH HIGH = An eighth of Step //
 */ 
   digitalWrite(MS1, LOW);      // Configures to Full Steps
   digitalWrite(MS2, LOW);    // Configures to Full Steps
   
  pinMode(PinCLK,INPUT);  // Set Pin to Input
  pinMode(PinDT,INPUT);  
  pinMode(PinSW,INPUT);
  digitalWrite(PinSW, HIGH); // Pull-Up resistor for switch
  attachInterrupt (0,rotarydetect,FALLING); // interrupt 0 always connected to pin 2 on Arduino UNO
}


void loop ()  {

  if (!(digitalRead(PinSW))) {   // check if button is pressed
  if (StepperPosition == 0) {  // check if button was already pressed
  } else {
      if (StepperPosition > 0) {  // Stepper was moved CW
        while (StepperPosition != 0){  //  Do until Motor position is back to ZERO
          digitalWrite(dir_pin, HIGH);  // (HIGH = anti-clockwise / LOW = clockwise)
          for (int x = 1; x < StepsToTake; x++) {
              digitalWrite(step_pin, HIGH);
              delay(1);
              digitalWrite(step_pin, LOW);
              delay(1);            
            }
            StepperPosition=StepperPosition-StepsToTake;
        }
      }
      else {
        while (StepperPosition != 0){ 
          digitalWrite(dir_pin, LOW);  // (HIGH = anti-clockwise / LOW = clockwise)
              for (int x = 1; x < StepsToTake; x++) {
              digitalWrite(step_pin, HIGH);
              delay(1);
              digitalWrite(step_pin, LOW);
              delay(1);            
            }
           StepperPosition=StepperPosition+StepsToTake;
        }
      }
      StepperPosition=0; // Reset position to ZERO after moving motor back
    }
  }

// Runs if rotation was detected
  if (TurnDetected)  {
        TurnDetected = false;  // do NOT repeat IF loop until new rotation detected

// Which direction to move Stepper motor
        if (rotationdirection) { // Move motor CCW
            digitalWrite(dir_pin, HIGH);  // (HIGH = anti-clockwise / LOW = clockwise)
            for (int x = 1; x < StepsToTake; x++) {
              digitalWrite(step_pin, HIGH);
              delay(1);
              digitalWrite(step_pin, LOW);
              delay(1);            
            }
            StepperPosition=StepperPosition-StepsToTake;
        }

        if (!rotationdirection) { // Move motor CW
            digitalWrite(dir_pin, LOW);  // (HIGH = anti-clockwise / LOW = clockwise)
            for (int x = 1; x < StepsToTake; x++) {
              digitalWrite(step_pin, HIGH);
              delay(1);
              digitalWrite(step_pin, LOW); 
              delay(1);         
            }
            StepperPosition=StepperPosition+StepsToTake;
        }
  }
}

I don’t know what the problem is but a couple of things occur to me.

First, you seem to have this code repeated 4 times. That’s a sure sign that you should put it in a function so there only needs to be one copy. Having 4 copies leaves open the possibility that they are not all the same and it can be hard to spot the differences.

          digitalWrite(dir_pin, HIGH);  // (HIGH = anti-clockwise / LOW = clockwise)
            for (int x = 1; x < StepsToTake; x++) {
                digitalWrite(step_pin, HIGH);
                delay(1);
                digitalWrite(step_pin, LOW);
                delay(1);            
            }
            StepperPosition=StepperPosition-StepsToTake;

The comment here is wrong

int StepsToTake=4;      // Controls the speed of the Stepper per Rotary click

That defines how far the motor moves. The speed is set by the delay()s in the previous snippet

I would not use either the WHILE or the FOR in this

              while (StepperPosition != 0){ 
                    digitalWrite(dir_pin, LOW);  // (HIGH = anti-clockwise / LOW = clockwise)
                    for (int x = 1; x < StepsToTake; x++) {

Instead I would use a variable to keep track of the position and allow loop() to do the repetition.

What happens if you slow down the motor - like this, for example

digitalWrite(step_pin, HIGH);
delayMicroseconds(10);         // plenty long enough for a pulse
digitalWrite(step_pin, LOW);
delay(20);                    // use this one to vary the interval between steps (the speed)

Have a look at the second example in this Simple Stepper Code - it does not use delay() for the timing.

Have you correctly set the current limit on the driver to match the current limit of the motor?

…R
Stepper Motor Basics

Have you run the encoder separately from the stepper, and confirmed that the output is as expected?

pinMode(PinCLK,INPUT);  // Set Pin to Input
  pinMode(PinDT,INPUT);  
  pinMode(PinSW,INPUT);
  digitalWrite(PinSW, HIGH); // Pull-Up resistor for switch
  attachInterrupt (0,rotarydetect,FALLING);

Are there pullups on the encoder module for PinCLK and PinDT?

void rotarydetect ()  {
delay(4);  // delay for Debouncing
if (digitalRead(PinCLK))
rotationdirection= digitalRead(PinDT);
else
rotationdirection= !digitalRead(PinDT);
TurnDetected = true;
}

delay() will not function inside of an ISR. It requires interrupts which are disabled within the ISR. If your encoder requires debouncing you will need to use hardware debounce, or an ISR with some response lockout.

For an encoder turned by hand, polling is usually sufficient, and software debounce can be implemented.

Encoders never need debouncing since they will auto-correct.

Quadrature encoders only allow one channel to change at a time, so bouncing
is equivalent to a single count oscillation, which is something you have to allow for anyway (if the
encoder happens to sit right on the boundary position).

00  <->  01
/|\      /|\
 |        |
\|/      \|/
10  <->  11

Bouncing only oscillates a single transition in the transition diagram, it doesn’t take you round the
loop and miscount turns.

Attempting to be clever about ignoring transitions you think are bounces makes the code much more
complex and likely to actually be wrong.

Encoders never need debouncing since they will auto-correct.

The OP had an interrupt on one pin on one transition. I do not believe that arrangement will be autocorrecting.

For example
Interrupt pin falls, and other pin is on position for +1.
Interrupt pin rises on a bounce, but nothing happens to the count because the interrupt is not triggered
Interrupt pin falls again to final position count, +1 again.

cattledog:
The OP had an interrupt on one pin on one transition. I do not believe that arrangement will be autocorrecting.

No, but its not the way to read a quadrature encoder, you must take account of every transition on one
or both pins. ie use CHANGE, not RISING or FALLING.