Help with Arduino idexer

Home Model Engine Machinist Forum

Help Support Home Model Engine Machinist Forum:

This site may earn a commission from merchant affiliate links, including eBay, Amazon, and others.
Sorry guys to be a dunce here, as I am electronically challenged
So is there a way to round off counts and still get back to exactly 360 ?
It sounds like there is no "sure Fire" method
I cut gears manually , but have a Arduino powered Indexing head (80/1) set up
but the old Fellows ( great Guy, rest his soul) program is not working so I need to update
Rich
Basically the solution was given by awake in post number #55.

I think of it like a dividing head with only one dividing plate. (steps per revolution on the motor beeing the holes).
  • The Plate in our example has 200 holes,
  • The indexer has a 40:1 ratio. That makes a total of 8000 holes for a full 360°
  • For 36 divisions you would have to move the handle 222.222... holes. This is impossible, you must put your plunger in one hole and cannot adjust somewhere next to it. So you can only move it 222 (or 223) holes.
  • The error of one hole off from the correct solution cannot be eliminated, but this is probably acceptable
  • After 36x222 holes we are at 7992 holes, so 8 holes short
  • The program is adding one hole, whenever the missing amount is large enough. In total out of 36 tooth spacings, 28 will be 222 steps and 8 will be 223 steps.

I hope that helps you as much as myself to understand what is going on.

Now the program needs to be modified, using awakes instruction. :cool:

@Richard Carlstedt , if you are comfortable with updating your arduino then you can already try the program that I posted in #54, at least it works for Mike.
It is working in a similar fashion, using different variable types, but should be usable until something better is available.

Greetings Timo
 
Timo,
Thanks for explaining this so every one can understand whats going on here. I just looked at the spreadsheet I worked on Sunday: A 42 tooth gear would have been off 40 holes in the 200 hole dividing plate you just described above. 16,0000/42=380.952380 steps needed, using only 380 steps 42 times would leave 40 holes short of 360. The original sketch did use 381 steps which only came up 2 steps long. Not sure how to put the new corrected code into the original sketch to see if makes it work better. The thing I'm surprised about is there are literally 100's of posts about this on HMEM and other places & I'm not sure that any of them actually worked correctly 🤔. Maybe no one used a dial indicator to check the accuracy like I have been doing??. After playing around with the fix you sent me on Monday I can go through many complete 360 degree revolutions on my stepper motor & my dial indicator (set on a 2" radius from the motor centerline) reads "zero" every time. (Provided I reset the entire circuit before I start). I'm glad this is getting some attention.
 
Last edited:
Actually the problem was described in the thread "Arduino rotary indexer for dummies", but I could not find any post of a stabe software for the arduino that had a stable (working with any given numbers) "fix" for it. Some people realized limitations, and seemed to have lived with them, by using uncritical numbers.

I must say on the mentioned thread, some of the older external links to google drive etc. are out of work, so there maybe some older versions that were catching it and worked stable. I also did not read through all the program versions I came accross.

Greetings Timo
 
Last edited:
L98, that is what happens in the code that Timo and I discussed above. By keeping all calculations as integers, and keeping up with the remainder, the code snippets Timo and I included above are guaranteed to come back to zero exactly. The "extra" steps will go in at regular intervals (as regular as possible). The result is that the maximum error at any given time would be no more than +/- .5 steps.

If you want to see how this looks in action, take a look at the spreadsheet that I attached a few posts above - it simulates the code that I posted, showing how it will occasionally insert the extra step.
 
L98, that is what happens in the code that Timo and I discussed above. By keeping all calculations as integers, and keeping up with the remainder, the code snippets Timo and I included above are guaranteed to come back to zero exactly. The "extra" steps will go in at regular intervals (as regular as possible). The result is that the maximum error at any given time would be no more than +/- .5 steps.

If you want to see how this looks in action, take a look at the spreadsheet that I attached a few posts above - it simulates the code that I posted, showing how it will occasionally insert the extra step.
@L98 you can find a "sort of working" arduino code in Post #54 as zip. But I think it should be replaced and tidied up a bit.
in post #57 awake provided an excel sheet that shows what the program calculates. (sort of a simulation of his example code from post #55.

Have fun!

*do not trust software, further than you can throw a Miele washdryer.
 
It seems the program also allows to enter angle increments (with two digits?).

When trying to use the same variables for both situations I am getting stuck.
 
