NEMA 23 stepper motor seamingly not rotating the correct number of steps

Hello all,

So I have a code I borrowed from the DroneBot Workshop youtube page. Its a simple stepper motor driving code orignaly meant for the 28-byj-48 unipolar stepper motor and its uln2003 driver. I changed it to work for a bipolar NEMA 23 stepper motor along with an industrial stepper motor driver (the kl-4030). The code below basicaly says move 200 steps, delay, then move 200 steps in the other direction. This stepper motor has 200 steps per revolution meaning that this code in theory would turn the stepper motor one full rotation and then go again in the other direction. However The stepper motor doesnt turn a full rotation at coded 200 steps, it does what seems to be a full rotation at coded 800 steps. The driver is set to full step mode and 3 amps. Furthermore, when setting the driver's dipswithes to half step mode, it takes 1600 steps to do a ful rotation. The 1600 to 800 change makes sense, but at full step mode these stpper motors are supposed to be 200 steps! not 800. Shouldnt full steps set in the dipswitches mean that when the code says go 200 steps the stepper motor turns one full rotation? Any thoughts?

/*
  Stepper Motor Demonstration 1
  Stepper-Demo1.ino
  Demonstrates 28BYJ-48 Unipolar Stepper with ULN2003 Driver
  Uses Arduino Stepper Library

  DroneBot Workshop 2018
  https://dronebotworkshop.com
*/

//Include the Arduino Stepper Library
#include <Stepper.h>

// Define Constants

// Number of steps per internal motor revolution 
const float STEPS_PER_REV = 200; 

//  Amount of Gear Reduction
const float GEAR_RED = 1;

// Number of steps per geared output rotation
const float STEPS_PER_OUT_REV = STEPS_PER_REV * GEAR_RED;

// Define Variables

// Number of Steps Required
int StepsRequired;

// Create Instance of Stepper Class
// Specify Pins used for motor coils
// The pins used are 8,9,10,11 
// Connected to ULN2003 Motor Driver In1, In2, In3, In4 
// Pins entered in sequence 1-3-2-4 for proper step sequencing

Stepper steppermotor(STEPS_PER_REV, 8, 9);

void setup()
{
// Nothing  (Stepper Library sets pins as outputs)
}

void loop()
{

  StepsRequired  =  STEPS_PER_OUT_REV; 
  steppermotor.setSpeed(100);   
  steppermotor.step(StepsRequired);
  delay(500);
  
  StepsRequired  =  STEPS_PER_OUT_REV; 
  steppermotor.setSpeed(100);   
  steppermotor.step(-StepsRequired);
  delay(500);
}

What happens if you use a much lower motor speed?

Post a link to the datasheet for your stepper driver.

...R
Stepper Motor Basics
Simple Stepper Code

The Stepper Library is intended for driving the coils of the stepper driver like your 28-byj-48 unipolar which require a "pattern" to work.

It is not intended for driving Step/Dir stepper drives. It works but at 1/4th the # of steps. I have done this also!

Read the links in Robin2 reply.

justone:
It is not intended for driving Step/Dir stepper drives.

I have not studied the code but the current documentation suggests that it now has an option for step and direction drivers.

However the AccelStepper library is a great deal more competent and flexible. And it is easy to make a step and direction driver work without any library

...R

This link brings you to the page that will give you the stepper motors information, located at the bottom of the page. According to its torque sheet I will eventually run it in half step mode at about 175 rpm.

This link brings you to the page that has the spec sheet for the kl-4030 stepper motor driver, located at the bottom of the page.

https://www.automationtechnologiesinc.com/products-page/kl-stepper-drivers/kl-4030driver/

I have also been experimenting with the speed the motor is set to. My understanding is that I currently have it set to 100 rpm. When changing the speed nothing else changes but the speed (and also if the speed is way high then the motor kind of just gives out, which is about what I expected to happen anyways) but the rotation amount is the same.

I will however begin learning the accel library and see what that might help.

That seems to be a very ordinary driver that just takes the usual step and direction inputs. The simple code in the link I gave you should be good for testing. It does not use any library.

...R

Robin2:
I have not studied the code but the current documentation suggests that it now has an option for step and direction drivers.

...R

Got a link to this current documentation that shows this option?

Maybe a simple program to show that this works with

a very ordinary driver that just takes the usual step and direction inputs

would help to clear things up.

justone:
Got a link to this current documentation that shows this option?

It all seems to be printed on the top of the driver enclosure

Maybe a simple program to show that this works with would help to clear things up.

That is the purpose of the link I already gave you - did you not study it carefully?

...R

Robin2:
It all seems to be printed on the top of the driver enclosure

That is the purpose of the link I already gave you - did you not study it carefully?

...R

Robin2 I see your posts and comments everywhere and you always crack me up.

Robin2:
That seems to be a very ordinary driver that just takes the usual step and direction inputs. The simple code in the link I gave you should be good for testing. It does not use any library.

...R

Your code worked well and defeated the 800 steps in a 200 step issue, I now realize I should have searched for if anyone had a simmilar problem to me and I would have found that post so thank you for the reply.

My next plan of attack is getting this nema 23 bipolar stepper motor and its kl-4030 stepper driver to follow a rotary encoder. Wish me luck.

