|
GNSS Positioning Module in Practice: ATGM336H GPS Tracker DIY, Let Your Device Know Where It Is

GNSS Positioning Module in Practice: ATGM336H GPS Tracker DIY, Let Your Device Know Where It Is

Why Do You Need Positioning Function?

Friends doing IoT projects must have encountered this requirement: where is the device? How to make it report its location? Shared bikes, logistics tracking, pet positioning, outdoor adventure recorders… these scenarios all require GNSS positioning.

Today we’ll use the domestic ATGM336H module (Beidou + GPS dual mode) to build a simple GPS tracker, cost under 50 yuan, and can store location data to SD card or send to server via 4G.

⚠️ Note: GNSS module needs open outdoor environment to position normally, basically no signal indoors for testing. I struggled in the office for half an hour at first with no response, thought the module was broken, took it downstairs and locked onto 8 satellites in one minute…

What Do You Need?

ItemModel/SpecPrice
GNSS ModuleATGM336H-5N¥25
Development BoardArduino Nano / ESP32¥15-25
OLED Display0.96-inch I2C¥8
microSD Card ModuleSPI interface¥5
Lithium Battery3.7V 500mAh¥10
Charging ModuleTP4056¥2
Jumper WiresMale-to-male/Female-to-female¥5
Total¥70-80

ATGM336H is a domestic Beidou + GPS dual-mode module from中科微 (Zhongke Wei), with good sensitivity, cold start can position in about 30 seconds. Compared to imported NEO-6M, price is half, performance difference is not much.

Hardware Connection

ATGM336H uses UART serial communication, default baud rate 9600. Wiring is very simple:

ATGM336HArduino Nano
VCC5V
GNDGND
TXD10 (RX)
RXD11 (TX)

Note: Module’s TX connects to board’s RX, RX connects to board’s TX, don’t reverse them. If using ESP32, you can customize software serial pins in code.

OLED and SD card module use I2C and SPI interfaces:

OLEDArduino
VCC3.3V
GNDGND
SCLA5
SDAA4
SD Card ModuleArduino
VCC5V
GNDGND
CSD4
MOSID11
MISOD12
SCKD13

Step 1: Read NMEA Data

GNSS module continuously outputs NMEA 0183 format data, this is a standard marine electronic device communication protocol. Common data lines include:

  • $GPGGA - Positioning information (time, latitude/longitude, altitude, satellite count)

  • $GPRMC - Recommended minimum positioning information (time, status, latitude/longitude, speed)

  • $GPGSV - Satellite status (visible satellite list)

We mainly parse $GPGGA and $GPRMC. First write the simplest reading program:

#include <SoftwareSerial.h>

SoftwareSerial gpsSerial(10, 11); // RX, TX

void setup() {
  Serial.begin(9600);
  gpsSerial.begin(9600);
  Serial.println("GPS Tracker Starting...");
}

void loop() {
  if (gpsSerial.available()) {
    String line = gpsSerial.readStringUntil('\n');
    Serial.println(line);
  }
}

After uploading the code and opening the serial monitor, you’ll see output like this:

$GPGGA,083522.00,3123.45678,N,12134.56789,E,1,08,1.2,50.5,M,0.0,M,,*6A
$GPRMC,083522.00,A,3123.45678,N,12134.56789,E,0.5,123.4,120326,,*1B
$GPGSV,3,1,12,01,45,123,45,02,30,234,40,03,60,345,42,04,20,056,38*78

If it’s all blank lines or satellite count in $GPGGA is 0, positioning hasn’t succeeded yet. Take it outdoors and wait 1-2 minutes, when satellite count is greater than 4 you can continue.

Step 2: Parse Latitude and Longitude

NMEA latitude/longitude format is a bit weird: DDMM.MMMMMM (degrees + minutes), not the decimal degrees we’re familiar with. Need to convert:

// Convert NMEA format to decimal degrees
float convertToDecimalDegrees(String nmeaCoord, char direction) {
  int degree = nmeaCoord.substring(0, 2).toInt();
  float minute = nmeaCoord.substring(2).toFloat();
  float decimal = degree + (minute / 60.0);

  // South latitude or West longitude needs to be negative
  if (direction == 'S' || direction == 'W') {
    decimal = -decimal;
  }
  return decimal;
}

// Parse GPGGA sentence
void parseGPGGA(String sentence) {
  // $GPGGA,time,latitude,N/S,longitude,E/W,fix quality,satellites,HDOP,altitude...
  int parts[20];
  int idx = 0;
  int start = 0;

  for (int i = 0; i < sentence.length(); i++) {
    if (sentence[i] == ',' || i == sentence.length() - 1) {
      parts[idx++] = sentence.substring(start, i).toInt();
      start = i + 1;
    }
  }

  // parts[6] is satellite count
  Serial.print("Satellites: ");
  Serial.println(parts[6]);
}

