Question on Best Way to Run a Stepper Motor

I am creating a scanning system where I am using a stepper motor to raise a scanner to an endstop, then lowering the scanner until it measure a certain distance away from an object. I have the code fully working, but am struggling getting the motor to spin faster without stalling.

My setup is a typical 3D printer z-axis. I took an ender 3 z motor and 4 start lead screw and ender 3 frame and I am using an arduino mega to run the z motor and read in an endstop switch at the top of the frame.

I am running the arduino into a TMC2209 motor driver, using STEP and DIR to run the stepper motor. Like I said, everything works fine, but the raising and lowering of the scanner is SLOW. I extracted just the motor control portion of my code to play around and see if I can speed things up. That code is below.

You can see the stepperRPM is set at 720 and this works great and really speeds things up when I hook up the motor wires to a free standing motor, but when I plug in my z axis motor it struggles and sometimes gets into state where the raising, or lowering stutters, like it is skipping steps and the only way to fix is to power everything off for a minute and restart, and it works for a bit, then stutters again.

I bought a higher torque motor, thinking I had to much load on the motor, but it doesn't appear this is the case. What I am trying to raise and lower is much, much lighter than a 3d printer x gantry. I haven't tried the higher torque motor yet, hoping to get some help here.

Do I need to accel/decel? Is there a better motor control library to use than the Basic Stepper Driver Library?

One other question that I have is that when I use the stepper.rotate() function, no matter the number I put in there, like 360 or 720, it doesn't actually rotate the full degrees before running the next line of code, so that is why I have the for loop of 100. Maybe I don't understand the stepper.rotate() function and how it actually works.

Any help would be appreciated. Thanks.

#include "BasicStepperDriver.h"

// Stepper Motor Driver Outputs
#define stepsPerRev 200
#define stepperRPM 720
#define stepperMicrosteps 1
#define stepperMotorDirOut 5
#define stepperMotorStepOut 6
#define stepperMotorEnableOut 7

const int16_t raiseRotationAngle = 360;
const int16_t lowerRotationAngle = -360; 

BasicStepperDriver stepper(stepsPerRev, stepperMotorDirOut, stepperMotorStepOut, stepperMotorEnableOut);

void setup(void) 
{
  Serial.begin(9600);
  stepper.begin(stepperRPM, stepperMicrosteps);
  stepper.setEnableActiveState(LOW);

  // Set motor driver outputs
  pinMode(stepperMotorEnableOut, OUTPUT);
  pinMode(stepperMotorStepOut, OUTPUT);
  pinMode(stepperMotorDirOut, OUTPUT);
}

void loop() 
{
  digitalWrite(stepperMotorEnableOut, HIGH);
  //Serial.println("Start of Loop");
  
  stepper.enable();

  for(int x = 0; x<100; x++)
  {
    stepper.rotate(raiseRotationAngle);
    Serial.print("Rotation Count: ");
    Serial.println(x);
  }

  for(int x = 0; x<100; x++)
  {
    stepper.rotate(lowerRotationAngle);
    Serial.print("Rotation Count: ");
    Serial.println(x);

  }
  
  stepper.disable();
}

The AccelStepper library uses acceleration to achieve higher speeds.

I was reading through the AccelStepper documentation and looking at the examples and was struggling a bit with how to use it. I will have to do more reading as it isn't as straight forward as the BasicStepperDriver library. Thanks for the tip.

I know what you mean. It took me a while to figure it out (as far as I have), too. Best thing is to play with the examples. That helped me. One key thing is to have your loop() function run as fast as possible (NO delays) and call the run function, for each motor, every time through loop().

You can write your own code to control the steppers. There is Robin2's simple stepper code, stepper basics tutorials. And his acceleration code demo. See reply #7.

Thanks for the replies. I recreated my code above using the AccelStepper file (code below), and I think I get it, but when using the runSpeed() it appears that acceleration isn't taken into account per the documentation.

Maybe I should include the full code of what I am trying to do and not just the motor control portion, but the there is a lot of other extraneous code in there that I would rather not share.

Basically, what I am ultimately trying to do with the motor control is that when a button is pressed, I want to run the motor as fast as possible, like 15 RPM up to a limit switch that is being monitored via an interrupt. Once the interrupt is triggered, the motor stops and then starts lowering at 15 RPM until a sensor on my scanner head reads a specific distance from an object. There is a slight delay from stopping the raise to starting the lower.

The raise is pretty straight forward, execute the run() or runSpeed() command until a flag turns true, based off an interrupt triggering.

The lower is more difficult, I need to run the motor, read the distance from a distance measurement sensor, determine if I am close enough or not to the object and repeat lowering the motor until I am close enough to the object and then stop the motor.

Again, I have it working using the BasicStepperDriver.h file, but the higher I set my RPM the more chattering I get in the motor. I am wondering if it is because I am starting from no speed to full speed right off the bat. This is where I was hoping the AccelStepper.h would help, but I am just not getting how to use it.

Here is the code that I used to get the basic AccelStepper motor control working for a constant RPM

#include <AccelStepper.h>

