Difference between NEO-6MV2 and NEO-M8N

I have a Photon 2 connected to a NEO-6MV2 and it works fine except for the precision limitations of the GPS module. I was under the (apparently wrong) impression that the NEO-M8N was a direct replacement for the NEO-6MV2 except for supply voltage being 3.3V rather than 5V. And yet, my code is not able to interpret the serial data that is being returned by the new GPS module. I have confirmed that it is returning data, but my code simply does not manage to read it. Is there some setting that I need to apply for the Particle-GPS library so that it knows that it needs to read from a M8N rather than a 6MV2?

Here is the (redacted) code I am using:

#include <Particle-GPS.h>
#include <neopixel.h>

SYSTEM_MODE(AUTOMATIC);
SYSTEM_THREAD(ENABLED);

const String DeviceID = "XXXXXX"; //registration number of vehicle on which the device will be installed


// IMPORTANT: Set pixel COUNT, PIN and TYPE
#define PIXEL_PIN SPI1 //for Particle Photon 2/P2
#define PIXEL_COUNT 1
#define PIXEL_TYPE WS2812

// *** Create a Gps instance. The RX an TX pins are connected to
// *** the TX and RX pins on the electron (Serial1).
Gps _gps = Gps(&Serial1);

// *** Create a timer that fires every 1 ms to capture
// *** incoming serial port data from the GPS.
Timer _timer = Timer(1, onSerialData);

const unsigned long NoFixGracePeriod = 900000; //15 minutes
unsigned long lastResetTime = 0;
unsigned long LastAlertUpload = 0;

Adafruit_NeoPixel strip(PIXEL_COUNT, PIXEL_PIN, PIXEL_TYPE);

void setup()
{
    // *** Initialize the USB Serial for debugging.
    Serial.begin();
    Serial.println("Initializing...");
    // *** Initialize the GPS.
    _gps.begin(9600);
    // *** Start the timer.
    _timer.start();
      
    // WS2812 //
    strip.begin();
    strip.show();
    strip.setPixelColor(0, strip.Color(255, 255, 0)); //yellow
    strip.show();
    ////////////
    lastResetTime = millis();
    delay(2000);
}

void onSerialData()
{
  _gps.onSerialData();
}

void loop()
{
    double latitude  = 0;
    double longitude = 0;
    int satellites;
    double speed;
    double altitude;
    double bearing;
    
    if(isPhotonConnectedToWiFi()){
        // *** Get the Antenna Status ($PGTOP). //
        Pgtop pgtop = Pgtop(_gps);
        if (pgtop.parse())
        {
            Serial.println("1) Antenna Status ($PGTOP)");
            Serial.println("======================================================");
            Serial.print("Command ID: "); Serial.println(pgtop.commandId);
            Serial.print("Antenna Status: "); Serial.println(pgtop.reference);
            Serial.println("");
        }
        //////////////////////////////////////////
        
        // *** Get the Global Positioning System Fixed Data ($GPGGA).
        Gga gga = Gga(_gps);
        if (gga.parse())
        {
            Serial.print("UTC Time: "); Serial.println(gga.utcTime);
            
            char latHemisphere = 'N';
            latitude = convertGGAToDecimal(gga.latitude, latHemisphere);
            Serial.print("Latitude: "); Serial.println(gga.latitude + "(" + latitude + ")");
            
            char lonHemisphere = 'E';
            longitude = convertGGAToDecimal(gga.longitude, lonHemisphere);
            Serial.print("Longitude: "); Serial.println(gga.longitude + "(" + longitude + ")");
            
            Serial.print("Position Fix Indicator: "); Serial.println(gga.positionFixIndicator);
            Serial.print("Satellites Used: "); Serial.println(gga.satellitesUsed);
            satellites = gga.satellitesUsed;
            Serial.print("Altitude: "); Serial.print(gga.altitude); Serial.print(" "); Serial.println(gga.altitudeUnit);
            altitude = gga.altitude;
            strip.setPixelColor(0, strip.Color(255, 255, 0)); //yellow
            strip.show();
        }
        
        // *** Get the Recommended Minimum Navigation Information ($GPRMC).
        Rmc rmc = Rmc(_gps);
        if (rmc.parse())
        {
            if((latitude==0)||(longitude==0)){
                latitude  = atof(rmc.latitude.c_str());
                longitude = atof(rmc.longitude.c_str());
            }
            Serial.print("Speed Over Ground: "); Serial.println(rmc.speedOverGround);
            speed = rmc.speedOverGround;
            Serial.print("Course Over Ground: "); Serial.println(rmc.courseOverGround);
            bearing = rmc.courseOverGround;
            Serial.print("Date: "); Serial.println(rmc.date);
            Serial.print("Mode: "); Serial.println(rmc.mode);
            Serial.println("");
            strip.setPixelColor(0, strip.Color(0, 255, 0)); //green
            strip.show();
        }
    }
    else {
        Serial.println("Not connected to WiFi");
        strip.setPixelColor(0, strip.Color(255, 0, 0)); //red
        strip.show();
    }
    
    delay(3000);
}

float convertGGAToDecimal(String ggaCoord, char hemisphere) {
    int degrees;
    float minutes;
    float decimalDegrees;
    
    //return ggaCoord.toFloat();

    // Convert String to C-style string
    char cstr[ggaCoord.length() + 1];
    ggaCoord.toCharArray(cstr, ggaCoord.length() + 1);

    // Determine if the coordinate is latitude or longitude based on string length
    int coordLen = strlen(cstr);
    if ((hemisphere == 'E')||(hemisphere == 'W')) {
        // Longitude
        degrees = (cstr[0] - '0') * 100 + (cstr[1] - '0') * 10 + (cstr[2] - '0');
        minutes = atof(cstr + 3);
    } else {
        // Latitude
        degrees = (cstr[0] - '0') * 10 + (cstr[1] - '0');
        minutes = atof(cstr + 2);
    }

    // Convert minutes to decimal degrees
    decimalDegrees = degrees + (minutes / 60.0);

    // Apply the hemisphere factor
    if (hemisphere == 'S' || hemisphere == 'W') {
        decimalDegrees = -decimalDegrees;
    }
    
    return decimalDegrees;
}

bool isPhotonConnectedToWiFi() {
    return WiFi.ready();
}

There is a possibility that your GNSS is using $GNGGA instead of $GPGGA. The N version includes both GPS and GLOSNAS, but the NEMA message format is otherwise the same.

If you can dump out the NEMA messages you can see what it's generating. If it is generating GNGGN you can just modify the library you are using to accept either.

1 Like

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