What is GPS/GNSS & How to Interface u-blox NEO-6M GPS Module with Arduino

Learn how GPS and other GNSS work, and interface the u-blox NEO-6M GY-NEO6MV2 module with Arduino boards using CSE_GNSS library and sample codes.
What is GPS/GNSS and How to Interface uBlox NEO-6M GPS Module with Arduino CIRCUITSTATE Electronics Feature Image

The word GPS is not unfamiliar to you. It’s a technology that has been around for a long time and we use it every day in a moving and connected world. So much so that the word GPS has become a generic term to identify a device that gives you geographic position. But the Global Positioning System or GPS is a specific system created by the USA for their military applications back in 1978 when they launched the first satellite of the system. It was known as Navstar GPS at that time. Even though GPS was the first of its kind, many other nations followed suit and started creating their own satellite constellations for regional and global positioning. Some of them are GLONASS by Russia, Galileo by the European Union, BeiDou by China, IRNSS (NavIC) by India, etc. Today, the umbrella term for all such satellite-based positioning systems is GNSS or Global Navigation Satellite System. So GPS is one of the many GNSSs. In this post, we are going learn how the GPS and GNSS work, and how to interface the u-blox NEO-6M GPS-only module with an Arduino-supported board.

What is GPS?

Let’s start with a brief explanation of the GPS. GPS stands for Global Positioning System. It is a constellation of 24 satellites orbiting the Earth at a height of around 20180 km. Even though only 24 are required, a total of 38 satellites are currently in orbit with only 32 of them operational. Each satellite weighs around 2000 Kg and is fully powered by solar panels. The satellites also carry precise atomic clocks. As we said before, GPS is one of the many GNSS. There are other GNSS systems with more or fewer satellites than GPS and at different orbital heights and types. GPS was originally conceived by the USA for military applications, but it was later opened for free public use and continues to remain so. GPS has a positional accuracy of 30-500 cm depending on how well the signal is received by a GPS receiver on the ground. At any time, 4 or more GPS satellites will be visible at a point on the surface of the Earth. Any compatible GPS receiver can acquire the signals broadcasted by the satellites and determine its position without any internet or data connection. That means GPS will work anywhere on Earth as long as the satellites are visible. Since the fundamental workings of all GNSS are the same, let’s learn how a GNSS works in the next section.

Need GPS/GNSS for your project?

CIRCUITSTATE can integrate GPS and other GNSS into your next product with exceptional accuracy for all applications such as navigation, asset tracking, surveying, and more. Contact us today to share your requirements.

Electronics Networking Vector Image

How does GNSS work?

GNSS stands for Global Navigation Satellite System. Any satellite system that provides global or regional positioning service can be classified as a GNSS. It can be restricted (allowing access to only verified users) or public (allowing free civilian use).

GNSS Architecture NovaTel
GNSS architecture. Source: Novatel

GNSS Segments

Every GNSS consists of at least three segments – Space Segment (SS), Control Segment (CS), and User Segment (US).

Space Segment

The Space Segment (SS) consists of a constellation or a collection of satellites orbiting the Earth at a defined height. The orbits of the satellites are usually circular with the orbital plane orientations at many different angles. Every satellite contains an atomic clock that can track time with the highest precision. Also, the time in all satellites will be in synchronization. The satellites also know their position in the orbit. Such information is sent to the satellite by stationary ground stations whose positions are known. Using their RF antennas, all satellites broadcast their own position and time back to Earth. The satellites use specific radio frequencies for this. For example, GPS satellites use the following bands.

  • GPS L1 Band: 1575.42 MHz with a bandwidth of 15.345 MHz
  • GPS L2 Band: 1227.6 MHz with a bandwidth of 11 MHz
  • GPS L5 Band: 1176.45 MHz with a bandwidth of 12.5 MHz

The transmissions from the satellites will cover roughly a circular area on the surface of the Earth. The transmission also creates a sphere with the satellite at the center. The data rate of the satellite broadcast can vary for different GNSS and for GPS it is 50 bps. That is very slow indeed.

GNSS Signal and Frequency Updated NovaTel
Frequency bands used by different GNSS. Source: Novatel

Control Segment

The Control Segment (CS) consists of multiple ground control stations and monitor stations. The CS takes care of updating the time in the atomic clocks of the satellites and maintains their synchronization within nanoseconds. The stations also send orbital position data called Ephemeris to the satellites so that the satellites know their own positions. Only parts of the CS can send any information to the satellites.

User Segment

The User Segment (US) consists of all devices that can receive the data broadcasted by the GNSS satellites. The US devices can only receive transmissions from the satellites but can’t transmit anything back to the satellites. Therefore there are no limits to how many US receiver devices can be operated at the same time in an area. A GNSS receiver can be stationary or mobile. A receiver should listen to the same broadcasting channels it wants to get data from. For GPS receivers, these bands are L1, L2, and L5. Other GNSS uses different bands. The receiver should have a computer to decode the communications and extract the data.

GNSS Operation

GNSS is a complex system requiring complex calculations and algorithms for accurate positioning. But we will try to explain it in simple terms here. A GNSS receiver can be anywhere on or near the surface of the Earth. The antenna of the receiver has to be oriented such that it can receive the signals broadcasted from the satellites above. Ideally, the sky has to be clear and the receiver should be within the line of sight (LoS) of the satellites in order to acquire the most legible signals as fast as possible. A receiver can also capture reflected (multipath reception) GNSS signals, but it will reduce accuracy. At least 4 satellites should be visible to the receiver in order to determine the 3-dimensional position (latitude, longitude, and altitude) of the receiver. 3 satellites are enough to calculate the 3-dimensional position but one more is needed to calculate time. This is because even though the satellites carry precise atomic clocks, a civilian-grade GNSS receiver contains only a less-accurate RTC (Real-time Clock). So the clock of the GNSS receiver has to be corrected in order to calculate the position accurately. The 4th satellite provides the GNSS receiver with data for time correction.

The data broadcasted by GNSS satellites is known as Navigation Message. The messages are coded in different formats depending on the GNSS, message type, and frequency band. For example, the L1 C/A is a legacy navigation message coding used in the GPS L1 band. C/A stands for Coarse/Acquisition which are two ranging codes. The codes are actually Pseudo Random Noise (PRN codes) that are unique for each satellite. PRN codes can be used to identify the satellite and it is important because all satellites of the same constellation transmit on the same frequency bands. The GNSS receiver also knows these PRN codes for the GNSS constellation it supports and generates the code sequence on its own periodically. Since the PRN codes can only match the phase when they are precisely aligned, any alignment errors indicate the deviation of time in the receiver. The receiver can correct such errors and establish proper communication with the satellite. The receiver can then start extracting the Navigation Message which is also modulated onto the same PRN code sequence. L1 C/A navigation message contains 25 pages/frames of 30 seconds each.


GPS L1-C/A Navigation Message Frame Format
L1 C/A frame format. Source: ESA

The content of every sub-frame is as follows:

  • Sub-frame 1: contains information about the parameters to be applied to the satellite clock status for its correction. These values are polynomial coefficients that allow converting time on board to GPS time. It also has information about satellite health.
  • Sub-frames 2 and 3: these sub-frames contain satellite ephemeris.
  • Sub-frame 4: provides ionospheric model parameters (in order to adjust for ionospheric refraction), UTC information (Universal Coordinate Time), part of the almanac, and indications whether the Anti-Spoofing, A/S, is activated or not (which transforms P code into the encrypted Y code).
  • Sub-frame 5: contains data from the almanac and the constellation status. It allows to quickly identify the satellite from which the signal comes. A total of 25 frames are needed to complete the almanac.

Sub-frames 1, 2, and 3 are transmitted with each frame (i.e., they are repeated every 30 seconds). Sub-frames 4 and 5 contain different pages (25 pages each) of the navigation message. Hence, the transmission of the full navigation message takes 25 × 30 seconds = 12.5 minutes. The content of sub-frames 4 and 5 is common for all satellites. Thence, the almanac data for all satellites in orbit can be obtained from a single satellite.

Now let’s see the steps followed by a typical GNSS receiver to acquire the position.

  1. Initial Boot-Up: When the GNSS receiver is turned on, its internal software begins to search for satellite signals. This phase is also known as a Cold Start because the receiver has to acquire all data from the satellites and it is going to take some time. This can take anywhere from 30 seconds to a few minutes depending on weather and other environmental conditions. A Hot Start on the other hand is a fast acquisition of position with previously saved data or by getting data from other sources other than the satellites. For example, Assisted-GPS (AGPS) uses a cellular network and the internet to furnish mainly the almanac data to a GPS receiver so that it doesn’t wait until acquiring the almanac from the constellation. The time it takes from boot up to the acquisition of 3D position is called Time to First Fix (TTFF).

  2. Satellite Search: The receiver’s antenna collects the radio signals from GPS satellites in line of sight. Ideally, it needs to connect to at least four satellites to calculate the exact location, but it can provide an approximate location with fewer. The receiver uses a process called signal correlation to identify the signals of individual satellites amidst all the noise. The GNSS satellites use spread spectrum modulation and other coding methods to make the signals robust in adverse conditions. The onboard computer of the GNSS receiver will have the required algorithms and codes to decode signals coming from the satellites.

  3. Data Decoding: Each GPS satellite continuously transmits a navigation message that includes the satellite’s current time, a bit of the satellite’s ephemeris (information about its orbit), and the almanac for all satellites (general information about their locations). The GPS receiver decodes this information.

  4. Time Delay Calculation: GPS signals travel at the speed of light, and even at that speed, there’s a measurable delay (Time of Flight, TOF) from the time the signal leaves the satellite (Time of Transmission, TOT) to the time it reaches the receiver (Time of Arrival, TOA). By calculating this delay, the receiver can figure out how far away each satellite is. The delay is also affected by the relative velocities of satellites, Earth, and other bodies, due to Einstein‘s relativistic time dilation effect. The time is also affected by the conditions of the ionosphere. Many such corrections have to be performed before we can use the data for further calculations.

  5. Trilateration: Now that the receiver knows the distance to at least four satellites, it can use a process called trilateration (Multi-trilateration, MLAT) to determine its own three-dimensional location (latitude, longitude, and altitude) as well as the current time. This process involves imagining spheres around each satellite: the radius of each sphere is the distance to the satellite. The point where these spheres intersect is the location of the receiver.

  6. Position Display: Once the receiver has calculated its position, it can display this information to the user. This might involve showing a dot on a map, or it could be as simple as displaying latitude and longitude coordinates in text format.

  7. Continuous Monitoring and Recalculation: After the initial position is calculated (First Fix), the receiver keeps listening for signals from the satellites. As the satellites move across the sky, they can become visible and invisible periodically. So the receiver has to continuously acquire signals from different satellites. This continuous reacquisition and recalculation happen even when the receiver is moving.

  8. Additional Processing: Depending on the capabilities of the receiver, it may also calculate velocity, direction of movement, and time.
