Captain Jack Sparrow Compass

Hello Everyone

I am working on an Arduino project with the goal of creating a compass system that utilizes a QMC5883L compass module, a Neo-6M GPS module, and a 28BYJ-48 stepper motor. The objective is to make the stepper motor follow a fixed GPS point by adjusting its orientation based on the difference between the GPS-calculated azimuth and the magnetic heading obtained from the compass module, the "zero Position of the Servo is determined with a button.

The setup involves connecting the GPS module to Arduino pins D2 (RX) and D3 (TX), the stepper motor to pins D8, D9, D10, and D11, and the compass module to the SDA and SCL pins (A4 and A5, respectively). The system uses the TinyGPS++ library for GPS data parsing and the QMC5883LCompass library for compass readings.

I have calibrated both the compass and the stepper motor and provided the target GPS coordinates for the system to follow. The power is supplied through the micro USB port on the Arduino.

This is my first time doing a project of this scale, most of the my code was done with the help of ChatGPT 3.5. I am open to any insights, suggestions, or assistance in refining the project for better accuracy or efficiency. Your input and help would be greatly appreciated.

#include <Wire.h>
#include <QMC5883LCompass.h>
#include <TinyGPS++.h>
#include <SoftwareSerial.h>
#include <Stepper.h>
#include <math.h>

#define STEPS 2048  // Steps per revolution for the 28BYJ-48 stepper motor
#define IN1 11      // Connection to IN1 of the stepper motor
#define IN2 10      // Connection to IN2 of the stepper motor
#define IN3 9       // Connection to IN3 of the stepper motor
#define IN4 8       // Connection to IN4 of the stepper motor
#define BUTTON 7    // Connection for the push button

SoftwareSerial gpsSerial(2, 3);  // RX, TX for GPS module
TinyGPSPlus gps;                 // GPS object

QMC5883LCompass compass;         // Compass object

Stepper stepper(STEPS, IN1, IN2, IN3, IN4);  // Initialization of the stepper motor

float targetLat = 47.5;  // Target latitude
float targetLon = 8.5;  // Target longitude

// Function to calculate azimuth angle between two coordinates
float calculateAzimuth(float lat1, float lon1, float lat2, float lon2) {
  // Conversion of coordinates from degrees to radians
  lat1 = radians(lat1);
  lon1 = radians(lon1);
  lat2 = radians(lat2);
  lon2 = radians(lon2);

  // Calculate differences in longitude and latitude
  float dLon = lon2 - lon1;

  // Calculate azimuth angle
  float y = sin(dLon) * cos(lat2);
  float x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(dLon);
  float azimuth = atan2(y, x);

  // Convert azimuth angle from radians to degrees
  azimuth = degrees(azimuth);

  // Adjust azimuth angle to the range of 0 to 360 degrees
  azimuth = fmod((azimuth + 360), 360);

  return azimuth;
}

void setup() {
  Serial.begin(9600);
  gpsSerial.begin(9600);
  Wire.begin();

  pinMode(BUTTON, INPUT_PULLUP); // Push button as input with pull-up resistor

  compass.init();

  if (!compass.begin()) {
    Serial.println("Could not find a valid QMC5883L sensor, check wiring!");
    while (1);
  }

  stepper.setSpeed(10);  // Stepper motor speed in revolutions per minute
}

void loop() {
  // Read GPS data
  while (gpsSerial.available() > 0) {
    if (gps.encode(gpsSerial.read())) {

      // Zero-point calibration using the push button
      if (digitalRead(BUTTON) == LOW) {
        stepper.setCurrentPosition(0); // Set the current stepper motor position to zero
        Serial.println("Zero-point calibrated!");
      }

      // Calculate direction to the target
      float currentLat = gps.location.lat();
      float currentLon = gps.location.lng();
      float azimuth = calculateAzimuth(currentLat, currentLon, targetLat, targetLon);
      
      // Read compass value
      compass.readRaw();
      float headingMag = compass.heading();
      
      // Calculate rotation angle for the stepper motor
      int steps = map(headingMag - azimuth, -180, 180, -STEPS/2, STEPS/2);
      
      // Rotate the stepper motor
      stepper.step(steps);
      
      // Debugging output
      Serial.print("Target Azimuth: ");
      Serial.print(azimuth);
      Serial.print(" | Magnetic Heading: ");
      Serial.println(headingMag);
    }
  }
}

You may struggle to get help on a project that involves input from ChatGPT.

How accurate is your project at indicating bearing as it stands? Does it calculate the correct bearing to the fixed point to say +/- 1 or 2 degrees? (You can check this with online distance and bearing calculators). Could you tell if it were off by 1 or 2 degrees when looking at where the stepper motor is pointing?

Get chatGPT to give you an annotated schematic showing how it is to be wired showing all connections, power, ground and power sources. Posting links to the technical information on the hardware devices will also help us help you. You can ask chatGPT for the links.

4 Likes

Evidently, the bot does not know that TinyGPS++ has a courseTo() method (it hasn't read the library documentation either).

That works as expected, so you don't need the calculateAzimuth function.

In the following, where do you apply the required magnetometer offsets and scale factors? How did you do the calibration?

      // Read compass value
      compass.readRaw();

It would be a good idea to get the compass working before adding the code for it to the rest of the project. Keep in mind that the magnetometer must be calibrated in place, and must be level (Z axis vertical) in order to work properly as a compass.

3 Likes

Hi, @ew0k
Welcome to the forum.

How does your code know what direction the stepper is pointing?
Especially when you first boot your code?

Tom... :grinning: :+1: :coffee: :australia:

2 Likes

The reason I've resorted to using Chat GPT is because I lack the programing capabilities.

Right now, precision of the direction is not my main Problem, as my code is not even fully functioning right now. Later the precision will probably be dependent on the correct orientation of the compass module and the calibration while booting where the compass needle while be zeroed with a button it hits on its path

Unfortunately, ChatGPT makes horrible mistakes that beginners fail to spot. You are trying to run before learning to crawl.

Start by getting just one aspect of the project working, and when you understand that completely, add another.

Simply making a digital compass is a significant challenge for a beginner, especially since it requires calibrating the magnetometer, so that would be a good place to start.

I did see that you claim to have done that step, so please answer the questions in post #2.

1 Like

Programming is another language, you do not just sit down and know it. Learning from those that do not properly speak the language will only hurt you in the long run.

I would suggest starting with the basics. You have 3 pieces of hardware - a compass module, a GPS module and a stepper motor.

The compass module and the GPS module likely have libraries that other users have written. Those libraries usually (but not always) come with example pieces of code that demonstrate the use of the library and hardware. Have a look at each one in turn and see if you can use the functions in the library to extract the information you need for the computations in your project.

I would start with either the compass module or the stepper motor to get the feel of how things work.

As your knowledge builds, you can try and combine pieces of code to ultimately achieve your goal. If you get stuck, then there a forum members who can help you with your code. Some may even have the same hardware modules that you have and could run your code for you to see what the issues may be.

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