Boron LTE & Asset Tracker V2 Shield PCB

Can I user Boron LTE on Asset Tracker Shield PCB board (with GPS chip)? If I can’t, is there an alternate solution for me?

The Boron does not fit in the Particle AssetTracker shield.

One option is to use the Adafruit Ultimate GPS FeatherWing, pictured here with a Boron LTE, Adafruit 128x32 OLED display, and an Adafruit Ultimate GPS FeatherWing in a tripler.

3 Likes

Very good suggestion.
Is there a shield underneath the 3 boards? If there is who makes them? Cos the Adafruit Ultimate GPS FeatherWing is just the GPS module.

This would be the Adafruit FeatherWing Trippler

also available via the Particle store

Do you have the sketch for the boronLTE/featherOLED/GPSwing on github? Can you share that with us?

This is the project.properties:

dependencies.AssetTrackerRK=0.1.7
dependencies.oled-wing-adafruit=0.0.5

Here’s the source:


#include "Particle.h"

// dependencies.AssetTrackerRK=0.1.7
// dependencies.oled-wing-adafruit=0.0.5


// Port of TinyGPS for the Particle AssetTracker
// https://github.com/mikalhart/TinyGPSPlus
#include "TinyGPS++.h"

#include "oled-wing-adafruit.h"

SYSTEM_THREAD(ENABLED);

/*
   This sample sketch demonstrates the normal use of a TinyGPS++ (TinyGPSPlus) object directly.
 */

void displayInfo(); // forward declaration

const unsigned long PUBLISH_PERIOD = 120000;
const unsigned long SERIAL_PERIOD = 5000;
const unsigned long MAX_GPS_AGE_MS = 10000; // GPS location must be newer than this to be considered valid

// The TinyGPS++ object
TinyGPSPlus gps;
unsigned long lastSerial = 0;
unsigned long lastPublish = 0;
unsigned long startFix = 0;
bool gettingFix = false;

OledWingAdafruit display;

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

	// The GPS module on the AssetTracker is connected to Serial1 and D6
	Serial1.begin(9600);

	// Settings D6 LOW powers up the GPS module
	pinMode(D6, OUTPUT);
	digitalWrite(D6, LOW);
	startFix = millis();
	gettingFix = true;

	display.setup();
	display.clearDisplay();
	display.display();
}

void loop()
{
	display.loop();

	while (Serial1.available() > 0) {
		if (gps.encode(Serial1.read())) {
			displayInfo();
		}
	}

}

void displayInfo()
{
	if (millis() - lastSerial >= SERIAL_PERIOD) {
		lastSerial = millis();

		char buf[128];
		if (gps.location.isValid() && gps.location.age() < MAX_GPS_AGE_MS) {


			display.clearDisplay();
			display.setTextSize(2);
			display.setTextColor(WHITE);
			display.setCursor(0,0);
			snprintf(buf, sizeof(buf), "%f", gps.location.lat());
			display.println(buf);
			snprintf(buf, sizeof(buf), "%f", gps.location.lng());
			display.println(buf);
			display.display();

			snprintf(buf, sizeof(buf), "%f,%f,%f", gps.location.lat(), gps.location.lng(), gps.altitude.meters());
			if (gettingFix) {
				gettingFix = false;
				unsigned long elapsed = millis() - startFix;
				Serial.printlnf("%lu milliseconds to get GPS fix", elapsed);
			}
		}
		else {
			strcpy(buf, "no location");
			if (!gettingFix) {
				gettingFix = true;
				startFix = millis();
			}
			display.clearDisplay();
			display.setTextSize(1);
			display.setTextColor(WHITE);
			display.setCursor(0,0);
			display.println("no fix");
			display.display();
		}
		Serial.println(buf);

		if (Particle.connected()) {
			if (millis() - lastPublish >= PUBLISH_PERIOD) {
				lastPublish = millis();
				Particle.publish("gps", buf, PRIVATE);
			}
		}
	}

}

1 Like

Thank you @rickkas7

Hi @rickkas7. I am using the Boron with the Adafruit Ultimate GPS Breakout, connecting the tx and rx pins to the Boron. I used your code above to get the location and it worked the very first time I flashed it to our board. However, I added this code to my other code using other sensors with the board as well. Now, when I try to flash your code or mine including the GPS while loop it will not flash to our Boron. Any thoughts on why this might be and how to fix it?