That's exactly what Timo accomplished on Monday with his revised sketch, find it earlier in this thread.
Hallo Mike N,

I tried this, My turntable is 1:36. An intermediate drive It has a gear ratio of 1:60. If you can, try it.

Code:

/* 4x4 matrix keypad amd a 20 x 4 LCD. From Bruce.

Arduino Rotary Table for Dummies

A4988 Stepstick/Pololu driver 5/2/2015
*/

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <Keypad.h>

const byte ROWS = 4;
const byte COLS = 4;
char keys[ROWS][COLS] = {
{'1','2','3','A'},
{'4','5','6','B'},
{'7','8','9','C'},
{'.','0','#','D'}
};

byte rowPINS[ROWS] = {11,10,9,8};
byte colPINS[COLS] = {7,6,5,4};

Keypad kpd = Keypad(makeKeymap(keys),rowPINS,colPINS, ROWS, COLS);

LiquidCrystal_I2C lcd(0x27,20,4); // set the LCD address to 0x20 for a 16 chars and 4 line display
// SCL - A5, SDA - A4, VCC - +5, Gnd - Gnd
//setup vars
const int stp = 2; // connect pin D2 to step
const int dir = 3; // connect pin D3 to dir
const int StepsPerRotation = 400; // Steps per rotation of stepper NOTE the driver is set to Half step
const int TableRatio = 90; // 36 ratio of rotary table
// ***************************************************************************************************
const float Multiplier = 60.0000; //(StepsPerRotation * TableRatio)/360; // 400*90=36000/360 = 100

/*Use the following Multipliers for the indicated ratios
100 to 1 = 111.1111
90 to 1 = 100
72 to 1 = 80.00
60 to 1 = 66.6667
40 to 1 = 44.4444
36 to 1 = 40.0000
32 to 1 = 35.55556
8 to 1 = 8.8889
4 to 1 = 4.4444

*/
// ***************************************************************************************************
const int stepdelay = 1;
float Degrees = 0; // Degrees from Serial input
float ToMove = 0; // Steps to move
float bob = 0;
int cho = 0;

void setup()
{
lcd.init(); // initialize the lcd
pinMode(stp, OUTPUT);
pinMode(dir, OUTPUT);

// Print welcome message to the LCD.

lcd.backlight();
lcd.print("Rotary Table Control");
lcd.setCursor(4,2);
lcd.print(" ");
lcd.setCursor(3,3);
lcd.print("90-1 Sep 2021");
delay(2000);
lcd.init();
cho = 0;
char key = kpd.getKey();
lcd.print("Enter Selection:");
lcd.setCursor(0,1);
lcd.print("Degrees = A");
lcd.setCursor(0,2);
lcd.print("Divisions = B");
lcd.setCursor(0,3);
lcd.print("JOG = C");
while(cho == 0)
{
key = kpd.getKey();
switch (key)
{
case NO_KEY:
break;
case 'A':
Degrees=getdegrees();
lcd.clear();
cho = 1;
break;
case 'B':
Degrees=getdivisions();
cho=2;
break;
case 'C':
Degrees=getjog();
lcd.clear();
cho=3;
break;
} // end case
} // end while cho=0
} // end setup

void loop() // MAIN LOOP
{
lcd.clear();
char key = kpd.getKey();
bob = 0;
lcd.setCursor(7,0);lcd.print("Total: ");lcd.print(bob,2); // total steps
lcd.setCursor(0,3);lcd.print("FOR=A REV=B X=C");
while(key != 'C') // C will return to start menu
{
lcd.setCursor(0,0);lcd.print(abs(Degrees),2);lcd.print((char)223);
key = kpd.getKey();
if(key == 'A') // FORWARD
{
bob = bob + Degrees;
ToMove = (Degrees*Multiplier);
digitalWrite(dir, LOW);
printadvance();
}
if(key=='B') // REVERSE
{
bob = bob - Degrees;
ToMove = (Degrees*Multiplier);
digitalWrite(dir, HIGH); // pin 13
printadvance();
}
} // end while not C loop
lcd.init();
setup();
} // end main VOID

