Stepper loosing position over time

All and all my code seems to be working pretty well except as time goes on and the stepper moves back and forth it seems to be slowly loosing its starting position, I have a Nema 23 motor running on a TB6600 driver set to 1/4 micro stepping @ 24V with an UNO. After about 5 minutes the stepper is almost a full rotation away from its starting position. I tried slowing the stepper down but it didn't seem to help. The web seems to think these motors can spin at 400rpm and its moving much slower than that anyway so i don't feel like its loosing steps. Any insight would be greatly appreciated..

#include <Adafruit_DS3502.h>                  
Adafruit_DS3502 ds3502 = Adafruit_DS3502();   

byte directionPin = 2;      //New Stepper control
byte stepPin = 3;
byte stepstop  = 4;


unsigned long curMillis;
unsigned long prevStepMillis = 0;
unsigned long millisBetweenStepsup = 1; // milliseconds
unsigned long millisBetweenStepsdown = 2; // milliseconds




#include "MultiMap.h"           //Multimap
int mappedValue;                //
int in[] = {0 , 31, 63, 95, 127};   //
int out[] = {0, 95, 115, 125, 127};  //



#define magnetDetected       HIGH
#define noMagnet             LOW

#define weAreTiming          true
#define weAreNotTiming       false

#define notfull              false
#define full                 true

#define resetting           true
#define tensioning          false

#define brakeon             true
#define brakeoff            false

#define clutchon            true
#define clutchoff           false

const byte BRAKE_IN_PIN    = A0;
const byte CLUTCH_IN_PIN    =A3; 
const byte PRESSURE        = A1;  // Pot on Analog Pin 1
const byte POTH            = A2;  // Pot on Analog Pin 2

bool timerRunningFlag      = weAreNotTiming;
bool fullthrottle          = notfull;
bool resetflag             = tensioning;
bool brakeflag             = brakeoff;
bool clutchflag            = clutchoff;

const byte sensor          = 6;
const byte heartbeatLED    = 13;
int reset = 7;

byte lastWheelState        = noMagnet;

int digitalPot                ;
int brake_value           = 0;
int clutch_value          = 0;
int clutch_temp           = 0;
int lowspeed               = 0;   // Low speed set
int highspeed              = 0;   // High Speed set
int lowrpm                 = 0;   // Low RPM kick in
int highrpm                = 0;   // High RPM kick in
int highValue              = 0;
int stepsLeft              = 0;
int force                  = 0;
int stepmath               = 0;
int tension                = 0;
int stepstaken             = 0;
int fullsqueeze            = 0;

int totaltension           =2500;

const int lowValue         = 800; //low speed setting

const int highLow          = 600; //reading 0
const int highHigh         = 200; //reading 1023

//timing stuff
unsigned long startTime;
unsigned long endTime;
unsigned long duration;
unsigned long timerMillis;
unsigned long heartbeatMillis;
unsigned long wheelMillis;

//*********************************************************************
void setup()
{
  analogReference(A0);
  ds3502.setWiper(0);
  pinMode (sensor, INPUT_PULLUP);

  pinMode (heartbeatLED, OUTPUT);

  Serial.begin(115200);

  while (!Serial)
  {
    delay(1);
  }

  Serial.println("Adafruit DS3502 Test");

  if (!ds3502.begin())                             // <-----<<<<<
  { // <-----<<<<<
    Serial.println("Couldn't find DS3502 chip");   // <-----<<<<<
    while (1);                                     // <-----<<<<<
  }                                                // <-----<<<<<

  Serial.println("Found DS3502 chip");
 
  pinMode(reset, INPUT_PULLUP);

  pinMode(directionPin, OUTPUT);      //New stepper
  pinMode(stepPin, OUTPUT);
  pinMode(stepstop, OUTPUT);
fullthrottle = notfull;
} 


//*********************************************************************
void loop()

