Stepper motor step accuracy

Hi ,

I need help about stepper motors and arranging exact steps that we want. I'm using it for color sorter project, in sorter part.

I have 200 steps Nema 10v bipolar stepper and arduino rev 3 official motor shield. These are hardwares that I used, without heating problem I don't have any problem with them.

I want to turn stepper 25 steps(45 degree) and wait half second and another 25 steps and another delay in my loop function.

In stepper.h library there is a function which called ".step(Float stepnumber)" I'm using it in my loop but it doesn't work stable. It's not doing 25 steps each time, sometimes 26 sometimes 24, less or more. I put a video of error below. You will understand what I actually mean.

View My Video

I guess I need to use that kind of structure to make sure if it's range of tollarance or not: if(abs(pos-tollerance)<=2.5&&...)

But I have never tried that kind of structure. Any help would be appreciated

A stepping motor should not skip steps, unless it is underpowered, overloaded or asked to step too quickly.

However, no one will be able to tell what the problem is, unless you supply quite a bit more information. Please post a link to the product page or details of the stepper motor, your wiring diagram, the power supply voltage and current capability, and also post your code using code tags (use the "#" button among the formatting options).

Why are you using a float when you want an integer number of steps?

...R

Thanks for quick answers guys,

Stepper:

Motor shield:

For voltage source, I've tried with 9V batery and Arduino 9v adapter.

Wiring diagram: Actually for stepper I didn't to extra wiring without connecting cables on shield A and B as figure:

Currently I'm using different kind of stepper movement to give project but this is the old code that I faced with 45 degree angle continues

//Boran KARADUMAN Color Sorter Project
//**************************************** LIBRARIES ***************************************
#include <Average.h> // See http://playground.arduino.cc/Main/Average
#include <Servo.h>
#include <Stepper.h>
//************************************ GLOBAL VARIABLES ************************************
//Sensor variables
int S0=1,S1=7,S2=6,S3=5, LED=4; 
int OUT=2;
//Servo and stepper Variables
Servo servo360;
int cpos=0;
int abc;
const int pwmA = 3;
const int pwmB = 11;
const int brakeA = 9;
const int brakeB = 8;
const int dirA = 12;
const int dirB = 13;
const int STEPS = 25; // 360 / stepAngle
// Initialize the Stepper class
Stepper myStepper(STEPS, dirA, dirB);

void setup() {
  Serial.begin(9600);
  TCS3200_Setup();
  servo360.attach(10); 
  delay(100);
  myStepper.setSpeed(250);

  // Turn on pulse width modulation
  pinMode(pwmA, OUTPUT);
  digitalWrite(pwmA, HIGH);
  pinMode(pwmB, OUTPUT);
  digitalWrite(pwmB, HIGH);

  // Turn off the brakes
  pinMode(brakeA, OUTPUT);
  digitalWrite(brakeA, LOW);
  pinMode(brakeB, OUTPUT);
  digitalWrite(brakeB, LOW);

}

void loop() {
  myStepper.step(STEPS);
  delay(250);
  Serial.println(ReadColor()); 
  servoDrive(abc); 
  delay(250);

}

void TCS3200_Setup() {
  pinMode(S0,OUTPUT); 
  pinMode(S1,OUTPUT); 
  pinMode(S2,OUTPUT); 
  pinMode(S3,OUTPUT); 
  pinMode(LED,OUTPUT); 
  pinMode(OUT,INPUT); 
}

void TCS3200_On() {
  digitalWrite(LED,HIGH); // Switch LED on
  digitalWrite(S0,HIGH); //Output frequency scaling (100%)
  digitalWrite(S1,HIGH);
  delay(5);
}

void TCS3200_Off() {
  digitalWrite(LED,LOW); // Switch LED off
  digitalWrite(S0,LOW); //Power off sensor
  digitalWrite(S1,LOW);
}

void NoFilter() { //Select no filter
  digitalWrite(S2,HIGH); 
  digitalWrite(S3,LOW);
  delay(5);
}

