Asset Tracker V2 Duplicate Locations?

So I just set up my Asset Tracker V2 with Electron and am sending back locations. However I am receiving duplicate locations which should be fairly rare. Even though my device is not moving the accuracy of the GPS should still make the values jump around.

Location has been changed. Disregard Avg Location. The values of highlighted areas seem to duplicate. Is this from interference from my external antenna? What can be causing this to happen?

I’d expect that behavior. The raw data from the GPS will jump around a bit even when the unit itself is not moving, so you’ll want to apply an algorithm to smooth it out.

1 Like

The issue is that it doesn’t jump around when it should be expected to:

For example here its showing that for 3.5 hours it doesnt move. While its true my device is not moving the GPS coords should not be duplicating itself. There should still be a small variance each time I read the locatiobn.

34.325361,-141.445038 at March 21, 2018 at 04:12AM
34.325361,-141.445038 at March 21, 2018 at 04:22AM
34.325361,-141.445038 at March 21, 2018 at 04:32AM
34.325361,-141.445038 at March 21, 2018 at 04:42AM
34.325361,-141.445038 at March 21, 2018 at 04:52AM
34.325361,-141.445038 at March 21, 2018 at 05:02AM
34.325361,-141.445038 at March 21, 2018 at 05:12AM
34.325361,-141.445038 at March 21, 2018 at 05:22AM
34.325361,-141.445038 at March 21, 2018 at 05:32AM
34.325361,-141.445038 at March 21, 2018 at 05:42AM
34.325361,-141.445038 at March 21, 2018 at 05:52AM
34.325361,-141.445038 at March 21, 2018 at 06:02AM
34.325361,-141.445038 at March 21, 2018 at 06:12AM
34.325361,-141.445038 at March 21, 2018 at 06:22AM
34.325361,-141.445038 at March 21, 2018 at 06:32AM
34.325361,-141.445038 at March 21, 2018 at 06:42AM
34.325361,-141.445038 at March 21, 2018 at 06:52AM
34.325361,-141.445038 at March 21, 2018 at 07:02AM
34.325361,-141.445038 at March 21, 2018 at 07:12AM
34.325361,-141.445038 at March 21, 2018 at 07:22AM
34.325361,-141.445038 at March 21, 2018 at 07:32AM
34.325361,-141.445038 at March 21, 2018 at 07:42AM

I see, yes, you did say that. Are you sleeping between checking the GPS? Which mode?

My guess is that the GPS is not starting back up properly in between checks. Reading the lat/lon information doesn’t actually query the GPS for it. The GPS constantly outputs the location information and the library stores the last value. If the GPS serial data stream didn’t start up properly, you’d keep getting the last location.

1 Like

Always on. No sleep mode because I found it hard to re aquire position when the signal strength is low.

// This #include statement was automatically added by the Particle IDE.
#include <AssetTracker.h>

// This #include statement was automatically added by the Particle IDE.
#include <google-maps-device-locator.h>


/* -----------------------------------------------------------
This example shows a lot of different features. As configured here
it will check for a good GPS fix every 10 minutes and publish that data
if there is one. If not, it will save you data by staying quiet. It also
registers 3 Particle.functions for changing whether it publishes,
reading the battery level, and manually requesting a GPS reading.
---------------------------------------------------------------*/

// Set whether you want the device to publish data to the internet by default here.
// 1 will Particle.publish AND Serial.print, 0 will just Serial.print
// Extremely useful for saving data while developing close enough to have a cable plugged in.
// You can also change this remotely using the Particle.function "tmode" defined in setup()
int transmittingData = 1;

// Used to keep track of the last time we published data
long lastPublish = 0;

// How many minutes between publishes? 10+ recommended for long-time continuous publishing!
int delayMinutes = 10;
int delayMinutesMoving = 1;

int vehicleAccel = 0;
const int AccelThreshold = 10500;

const unsigned int AverageLocationCount = 10;
float PreviousLocations [AverageLocationCount + 1][2] = {0.0f};
int PreviousLocationCount = 0;

// Creating an AssetTracker named 't' for us to reference
AssetTracker t = AssetTracker();

// A FuelGauge named 'fuel' for checking on the battery state
FuelGauge fuel;


//GoogleMapsDeviceLocator locator;

// setup() and loop() are both required. setup() runs once when the device starts
// and is used for registering functions and variables and initializing things
void setup() {
    // Sets up all the necessary AssetTracker bits
    t.begin();

    t.antennaExternal();

    // Enable the GPS module. Defaults to off to save power.
    // Takes 1.5s or so because of delays.
    t.gpsOn();


    // Opens up a Serial port so you can listen over USB
    Serial.begin(9600);

    // These three functions are useful for remote diagnostics. Read more below.
    Particle.function("tmode", transmitMode);
    Particle.function("batt", batteryStatus);
    Particle.function("gps", gpsPublish);

    //locator.withSubscribe(locationCallback).withLocatePeriodic(30);
}