float getjog()
{
float Degrees = 0;
float num = 0.00;
char key = kpd.getKey();
lcd.clear();
lcd.setCursor(6,0);lcd.print("Jogging");
lcd.setCursor(0,1);lcd.print("A=1 B=10 C=100 Steps");
lcd.setCursor(0,2);lcd.print("Enter Degrees:");lcd.setCursor(0,3);lcd.print("OK = # ");lcd.print((char)60);lcd.print((char)45);lcd.print(" D");

while(key != '#')
{
switch (key)
{
case NO_KEY:
break;
case 'A':
Degrees = 1;
lcd.setCursor(14,2);lcd.print(Degrees);
break;
case 'B':
Degrees = 10;
lcd.setCursor(14,2);lcd.print(Degrees);
break;
case 'C':
Degrees = 100;
lcd.setCursor(14,2);lcd.print(Degrees);
break;
case 'D':
num=0.00;
lcd.setCursor(14,2);lcd.print(" ");
lcd.setCursor(14,2);
break;
}
key = kpd.getKey();
}
return Degrees;
}

float getdivisions()
{
float Degrees = 0;
float num = 0.00;
char key = kpd.getKey();
lcd.clear();
lcd.setCursor(0,1);lcd.print("Enter Division:");lcd.setCursor(0,3);lcd.print("OK = # ");lcd.print((char)60);lcd.print((char)45);lcd.print(" D");
lcd.setCursor(16,1);

while(key != '#')
{
switch (key)
{
case NO_KEY:
break;

case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
num = num * 10 + (key - '0');
lcd.print(key);
break;

case 'D':
num=0.00;
lcd.setCursor(16,1);lcd.print(" ");
lcd.setCursor(16,1);
break;
}
Degrees = 360/num;
key = kpd.getKey();
}
return Degrees; //num;
}

float getdegrees()
{
//int key = 0;
float num = 0.00;
float decimal = 0.00;
float decnum = 0.00;
int counter = 0;
lcd.clear();
//lcd.init();
char key = kpd.getKey();
lcd.setCursor(0,1);lcd.print("Enter Degrees:");lcd.setCursor(0,3);lcd.print("OK = # ");lcd.print((char)60);lcd.print((char)45);lcd.print(" D");
lcd.setCursor(15,1);
bool decOffset = false;

while(key != '#')
{
switch (key)
{
case NO_KEY:
break;

case '.':
if(!decOffset)
{
decOffset = true;
}
lcd.print(key);
break;

case 'D':
num=0.00;
lcd.setCursor(15,1);lcd.print(" ");
lcd.setCursor(15,1);
break;

case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
if(!decOffset)
{
num = num * 10 + (key - '0');
lcd.print(key);
}
else if((decOffset) && (counter <= 1))
{
num = num * 10 + (key - '0');
lcd.print(key);
counter++;
}
break;
} //end case
decnum = num / pow(10, counter);
key = kpd.getKey();
} //end while not #
return decnum;
} // end getdegrees

void printadvance() // print function
{
lcd.setCursor(6,1);lcd.print("Moving");
lcd.setCursor(4,2);lcd.print("Steps ");lcd.print(ToMove,0);
lcd.setCursor(13,0);lcd.print(bob,2);
rotation(ToMove,0);
lcd.setCursor(6,1);lcd.print(" ");
}

void rotation(long tm, int d)
{
for(long i = 0; i < tm; i++) // Problem Fix
{
digitalWrite(stp, HIGH);
delay(stepdelay);
digitalWrite(stp, LOW);
delay(stepdelay);
}
}

void software_Reset() // Restarts program from beginning but does not reset the peripherals and registers
{
asm volatile (" jmp 0");
}

Regards, Imre
 
It seems the program also allows to enter angle increments (with two digits?).

When trying to use the same variables for both situations I am getting stuck
It seems the program also allows to enter angle increments (with two digits?).

When trying to use the same variables for both situations I am getting stuck.
Yes, you can enter angles with 2 digits after the decimal. If you ask for 45 degrees you get it, if you want 44.4444 it gives 44.44
The equal divisions of 360 degrees are more important for my application.
 
Hallo Mike N,

I tried this, My turntable is 1:36. An intermediate drive It has a gear ratio of 1:60. If you can, try it.

Code:

/* 4x4 matrix keypad amd a 20 x 4 LCD. From Bruce.

Arduino Rotary Table for Dummies

A4988 Stepstick/Pololu driver 5/2/2015
*/

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <Keypad.h>

const byte ROWS = 4;
const byte COLS = 4;
char keys[ROWS][COLS] = {
{'1','2','3','A'},
{'4','5','6','B'},
{'7','8','9','C'},
{'.','0','#','D'}
};