I took the while (Serial1.available() > 0) out of the code and it began to flash. So now I only have

if (gps.encode(Serial1.read())) {
		    
			displayInfo();
		}

however there it seems there is no data being read from Serial1 now. So is there no available space on the buffer for data to be written/read? I tried including Serial1.blockOnOverrun(false); to keep writing to Serial1 even if there is no space but I don’t think this is working… Not sure if I’m using that function correctly?

@rickkas7 So, I have been playing with your sketch quite a bit. I wanted to see if I could put the latitude and longitude into a Particle.variable, based on the TinyGPS++.h, but it seems to send back unreadable data in the Particle console. (BTW, I took off the OLED and used a doubler)

I get these numbers in the Particle console that I don’t understand:

VARIABLES

v gpsFix (bool) = true GET

v gpsLat (double) = 1.843727873348212e-308 GET

v gpsLon (double) = 7.45204603866976e-309 GET

v gpsTime (int32) = 1 GET

v gpsSpeed (double) = 7.45204603866976e-309 GET

Here is my sketch, for reference:

#include "Particle.h"

#include "TinyGPS++.h"

SYSTEM_THREAD(ENABLED);

const unsigned long PUBLISH_PERIOD = 15000; // GPS publish rate
const unsigned long SERIAL_PERIOD = 5000;
const unsigned long MAX_GPS_AGE_MS = 10000; // GPS location must be newer than this to be considered valid

TinyGPSPlus gps; // The TinyGPS++ object
unsigned long lastSerial = 0;
unsigned long lastPublish = 0;
unsigned long startFix = 0;
bool validFix = false;

void setup() {
    Serial.begin(9600);
    Serial1.begin(9600); 
    pinMode(D6, OUTPUT);
    digitalWrite(D6, LOW); 
    startFix = millis();
    validFix = true;
    Particle.variable("gpsFix", validFix);  
    Particle.variable("gpsLat", gps.location.lat()); // Latitude in degrees (double)
    Particle.variable("gpsLon", gps.location.lng()); // Longitude in degrees (double)
    Particle.variable("gpsTime", gps.time.value()); // Raw time in HHMMSSCC format (u32)
    Particle.variable("gpsSpeed", gps.speed.mph()); // Speed in miles per hour (double)
}

void loop() {
    while (Serial1.available() > 0) {
        gps.encode(Serial1.read()); 
        gpsVariable();
    }
}

void gpsVariable(){
    if (millis() - lastSerial >= SERIAL_PERIOD) {
        lastSerial = millis();
        char pubbuf[133];
        if (gps.location.isValid() && gps.location.age() < MAX_GPS_AGE_MS) {
            snprintf(pubbuf, sizeof(pubbuf), "{\"position\": {\"value\":1, \"context\":{\"gpsLat\": \"%f\", \"gpsLng\": \"%f\", \"gpsTime\": \"%f\", \"gpsSpeed\": \"%f\"}}}", gps.location.lat(), gps.location.lng(), gps.time.value(), gps.speed.mph());
            Serial.println(pubbuf);
            if (validFix) {
                validFix = true;
                unsigned long elapsed = millis() - startFix;
                }
        }
        else {
            if (!validFix) {
                validFix = false;
                startFix = millis();
                }
        }
        if (Particle.connected()) {
            if (millis() - lastPublish >= PUBLISH_PERIOD) {
                lastPublish = millis();
                Particle.publish("GPS Position", pubbuf, PRIVATE);
            }
        }
    }
}

@existech, obviously there is nothing in the compiler to flag the way you declared your Particle.variable(). You can’t use a function as the variable itself. Instead declare the correct variable types globally and use those in your Particle.variable() declarations. Then, somewhere in your code, update those varialbes using the TinyGPS++ function calls.

2 Likes

@peekay123 like this?

// This sketch is only for the Boron with Featherwing GPS

#include "Particle.h"

#include "TinyGPS++.h"

SYSTEM_THREAD(ENABLED);

