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.
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");
}
Hi, cwalk. The test was done. Board ratio 39,999 it didn't work for me (I have the good one 54). After changing the board ratio, it works flawlessly. It is likely that the 1:60 ratio interfered with the original correct step. Round table 1:36 + with belt drive 1:60 ratio.
Original: const float Multiplier = (StepsPerRotation * TableRatio)/360; // 400*39.9999=15999.96/360 = 44.444333
Own: const float Multiplier = (StepsPerRotation * TableRatio)/360; // 400*54=21600/360=60

Thanks for the help.
 
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");
}
Not sure if this is the right place to join in here? I built a Arduino Indexer using the sketch listed in this post. I cut a few gears on my 40-1 index head & I thought this would make my indexing quicker & easier. The controller works great on every division that divides to a whole # from 16,000 steps (2,4,5,8,10,16,20,25 etc). Most steps with odd numbers don’t end up making a 360 degree rotation. All of the accumulated error ends up between the first & last division. More error on some like a 21 tooth gear would end up 19 steps off from making a complete 16,000 rotation. This doesn't sound like much, however my gears will not match up with this much accumulated error. I have read several posts on HMEM that talk about this as a rounding problem. Some one had a solution to add the missing steps in the code once the error = one step?? I'm not a Arduino sketch maker, but I'm a great copycat! I wonder if anyone has a fix for this?
 
Not sure if this is the right place to join in here? I built a Arduino Indexer using the sketch listed in this post. I cut a few gears on my 40-1 index head & I thought this would make my indexing quicker & easier. The controller works great on every division that divides to a whole # from 16,000 steps (2,4,5,8,10,16,20,25 etc). Most steps with odd numbers don’t end up making a 360 degree rotation. All of the accumulated error ends up between the first & last division. More error on some like a 21 tooth gear would end up 19 steps off from making a complete 16,000 rotation. This doesn't sound like much, however my gears will not match up with this much accumulated error. I have read several posts on HMEM that talk about this as a rounding problem. Some one had a solution to add the missing steps in the code once the error = one step?? I'm not a Arduino sketch maker, but I'm a great copycat! I wonder if anyone has a fix for this?
The first possible error is setting the TableRatio to 39.99999... this should be 40.

Cheers,

Andrew in Melbourne
 
Not sure if this is the right place to join in here? I built a Arduino Indexer using the sketch listed in this post. I cut a few gears on my 40-1 index head & I thought this would make my indexing quicker & easier. The controller works great on every division that divides to a whole # from 16,000 steps (2,4,5,8,10,16,20,25 etc). Most steps with odd numbers don’t end up making a 360 degree rotation. All of the accumulated error ends up between the first & last division. More error on some like a 21 tooth gear would end up 19 steps off from making a complete 16,000 rotation. This doesn't sound like much, however my gears will not match up with this much accumulated error. I have read several posts on HMEM that talk about this as a rounding problem. Some one had a solution to add the missing steps in the code once the error = one step?? I'm not a Arduino sketch maker, but I'm a great copycat! I wonder if anyone has a fix for this?
Hello Mike,

What should we do?

the program calculates 761.9047 steps to move. (but you can only make it move 762 steps or 761 steps)
So the loop goes:
i=1; if 1 is smaller than 761.9047 then step the motor one step further and increase i by one
i=2, if 2 is smaller than 761.9047 step the motor once and increase i by one.
.
.
.
i=762 if 762 is smaller than 761.9047, OH it is bigger? then it stepped far enough;.. done.

So instead of 761.9047 it goes 761.

a) you uprgade your hardware to a finer grid, so that one missing step would not make that big of a difference :)
e.g. a DM542 stepper driver can be set to 25000 steps per rev. would result in an error of 0.048/47619.
So your total step loss would be 1/1000 000 instead of 19/16000.

b) you keep track of the missing angle and add it to the next move ( it will result in sometimes going too far and sometimes going not far enough)

Changing that code is a little bit of a challenge for me :) maybe someone else can do a quicker job of it?
Independent from who is or who is not fixing it!
Is a 1/761 error between divisions a reaal world issue or not?
 
Last edited:
Hello Mike,

What should we do?

the program calculates 761.9047 steps to move. (but you can only make it move 762 steps or 761 steps)
So the loop goes:
i=1; if 1 is smaller than 761.9047 then step the motor one step further and increase i by one
i=2, if 2 is smaller than 761.9047 step the motor once and increase i by one.
.
.
.
i=762 if 762 is smaller than 671.9047, OH it is bigger? then it stepped far enough;.. done.

fSo instead of 671.9047 it goes 671.

a) you uprgade your hardware to a finer grid, so that one missing step would not make that big of a difference :)
e.g. a DM542 stepper driver can be set to 25000 steps per rev. would result in an error of 0.048/47619.
So your total step loss would be 1/1000 000 instead of 19/16000.