byte rowPINS[ROWS] = {11,10,9,8};
byte colPINS[COLS] = {7,6,5,4};

Keypad kpd = Keypad(makeKeymap(keys),rowPINS,colPINS, ROWS, COLS);

LiquidCrystal_I2C lcd(0x27,20,4); // set the LCD address to 0x20 for a 16 chars and 4 line display
// SCL - A5, SDA - A4, VCC - +5, Gnd - Gnd
//setup vars
const int stp = 2; // connect pin D2 to step
const int dir = 3; // connect pin D3 to dir
const int StepsPerRotation = 400; // Steps per rotation of stepper NOTE the driver is set to Half step
const int TableRatio = 90; // 36 ratio of rotary table
// ***************************************************************************************************
const float Multiplier = 60.0000; //(StepsPerRotation * TableRatio)/360; // 400*90=36000/360 = 100

/*Use the following Multipliers for the indicated ratios
100 to 1 = 111.1111
90 to 1 = 100
72 to 1 = 80.00
60 to 1 = 66.6667
40 to 1 = 44.4444
36 to 1 = 40.0000
32 to 1 = 35.55556
8 to 1 = 8.8889
4 to 1 = 4.4444

*/
// ***************************************************************************************************
const int stepdelay = 1;
float Degrees = 0; // Degrees from Serial input
float ToMove = 0; // Steps to move
float bob = 0;
int cho = 0;

void setup()
{
lcd.init(); // initialize the lcd
pinMode(stp, OUTPUT);
pinMode(dir, OUTPUT);

// Print welcome message to the LCD.

lcd.backlight();
lcd.print("Rotary Table Control");
lcd.setCursor(4,2);
lcd.print(" ");
lcd.setCursor(3,3);
lcd.print("90-1 Sep 2021");
delay(2000);
lcd.init();
cho = 0;
char key = kpd.getKey();
lcd.print("Enter Selection:");
lcd.setCursor(0,1);
lcd.print("Degrees = A");
lcd.setCursor(0,2);
lcd.print("Divisions = B");
lcd.setCursor(0,3);
lcd.print("JOG = C");
while(cho == 0)
{
key = kpd.getKey();
switch (key)
{
case NO_KEY:
break;
case 'A':
Degrees=getdegrees();
lcd.clear();
cho = 1;
break;
case 'B':
Degrees=getdivisions();
cho=2;
break;
case 'C':
Degrees=getjog();
lcd.clear();
cho=3;
break;
} // end case
} // end while cho=0
} // end setup

void loop() // MAIN LOOP
{
lcd.clear();
char key = kpd.getKey();
bob = 0;
lcd.setCursor(7,0);lcd.print("Total: ");lcd.print(bob,2); // total steps
lcd.setCursor(0,3);lcd.print("FOR=A REV=B X=C");
while(key != 'C') // C will return to start menu
{
lcd.setCursor(0,0);lcd.print(abs(Degrees),2);lcd.print((char)223);
key = kpd.getKey();
if(key == 'A') // FORWARD
{
bob = bob + Degrees;
ToMove = (Degrees*Multiplier);
digitalWrite(dir, LOW);
printadvance();
}
if(key=='B') // REVERSE
{
bob = bob - Degrees;
ToMove = (Degrees*Multiplier);
digitalWrite(dir, HIGH); // pin 13
printadvance();
}
} // end while not C loop
lcd.init();
setup();
} // end main VOID

float getjog()
{
float Degrees = 0;
float num = 0.00;
char key = kpd.getKey();
lcd.clear();
lcd.setCursor(6,0);lcd.print("Jogging");
lcd.setCursor(0,1);lcd.print("A=1 B=10 C=100 Steps");
lcd.setCursor(0,2);lcd.print("Enter Degrees:");lcd.setCursor(0,3);lcd.print("OK = # ");lcd.print((char)60);lcd.print((char)45);lcd.print(" D");

while(key != '#')
{
switch (key)
{
case NO_KEY:
break;
case 'A':
Degrees = 1;
lcd.setCursor(14,2);lcd.print(Degrees);
break;
case 'B':
Degrees = 10;
lcd.setCursor(14,2);lcd.print(Degrees);
break;
case 'C':
Degrees = 100;
lcd.setCursor(14,2);lcd.print(Degrees);
break;
case 'D':
num=0.00;
lcd.setCursor(14,2);lcd.print(" ");
lcd.setCursor(14,2);
break;
}
key = kpd.getKey();
}
return Degrees;
}