GNSS Trilateration with Three Satellites Illustration
GNSS trilateration with three satellites. The three broadcast spheres intersect at two points A and B. An extra satellite will be able to narrow down the position to just one.

Major GNSSs

There are 6 GNSS currently available for the public around the world. Some of them are truly global, and some of them are regional or intended to augment regional positioning by aiding an existing GNSS. Let’s see the major GNSS and how they compare.

GPS

PropertyValue
Country/RegionUnited States
OperatorUS Space Force
Operational Year1993
TypeMilitary/Civilian
CoverageGlobal
Accuracy30 – 500 cm
Total Satellites24 as per design, 32 in orbit
Orbital Height20,180 km
Frequency BandsL1 = 1575.42 MHz, 15.345 MHz BW
L2 = 1227.6 MHz, 11 MHz BW
L5 = 1176.45 MHz, 12.5 MHz BW
Geodetic DatumWGS 84

GLONASS

PropertyValue
Country/RegionSoviet Union (now Russia)
OperatorRoscosmos (Russia)
Operational Year1995
TypeMilitary/Civilian
CoverageGlobal
Accuracy2.8 – 7.38 m
Total Satellites24 as per design, 25 in orbit
Orbital Height19,130 km
Frequency BandsG1 = 1589.0625 MHz to 1605.375 MHz
G2 = 1242.9375 MHz to 1248.625 MHz
G3 = 1201 MHz
Geodetic DatumPZ-90.11

GALILEO

PropertyValue
Country/RegionEuropean Union
OperatorEUSPA, ESA
Operational Year2016
TypeCommercial/Civilian
CoverageGlobal
Accuracy20 cm
Total Satellites30 (24 + 6) as per design, 28 in orbit
Orbital Height23,222 km
Frequency BandsE1 = 1559 – 1591 MHz, fc = 1575.42 MHz
E6 = 1260 – 1300 MHz, fc = 1278.75 MHz
E5 = 1164 – 1214 MHz, fc = 1189 MHz
E5a = 1164 – 1189 MHz, fc = 1176.5 MHz
E5b = 1189 – 1214 MHz, fc = 1201.5 MHz
Geodetic DatumGTRF

BeiDou

PropertyValue
Country/RegionChina
OperatorCNSA
Operational Year2000
TypeMilitary/Commercial
CoverageGlobal
Accuracy10 cm to 3.6 m
Total Satellites30 as per design, 35 in orbit
Orbital Height23,222 km
Frequency BandsB1C = 1575.42 MHz, 32.736 MHz BW
B2a = 1176.45 MHz, 20.46 MHz BW
B3I = 1268.52 MHz, 20.46 MHz BW
Geodetic DatumCGCS2000
PropertyValue
Country/RegionIndia
OperatorISRO
Operational Year2018
TypeMilitary/Commercial
CoverageRegional
Accuracy2 – 3 m
Total Satellites9
Orbital Height35,786 km
Frequency BandsL1 = 1575.42 MHz
L5 = 1176.45 MHz
S = 2498.028 MHz
Geodetic DatumWGS 84

QZSS

PropertyValue
Country/RegionJapan
OperatorJAXA
Operational Year2018
TypeCivilian
CoverageRegional (GPS Augmented)
Accuracy10 cm – 10 m
Total Satellites5
Orbital Height35,786 km
Frequency BandsL5 = 1176.45 MHz, 24 MHz BW
L2C = 1227.6 MHz, 11 MHz BW
E6/LEX = 1278.75 MHz, 20 MHz BW
L1 = 1575.42 MHz,12 MHz BW 
Geodetic DatumWGS 84

NMEA 0183

Since GNSS like GPS and GLONASS are available for civilian use, there are many companies around the world making GNSS receivers. Inside such dedicated GNSS receivers and other devices like smartphones, the GNSS functionality is added by including a GPS chipset, either as part of the SoC or as a separate module. When many manufacturers offer the same solution, there is a vital need for unifying their interfaces and data formats to ensure interoperability. The NMEA 0183 is a proprietary standard formed by the National Marine Electronics Association (NMEA). It was originally intended for marine applications and as a method to standardize various electronic devices used in marine applications. But today, most GNSS chipsets and modules have the ability to output GNSS data as NMEA sentences. Since NMEA 0183 employs ASCII text-based data over a serial communication line, it is very easy to read and interpret the data. The u-blox NEO-6M GPS module we are going to use in this tutorial also outputs GPS data as NMEA 0183 sentences. The NMEA 0183 is currently superseded by the NMEA 2000 standard.

Format

Every NMEA sentence is a comma-separated value (CSV) string that ends with the control characters CR (Carriage Return) and LF (Newline/Line Feed). The general format of an NMEA sentence is,

<Start Delimiter><Talker ID><Message ID>,<..Data..>,<Data Delimiter><Checksum><CRLF>
FieldLength (Bytes)DescriptionExample
Start Delimiter1Indicates the start of the sentence. Can be $ or ! character.$
Talker ID2Identifies the source of the message.GP = GPS
BD/GB = Beidou
GL = GLONASS
GA = Galileo
GI/IR = NavIC (IRNSS)
QZ = QZSS
GN = Multi-GNSS
Message ID3The NMEA message ID.RMC = Required Minimum Specific Data
DataVariableComma-separated data or variable length.070146.00,A,0902.599333,N
Data Delimiter1Marks the end of the data field.*
Checksum2A two-byte truncated hexadecimal XOR of ASCII characters between the Start Delimiter and Data Delimiter. 05
CRLF2Carriage Return and Line FeedCRLF
The general format of an NMEA sentence.
  1. Messages have a maximum length of 82 characters, including the $ or ! starting character and the ending <LF>.

  2. Most data fields have a constant length (in bytes) regardless of their current value. 0s may be used to pad data to match constant lengths.

  3. Where data is unavailable, the corresponding field remains blank (it contains no character before the next delimiter).

  4. The Talker ID can be different depending on the type of GNSS module you are using. And some NMEA sentences contain the same data regardless of different Talker IDs. For example, GPRMC and GNRMC have identical formats and data.

  5. The first character that immediately follows the last data field character is an asterisk (*), but it is only included if a checksum is supplied.

  6. There are multiple NMEA 0183 versions such as 3.01, 4.1, etc. Depending on the NMEA 0183 version the GNSS module is using, the NMEA sentence formats could vary to a small degree. Check the datasheet and application notes of your GNSS module to find the exact version being used and the supported formats.

  7. Not all GNSS modules output all the NMEA sentences at the same time. Some of the sentences can be hidden until you enable them manually. There are proprietary NMEA sentences used for configuring the GNSS module which closely resemble the standard messages in their formats.

Now let’s see a few of the generally used NMEA sentence types and their examples.

GPRMC

GPRMC stands for GPS Recommended Minimum Specific Position Data. The GP may be replaced with GN indicating GNSS when the module supports multiple GNSS constellations. This sentence contains the minimum data you would expect from a GNSS receiver. An example GPRMC message is given below.

$GPRMC,<Time>,<Status>,<Latitude>,<N/S>,<Longtitude>,<E/W>,<Speed>,<Course>,<Date>,<Mag Var>,<Mag Var Dir>,<Pos Mode>*<Checksum><CR><LF>
$GPRMC,070146.00,A,0902.599333,N,07632.866373,E,0.0,,031022,1.9,W,A*05<CR><LF>
FieldDescriptionFormatTypeExample
1Header$AAAAAString$GPRMC
2UTC time of locationhhmmss.ssNumeric070146.00
3Position fix status.
A = Data Valid
V = Data Invalid
ACharacterA
4LatitudeDDMM.mmmmmmNumeric0902.599333
5Latitude Direction.
N = North
S = South
ACharacterN
6LongitudeDDDMM.mmmmmmNumeric07632.866373
7Longitude Direction.
E = East
W = West
ACharacterE
8Speed over ground in knotsx.xNumeric0.0
9Course over the ground in degreesx.xNumeric323.3
10Date: dd/mm/yyddmmyyNumeric031022
11Magnetic variation in degrees (always positive)x.xNumeric1.9
12Magnetic variation direction.
E = Easterly variation (E) subtracts from True course.
W = Westerly variation (W) adds to True course.
ACharacterW
13Positioning system mode indicator.
A = Autonomous
D = Differential
E = Estimated (dead reckoning)
M = Manual input
N = Data not valid
ACharacterA
14Data Delimiter*Character*
15ChecksumhhHex Numeric05
16Sentence terminatorAACharacter[CR] [LF]
  • The GPRMC/GNRMC sentence could contain an additional field called Second Mode Indicator after the Positioning Mode Indicator in NMEA 0183 version 4.0 or later.