void RedFilter() { //Select red filter
  digitalWrite(S2,LOW); 
  digitalWrite(S3,LOW);
  delay(5);
}

void GreenFilter() { //Select green filter
  digitalWrite(S2,HIGH); 
  digitalWrite(S3,HIGH);
  delay(5);
}

void BlueFilter() { //Select blue filter
  digitalWrite(S2,LOW); 
  digitalWrite(S3,HIGH);
  delay(5);
}

char* ReadColor() { //0=yellow, 1=red, 2=green, 3=blue, 4=object out of range
  float FrequencyClear,FrequencyRed,FrequencyGreen,FrequencyBlue;
  int PercentageRed,PercentageGreen,PercentageBlue;
  TCS3200_On();
  NoFilter();
  FrequencyClear=500.0/pulseIn(OUT,LOW,10000); // Frequency in kHz
  RedFilter();
  FrequencyRed=500.0/pulseIn(OUT,LOW,10000); // Frequency in kHz
  GreenFilter();
  FrequencyGreen=500.0/pulseIn(OUT,LOW,10000); // Frequency in kHz
  BlueFilter();
  FrequencyBlue=500.0/pulseIn(OUT,LOW,10000); // Frequency in kHz
  TCS3200_Off();
  //Output frequency blue, green, red percentage represents the ratio of the 
  //respective color to the Clear channel absolute value:
  PercentageRed=int((FrequencyRed/FrequencyClear)*100.0);
  PercentageGreen=int((FrequencyGreen/FrequencyClear)*100.0);
  PercentageBlue=int((FrequencyBlue/FrequencyClear)*100.0);
  //Learned blue, green, red percentage values of different colors
  int SavedColorRed[] = {42,50,19,13}; 
  int SavedColorGreen[] = {30,22,45,26};
  int SavedColorBlue[] = {20,30,36,58};
  char* GetColor[] = {"yellow","red","green","blue",""};
  int ColorArray[3];
  int i_color; 
  int ClosestColor;
  int MaxDiff;
  int MinDiff=300;
  if(FrequencyClear<1.5){ClosestColor=4; 
   }// Object out of range
  else {
    for (i_color=0; i_color<4; i_color++) { //Find closest color
      ColorArray[0]=abs(SavedColorRed[i_color]-PercentageRed);
      ColorArray[1]=abs(SavedColorGreen[i_color]-PercentageGreen);
      ColorArray[2]=abs(SavedColorBlue[i_color]-PercentageBlue);
      MaxDiff=maximum(ColorArray,3);
      if (MaxDiff<MinDiff) {
        MinDiff=MaxDiff;
        ClosestColor=i_color;
        abc=i_color;
       }
     }
   }
   return GetColor[ClosestColor];  
} 

void servoDrive(int curr){
    switch(curr){
      case 0: 
      servo360.write(15);
         break;
      case 1:
      servo360.write(60);
         break;
    case 2:
      servo360.write(105);
         break;
    case 3:
      servo360.write(145);
         break;
     default:  ;}
}

@Robin2

I wanted to make sure to give 25.0 value as a step. But even int I was confronting same problem.

And here is the video and code of last version of project.

In here I'm using stepper as a servo, first 45 degree, than another 45 degree, finaly 90 degree back. It still has little errors but when it go opposite direction, fixing little error.

Sorry about my english btw.

Video:http://tinypic.com/player.php?v=250nux2>&s=8#.U3OFY_l_tZ5

Code:

//Boran KARADUMAN Color Sorter Project
//**************************************** LIBRARIES ***************************************
#include <Average.h> // See http://playground.arduino.cc/Main/Average
#include <Servo.h>
#include <Stepper.h>
//************************************ GLOBAL VARIABLES ************************************
//Sensor variables
int S0=1,S1=7,S2=6,S3=5, LED=4; 
int OUT=2;
//Servo and stepper Variables
Servo servo360;
int cpos=0;
int abc;
int check1=0;
int check2 ;
int check3;
const int pwmA = 3;
const int pwmB = 11;
const int brakeA = 9;
const int brakeB = 8;
const int dirA = 12;
const int dirB = 13;
const int STEPS = 25; // 360 / stepAngle
// Initialize the Stepper class
Stepper myStepper(STEPS, dirA, dirB);

