M5Stack Atomic GPS. ESP32 TinyGPS++ tracker, GPX export on SD card, visualization on Google Maps or VSCode

m5stack gps Atom lite tailbat gpx google maps vscode export
Table of Contents

The GPS module for M5Stack Atom is a mini box that combines a UBX-M8030-KT u-blox GPS module and an M5Atom Lite ESP32-PICO-D4 mini module from M5Stack. For this project, we are going to develop a GPS tracker using the Arduino TinyGPS++ library which will be used to retrieve the location data, the number of satellites, the altitude and the positioning accuracy (HDOP). The tracker’s GPS data will be recorded on a microSD card in GPX format in order to be able to display the track on mapping software such as OpenStreetMap, Google MAP or Leaflet.


A statistics file is also generated automatically by the Arduino program. It exports the distance traveled in meters and kilometers, the maximum and average speed.

Presentation of the M5Atom Lite GPS module from M5Stack

The M5Stack GPS module is a box that has a UBX-M8030-KT u-blox GPS receiver on which a Core M5Atom Lite is inserted (the version with a single light point).

  • Prices in  €
  • Prices in $

The package contains the following items in a protective transparent plastic case

  • M5Atom Lite built around an ESP32-PICO-D4 SoC from Espressif
  • The u-blox GPS box
  • A USB-C cable for programming
  • Screws + Allen key

atomic m5stack M5atom lite gps module

The GPS box is equipped with the following elements

  • A UBX-M8030-KT GPS receiver from the manufacturer u-blox
  • A micro-SD card reader
  • A 4-pin Grove A PH2.0 port exposing the I2C bus (pins 21 and 22 of the ESP32-PICO-D4)
atomic m5stack M5atom lite gps tailbat module atomic m5stack M5atom lite gps tailbat module side atomic m5stack M5atom lite gps module sdcard


Small regret, the box does not embed a LiPo battery. To power the pack, you will need to use a Power Bank, the M5Stack TailBat power supply sold separately or to DIY your own 3D printing solution.

  • Prices in €
  • Prices in $

6.2Expert Score
M5Atom Lite GPS module

GPS pack with ESP32-Pico-D4 M5Atom Lite mini module

Price / Specifications ratio
Build quality
Software support
  • Compact
  • Speed of acquisition of the GPS signal
  • No LiPo battery or connector
  • TailBat pack poorly suited to the pack
  • Cannot configure the GPS

Presentation of the M5Atom Lite ESP32-PICO-D4

m5stack m5atom lite esp32 pico d4The M5Stack Atom Lite is a very compact mini development board measuring 24x24x10mm built around an ESP32-PICO-D4 microcontroller from Espressif equipped with 4MB of integrated SPI flash memory. The PICO is a version suitable for clothing or mobile electronics. Like its big brother, it has WiFi and Bluetooth connectivity.

  • Prices in €
  • Prices in $

Here are the main equipment and technical characteristics of the Atom Lite

LED RGB SK6812 driver on GPIO27 pin
IR emitter GPIO12 pin
Buttons User on pin GPIO39


GPIO compatible breadboard G19, G21, G22, G23, G25, G33

3V3, 5V, GND

Ports USB-C for power and programming

GROVE (I2C + I/0 + UART) 4 pin PH2.0 connector. GND, 5V, G26, G32

WiFi antenna 2.4G 3D antenna
Operating temperature 0°C to 40°C
Weight 3g
Dimensions 24 x 24 x 10 mm

More information on this page.

Note, the IR emitter cannot be used when the module is installed on the GPS module.

UBX-M8030 u-blox GPS receiver (M8 series)

The UBX-M8030 receiver is a versatile GPS chip from the u-blox M8 series, the main characteristics of which are:

  • Simultaneous reception of up to 3 types of GNSS positioning systems (GPS, Galileo, GLONASS, BeiDou)
  • Navigation sensitivity ranging down to -167 dBm
  • Low power consumption
  • Superior positioning accuracy in urban
  • Support for all satellite systems
  • Operating temperature range from -40°C to + 105°C (automotive grade)

From an IT point of view, the UBX-M8030 GPS receiver sends at a frequency of 10Hz (10 times per second) messages to the NMEA standard via several interfaces (UART, I2C, USB and SPI). M5Stack has opted for the UART 9600 baud serial interface.

