Stepper Motor Step Output

I am using a A4988 stepper driver and NEMA 17 stepper motor. Am am also using Arduino to program the step and direction outputs. My program seems to be correct, but in using an oscilloscope it tells me that the board is outputting direction correctly, but not outputting step logic like it should. My goal is to get the stepper motor to follow an s-curve in one direction, then the other, and keep repeating this for a set amount of time. The circuit, microcontroller, and motor are all working fine because I have uploaded simple programs and they work like they should. Could someone find the error in my program that is resulting in the lack of step output? The equations were found online. Any help would be much appreciated and thanks in advance!

> // Givens
> const float ta = 3e5;     // acceleration time (microsec)
> const float td = 3e5;     // decelleration time (microsec)
> const float Vm = 3600;    // steady state velocity (pulse/sec)
> const float Pt = 3200;    // total number of pulses for move (1600 steps per rev)

> // Other variables
> long dly;           // stepper pulse delay (microsec)
> long t = td/9;      // current time (microsec)  -  You need to seed the initial time with something > 0 so you don't 
                                                   // calculate too long of a delay
> long t12;           // time during constant velocity (microsec)
> int count = 0;
> int Perr = 0;
> int loopcount = 0;

> const float loopdelay = 1000;

> const int dirPin = 13;  //red=dirPin, white=stepPin, black=digitalGND
> const int stepPin = 3;


> void setup() {
>  pinMode(dirPin, OUTPUT);
>  pinMode(stepPin, OUTPUT);
>  
>  // Calculate the time at constant velocity 
>  t12 = (Pt/(Vm/1e6))-0.5*(ta+td);
> }


> void loop() {
>   loopcount++;

>   if ((loopcount % 2) == 0){
>     digitalWrite(dirPin,HIGH);
>   }
>   else {
>     digitalWrite(dirPin,LOW);
>   }
>   
>  // Decide which part of the velocity curve your at
>  if (t<ta) {                                       // Acceleration
>    dly = (ta)/(2*(Vm/1e6)*t);
>  } 
>  else if (t>=ta && t<(ta+t12)){                    // Constant velocity
>    dly = 1/(2*(Vm/1e6));
>  }
>  else if (t>=(ta+t12) && t<(ta+t12+td)){           // Deceleration
>    dly = 1/(2*((Vm/1e6)-(Vm/(1e6*td))*(t-ta-t12)));
>  }
>  
>  t = t+2*dly; // update the current time
>  
>  // Move stepper one pulse using delay just calculated
>  digitalWrite(stepPin, HIGH);
>  delayMicroseconds(dly);
>  digitalWrite(stepPin, LOW);
>  delayMicroseconds(dly);
>  count ++;

>  // The move is finished
>  if (t>(ta+t12+td)){
>    
>    count=0;
>    t=td/9;

>  }
>    delay (loopdelay);
>  
> }

Hi.

When looking at the step signal with your scope, what do you see (e.g. just a constant zero or something unpredictable)? Have you tried running the simplified code again since having this issue with the step pin to confirm that pin did not become damaged or a connection did not just get loose? Could you post pictures of your setup that show all of your connections?

By the way, it looks like the first if statement in your code causes the motor to change directions every step, so the motor would just be stepping back and forth constantly. Is the behavior you are aiming for?

-Claire

Thank you very much for the response. Unfortunately, I cannot upload a picture because the circuit design is confidential. When looking at the oscilloscope I see a constant zero. I have checked the connections and they are secure and the connecting wires and soldered joints are intact and functioning. Could you explain what you mean by the code causing it to move only a single step? Thanks again

UPDATE: I did find an error in my code. However, I am now experiencing interference between the step and direction outputs. They are form completely separate pins therefore I know the problem is in my code.

If you want help looking for issues in your updated code, you could post it along with a description of what you want it to do and what it is actually doing, and I would be happy to take a look.

-Claire

The motor is receiving the same output from both direction and step. This should not be the case. The program is meant to accelerate the motor in on direction, move at a constant velocity, then decelerate. The motor would then do the same thing back and forth.

// Givens
long ta = 3e5;     // acceleration time (microsec)
long td = 3e5;     // deceleration time (microsec)
long Vm = 3200;    // steady state velocity (pulse/sec)
long Pt = 3200;    // total number of pulses for move (1600 steps per rev)

// Other variables
long dly;           // stepper pulse delay (microsec)
long t = td/9;      // current time (microsec)  -  You need to seed the initial time with something > 0 so you don't calculate too long of a delay
long t12 = 1e6 - ta - td;           // time during constant velocity (microsec)