void setup() {
  Serial.begin(9600);
  TCS3200_Setup();
  servo360.attach(10); 
  delay(100);
  myStepper.setSpeed(300);

  // Turn on pulse width modulation
  pinMode(pwmA, OUTPUT);
  digitalWrite(pwmA, HIGH);
  pinMode(pwmB, OUTPUT);
  digitalWrite(pwmB, HIGH);

  // Turn off the brakes
  pinMode(brakeA, OUTPUT);
  digitalWrite(brakeA, LOW);
  pinMode(brakeB, OUTPUT);
  digitalWrite(brakeB, LOW);

}

void loop() {
  Serial.println(check1);
  Serial.println(check2);
  Serial.println(check3);
  
  myStepper.step(STEPS);  
  delay(250);
  Serial.println(ReadColor());  
  servoDrive(abc); 
  delay(500);
  myStepper.step(STEPS);
  delay(125);
  myStepper.step(-STEPS*2);
  delay(500);

}

void TCS3200_Setup() {
  pinMode(S0,OUTPUT); 
  pinMode(S1,OUTPUT); 
  pinMode(S2,OUTPUT); 
  pinMode(S3,OUTPUT); 
  pinMode(LED,OUTPUT); 
  pinMode(OUT,INPUT); 
}

void TCS3200_On() {
  digitalWrite(LED,HIGH); // Switch LED on
  digitalWrite(S0,HIGH); //Output frequency scaling (100%)
  digitalWrite(S1,HIGH);
  delay(5);
}

void TCS3200_Off() {
  digitalWrite(LED,LOW); // Switch LED off
  digitalWrite(S0,LOW); //Power off sensor
  digitalWrite(S1,LOW);
}

void NoFilter() { //Select no filter
  digitalWrite(S2,HIGH); 
  digitalWrite(S3,LOW);
  delay(5);
}

void RedFilter() { //Select red filter
  digitalWrite(S2,LOW); 
  digitalWrite(S3,LOW);
  delay(5);
}

void GreenFilter() { //Select green filter
  digitalWrite(S2,HIGH); 
  digitalWrite(S3,HIGH);
  delay(5);
}

void BlueFilter() { //Select blue filter
  digitalWrite(S2,LOW); 
  digitalWrite(S3,HIGH);
  delay(5);
}

char* ReadColor() { //0=white, 1=orange, 2=yellow, 3=red, 4=green, 5=blue, 6=object out of range
  float FrequencyClear,FrequencyRed,FrequencyGreen,FrequencyBlue;
  int PercentageRed,PercentageGreen,PercentageBlue;
  TCS3200_On();
  NoFilter();
  FrequencyClear=500.0/pulseIn(OUT,LOW,10000); // Frequency in kHz
  RedFilter();
  FrequencyRed=500.0/pulseIn(OUT,LOW,10000); // Frequency in kHz
  GreenFilter();
  FrequencyGreen=500.0/pulseIn(OUT,LOW,10000); // Frequency in kHz
  BlueFilter();
  FrequencyBlue=500.0/pulseIn(OUT,LOW,10000); // Frequency in kHz
  TCS3200_Off();
  //Output frequency blue, green, red percentage represents the ratio of the 
  //respective color to the Clear channel absolute value:
  PercentageRed=int((FrequencyRed/FrequencyClear)*100.0);
  PercentageGreen=int((FrequencyGreen/FrequencyClear)*100.0);
  PercentageBlue=int((FrequencyBlue/FrequencyClear)*100.0);
  
     check1=PercentageRed;
   check2=PercentageGreen;
   check3=PercentageBlue;
   
  //Learned blue, green, red percentage values of different colors
  int SavedColorRed[] = {42,50,30,20}; 
  int SavedColorGreen[] = {36,20,45,26};
  int SavedColorBlue[] = {16,25,28,40};
  char* GetColor[] = {"yellow","red","green","blue",""};
  int ColorArray[3];
  int i_color; 
  int ClosestColor;
  int MaxDiff;
  int MinDiff=300;
  if(FrequencyClear<1.5)ClosestColor=4; // Object out of range
  else {
    for (i_color=0; i_color<4; i_color++) { //Find closest color
      ColorArray[0]=abs(SavedColorRed[i_color]-PercentageRed);
      ColorArray[1]=abs(SavedColorGreen[i_color]-PercentageGreen);
      ColorArray[2]=abs(SavedColorBlue[i_color]-PercentageBlue);
      MaxDiff=maximum(ColorArray,3);
      if (MaxDiff<MinDiff) {
        MinDiff=MaxDiff;
        ClosestColor=i_color;
        abc=i_color;
       }
     }
   }
   return GetColor[ClosestColor];  
} 

