Help Coding SparkFun Redboard to Control Stepper Motor

Hi all,

I've been tasked with programming a Nema 23 stepper with a DM542T Driver and a Sparkfun Redboard (Equivalent to an Arduino Uno I believe).

I need one button to spin the motor clockwise when pressed down and stop when the button is not pushed, and another button to spin the motor counter clockwise when pressed down and stop when the button is not pushed.

I was able to get the two buttons to work, but I'm having trouble getting the motor to spin at an exact RPM. I think I need to fix the way my loop is set up to fix this issue, but what do you guys think?

In addition, how would you recommend adding a feature so I can input any desired RPM so the stepper motor will run at that speed? Is there a formula that relates Pulse/Rev and RPM?

Thank you!

// Pin Definitions
const int Dirp = 3;
const int stepPin = 4;
const int GreenPin= 8;
const int RedPin= 9;

// Variables
int GreenState = 0;         // current state of the button
int RedState = 0;           // current state of the button
bool isForward = false;     // Set isForward as False
bool isBackward = false;    // Set isBackward as False

void setup() {
  pinMode(GreenPin, INPUT_PULLUP); // GreenPin is HIGH until button is pushed
  pinMode(RedPin, INPUT_PULLUP);   // RedPin is HIGH until button is pushed
  pinMode(stepPin, OUTPUT);        // Set stepPin as Output
  pinMode(Dirp, OUTPUT);           // Set Dirp as Output
}

void loop() 
{
  isForward = false;
  isBackward = false;

  GreenState = digitalRead(GreenPin);
  RedState = digitalRead(RedPin);

    if(GreenState == LOW)
    {
      digitalWrite(Dirp,HIGH);
      isBackward = true;
      delayMicroseconds(40);
    }
      if(RedState == LOW)
      {
        digitalWrite(Dirp,LOW);
        isForward = true; 
        delayMicroseconds(40);
      }
      while(isForward || isBackward)
      {
        digitalWrite(stepPin,HIGH);
        delayMicroseconds(40);
        digitalWrite(stepPin,LOW);
        delayMicroseconds(40);

        GreenState = digitalRead(GreenPin);
        RedState = digitalRead(RedPin);
        if(GreenState == HIGH || RedState == HIGH)
        {
          isForward = false; // Stop Spinning if Button is not Pressed
          isBackward = false;
        }
      }
}


That works in the church. Knowing is needed but hopefully there's a helper knowing.

Stepper motors are good at making precise moves. For speed control critical tasks DC motors are preferably used.

In the very last line, that delay looks very low. Does the stepper run without buzzing and stopping?

There are libraries that handles speed. Accelstepper is an old guy, not so easy to use and there's a younger one, Moto- something (can't find the name).
Let's hope a knowing helper can fill in the blanks.

1 Like

I think that the library that @Railroader is thinking of is the MobaTools library with a class for steppers. Easier to use and learn than AccelStepper in my opinion. Documentation available on the GitHub page. The library should be installed through the IDE library manager.

Here is a code that, I believe, does what you describe. Push one button for steady clock wise rotation at a set RPM, push the other for a for steady anti-clock wise rotation at a set RPM, push or release both at the same time the stepper will stop. To get accurate RPM, the hardware and software settings must match. That is motor steps/rev and microstepping. Tested on real hardware.

#include <MobaTools.h>

const byte stepPin = 2;
const byte dirPin = 5;
const byte enablePin = 8;
const byte fwdButtonPin = 9;
const byte backButtonPin = 10;


const unsigned int motorStepsPerRev = 200;
const unsigned int microstepMultiplier = 4;
const int STEPS_REVOLUTION = motorStepsPerRev * microstepMultiplier;

MoToStepper stepper( STEPS_REVOLUTION, STEPDIR );

void setup()
{
   Serial.begin(115200);
   pinMode(fwdButtonPin, INPUT_PULLUP);
   pinMode(backButtonPin, INPUT_PULLUP);
   stepper.attach( stepPin, dirPin );
   stepper.setSpeed(1000);  // rpm /10, 1000 = 100 RPM
   stepper.setRampLen(100);
   stepper.setZero();
}

void loop()
{
   bool fwdButtonState = digitalRead(fwdButtonPin);
   bool backButtonState = digitalRead(backButtonPin);

   if (fwdButtonState == LOW && backButtonState == LOW) // both pushed
   {
      stepper.rotate(0);
   }
   else if (fwdButtonState == LOW && backButtonState == HIGH) // fwd pushed
   {
      stepper.rotate(1);
   }
   else if (fwdButtonState == HIGH && backButtonState == LOW) // back pushed
   {
      stepper.rotate(-1);
   }
   else
   {
      stepper.rotate(0);
   }
}
1 Like

Indeed. Spot on. Thanks!