Actually, "control a bipolar stepper motor with industrial driver with a rotary encoder" code is something I've been working on for a while. Which is why I just got it finished, not long after posting that last comment lol.

I only asked about the basic movement first as I continued up the chain to more difficult coding.

I see myself posting this in some thread later as I continue to test more with it and later also draw up a system block diagram of the wiring and such but thanks to you @Robin2 and other people on the internet I have finally come up with a usefull code, attatched below. let me know what you think!

// This code was compiled and tested by me, Joseph Fry / fryj1992 on the Arduino Forums
// I manipulated some small areas of the code but this code came from several sources listed below
// The main body of code came from ZHut Arduino tutorials - http://thezhut.com/?page_id=22
// A secondary portion of the code came from user Robin2 on the Arduino Forums
// Lastly, the setdir boolean understandng came from DroneBot Workshop on Youtube https://www.youtube.com/watch?v=iY_4YOlpqyI&list=PLYGPFpmz792l7OSxR50Q0uKe8ilSZzj5O&index=4

// For using an optical incremental rotary encoder to controll a 200 step bipolar stepper motor
// through a KL-4030 stepper driver with an arduino uno micro controller 

// Per its specs, on the KL-4030 do not use the enable pins. Connect Pulse+ and Direction+ to a common
// 5volt from the uno board. Connect the A+, A-, B+, B- pins from the motor to the driver according to
// the motor specs. Connect the driver to an external power source per the driver and motor specs. Connect
// the rotary encoder VCC and ground to the uno board per its specs. Connect the rest of the pins to the 
// arduino board as detailed below... 


const int encoderPinA = 2;   // encoder wire A
const int encoderPinB = 3;   // encoder wire B
int pulPin = 8; // the pulse- pin from the driver (- as detailed in the driver specs)
int dirPin = 9; // the direction- pin from the driver (- as detailed in the driver specs)
volatile int encoderPos = 0;    // counter
unsigned int lastReportedPos = 1;   // change
static boolean rotating = false;    // debounce
boolean A_set = false;
boolean B_set = false;
int pulseWidthMicros = 20;  // currently a "find whats right" variable for me...
int millisbetweenSteps = 2; // milliseconds between each step, kept low for 1 to 1 ease with the rotary encoder
boolean setdir = LOW; // Change this between HIGH & LOW to switch between Clockwise & Counter Clockwise rotations
int s=1; // Change this number to the amount of steps your stepper motor should take for every pulse of the rotary encoder - 
// - (due to the introduction of a rotary encoder through this code, this variable might not be a correct ratio - 
// - and instead be a number you have to eyeball and adjust)


void setup() {
pinMode(encoderPinA, INPUT_PULLUP);
pinMode(encoderPinB, INPUT_PULLUP);
pinMode(dirPin, OUTPUT);
pinMode(pulPin, OUTPUT);
attachInterrupt(0, doEncoderA, CHANGE); // an intterupt for the rotary encoder wire A - pin 2
attachInterrupt(1, doEncoderB, CHANGE); // an intterupt for the rotary encoder wire B - pin 3

}

void doEncoderA() {
// debounce
if ( rotating );  // wait a little until the bouncing is done
// Test transition
if ( digitalRead(encoderPinA) != A_set ) { // debounce once more
A_set = !A_set;
// adjust counter + if A leads B
if ( A_set && !B_set )
encoderPos = s; 
setdir = !setdir;
rotating = false;  // no more debouncing until loop() hits again
}
}

// Interrupt on B changing state
void doEncoderB() {
if ( rotating );
if ( digitalRead(encoderPinB) != B_set ) {
B_set = !B_set;
//  adjust counter – 1 if B leads A
if ( B_set && !A_set )
encoderPos = s;
rotating = false;
}
}

void loop() {
rotating = true;  // reset the debouncer

if (lastReportedPos != encoderPos) {
lastReportedPos = encoderPos;                                                       
  
  digitalWrite(dirPin, setdir);
   
  for(int n = 0; n < encoderPos; n++) {
    digitalWrite(pulPin, HIGH);
    delayMicroseconds(pulseWidthMicros);
    digitalWrite(pulPin, LOW);
    
    delay(millisbetweenSteps);
  }

encoderPos = 0;
}
}

I'm not good at reviewing code without a specific problem to be resolved so I will just make a couple of comments about style.

Always use the AutoFormat tool to indent code so it is easy to see where parts begin and end. For example I think this

void doEncoderB() {
if ( rotating );
if ( digitalRead(encoderPinB) != B_set ) {
B_set = !B_set;
//  adjust counter - 1 if B leads A
if ( B_set && !A_set )
encoderPos = s;
rotating = false;
}
}

should be like this - but it's not 100% clear

void doEncoderB() {
    if ( rotating ){}
    if ( digitalRead(encoderPinB) != B_set ) {
        B_set = !B_set;
        //  adjust counter - 1 if B leads A
        if ( B_set && !A_set ) {
            encoderPos = s;
            rotating = false;
        }
    }
}

Also note that I have used {} braces with all the IFs

Don't use single letter variable names except as the index in a FOR loop

int s=1; // Change this number to the amount of steps your stepper motor

because they are impossible to find with search or search and replace.

Always use meaningful variable names such as numberOfMotorSteps. Not only will the code be easier to read but you won't need comments to explain things.

...R