int count = 0;
int Perr = 0;
int loopcount = 0;

const float loopdelay = 1000;

define dirPin 13  //red=dirPin, white=stepPin, black=digitalGND
define stepPin 3


void setup() {
  
 pinMode(dirPin, OUTPUT);
 pinMode(stepPin, OUTPUT);
 
}


void loop() {
  loopcount++;

  if ((loopcount % 2) == 0){
    digitalWrite(dirPin,HIGH);
  }
  else {
    digitalWrite(dirPin,LOW);
  }
  
 // Decide which part of the velocity curve your at
 if (t<ta){                                       // Acceleration
   dly = (ta)/(2*(Vm/1e6)*t);
 } 
 else if (t>=ta && t<(ta+t12)){                    // Constant velocity
   dly = 1/(2*(Vm/1e6));
 }
 else if (t>=(ta+t12) && t<(ta+t12+td)){           // Slow down
   dly = 1/(2*((Vm/1e6)-(Vm/(1e6*td))*(t-ta-t12)));
 }
 
 t = t+2*dly; // update the current time
 
 // Move stepper one pulse using delay just calculated
 digitalWrite(stepPin, HIGH);
 delayMicroseconds(dly);
 digitalWrite(stepPin, LOW);
 delayMicroseconds(dly);
 count ++;

 // The move is finished
 if (t>=(ta+t12+td)){

   count=0;
   t=td/9;

 
   delay (loopdelay);
 }
}

It looks like your code still has the issue that I pointed out previously. Your first if statement causes the DIR signal to change each step.

  if ((loopcount % 2) == 0){
    digitalWrite(dirPin,HIGH);
  }
  else {
    digitalWrite(dirPin,LOW);
  }

If you do not want that, you either need to adjust the number that you are using in the modulo statement or modify your code so it does not reach this if statement after every step.

-Claire

I added a condition that the loopcount must equal Pt, or the number of requested pulses per move. The step output behaves correctly, but the dir output is displaying constant 0. Thank you again
if ((loopcount % 2) == 0 && loopcount == Pt){ digitalWrite(dirPin,HIGH); } else { digitalWrite(dirPin,LOW); }

I also made another condition for loopcount vs a direction change counter called dircount. After uploading this to the board, The dir was a constant 0.