b) you keep track of the missing angle and add it to the next move ( it will result in sometimes going too far and sometimes going not far enough)

Changing that code is a little bit of a challenge for me :) maybe someone else can do a quicker job of it?
Independent from who is or who is not fixing it!
Is a 1/761 error between divisions a reaal world issue or not?
I tried to change the grid to higher resolution, it still rounds to a given number of steps for the entire loop to 1524 steps. Actually, the accumulated error ends up equivalent to being a full hole off on a indexing plate on the last division. Gear mesh has a tight spot.
 
Last edited:
I tried to change the grid to higher resolution, it still rounds to a given number of steps for the entire loop either 761 or 762 steps.
Yes and no! If you increase the resolution it will not round to 761 or 762 steps, but to the resulting number with the new resolution as I calculated in the given example.
That is of course, because it was programmed that way as.
It calculates the steps to move. Everything behind the decimal point is cut off by the rotation loop.

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

If the grid is changed to higher resolution your total error gets less. It cannot become higher than 1 step per divison.

For the given example of 21 divisons. 21 steps of 1 000 000 steps would be 0°0'27''

21 steps of 16000 steps are 0°28' (almost half degree)

So the error would go down from 28 minutes, to 27 seconds. Quite a bit.

But you had overlooked the essential question I had hidden in the previous post.

Is a 1/761 error between divisions a reaal world issue or not?

Greetings Timo
 
Last edited:
Yes it is odd, but not the reason for the behaviour. The movement loop stops as posted above at 761 steps, of 761.9 steps, so 0.9*21 steps are missing at the end.
Do to rounding, the code sets the steps to 762, it overshoots about 19 steps at the end. the distance between each division isn't much. However, the accumulated error all ends up between the first & last gear tooth. 761 comes up short 762 comes up long.
 
Yes ofcourse, it calculates the steps to move. Everything behind the decimal point is cut off by the move loop.
But if you change the grid to higher resolution your total error gets less. I cannot be higher than 1 step per divison.

void rotation(float tm, int d)
{
for(int i = 0; i < tm; i++)
{
digitalWrite(stp, HIGH);
delay(stepdelay);
digitalWrite(stp, LOW);
delay(stepdelay);
}
Doesn't it still either calculate to 761 or 762 steps for the complete loop, putting all of the error between the first & last division? The code needs to add about 19 steps evenly divided into 16000 steps to fix the accumulated error. I don't know how to fix the code??
 
Is a 1/761 error between divisions a reaal world issue or not?

Doesn't it still either calculate to 761 or 762 steps for the complete loop, putting all of the error between the first & last division? The code needs to add about 19 steps evenly divided into 16000 steps to fix the accumulated error. I don't know how to fix the code??
Hello, now we got out of sequence. I tried to answer your question before it was posted :)

We can try more practical approach. What does your stepper driver offer?
 
Hello, now we got out of sequence. I tried to answer your question before it was posted :)

We can try more practical approach. What does your stepper driver offer?
I tried with the Spread sheet program.
If I snip off the end of the number, and add it to the next move. It would move.
arduino rotary.jpg

So at the end it would have moved 16000 exact.
 
Hello, now we got out of sequence. I tried to answer your question before it was posted :)

We can try more practical approach. What does your stepper driver offer?
I am going to set the driver to a higher resolution and try it again, I think you are right it should reduce my accumulated error. The DM542T driver can offer as many as 25000 pulse per revolution.
 
@Mike,

can you try this? I cannot vouch for myself here, but it compiles and without testing it. I think it might do what I describe.
 

Attachments

  • arduinorotary.zip
    2.2 KB
@Mike,

can you try this? I cannot vouch for myself here, but it compiles and without testing it. I think it might do what I describe.
This one overshoots by about 10 degrees. I noticed that the last step = 763 pulses, if it started a 761 & then added one pulse to 762 19 equal times I think it would be dead on!
 
It must round up to 762 & then 1 pluses 19 times. It needs to start at 761 & add one pluse 19 times (762)

You are really on to the solution I think!
I just checked to see if the common ones still work, like 20 divisions it also overshoots this now, it moves 801 steps instead of the required 800 steps??
 
I just checked to see if the common ones still work, like 20 divisions it also overshoots this now, it moves 801 steps instead of the required 800 steps??
Mmh, I had some hope, but not to high hope. Usually some small detail or check is missed.
Provided the numbers add up to be even. Like 800 steps. The thing should not move anything additional.
Then I hope you are able to "get back to before".
The thing is, the program is not "rounding", it is cutting off the number. So 761.9 becomes 761 672,8 becomes 672.
If the thing is not doing a complete 360° when set to 21 divisions, then there is a programming mistake in it.
 
Back
Top