{
  digitalRead(reset);
  while (digitalRead(reset) == LOW)
    {
      stepstaken = 0;
      tension = 0;
      digitalWrite(stepstop, HIGH);
      if (resetflag == tensioning) { 
      Serial.println("reset");
      resetflag = resetting;
      }
      digitalRead(reset);
      
    }
  
  digitalWrite(stepstop, LOW);  // reengage stepmotor
  resetflag = tensioning;
  
  if(millis() - heartbeatMillis >= 500)
  {    heartbeatMillis = millis();
    digitalWrite(heartbeatLED, !digitalRead(heartbeatLED));
  }

  //***********************
  //time to check the wheel sensor ?
  if (millis() - wheelMillis >= 10)
  {
    //restart the TIMER
    wheelMillis = millis();
    checkWheelSensor();
  }

  if (timerRunningFlag == weAreTiming && millis() - timerMillis >= lowValue)    //timeout
   {
    timerRunningFlag = weAreNotTiming;
    duration = lowValue;
    printDigitalPot();
    
    //timerRunningFlag = weAreTiming;       //testing

      //start this TIMER
    //  startTime = millis();

      //start this TIMER
    //  timerMillis = millis();             //too here
  }

  //***********************
  //Other non-blocking code goes here
  //***********************

 
  brake_value = analogRead(BRAKE_IN_PIN);
  clutch_value = analogRead(CLUTCH_IN_PIN);
  digitalRead(reset);
  
  curMillis = millis();
  
  if (tension > stepstaken && curMillis - prevStepMillis >= millisBetweenStepsup) {
    digitalWrite(directionPin, HIGH);
    prevStepMillis = curMillis;
        digitalWrite(stepPin, HIGH);
        digitalWrite(stepPin, LOW);
   stepstaken = stepstaken+1;
   }


if (tension < stepstaken && curMillis - prevStepMillis >= millisBetweenStepsdown) {
   digitalWrite(directionPin, LOW);
   prevStepMillis = curMillis;
        digitalWrite(stepPin, HIGH);
        digitalWrite(stepPin, LOW);
   stepstaken = stepstaken-1;
   }
  
 while (brake_value < 500) {  // used to be 920
    ds3502.setWiper(127);
    if (brakeflag == brakeoff) {
    Serial.print("Brake on ");
    Serial.println(brake_value);
    brakeflag = brakeon;
    }
    curMillis = millis();
   if (stepstaken > 0 && curMillis - prevStepMillis >= millisBetweenStepsup) {
   digitalWrite(directionPin, LOW);
   prevStepMillis = curMillis;
        digitalWrite(stepPin, HIGH);
        digitalWrite(stepPin, LOW);
    stepstaken = stepstaken-1;
   }
    brake_value = analogRead(BRAKE_IN_PIN);
    }

  brakeflag = brakeoff;
 
  while (clutch_value < 900 && brake_value > 920) {
    clutch_temp = map(clutch_value, 800, 80, digitalPot, 127);
    clutch_temp = constrain(clutch_temp, 0, 127);
    ds3502.setWiper(clutch_temp);
    if (clutchflag == clutchoff) {
    Serial.print("Clutch on ");
    Serial.print(clutch_value);
    Serial.print("  Digitalpot value:  ");
    Serial.println(clutch_temp);
    clutchflag = clutchon;
    }
    curMillis = millis();
    if (stepstaken > 0 && curMillis - prevStepMillis >= millisBetweenStepsdown) {
   digitalWrite(directionPin, LOW);
   prevStepMillis = curMillis;
        digitalWrite(stepPin, HIGH);
        digitalWrite(stepPin, LOW);
    stepstaken = stepstaken-1;
   }

    brake_value = analogRead(BRAKE_IN_PIN);
    clutch_value = analogRead(CLUTCH_IN_PIN);
    }

 clutchflag = clutchoff;
    

  
    

} //END of loop()


