# How do I make a stepper motor compass cross 360° to 0°?

I am building a wet compass for a flight simulator. I currently have a stepper motor functioning well with the simulator but at the point of crossing 360° to 0° the stepper does a full reverse 360° to get into position.

My question... can anyone please assist me in creating code that makes the linear cross from 360° to 0° work in both directions?

The simulator feeds a `float val` that is a degree out of 360° e.g. 172.13. My stepper has 4076 steps per full revolution. You will see the math in the code below. I am using the `AccelStepper` library.

``````void ProgOut(byte id, float val) {
switch (1) {
case 1:

if (val)
{ stepper1.moveTo(val * 11.3222222);         }

stepper1.run();

break; }}
``````

I have tried something like this:

``````void ProgOut(byte id, float val) {
switch (1) {
case 1:
if ( stepper1.distanceToGo () >= 4064){
stepper1.moveTo(4076);
stepper1.setCurrentPosition(0);
}
else if (val)
{

stepper1.moveTo(val * 11.3222222);
}

stepper1.run();

break; }}
``````
• Your library doesn't understand that your stepper goes in a full circle. See if it has some more primitive moves, like "home" and "move by n steps". If it does you're in business, but you'll have to write your own "go to" function. Alternately, dig through the documentation and see if it can be TOLD that it's dealing with a stepper that goes in a circle. Again, if it does, you're in business.
– TimWescott
Nov 10, 2018 at 0:52
• have you tried to go to 361? Nov 10, 2018 at 1:02
• @TimWescott thanks Tim for the suggestion. I’ll go through it again to see what I have available
– Andy
Nov 10, 2018 at 1:25
• @jsotola the Val is feeding from the simulator software. So the maximum is actually 359.99. The Val after that would be 0
– Andy
Nov 10, 2018 at 1:26
• why are you involving data from the simulator during debugging? .... figure out how to step from 359 to 0 without moving a full circle ..... once that works, then use the simulator data again Nov 10, 2018 at 2:00

Two options (for starters):

1. Use the `move()` class rather than the `moveTo()` class. This will allow you to do relative moves rather than absolute.
2. Use `setCurrentPosition()` (which sets the current position to zero) followed by `moveTo()` with a destination which is `newPos - prevPos`.

For either to work you will need to keep track of the current position of the needle.

To work out the relative move you will need to do some kink of modulo arithmetic but this will require some trickery to generate negative values for anti-clockwise moves.

``````// delta is the angular adjustment required.
setCurrentPosition();        // Zero the motor.
moveTo(delta);               // Move absolute from the new zero.
``````
• The code assumes that you will never have to make a heading adjustment of more that 180° in one step.
• Adding in the 180° before the modulo calculation and subtracting it again afterwards is a trick to allow negative results from the modulo arithmetic.

Also working on making a compass for flight simulator. Hopefully the following code will help answer the question. This is a working code that I have tested using serial monitor... Note: For Flight Sim use, I did find that to get enough speed and smooth movement for the X27-168 gauge motor you need to use a stepper driver with microstepping rather than driving the X27-168 directly from the Nano I/O pins. You will have to adjust Max speed & acceleration and also edit the firmware for micro-stepping with using a stepper driver. Note: When using a stepper driver chip, you need to use the correct type for 6 step coil energising that the X27-168 stepper uses eg. AX1201728SG. Polulu (A4988) type stepper drivers use 8 steps coil energisation which will not move the gauge motor correctly - while it will move the gauge motor it creates a lot of noise and is not ideal.