Only regret, there is only the TX pin which is connected. This means that it will not be possible (without modifying the board) to send configuration commands. This can be blocking for some applications but on a daily basis, it works very well.

Useful Resources

Here are some links to useful resources

The NMEA 0183 standard

There are several constellations of satellites allowing for positioning

  • Galileo the European system
  • GPS the oldest (and best known) American system
  • GLONASS  the Ruse system
  • BeiDou the Chinese system

Each satellite sends frames which are a simple string of characters that the satellite receiver will recover and decode. The NEMA 0183 is a standard used by all positioning system enabling chip development versatile multi-systems. The NMEA 0183 standard   is a specification for communication between marine equipment, including GPS equipment. It is defined and controlled by the  National Marine Electronics Association (NMEA), an American association of manufacturers of marine electronic devices.

Each system has its own prefix to identify it

Here is an example of a NMEA frame


$ GPGGA: Type of frame
074036.289     : Frame sent at 07:40m 36.289s ( UTC standard time )
4936.5375, N    : Latitude 49.608958 ° North = 48 ° 36’32.25 “North
00740.9373, E  : Longitude 7.682288 ° East = 7 ° 40’56.238 “East
1: Positioning type. 1 for the GPS
04                        : Number of satellites used to calculate the coordinates
3.2: Horizontal precision or HDOP (Horizontal dilution of precision)
202.2, M             : Altitude 202.2 meters
,,,,, 0000: Other information can be entered in these fields
* 0E: Parity checksum, a single XOR  on characters between $ and *3

More information on this Wikipedia page.

By retrieving the signal from several satellites, the GPS receiver is able to determine its position on the ground by triangulation. The more satellites there are, the better the positioning accuracy will be. This is the HDOP.

TinyGPSPlus, the ideal library for a GPS Tracker

There are several ESP32 / ESP8266 compatible Arduino libraries that allow you to decode GPS messages to the NMEA standard. You will also find in the example AtomicGPS with the M5Atom library, a library for decoding NMEA messages.

After having tested Steve Marple’s M5Stack and MicroNMEA library , I advise you to use Mikal Hart’s TinyGPSPlus.

The big advantage of TinyGPS++ is that it has lots of tools:

  • Extraction of the date and time which is in UTC format
  • Checks the validity of all information (location, date, time, speed, etc.)
  • And especially the distanceBetween() method which calculates the distance traveled between two points

Create a project and install the ESP32 and M5Stack libraries on the Arduino IDE

Before you start, you will already need to install the ESP32-Arduino SDK that supports ESP32 and ESP32-Pico development boards. Everything is explained in detail in this tutorial.

Read Also
ESP32. Getting started with ESP32-Arduino on IDE Arduino, macOS, Windows, Linux

Once the Arduino IDE is ready, open the library manager and install the following libraries:

  • M5Atom the basic library which provides access to the LED and / or user button
  • FastLED it is used by the M5Atom library to drive the LED located under the user button
  • TinyGPSPlus the library to decode GPS NMEA frames
  • CSV Parser used in the project to store and reload some statistics (distance traveled, average speed and maximum speed)

Select the M5Stick-C development board

The M5Atom Lite is built a lite version of the ESP32, the ESP32-PICO. If you choose a standard ESP32 development board, you will get an error uploading the program from the Arduino IDE.

There is no configuration (yet) for the Core M5Atom Lite and M5Atom. You must select the M5Stick-C from the list which also includes an ESP32-PICO.

ide arduino M5stickc M5atom lite M5atomic esp32-pico

Decrease the transfer speed to 115200 baud otherwise you will get an error.

Select the level of debugging messages, Info for example.

Create a project and install the libraries on PlatformIO

On PlatformIO, there is much less preparation. Open the PlatformIO home screen

platformio pio tool menu vscode

Create a new project

Create a new project with PlatformIO under VSCode

In the configuration wizard:

  • Give a name to your project
  • Select the M5Stick-C board (as on the Arduino IDE)
  • Keep the Arduino framework
  • Possibly modify the registration file
  • Start the creation of the project by clicking on Finish

platformio M5stickc M5atom lite M5atomic esp32-pico

When the project is ready, open the platformio.ini configuration file and paste the following configuration to install the libraries. The installation of the library begins with each backup of the platformio.ini file.