Actually, manually parsing NMEA is quite troublesome, recommend using the TinyGPSPlus library:

#include <TinyGPSPlus.h>
#include <SoftwareSerial.h>

TinyGPSPlus gps;
SoftwareSerial gpsSerial(10, 11);

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

void loop() {
  while (gpsSerial.available()) {
    gps.encode(gpsSerial.read());
  }

  if (gps.location.isUpdated()) {
    Serial.print("Latitude: ");
    Serial.println(gps.location.lat(), 6);
    Serial.print("Longitude: ");
    Serial.println(gps.location.lng(), 6);
    Serial.print("Satellites: ");
    Serial.println(gps.satellites.value());
    Serial.print("Altitude: ");
    Serial.print(gps.altitude.meters());
    Serial.println(" meters");
  }
}

Step 3: Display and Storage

Add OLED display to see current position in real-time:

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

void displayGPS(float lat, float lon, int sats, float alt) {
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0, 0);

  display.println("GPS Tracker");
  display.println("-----------");
  display.print("Lat: ");
  display.println(lat, 5);
  display.print("Lon: ");
  display.println(lon, 5);
  display.print("Sats: ");
  display.println(sats);
  display.print("Alt: ");
  display.print(alt);
  display.println("m");

  display.display();
}

If you want to record tracks, you can store data to SD card:

#include <SD.h>
#include <SPI.h>

File logFile;

void setupSD() {
  if (!SD.begin(4)) {
    Serial.println("SD card initialization failed!");
    return;
  }
  Serial.println("SD card ready");
}

void logGPS(float lat, float lon, int sats, float alt) {
  String fileName = "track" + String(millis()) + ".txt";
  logFile = SD.open(fileName, FILE_WRITE);

  if (logFile) {
    logFile.print(millis());
    logFile.print(",");
    logFile.print(lat, 6);
    logFile.print(",");
    logFile.print(lon, 6);
    logFile.print(",");
    logFile.print(sats);
    logFile.print(",");
    logFile.println(alt, 1);
    logFile.close();
  }
}

Data format is CSV, convenient for later visualization with Excel or map tools.

Step 4: Low Power Design

If it’s a battery-powered tracker, power consumption is very important. ATGM336H operating current is about 20mA, ESP32 deep sleep can achieve 10μA.

Strategy: Wake up every 5 minutes, position for 30 seconds, record position, then continue sleeping.

#include <esp_sleep.h>

#define uS_TO_S_FACTOR 1000000ULL
#define TIME_TO_SLEEP  300  // 5 minutes

void setup() {
  // Initialize GPS, SD, etc.
  esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
  Serial.println("Preparing to enter deep sleep...");
}

void loop() {
  // Execute after wake up
  readAndLogGPS();

  // Sleep again
  esp_deep_sleep_start();
}

This way a 1000mAh battery can last several months.

Common Problem Troubleshooting

Problem 1: Module continuously outputs blank data

  • Cause: No signal indoors or antenna not connected properly

  • Solution: Take to open outdoor area, check if antenna is tightened (ATGM336H needs external active antenna)

Problem 2: Latitude/longitude always 0

  • Cause: Haven’t completed first positioning yet (cold start needs 30-60 seconds)

  • Solution: Be patient, keep module stationary, ensure antenna faces up

Problem 3: Serial port garbled

  • Cause: Baud rate mismatch or wiring error

  • Solution: Confirm baud rate is 9600, check if TX/RX are reversed

Problem 4: SD card write fails

  • Cause: Insufficient power or poor contact

  • Solution: Use independent 5V power supply for SD card module, check if CS pin is correct

Problem 5: Positioning drift is severe

  • Cause: Multipath effect (high-rise reflection) or too few satellites

  • Solution: Ensure open sky view, wait for satellite count >8 before recording, do filtering processing in software

Extended Applications

With basic positioning function, you can continue to expand:

  1. 4G Remote Reporting: Send location data to cloud server in real-time via SIM800L or EC20 module, achieve remote monitoring

  2. Map Track Visualization: Import CSV data from SD card to Google Earth or Amap, replay complete movement track

  3. Geofence Alarm: Set geographic coordinate range, automatically trigger buzzer or send SMS alert when device leaves designated area

  4. Multi-device Network Management: Assign unique ID to each tracker, server-side unified management of position information for dozens or hundreds of nodes

  5. Solar Power Optimization: With small solar panel and TP4056 charging module, achieve long-term maintenance-free operation outdoors

Summary

GNSS positioning is a common function in IoT projects, ATGM336H as a domestic module has high cost-performance ratio, combined with Arduino or ESP32 can quickly implement positioning tracker. Key points:

  • Test outdoors, no signal indoors

  • Use TinyGPSPlus library to simplify parsing

  • Low power design extends battery life

  • CSV format storage convenient for later processing

Hope this blog article is helpful to you!


Related resources: