Hello,
i have built an rc boat and iam using the hybrid neo-m8n for gps+compass sensor. I have tested the gps on u-center and it is working fine. The problem is the compass. The heading iam receiving is completely off. Ι will post 2 pictures. One is showing the position of the gps on the boat which is away from the other electronics and as parallel as it could with the earth's plane and the other the gps from above with an arrow on the covering. I measured the heading with my iphone compass and when i was supposed to get 265 degrees heading i got 359 from the gps compass. I am using Adafruit_Sensor.h and Adafruit_HMC5883_U.h libraries for the programming. Can we please find a solution to this huge heading error? The code iam using for the testing is shown below (the libraries are supposed to take care of the error caused by tilting the compass sensor):
#include <TinyGPS++.h>
#include <SoftwareSerial.h>
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_HMC5883_U.h>
#include <stdlib.h>
#include <Servo.h>
static const int OPin1 = 22, OPin2 = 23, OPin3 = 24;
static const uint32_t GPSBaud = 9600;
float gpslat, gpslon, headingDegrees;
uint8_t sats, hours, mins, secs, day, month;
uint16_t year;
uint32_t start,end,time,endgpsdatawaitmS, startGetFixmS, endFixmS, i = 0, j = 0, k, angle;
static char varbuf[32], sendbuf[32];
bool received = false, newData = false;
// Assign a Uniquej ID to the HMC5883 Compass Sensor
Adafruit_HMC5883_Unified mag = Adafruit_HMC5883_Unified(12345);
// The TinyGPS++ object
TinyGPSPlus gps;
void setup()
{
pinMode(OPin1, OUTPUT);
digitalWrite(OPin1, HIGH);
pinMode(OPin2, OUTPUT);
digitalWrite(OPin2, HIGH);
pinMode(OPin3, OUTPUT);
digitalWrite(OPin3, HIGH);
Serial.begin(GPSBaud);
Serial3.begin(GPSBaud);
Serial2.begin(GPSBaud);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
sensor_t sensor;
mag.getSensor(&sensor);
startGetFixmS = millis();
endgpsdatawaitmS = millis() + 5000;
}
void loop()
{
//delay(1000);
//Serial.println("Data from gps:");
if (gpsWaitFix(5))
{
if (mag.begin())
{
displayCompassInfo();
}
gpslat = gps.location.lat();
gpslon = gps.location.lng();
sats = gps.satellites.value();
hours = gps.time.hour();
mins = gps.time.minute();
secs = gps.time.second();
day = gps.date.day();
month = gps.date.month();
year = gps.date.year();
if (millis() > endgpsdatawaitmS) { //send every 5 seconds
Serial.println("Sending data to feather...");
Serial2.print("<");
Serial2.print(gpslat, 6);
Serial2.print(" ");
Serial2.print(gpslon, 6);
Serial2.print(" ");
Serial2.print("Sat: ");
Serial2.print(sats);
Serial2.print(">");
delay(100);
Serial2.print("< Compass Heading: ");
Serial2.print(headingDegrees);
Serial2.print(">");
delay(100);
Serial2.print("< Gps Heading: ");
Serial2.println(gps.course.deg()); // heading from gps (vehicle need to be moving or heading is random)
Serial2.print(">");
delay(100);
endgpsdatawaitmS = millis()+5000;
}
startGetFixmS = millis(); //have a fix, next thing that happens is checking for a fix, so restart timer
}
else
{
Serial2.println();
Serial2.print("No gps fix");
}
}
bool gpsWaitFix(uint16_t waitSecs)
{
//waits a specified number of seconds for a fix, returns true for good fix
uint32_t endwaitmS;
uint8_t GPSchar;
Serial.print(F("Wait GPS Fix "));
Serial.print(waitSecs);
Serial.println(F(" seconds"));
endwaitmS = millis() + (waitSecs * 1000);
while (millis() < endwaitmS)
{
if (Serial3.available() > 0)
{
GPSchar = Serial3.read();
gps.encode(GPSchar);
}
if (gps.location.isUpdated() && gps.date.isUpdated())
{
endFixmS = millis(); //record the time when we got a GPS fix
newData = true;
return true;
}
}
return false;
}
void displayCompassInfo()
{
/* Get a new sensor event */
sensors_event_t event;
mag.getEvent(&event);
/* Display the results (magnetic vector values are in micro-Tesla (uT)) */
Serial.print("X: "); Serial.print(event.magnetic.x); Serial.print(" ");
Serial.print("Y: "); Serial.print(event.magnetic.y); Serial.print(" ");
Serial.print("Z: "); Serial.print(event.magnetic.z); Serial.print(" "); Serial.println("uT");
// Hold the module so that Z is pointing 'up' and you can measure the heading with x&y
// Calculate heading when the magnetometer is level, then correct for signs of axis.
float heading = atan2(event.magnetic.y, event.magnetic.x);
// Once you have your heading, you must then add your 'Declination Angle', which is the 'Error' of the magnetic field in your location.
// Find yours here: http://www.magnetic-declination.com/
float declinationAngle = 0.081;
heading += declinationAngle;
// Correct for when signs are reversed.
if (heading < 0)
heading += 2 * PI;
// Check for wrap due to addition of declination.
if (heading > 2 * PI)
heading -= 2 * PI;
// Convert radians to degrees for readability.
float headingDegrees = heading * 180 / M_PI;
Serial.print("Heading (degrees): "); Serial.println(headingDegrees);
delay(1000);
}