float getdivisions()
{
float Degrees = 0;
float num = 0.00;
char key = kpd.getKey();
lcd.clear();
lcd.setCursor(0,1);lcd.print("Enter Division:");lcd.setCursor(0,3);lcd.print("OK = # ");lcd.print((char)60);lcd.print((char)45);lcd.print(" D");
lcd.setCursor(16,1);

while(key != '#')
{
switch (key)
{
case NO_KEY:
break;

case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
num = num * 10 + (key - '0');
lcd.print(key);
break;

case 'D':
num=0.00;
lcd.setCursor(16,1);lcd.print(" ");
lcd.setCursor(16,1);
break;
}
Degrees = 360/num;
key = kpd.getKey();
}
return Degrees; //num;
}

float getdegrees()
{
//int key = 0;
float num = 0.00;
float decimal = 0.00;
float decnum = 0.00;
int counter = 0;
lcd.clear();
//lcd.init();
char key = kpd.getKey();
lcd.setCursor(0,1);lcd.print("Enter Degrees:");lcd.setCursor(0,3);lcd.print("OK = # ");lcd.print((char)60);lcd.print((char)45);lcd.print(" D");
lcd.setCursor(15,1);
bool decOffset = false;

while(key != '#')
{
switch (key)
{
case NO_KEY:
break;

case '.':
if(!decOffset)
{
decOffset = true;
}
lcd.print(key);
break;

case 'D':
num=0.00;
lcd.setCursor(15,1);lcd.print(" ");
lcd.setCursor(15,1);
break;

case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
if(!decOffset)
{
num = num * 10 + (key - '0');
lcd.print(key);
}
else if((decOffset) && (counter <= 1))
{
num = num * 10 + (key - '0');
lcd.print(key);
counter++;
}
break;
} //end case
decnum = num / pow(10, counter);
key = kpd.getKey();
} //end while not #
return decnum;
} // end getdegrees

void printadvance() // print function
{
lcd.setCursor(6,1);lcd.print("Moving");
lcd.setCursor(4,2);lcd.print("Steps ");lcd.print(ToMove,0);
lcd.setCursor(13,0);lcd.print(bob,2);
rotation(ToMove,0);
lcd.setCursor(6,1);lcd.print(" ");
}

void rotation(long tm, int d)
{
for(long i = 0; i < tm; i++) // Problem Fix
{
digitalWrite(stp, HIGH);
delay(stepdelay);
digitalWrite(stp, LOW);
delay(stepdelay);
}
}

void software_Reset() // Restarts program from beginning but does not reset the peripherals and registers
{
asm volatile (" jmp 0");
}

Regards, Imre
I setup my test station again & tried this sketch. I set the parameters to match my 800 steps on the driver & 40 to one ratio on my gearhead. It comes up about 3 degrees short of making a full 360 degree rotation on a 21 tooth gear division. 32,000/21=1523.8095. (missing 17 steps) because it does 21 * 1523.000. It works & made a full 360 rotation for the 20 tooth gear. (because it is divisible by 32,000/20=1600 steps per rev). I've studied this code & I don't see any where that the missing steps are accounted for?? Thanks for sharing.
 
Last edited:
It seems the program also allows to enter angle increments (with two digits?).

When trying to use the same variables for both situations I am getting stuck.
For angle inputs are we limited to 2 place decibels or could we have 3 or 4 place? I noticed that the accumulated moves on the display show 4 place decibels???
 
For angle inputs are we limited to 2 place decibels or could we have 3 or 4 place? I noticed that the accumulated moves on the display show 4 place decibels???
At the moment I feel like the 10 year old who ripped appart Grandpas old Alarm clock. No one knows if all the pieces come back together ever. No one knows what is lost :cool: .
 
For angle inputs are we limited to 2 place decibels or could we have 3 or 4 place? I noticed that the accumulated moves on the display show 4 place decibels???

Mike, in terms of input, that is purely a matter of how the software is designed. As long as the display will accommodate it, you could design the software to input any arbitrary number of decimal places.

Whether or not the system can resolve the motion to that level of precision, however, depends on the hardware design. If, for example, the hardware is set up for 8000 steps per full revolution, your finest resolution of a degree is 8000/360 = 22.22222 ... only slightly better than 5/100ths of a degree. So inputting an angle of 12.857143 won't actually give you any better result than inputting an angle of 12.86.