//*********************************************************************
void checkWheelSensor()
{
  byte thisState = digitalRead(sensor);

  //***********************
  //was there a change in state ?
  if (lastWheelState != thisState)
  {
    //update to the new state
    lastWheelState = thisState;

    //***********************
    //if we are 'not' timing has the sensor detected the magnet ?
    if (timerRunningFlag == weAreNotTiming && thisState == magnetDetected)
    {
      //enable timing
      timerRunningFlag = weAreTiming;

      //start this TIMER
      startTime = millis();

      //start this TIMER
      timerMillis = millis();
    }

    //***********************
    if (timerRunningFlag == weAreTiming && thisState == noMagnet)
    {
      //disable the timing
      timerRunningFlag = weAreNotTiming;

      endTime = millis();

      duration = endTime - startTime;

      printDigitalPot();
    }

  } //END of  if(lastWheelState != thisState)

} //END of checkWheelSensor()


//*********************************************************************
void printDigitalPot()
{ 
  highspeed = analogRead(POTH); //0 to 1023
  highValue = map(highspeed, 0, 1000, highLow, highHigh);

  int temp = map( duration, highValue, lowValue, 0, 127); 
  temp = constrain(temp, 0, 127);   //stay within the 0-127 range
  
  
  
  digitalPot=multiMap(temp, in, out, 5);
  
  ds3502.setWiper(digitalPot);
  force = analogRead(PRESSURE);
  force = map(force,0,1023,0,totaltension); 
  stepmath = map(temp,0,127,force,0);  //temp might become "digitalPot" again

  if (temp > 0) //less than full throttle
    {
    fullthrottle = notfull;
    tension = stepmath;
    }

  if (fullthrottle == full)
    {
      fullsqueeze = 10; //stepmath/300; //300 may need to change depending on required full throttle pressure
      tension = tension+fullsqueeze;
      }

    if (fullthrottle == notfull && temp == 0)
      {fullthrottle = full;
      tension = stepmath;

       }

 
   
   
  Serial.print("B: ");
  Serial.print(brake_value);
  Serial.print("C: ");
  Serial.print(clutch_value);
  Serial.print("  ");
  Serial.print(lowValue);
  Serial.print("  ");
  Serial.print("Timer spread ");
  Serial.print(highValue);
  Serial.print ("  Time in millis = ");
  Serial.print (duration);
  Serial.print("  ");
  Serial.print(temp);
  Serial.print("   Digital pot set to: ");
  Serial.print(digitalPot);
  Serial.print("\t");
  Serial.print("Savage level: ");
  Serial.print(force);
  Serial.print("  ");
  Serial.print(stepmath);
  Serial.print(" -Stepmath   Stepstaken- ");
  Serial.print(stepstaken);
  Serial.print("   Needed tension: ");
  Serial.println(tension);
  Serial.println("");
  
 

} //END of  printDigitalPot()

I think that it's loosing steps. Speed is not the only limiting factor. Have you tried the AccelStepper library with a limited acceleration?

I too think it is losing steps, but you have not given enough information. Perhaps the stepper is overloaded, or the current limit is set incorrectly.

The web seems to think these motors can spin at 400rpm

"The web" does not think at all. For information, check the motor data sheet instead.

How long of a step pulse does your driver need?

I'd put that code into its own function, and reorder the operations to have a longer pulse:

void stepStepper(byte dir){
//    digitalWrite(directionPin,dir > 0 ? HIGH,LOW); // edit typo
    digitalWrite(directionPin,dir > 0 ? HIGH:LOW);
    digitalWrite(stepPin, HIGH);
    prevStepMillis = curMillis;
    stepstaken = stepstaken+dir;
    digitalWrite(stepPin, LOW);
}

@sugakane, your topic has been moved to a more suitable location on the forum. Installation and Troubleshooting is not for problems with (nor for advise on) your project :wink: See About the Installation & Troubleshooting category.

Are you sure your step pulse is long enough? Try:

  digitalWrite(stepPin, HIGH);
  delayMicroseconds(12);
  digitalWrite(stepPin, LOW);
1 Like

