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);
}
}
}