It is important to note that any single movement of the table - e.g., move 12.86° - will, unless it just happens to be an exact divisor of the total steps required by the hardware design, result in some error. To take the example above, a move of 12.86°, when each degree requires 22.22222 ... steps, will require 285.777777 ... steps on the stepper motor. See the problem? There is no way to give a fraction (.77777 ... ) of a step, so you have to round it. No, it doesn't get any better if you use more digits in the input; multiply 12.857143 times 22.222222 ... comes out to 285.714286 steps - still not an even number of steps, which will have to be rounded. Either one is going to round to 286 steps. That's going to leave you with an error of .013° - probably close enough for the accuracy we can achieve as hobbiests ... unless you are planning to input this same amount over and over again, each time treating it as a "single" step, with the desire to get 28 even divisions around a circle. Yes, as it happens, 360 / 28 = 12.857143.

I'm not sure how clear I have made the previous point, so let me try to sum it up this way. If you tell the software to generate 28 evenly spaced features around the circle, it can keep track of when it needs to round up and when it needs to round down, so that at the end of 28 steps it is precisely back to zero. But if you just tell the software to take a single step, 28 times, it will round up every time, so that 28 steps later, you have "overshot" zero by a few steps.

You may be wondering why the software doesn't still keep track of and compensate for the rounding error. The answer is, it could do that only if it knows that you are trying to hit 28 even divisions across a circle - in other words, if you put it in that way, rather than trying to give it a degree movement.

Yes, some of you are going to ask, "which software"? In theory, one could design the software such that it always tries to go back to zero after a series of single steps. But the best way to do that is to have a way to set the zero point, and have a button or command that returns to it. Otherwise, how is the software to know when you are at zero?
 
Mike, in terms of input, that is purely a matter of how the software is designed. As long as the display will accommodate it, you could design the software to input any arbitrary number of decimal places.

Whether or not the system can resolve the motion to that level of precision, however, depends on the hardware design. If, for example, the hardware is set up for 8000 steps per full revolution, your finest resolution of a degree is 8000/360 = 22.22222 ... only slightly better than 5/100ths of a degree. So inputting an angle of 12.857143 won't actually give you any better result than inputting an angle of 12.86.

It is important to note that any single movement of the table - e.g., move 12.86° - will, unless it just happens to be an exact divisor of the total steps required by the hardware design, result in some error. To take the example above, a move of 12.86°, when each degree requires 22.22222 ... steps, will require 285.777777 ... steps on the stepper motor. See the problem? There is no way to give a fraction (.77777 ... ) of a step, so you have to round it. No, it doesn't get any better if you use more digits in the input; multiply 12.857143 times 22.222222 ... comes out to 285.714286 steps - still not an even number of steps, which will have to be rounded. Either one is going to round to 286 steps. That's going to leave you with an error of .013° - probably close enough for the accuracy we can achieve as hobbiests ... unless you are planning to input this same amount over and over again, each time treating it as a "single" step, with the desire to get 28 even divisions around a circle. Yes, as it happens, 360 / 28 = 12.857143.

I'm not sure how clear I have made the previous point, so let me try to sum it up this way. If you tell the software to generate 28 evenly spaced features around the circle, it can keep track of when it needs to round up and when it needs to round down, so that at the end of 28 steps it is precisely back to zero. But if you just tell the software to take a single step, 28 times, it will round up every time, so that 28 steps later, you have "overshot" zero by a few steps.

You may be wondering why the software doesn't still keep track of and compensate for the rounding error. The answer is, it could do that only if it knows that you are trying to hit 28 even divisions across a circle - in other words, if you put it in that way, rather than trying to give it a degree movement.

Yes, some of you are going to ask, "which software"? In theory, one could design the software such that it always tries to go back to zero after a series of single steps. But the best way to do that is to have a way to set the zero point, and have a button or command that returns to it. Otherwise, how is the software to know when you are at zero?
Thanks for explaining this. 🙂
 
Mike, in terms of input, that is purely a matter of how the software is designed. As long as the display will accommodate it, you could design the software to input any arbitrary number of decimal places.