GPVTG

The GPVTG gives the direction of travel (course) and the speed. GPVTG is generated for GPS-only systems and GNVTG is generated for multi-constellation (multi-GNSS) systems. Other talker IDs are also possible.

$GPVTG,<COGT>,T,<COGM>,M,<SoGN>,N,<SoGK>,K,<Pos Mode>*<Checksum><CR><LF>
$GPVTG,77.52,T,,M,0.004,N,0.008,K,A*06

FieldDescriptionFormatTypeExample
1Header$AAAAAString$GPVTG
2COGT (Course over ground in degrees in reference to “true” Earth poles)ddd.ddNumeric77.52
3True course indicatorACharacterT
4COGM (Course over ground in degrees in reference to Earth’s magnetic poles)ddd.ddNumeric12.5
5Magnetic course indicatorACharacterM
6Speed over ground in knots (SoGN)xx.xxx0.004
7Speed unit.
N = knots
ACharacterN
8Speed over ground in km/h (SoGK)xx.xxxNumeric0.008
9Speed unit.
K = km/h
ACharacterK
10Positioning mode indicator.
A =Autonomous
D = Differential
E = Estimated (dead reckoning)
M = Manual Input
S = Simulator
N = Data not valid
ACharacterD
11Data Delimiter*Character*
12ChecksumhhHex Numeric05
13Sentence terminatorAACharacter[CR] [LF]
  • The number of characters and the precision of floating point values can vary depending on the GNSS module vendor.

  • Some documents refer course as Track. Course/Track is known as heading. It is essentially the direction in degrees with reference to either Earth’s rotational poles or magnetic poles.

GPGGA

GPGGA provides altitude, positioning error, quality indicator, and number of satellites being used among other data.

$GPGGA,<Time>,<Latitude>,<N/S>,<Longitude>,<E/W>,<Quality>,<Num SV>,<HDOP>,<Altitude>,<Altitude Unit>,<Geo Sep>,<Sep Unit>,<Diff Age>,<Diff Station ID>*<Checksum><CR><LF>
$GPGGA,092725.00,4717.11399,N,00833.91590,E,1,08,1.01,499.6,M,48.0,M,,*5B
FieldDescriptionFormatTypeExample
1Header$AAAAAString$GPGGA
2UTC time of locationhhmmss.ssNumeric070146.00
3LatitudeDDMM.mmmmmmNumeric0902.599333
4Latitude Direction.
N = North
S = South
ACharacterN
5LongitudeDDDMM.mmmmmmNumber07632.866373
6Longitude Direction.
E = East
W = West
ACharacterE
7Quality indicator of position fix.xDigit1
8Number of satellites used.xxNumeric08
9HDOP (Horizontal Dilution of Precision)x.xxNumeric1.01
10Altitude above mean sea level.xxx.xxNumeric499.6
11Altitude unit.
M = Meters
ACharacterM
12Geoid separation (Difference between geoid and mean sea level).xx.xNumeric48.0
13Geoid separation unit.ACharacterM
14Age of differential corrections (blank when DGPS is not used) in seconds.xNumeric5
15ID of station providing differential corrections (blank when DGPS is not used).xNumeric12
16Data Delimiter*Character*
17ChecksumhhHex Numeric05
18Sentence terminatorAACharacter[CR] [LF]
  • Other talker IDs are possible other than GP.

  • The possible values of the quality indicator can be found the in the GNSS datasheet.

GPGSA

$GPGSA,<Op Mode>,<Nav Mode>,<..Satellite Numbers..>,<PDOP>,<HDOP>,<VDOP>*<Checksum><CR><LF>
$GPGSA,A,3,29,12,23,15,25,13,11,,,,,,3.66,1.31,3.41*0C
FieldDescriptionFormatTypeExample
1Header$AAAAAString$GPGSA
2Operation mode.
M = Manual 2D or 3D
A = Automatic 2D or 3D
ACharacterA
3Navigation mode.
1 = No fix
2 = 2D fix
3 = 3D fix
xDigit3
4Satellite 0xNumeric12
5Satellite 1xNumeric12
6Satellite 2xNumeric12
7Satellite 3xNumeric12
8Satellite 4xNumeric12
9Satellite 5xNumeric12
10Satellite 6xNumeric12
11Satellite 7xNumeric12
12Satellite 8xNumeric12
13Satellite 9xNumeric12
14Satellite 10xNumeric12
15Satellite 11xNumeric12
16PDOP (Position Dilution of Precision)x.xxNumeric3.66
17HDOP (Horizontal Dilution of Precision)x.xxNumeric1.31
18VDOP (Vertical Dilution of Precision)x.xxNumeric3.41
19Data Delimiter*Character*
20ChecksumhhHex Numeric05
21Sentence terminatorAACharacter[CR] [LF]
  • Other talker IDs other than GP are possible.

  • Only 12 satellite numbers are shown in a sentence. If fewer than 12 satellites are used, the unused fields will remain blank.

GPGSV

The GPGSV sentence gives more detailed data about the satellites being used including their numbers (IDs) and signal strength. This can be used to determine the best position of your GNSS antenna for the best performance.

$GPGSV,<Num Msg>,<Seq Num>,[..<Sat ID>,<Elevation>,<Azimuth>,<Signal Strength>..]*<Checksum><CR><LF>
$GPGSV,3,1,12,05,24,025,17,11,06,069,18,12,33,179,30,13,34,075,30*71
$GPGSV,3,2,12,15,64,110,31,18,18,313,20,20,03,039,,23,40,255,21*73
$GPGSV,3,3,12,24,16,160,19,25,47,228,27,29,53,356,28,50,32,097,37*74
FieldDescriptionFormatTypeExample
1Header $AAAAAString$GPGSV
2Number of total GSV messages.xNumeric3
3Sequence number of this message.xNumeric1
4Satellite IDxNumeric12
5Satellite Elevation in degrees (0-90)ddNumeric38
6Azimuth in degrees (0-359)ddNumeric230
7Signal Strength (C/N0) in dBHz. Range 0-99. Blank when not tracking.xxxNumeric44
More Satellite data..
20Data Delimiter*Character*
21ChecksumhhHex Numeric05
22Sentence terminatorAACharacter[CR] [LF]
  • Other talker IDs other than GP are possible. For a multi-GNSS, there can be multiple sets of xxGSV sentences giving data of satellites from each constellation.

  • Up to 4 satellite data will be available in a sentence. The sentence length can also vary depending on the GNSS module and NMEA version.

u-blox NEO-6M GPS

The NEO-6M is a NEO-6 series GPS module from u-blox. The only supported GNSS by NEO-6M is GPS. There are two other variants in the family called NEO-6G and NEO-6Q. The NEO-6 is now an outdated version and if you plan to get the same functionalities, u-blox recommends the newer NEO-M9N module.

Features

  • u-blox 6 position engine:
    • Navigate down to –162 dBm and –148 dBm cold start.
    • Faster acquisition with AssistNow Autonomous.
    • Configurable power management.
    • Hybrid GPS/SBAS engine (WAAS, EGNOS, MSAS).
    • Anti-jamming technology.
  • Simple integration with u-blox wireless modules.
  • A-GPS: AssistNow Online and AssistNow Offline services, OMA SUPL compliant.
  • Backward compatible (hardware and firmware); easy migration from NEO-5 family or NEO-4S.
  • LCC package for reliable and cost-effective manufacturing.
  • Compatible with u-blox GPS Solution for Android.
  • Based on GPS chips qualified according to AEC-Q100.
  • Manufactured in ISO/TS 16949 certified production sites.
  • Qualified according to ISO 16750.
  • UART, USB, DDC (I2C compliant), and SPI interfaces.
  • Available in Crystal and TCXO versions.
  • Onboard RTC crystal for faster warm and hot starts.
  • 1.8 V and 3.0 V variants.
  • Dimensions: 16 x 12.2 x 2.4 mm

Specifications

PropertyValue
Receiver50 Channels, GPS L1 frequency (1575.42 MHz), C/A Code, SBAS: WAAS, EGNOS, MSAS
Time-To-First-FixCold Start27 s
Warm Start27 s
Hot Start1 s
Aided Start<3 s
SensitivityTracking & Navigation-161 dBm
Reacquisition-160 dBm
Cold Start (without aiding)-147 dBm
Hot Start-156 dBm
Maximum Navigation update rate5 Hz
Horizontal position accuracyGPS2.5 m
SBAS2.0 m
SBAS + PPP< 1 m (2D, R50)
SBAS + PPP< 2 m (3D, R50)
Configurable Timepulse frequency range0.25 Hz to 1 kHz
Accuracy for Timepulse signalRMS30 ns
99%<60 ns
Granularity21 ns
Compensated15 ns
Velocity accuracy0.1 m/s
Heading accuracy0.5 degrees
Operational LimitsDynamics<= 4 g
Altitude50,000 m
Velocity500 m/s
Supported ProtocolsNMEA 0183 v2.3Input/Output
UBXInput/output, binary, u-blox proprietary
RTCMInput, v2.3
InterfacesUARTFrom 4800-230400 bps.
Default to 9600 bps.
USB2.0 FS (Full Speed, 12 Mbit/s)
SPI100 kbit/s
DDC (Display Data Channel)I2C compatible
Operating Voltage2.7 – 3.6V
Operating CurrentMax67 mA
Power Save11 mA

GY-NEO6MV2

The GY-NEO6MV2 (also known as GY-GPS6MV2)is a generic NEO-6M module available as a breakout board that contains the basic power and antenna circuitry. The module shown below is probably the cheapest GPS module you can find in the market. In India, you can get it for as low as Rs.250. The board integrates an LDO, Lithium battery for data retention, EEPROM, U.FL RF connector for the antenna, and a position fix indicator LED. The module also comes with a ceramic patch antenna that can be connected to the main board. Even though the NEO-6M module has more pins, only 4 pins are broken out on the GY-NEO6MV2 module.

The onboard Lithium battery allows the GPS module to keep running its internal RTC that maintains the time once it is acquired. This will help with a fast TTFF. The 24C32A EEPROM allows the module to save configuration permanently. The 4A2D LDO voltage regulator can accept voltages up to 6V. So you can power the module either from a 3.3V supply or a 5V supply.

ublox NEO-6M GY-NEO6MV2 GPS Module Vertical View
There are only four pins broken out on the GY-NEO6MV2 module.

Pinout

uBlox NEO-6 GPS Module Pinout
u-blox NEO-6 pinout
PinsDescription
VCCPower supply (5 or 3.3V)
TXSerial output
RXSerial input
GNDGround
GY-NEO6MV2 module pinout

Schematic

Below is the schematic for the GY-NEO6MV2 module. It is not an exact one but identical.

GY-NEO6MV2 uBlox GPS Module Schematic

Wiring

ublox NEO-6M GY-NEO6MV2 GPS Module Connected to Firebettle ESP32 Board
Our test setup using DFRobot FireBettle 2 ESP32-E board

We are going to use the DFRobot FireBeetle 2, an ESP32 development board for this demo. Any GPIO pins of the ESP32 pins can be mapped to the UART peripheral. But you don’t have to use the same board. Since we using Arduino code, it will work on any Arduino-compatible board. We only need to connect the TX, RX, GND, and 3.3V supply pins of the module. Below is the wiring for FireBeetle V2.

FireBeetle 2GY-NEO6MV2
3V3VCC
D10 (GPIO17)TX
D11 (GPIO16)RX
GNDGND
Wiring between ESP32 board and GY-NEO6MV2

Arduino Code

Below is an Arduino code you can use to test the output from the GY-NEO6MV2 module. This code will only work if you have a second hardware UART serial port. Boards like ESP32, Raspberry Pi Pico (RP2040), SMT32, Arduino Due, etc. have more than one hardware serial port. In that case, you can use one port for printing the messages and one for reading/writing from the GNSS module. Boards like Arduino Uno, and Arduino Nano have only one serial port which is connected to the USB-Serial chip on the board. In that case, you should use a software serial port with the help of the SoftwareSerial library.

#include <Arduino.h>

#define   PORT_GPS_SERIAL       Serial1 // GPS serial port
#define   PORT_DEBUG_SERIAL     Serial // Debug serial port

void setup() {
  PORT_DEBUG_SERIAL.begin (115200);
  PORT_GPS_SERIAL.begin (9600);

  // Pins have to be set after the serial port is initialized.
  PORT_GPS_SERIAL.setPins (D10, D11); // GPIO 17, 16

  PORT_DEBUG_SERIAL.println();
  PORT_DEBUG_SERIAL.println ("--- GY-NEO6MV2 GPS Module ---");
  delay (1000);
}

void loop() {
  readGNSS();
  delay (10);
}

void readGNSS() {
  if (PORT_GPS_SERIAL.available() > 0) {
    // String line = PORT_GPS_SERIAL.readStringUntil ('\n'); // NMEA lines end with '\r\n'.
    // PORT_DEBUG_SERIAL.println (line);
    // PORT_DEBUG_SERIAL.write (PORT_GPS_SERIAL.read());

    char c = PORT_GPS_SERIAL.read();
    if (c == '\n') {
      PORT_DEBUG_SERIAL.print ("<LF>");
      PORT_DEBUG_SERIAL.println();
    }
    else if (c == '\r') {
      PORT_DEBUG_SERIAL.print ("<CR>");
    }
    else {
      PORT_DEBUG_SERIAL.write (c);
    }
  }
  // delay (10);
}
GY-NEO6MV2-Read.ino

The above code will simply read whatever output is coming from the GY-NEO6MV2 module. In the setup() function, we initialize the two serial ports. For ESP32, we have to assign the serial port pins after the begin() statement. Otherwise, the pins won’t be assigned correctly. In the loop() function, we continuously call the readGNSS() function and a small delay of 10 ms. The delay is not necessary.

In the readGNSS() function, we will continuously check if the UART buffer has any characters left in it. If yes, we will read a single character from the buffer. If the read character is a Line Feed (LF, \n), we will print “<LF>” and a newline so that we can start a new line after the current one. NMEA sentences coming from the GNSS module are always terminated with a Carriage Return (CR, \r) character followed by a Line Feed. Replacing the terminator characters with strings allows us to see them on the serial monitor.

Similarly, if the read character is a CR, we will replace it with “<CR>”. Any other character will be printed to the debug serial port without any modification. The GNSS module always outputs ASCII characters, so all of them will be readable from the serial monitor.

Below is the output from GY-NEO6MV2 module when the code is run. It shows a single set of NMEA lines generated by the module. After a set is complete, the module will output the next set of lines. The LED on the GY-NEO6MV2 will also start blinking when it acquires a valid position. If a fix is not acquired or lost, the LED remains off.

$GPRMC,065545.00,A,0902.59562,N,07632.86964,E,0.067,,090723,,,D*7F<CR><LF>
$GPVTG,,T,,M,0.067,N,0.124,K,D*20<CR><LF>
$GPGGA,065545.00,0902.59562,N,07632.86964,E,2,07,1.31,13.8,M,-94.6,M,,0000*43<CR><LF>
$GPGSA,A,3,29,12,23,15,25,13,11,,,,,,3.66,1.31,3.41*0C<CR><LF>
$GPGSV,3,1,12,05,24,025,17,11,06,069,18,12,33,179,30,13,34,075,30*71<CR><LF>
$GPGSV,3,2,12,15,64,110,31,18,18,313,20,20,03,039,,23,40,255,21*73<CR><LF>
$GPGSV,3,3,12,24,16,160,19,25,47,228,27,29,53,356,28,50,32,097,37*74<CR><LF>
$GPGLL,0902.59562,N,07632.86964,E,065545.00,A,D*68<CR><LF>
Serial Monitor

You can also use the readStringUntil() function from Arduino to read the UART buffer. In that case, you can supply which terminating character to search for when reading a single line at a time. The terminating character is not included in the returned string.

If you are using boards like Arduino Uno, or Nano and want to use GPIO pins for software serial, then try the following code. You can set the TX and RX pins to any suitable GPIO pins.

#include <Arduino.h>
#include <SoftwareSerial.h>

#define   PORT_GPS_SERIAL       Serial1 // GPS serial port
#define   PORT_DEBUG_SERIAL     Serial // Debug serial port

const byte rxPin = 2;
const byte txPin = 3;

// Set up a new SoftwareSerial object
SoftwareSerial Serial1 (rxPin, txPin);

void setup() {
  PORT_DEBUG_SERIAL.begin (115200);

  // Define pin modes for TX and RX
  pinMode (rxPin, INPUT);
  pinMode (txPin, OUTPUT);

  PORT_GPS_SERIAL.begin (9600);

  PORT_DEBUG_SERIAL.println();
  PORT_DEBUG_SERIAL.println ("--- GY-NEO6MV2 GPS Module ---");
  delay (1000);
}

void loop() {
  readGNSS();
  delay (10);
}

void readGNSS() {
  if (PORT_GPS_SERIAL.available() > 0) {
    // String line = PORT_GPS_SERIAL.readStringUntil ('\n'); // NMEA lines end with '\r\n'.
    // PORT_DEBUG_SERIAL.println (line);

    char c = PORT_GPS_SERIAL.read();
    if (c == '\n') {
      PORT_DEBUG_SERIAL.print ("<LF>");
      PORT_DEBUG_SERIAL.println();
    }
    else if (c == '\r') {
      PORT_DEBUG_SERIAL.print ("<CR>");
    }
    else {
      PORT_DEBUG_SERIAL.write (c);
    }
  }
  // delay (10);
}
GY-NEO6MV2-Read.ino

CSE_GNSS Library

If you want to extract and format individual parameters from the NMEA sentences you get from the GNSS module, you will have to write your own functions for it. To make things easier, we have developed a generic Arduino library for reading and extracting data from any GPS/GNSS module that outputs NMEA data through a serial port. The open-source library is called CSE_GNSS (CSE for CIRCUITSTATE Electronics) and is available on our GitHub. You can fork the project and make changes to the library to suit your needs.

Here, we will give a walkthrough of the library and explain how you can use it to define NMEA sentence formats and extract data from the GNSS module. There are two classes defined as part of the library.

  1. CSE_GNSS – A generic GNSS device class to initialize and read GNSS modules with serial ports.

  2. NMEA_0183_Data – A generic class to wrap NMEA sentences and functions to operate on them.

The View_GNSS_Data.ino is the most basic example available in the library. It simply reads the data coming from the GNSS module and prints it to the serial monitor. While reading the NMEA sentences, the terminating CRLF is replaced with an “<LF>” string. This is because the CSE_GNSS library requires only a single newline as the terminating character. It is for the sake of easy processing.

//======================================================================================//
/**
 * @file View_GNSS_Data.ino
 * @brief Reads the NMEA output from the GNSS module and prints it on the serial monitor.
 * @date +05:30 04:34:13 PM 10-07-2023, Monday
 * @version 0.1.0
 * @author Vishnu Mohanan (@vishnumaiea)
 * @par GitHub Repository: 
 * @par MIT License
 * 
 */
//======================================================================================//

#include <Arduino.h>
#include <CSE_GNSS.h>

//======================================================================================//

#define   PORT_GPS_SERIAL       Serial1 // GPS serial port
#define   PORT_DEBUG_SERIAL     Serial // Debug serial port

//======================================================================================//
// Forward declarations

void setup();
void loop();

//======================================================================================//

// Set the serial ports and the baudrate for the GNSS module.
// Both ports have to be manually initialized through begin() call.
CSE_GNSS GNSS_Module (&PORT_GPS_SERIAL, &PORT_DEBUG_SERIAL);

//======================================================================================//
/**
 * @brief Setup the serial ports and pins.
 * 
 */
void setup() {
  PORT_DEBUG_SERIAL.begin (115200);

  // For ESP32 boards
  PORT_GPS_SERIAL.begin (9600, SERIAL_8N1, 17, 16);

  // // For other boards.
  // PORT_GPS_SERIAL.begin (9600);
  
  GNSS_Module.begin();

  PORT_DEBUG_SERIAL.println();
  PORT_DEBUG_SERIAL.println ("--- CSE_GNSS View_GNSS_Data ---");
  delay (1000);
}

//======================================================================================//
/**
 * @brief Runs indefinitely.
 * 
 */
void loop() {
  String GNSS_Data = GNSS_Module.read ("$GPRMC");
  delay (10);
}

//======================================================================================//

View_GNSS_Data.ino

To use the library, you first need to include the CSE_GNSS.h header file. You should have already installed the library from the Arduino Library Manager. If you are using PlatformIO for Arduino, then you can search for the library and add it to the lib_deps configuration. We need two serial ports for running this example. Since we are going to use the FireBeetle 2 ESP32-E board here, we can use the default Serial (Serial0 connected to USB-UART chip) for debugging with a serial monitor, and Serial1 for communicating with the GPS module. Both these serial ports are hardware UARTs. The CSE_GNSS can also accept a software serial port for the GNSS module.

In the following line, we create a new CSE_GNSS object called GNSS_Module. We are sending the GNSS serial and debug serial ports during the object instantiation (creating an instance of an object). Even though the constructor accepts two more parameters (the baud rates of both ports), we are not sending those values. The baud rates are set to 0 by default. When they are set to 0, the library will not try to initiliaze the ports with a begin() call. Instead, you have to manually initialize them before initializing the CSE_GNSS object.

CSE_GNSS GNSS_Module (&PORT_GPS_SERIAL, &PORT_DEBUG_SERIAL);
C++

In the setup() function, we initialize both of the serial ports with appropriate baud rates. In the next statement, we will initialize the GNSS_Module with the begin() function. At this point, the GNSS module will be ready to be used.

In the loop() function, we have the following line that takes care of reading the GNSS module and printing debug messages to the serial monitor.

String GNSS_Data = GNSS_Module.read ("$GPRMC");
C++

The read() is a function from the CSE_GNSS class, which accepts a String value as an argument. The string is used to search the incoming data from the GNSS module and read a complete set of NMEA sentences. The default value is “$GPRMC”. That means, the read() function will read NMEA lines from one GPRMC line to the next GPRMC line (the second GPRMC line is not included). This ensures that you get a complete set of lines every time you call read(). The set of NMEA sentences will be returned as a String which is saved to the GNSS_Data string.

Below is the output from GY-NEO6MV2 GNSS module. The module is generating a set of 7 NMEA sentences every second.

CSE_GNSS read(): Read 7 lines.
CSE_GNSS read(): GNSS Data: 
$GPRMC,112501.00,A,0902.59631,N,07632.85888,E,0.134,,100723,,,A*71<LF>
$GPVTG,,T,,M,0.134,N,0.248,K,A*2B<LF>
$GPGGA,112501.00,0902.59631,N,07632.85888,E,1,03,1.97,3.8,M,-94.6,M,,*7D<LF>
$GPGSA,A,2,32,18,23,,,,,,,,,,2.21,1.97,1.00*05<LF>
$GPGSV,2,1,06,10,,,28,18,51,126,32,23,29,049,30,24,03,040,*4B<LF>
$GPGSV,2,2,06,32,54,320,30,50,32,097,37*73<LF>
$GPGLL,0902.59631,N,07632.85888,E,112501.00,A,A*69<LF>

CSE_GNSS read(): Read 7 lines.
CSE_GNSS read(): GNSS Data: 
$GPRMC,112503.00,A,0902.59625,N,07632.85869,E,0.229,,100723,,,A*76<LF>
$GPVTG,,T,,M,0.229,N,0.424,K,A*28<LF>
$GPGGA,112503.00,0902.59625,N,07632.85869,E,1,03,1.97,3.7,M,-94.6,M,,*7A<LF>
$GPGSA,A,2,32,18,23,,,,,,,,,,2.21,1.97,1.00*05<LF>
$GPGSV,2,1,06,10,,,26,18,51,126,33,23,29,049,28,24,03,040,*4D<LF>
$GPGSV,2,2,06,32,54,321,31,50,32,097,37*73<LF>
$GPGLL,0902.59625,N,07632.85869,E,112503.00,A,A*61<LF>

CSE_GNSS read(): Read 7 lines.
CSE_GNSS read(): GNSS Data: 
$GPRMC,112505.00,A,0902.59624,N,07632.85901,E,0.052,,100723,,,D*75<LF>
$GPVTG,,T,,M,0.052,N,0.097,K,D*2F<LF>
$GPGGA,112505.00,0902.59624,N,07632.85901,E,2,03,1.97,3.8,M,-94.6,M,,0000*7E<LF>
$GPGSA,A,2,32,18,23,,,,,,,,,,2.21,1.97,1.00*05<LF>
$GPGSV,2,1,06,10,,,26,18,51,126,33,23,29,049,29,24,03,040,*4C<LF>
$GPGSV,2,2,06,32,54,321,30,50,32,097,37*72<LF>
$GPGLL,0902.59624,N,07632.85901,E,112505.00,A,D*6C<LF>
Serial Monitor

If you get the last code working, then your GNSS module and serial communication are working as desired. Now let’s see how we can read, extract, and print values in the GPRMC sentence. Try uploading the code below. This example sketch is called Print_GPRMC.ino.

//======================================================================================//
/**
 * @file Print_GPRMC.ino
 * @brief Read, parse and print GPRMC values to the serial monitor.
 * @date +05:30 04:34:13 PM 10-07-2023, Monday
 * @version 0.1.0
 * @author Vishnu Mohanan (@vishnumaiea)
 * @par GitHub Repository: 
 * @par MIT License
 * 
 */
//======================================================================================//

#include <Arduino.h>
#include <CSE_GNSS.h>

//======================================================================================//

#define   PORT_GPS_SERIAL       Serial1 // GPS serial port
#define   PORT_DEBUG_SERIAL     Serial // Debug serial port

//======================================================================================//
// Forward declarations

void setup();
void loop();

//======================================================================================//

// Set the serial ports and the baudrate for the GNSS module.
// Both ports have to be manually initialized through begin() call.
CSE_GNSS GNSS_Module (&PORT_GPS_SERIAL, &PORT_DEBUG_SERIAL);

// GPRMC (No Second Mode indicator)
String GPRMC_Sample = "$GPRMC,165729.00,A,0902.595184,N,07632.860862,E,0.0,,031022,1.9,W,A*00";
String GPRMC_Data_Names [] = {"Header", "UTC", "Status", "Latitude", "Latitude Direction", "Longitude", "Longitude Direction", "Speed", "Course", "Date", "Mag Variation", "Mag Variation Direction", "Mode", "Checksum"};
String GPRMC_Description = "Recommended Minimum Specific GNSS Data";
NMEA_0183_Data NMEA_GPRMC ("GPRMC", GPRMC_Description, 14, GPRMC_Data_Names, GPRMC_Sample);

//======================================================================================//
/**
 * @brief Setup the serial ports and pins.
 * 
 */
void setup() {
  PORT_DEBUG_SERIAL.begin (115200);

  // For ESP32 boards
  PORT_GPS_SERIAL.begin (9600, SERIAL_8N1, 17, 16);

  // // For other boards.
  // PORT_GPS_SERIAL.begin (9600);
  
  GNSS_Module.begin();
  GNSS_Module.addData (&NMEA_GPRMC);

  PORT_DEBUG_SERIAL.println();
  PORT_DEBUG_SERIAL.println ("--- CSE_GNSS View_GNSS_Data ---");
  delay (1000);
}

//======================================================================================//
/**
 * @brief Runs indefinitely.
 * 
 */
void loop() {
  String GNSS_Data = GNSS_Module.read ("$GPRMC");
  GNSS_Module.getDataRef ("GPRMC").find (GNSS_Data, 0);
  GNSS_Module.getDataRef ("GPRMC").print();
  delay (10);
}

//======================================================================================//

Print_GPRMC.ino

The code is almost the same as the previous one with a few minor changes. In the new code, we have the following lines where we create a new NMEA_0183_Data object called NMEA_GPRMC.

// GPRMC (No Second Mode indicator)
String GPRMC_Sample = "$GPRMC,165729.00,A,0902.595184,N,07632.860862,E,0.0,,031022,1.9,W,A*00";
String GPRMC_Data_Names [] = {"Header", "UTC", "Status", "Latitude", "Latitude Direction", "Longitude", "Longitude Direction", "Speed", "Course", "Date", "Mag Variation", "Mag Variation Direction", "Mode", "Checksum"};
String GPRMC_Description = "Recommended Minimum Specific GNSS Data";
NMEA_0183_Data NMEA_GPRMC ("GPRMC", GPRMC_Description, 14, GPRMC_Data_Names, GPRMC_Sample);
C++

To make it easier to extract data coming from the GNSS module, we can use the NMEA_0183_Data class. We can define a new NMEA sentence as an array of data and an array of data names. The GPRMC_Data_Names is an array holding the data names as strings. The array has 14 data names. This allows us to extract up to 14 data fields from the incoming GPRMC sentence. The GPRMC_Sample is a sample string of the expected GPRMC sentence from the GNSS module. We can use it as a reference to test the library and other functions even when we are not actively receiving any data from the GNSS module.

GPRMC_Description is simply a string that gives the description of the GPRMC sentence. The name of the variable and the description is completely arbitrary and you may change it to anything else. The important line is the last one where we instantiate the NMEA_GPRMC. To instantiate any NMEA_0183_Data object, you must send 5 parameters.

  1. The sentence name or header. This can be “GPRMC” for example.

  2. A human-readable description of the sentence such as “Recommended Minimum Specific GNSS Data”. This should be a String type.

  3. The number of data fields to expect. In our case, we are expecting the GPRMC sentence to have 14 data fields.

  4. An array of data names. The position of the names sequentially corresponds to the data items. For example, the position of “Header” value in the array which is 0, corresponds to the 0th data in the data array. The data array will be internal to the object and can be accessed as dataList. The data names can be accessed as dataNameList.

  5. Last, a sample message of the NMEA sentence we are expecting. This should be as exactly as output by the GNSS module with the most number of valid data. Do not try to copy NMEA sentences from the web and always expect it to work. If there is a mismatch in the number of data fields, it can create many run-time errors.

With those four lines, we have completed creating a valid NMEA data structure for GPRMC. Now how do we tell this to the GNSS module? We can do that using the addData() function of CSE_GNSS class as shown in the following line found in setup().

GNSS_Module.addData (&NMEA_GPRMC);
C++

This will add the newly created NMEA_GPRMC object to the GNSS_Module. Once added, you can access the data through the GNSS_Module object. You can create any number of NMEA_0183_Data objects like this and add them to the GNSS_Module object. This is possible because the dataList member of CSE_GNSS class is a C++ vector.

Now how do we parse, extract and print the data? The loop() function now has two extra lines to do that. The first line of loop() takes care of reading a complete set of lines and saving them to GNSS_Data. Remember that the lines contained in the string are separated only by an LF and not a combination of CRLF. The next line is interesting.

GNSS_Module.getDataRef ("GPRMC").find (GNSS_Data, 0);
C++

Here we chain two functions from the CSE_GNSS class. The getDataRef() is a function that will return a reference (C++ reference) to the NMEA_0183_Data object in the dataList. Here, the string parameter is “GPRMC”. This will cause the getDataRef() function to return the reference to the NMEA_GPRMC object we previously added to the GNSS_Module. Since the function is returning a reference to an object, we can use the dot operator (member access operator) to access the NMEA_0183_Data members. find() is a function from NMEA_0183_Data class that accepts two parameters. A string data where valid NMEA sentences are separated by LF, and the position of the line we want to extract. In our case, the data string is the GNSS_Data which we collected from the GNSS module. So we can send that as the first parameter. With the second parameter 0, we mean that from the input lines, we want to parse the first occurrence of GPRMC. Why such a parameter is important because some NMEA sentences like GPGSV can have multiple lines with the same format and names, but contain different data. So if we have a complete set of NMEA lines from a GNSS module, we should be able to tell which line exactly we want to extract. If there are two GPGSV lines, then we can send 0 to parse the first line, and 1 to parse the second line. Since GPRMC will only appear once in a cycle, we just need to parse the first occurrence.

The second parameter in find() is optional also. So if you don’t send a second parameter, find() will simply parse the first occurrence of the NMEA sentence. find() will find the specific NMEA sentence from multiple lines and then save the line to the sentence member of NMEA_GPRMC. The function will also do a data parsing (extracting) if everything turns out to be good. You can also manually call the parse function parse(). Parsing will cause data from the NMEA line to be extracted and saved to the dataList of NMEA_GPRMC. Now it’s a matter of printing the data and the next line does that.

GNSS_Module.getDataRef ("GPRMC").print();
C++

This line will print whatever data is available in dataList along with the data names from dataNameList. Below is the output from the code.

CSE_GNSS read(): Read 9 lines.
CSE_GNSS read(): GNSS Data: 
$GPRMC,170714.00,A,0902.60148,N,07632.86605,E,0.188,,100723,,,D*7A<LF>
$GPVTG,,T,,M,0.188,N,0.349,K,D*29<LF>
$GPGGA,170714.00,0902.60148,N,07632.86605,E,2,09,1.05,13.2,M,-94.6,M,,0000*4D<LF>
$GPGSA,A,3,21,26,03,27,02,16,08,31,04,,,,1.81,1.05,1.48*09<LF>
$GPGSV,4,1,15,01,19,211,17,02,15,195,16,03,69,277,28,04,32,346,21*7A<LF>
$GPGSV,4,2,15,07,16,276,14,08,29,160,28,09,10,324,09,16,54,038,15*7E<LF>
$GPGSV,4,3,15,21,15,188,16,22,17,100,23,26,20,034,18,27,32,119,26*7C<LF>
$GPGSV,4,4,15,31,10,043,16,32,02,117,,50,32,097,34*47<LF>
$GPGLL,0902.60148,N,07632.86605,E,170714.00,A,D*65<LF>

NMEA_0183_Data find(): Lines to search = 9
NMEA_0183_Data find(): Found GPRMC line at position 0
NMEA_0183_Data set(): $GPRMC,170714.00,A,0902.60148,N,07632.86605,E,0.188,,100723,,,D*7A
NMEA_0183_Data check(): $GPRMC,170714.00,A,0902.60148,N,07632.86605,E,0.188,,100723,,,D*7A
NMEA_0183_Data check(): Valid GPRMC sentence.
NMEA_0183_Data parse(): $GPRMC,170714.00,A,0902.60148,N,07632.86605,E,0.188,,100723,,,D*7A
NMEA_0183_Data parse(): Completed.
NMEA_0183_Data print(): 
GPRMC: Recommended Minimum Specific GNSS Data
  Header: $GPRMC
  UTC: 170714.00
  Status: A
  Latitude: 0902.60148
  Latitude Direction: N
  Longitude: 07632.86605
  Longitude Direction: E
  Speed: 0.188
  Course: 
  Date: 100723
  Mag Variation: 
  Mag Variation Direction: 
  Mode: D
  Checksum: 7A
Serial Monitor

Look how neatly we are printing each data field of the GPRMC sentence. We had to search 9 lines of data and found a GPRMC line at position 0. The check() function can validate the NMEA sentence before parsing. Similar to how we have done for GPRMC, we can also add other NMEA sentence types and extract their data. We hope these two examples will give you enough insight into how to use the CSE_GNSS library.

U-Center Application

U-Center is a free application from ublox for evaluating, testing, and configuring GPS/GNSS modules from ublox. The application can be used to evaluate the full potential of a GNSS module. For connecting the GY-NEO6MV2 module to the computer, you will need a suitable USB-Serial converter. We are going to use an FT232L clone module. You can that or any other converters like CP2102, CH340, etc. Just make sure that your computer has the required drivers already installed. You can download the U-Center application below.

Simply connect the VCC, GND, RX, and TX pins of the GPS module to the USB-Serial converter and then connect to the computer. A COM port will be generated. If you have the U-Center application already open, you will need to relaunch it so that it can detect the new COM port.

The application has an outdated UI but it works regardless. To connect to a device, use the Receiver → Connection menu and select the COM port. To view the NMEA messages from the GPS module, enable it from View → Text Console.

Below is a screenshot of the application where active communication is in progress. The GPS has not been able to fix a position yet, due to rainy weather. But since the receiver and antenna are so sensitive, they can capture the satellite signals occasionally. But as we know, at least 4 satellites have to be visible for a minimum duration so that the GPS module can fetch data from them completely.

U-Center Application for GPS GNSS Evaluation and Testing from ublox No Fix Window
3 satellites in view but not for long enough

There are many other tools and features in the U-Center app. You can figure out them yourself, and understand the working of your GNSS modules better.

GNSS Terms & Concepts

When working with any GNSS, there are a few things to keep in mind including terminologies and other related technologies. In this section, let’s cover the most useful GNSS terms and concepts.

Geographic Coordinates

Latitude and Longitude ScienceNotes
Latitude and Longitude. Source: Science Notes

There are multiple ways to denote geographical coordinates on the surface of the Earth. In this section, we will discuss the most widely used notation methods and how you can convert between them. There are mainly three ways,

1. Degrees Minutes Seconds (DMS)

This is the easiest to understand by reading. It considers Earth as a sphere and divides the surface into many subdivisions. Since the angle is the most suitable to divide a spherical surface, the surface is laterally and longitudinally divided into a range of angles. For latitude, the Earth’s Equator serves as the reference point or origin. From the Equator, both South and North sides extend to 90 degrees, making it a hemisphere with 180° divisions. For the longitude, Earth’s surface is longitudinally divided into 360° with the Prime Meridian serving as the reference point. The values are written in the range of -180° to +180° or substituting the signs with directions (E or W) instead of writing 0 to 360°.

With a longitude and latitude value, we can specify any point on the Earth’s surface accurately. But there is a practical problem. Since Earth is really large we always have to use very small values of degrees, such as small fractions. It is cumbersome to say 0.000362° in practical cases. To solve this problem, the degree can be divided into smaller units. An Arc Minute divides 1° into 60 subdivisions. That means,

1° = 60 Arc Minutes

Arc Minute is denoted with ' suffix, such as 15′. Similarly, an Arc Second divides the Arc Minute into another 60 smaller divisions. That means,

1° = 60= 360 Arc Second

The Arc Second is denoted with  as a suffix, such as 20”. Do not be confused with minutes and seconds used for time measurement with arc minutes and seconds. They are different but related. Dividing a circle into 360° and then dividing each degree into 60 [arc minutes] and then into smaller 60 [arc seconds] has practical advantages. This convention has been followed even from ancient times and continues to remain.

To accurately denote locations on Earth easily, we can use a combination of Degrees, Arc Minutes, and Arc Seconds. This style is called Degrees Minutes Seconds (DMS) notation. For example, the US Capitol location can be written in DMS format as 38° 53′ 23″ N, 77° 00′ 32″ W.

UnitLatitude Range (w/ direction)Longitude Range (w/ direction)
Degree0-900-180
Minutes0-600-60
Seconds0-600-60
Values and their ranges

Value TypeNESW
Latitude+××
Longitude×+×
Directions and their equivalent signs

2. Degrees Decimal Minutes (DDM)

Using combinations of numbers, special symbols, and letters are not easy in the sense of efficient and friendly computing. To reduce the complexity, we can eliminate a separate arc second value by converting it to equivalent arc minutes. To do this all we need to do is to divide the arc second value by 60 and then add the result to the arc minute value as a fraction. This system of units with 60 as the base is called the sexagesimal system. We can convert the previously seen coordinate into DDM notation.

Latitude/LongitudeDMSDDM
Latitude38° 53′ 23″ N38° 53.383333333′ N
Longitude77° 00′ 32″ W77° 0.533333333′ W
DMS vs DDM

3. Decimal Degrees (DD)

We can simplify the notation even further for a more efficient digital notation. We can eliminate the arc minute part by converting it to degrees by dividing the value by 60 and then adding the result to the degree value. This notation style is called Decimal Degrees since latitude and longitudes can be written as fractional values with a decimal point. The directions can be further eliminated by adding positive (+) and negative (-) signs, making the number easy to store as an integer value. This makes computations involving geographical coordinates easier for programmers. You can use this tool to convert these values easily.

Latitude/LongitudeDMSDDMDDDD w/ sign
Latitude38° 53′ 23″ N38° 53.383333333′ N38.8897222222° N+38.8897222222°
Longitude77° 00′ 32″ W77° 0.533333333′ W77.0088888889° W-77.0088888889°
DMS vs DDM vs DD

GPRMC Coordinates

The GY-GPS6MV2 GNSS module outputs the coordinate data in Degrees Decimal Minutes (DDM) format. This format is also called DMM (D° M.M). The format is as given below.

DD° MM.mmmmmm’ A for Latitude
DDD° MM.mmmmmmm’ A for Longitude

1. DD/DDD = Degrees – This can be 0-90° for latitude and 0-180° for longitude values. Positive latitudes are North (N) of the Equator while negative latitudes are South (S) of the Equator. For longitudes, positive values are East (E) of Prime Meridian and negative values are to the West (W).

Below is a set of the same coordinates represented in different formats.

FormatCoordinates
DMS9° 2′ 35.928″ N, 76° 32′ 51.6″ E
DDM w/ direction9° 2.5988′ N, 76° 32.86′ E
DD9.0433133333 N, 76.5476666667 E
DD w/ sign9.0433133333, -76.5476666667
Latitude and Longitude in different formats

Both of these represent the same coordinates but the first one has explicit directions, and the last has positive or negative signs. The sign may be omitted for positive values, in the case there are no explicit direction values.

In the DD format, the latitude only takes two positions since it only has to show values between 0 and 90. If the value is less than 10, then the leading position can be padded with 0. For example, 9° should be written as 09. In the case of longitude, three positions (DDD) are required to show values ranging from 0 to 180. The leading positions may be padded with 0s to keep the lengths the same. For example, 76° can be shown as 076.

2. MM.mmmmmm = Decimal arc minutes – The first two values represent the arc minute value as a whole number. The value range for arc minute is 0-60 and it will be always positive. The positions after the decimal place represents seconds converted to decimal minutes by dividing the second value by 60. The more decimal places, more the precision. Common GPS modules only have a decimal minute precision of 4 places.

3. A = Latitude or Longitude compass directions – This value is a single letter representing the direction. The value can be N (North/positive) or S (South/negative) for Latitude. For Longitude, the direction can be E (East/positive) or W (West/negative).

Below is an example coordinate output from a GPS/GNSS module.

0902.599333,N
07632.866373,E

These values are fetched from the following GPRMC (NMEA) sentence. Latitude always comes first followed by Longitude.

$GPRMC,070146.00,A,0902.599333,N,07632.866373,E,0.0,,031022,1.9,W,A*05

As you can see, the values are padded with leading zeros to keep their lengths uniform for the entire range. Let’s break down the values by each byte.

0902.599333,N
DDMM.mmmmmm,A
GPRMC Latitude format

Now let’s decode the data and find the coordinates in different formats.

FieldBytesActual Value=Degrees=Minutes=Seconds
DD099 (÷1)540 (×60)3240 (×360)
MM022′0.0333333333 (÷60)2 (×1)120 (×60)
.mmmmmm.5993330.599333′0.00998888333 (÷60)0.599333 (×1)35.95998 (×60)
Latitude value conversions

This Latitude can be written in different formats as,

FormatCoordinates
Degree Minute Second (DMS)9° 2′ 35.95998” N
Degrees Decimal Minutes (DDM)9° 2.599333′ N
Decimal Degrees (DD) w/ direction9.0433222167° N
Decimal Degrees (DD) w/ sign+9.0433222167
Latitude in different formats

Similarly, we can do the conversion for the Longitude value as well.

07632.866373,E
DDDMM.mmmmmm,A
GPRMC Longitude format

FieldBytesActual Value=Degrees=Minutes=Seconds
DDD07676°76 (÷1)4560 (×60)27360 (×360)
MM3232′0.533333333 (÷60)32 (×1)1920 (×60)
.mmmmmm.8663730.866373′0.01443955 (÷60)0.866373 (×1)51.98238 (×60)
Longitude value conversions

The Longitude can be written in various formats as,

FormatCoordinates
Degree Minute Second (DMS)76° 32′ 51.98238” E
Degrees Decimal Minutes (DDM)76° 32.866373′ E
Decimal Degrees (DD) w/ direction76.5477728833° E
Decimal Degrees (DD) w/ sign+76.5477728833
Longitude in different formats

GNSS Accuracy

Depending on which GNSS you are using, the accuracy can get to an impressive 10 cm or more. Civilian GNSS access will usually have degraded accuracy while restricted or encrypted access will have much greater accuracy. But how do you know you are getting an accurate position all the time? What is the practical accuracy you get from a GNSS? What does the accuracy depend on? The accuracy of any GNSS system is affected by numerous variables; some controlled and some uncontrolled. Accuracy is how close a reported value is to the actual value. The following are a few things that affect the accuracy of the position reported by a GNSS receiver.

  1. Satellites in View – This indicates how many many satellites from which a GNSS receiver can receive a good signal. At least 4 SVs (satellite vehicles) are needed for a position fix. If there are more than 4 satellites in the vicinity, then accuracy can be improved further. If the GNSS receiver is multi-constellation supported, then it will naturally get signals from more SVs at a time. Modern GNSS receivers can use data from multiple GNSS to improve fixing and tracking. The position of SVs in the sky also matters. If the satellites are visible closer to above your head (Zenith) and are dispersed evenly, then the signals from those satellites are more reliable than what coming from satellites closer to the horizon. This is because the signals will have to travel longer through the atmosphere when the satellites are closer to the horizon. Adverse weather conditions can also affect signal quality, such as rain, clouds, snow, lightning, EMI, solar winds, dust storms, etc. These variables can not be controlled.

  2. Antenna Sensitivity – It doesn’t matter how good is the visibility of satellites if your GNSS antenna has poor sensitivity. A properly matched, filtered, and tuned antenna will have a higher gain and thus enabling the RF front-end of the GNSS receiver to acquire signals amidst all the noise. Improving antenna sensitivity improved overall accuracy and TTFF.

  3. Epheremis and Almanac – These are data a GNSS receiver has to acquire in some way before it can start calculating the position (Trilateration). The data will be received as fragments from the satellites and the GNSS receiver has to wait until it fully receives the data to give you the best results. But even before that, the GNSS receiver will start giving you some estimated values and indicates the quality of the results in some way. This is because something is better than nothing when it comes to positioning. The positions of the satellites have to be continuously monitored and corrected so that positioning errors can be kept to a minimum. The ground segment of the GNSS takes care of this. The satellite data has to be renewed periodically to maintain accuracy.

A term that comes up when talking about GNSS accuracy is the Dilution of Precision (DOP). There are several types of DOP:

  1. Geometric Dilution of Precision (GDOP): This is a comprehensive factor that considers the combined effect of PDOP and TDOP. It’s the overall DOP that includes both spatial and temporal DOP. The lower the GDOP, the better the geometry of the satellites is and, therefore, the higher the positional precision is.

  2. Position Dilution of Precision (PDOP): This considers the geometry of the satellites in terms of the receiver’s x, y, and z positions (3D position). The PDOP value is a function of the angles between the satellites as observed from the receiver. A lower PDOP means a better configuration of satellites and higher position precision.

  3. Horizontal Dilution of Precision (HDOP): This takes into account the satellite geometry for the receiver’s x and y positions (2D position). Lower values of HDOP represent better horizontal precision.

  4. Vertical Dilution of Precision (VDOP): This measures the effect of satellite geometry on the precision of the receiver’s z-position (height). A lower VDOP means better vertical precision.

  5. Time Dilution of Precision (TDOP): This measures the effect of satellite geometry on the timing precision. Lower values indicate better time precision.

Some of these values are outputted by a GNSS receiver which you can use to determine how reliable the position data coming from the receiver is. In general, DOP is a useful concept for understanding the inherent geometric precision limit for a particular set of satellite observations. It is usually combined with other quality measures (like Carrier-to-Noise ratio, CN0) to assess the overall quality and expected accuracy of GNSS observations.

A-GPS

If we can help the GNSS receiver in acquiring some of the data it needs, then it can calculate the precision accurately within a short time. Assisted-GPS or Augmented-GPS is a term when we use other data sources such as the Internet or a mobile network to provide fresh ephemeris, almanac, time, and other relevant data to the GNSS receiver. Most GNSS receivers allow sending this data in some way. A-GPS will result in a faster TTFF and accurate positioning.

SBAS

SBAS GNSS Augmentation LBAS_EN Teria
GNSS corrections are determined and sent to GNSS receivers through SBAS. Source: Teria

Similar to how we help the GNSS receiver through A-GPS, an entire GNSS can be augmented or improved with external data sources. These mainly include stationary bases on the ground whose locations are precisely determined. So if one such base acquires its own position from the GNSS satellites and finds a deviation from its actual position value, then that error can be used to further correct all other GNSS calculations done by all GNSS receivers in that area. SBAS stands for Satellite-based Augmentation System and is a general term for such technology. SBAS mainly used for improving regional positioning to mainly help aviation. Some of the widely used SBAS are WAAS (USA), EGNOS (EU), QZSS (Japan), GAGAN (India), BDSBAS (China), etc. The u-blox NEO-6M module supports SBAS and you can find more details about it from the datasheet. When external data sources are used for GNSS corrections, it is termed Differential GNSS (DGNSS) or DGPS for GPS-only systems.

TTFF

TTFF stands for “Time To First Fix”. It refers to the time it takes for a GNSS receiver to acquire satellite signals and navigation data, and calculate a position solution (a “fix”).

The TTFF can vary based on a number of factors, including the specific circumstances under which the GNSS receiver is operating. Here are three main categories of TTFF:

  1. Cold Start: This refers to the scenario where the GNSS receiver starts from a completely unknown state, without any prior knowledge of its approximate location, time, or the satellites’ orbital information (the almanac and ephemeris data). It needs to search for all satellites, download the almanac and ephemeris data, and then calculate a position. The TTFF in a cold start scenario is typically the longest, often taking a minute or more.

  2. Warm Start: In this case, the receiver has an approximate knowledge of the time and its location, and it also has a valid almanac, but does not have valid ephemeris data for the satellites. Therefore, the receiver must obtain the ephemeris data from each of the satellites in view before calculating a position, which typically takes a bit less time than a cold start.

  3. Hot Start: Here, the receiver has valid time, location, almanac, and ephemeris data, typically because it was recently in use. It can calculate a position as soon as it has received signals from a sufficient number of satellites, which is usually quite quick, often within a few seconds.

The TTFF is a critical performance measure for GNSS receivers, especially for certain applications like emergency services or vehicle navigation, where quickly getting a position fix is very important. Most modern GNSS receivers have the ability to retain critical information in their memory and keep the internal RTC (Real-time Clock) running using a little battery power. You can also find this on the GY-NEO6MV2 module. This helps the module retain data when the main power is interrupted for a short period of time. Some data may still get outdated after a fixed time, regardless of uninterrupted power.

Dead Reckoning

Dead reckoning is a navigational technique that calculates a current position based on a previously known position, or fix, and advancing that position based upon known or estimated speeds over elapsed time, and course (direction). Dead reckoning can be used to estimate a current position when the signal from satellites is weak or lost, such as when you’re in a tunnel or surrounded by high-rise buildings. This is often the case in urban environments, a phenomenon known as the urban canyon effect.

In systems employing GNSS dead reckoning, the GNSS provides an initial position fix, while sensors like accelerometers, gyroscopes, and sometimes wheel-speed sensors (in the case of vehicle navigation systems), measure changes in direction and speed. These measurements are used to calculate the current position relative to the last known position. The technique is particularly useful in maintaining reasonable positional information between GNSS updates or during GNSS outages.

However, dead reckoning is subject to cumulative errors. Since each new position is calculated from a previous position, any error in the measurement process (which can come from sensor inaccuracies or other factors) is carried forward and magnified over time. In other words, dead reckoning is usually used in conjunction with other positioning systems, not as a standalone navigation tool.

Ephemeris

We have already talked about ephemeris in many places. Ephemeris is the data that can be used to determine the orbital position of a satellite, or any orbiting bodies for that matter. Even though the satellites are released to a fixed and known orbital height, their orbital positions can change at times. Orbital deviation can happen due to natural effects or be intentional such as in the case of collision avoidance maneuvers. Such deviations and corrections need to be tracked precisely by ground stations and the correction data has to be sent to the satellites. Some satellites have laser retroreflectors to pinpoint the position of a satellite with a laser beam.

Whenever a GNSS receiver gets data from a satellite, the ephemeris data should be up to date with the actual state of the satellite. This is why it is important to refresh the ephemeris data frequently to keep the GNSS position accurate and reliable. The ephemeris is unique for a satellite.

Almanac

Similar to ephemeris, the Almanac also gives orbital data regarding the satellites. But the almanac is the same for all satellites of a particular GNSS but less accurate. The almanac data is also larger and thus requires more time to download completely from the satellites. One way of improving the TTFF is providing the GNSS receiver with this almanac data. Both ephemeris and almanac have certain lifetimes and should be refreshed once they expire.

Geodetic Datum

WGS84 Mean Earth Radii Wikipedia
Mean earth radii according to WGS84

A Geodetic Datum is a mathematical model of the Earth that can be used as a reference frame to express geographic locations as coordinates. Longitude, latitude, elevation, etc can be expressed with proper mathematical correlation. This is extremely important for surveying, navigation, and positioning of locations on Earth. GNSS also uses different types of geodetic models to express positions. The GPS uses a system known as WGS 84 (World Geodetic System) which considers the Earth as an ellipsoid. Many such systems exist and are used by different GNSSs.

Troubleshooting

If you are unable to get position data from the GNSS module or not able to communicate with it, try the following troubleshooting tips.

  1. No data from the GNSS module:
    • Make sure you are using valid GPIO pins for the UART.
    • Check if your serial port is correctly configured and initialized.
    • Make sure the TX and RX pins are connected correctly and are not swapped.
    • Make sure the GNSS module is getting the correct working voltage.

  2. Garbage data coming from the GNSS module:
    • Make sure your baud rate is correct.
    • Check for loose wires. Don’t use long wires.

  3. No position data from the GNSS module even after a long time.
    • Make sure you have connected the external antenna if there is one.
    • Place the antenna in the correct orientation facing a clear sky without obstructions.
    • Make sure the Lithium battery connected to the GNSS module is healthy.

  4. CSE_GNSS library is not fetching data correctly or has no data:
    • Check if you have defined the NMEA data structures correctly and the data field count is correct.
    • Check your GNSS datasheet for the NMEA version and also check the GNSS firmware version.

That’s all for this tutorial. We hope we have been able to give you a complete overview of the GPS/GNSS technology. You can learn more about GNSS from the reference links added at the end of this post. If you need specific information about your GPS/GNSS module, try checking the official datasheet and application notes from the manufacturer. In the upcoming posts, we will feature multi-constellation GNSS receivers. If you have any feedback for improving this post, please let us know in the comments.

  1. GY-NEO6MV2 – Buy from Robu
  2. ublox NEO-6M – ublox Product Page
  3. What are Global Navigation Satellite Systems? – Novatel
  4. GPS Navigation Message – ESA
  5. NMEA 0183 – Wikipedia
  6. ublox NEO-M9 – Product Page
  7. DFRobot FireBeetle 2 ESP32E
  8. SoftwareSerial – Arduino Library 
  9. CSE_GNSS – Arduino Library – GitHub
  10. Trilateration – Wikipedia
  11. U-Center Application – Download
  12. Getting Started with U-Center for u-blox – SparkFun
  13. Building a GPS System – SparkFun
  14. Understanding GNSS Orbits – SparkFun

Share to your friends
Vishnu Mohanan

Vishnu Mohanan

Founder and CEO at CIRCUITSTATE Electronics

Articles: 90

Leave a Reply

Your email address will not be published. Required fields are marked *

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

The reCAPTCHA verification period has expired. Please reload the page.