Ardiuno UNO and a4983 with regulator and stepper motor

I think this is another case of your getting ahead of yourself. How can you consider micro-stepping “ideal” before you actually know what it is? Micro-stepping basically gives your stepper motor more steps per revolution. It is not a generally effective way of controlling stepping speed. Changing the micro-stepping resolution requires use of the MS1, MS2, and MS3 pins; you can either directly tie them to the appropriate voltages for the resolution you want, or you can connect them to I/O lines on your Arduino and control them dynamically from your program. I think you should stay away from micro-stepping right now because it will needlessly complicate things.

While your stepper test code might work “perfectly”, I suspect you still do not understand it. Given that there is likely not a prewritten program out there that does what you want, you really should take the time to figure out what you’re doing so that you can develop the skills to come up with a custom solution. For example, do you understand what part of your test program sets the stepping speed? Can you change it to make your stepper motor turn at half the speed? Can you change it so that your stepper motor turns at 10 RPM? If not, these are the kinds of questions you should be asking us at this point.

Also, when you post code, please surround it with [ code ][ /code ] tags (minus the spaces). You can type them directly, or you can get them by pressing the “Code” button above the post textbox.

- Ben

Hi Ben, i will work on things more here.

BTW, I know Micro Stepping is Ideal as this is a Camera Track that I am building, and I need lateral movement to as smooth as possible.

What i was getting at was, that smooth stepping is more important than a speed variant.

I will work on a sketch for adjust speed / rpm and steps and get back to.

SO here is my current Sketch

#define stepPin 7
#define dirPin 6
#define enablePin 5
void setup()
{
  // We set the enable pin to be an output
  pinMode(enablePin, OUTPUT);
  // then we set it HIGH so that the board is disabled until we
  // get into a known state.
  digitalWrite(enablePin, HIGH);
  Serial.begin(9600);
  Serial.println("Starting stepper exerciser.");
  pinMode(stepPin, OUTPUT);
  pinMode(dirPin, OUTPUT);
}
void loop()
{
  int j;
  // set the enablePin low so that we can now use our stepper driver.
  digitalWrite(enablePin, LOW);
  // wait a few microseconds for the enable to take effect
  // (That isn't in the spec sheet I just added it for sanity.)
  delayMicroseconds(2);
  // we set the direction pin in an arbitrary direction.
  digitalWrite(dirPin, HIGH);
  for(j=0; j<=10000; j++) {
    digitalWrite(stepPin, LOW);
    delayMicroseconds(2);
    digitalWrite(stepPin, HIGH);
    delayMicroseconds(1000);
  }
}

With the above, does the motor run based on the current from the power source? and do is 200 steps?
Ive been pondering on how to set the speed with setSpeed(number) and steps with step(number)
Once I can figure that out, I can set the setSpeed and step as variables that the POT can change - correct?

Yes, your motor is being powered by the VMOT power source. I don’t understand your question about “do is 200 steps”.

You are still getting ahead of yourself by planning out what you will name your future functions. My question is very simple: do you understand how the program you just posted actually works? If not, please take the time to ask questions until you do. For example, can you look at the code and tell me what part is determining the motor speed right now? Could you tell me from just the code what that speed is? Can you edit your code by changing one line to make the stepper motor turn twice as slowly or at a known speed, like 10 RPM?

In short, take things a bit slower and try to understand and learn as you go. One way to do that is to ask specific questions about things you find confusing. Another is tweak small segments of your working code to observe how the change in code affects the program’s behavior.

- Ben

Its my nature - thanks for forcing me to take things slower Ben :slight_smile:
Lets forget about the POT for now, and work on simply tweaking the Sketch so that I can declare RMP and step variables to change later with the POT.

Is the Action Scripter in me - I keep forgetting that I can actually breaks things with this project.

