GPS Tracker with Arduino MKR FOX 1200

GPS Tracker with Arduino MKR FOX 1200 © GPL3+

Sending accurate float:32 GPS data via the Sigfox network.

  • 10,959 views
  • 14 comments
  • 44 respects

Components and supplies

Abx00014 featured xjsqphgdlv
Arduino MKR Fox 1200
×1
GPS Module (Generic)
I´m using a fake ublox NEO6m that resulted to be a ATGM332D remarked. If the module had standby mode you would not need the transistor switch.
×1
Fairchild semiconductor pn2222abu. image
General Purpose Transistor NPN
I´m using a BC548.
×1
Mfr 25frf52 1k sml
Resistor 1k ohm
×1

About this project

About This Project

The tracker uses an ATGM332 GPS module to get the GPS position with more accuracy than the location services provided by Sigfox. Then, the position data is sent as a 'string' via the Sigfox network, and finally delivered by email.

The Arduino MKR FOX 1200

The board is similar to the Arduino Zero, which is based on the SAM D21, and includes a ATA8520 Sigfox module. It is a low power board which comes with a one year free subscription to the Sigfox network with the board (for up to 140 messages per day), as well as free access to Spot'it geolocation service.

More info: https://store.arduino.cc/arduino-mkrfox1200

The ATGM332 GPS Module

This low-cost, low-power GPS module fits very well with the Arduino MKR FOX 1200 because it works with only 2.7V (nominal 3.3V).

Initially, I had bought a NEO6m2 module which has standby mode, but it resulted to be a fake NEO6 module. It actually was a ATGM332 module. The result was that it lacks of a standby mode, so I needed to use a transistor to turn the GPS module on when needed, and turn it off in order to save battery. My goal is to have location info at slow rate, i.e. 4 messages per hour, as Sigfox only allows 140 messages per day.

I use the TinyGPS library (https://github.com/mikalhart/TinyGPS) to decode the GPS frames.

The Transistor Switch

I needed to turn the GPS on and off when needed. I thought relay modules were too bulky and powerful if I only needed to switch a 3V and few milliamps load. In addition, most relay modules need 5V. So, a transistor would be a better solution. Also, the MKR FOX 1200 only provides 7 mA per I/O pin.

I use a BC548 NPN transistor to switch between the saturation and cut-off regions. When a zero signal is applied to the Base of the transistor it turns “OFF”, acting like an open switch and no collector current flows. With a positive signal appliedto the Base of the transistor it turns “ON” acting like a closed switch and maximum circuit current flows through the device.

More info at: https://www.electronics-tutorials.ws/transistor/tran_4.html

Connections

The only power source is a two 1.5V AA battery pack that powers the Arduino MKR FOX 1200. The GPS module gets is power from the Arduino board.

The Arduino MKR FOX 1200, communicates with the GPS module using a second Serial port through pins 13 and 14, called Serial1 in the code. (See https://www.arduino.cc/en/Tutorial/SamdSercom). The TX data output of the GPS module is connected to the Serial data input (pin 13) of the Arduino board.

Besides, the Arduino board uses the PIN2 to turn the GPS module on and off, as it is explained.

Sending GPS Info via Sigfox

I wanted to send the GPS info using float type data, but when I tried I always received null values.

Searching the web, I came across this project https://github.com/nicolsc/SmartEverything_SigFox_GPS by Nicolas Lesconnec. He uses AT commands to send any data type, and convert 'float' to 'hex'. However, I think the Arduino MKR FOX 1200 doesn´t have AT mode, and I couldn´t make it work.

So, I made dozens of tests and, modifying the Nicolas´s code, I found a way to send a 'string' that was parsed as 'float:32' by the Sigfox platform, and it could be used directly without any conversion by the final receiver.

Sigfox data is limited to 12 bytes. The data I send to the SigFox network is:

Latitude, float:32type, 4 bytes.

Longitude, float:32type, 4 bytes.

Altitude, float:32type, 4 bytes.

The Sigfox Callback Configuration

The Sigfox Custom Callback configuration is:

lat::float:32lng::float:32 alt::float:32

You will receive an email like this:

In order to see the position easily, I included a URL to Google Maps using the informationreceived: https://maps.google.com/maps/?q={customData#lat}, {customData#lng}

And finally, this is the result:

Code

MKRFOX GPS TrackerArduino
#include <SigFox.h>
#include <ArduinoLowPower.h>
#include <TinyGPS.h>//incluimos TinyGPS

#define WAITING_TIME 15
#define GPS_PIN 2
#define GPS_INFO_BUFFER_SIZE 128

bool debug = false;

TinyGPS gps;//GPS Object

//GPS data variables
int year;
byte month, day, hour, minute, second, hundredths;
unsigned long chars;
unsigned short sentences, failed_checksum;
char GPS_info_char;
char GPS_info_buffer[GPS_INFO_BUFFER_SIZE];
unsigned int received_char;
bool message_started = false;
int i = 0;

// GPS coordinate structure, 12 bytes size on 32 bits platforms
struct gpscoord {
  float a_latitude;  // 4 bytes
  float a_longitude; // 4 bytes
  float a_altitude;  // 4 bytes
};

float latitude  = 0.0f;
float longitude = 0.0f;
float altitud = 0;


//////////////// Waiting function //////////////////
void Wait(int m, bool s) {
  //m minutes to wait
  //s slow led pulses
  if (debug) {
    Serial.print("Waiting: "); Serial.print(m); Serial.println(" min.");
  }

  digitalWrite(LED_BUILTIN, LOW);

  if (s) {

    int seg = m * 30;
    for (int i = 0; i < seg; i++) {
      digitalWrite(LED_BUILTIN, HIGH); //LED on
      delay(1000);
      digitalWrite(LED_BUILTIN, LOW); //LED off
      delay(1000);
    }

  } else {
    int seg = m * 15;
    for (int i = 0; i < seg; i++) {
      digitalWrite(LED_BUILTIN, HIGH); //LED on
      delay(1000);
      digitalWrite(LED_BUILTIN, LOW); //LED off
      delay(3000);

    }
  }
}

/////////////////// Sigfox Send Data function ////////////////
void SendSigfox(String data) {
  if (debug) {
    Serial.print("Sending: "); Serial.println(data);
    if (data.length() > 12) {
      Serial.println("Message too long, only first 12 bytes will be sent");
    }
  }

  // Remove EOL
  //data.trim();

  // Start the module
  SigFox.begin();
  // Wait at least 30mS after first configuration (100mS before)
  delay(100);
  // Clears all pending interrupts
  SigFox.status();
  delay(1);
  if (debug) SigFox.debug();
  delay(100);

  SigFox.beginPacket();
  SigFox.print(data);


  if (debug) {
    int ret = SigFox.endPacket(true);  // send buffer to SIGFOX network and wait for a response
    if (ret > 0) {
      Serial.println("No transmission");
    } else {
      Serial.println("Transmission ok");
    }

    Serial.println(SigFox.status(SIGFOX));
    Serial.println(SigFox.status(ATMEL));

    if (SigFox.parsePacket()) {
      Serial.println("Response from server:");
      while (SigFox.available()) {
        Serial.print("0x");
        Serial.println(SigFox.read(), HEX);
      }
    } else {
      Serial.println("Could not get any response from the server");
      Serial.println("Check the SigFox coverage in your area");
      Serial.println("If you are indoor, check the 20dB coverage or move near a window");
    }
    Serial.println();
  } else {
    SigFox.endPacket();
  }
  SigFox.end();
}


//////////////////  Convert GPS function  //////////////////
/* Converts GPS float data to Char data */

String ConvertGPSdata(const void* data, uint8_t len) {
  uint8_t* bytes = (uint8_t*)data;
  String cadena ;
  if (debug) {
    Serial.print("Length: "); Serial.println(len);
  }

  for (uint8_t i = len - 1; i < len; --i) {
    if (bytes[i] < 12) {
      cadena.concat(byte(0)); // Not tested
    }
    cadena.concat(char(bytes[i]));
    if (debug) Serial.print(bytes[i], HEX);
  }

  if (debug) {
    Serial.println("");
    Serial.print("String to send: "); Serial.println(cadena);
  }

  return cadena;
}


////////////////////////// Get GPS position function/////////////////////
String GetGPSpositon() {

  int messages_count = 0;
  String pos;

  if (debug) Serial.println("GPS ON");
  digitalWrite(GPS_PIN, HIGH); //Turn GPS on
  Wait(1, false);
  while (messages_count < 5000) {
    while (Serial1.available()) {

      int GPS_info_char = Serial1.read();

      if (GPS_info_char == '$') messages_count ++; // start of message. Counting messages.


      if (debug) {
        if (GPS_info_char == '$') { // start of message
          message_started = true;
          received_char = 0;
        } else if (GPS_info_char == '*') { // end of message
          for (i = 0; i < received_char; i++) {
            Serial.write(GPS_info_buffer[i]); // writes the message to the PC once it has been completely received
          }
          Serial.println();
          message_started = false; // ready for the new message
        } else if (message_started == true) { // the message is already started and I got a new character
          if (received_char <= GPS_INFO_BUFFER_SIZE) { // to avoid buffer overflow
            GPS_info_buffer[received_char] = GPS_info_char;
            received_char++;
          } else { // resets everything (overflow happened)
            message_started = false;
            received_char = 0;
          }
        }
      }

      if (gps.encode(GPS_info_char)) {
        gps.f_get_position(&latitude, &longitude);
        altitud = gps.altitude() / 100;

        // Store coordinates into dedicated structure
        gpscoord coords = {altitud, longitude, latitude};

        gps.crack_datetime(&year, &month, &day, &hour, &minute, &second, &hundredths);

        if (debug) {
          Serial.println();
          Serial.println();
          Serial.print("Latitud/Longitud: ");
          Serial.print(latitude, 5);
          Serial.print(", ");
          Serial.println(longitude, 5);
          Serial.println();
          Serial.print("Fecha: "); Serial.print(day, DEC); Serial.print("/");
          Serial.print(month, DEC); Serial.print("/"); Serial.print(year);
          Serial.print(" Hora: "); Serial.print(hour, DEC); Serial.print(":");
          Serial.print(minute, DEC); Serial.print(":"); Serial.print(second, DEC);
          Serial.print("."); Serial.println(hundredths, DEC);
          Serial.print("Altitud (metros): "); Serial.println(gps.f_altitude());
          Serial.print("Rumbo (grados): "); Serial.println(gps.f_course());
          Serial.print("Velocidad(kmph): "); Serial.println(gps.f_speed_kmph());
          Serial.print("Satelites: "); Serial.println(gps.satellites());
          Serial.println();

        }

        gps.stats(&chars, &sentences, &failed_checksum);
        if (debug) Serial.println("GPS turned off");
        digitalWrite(GPS_PIN, LOW); //GPS turned off
        pos = ConvertGPSdata(&coords, sizeof(gpscoord)); //Send data
        return pos;

      }

    }
  }
  pos = "No Signal";
}




//////////////////SETUP///////////////////

void setup() {
  if (debug) {
    Serial.begin(9600);
    while (!Serial) {}// wait for serial port to connect. Needed for native USB port only
    Serial.println("Serial Connected");
  }

  //Serial1 pins 13-14 for 3.3V connection to GPS.
  Serial1.begin(9600);
  while (!Serial1) {}
  if (debug) {
    Serial.println("GPS Connected");
  }

  pinMode(GPS_PIN, OUTPUT); //pin de interruptor del GPS

  if (!SigFox.begin()) {
    Serial.println("Shield error or not present!");
    return;
  }

  // Enable debug led and disable automatic deep sleep
  if (debug) {
    SigFox.debug();
  } else {
    SigFox.end(); // Send the module to the deepest sleep
  }


}



//////////////////////LOOP////////////////////////

void loop() {

  String position_data;

  position_data = GetGPSpositon();
  SendSigfox(position_data);

  Wait(WAITING_TIME, false);


}

Schematics

Connections
mkrfox_gps_schema_EYXRfZVOg2.vsd

Comments

Similar projects you might like

Arduino MKR FOX 1200 Sigfox Meteo Station

Project tutorial by Giovanni Gentile

  • 3,393 views
  • 5 comments
  • 7 respects

MKR FOX 1200 Movement Trigger

Project tutorial by Arduino_Genuino and Andrea Richetta

  • 11,173 views
  • 3 comments
  • 26 respects

MKR FOX 1200 Weather Monitor

Project tutorial by Arduino_Genuino

  • 22,796 views
  • 13 comments
  • 39 respects

Publish Any Event to Wia Using Your MKR FOX 1200

Project tutorial by Spivey

  • 465 views
  • 0 comments
  • 2 respects

GPS Location Display With GPS And TFT Display Shields

Project tutorial by Boian Mitov

  • 10,157 views
  • 5 comments
  • 27 respects
Add projectSign up / Login