Hello,
I'm using an MKR1500 with a GPS6MV2 board that has a NEO-6M GPS Module.
I want to make a system which can track location when the board is powered on via USB.
When the board is unplugged and the USB looses power i want the board to continue to send positional data over the MQTT Network for an hour before going to sleep until the board is powered on.
I need this system to be as reliable as possible. The Positional data doesn't need to be incredibly accurate but it must be reliable and relatively fail safe.
What i have working so far.
- The MQTT connection works.
- The Sleep wake functionality is stable.
- I have seen the GPS module work.
The Problem.
- The GPS module seems flakey at best, i've tested it in various places, and sometime it takes a crazy amount of time to find a lock.
- other times the inbuilt Blue LED on the board starts flashing meaning it has a lock but the lat and long values aren't updated.
- I modified the original GPS code to remove a while loop and replace it with a for loop of 50 cycles because it was causing the program lock, not sure why the original code would of had a while(1) loop which is impossible for the program to enter.
Can anyone please help ? Why does TinyGPS seem so flakey ?
Can i use the modem / networking classes to get very rough position if the GPS cant find a lock?
Here's the code.
#include "main.h"
#include <Arduino.h>
#include <TimeLib.h>
#include "ArduinoLowPower.h"
#include <MKRNB.h>
#include <ArduinoMqttClient.h>
#include <TinyGPSPlus.h>
#include <Arduino_MKRGPS.h>
#include "wiring_private.h"
// PIN Number
const char PINNUMBER[] = SECRET_PINNUMBER;
// #define serialGPS Serial1
Uart serialGPS (&sercom3, 1, 0, SERCOM_RX_PAD_1, UART_TX_PAD_0); // Create the new UART instance assigning it to pin 1 and 0
// initializing network instances.
NBClient client;
MqttClient mqttClient(client);
NBModem modem;
GPRS gprs;
NB nbAccess;
// initializing GPS instances
TinyGPSPlus gps;
// sleep & wake variables.
const int powerDetectionPin = 5;
bool powerd = true;
bool hasBeenWoken;
bool wasSentToSleep;
// GPS variables.
float latitude;
float longitude;
int sattaliteCount;
// Sending data length variables
unsigned long unpluggedTime;
unsigned long dataSendingDuration = 60 * 60 * 1000; // n Minutes
// Publishing Frequency Variables
unsigned long previousMillis = 0;
unsigned long interval = 1 * 60 * 1000; // n Minutes
void charging() {
hasBeenWoken = true;
}
void connectToNetwork()
{
Serial.println("Setting up network...");
// connection state
boolean connected = false;
Serial.print("Modem Initialization ...");
// After starting the modem with NB.begin()
// attach to the GPRS network with the APN, login and password
while (!connected)
{
Serial.print(".");
if ((nbAccess.begin(PINNUMBER) == NB_READY) &&
(gprs.attachGPRS() == GPRS_READY))
{
connected = true;
Serial.println("Connected");
}
else
{
Serial.println("Not connected. ");
delay(1000);
}
}
// prints the modems IMEI number cut and paste into Adafruit cloud
Serial.println(modem.getIMEI());
mqttClient.setId(modem.getIMEI());
mqttClient.setUsernamePassword(AIO_USERNAME, AIO_KEY);
Serial.print("MQTT Initialization ...");
if (!mqttClient.connect(AIO_SERVER, AIO_SERVERPORT))
{
Serial.print("MQTT connection failed! Error code = ");
Serial.println(mqttClient.connectError());
// Rerunning Setup if connection fails.
setup();
} else {
Serial.println("Connected");
}
}
void connectGPS(){
Serial.print("GPS Initialization.");
Serial.println(serialGPS.read());
// - - - - - - GPS Section - - - - - -
for (int i = 0; i < 50; i++) {
if(serialGPS.available()) {
Serial.print(".");
if(gps.encode(serialGPS.read()))
{
gps.location.lat();
// sattaliteCount = gps.satellites.value();
if(gps.location.isValid())
{
Serial.print("decoding sucsesful.");
latitude = gps.location.lat();
longitude = gps.location.lng();
}
Serial.print("enconding valid.");
break;
}
delay(50);
}
}
Serial.println("");
}
void setup() {
for (int i = 0; i < 20; i++) {
digitalWrite(LED_BUILTIN, HIGH);
delay(100);
digitalWrite(LED_BUILTIN, LOW);
delay(100);
}
delay(1000);
serialGPS.begin(9600);
// GPS Input and Output Pins.
pinPeripheral(1, PIO_SERCOM); //Assign RX function to pin 1
pinPeripheral(0, PIO_SERCOM); //Assign TX function to pin 0
// put your setup code here, to run once:
pinMode(powerDetectionPin, INPUT_PULLUP);
// Wake up interupt when board is plugged in.
LowPower.attachInterruptWakeup(powerDetectionPin, charging, RISING);
connectToNetwork();
}
void loop() {
unsigned long currentMillis = millis();
// initiating Setup after wake up.
if(hasBeenWoken && wasSentToSleep){
hasBeenWoken = false;
wasSentToSleep = false;
setup();
}
// Updating GPS Position.
connectGPS();
// - - - - - - SENDING DATA SECTION - - - - - -
if(currentMillis - previousMillis >= interval)
{
// save the last time a message was sent
previousMillis = currentMillis;
Serial.println("Publishing Data");
// Check to to stop 0, 0 being sent before GPS lock.
if(latitude != 0.0 && longitude != 0.0){
Serial.println("Lat: " + String(latitude) + " - Long: " + String(longitude) );
// Updating the dashboard with location.
mqttClient.beginMessage(AIO_FEED_LOCATION);
mqttClient.print("{\"lat\":");
mqttClient.print(latitude);
mqttClient.print(",");
mqttClient.print("\"lon\":");
mqttClient.print(longitude);
mqttClient.println("}");
mqttClient.endMessage();
}
// Updating the dashboard Logs
mqttClient.beginMessage(AIO_FEED_LOGS);
mqttClient.println(" - Modem IMEI number: " + String(modem.getIMEI()));
mqttClient.println(" - currentMillis: " + String(currentMillis));
mqttClient.println(" - unpluggedTime: " + String(unpluggedTime));
mqttClient.println(" - difference: " + String(currentMillis - unpluggedTime));
mqttClient.println(" - threshhold: " + String(dataSendingDuration));
mqttClient.println(" - sattaliteCount: " + String(sattaliteCount));
mqttClient.println(" - GPS Coordinates: " + String(latitude) + " latitude, " + String(longitude) + " longitude");
mqttClient.println(" - digitalRead(5): " + String(digitalRead(5)));
mqttClient.endMessage();
for (int i = 0; i < 2; i++) {
digitalWrite(LED_BUILTIN, HIGH);
delay(100);
digitalWrite(LED_BUILTIN, LOW);
delay(100);
}
delay(1000);
for (int i = 0; i < 2; i++) {
digitalWrite(LED_BUILTIN, HIGH);
delay(100);
digitalWrite(LED_BUILTIN, LOW);
delay(100);
}
}
// - - - - - - SLEEP CONTROL SECTION - - - - - -
// Check when board has been unplugged for first time.
if(!digitalRead(5) && powerd){
powerd = false;
// recording time when unplugged.
unpluggedTime = currentMillis;
for (int i = 0; i < 7; i++) {
digitalWrite(LED_BUILTIN, HIGH);
delay(200);
digitalWrite(LED_BUILTIN, LOW);
delay(200);
}
delay(1000);
}
// resetting after being re plugged.
else if (digitalRead(5) && !powerd) {
powerd = true;
}
// updating times whilst board is plugged in.
if(digitalRead(5)){
unpluggedTime = currentMillis;
}
// Final Check before sending board to sleep.
if((currentMillis - unpluggedTime > dataSendingDuration)){
for (int i = 0; i < 10; i++) {
digitalWrite(LED_BUILTIN, HIGH);
delay(100);
digitalWrite(LED_BUILTIN, LOW);
delay(100);
}
delay(1000);
wasSentToSleep = true;
LowPower.sleep();
for (int i = 0; i < 10; i++) {
digitalWrite(LED_BUILTIN, HIGH);
delay(100);
digitalWrite(LED_BUILTIN, LOW);
delay(100);
}
}
// Makes LED flash to show loop is turning.
for (int i = 0; i < 5; i++) {
digitalWrite(LED_BUILTIN, HIGH);
delay(500);
digitalWrite(LED_BUILTIN, LOW);
delay(500);
}
Serial.print(".");
delay(2000);
}
void SERCOM3_Handler()
{
serialGPS.IrqHandler();
}