platform = espressif32
board = m5stick-c
framework = arduino

monitor_speed = 115200

lib_deps = 
    m5stack/M5Atom @ ^0.0.1
    fastled/FastLED @ ^3.3.3
    mikalhart/TinyGPSPlus @ ^1.0.2
    michalmonday/CSV Parser @ ^0.2.0

build_flags = -DCORE_DEBUG_LEVEL=5

What does this configuration contain

  • monitor_speed allows to modify the speed of the PlatformIO serial monitor which defaults to a 9600 baud rate
  • lib_deps the list of libraries to install (M5Atom, FastLED, TinyGPSPlus, CSV Parser)
  • build_flags allows to define the message level of the ESP_LOG library, more practical than the Serial.print().

A GPS tracker project with export to GPX format

The objective of this project is to save the coordinates at regular intervals as well as in GPX format. The GPX format is a standard GPS coordinate recording format supported by all mapping software. It is a file in XML format, here is an example taken from the project. To learn more about the GPX format, you will find plenty of information on this Wikipedia page.

<?xml version="1.0" encoding="UTF-8"?>
<gpx version="1.1" creator="diyprojects.io" xmlns="http://www.topografix.com/GPX/1/1" 
xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd">
      <trkpt lat="..." lon="...">
trk : trace

trkseg : segment

trkpt : GPS coordinates (latitude, longitude)

time : timestamp in ISO 8601 format

sat : number of satellites

he : altitude

hdop : precision


The more the acquisition frequency increases, the more the risk of destroying the micro SD card increases when you want to recover the data. Rather than suddenly cutting off the power supply by removing the battery for example, it will suffice to press the user button once (pin GPIO39 of the ESP32) and wait for the LED to flash twice in orange.

To resume recording, insert the micro SD card in the reader and do a Reset using the side button.

Arduino program parameters

Here are the settings that you can adjust according to your needs. The value in (parentheses) is the default.

  • TIME_ZONE (1) time difference compensation
  • RECORD_FREQUENCY (5000) Recording frequency
  • ACTIVATE_DEEP_SLEEP_ONCLICK (true) activate standby when user button is pressed
  • GPS_TIMEOUT (5000) Reports an error if the GPS did not respond within the allotted time
  • FORCE_UPDATE_STATS (false) Force statistics to be saved
  • SPEED_BUFFER_SIZE (10) Number of points used to calculate the average speed

How to use the TinyGPS++ library

The GPS receiver continuously sends messages to the serial port (UART). To retrieve these strings, we will therefore open a second serial port and “pass” the strings to the TinyGPS++ library which will take care of decoding all this.

We created an object of type TinyGPSPlus which contains all the methods and the GPS data as well as a second serial port (the first being used to upload and debug the program). The name doesn’t matter.

TinyGPSPlus gps;
HardwareSerial gps_uart(1);

In the setup() , it will then suffice to open the serial port on pin 22. The RX pin of the GPS module not being connected, we pass the value -1 as a parameter.


Then, it suffices to retrieve at regular intervals (for example every second) the messages sent by the GPS module in the loop () .

static void readGPS(unsigned long ms)
    while (gps_uart.available())
  } while (millis() - start < ms);

How to retrieve GPS data with TinyGPS++ (API)

The GPS data are grouped in the TinyGPS++ library in the following objects. Each object has an isValid() method which makes it possible to check that the decoded values ​​are correct and isUpdated() which makes it possible to know if the value has been updated since the last acquisition. This reduces the number of GPS points in the GPX file.

  • TinyGPSLocation location , GPS coordinates. Functions age(), lat(), lng(), rawlat(), rawlng()
  • TinyGPSDate date , date of the GPS point. Functions age(), year(), month(), day()
  • TinyGPSTime time hour of the GPS point. Functions age(), hour(), minute(), second(), centisecond()
  • TinyGPSSpeed speed. Speed. Functions knots(), mph(), mps(), kmph()
  • TinyGPSCourse race . Race function()
  • TinyGPS Altitude altitude. Functions meter(), miles(), kilometers(), feet()
  • TinyGPSInteger satellites. Value() functions to retrieve the number of satellites
  • TinyGPSHDOP hdop. hdop() function

For example to recover the speed of the vehicle in km/h, we will execute