You absolutely need to use speed ramping with a large NEMA23 stepper otherwise it will definitely miss-step like this (you are breaking the laws of physics otherwise) - try the AccelStepper library and experiment with the acceleration value.

1 Like

I have just tried adding the delayMicroseconds for the step pulse. It didn't seem to work. When I originally set about writing this code I tried to use the AccelStepper library but couldn't get it to function in a non blocking way correctly. Any thoughts how i would achieve that?

accelStepper is good at non-blocking. It needs the stepper.run() called each loop().

With the whiles in your loop(), it doesn't look like your code is non-blocking. For example, although the stepping is surrounded by a millis test, the millis test is surrounded by a while here:

  while (clutch_value < 900 && brake_value > 920) {
    clutch_temp = map(clutch_value, 800, 80, digitalPot, 127);
    clutch_temp = constrain(clutch_temp, 0, 127);
    ds3502.setWiper(clutch_temp);
    if (clutchflag == clutchoff) {
      Serial.print("Clutch on ");
      Serial.print(clutch_value);
      Serial.print("  Digitalpot value:  ");
      Serial.println(clutch_temp);
      clutchflag = clutchon;
    }
    curMillis = millis();
    if (stepstaken > 0 && curMillis - prevStepMillis >= millisBetweenStepsdown) {
      digitalWrite(directionPin, LOW);
      prevStepMillis = curMillis;
      digitalWrite(stepPin, HIGH);
      digitalWrite(stepPin, LOW);
      stepstaken = stepstaken - 1;
    }

    brake_value = analogRead(BRAKE_IN_PIN);
    clutch_value = analogRead(CLUTCH_IN_PIN);
  }

Which of its examples did you try?

its been a while since i worked on the project but just started getting back into it. I am trying to integrate accelstepper into the program
I now have a nema 17 step motor with a l298n driver running at 24v when i run the below code the step motor kinda just pulses and after 30 seconds or so the driver chip started smoking. I had removed the 5v jumper from the board before i tested it.

#include <Adafruit_DS3502.h>                  
Adafruit_DS3502 ds3502 = Adafruit_DS3502();   


#include <AccelStepper.h>
#define MotorInterfaceType 4
AccelStepper stepper = AccelStepper(MotorInterfaceType, 6, 7, 8, 9); // Check for free pins


unsigned long curMillis;
unsigned long prevStepMillis = 0;
unsigned long millisBetweenStepsup = 1; // milliseconds
unsigned long millisBetweenStepsdown = 2; // milliseconds
int stepdelay              =10; //testing
int clutchadvance          =10; //testing
int brakespeed             =5; //testing



#include "MultiMap.h"           //Multimap
int mappedValue;                //
int in[] = {0 , 31, 63, 95, 127};   //
int out[] = {0, 95, 115, 125, 127};  //



#define magnetDetected       HIGH
#define noMagnet             LOW

#define weAreTiming          true
#define weAreNotTiming       false

#define notfull              false
#define full                 true

#define resetting           true
#define tensioning          false

#define brakeon             true
#define brakeoff            false

#define clutchon            true
#define clutchoff           false

const byte BRAKE_IN_PIN    = A0;
const byte CLUTCH_IN_PIN    =A3; 
const byte PRESSURE        = A1;  // Pot on Analog Pin 1
const byte POTH            = A2;  // Pot on Analog Pin 2

bool timerRunningFlag      = weAreNotTiming;
bool fullthrottle          = notfull;
bool resetflag             = tensioning;
bool brakeflag             = brakeoff;
bool clutchflag            = clutchoff;

const byte sensor          = 5;
const byte heartbeatLED    = 13;
int reset                  = 12;

byte lastWheelState        = noMagnet;

int digitalPot                ;
int brake_value           = 0;
int clutch_value          = 0;
int clutch_temp           = 0;
int lowspeed               = 0;   // Low speed set
int highspeed              = 0;   // High Speed set
int lowrpm                 = 0;   // Low RPM kick in
int highrpm                = 0;   // High RPM kick in
int highValue              = 0;
int stepsLeft              = 0;
int force                  = 0;
int stepmath               = 0;
int tension                = 0;
int stepstaken             = 0;
int fullsqueeze            = 0;