Here are my questions for the script I am using right now.

  • 1: I have 4 wires from the Motor to the dirver board, yet I am only sending signals from 3 on the Arduino - why?
  • 2: I understand the concept of setSpeed(#) and steps(#), but in the Sketch i’m not quite sure how to define those values without a function
  • 3: I understand the digitalWrite - LOW vs HIGH is on and off to the coils with the delays between them, the only way I have been able to adjust the speed is to change the delays between - hence the setSpeed(#) and Steps(#) question number 2.

Here is the Sketch that you suggested I start with.

#define stepPin 7
#define dirPin 6
#define enablePin 5
void setup()
{
  // We set the enable pin to be an output
  pinMode(enablePin, OUTPUT);
  // then we set it HIGH so that the board is disabled until we
  // get into a known state.
  digitalWrite(enablePin, HIGH);
  Serial.begin(9600);
  Serial.println("Starting stepper exerciser.");
  pinMode(stepPin, OUTPUT);
  pinMode(dirPin, OUTPUT);
}
void loop()
{
  int j;
  // set the enablePin low so that we can now use our stepper driver.
  digitalWrite(enablePin, LOW);
  // wait a few microseconds for the enable to take effect
  // (That isn't in the spec sheet I just added it for sanity.)
  delayMicroseconds(2);
  // we set the direction pin in an arbitrary direction.
  digitalWrite(dirPin, HIGH);
  for(j=0; j<=10000; j++) {
    digitalWrite(stepPin, LOW);
    delayMicroseconds(2);
    digitalWrite(stepPin, HIGH);
    delayMicroseconds(1000);
  }
}

And here is the Sketch I am working on - Am i going in the right direction?

#define stepPin 7
#define dirPin 6
#define enablePin 5
#define STEPS 200

// Set the Variables here to be changed by the Potentiometer later
int myRPM = 10;  // RPM Var
int mySteps = 200; // Step Var

{
  // We set the enable pin to be an output
  pinMode(enablePin, OUTPUT);
  // then we set it HIGH so that the board is disabled until we
  // get into a known state.
  digitalWrite(enablePin, HIGH);
  Serial.begin(9600);
  Serial.println("Starting stepper exerciser.");
  pinMode(stepPin, OUTPUT);
  pinMode(dirPin, OUTPUT);
}
void loop()
{
  myRPM.setSpeed(50);
  mySteps.step(500); // 500 steps
  Serial.println(myRPM); // show me the RPM in the Serial Monitor
  Serial.println(mySteps); // show me the step count in the Serial Monitor
}
  1. This requires you understand how a stepper motor actually works. The stepper motor is comprised of two coils, and energizing these coils in a specific sequence causes the motor to step in small increments. The A4988 IC takes care of all this for you in response to a simpler input: direction and step. Every time you send a pulse to the STEP pin, the A4988 appropriately changes the way the coils are energized (based on the state of the DIR input) to take another step.

  2. I think the problem is that the “concept” of setSpeed() and steps() is so high-level right now as to not be meaningful (for example, understanding the concept of flight does not necessarily help me design a plane), and in a practical sense you don’t yet understand how to control the stepper motor speed or the number of steps it takes. Ultimately, you might want to use functions for this, but first let’s just work on changing speed or number of steps by making very small, hard-coded modifications to your program.

  3. Yes, you can control the speed by adjusting the delays between pulses to the step pin. So now put this in practice!

Your new sketch is not going in any meaningfully new direction yet because it doesn’t implement any of the low-level details, and right now I’m trying to help you understand the low-level part of this (also, what you’ve written is not valid C++ code and will not compile).

For now, forget about making new functions and focus on the very specific questions I’ve asked in my last two posts to you. If it helps, you can consider them a homework assignment:

  1. Please look at the starting sketch you just posted and tell me from the code alone how quickly it will make the stepper motor turn and how many steps the stepper motor will take. If you cannot do this, you do not yet understand the program enough to modify it the way you want.

  2. Modify a single line of the program to decrease the stepper motor speed by a factor of two.

  3. Modify a single line of the program to make the stepper motor turn at 60 RPM.

Once you can do the above, you should have the tools to understand how to make your arbitrary speed function. If you need help, please ask.

- Ben

Heheh ok Ben, thanks - back to school here.

Once again, I appreaciate your help.
I hope at your end, that you have a good grasp on the project and its eventual use - do you?

Homework Results

A: The for statement is saying - if J = 0 and less than 10000 steps then run - so if left to run, the motor will do 10000 steps - right?
The speed is determined by the delays, so with a 1000 microsecond delay would that be a 10th of second between power on, or each step? Im not sure how to calcutate the math on this, is it something like - delay High time / 200 (200 being the steps the motor does in one revolution)

A: High delay / 2 - so

    digitalWrite(stepPin, LOW);
    delayMicroseconds(4);
    digitalWrite(stepPin, HIGH);
    delayMicroseconds(2000);

How am I doing here Ben?

This was somewhat of a trick question. You are correct that the for-loop produces 10000 steps, but that’s not the entire story. You have the for-loop inside a special function called loop(), which the Arduino runs over and over again. Specifically, program flow on the Arduino looks like this:

setup();
while (1)  // loop forever
  loop();

So what your program actually does is 10000 steps followed immediately by 10000 more steps, followed immediately by 10000 more steps, etc. Effectively, it will continue stepping endlessly until you disconnect power. It sounds like this is not the ultimate behavior you want, and there are a few workarounds:

  1. Move all of your code to setup() and leave loop() empty. As you can see by what I wrote above, the Arduino only runs setup() once.

  2. Have the execution of the for-loop be based conditionally on some external event. You can simulate this initially with a variable:

unsigned char takeSteps = 1;  // global variable

void loop()
{
  int j;
  digitalWrite(enablePin, LOW);  // enable driver
  delayMicroseconds(2);
  digitalWrite(dirPin, HIGH);  // set step direction

  if (takeSteps)
  {
    takeSteps = 0;
    for(j=0; j<=10000; j++)
    {
      digitalWrite(stepPin, LOW);
      delayMicroseconds(2);
      digitalWrite(stepPin, HIGH);
      delayMicroseconds(1000);
    }
  }
}

So the next thing you should do is take this out of the realm of theory and test it. Reduce the number of steps to something much smaller, like 500, and see what happens when you run the code the way you have it vs making one of the two changes I suggest above. Does it run forever in the former case and stop after approximately half a second in the later case?

It is delaying for 1000 microseconds between each step pulse, and each step pulse triggers a physical step of the stepper motor. Note that 1000 microseconds is equal to 1 millisecond, which is 1/1000th of a second (I’m not sure where your “10th of a second” is coming from). So basically, what it boils down to is that your stepper motor is stepping at 1000 steps per second (or 1 kHz), which is equivalent to

1000 steps/s / 200 steps/rev = 5 rev/s

And if it’s making 5 revolutions per second, it is making 60*5 = 300 revolutions per minute (a.k.a. RPM). If you run your code, do you see the stepper motor making approximately 5 full rotations per second?

If you have a target RPM, you can reverse the math to compute the delay time (in microseconds) as follows:

delay_us = 60,000,000 / (RPM * (steps/rev))

If your stepper motor is 200 steps per revolution, this reduces to:

delay_us = 300,000 / RPM

NOTE: The delayMicroseconds() function cannot take arguments larger than 65,535. If you want to achieve speeds slower than 4.5 RPM, you should instead use the delay() function, which takes an arguments in units of milliseconds instead of microseconds. When delaying in units of milliseconds, your equation changes to:

delay_ms = 300 / RPM

That’s right, except you don’t really need to double the low delay time. For the most part, you can consider the low time to be negligible and just leave it as a fixed 2 us delay that is always much smaller than the high delay time. Also, your text description of “high delay / 2” does not match what you did and is not correct. Notice that you doubled the delay time, you didn’t halve it. Making the delay longer makes the stepper motor move more slowly; the two parameters are inversely related.

- Ben

1 and 2 combined sketch below - looks like I am getting about fast 50 revolutions and the it stops.
SO it that sketch basically running the loop once now?
Can you explain to me again, why we have to define the delays and for statement twice? One time in the setup and once in the loop.

  1. I reduced the steps from 10000 to 500, and yes it ran for about a second and then stopped - so doing this will ultimately give the duration timing i am looking for right?
#define stepPin 7
#define dirPin 6
#define enablePin 5

void setup()
{
  // We set the enable pin to be an output
  pinMode(enablePin, OUTPUT);
  // then we set it HIGH so that the board is disabled until we
  // get into a known state.
  digitalWrite(enablePin, HIGH);
  Serial.begin(9600);
  Serial.println("Starting stepper exerciser.");
  pinMode(stepPin, OUTPUT);
  pinMode(dirPin, OUTPUT);
  
    int j;
  // set the enablePin low so that we can now use our stepper driver.
  digitalWrite(enablePin, LOW);
  // wait a few microseconds for the enable to take effect
  // (That isn't in the spec sheet I just added it for sanity.)
  delayMicroseconds(2);
  // we set the direction pin in an arbitrary direction.
  digitalWrite(dirPin, HIGH);
  for(j=0; j<=10000; j++) {
    digitalWrite(stepPin, LOW);
    delayMicroseconds(2);
    digitalWrite(stepPin, HIGH);
    delayMicroseconds(1000);
  }
}


//Have the execution of the for-loop be based conditionally on some external event
unsigned char takeSteps = 1;  // global variable

void loop()
{
  int j;
  digitalWrite(enablePin, LOW);  // enable driver
  delayMicroseconds(2);
  digitalWrite(dirPin, HIGH);  // set step direction

  if (takeSteps)
  {
    takeSteps = 0;
    for(j=0; j<=10000; j++)
    {
      digitalWrite(stepPin, LOW);
      delayMicroseconds(2);
      digitalWrite(stepPin, HIGH);
      delayMicroseconds(1000);
    }
  }
}

Also an FYI - the motor got very hot, after a short period - is this because I am running it at %100 power and it is using the full 12v’s from the battery?

Sorry I wasn’t more clear. The point was that there are several ways to get the stepper motor to stop after a predefined number of steps, and you were supposed to chose either 1 or 2, not implement both. I’m glad you were confused by this because it means you were paying attention enough to notice something was amiss!

It’s not necessarily a bad sign that the motor is hot; there’s a lot of current flowing through it pretty much the whole time your sketch is running. One way to help keep it cool is to disable the driver when you are not stepping. Note, however, that the stepper motor will not hold it’s position when it is disabled, so this is only an option if nothing is applying external torque to the stepper motor while it is at rest. For example:

void loop()
{
  int j;
  digitalWrite(dirPin, HIGH);  // set step direction

  if (takeSteps)
  {
    digitalWrite(enablePin, LOW);  // enable driver
    delayMicroseconds(2);
    takeSteps = 0;
    for(j=0; j<=10000; j++)
    {
      digitalWrite(stepPin, LOW);
      delayMicroseconds(2);
      digitalWrite(stepPin, HIGH);
      delayMicroseconds(1000);
    }
    digitalWrite(enablePin, HIGH);  // disable driver
  }
}

However, you should probably double check that you aren’t exceeding the current rating of your stepper motor, and if you can get by without the full torque, you can always drop the current limit down below the motor’s current rating to keep it cooler.

So now that you know how to control the motor speed, you can factor in your pot. The way I suggest you do this initially is by replacing the high step delay with a global variable whose value is a function of the pot position. The main thing to figure out here is how to scale your pot readings to get an appropriate range of motor speeds. Can you try taking a stab at this?

- Ben

Thanks again.

So in my void setup - should it look like this?
The motor rotates shimmies a little and then runs the loop

void setup()
{
  // We set the enable pin to be an output
  pinMode(enablePin, OUTPUT);
  // then we set it HIGH so that the board is disabled until we
  // get into a known state.
  digitalWrite(enablePin, HIGH);
  Serial.begin(9600);
  Serial.println("Starting stepper exerciser.");
  pinMode(stepPin, OUTPUT);
  pinMode(dirPin, OUTPUT);
  
  int j;
  // set the enablePin low so that we can now use our stepper driver.
  digitalWrite(enablePin, LOW);
  // wait a few microseconds for the enable to take effect
  // (That isn't in the spec sheet I just added it for sanity.)
  delayMicroseconds(2);
  // we set the direction pin in an arbitrary direction.
  digitalWrite(dirPin, HIGH);
  for(j=0; j<=500; j++) {
    digitalWrite(stepPin, LOW);
    delayMicroseconds(2);
    digitalWrite(stepPin, HIGH);
    delayMicroseconds(1000);
  }
}

As for the current flow, i agree i need the tourque, specifically as unlimately this will be a very slow moving track. Am I correct in assuming that, if the delay is too long between steps, and there is no current - that the motor will slip. This rig will be setup on lateral angles fyi

HOT motor and current issue - yes please help with this.
The battery is 12V and the Motor is 4v - do I do this be increasing the delay? I had the motor running cooler in previous Sketches by reduding the speed to 60%

I’m not sure what this means, but what you have should work. Does it? Ultimately, I think you want to have your code in loop(), though.

The motor will only slip if the driver is disabled and there are external forces/torques. I’m not completely sure what you mean by “setup on lateral angles”. If the track is flat, the motor probably won’t slip if you disable the driver. In the end, you can pretty easily try it and see whether disabling is an option. If not, you will just be constantly dumping power through the stepper motors to keep up the holding torque.

- Ben

The motor voltage is not relevant because the driver is actively limiting the current. What is important is the current rating; make sure you have the driver configured so it doesn’t exceed this. Decreasing the speed does not decrease the current draw of stepper motors (actually, it is the opposite; average current goes down as the step rate goes up, and the worst case is when you are not stepping at all). Also, I don’t know what you mean by “reducing the speed to 60%”. 60% of what?

- Ben

Yes it does, and by shimmy, i mean the motor does the steps defined in the void setup and THEN runs the void loop steps. Why do I need to do this?

void setup()
{
  // We set the enable pin to be an output
  pinMode(enablePin, OUTPUT);
  // then we set it HIGH so that the board is disabled until we
  // get into a known state.
  digitalWrite(enablePin, HIGH);
  Serial.begin(9600);
  Serial.println("Starting stepper exerciser.");
  pinMode(stepPin, OUTPUT);
  pinMode(dirPin, OUTPUT);
  
  int j;
  // set the enablePin low so that we can now use our stepper driver.
  digitalWrite(enablePin, LOW);
  // wait a few microseconds for the enable to take effect
  // (That isn't in the spec sheet I just added it for sanity.)
  delayMicroseconds(2);
  // we set the direction pin in an arbitrary direction.
  digitalWrite(dirPin, HIGH);
  for(j=0; j<=500; j++) {
    digitalWrite(stepPin, LOW);
    delayMicroseconds(2);
    digitalWrite(stepPin, HIGH);
    delayMicroseconds(1000);
  }
}

Also I thought the code was in the loop??? no?

unsigned char takeSteps = 1;  // global variable

void loop()
{
  int j;
  digitalWrite(dirPin, HIGH);  // set step direction

  if (takeSteps)
  {
    digitalWrite(enablePin, LOW);  // enable driver
    delayMicroseconds(2);
    takeSteps = 0;
    for(j=0; j<=500; j++)
    {
      digitalWrite(stepPin, LOW);
      delayMicroseconds(2);
      digitalWrite(stepPin, HIGH);
      delayMicroseconds(1000);
    }
    digitalWrite(enablePin, HIGH);  // disable driver - this is basically a stop delivering current command
  }
}

I was using this in the past with the Stepper.h Arduino library and from what ive read, if one runs motor at less than 100 in setSpeed - it reduces the current as the driver limits the amount to the motor.

void loop()
{
///// Turn the stepper 200 steps with a 1 sec delay between steps at 60rpm
/// then reverse the direction and do 50 steps at 20rpm with a 1sec delay between steps
stepper.setSpeed(60);
stepper.step(200);
delay(1000);
//stepper.setSpeed(20);
//stepper.step(-50);
//delay(1000);
}

Did you not read what I wrote a few posts back?

I’m not sure how to make this more clear: you should not be taking steps in both setup() and loop(). You should pick one. I suggest loop().

- Ben

The Stepper.h Arduino library does not work with the A4988 motor driver. Anything you read about how it works is not relevant to your setup, and you cannot draw any conclusions based on what you observed while running it. In general, a stepper motor will draw less current the more quickly you step it.

- Ben

Totally understood, the more I work with you this, the more of an understaning of all I am gaining - i LOVE it! Thanks again for keeping me from jumping to far ahead.

Just to clarify with you i am using the a4983 with regulator, not the a4988