// Stepper Motor Driver Outputs
//#define stepsPerRev 200
//#define stepperRPM 720
//#define stepperMicrosteps 1
#define stepperMotorDirOut 5
#define stepperMotorStepOut 6
//#define stepperMotorEnableOut 7

float maxStepperSpeed = 4000;
uint8_t stepperMotorEnableOut = 7;
float stepperSpeed = 3000;
float stepperAccel = 500;

const int16_t raiseRotationAngle = 360;
const int16_t lowerRotationAngle = -360; 

//BasicStepperDriver stepper(stepsPerRev, stepperMotorDirOut, stepperMotorStepOut, stepperMotorEnableOut);

AccelStepper zStepper(1, stepperMotorStepOut, stepperMotorDirOut);  // (Type:driver, STEP, DIR)

void setup(void) 
{
  Serial.begin(9600);
  
  zStepper.setPinsInverted(false, false, true);
  zStepper.setEnablePin(stepperMotorEnableOut);
  zStepper.setMaxSpeed(maxStepperSpeed);  
  zStepper.setAcceleration(stepperAccel);
}

void loop() 
{
  zStepper.enableOutputs();
  zStepper.setSpeed(stepperSpeed);
  zStepper.run();
}

Here is a version where I tried to run in one direction using a for loop and then run in another direction using a for loop. This didn't work and the motor just buzzed constantly.

#include <AccelStepper.h>

// Stepper Motor Driver Outputs
//#define stepsPerRev 200
//#define stepperRPM 720
//#define stepperMicrosteps 1
#define stepperMotorDirOut 5
#define stepperMotorStepOut 6
//#define stepperMotorEnableOut 7

float maxStepperSpeed = 4000;
uint8_t stepperMotorEnableOut = 7;
float stepperSpeed = 3000;
float stepperAccel = 500;

const int16_t raiseRotationAngle = 360;
const int16_t lowerRotationAngle = -360; 

//BasicStepperDriver stepper(stepsPerRev, stepperMotorDirOut, stepperMotorStepOut, stepperMotorEnableOut);

AccelStepper zStepper(1, stepperMotorStepOut, stepperMotorDirOut);  // (Type:driver, STEP, DIR)

void setup(void) 
{
  Serial.begin(9600);
  
  zStepper.setPinsInverted(false, false, true);
  zStepper.setEnablePin(stepperMotorEnableOut);
  zStepper.setMaxSpeed(maxStepperSpeed);  
  zStepper.setAcceleration(stepperAccel);
}

void loop() 
{
  zStepper.enableOutputs();
  zStepper.setSpeed(stepperSpeed);
  //zStepper.run();
  
  for(int x = 0; x<100; x++)
  {
    zStepper.run();
  }

  zStepper.setSpeed(-stepperSpeed);
  for(int x = 0; x<100; x++)
  {
    zStepper.run();
  }
  
  zStepper.disableOutputs();
}

Do I really need to worry about the acceleration, going from 0 to full 15 RPM or can I just keep using BasicStepperDriver and live with the slight chattering?

Didn't see the supply voltage used, and motor resistance.
For speed/torque you need a high(er) motor voltage, and low-impedance steppers.
24volt seems the limit for that driver.
Leo..

In the AccelStepper library the run() function applies acceleration and the runSpeed() function does not.

...R

The motor supply is 12v, coming from a meanwell 12v 29A 350W power supply, feeding a TMC2209 driver. The motor I am running has specs as follows.

Electrical Specification:
Product type:Bipolar 42 Stepper Motor
Step Angle: 1.8 deg.
Rated Current/phase: 1.5A
Holding Torque:42N.cm (60oz.in)

General Specification:
Step angle accuracy: + - 5%(full step,not load)
Resistance accuracy: + - 10%
Inductance accuracy: + - 20%
Temperature rise: 80deg Max(rated current,2 phase on)
Ambient temperature ----------20deg ~+50deg
Insulation resistance:100M Min,500VDC
Insultion Strength--------500VAC for one minute.

I guess my biggest question is how do I command the motor to go from a stop to the set speed while also attempting to measure a prox sensor. Everything I have read about AccelStepper is you want very little else running in the loop where the run() function is called. So how do you run the stepper yet stop it based off another input occurring where you can't really use an interrupt for the input because you are measuring a distance and not a one time switch input?

Sorry for not understanding the library or how to accomplish this. I do have my program working using BasicStepperDriver, but I get no acceleration from zero to full speed and think this is causing some chattering in my motor.

kgrigio:
Everything I have read about AccelStepper is you want very little else running in the loop where the run() function is called. ]

This is not just a matter for the AccelStepper library.

A stepper motor needs to be commanded to step at appropriate intervals. If those intervals are very short (i.e. a high rate of steps per second) then a 16MHz Arduino may not have time to do other useful things between steps.

How many steps per second does your project require?

...R

What is the prox sensor? What code are you using to use the prox sensor? Does the prox sensor code block? You need to call the run() function for each motor as often as possible and at least as fast as you want to step the motor. What is the highest step per second rate that you need a stepper to run?