In addition to these methods, we can know the distance between two points (GPS coordinates) using the methods

static double distanceBetween(double lat1, double long1, double lat2, double long2)


static double courseTo(double lat1, double long1, double lat2, double long2)

For example, knowing the GPS coordinates of the previous point, we can estimate the distance traveled between two measurements like this

double _distance = gps.distanceBetween(gps.location.lat(), gps.location.lng(), prev_lat, prev_long);
Serial.print("distance = "); Serial.println(_distance);

How do I create and then add data to a GPX file?

In the article “Store data on a micro SD card. Arduino code compatible ESP32, ESP8266”, we saw the basic methods of storing data on an SD card. It’s ultimately as easy as printing text on the serial monitor.

Read Also
ESP32. Store temporary data in RTC memory during deep-sleep

Here, we want to add data to an existing file each time we get new GPS coordinates. To add a new point to the GPX file (which is an XML format), the trick is to move the pointer to the place where you want to insert new data using the seek() function.

<?xml version="1.0" encoding="UTF-8"?>
<gpx version="1.1" creator="diyprojects.io" xmlns="http://www.topografix.com/GPX/1/1" 
xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd">
      <trkpt lat="..." lon="..."></trkpt>
      <trkpt lat="..." lon="..."></trkpt>
      <trkpt lat="..." lon="..."></trkpt>
            <--------------------------------- POINTER

This way, there will be no need to store a large amount of data in memory. This is much more efficient than JSON which stores data on flash memory.

Remember that flash memory has a limited number of write cycles which is not suitable for a data acquisition system.

To position the pointer, all you have to do is “measure” the size of the file using the size() function and subtract the size used by the end string (here 27 bytes).

unsigned long filesize = gpxFile.size();
filesize -= 27;

Then we write the data of the new point and the end of the file using the print() method. To avoid unnecessary use of the microcontroller’s memory, use the F macro.

gpxFile.print(F("<trkpt lat=\"")); 
gpxFile.print(F("\" lon=\""));

How to flash the LED of the M5Atom Lite

If you run the example delivered with the M5Atom Lite library, you will get two errors.

FastLed, the library is not installed. We have already solved the problem previously

The line M5.dis.fillpix(0x00004f); returns an error because the fillpix() method is not exposed by the M5Atom Lite library. The fillpix() method has been replaced by the drawpix() method which manages the LED matrix of the M5Atom 2020. As there is only one light point available on the M5Atom Lite, it suffices to indicate 0.0 as coordinates.


In theory, it is possible to use the color palette of the FastLED library rather than passing the Hexa value of the desired color. It is much simpler. However, I obtained unexpected results without finding the source of the problem. If you’ve fixed the issue, feel free to share your solution in the comments below the project.


Project Code of GPS Tracker with an M5Atom Lite

Here is the code for the project which you can also grab from GitHub.

#include <Arduino.h>
#include "M5Atom.h"
#include <SPI.h>
#include "FS.h"
#include <SD.h>
#include <TinyGPS++.h>
#include "esp_log.h"
#include <CSV_Parser.h>

#define TIME_ZONE 1             // Time compensation 
#define RECORD_FREQUENCY 5000   // Record frequency  

#define GPS_TIMEOUT    5000     /* GPS acquisition Timeout  */
#define DISPLAY_GPS_DATA true   /* Display GPS message 

static const char* TAG = "m5atom_gps";

/*        PROTOTYPES        */
static void readGPS(unsigned long ms);
static void printGPSData();
static void createDataFile();
static void addGPXPoint();
static void blink_led_orange();
static void blink_led_red();
static void blink_led_blue();
static void blink_led_green();
static void updateStatFile();
static void printWakeupReason();

// The TinyGPS++ object
TinyGPSPlus gps;
HardwareSerial gps_uart(1);

bool firstStart = true;         // Create GPX file in first start 
char filepath_gpx[25];          // GPX file name 
char filepath_stats[25];        // Stat file name 
char today_folder[15];          // Today folder 
char point_date[22];
float prev_lat = NULL;            // No previous point on startup
float prev_long;  
bool ENABLE_GPS = true;
bool DESACTIVATE_GPS = false;

typedef struct TODAYSTATS
  float dist;
  float speed_max;
  float speed_mean; 
  double  speedbuffer[SPEED_BUFFER_SIZE];
  bool  speedbufferfull = false;
  int   speedbufferpos = 0;

TODAYSTATS_t today_stats;

void external_button_pressed()
  if ( !ENABLE_GPS ) {
  } else {

void setup() {
    // begin(bool SerialEnable , bool I2CEnable , bool DisplayEnable )

    // Disable WiFi modem to save power
    // Désactive le modem WiFi pour économiser de la batterie

    if(!SD.begin(-1, SPI, 40000000)){
      ESP_LOGE(TAG, "initialization failed!");
    } else {
      sdcard_type_t Type = SD.cardType();

        Serial.printf("SDCard Type = %d \r\n",Type);
        Serial.printf("SDCard Size = %d \r\n" , (int)(SD.cardSize()/1024/1024));

    // Open Serial port with GPS module 
    // Ouvre le port série avec le module HPS


    // Disable GPS when pressing M5Atom Lite Button (GPIO39)
    pinMode(39, INPUT);
    attachInterrupt(39, [] {
      ESP_LOGI(TAG,"Change GPS stat %u", ENABLE_GPS);
      if ( !ENABLE_GPS ) DESACTIVATE_GPS = true;
    }, RISING);


void loop() 
    DESACTIVATE_GPS = false;
    // On met en sommeil le module
      // Le tacker GPS pourra être 
      ESP_LOGI(TAG,"Wakeup on button activated");
  // GPS module is activated 
  if ( ENABLE_GPS ) {

    if (gps.location.isValid() && gps.date.isValid() ) {
        if ( firstStart ) {
          firstStart = false;

    if (millis() > GPS_TIMEOUT && gps.charsProcessed() < 10)
      ESP_LOGW(TAG, "No GPS data received: check wiring or position");


static void createDataFile()
  // GPX File name
  // Nom du fichier GPX
  sprintf(today_folder, "/%04d-%02d-%02d", gps.date.year(), gps.date.month(), gps.date.day() );
  if (!SD.exists(today_folder)){
    ESP_LOGI(TAG, "Create today folder %s", today_folder);
  } else {
    ESP_LOGI(TAG, "Today folder already exists %s\n", today_folder);
  // GPX file path
  sprintf(filepath_gpx, "%s/track.gpx", today_folder);
  sprintf(filepath_stats, "%s/stats.csv", today_folder);
  ESP_LOGI(TAG, "GPX file path %s\n", filepath_gpx);
  ESP_LOGI(TAG, "Stats file path %s\n", filepath_stats);
  // Reload today stats
  if ( SD.exists(filepath_stats) ) {
    File statsFile = SD.open(filepath_stats, FILE_READ);
    if ( statsFile ) {
      CSV_Parser cp(/*format*/ "sf", /*has_header*/ true, /*delimiter*/ ',');

      if ( cp.getRowsCount() > 0 ) {
        float *val_col = (float*)cp["value"];

        if (val_col) 
          today_stats.dist        = (float)val_col[0]; 
          today_stats.speed_max   = (float)val_col[1];  
          today_stats.speed_mean  = (float)val_col[2];  
          //Serial.printf("dist %f | max speed %f | mean speed %f  \n", today_stats.dist, today_stats.speed_max, today_stats.speed_mean);
      } else {
        ESP_LOGW(TAG,"Stat file removed because probably corrupted. I'll be re-saved next time");

  // Create today GPX file if not exists  
  if ( !SD.exists(filepath_gpx) ) {
    ESP_LOGI(TAG, "Create new GPX file %s", filepath_gpx);
    // Create GPX file on startup if not exists
    File gpxFile = SD.open(filepath_gpx, FILE_WRITE);
    // GPX file header
    if ( gpxFile ) {
        "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n"
        "<gpx version=\"1.1\" creator=\"diyprojects.io\" xmlns=\"http://www.topografix.com/GPX/1/1\" \r\n"
        "xsi:schemaLocation=\"http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd\">\r\n"
    } else {
      ESP_LOGW(TAG, "Impossible to open %s GPX file", filepath_gpx);
  } else {
    ESP_LOGI(TAG, "%s file already exists", filepath_gpx);

static void readGPS(unsigned long ms)
  ESP_LOGI(TAG, "Read GPS stream");
  bool led_state = true;
  unsigned long start = millis();
    while (gps_uart.available())
      //Serial.println( (millis() - start) % 250);
      if ( (millis() - start) % 250 != 80 ) {
        led_state = !led_state;
      if ( led_state ) 
  } while (millis() - start < ms);

  if ( DISPLAY_GPS_DATA ) printGPSData();

static void addGPXPoint()
  // Only if speed > 5 km/h, update max/mean speed, distance traveled
  if ( gps.speed.kmph() > 5 ) {
    // Add new speed point in the buffer
    double current_speed = gps.speed.kmph();

    today_stats.speedbuffer[today_stats.speedbufferpos] = current_speed;
    today_stats.speedbufferpos += 1;

    if ( current_speed > today_stats.speed_max ) today_stats.speed_max = current_speed;
    if ( today_stats.speedbufferpos >= 10 ) {
      today_stats.speedbufferpos = 0;
      today_stats.speedbufferfull = true;
    if ( today_stats.speedbufferfull ) {
      float speed_mean = 0;
      for (int l = 0; l < SPEED_BUFFER_SIZE; l++)
        speed_mean += today_stats.speedbuffer[l];
        Serial.print("add to mean"); Serial.println(today_stats.speedbuffer[l]);
      Serial.print("speed_mean total"); Serial.println(speed_mean);
      speed_mean = speed_mean / SPEED_BUFFER_SIZE;
      today_stats.speed_mean = speed_mean;
    // Estimate distance traveled from the lasted position
    if ( prev_lat != NULL ) {
      double _distance = gps.distanceBetween(gps.location.lat(), gps.location.lng(), prev_lat, prev_long);
      Serial.print("distance = "); Serial.println(_distance);
      // Ajoute la distance parcourue si < 1 km
      if ( _distance > 0 ) {
        today_stats.dist += _distance;

      prev_lat = gps.location.lat();
      prev_long = gps.location.lng();
      //ESP_LOGI(TAG,"Distance traveled %d", _distance );
    } else {
      prev_lat = gps.location.lat();
      prev_long = gps.location.lng();

  if ( FORCE_UPDATE_STATS ) updateStatFile();

  sprintf(point_date, "%4d-%02d-%02dT%02d:%02d:%02dZ",gps.date.year(), gps.date.month(), gps.date.day(), gps.time.hour() + TIME_ZONE, gps.time.minute(),gps.time.second());

  File gpxFile = SD.open(filepath_gpx, FILE_WRITE);
  if( !gpxFile ) {
    ESP_LOGW(TAG, "Impossible to open %s GPX file", filepath_gpx);
  } else {
    ESP_LOGI(TAG, "Add new point %s", point_date);
    double _lat = gps.location.lat();
    double _lng = gps.location.lng();
    double _alt = gps.altitude.meters();
    double _hdop = gps.hdop.hdop();
    int    _sat  = gps.satellites.value();

    unsigned long filesize = gpxFile.size();
    // back up the file pointer to just before the closing tags
    filesize -= 27;
    gpxFile.print(F("<trkpt lat=\"")); 
    gpxFile.print(F("\" lon=\""));
    // Satellites
    // Elevation | Altitude 


static void updateStatFile()
  File statsFile = SD.open(filepath_stats, FILE_WRITE);
  if(!statsFile) {
    ESP_LOGW(TAG, "Impossible to open %s stats file", filepath_stats);
  } else {
    ESP_LOGI(TAG, "Add stats data to file");
    // Distance parcourue aujourd'hui en mètres
    // Distance parcourue aujourd'hui en km
    statsFile.print(today_stats.dist / 1000., 2);
    // Vitesse maxi aujourd'hui
    // Vitesse moyenne aujourd'hui
static void printGPSData()
  Serial.print(F("Location: ")); 
  if (gps.location.isValid())
    Serial.print(gps.location.lat(), 6);
    Serial.print(gps.location.lng(), 6);
    Serial.print(F(", age:"));
    Serial.print(gps.location.age(), 6);    
    Serial.print(F(", hdop:"));
    Serial.print(gps.hdop.hdop(), 3);
    Serial.print(F("INVALID LOCATION"));

  Serial.print(F(" Date/Time: "));
  if (gps.date.isValid())
    Serial.print(F("INVALID DATE"));

  Serial.print(F(" "));
  if (gps.time.isValid())
    if (gps.time.hour() < 10) Serial.print(F("0"));
    if (gps.time.minute() < 10) Serial.print(F("0"));
    if (gps.time.second() < 10) Serial.print(F("0"));
    //if (gps.time.centisecond() < 10) Serial.print(F("0"));
    Serial.print(F("INVALID TIME"));

  Serial.print(F(" Altitude (m):"));

  Serial.print(F(" Speed (km/h):"));
  if (gps.speed.isValid() )
    Serial.print(F("INVALID SPEED"));

  Serial.print(F(" Course:"));
  if (gps.course.isValid() )
    Serial.print(F("INVALID COURSE"));


static void printWakeupReason()
  esp_sleep_wakeup_cause_t wakeup_reason;
  wakeup_reason = esp_sleep_get_wakeup_cause();

    case ESP_SLEEP_WAKEUP_EXT0 : Serial.println("Wakeup caused by external signal using RTC_IO"); break;
    case ESP_SLEEP_WAKEUP_EXT1 : Serial.println("Wakeup caused by external signal using RTC_CNTL"); break;
    case ESP_SLEEP_WAKEUP_TIMER : Serial.println("Wakeup caused by timer"); break;
    case ESP_SLEEP_WAKEUP_GPIO : Serial.println("Wakeup caused by GPIO"); break;
    case ESP_SLEEP_WAKEUP_UART : Serial.println("Wakeup caused by UART"); break;
    default : Serial.printf("Wakeup was not caused by deep sleep: %d\n",wakeup_reason); break;

static void blink_led_orange()

static void blink_led_red()

static void blink_led_blue()

static void blink_led_green()

Files generated by the Tracker’s Arduino program

Each GPS frame being time-stamped, the program automatically creates a file with the current date as soon as the GPS Tracker is started. This folder contains the tracker.gpx file which is your route and the stats.csv file (for Comma Separated Values).

  |_ tracker.gpx
  |_ stats.csv

The statistical data are separated by a comma: distance traveled in meters, distance traveled in km, maximum speed in km / h, average speed in km / h. The data is organized in three columns (key, value, unit).


View a GPX file?

Warning, before extracting the microSD card from the reader, do not forget to stop the GPS by pressing the button and waiting for the LED flashes twice in orange.

There is a multitude of internet sites that allow you to plot GPX files and follow the altitude difference of the hike

If you use VSCode (Visual Studio Code) to develop your ESP32 projects with PlatformIO, there are also two very practical plugins (Geo data Viewer and VSCode Map Preview) that allow you to view GPX, KML, GeoJSON, CSV plots … all this without leaving the code editor. Great!

Import a GPX track to Google Maps

To import a GPX track to Google Maps, you will need to have an account and sign in to it. Then go to Google Map and open the side menu to access your addresses.

Sorry, all pictures are in French

google map gpx your address

Go to the Cards tab then Create a card at the bottom of the menu

google map tab your maps google map add gpx map


Click on Import then drag the recovered GPX file onto the SD card.

Google Map also supports import of CSV, XLSX (Microsoft Excel) and KML formats.

google map import map google map deposit gpx map


The plot is displayed immediately after the end of the transfer of the GPX file to the Google servers.

google map gpx trace import m5stack M5atom gps

Display a GPX file directly in VSCode with the Geo data Viewer plugin

If you don’t like the idea of ​​sending your personal data to Google’s servers, you can very well view your GPX files directly in Microsoft’s VSCode code editor using the Geo Data Viewer plugin. Open the plugin menu to install it.

vscode plugin install menu kml

To view a GPX file (or other supported format), open the file in the editor and then summon the menu with the key combination   Ctrl + Alt + M.

Geo Data Viewer opens a new page with many visualization and export tools.

gpx vscode geo data viewer plugin m5atom lite gps


2021/01/22 Publication of the article

Thanks for reading

French version


Click to rate this post!
[Total: 2 Average: 5]

Thanks for your reading

Did you like this project ? Don't miss any more projects by subscribing to our weekly newsletter!

Are you having a problem with this topic?

Maybe someone has already found the solution, visit the forum before asking your question
We will be happy to hear your thoughts

Leave a Reply

Read more
DIY Projects
DIY Projects