int totaltension           =4500;

int lowValue         = 800; //low speed setting

const int highLow          = 600; //reading 0
const int highHigh         = 200; //reading 1023

//timing stuff
unsigned long startTime;
unsigned long endTime;
unsigned long duration;
unsigned long timerMillis;
unsigned long heartbeatMillis;
unsigned long wheelMillis;

//*********************************************************************
void setup()
{
  analogReference(A0);
  ds3502.setWiper(0);
  pinMode (sensor, INPUT_PULLUP);

  pinMode (heartbeatLED, OUTPUT);

  Serial.begin(115200);

  while (!Serial)
  {
    delay(1);
  }

  Serial.println("Adafruit DS3502 Test");

  if (!ds3502.begin())                             // <-----<<<<<
  { // <-----<<<<<
    Serial.println("Couldn't find DS3502 chip");   // <-----<<<<<
    while (1);                                     // <-----<<<<<
  }                                                // <-----<<<<<

  Serial.println("Found DS3502 chip");
 
  pinMode(reset, INPUT_PULLUP);

// Set the maximum steps per second:
  stepper.setMaxSpeed(600);

  // Set the maximum acceleration in steps per second^2:
  stepper.setAcceleration(100);
fullthrottle = notfull;
} 


//*********************************************************************
void loop()

{
  digitalRead(reset);
  while (digitalRead(reset) == LOW)
    {
      stepstaken= 0;
      tension = 0;            
      digitalWrite(heartbeatLED, LOW);
      if (resetflag == tensioning) { 
        Serial.println("reset");
        resetflag = resetting;
        }
      digitalRead(reset);
      
    }
  
  resetflag = tensioning;
  
  if(millis() - heartbeatMillis >= 500)
  {    heartbeatMillis = millis();
    digitalWrite(heartbeatLED, !digitalRead(heartbeatLED));
  }

  //***********************
  //time to check the wheel sensor ?
  if (millis() - wheelMillis >= 10)
  {
    //restart the TIMER
    wheelMillis = millis();
    checkWheelSensor();
  }

  if (timerRunningFlag == weAreTiming && millis() - timerMillis >= lowValue)    //timeout
   {
    timerRunningFlag = weAreNotTiming;
    duration = lowValue;
    printDigitalPot();
    
    //timerRunningFlag = weAreTiming;       //testing

      //start this TIMER
    //  startTime = millis();

      //start this TIMER
    //  timerMillis = millis();             //too here
  }

  //***********************
  //Other non-blocking code goes here
  //***********************

 
stepper.run();
  brake_value = analogRead(BRAKE_IN_PIN);
  clutch_value = analogRead(CLUTCH_IN_PIN);
  digitalRead(reset);
  
  curMillis = millis();
  

   while (brake_value < 500) {  // used to be 920
    ds3502.setWiper(127);
    if (brakeflag == brakeoff) {
    Serial.print("Brake on ");
    Serial.println(brake_value);
    brakeflag = brakeon;
    }
    curMillis = millis();
    brake_value = analogRead(BRAKE_IN_PIN);
    }

  brakeflag = brakeoff;
 
  while (clutch_value < 900 && brake_value > 920) {
    clutch_temp = map(clutch_value, 800, 80, digitalPot, 127);
    clutch_temp = constrain(clutch_temp, 0, 127);
    ds3502.setWiper(clutch_temp);
    if (clutchflag == clutchoff) {
    Serial.print("Clutch on ");
    Serial.print(clutch_value);
    Serial.print("  Digitalpot value:  ");
    Serial.println(clutch_temp);
    clutchflag = clutchon;
    }
    curMillis = millis();
    brake_value = analogRead(BRAKE_IN_PIN);
    clutch_value = analogRead(CLUTCH_IN_PIN);
    }

 clutchflag = clutchoff;
    

  
    

} //END of loop()


