I got stuck converting degrees to steps

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?

(deleted)

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.

Using integer division, 400/360=1.

Restruction the calculation using long integers to avoid overflow, as follows:

steps = (diff*400L)/360L;

Hint: the parentheses are not necessary.

spycatcher2k:
(Stops the PMs saying I'm being a DICK).

If this is a persistent problem, we can help.

if(Distance==(diff*(400/360)){

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.

Looks like someone would make a thin internal gear box with 5:9 ratio to fit a NEMA face. Maybe they do? :confused:

Mathematically, 400/360 is equal to 10/9.

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

remainingDistance_dg = calculateDistance_st(offset_dg);

is wrong and a conversion needs to be done.

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. :slight_smile:

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? :confused:

that would be a clever solution :slight_smile:

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:

 ButtonState1 = digitalRead(SWITCH1);
  if(ButtonState1==LOW){
      Dest=0;
        }
 ButtonState2 = digitalRead(SWITCH2);
  if(ButtonState2==LOW){
      Dest=65;
        } 
 ButtonState3 = digitalRead(SWITCH3);     
  if(ButtonState3==LOW){
      Dest=132;
        }      
 ButtonState4 = digitalRead(SWITCH4);      
  if(ButtonState4==LOW){
      Dest=199;
        }
 ButtonState5 = digitalRead(SWITCH5);           
  if(ButtonState5==LOW){
      Dest=266;
        }    
  ButtonState6 = digitalRead(SWITCH6);
  if(ButtonState6==LOW){
      Dest=333;
        }


diff=200-abs(abs(Source-Dest)-200);
diffplus=200-abs(abs((Source+1)-Dest)-200);
diffmin=200-abs(abs((Source-1)-Dest)-200);