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.

cwalk

Member
Joined
Mar 4, 2023
Messages
9
Reaction score
3
Location
UK
I have recently completed the Arduino indexer for dummies . When I use it to do 360 degrees it is about 2 to 3 degrees short and this is cumulative.
My dividing head has a 40/1 worm drive and the stepper motor has 400 steps per. revolution.
Is there any way of tweaking the software to make 360 degrees actually 360 degrees? Would there be any other solution ?
I would really appreciate any help, as I have put a fair bit of wok in to modify my dividing head, and I obviously cannot use it with such a large innaccuracy.

Many thanks in anticipation, Colin.
 
How do you control the stepper motor? Often that is done with software. That is where you would need to make adjustments to make the indexer accurate.
Tell us a bit about how you control so we have an idea of how to make changes.
 
How do you control the stepper motor? Often that is done with software. That is where you would need to make adjustments to make the indexer accurate.
Tell us a bit about how you control so we have an idea of how to make changes.
Thank you for your prompt reply,
The stepper motor is controlled by the Arduino sketch, provided by bmac2 in Rotary table indexer for dummies. I have absolutely no idea about Arduino sketches, i.e. a dummy. I followed the instructions by numbers, and it does work, but not accurately. I have tried altering the gear ratio in the sketch several times, but this does not help. I am using a 200 step motor on half steps, 400 steps per revolution, and the gear ratio is 40/1 (worm and wheel). I hope this helps, cwalk.
 
If the error you get is exactly the same every time, it could be a software issue but since other people have not come in with the same complaint I'm guessing it isn't that. Something that can give that kind of error that is close but not exactly the same every time is a stepper motor that skips steps. This can be caused by a mechanical problem like a sticky spot in the rotation or an electrical problem.

I made a mini mill into a CNC mill and it would be accurate most of the time. However it would sometimes skip a step or maybe a few in a row. I found that the driver wasn't giving it sufficient power. Trying to increase the amperage caused worse problems. Ah, the stepper motor driver chip was overheating and stopping the output for a few milliseconds as it cooled. Power is a factor of amperage and voltage so instead of increasing the amperage, I increase the voltage of the power supply and my problem disappeared.

They say a picture is worth a thousand words. If you can post a picture of the setup including the power supply, the Arduino, and the stepper motor driver it will help.
 
If the error you get is exactly the same every time, it could be a software issue but since other people have not come in with the same complaint I'm guessing it isn't that. Something that can give that kind of error that is close but not exactly the same every time is a stepper motor that skips steps. This can be caused by a mechanical problem like a sticky spot in the rotation or an electrical problem.

I made a mini mill into a CNC mill and it would be accurate most of the time. However it would sometimes skip a step or maybe a few in a row. I found that the driver wasn't giving it sufficient power. Trying to increase the amperage caused worse problems. Ah, the stepper motor driver chip was overheating and stopping the output for a few milliseconds as it cooled. Power is a factor of amperage and voltage so instead of increasing the amperage, I increase the voltage of the power supply and my problem disappeared.

They say a picture is worth a thousand words. If you can post a picture of the setup including the power supply, the Arduino, and the stepper motor driver it will help.
 
Thank you for your comments.
I have checked the wiring, all good, and tried a different stepper motor. The results were exactly the same, a 3 degree shortfall in 360 degrees.
I feel it must be an error in the Arduino sketch somewhere, but I don't have the expertise to find it.
 
Hi Colin - can you link to the exact version of the Arduino sketch that you downloaded please? Happy to have a look and see if I can find anything.
Also details of your exact setup would be helpful!
Cheers - Andrew
 
Hi Colin - can you link to the exact version of the Arduino sketch that you downloaded please? Happy to have a look and see if I can find anything.
Also details of your exact setup would be helpful!
Cheers - Andrew
Thank tou Andrew for your reply.
The setup is exactly as bmac2 describes in the article Rotary indexer for Dummies on this website. I have followed the instruction, as i am not arduino
savvy. The arduino sketch is towards the end of the article. Apart from altering the gear ratio, ( 40/1 worm and wheel,) everything is as the article.
Thank you for your kind offer of help. Colin
 
Looks to me like the issue is here
const int Multiplier = (StepsPerRotation * TableRatio)/360; // 200*90=18000/360 = 50
The assumption is made that this is going to come out to an even integer value, and is assigned to an int. That's not the case. I suspect changing it to read
const float Multiplier = (StepsPerRotation * TableRatio)/360; // 200*90=18000/360 = 50
will fix the issue with the precision. Hopefully it doesn't cause you any other troubles in the code.
 
Hi Colin - please try tiger12506's suggestion. The trouble is likely to be that in your setup the Multiplier calculation is:

Multiplier = (400 * 40) / 360 which works out to 44.444444

but the sketch is assigning that to an "int" (integer), so all it stores is 44. In bMac's original setup with the 90:1 table the calculation gives a integer result as tiger12560 shows, so the problem is less obvious.

(The reason I was asking for a link to the sketch is that there were multiple revsions of it as I recall, but I may be confused with another project. I actually re-wrote the whole sketch for myself, mainly as an exercise in Arduino coding but also because I found the original sketch a bit confusing!)

Keep us posted, eh?

Cheers - Andrew
 
Hi Colin - please try tiger12506's suggestion. The trouble is likely to be that in your setup the Multiplier calculation is:

Multiplier = (400 * 40) / 360 which works out to 44.444444

but the sketch is assigning that to an "int" (integer), so all it stores is 44. In bMac's original setup with the 90:1 table the calculation gives a integer result as tiger12560 shows, so the problem is less obvious.

(The reason I was asking for a link to the sketch is that there were multiple revsions of it as I recall, but I may be confused with another project. I actually re-wrote the whole sketch for myself, mainly as an exercise in Arduino coding but also because I found the original sketch a bit confusing!)

Keep us posted, eh?

Cheers - Andrew
Do a browser search on "Stepper Motor Error" to find out more about this problem.
 
I also built one of these. I also found the error problem. However, this may help and I believe that it was posted on this forum:

The attached file contains the arduino sketch I wrote for my dividing head. The math algorithm is written to assure that the 0 (zero) location always winds up at the same point of rotation. As it moves, it recalculates the position from zero so no matter how many times it goes around or back and forth, it maintains positional integrity. The algorithm should work for your rotary table as well.
Chuck Fellows



Arduino Rotary Table for Dummies
 
I also built one of these. I also found the error problem. However, this may help and I believe that it was posted on this forum:

The attached file contains the arduino sketch I wrote for my dividing head. The math algorithm is written to assure that the 0 (zero) location always winds up at the same point of rotation. As it moves, it recalculates the position from zero so no matter how many times it goes around or back and forth, it maintains positional integrity. The algorithm should work for your rotary table as well.
Chuck Fellows
Thanks for your reply, I have downloaded the file, but when I open it my Arduino IDE says the main file is missing. I would like to try this sketch, if it is possible to download it, and open it fully. I am using Winzip to open zip files.
Regards Colin.
 
Hi Colin - please try tiger12506's suggestion. The trouble is likely to be that in your setup the Multiplier calculation is:

Multiplier = (400 * 40) / 360 which works out to 44.444444

but the sketch is assigning that to an "int" (integer), so all it stores is 44. In bMac's original setup with the 90:1 table the calculation gives a integer result as tiger12560 shows, so the problem is less obvious.

(The reason I was asking for a link to the sketch is that there were multiple revsions of it as I recall, but I may be confused with another project. I actually re-wrote the whole sketch for myself, mainly as an exercise in Arduino coding but also because I found the original sketch a bit confusing!)

Keep us posted, eh?

Cheers - Andrew

Thanks everyone for yor help. I finally stumbled on a way to correct the innaccuracy. This was by trial and lots of error. I tweaked the table ratio in the sketch by about+0 .15, and changed the Ints to float for the ratio and multiplier. I fastened a digital protractor to the faceplate of the dividing head, and this repeatedly returned to zero, after several turns of the disc. So, thanks once again for all your suggestions, best wishes with all your projects, Colin.
 
Hi, cwalk. can i ask you to upload your code.

Regards, Imre

Hello Imre, This is the code which I used. Hope it is useful to you.
Regards Colin
/*
4x4 matrix keypad amd a 20 x 4 LCD.
Edit StepsPerRotation & TableRatio(# of turns for 360 degrees)in line 29
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 2 to step
const int dir = 3; // connect pin 3 to dir
const int StepsPerRotation = 400; // Set Steps per rotation of stepper NOTE the driver is set to Half step
const float TableRatio = 39.9999; // ratio of rotary table
const float Multiplier = (StepsPerRotation * TableRatio)/360; // 400*39.9999=15999.96/360 = 44.444333
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("updated 2016");
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(float tm, int d)
{
for(int i = 0; i < tm; i++)
{
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");
}
 
Hello Imre, This is the code which I used. Hope it is useful to you.
Regards Colin
/*
4x4 matrix keypad amd a 20 x 4 LCD.
Edit StepsPerRotation & TableRatio(# of turns for 360 degrees)in line 29
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 2 to step
const int dir = 3; // connect pin 3 to dir
const int StepsPerRotation = 400; // Set Steps per rotation of stepper NOTE the driver is set to Half step
const float TableRatio = 39.9999; // ratio of rotary table
const float Multiplier = (StepsPerRotation * TableRatio)/360; // 400*39.9999=15999.96/360 = 44.444333
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("updated 2016");
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(float tm, int d)
{
for(int i = 0; i < tm; i++)
{
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");
}
cwalk Thanks, "ino" translated it flawlessly. I can test it at the end of the week. I am reporting my experience. My board is 1:36 with a little modification it will be good. All the best From Hungary.
 
Last edited:

Latest posts

Back
Top