// loop() runs continuously
void loop() {
    // You'll need to run this every loop to capture the GPS output
    t.updateGPS();

//locator.loop();

vehicleAccel = t.readXYZmagnitude();

if (vehicleAccel > AccelThreshold) 
{
        if (millis()-lastPublish > delayMinutesMoving*60*1000) {
            // Remember when we published
            lastPublish = millis();

            //String pubAccel = String::format("%d,%d,%d", t.readX(), t.readY(), t.readZ());
            //Serial.println(pubAccel);
            //Particle.publish("A", pubAccel, 60, PRIVATE);

            // Dumps the full NMEA sentence to serial in case you're curious
            //Serial.println(t.preNMEA());

            // GPS requires a "fix" on the satellites to give good data,
            // so we should only publish data if there's a fix
        
            UpdateAverageLocation();
            PublishGPSAvg();
        }
    }

    else
    {
        // if the current time - the last time we published is greater than your set delay...
        if (millis()-lastPublish > delayMinutes*60*1000) {
            // Remember when we published
            lastPublish = millis();

            //String pubAccel = String::format("%d,%d,%d", t.readX(), t.readY(), t.readZ());
            //Serial.println(pubAccel);
            //Particle.publish("A", pubAccel, 60, PRIVATE);

            // Dumps the full NMEA sentence to serial in case you're curious
            //Serial.println(t.preNMEA());

            // GPS requires a "fix" on the satellites to give good data,
            // so we should only publish data if there's a fix
        
            UpdateAverageLocation();
            PublishGPSAvg();
        }
    
    }
}

void locationCallback(float lat, float lon, float accuracy) {
  // Handle the returned location data for the device. This method is passed three arguments:
  // - Latitude
  // - Longitude
  // - Accuracy of estimated location (in meters)
}

void UpdateAverageLocation(void)
{
    if (t.gpsFix()) 
    {

       PreviousLocationCount++;
    
        if(PreviousLocationCount > AverageLocationCount)
        {
            PreviousLocations[PreviousLocationCount % AverageLocationCount][0] = t.readLatDeg();
            PreviousLocations[PreviousLocationCount % AverageLocationCount][1] = t.readLonDeg();
        }
    
        else
        {
            PreviousLocations[PreviousLocationCount][0] = t.readLatDeg();
            PreviousLocations[PreviousLocationCount][1] = t.readLonDeg();
        }
    
        PreviousLocations[0][0] = 0.0f;
        PreviousLocations[0][1] = 0.0f;
    
        for (int i = 1; i <= AverageLocationCount; i++)
        {
            PreviousLocations[0][0] += PreviousLocations[i][0];
            PreviousLocations[0][1] += PreviousLocations[i][1];
        }
    
        if(PreviousLocationCount >= AverageLocationCount)
        {
            PreviousLocations[0][0] = PreviousLocations[0][0]/AverageLocationCount;
            PreviousLocations[0][1] = PreviousLocations[0][1]/AverageLocationCount;
        }
    
        else
        {
            PreviousLocations[0][0] = PreviousLocations[0][0]/PreviousLocationCount;
            PreviousLocations[0][1] = PreviousLocations[0][1]/PreviousLocationCount;
        }
    
        Serial.println("Avg Loc: " + String::format("%.6f",PreviousLocations[0][0]) + "," + String::format("%.6f",PreviousLocations[0][1]));
    
    }
}

void UpdateAverageLocation2(void)
{

   if (t.gpsFix()) 
    {

    PreviousLocationCount++;
    
    PreviousLocations[0][0] += t.readLatDeg();
    PreviousLocations[0][1] += t.readLatDeg();
    
    if (PreviousLocationCount >= 10)
    {
        
        PreviousLocations[0][0] /= PreviousLocationCount;
        PreviousLocations[0][1] /= PreviousLocationCount;
        
        PublishAvgLoc();
            
    }
    
}

}

void PublishGPS()
{
    if (t.gpsFix()) 
    {
                // Only publish if we're in transmittingData mode 1;
        if (transmittingData) 
        {
            // Short publish names save data!
            Particle.publish("G", t.readLatLon(), 60, PRIVATE);
        }
    }
    // but always report the data over serial for local development
    Serial.println(t.readLatLon());
}

void PublishGPSAvg()
{
    if (t.gpsFix()) 
    {
                // Only publish if we're in transmittingData mode 1;
        if (transmittingData) 
        {
            // Short publish names save data!
            Particle.publish("G", String::format(t.readLatLon() + " Avg %.6f",PreviousLocations[0][0]) + "," + String::format("%.6f",PreviousLocations[0][1]), 60, PRIVATE);
        }
    }
    // but always report the data over serial for local development
    Serial.println(t.readLatLon());
}

void PublishAvgLoc()
{
    if (t.gpsFix()) 
    {
        // Short publish names save data!
        Particle.publish("AVGLOC", String::format("%.6f",PreviousLocations[0][0]) + "," + String::format("%.6f",PreviousLocations[0][1]), 60, PRIVATE);
    }

}

// Allows you to remotely change whether a device is publishing to the cloud
// or is only reporting data over Serial. Saves data when using only Serial!
// Change the default at the top of the code.
int transmitMode(String command) {
    transmittingData = atoi(command);
    return 1;
}

// Actively ask for a GPS reading if you're impatient. Only publishes if there's
// a GPS fix, otherwise returns '0'
int gpsPublish(String command) {
    if (t.gpsFix()) {
        Particle.publish("G", t.readLatLon(), 60, PRIVATE);

        // uncomment next line if you want a manual publish to reset delay counter
        // lastPublish = millis();
        return 1;
    } else {
      return 0;
    }
}

// Lets you remotely check the battery status by calling the function "batt"
// Triggers a publish with the info (so subscribe or watch the dashboard)
// and also returns a '1' if there's >10% battery left and a '0' if below
int batteryStatus(String command){
    // Publish the battery voltage and percentage of battery remaining
    // if you want to be really efficient, just report one of these
    // the String::format("%f.2") part gives us a string to publish,
    // but with only 2 decimal points to save space
    Particle.publish("B",
      "v:" + String::format("%.2f",fuel.getVCell()) +
      ",c:" + String::format("%.2f",fuel.getSoC()),
      60, PRIVATE
    );
    // if there's more than 10% of the battery left, then return 1
    if (fuel.getSoC()>10){ return 1;}
    // if you're running out of battery, return 0
    else { return 0;}
}