int Distance = 0 ; // distance the stepper has traveled
int Go= 0; // let the motor step
int Dest = 0; // destination the motor needs to go
int Source =0; // where the motor currently is
int diff = 0;
int diffplus=0;
int diffmin=0;
// the algorithm i found online
diff=180-abs(abs(Source-Dest)-180); //find diffrence and wrap
diffplus=180-abs(abs((Source+1)-Dest)-180); //calculate effect of adding
diffmin=180-abs(abs((Source-1)-Dest)-180); //.......subtracting
if(diffplus>=diffmin){
digitalWrite(DIR,HIGH); //direction is set clockwise
}
else{digitalWrite(DIR,LOW); //direction is set counter-clockwise
}
if(Dest!=Source){
Go=1;
}
while (Go==1){
digitalWrite(STEP,HIGH);
delayMicroseconds(1500);
digitalWrite(STEP,LOW);
delayMicroseconds(1500);
Distance=Distance+1;
Serial.print(Distance);
if(Distance==(diff*(400/360)){
Go=0;
Source=Dest;
Distance=0;
}
Hi Arduino Community,
The code above is a small part of a program I’m working on. I successfully used an algorithm, that I found online, to calculate shortest direction of travel between two degrees on a circle.
The program is used to control a 1.8° stepper in half step, so that is 400 steps for al full rotation. Now here starts my problem. let's say I want to move 60° the motor needs (400/360)*60=66,6666667 steps.
with the current while/if statement the motor does only 60 steps, so there is obviously something wrong with my approach.
Could somebody give me a step in the good direction to get this working?
Once you have sorted out the data types then consider changing this
if (Distance == (diff * (400 / 360))
When comparing the results of a calculation with a value it is almost always preferable not to test for equality but rather to test whether a value equals or is less than or greater than the value being tested. This is particularly the case with floats as their value will almost never be exactly what you expect.
Note that 400/360 is equal to 1 because both are integers and the result is truncated. 60 degrees times 1 is 60 steps.
You could do much better with (diff * 400) / 360. That would be 66.
WARNING: Angles over 81 will cause an integer overflow. Use longs:
(diff * 400L) / 360L.
You can do even better by rounding to the nearest step:
(diff * 400L+180L) / 360L would be 67.
The OP has a 200 step motor, with a 9:5 gearbox, 1 step on the 5 gear gives 1 degree on the 9 gear, 60 steps on the 5 gear (108 degrees) gives 60 degrees on the 9 gear.
MartijnBeek:
let’s say I want to move 60° the motor needs (400/360)*60=66,6666667 steps.
Well, you can’t move a stepper 66.6667 steps. When you use a stepper, your code has to keep track of where it is. If you use fractional values, then you will get rounding off errors that will accumulate over time.
To address this, don’t measure angles in degrees. Measure them in number of half-steps. By this, I mean that the unit for Dest and Steps should be ‘1 400th of a full rotation’. And the variables and whatnot need to be integer values. Never use float for anything that needs to be counted precisely.
Personally, I like to suffix variables and functions that hold amounts of stuff with a short suffix indicating the unit of measure. Say ‘_dg’ for degrees, ‘_rd’ for radians, and ‘_st’ for steps. That way, you can easily see that
odometer:
Mathematically, 400/360 is equal to 10/9.
Good point! One could switch to 10/9 to avoid integer overflow. Using (degrees * 10) / 9 would get you 60°->66 steps without risking integer overflow (359*10 << 32767).
To get an even closer result you need to round off to the nearest step. To do that you would add half the divisor before dividing but 9/2 is not an integer. Double both the numerator and denominator (use 20/18): (degrees*20 + 9) / 18 would get you 60°->67 steps.
First, thanks to everyone that replied! It’s so cool to see so many smart people helping with out with a question.
spycatcher2k:
Is this an INT ?
I'm providing a hint, not a solution.
Thanks for the hint!
edgemoron:
Looks like someone would make a thin internal gear box with 5:9 ratio to fit a NEMA face. Maybe they do?
that would be a clever solution
PaulMurrayCbr:
Well, you can't move a stepper 66.6667 steps. When you use a stepper, your code has to keep track of where it is. If you use fractional values, then you will get rounding off errors that will accumulate over time.
To address this, don't measure angles in degrees. Measure them in number of half-steps. By this, I mean that the unit for Dest and Steps should be '1 400th of a full rotation'. And the variables and whatnot need to be integer values. Never use float for anything that needs to be counted precisely.
This turned out te be the solution for me. Instead of using 360 degrees I now use 400 steps.To avoid fractional values (400/6=6.66666666666667) I divided the circle in 567 steps(335) and 165 steps. See the code below: