To connect a GPS and Arduino, wire the GPS TX pin to the Arduino RX pin (SoftwareSerial Pin 8), the GPS RX pin to the Arduino TX pin (Pin 9), VCC to 5V, and GND to GND. Use the TinyGPSPlus library to parse NMEA sentences over serial. This guide targets the Arduino UNO R4 Minima paired with a high-quality 5V-tolerant GPS module, bypassing the counterfeit chip issues common with cheap clones.
Project Overview & Difficulty Rating
When building a GPS and Arduino project, the most common point of failure isn't the code; it is the hardware selection. The market is flooded with $3 NEO-6M modules that feature counterfeit silicon, missing backup batteries, and antennas that fail to lock onto satellites. For a reliable build, we are using a verified chipset and the modern ARM-based UNO R4.
Hardware Spec Sheet & Parts List
Before you start stripping wires, verify you have the exact variants listed below. Substituting a raw 3.3V u-blox NEO-M8N without a logic level shifter will fry the module when connected to the UNO R4's 5V logic pins.
| Component | Exact Variant / Model | Est. Price | Why This Variant? |
|---|---|---|---|
| Microcontroller | Arduino UNO R4 Minima | $20.00 | RA4M1 ARM Cortex-M4 runs at 48MHz, vastly outperforming the old ATmega328P for serial parsing. |
| GPS Module | Adafruit Ultimate GPS v3 (PA6H) | $29.95 | Built-in 3.3V regulator and level shifters make it 5V safe. Includes a high-gain ceramic patch antenna. |
| Backup Battery | CR1220 3V Lithium Coin Cell | $1.50 | Powers the RTC and retains ephemeris data for fast hot-starts. |
| Wiring | 22 AWG Solid Core Jumper Wires | $5.00 | Standard breadboard prototyping wire. |
Pin Mapping & Wiring Steps
The UNO R4 Minima routes its primary Hardware Serial (Pins 0 and 1) directly to the USB-C port for serial monitor debugging. If you wire the GPS to Pins 0 and 1, you will create a bus collision when trying to print debug data to your PC. Therefore, we use SoftwareSerial on Pins 8 and 9.
| GPS Module Pin | Arduino UNO R4 Pin | Wire Color | Function / Notes |
|---|---|---|---|
| VIN (or 5V) | 5V | Red | Powers the module's internal 3.3V LDO. |
| GND | GND | Black | Common ground reference. |
| TX | Pin 8 (Soft RX) | Green | GPS transmits NMEA data to Arduino. |
| RX | Pin 9 (Soft TX) | Blue | Arduino sends configuration commands to GPS. |
Numbered Wiring Steps:
- Disconnect the Arduino UNO R4 from USB power before wiring.
- Insert the CR1220 battery into the GPS module holder (positive side facing up). This is critical for retaining satellite orbital data between power cycles.
- Connect the 5V and GND rails on your breadboard to the Arduino's 5V and GND pins.
- Wire the GPS TX to Arduino Pin 8, and GPS RX to Arduino Pin 9.
- Mount the ceramic patch antenna so it faces directly upward. Patch antennas have a strict hemispherical reception pattern; mounting it sideways will attenuate the signal by up to 20dB.
Complete Arduino Code with Error Handling
This code targets the Arduino UNO R4 Minima. It utilizes the TinyGPSPlus library by Mikal Hart, which is the industry standard for parsing NMEA 0183 sentences on resource-constrained microcontrollers. Install it via the Arduino Library Manager before compiling.
#include <SoftwareSerial.h>
#include <TinyGPSPlus.h>
// Pin definitions for Arduino UNO R4 Minima
const int RXPin = 8;
const int TXPin = 9;
const uint32_t GPSBaud = 9600; // Default for Adafruit Ultimate GPS v3
// The TinyGPSPlus object
TinyGPSPlus gps;
// The serial connection to the GPS device
SoftwareSerial ss(RXPin, TXPin);
void setup() {
// Initialize Hardware Serial for USB debugging
Serial.begin(115200);
// Initialize Software Serial for GPS
ss.begin(GPSBaud);
Serial.println(F("=== GPS and Arduino UNO R4 Tracker ==="));
Serial.println(F("Waiting for satellite lock..."));
}
void loop() {
// Read incoming NMEA characters from the GPS
while (ss.available() > 0) {
if (gps.encode(ss.read())) {
displayInfo();
}
}
// ERROR HANDLING: Check if the GPS is actually sending data
// If 5 seconds pass and we haven't processed at least 10 characters, something is wrong.
if (millis() > 5000 && gps.charsProcessed() < 10) {
Serial.println(F("[FATAL] No GPS characters received on SoftwareSerial."));
Serial.println(F("Action: Check TX/RX swap and verify baud rate."));
delay(5000); // Prevent serial monitor spam
}
}
void displayInfo() {
Serial.print(F("Location: "));
if (gps.location.isValid()) {
Serial.print(gps.location.lat(), 6);
Serial.print(F(","));
Serial.print(gps.location.lng(), 6);
} else {
Serial.print(F("INVALID"));
}
Serial.print(F(" | Satellites: "));
if (gps.satellites.isValid()) {
Serial.print(gps.satellites.value());
} else {
Serial.print(F("NONE"));
}
Serial.print(F(" | HDOP: "));
if (gps.hdop.isValid()) {
Serial.print(gps.hdop.hdop());
}
Serial.println();
}
Troubleshooting: "No GPS Fix" and Common Failures
When a GPS and Arduino setup fails to output coordinates, the serial monitor will typically hang on "Waiting for satellite lock..." or trigger our custom error string: [FATAL] No GPS characters received on SoftwareSerial.
If you hit this error, here are the first three things to check, ranked by probability:
- TX/RX Swap (80% of failures): If
gps.charsProcessed()remains at 0, the Arduino is listening on Pin 8, but the GPS is transmitting to Pin 9. Swap the two data wires. - Indoor Testing / Line of Sight (15% of failures): GPS signals are incredibly weak (around -130 dBm) by the time they reach Earth's surface. They will not penetrate metal roofs, foil-backed insulation, or heavy concrete. You must test your initial lock outdoors or directly next to an open, single-pane window.
- Baud Rate Mismatch (5% of failures): If you are using a salvaged u-blox module, it may have been previously configured via U-Center software to output at 38400 or 115200 baud. Change
const uint32_t GPSBaud = 9600;in the code to match the module's actual baud rate.
$GPGGA sentence contains the fix data (latitude, longitude, altitude), while $GPRMC contains speed and heading. TinyGPSPlus parses these in the background. If your serial monitor shows raw text starting with $GP instead of parsed coordinates, you forgot to include the gps.encode() function in your loop.
Extending and Simplifying the Build
Once you have a stable lock, you will likely want to log this data or display it. Here is how to modify the architecture based on your end goal.
How to Simplify:
If you are tired of dealing with SoftwareSerial limitations (it disables interrupts while listening, which can interfere with PWM or servo libraries), switch to an ESP32 DevKit v1. The ESP32 features three hardware UARTs. You can wire the GPS to UART2 (GPIO 16/17) and use Serial2.begin(9600), freeing up CPU cycles and eliminating software serial jitter entirely.
How to Extend:
To build a standalone datalogger, add an SPI-based MicroSD card module (like the Adafruit MicroSD breakout). Wire the SD CS pin to Pin 10, MOSI to 11, MISO to 12, and SCK to 13. Use the SdFat library to write the parsed gps.location.lat() and gps.location.lng() to a CSV file every 5 seconds. Ensure you add a 3.7V LiPo battery and a charger module (like the TP4056) to make the tracker mobile.
Frequently Asked Questions
Can I use a GPS and Arduino UNO without an external antenna?
Technically yes, but practically no. The tiny ceramic patch antenna soldered directly to the PCB of cheap modules has a gain of roughly 1-2 dBi. Without an external active antenna (which includes a built-in Low Noise Amplifier drawing ~15mA), your Time-To-First-Fix (TTFF) will increase from 1 second to over 10 minutes, and you will lose lock entirely under tree cover or near tall buildings. Always use the included patch antenna or upgrade to an external SMA active antenna for mobile tracking.
Why is my GPS and Arduino setup taking 15 minutes to get a fix?
This is known as a "Cold Start." When a GPS module powers on without any stored almanac or ephemeris data (the orbital paths of the satellites), it must download this data directly from the satellites at a painfully slow 50 bits per second. This takes about 12.5 minutes. To fix this, ensure your module has a charged CR1220 backup battery, or use a module with a supercapacitor. This allows for a "Hot Start," where the module remembers the satellite positions and locks in under 3 seconds.
How do I change the baud rate on a u-blox GPS module using Arduino?
You cannot change the baud rate using TinyGPSPlus alone, as it is a parsing library, not a configuration tool. To change the baud rate of a u-blox module, you must send raw UBX binary protocol commands via the Arduino's TX pin. Alternatively, plug the GPS module directly into your PC using a USB-to-Serial FTDI adapter, and use the official u-blox U-Center Windows software to change the baud rate and save it to the module's non-volatile memory (BBR/Flash).
Does the Arduino UNO R4 WiFi work better for GPS tracking projects?
The UNO R4 WiFi uses the exact same RA4M1 main processor as the Minima, so the core GPS parsing performance is identical. However, the WiFi variant includes an ESP32-S3 co-processor. If your project requires pushing the GPS coordinates to an MQTT broker, a cloud dashboard, or a LoRaWAN gateway, the UNO R4 WiFi is vastly superior because it handles the network stack on the secondary chip, leaving the main ARM Cortex-M4 entirely dedicated to reading the GPS serial stream without network-induced latency drops.






