Accelstepper Position Control

Hi,
i am trying to get a stepper motor (Nema 17, CL42T closed loop driver), to move to a positition defined by an integer using AccelStepper. This works just fine with this code:

#define DCSBIOS_DEFAULT_SERIAL

#include "DcsBios.h"
#include "AccelStepper.h"

AccelStepper stepper(1,2,3);

unsigned int POS = 0;

void onPltAltimeterNeedleChange(unsigned int newValue) {
    POS = map(newValue, 0, 65535, 0, 800);
}
DcsBios::IntegerBuffer pltAltimeterNeedleBuffer(0x133c, 0xffff, 0, onPltAltimeterNeedleChange);

void setup() {
  stepper.setMaxSpeed(2000);
  stepper.setAcceleration(10000);
    DcsBios::setup();
}

void loop() {
  DcsBios::loop();
    stepper.moveTo(POS);
    stepper.run();
  

}

The "newValue" integer is provided by a flight sim and corresponds to the position of a cockpit gauge, ie 0 is the 12oclock position, 32.767 is the 6ocklock position, and 65535 is 0,005° CCW of the first position.
The issue is that when the newValue crosses 0, the stepper will do a 359° turn to reach its new position, see the attached video.

In the past i tried this code, provided by another forum user, which did fix the issue, but introduced major positional error.

#define DCSBIOS_DEFAULT_SERIAL
#include "DcsBios.h"
#include "AccelStepper.h" 
AccelStepper stepper(1,3,4);

int val = 0;
int AltNeedle = 0;

void onPltAltimeterNeedleChange(unsigned int newValue) {
   static unsigned int oldValue = 0;
   int change = (int)(newValue - oldValue); 
   AltNeedle += map(change,-32768,32767,-400,400);   
   oldValue = newValue;
}
DcsBios::IntegerBuffer pltAltimeterNeedleBuffer(0x133c, 0xffff, 0, onPltAltimeterNeedleChange);

void setup() {
  DcsBios::setup(); 
  stepper.setMaxSpeed(1000);
  stepper.setAcceleration(1000);
  
}

void loop() {
    DcsBios::loop();
    stepper.moveTo(AltNeedle);
    stepper.run();
    
  }

So, im basically looking for a way to tell Accelstepper to go from position 65535 to 0 by going 0,005° CW, and not 359.995° CCW, and the other way round.

Any advice would be appreciated

Use an unsigned int, or an unsigned long if You can. I use ul and Accelstepper and face no problem.

1 Like

Which board are you using?
I think the main problem is using 'int' for AltNeedle. You should use a long value and add the change value without mapping. Do the mapping only in the moveTo statement

Im using an Arduino Nano

So basically, have the Position continue beyond 65535 by adding/subtracting the positional value from a long with the accumlated position?

From your second Sketch

change to:

long AltNeedle = 0;

void onPltAltimeterNeedleChange(unsigned int newValue) {
   static unsigned int oldValue = 0;
   int change = (int)(newValue - oldValue); 
   AltNeedle += change;
   oldValue = newValue;
}

and

    stepper.moveTo(AltNeedle);

to

    stepper.moveTo( map( AltNeedle, 0, 65535, 0, 800)  );

completely untested :wink: but as far as I know the return value of map is not limited to its parameter values. Simply try :innocent:

1 Like

It works! You're my hero, thanks so much!
Could you perhaps explain why this fixed it? I am trying to lern after all xD

I am glad that it works and that I could help you.

Mapping from high values to low values always creates an inaccuracy, because several high resolution values lead to the same low resolution value. So this

   AltNeedle += map(change,-32768,32767,-400,400);   

creates in inaccuracy with every change to Altneedle. So the inaccuracy accumulates with every new change. With the changed version

   AltNeedle += change;

there is no mapping when changing AltNeedle, so there no inaccuracy that can accumulate. Of course, now the value of AltNeedle can get much bigger, so it must be 'long' to hold these values.

Of course, there is also an inaccuracy when mapping the AltNeedle value to the resolution of the motor in moveTo(). But this inaccuracy does not accumulate. It is only because of the lower step resolution of the motor.

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.