Thank you for the help! This code works really well! I just have a few more questions:

  1. Is microstepMultiplier based on the Stepper Driver? If so, how do I know what to set it as? (If the Pulse/Rev on the driver is 800 and the steps/rev on the motor is 200, is the microstepMultiplier = 4?)

  2. Can the pins be set to 4 3 5 8 9 instead of 2 5 8 9 10? I changed it to 4 3 5 8 9 but wanted to make sure this doesn't somehow cause issues? (Super beginner question lol)

Thanks again!

Yes. You set the microstepping on the driver with dip switches according to this table. With your driver, motorStepsPerRev = 200 and microstepMultiplier = Pulses/rev (from the table) / motorStepsPerRev . But that is not really important.

image

Your driver sets multistepping differently from the drivers that I use. With my drivers, I need to calculate the value for steps\rev, but your driver tells you that number from the table.

Of course. Set them however that you want or need. Just avoid using pins 0 or 1 since those pins are the hardware serial used for programs upload. The pins that I used are because I have a CNC shield and that dictates which pins are used for the motor step and dir terminals on the drivers.

It is recommended that one use at least about 4x microstepping (800 Pulses/rev) to mitigate resonance effects.

Thanks again! Is there a Pulse/Rev setting that works best with the stepper.setspeed() command? I noticed different speeds when changing the Pulse/Rev setting on the Driver/code.

It is indeed the equivalent of an Uno; main difference is that it uses a FTDI chip for the USB instead of the 16U2.

The one in the image looks a lot cleaner than mine :rofl:

1 Like

I am not sure that I understand the question. The setSpeed() funcion should work fine up to the maximum allowed speed. The maximum speed depends on the library (AccelStepper, 4000 steps/second), the motor power supply (higher voltage allows higher speed) and other, lessor, factors.

AccelStepper uses steps/second as the speed unit. So, yes, at the same steps/sec and different Pulse/rev settings the visible speed will be different. At 200 Pulse/rev and 200 steps/sec there will be 1 rev per second (60RPM). At 800 Pulse/rev and 200 steps/sec there will be 1/4 rev per second (15RPM).

Fine You can confirm that. I wouldn't know and can't give any promises.

Howdy! I realized that holding the button down is hard on the fingers.

Is there a way to change the loop section of the code so that pressing one button starts clockwise movement and pressing the same button again ends clockwise movement? And so that pressing the other button starts counter-clockwise movement and pressing the same button again ends counter-clockwise movement?

Thank you!

Which code ?

And for what you want to achieve, read up on the state change detection.

This Code:

Here is a demo to do that. It uses the state change detection like shown in my state change detection tutorial.. Tested on real hardware.

#include <MobaTools.h>

const byte stepPin = 2;
const byte dirPin = 5;
const byte enablePin = 8;
const byte fwdButtonPin = 9;
const byte backButtonPin = 10;


const unsigned int motorStepsPerRev = 200;
const unsigned int microstepMultiplier = 4;
const int STEPS_REVOLUTION = motorStepsPerRev * microstepMultiplier;

MoToStepper stepper( STEPS_REVOLUTION, STEPDIR );

void setup()
{
   Serial.begin(115200);
   pinMode(fwdButtonPin, INPUT_PULLUP);
   pinMode(backButtonPin, INPUT_PULLUP);
   stepper.attach( stepPin, dirPin );
   stepper.setSpeed(1000);  // rpm /10, 1000 = 100 RPM
   stepper.setRampLen(100);
   stepper.setZero();
}

void loop()
{
   static bool lastFwdButtonState = HIGH;
   static bool lastBackButtonState = HIGH;
   static bool fwdMode = 0;
   static bool backMode = 0;

   static unsigned long timer = 0;
   unsigned long interval = 50; // check 20 times per second
   if (millis() - timer >= interval)
   {
      timer = millis();

      bool fwdButtonState = digitalRead(fwdButtonPin);
      bool backButtonState = digitalRead(backButtonPin);

      if (fwdButtonState != lastFwdButtonState)
      {
         if (fwdButtonState == LOW)
         {
            fwdMode = !fwdMode; // toggle mode
            if (fwdMode == 1)
            {
               stepper.rotate(1);
            }
            else
            {
               stepper.rotate(0);
            }
         }
         lastFwdButtonState = fwdButtonState;
      }

      if (backButtonState != lastBackButtonState)
      {
         if (backButtonState == LOW)
         {
            backMode = !backMode; // toggle mode
            if (backMode == 1)
            {
               stepper.rotate(-1);
            }
            else
            {
               stepper.rotate(0);
            }
         }
         lastBackButtonState = backButtonState;
      }
   }
}

There is no provision for the case if both buttons are pressed. Whichever switch makes contact first will determine the outcome.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.