const unsigned long PUBLISH_PERIOD = 15000;
const unsigned long SERIAL_PERIOD = 5000;
const unsigned long MAX_GPS_AGE_MS = 10000; // GPS location must be newer than this to be considered valid

TinyGPSPlus gps; // The TinyGPS++ object
FuelGauge fuel;
unsigned long lastSerial = 0;
unsigned long lastPublish = 0;
unsigned long startFix = 0;
bool validFix = false;
double latitude;
double longitude;
double gpstime;
double gpsspeed;
int battery;

void setup() {
    Serial.begin(9600);// The GPS module on the AssetTracker is connected to Serial1 and D6
    Serial1.begin(9600);
    pinMode(D6, OUTPUT);
    digitalWrite(D6, LOW); // Settings D6 LOW powers up the GPS module
    startFix = millis();
    validFix = true;
    Particle.variable("gpsFix", validFix); //ture or false 
    Particle.variable("gpsLat", latitude); // Latitude in degrees (double)
    Particle.variable("gpsLon", longitude); // Longitude in degrees (double)
    Particle.variable("gpsTime", gpstime); // Raw time in HHMMSSCC format (u32)
    Particle.variable("gpsSpeed", gpsspeed); // Speed in miles per hour (double)
    Particle.variable("batt", battery);
}

void loop() {
    while (Serial1.available() > 0) {
        gps.encode(Serial1.read()); 
        gpsVariable();
    }
}

void gpsVariable(){
    if (millis() - lastSerial >= SERIAL_PERIOD) {
        lastSerial = millis();
        latitude = gps.location.lat();
        longitude = gps.location.lng();
        gpstime = gps.time.value();
        gpsspeed = gps.speed.mph();
        battery = fuel.getVCell();
        char pubbuf[133];
        if (gps.location.isValid() && gps.location.age() < MAX_GPS_AGE_MS) {
            snprintf(pubbuf, sizeof(pubbuf), "{\"position\": {\"value\":1, \"context\":{\"gpsLat\": \"%f\", \"gpsLng\": \"%f\", \"gpsTime\": \"%f\", \"gpsSpeed\": \"%f\"}}}", gps.location.lat(), gps.location.lng(), gps.time.value(), gps.speed.mph());
            Serial.println(pubbuf);
            if (validFix) {
                validFix = true;
                unsigned long elapsed = millis() - startFix;
                }
        }
        else {
            if (!validFix) {
                validFix = false;
                startFix = millis();
                }
        }
        if (Particle.connected()) {
            if (millis() - lastPublish >= PUBLISH_PERIOD) {
                lastPublish = millis();
                Particle.publish("GPS Position", pubbuf, PRIVATE);
            }
        }
    }

}

@existech, that’s exactly the way! Try it and see what happens.

It worked! You are awesome. Don’t forget us newbies always looking up to you pros!

I can’t seem to get usable data for the time, speed and battery. I am reading online to figure it out. I am thinking I am formatting it wrong. If you have any resources, that would be great.

You see, the time and speed are all messed up.

VARIABLES

v gpsTime (double) = 14525100 GET

v gpsSpeed (double) = 0.207140301 GET

I can’t even get the batt to show at all

@existech, it’s always good to refer to library examples for guidance. In the case of TinyGPS++ you will see that gps.time.value() will return an unsigned int value representing the GMT time in UTC format. For hours, minutes or seconds, use gps.time.hour(), gps.time.minute(), gps.time.second() which all return a uint8_t aka an unsigned byte value.

As for battery, a little digging into the forum or the docs would show that fuel.getVCell() returns a float, not an int!

As for speed, it does return a double value but don’t expect a perfect zero value when you are not moving as there are always statistical deviations in the calculated data from the satellites.

2 Likes

Just a note here, you should assign the float you get from fuel.getVCell() to a double which you then expose via Particle.variable() don't try to register a float directly (nor try type casting it)

2 Likes

Thank you! I am learning rapidly

Is the screen necessary for the tracker to work, also is there any tutorial someone can post?

The screen is optional. I wrote a blog post about the project here with a full tutorial: https://blog.particle.io/2019/05/17/learn-how-to-build-this-cellular-asset-tracker-with-a-particle-boron/