void servoDrive(int curr){
    switch(curr){
      case 1: 
      servo360.write(72);
         break;
      case 2:
      servo360.write(87);
         break;
    case 0:
      servo360.write(108);
         break;
    case 3:
      servo360.write(130);
         break;
     default:  ;}
}

Btw why moderators moved this topic also project guidience. I think my problem is about fixing stepper's steps accuracy with programing.

I wanted to make sure to give 25.0 value as a step. But even int I was confronting same problem.

Stick to ints because floats are only ever an approximation to the value. 25.0 could very well be 24.9999999234 and it could truncate rather than round.

A 9V battery can't possibly supply the ~1 ampere required by that motor in full step mode. How much current can your power supply deliver?

jremington:
A 9V battery can't possibly supply the ~1 ampere required by that motor in full step mode. How much current can your power supply deliver?

Well actually with arduino adapter I provide 12V 1.0A, are we sure that it is beacuse of the hardware?

Thanks for advice Grumpy_Mike :slight_smile:

You may want to look into the AccelStepper library. Using that library allows you to accelerate the motor from one speed to another. The motor is less likely to miss steps if accelerated. And the library allows you to use more than one stepper if needed.
http://www.airspayce.com/mikem/arduino/AccelStepper/

That power supply should work. However,

const int STEPS = 25; // 360 / stepAngle
// Initialize the Stepper class
Stepper myStepper(STEPS, dirA, dirB);
...
  myStepper.setSpeed(300);

STEPS is supposed to be the number of steps/revolution.
Can your stepper motor start from a standstill and rotate at 300 RPM? Try reducing the speed.

jremington:
That power supply should work. However,

const int STEPS = 25; // 360 / stepAngle

// Initialize the Stepper class
Stepper myStepper(STEPS, dirA, dirB);
...
 myStepper.setSpeed(300);



STEPS is supposed to be the number of steps/revolution.
Can your stepper motor start from a standstill and rotate at 300 RPM? Try reducing the speed.

I've tried different amount of speeds (more and less )but still was same but when I go to lab tomorrow will try it from standstill to 300 rpm.

@groundfungus: great command, I was trying to understand that library today. Moreover tried some speed, acceleration values. But problem, it was vibrating stepper too much, couldn't understand why. Are you good at that library? Why do you think it's vibrating too much and what should be my accel and speed values,?

  stepper.setMaxSpeed(400);
  stepper.setSpeed(400);
  
  stepper.setAcceleration(300);
  //stepper.moveTo(distance);
  
  
}

void loop(){  
 if (stepper.distanceToGo() == 0) {
    stepper.run();                   // let the AccelStepper to disable motor current after stop
    delay(500);                     // wait 2 sec in final position 
    stepper.moveTo(stepper.currentPosition()+45);
  }
  stepper.run();
}

Here is my testing values with is library.

I am certainly no expert on the accelstepper lib. I have experimented with it a bit. My suggestion would be to try different max speeds and accelerations and see where/if it smooths out.

Why do you think it's vibrating too much

Most of the vibration is caused by mechanical resonance. This can me avoided by changing the speed or by changing the motor mounting arrangements and motor coupling.