Stepper Motor S-Curve

I am using a NEMA 17 stepper motor along with a A4988 stepper driver. I am using an s-curve program that I found on this forum, only I want it to accelerate one direction, then the other as opposed to doing it in one direction. However, when I hook my arduino uno board up to an oscilloscope, the direction output shows a constant 0 while the step output is correct. Both the board, circuit setup, and driver are functioning as they work on simpler programs. Is there something wrong with my code? Thanks!

The original one-directional code was taken from here: S-Curve for EasyDriver v3 Stepper Motor Driver - Interfacing - Arduino Forum

// 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);
 }
}
}

const float loopdelay = 1000;

What is the purpose of declaring a float and then using it to store an int?

delay() does not take a float.

What do your Serial.print()s tell you is happening?

I changed the loopdelay to an int as you said but it made no difference. I do not have any Serial.print in my program. Should I add that to help understand what is happening?

I added Serial.print to tell me the direction and when it resets. However, it never displays HIGH/LOW (direction indicators), only reset.

// 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);
 }
}
}

However, it never displays HIGH/LOW (direction indicators), only reset.

That would imply, then, that loopcount never equals Pt. What does it contain?

That would be correct. However, this should not be the case. The loopcount should keep running until it has reached the desired amount of steps. What do you mean by "What does it contain?"

What do you mean by "What does it contain?"

He means what value is contained in the variable "loopcount".

1e5 is a floating point constant. Why are you mixing floats and longs? The math (especially division) behaves very differently for the two.

loopcount is initially set to equal zero but one is added every time it goes through the loop. When it decides that the move is finished, then the loopcount is reset to zero. Is it possible that it is in the wrong position or a condition is incorrect so that it is never met?

I have heard this on several occasions but am not quite sure what you mean. Could you give me an example in the code and how to fix it? I do not wish to have you do my code for me I would just like an example to go by. This may also solve some of my other minor issues.

Thanks!

Is it possible that it is in the wrong position or a condition is incorrect so that it is never met?

Of course it is. Serial.print() loopcount to see what it is actually doing.

Thank you for the helpful tip. I added this and it is never reaching the requested amount of steps. I believe it is reaching the time constraint first. However, I need the time constraint in order to make the equations correct. Any ideas?

Here is my current code:

// 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++;

  Serial.println(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
 //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;
   t=td/9;
   
   Serial.println("reset");
 
   delay (loopdelay);
 }
}
}

Any ideas?

You know when the stepper is accelerating. You know when it is running at constant speed. You know when it is slowing down. You know when it reaches minimum speed. That seems to be the time to change direction, regardless of how many steps it took.

You are correct however the time is reset before the decision is made to change direction. Therefore the loopcount must be used in order to make sure that the number of steps are met.

however the time is reset before the decision is made to change direction.

Ummm. Why?

Otherwise the delay that is used to calculate the velocity of each individual step will grow longer and longer. Therefore it needs to reset every time before it changes direction. Is my thinking correct? Or is there a way around this that I am not seeing?

Therefore it needs to reset every time before it changes direction.

My question is does it need to be reset before it changes direction, or WHEN it changes direction? That is, isn't the place in the code where you reset the delay the place to change direction?

I've done something similar in the past, and used a fast continuous loop to track all the motion functions.
Rather than insert delay() to slow down the ramp, I used millis() counters to 'skip' step pulses when needed.
Not only does it work well, but it allows your step code to responsive to other things (like sensing limit switches etc).
It will require a significant rewrite of your code...
My project had four steppers running at >10kHz step rate on a 16MHz MEGA.

Paul you are a genius. I am kicking myself that I did not see this before. I moved the time reset function and it works perfectly as of now. Thanks so much everyone for the help.