Whether or not the system can resolve the motion to that level of precision, however, depends on the hardware design. If, for example, the hardware is set up for 8000 steps per full revolution, your finest resolution of a degree is 8000/360 = 22.22222 ... only slightly better than 5/100ths of a degree. So inputting an angle of 12.857143 won't actually give you any better result than inputting an angle of 12.86.

It is important to note that any single movement of the table - e.g., move 12.86° - will, unless it just happens to be an exact divisor of the total steps required by the hardware design, result in some error. To take the example above, a move of 12.86°, when each degree requires 22.22222 ... steps, will require 285.777777 ... steps on the stepper motor. See the problem? There is no way to give a fraction (.77777 ... ) of a step, so you have to round it. No, it doesn't get any better if you use more digits in the input; multiply 12.857143 times 22.222222 ... comes out to 285.714286 steps - still not an even number of steps, which will have to be rounded. Either one is going to round to 286 steps. That's going to leave you with an error of .013° - probably close enough for the accuracy we can achieve as hobbiests ... unless you are planning to input this same amount over and over again, each time treating it as a "single" step, with the desire to get 28 even divisions around a circle. Yes, as it happens, 360 / 28 = 12.857143.

I'm not sure how clear I have made the previous point, so let me try to sum it up this way. If you tell the software to generate 28 evenly spaced features around the circle, it can keep track of when it needs to round up and when it needs to round down, so that at the end of 28 steps it is precisely back to zero. But if you just tell the software to take a single step, 28 times, it will round up every time, so that 28 steps later, you have "overshot" zero by a few steps.

You may be wondering why the software doesn't still keep track of and compensate for the rounding error. The answer is, it could do that only if it knows that you are trying to hit 28 even divisions across a circle - in other words, if you put it in that way, rather than trying to give it a degree movement.

Yes, some of you are going to ask, "which software"? In theory, one could design the software such that it always tries to go back to zero after a series of single steps. But the best way to do that is to have a way to set the zero point, and have a button or command that returns to it. Otherwise, how is the software to know when you are at zero?
To improve accuracy one may need to change the hardware to help the software? The 2-phase 0.9° stepper motor and the 3-phase 1.2° stepper motor are especially suitable for applications that require higher accuracy. But that also changes the simplicity of using the arduino ?
 
To improve accuracy one may need to change the hardware to help the software? The 2-phase 0.9° stepper motor and the 3-phase 1.2° stepper motor are especially suitable for applications that require higher accuracy. But that also changes the simplicity of using the arduino ?

Certainly, every increase in the number of steps available will provide a corresponding increase in the accuracy. One way to increase the available steps is to get a .9° stepper motor (400 steps per revolution); another is to half- or micro-step (with some loss of torque, so may need to beef up the stepper motor). Yet another is to further increase the ratio of the drive, from 40:1 to 90:1 or better. Each of these comes with tradeoffs; for the mechanical ratios, one must take backlash into account.

I am contemplating a design that will use a 1.8° stepper motor (200 steps), with a 3:1 belt drive, driving a 60:1 table. This will result in 36000 steps per revolution, allowing for .01° accuracy before any half- or micro-stepping.
 
Certainly, every increase in the number of steps available will provide a corresponding increase in the accuracy. One way to increase the available steps is to get a .9° stepper motor (400 steps per revolution); another is to half- or micro-step (with some loss of torque, so may need to beef up the stepper motor). Yet another is to further increase the ratio of the drive, from 40:1 to 90:1 or better. Each of these comes with tradeoffs; for the mechanical ratios, one must take backlash into account.

I am contemplating a design that will use a 1.8° stepper motor (200 steps), with a 3:1 belt drive, driving a 60:1 table. This will result in 36000 steps per revolution, allowing for .01° accuracy before any half- or micro-stepping.
"Each of these comes with tradeoffs; for the mechanical ratios, one must take backlash into account."

I agree wholeheartedly that is why it changes the simplicity of using the arduino uno a 8 bit micro to a AVR or PIC 16 / 32 bit microprocessor. (Using a incremental rotary encoder) Which I believe is way above the original scope of arduino rotary table for dummies.
Well that's my two cents worth back to machining.
Keep us posted on your build.
 
Update:
The sketch that Timo posted here #54 completely solved the missing steps problem. The rotation always comes back to "zero" regardless of the number of divisions. Problem solved! Timo is working out a few bugs and making improvements to the angular portion of the sketch. Once the sketch is ready I'm sure it will be posted in this thread. Thanks for interest in this endeavor!
 

Latest posts

Back
Top