void loop() {

loopcount++;

if (loopcount == Pt){

dircount++;

if ((dircount % 2) == 0){
digitalWrite(dirPin,HIGH);
}
else {
digitalWrite(dirPin,LOW);
}
}

else{

// Decide which part of the velocity curve your at

the rest of the code is the same

Where in the code do you set Pt? Is it a constant?

Rather than just adding more counters, it seems like you should just have one counter that counts the number of steps it takes to complete one whole section of your S-curve before changing direction.

-Claire

I apologize. My entire code is below:

// Givens
long ta = 3e5;     // acceleration time (microsec)
long td = 3e5;     // deceleration time (microsec)
long Vm = 3200;    // steady state velocity (pulse/sec)
long Pt = 3200;    // total number of pulses for move (1600 steps per rev)

// Other variables
long dly;           // stepper pulse delay (microsec)
long t = td/9;      // current time (microsec)  -  You need to seed the initial time with something > 0 so you don't calculate too long of a delay
long t12 = 1e6 - ta - td;           // time during constant velocity (microsec)

int count = 0;
int loopcount = 0;
int dircount = 0;

const float loopdelay = 1000;

#define dirPin 13  //red=dirPin, white=stepPin, black=digitalGND
#define stepPin 3


void setup() {
  
 pinMode(dirPin, OUTPUT);
 pinMode(stepPin, OUTPUT);
 
}


void loop() {

  loopcount++;

if (loopcount == Pt){

  dircount++;
  
  if ((dircount % 2) == 0){
    digitalWrite(dirPin,HIGH);
  }
  else {
    digitalWrite(dirPin,LOW);
  }
}

else{
  
 // Decide which part of the velocity curve your at
 if (t<ta){                                       // Acceleration
   dly = (ta)/(2*(Vm/1e6)*t);
 } 
 else if (t>=ta && t<(ta+t12)){                    // Constant velocity
   dly = 1/(2*(Vm/1e6));
 }
 else if (t>=(ta+t12) && t<(ta+t12+td)){           // Slow down
   dly = 1/(2*((Vm/1e6)-(Vm/(1e6*td))*(t-ta-t12)));
 }
 
 t = t+2*dly; // update the current time
 
 // Move stepper one pulse using delay just calculated
 digitalWrite(stepPin, HIGH);
 delayMicroseconds(dly);
 digitalWrite(stepPin, LOW);
 delayMicroseconds(dly);
 count ++;

 // The move is finished
 if (t>=(ta+t12+td)){

   count=0;
   t=td/9;

 
   delay (loopdelay);
 }
}
}

My thought process was that the direction should not change before the requested amount of steps are completed. Therefore, I needed to add one counter to make sure that that number is met. The second counter is simply to alternate the loop direction every time it completes a move. What would you suggest? Thank you for your continuous responses. All your help is much appreciated and the suggestions are very helpful.

Having two counters the way you proposed could work, but in your current program loopcount is never reset to zero, so it will only ever equal Pt once, so the motor will only ever change directions once.

-Claire

I added the reset function and cleaned up the program slightly. However, the oscilloscope still displays a constant 0, not even one direction change. I tried switching HIGH and LOW in the digitalWrite() statements at the beginning of the loop. The oscilloscope still displayed a constant 0. Therefore, the board is not giving any directional output. Is that a problem with my code? The code is below:

// Givens
long ta = 3e5;     // acceleration time (microsec)
long td = 3e5;     // deceleration time (microsec)
long Vm = 3200;    // steady state velocity (pulse/sec)
long Pt = 3200;    // total number of pulses for move (1600 steps per rev)

// Other variables
long dly;           // stepper pulse delay (microsec)
long t = td/9;      // current time (microsec)  -  You need to seed the initial time with something > 0 so you don't calculate too long of a delay
long t12 = 1e6 - ta - td;           // time during constant velocity (microsec)

int count = 0;
int loopcount = 0;
int dircount = 0;

const float loopdelay = 1000;

#define dirPin 13  //red=dirPin, white=stepPin, black=digitalGND
#define stepPin 3


void setup() {
  
 pinMode(dirPin, OUTPUT);
 pinMode(stepPin, OUTPUT);
 
}


void loop() {

  loopcount++;

if (loopcount == Pt){

  dircount++;
  
  if ((dircount % 2) == 0){
    digitalWrite(dirPin,HIGH);
  }
  else {
    digitalWrite(dirPin,LOW);
  }
}

else{
  
 // Decide which part of the velocity curve your at
 if (t<ta){                                       // Acceleration
   dly = (ta)/(2*(Vm/1e6)*t);
 } 
 else if (t>=ta && t<(ta+t12)){                    // Constant velocity
   dly = 1/(2*(Vm/1e6));
 }
 else if (t>=(ta+t12) && t<(ta+t12+td)){           // Slow down
   dly = 1/(2*((Vm/1e6)-(Vm/(1e6*td))*(t-ta-t12)));
 }
 
 t = t+2*dly; // update the current time
 
 // Move stepper one pulse using delay just calculated
 digitalWrite(stepPin, HIGH);
 delayMicroseconds(dly);
 digitalWrite(stepPin, LOW);
 delayMicroseconds(dly);
 count ++;

 // The move is finished
 if (t>=(ta+t12+td)){
  
   loopcount=0;
   count=0;
   t=td/9;

 
   delay (loopdelay);
 }
}
}
```
I finally figured out how to post code correctly :joy:

I now added Serial.print to tell me the direction and when it resets. However, it never displays HIGH/LOW (direction indicators), only reset. It is as if the loopcount condition is never met therefore it cannot choose a direction. If this is true, I am not sure why that would be. The loopcount should keep adding one until the desired number of steps has been met. Is it possible that the loopcount++ is in the wrong spot?

// Givens
long ta = 3e5;     // acceleration time (microsec)
long td = 3e5;     // deceleration time (microsec)
long Vm = 3200;    // steady state velocity (pulse/sec)
long Pt = 3200;    // total number of pulses for move (1600 steps per rev)

// Other variables
long dly;           // stepper pulse delay (microsec)
long t = td/9;      // current time (microsec)  -  You need to seed the initial time with something > 0 so you don't calculate too long of a delay
long t12 = 1e6 - ta - td;           // time during constant velocity (microsec)

int count = 0;
int loopcount = 0;
int dircount = 0;

const int loopdelay = 1000;

#define dirPin 13  //red=dirPin, white=stepPin, black=digitalGND
#define stepPin 3


void setup() {

 Serial.begin(9600);
  
 pinMode(dirPin, OUTPUT);
 pinMode(stepPin, OUTPUT);
 
}


void loop() {

  loopcount++;
  
if (loopcount == Pt){

  dircount++;
  
  if ((dircount % 2) == 0){
    digitalWrite(dirPin,HIGH);
    Serial.println("HIGH");
  }
  else {
    digitalWrite(dirPin,LOW);
    Serial.println("LOW");
  }
}

else{
  
 // Decide which part of the velocity curve your at
 if (t<ta){                                        // Acceleration
   dly = (ta)/(2*(Vm/1e6)*t);
   //Serial.println("Acceleration");
 } 
 else if (t>=ta && t<(ta+t12)){                    // Constant velocity
   dly = 1/(2*(Vm/1e6));
   //Serial.println("Constant Velocity");
 }
 else if (t>=(ta+t12) && t<(ta+t12+td)){           // Slow down
   dly = 1/(2*((Vm/1e6)-(Vm/(1e6*td))*(t-ta-t12)));
   //Serial.println("Deceleration");
 }
 
 t = t+2*dly; // update the current time
 
 // Move stepper one pulse using delay just calculated
 digitalWrite(stepPin, HIGH);
 delayMicroseconds(dly);
 digitalWrite(stepPin, LOW);
 delayMicroseconds(dly);
 count ++;

 // The move is finished
 if (t>=(ta+t12+td)){
  
   loopcount=0;
   count=0;
   t=td/9;
   
   Serial.println("reset");
 
   delay (loopdelay);
 }
}
}
```

UPDATE:  I added Serial.print to the loopcount and it appears that is adding one every time, but the loopcount is never reaching the desired amount of steps.  The time constraint is limiting it, but it is necessary to keep.  Any ideas on why this is happening?  You have been very helpful so far and would appreciate any further help.

Thanks for formatting your code!

In the second program you posted it looks like loopcount is getting reset in the section that is run when loopcount is not equal to Pt. That could work depending on how long it takes your move to finish, but I suspect that it is being reset before it ever reaches Pt. It looks like you could instead reset loopcount every time it equals Pt:

if (loopcount == Pt){
  loopcount=0;
  dircount++;

If you continue to have trouble, I recommend starting a new version of the code that only counts to a certain number of times through the loop and then changes direction (no extra math for creating your waveform). Once that is working you can add one feature and verify each part still works before moving on to the next thing.

-Claire

Thank you so much for the help. I actually figured out that the time reset function was in the wrong spot and moved it. Now the program works as it should. I am kicking myself that it was that easy. The final WORKING program is below:

// Givens
long ta = 3e5;     // acceleration time (microsec)
long td = 3e5;     // deceleration time (microsec)
long Vm = 3200;    // steady state velocity (pulse/sec)
long Pt = 3200;    // total number of pulses for move (1600 steps per rev)

// Other variables
long dly;           // stepper pulse delay (microsec)
long t = td/9;      // current time (microsec)  -  You need to seed the initial time with something > 0 so you don't calculate too long of a delay
long t12 = 1e6 - ta - td;           // time during constant velocity (microsec)

int count = 0;
int loopcount = 0;
int dircount = 0;

const int loopdelay = 1000;

#define dirPin 4   //red=dirPin, white=stepPin, black=digitalGND
#define stepPin 3


void setup() {

 Serial.begin(9600);
  
 pinMode(dirPin, OUTPUT);
 pinMode(stepPin, OUTPUT);
 
}


void loop() {

  loopcount++;

  //Serial.println(loopcount);
  
if (t>=(ta+t12+td)){

  dircount++;

  t=td/9;
  
  if ((dircount % 2) == 0){
    digitalWrite(dirPin,HIGH);
    Serial.println("HIGH");
  }
  else {
    digitalWrite(dirPin,LOW);
    Serial.println("LOW");
  }
}

else{
  
 // Decide which part of the velocity curve your at
 if (t<ta){                                        // Acceleration
   dly = (ta)/(2*(Vm/1e6)*t);
   //Serial.println("Acceleration");
 } 
 else if (t>=ta && t<(ta+t12)){                    // Constant velocity
   dly = 1/(2*(Vm/1e6));
   //Serial.println("Constant Velocity");
 }
 else if (t>=(ta+t12) && t<(ta+t12+td)){           // Slow down
   dly = 1/(2*((Vm/1e6)-(Vm/(1e6*td))*(t-ta-t12)));
   //Serial.println("Deceleration");
 }
 
 t = t+2*dly; // update the current time
 //Serial.println(dly);
 
 // Move stepper one pulse using delay just calculated
 digitalWrite(stepPin, HIGH);
 delayMicroseconds(dly);
 digitalWrite(stepPin, LOW);
 delayMicroseconds(dly);
 count ++;

 // The move is finished
 if (t>=(ta+t12+td)){
  
   loopcount=0;
   count=0;
   
   Serial.println("reset");
 
   delay (loopdelay);
 }
}
}
```
1 Like