//*********************************************************************
void checkWheelSensor()
{
  byte thisState = digitalRead(sensor);

  //***********************
  //was there a change in state ?
  if (lastWheelState != thisState)
  {
    //update to the new state
    lastWheelState = thisState;

    //***********************
    //if we are 'not' timing has the sensor detected the magnet ?
    if (timerRunningFlag == weAreNotTiming && thisState == magnetDetected)
    {
      //enable timing
      timerRunningFlag = weAreTiming;

      //start this TIMER
      startTime = millis();

      //start this TIMER
      timerMillis = millis();
    }

    //***********************
    if (timerRunningFlag == weAreTiming && thisState == noMagnet)
    {
      //disable the timing
      timerRunningFlag = weAreNotTiming;

      endTime = millis();

      duration = endTime - startTime;

      printDigitalPot();
    }

  } //END of  if(lastWheelState != thisState)

} //END of checkWheelSensor()


//*********************************************************************
void printDigitalPot()
{ 
  highspeed = analogRead(POTH); //0 to 1023
  highValue = map(highspeed, 0, 1000, highLow, highHigh);
  lowValue = (highValue + 400);
  
  int temp = map( duration, highValue, lowValue, 0, 127); 
  temp = constrain(temp, 0, 127);   //stay within the 0-127 range
  
  
  
  digitalPot=multiMap(temp, in, out, 5);
  
  ds3502.setWiper(digitalPot);
  force = analogRead(PRESSURE);
  force = map(force,0,1023,0,totaltension); 
  stepmath = map(temp,0,127,force,0);  //temp might become "digitalPot" again

  if (temp > 0) //less than full throttle
    {
    fullthrottle = notfull;
    tension = stepmath;
    }

  if (fullthrottle == full)
    {
      fullsqueeze = 10; //stepmath/300; //300 may need to change depending on required full throttle pressure
      tension = tension+fullsqueeze;
      }

    if (fullthrottle == notfull && temp == 0)
      {fullthrottle = full;
      tension = stepmath;

       }

 stepper.moveTo(tension);
   
   
  Serial.print("B: ");
  Serial.print(brake_value);
  Serial.print("C: ");
  Serial.print(clutch_value);
  Serial.print("  ");
  Serial.print(lowValue);
  Serial.print("  ");
  Serial.print("Timer spread ");
  Serial.print(highValue);
  Serial.print ("  Time in millis = ");
  Serial.print (duration);
  Serial.print("  ");
  Serial.print(temp);
  Serial.print("   Digital pot set to: ");
  Serial.print(digitalPot);
  Serial.print("\t");
  Serial.print("Savage level: ");
  Serial.print(force);
  Serial.print("  ");
  Serial.print(stepmath);
  Serial.print(" -Stepmath   Stepstaken- ");
  Serial.print(stepstaken);
  Serial.print("   Needed tension: ");
  Serial.println(tension);
  Serial.println("");
  
 

} //END of  printDigitalPot()

Use a newer MOSFET driver with current limiter. What voltage is your stepper rated for? Voltage or current driven?

The L298N is an ancient, inefficient brushed DC motor driver, for small, low power toy motors. It is totally unsuitable for almost all stepper motors.

Use a modern stepper driver that can handle the current rating of the stepper, and be sure to adjust the current limit correctly. Pololu has the best selection.

1 Like

Would something like a A4988 be appropriate? I am looking for a cost effective option as Iā€™m trying to prototype what would hopefully be a consumer product at some point

The A4988 driver is good for 1A coil current without a heat sink and active (fan) cooling. 1.5A with a heat sink and fan cooling.

DRV8825 driver is good for 1.5A coil current without a heat sink and active (fan) cooling. 2.2A with a heat sink and fan cooling.

TB6600 is good for up to 4A.

What is the coil current spec. for your stepper?

You might want to investigate the MobaTools stepper library. It uses acceleration and may be easier for you to use. The library is available via the IDE library manager.

1 Like

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