I did have to add the following to get both left and right movements through North. I used Movement rather than delta -
if(Movement( < -180){Movement = Movement + 360;}

A single movement of 180 degrees defaults to CCW direction. however with Flight simulator data extraction, you shouldn't get a single movement of that amount.

``````/*Analog Compass Gauge.**
This uses an Arduino Nano processor that has four of its I/O's directly connected to an X27-168 geared stepper motor(Gauge indicator motor).
While it works, there should really be four sets of protection diodes across each of the I/O pins - diode to +5V & diode to 0V to eliminate spikes over 5v and below 0v on each I/O pin.
The X27-168 geared stepper motor has had the internal stop cut off on the main output shaft gear to allow full 360 degree movement.
A 55mm dia plastic round plate has been fitted to the X27-168 geared stepper motor 1mm diameter drive shaft and a printed label attached to the plate to show compass direction.
The plastic plate has a small Neodymium magnet (1mm dia x 2mm long) which can pass near a Hall Effect sensor (A3144)to provide a homing reference signal.
+5v,0v and I/O signal pin is connected directly to the Hall Effect sensor. The Nano internal I/O resistor is used to provide a pullup voltage for the Hall effect sensor signal.  The firmware uses the AccelStepper library.
PC Serial Monitor is used to enter new compass headings.
The X27-168 geared stepper motor is referred to as "stepper1" in the firmware.
*/
#include "AccelStepper.h"
AccelStepper Stepper1(AccelStepper::FULL4WIRE, 3, 4, 5, 6);   // Define stepper I/O pins (Using I/O pins connected directly to X27-168 Geared Stepper Motor)
//AccelStepper Stepper1(AccelStepper::DRIVER, 2, 5); // Defines I/O pins when using a stepper driver e.g. AX1201728SG Quad driver chip -  Dir pin - Stepper pin
#define Home_Sensor      2   // Pin 2 - Connected to Home Sensor - Hall Effect A3144- (0v when sensed)
int Offset = -67;   // ****** Adjust this setting to ensure North facing when at Home Position(0)  ******
int MaxSpeed = 80;   // ****** Adjust this setting for Max Speed of Stepper as to not miss steps    ******
int Acceleration = 25   // ****** Adjust this setting for Acceleration of Stepper as to not miss steps ******
int    Move_finished =   1;   // Used to check if move is completed
long   Initial_Homing = -1;   // Used to Home Stepper at startup
String InputString =    "";   // String to hold incoming data from serial monitor
bool   StringComplete = false;   // Whether the string is complete
int    Movement;   // Register for difference between Last and New heading
void setup() {
Serial.begin(9600);   // Start the Serial monitor at 9600 Baud
pinMode(Home_Sensor, INPUT_PULLUP);   // Using internal pullup for Hall Effect sensor
delay(5);   // Wait for stepper Driver wake up (if used)
Stepper1.setMaxSpeed(MaxSpeed);   // Intial Homing Max Speed of Stepper (Slower to get better accuracy)
Stepper1.setAcceleration(Acceleration );   // Intial Homing Acceleration of Stepper
Serial.println("........ Homing Stepper ........");

while (digitalRead(Home_Sensor)) {   // Make the Stepper1 move CW until the sensor is activated
Stepper1.moveTo(Initial_Homing);   // Set the position to move to
Initial_Homing--;   // Decrease by 1 for next move if needed
Stepper1.run();   // Start moving stepper1
delay(5);
}
Stepper1.setCurrentPosition(0);   // Set the current position as zero for now
Initial_Homing=1;
while (!digitalRead(Home_Sensor)) {   // Make the Stepper1 move CCW until the sensor is deactivated
Stepper1.moveTo(Initial_Homing);
Stepper1.run();
Initial_Homing++;
}
//**** Should now be Homed to Magnet position which may not be North as per label. Below allows tuning to correct position of label ****
Stepper1.setCurrentPosition(0);
Stepper1.setMaxSpeed(MaxSpeed);   // Intial Homing Correction Max Speed of Stepper1
Stepper1.setAcceleration(Acceleration );   // Intial Homing Correction Acceleration of Stepper1

Stepper1.moveTo(Offset);   // To correct to have North as Home position
while(Stepper1.distanceToGo() != 0){Stepper1.run();}   // Step to adjusted home position
Stepper1.setCurrentPosition(0);   // Set Home position that will be used for all further movements..
Serial.println("........ Homing Completed ........");
Serial.println(" *** Enter Compass Heading 0 - 259 Degrees ***");
// ---------   End of intial Homing Setup  ------------
}
void loop() {
while (Serial.available() > 0) {   // Read serial input:
if (isDigit(InChar)) {InputString += (char)InChar;}   // Convert the incoming byte to a char and add it to the string
if (InChar == '\n') {   // If you get a newline,
NewHeading = (NewHeading/2)*2;   // Eliminates 1 degree movements. Reduces movement errors with small movements

if(NewHeading > 359 ||NewHeading < 0) {   // Displays error message if input is out of range
Serial.println("Input Error. Enter value between 0 - 259 Degrees ");
}

}
InputString = "";   // Clear the string for new input:
Movement = ((NewHeading + 180 - LastHeading) % 360) - 180;   // Allows movement from North East to North West
if(Movement < -180){Movement = Movement + 360;}   // Allows movement from North West to North East
Stepper1.setCurrentPosition(0);   // Zero the motor.
Stepper1.setMaxSpeed(MaxSpeed);   // Set Max Speed of Stepper1
Stepper1.setAcceleration(Acceleration );   // Set Acceleration of Stepper1

Stepper1.move(Movement*2);   // Set new move to position of Stepper1