October
2000, Issue 123
Navigating
With GPS
GETTING
THE DATA
Most
GPS receivers output data in NMEA-0183 format. NMEA
stands for the National Marine Electronics Association.
The data is sent via RS-232 at 4800 bps, with most GPS
receivers providing a serial port that outputs NMEA
GPS messages at 1-s intervals. NMEA messages are sent
by talkers (identified by a two-character ID string
with a "GP" prefix) and received by listeners.
The messages are one-way: from talker to listener. Thus,
an application programs control of the receivers
output is limited. Data enters your application program
at 4800 bps at 1-s intervals, period. The data rate
and burst time cant be changed. This is OK for
most land- and sea-based applications.
An
NMEA sentence contains an address field, data field,
and checksum. The address field is composed of a sentence
formatter and talker identifier. The latter indicates
where the data comes from. For GPS, the talker identifier
is GP. Two useful GPS talker identifiers are RMC and
GGA. The sentence formatter indicates the content of
the data field.
NMEA
messages are easy for a program to parse because they
are consistent and well defined. The general NMEA message
format is:
$<Address>,<Data>*<Checksum><CR><LF>
The
address field, <Address>, is broken down as <talker><sentence_
formatter>. All fields are comma delimited except
<Checksum>, which is delimited by
a star (see Figure 2).
$<Address>,<Data>*<Checksum><CR><LF>
<Address> = <Talker><Sentence_formatter>
<Talker> = GP
<Sentence_formatter> = one of RMC GGA GSV
ZDA |
| Figure 2This is the NMEA sentence
format. |
Table
1 lists eight examples of NMEA GPS messages. The most
useful one is the RMC message, which contains all of
the basic information required to build a navigation
system. RMC is listed as recommended minimum specific
GPS/transit data (see Figure 3). Although I dont
know what the "C" stands for in RMC, I know
I like the utilitarian nature of this message. It contains
time, status, position, speed, course, and date.
| RMC |
Contains recommended
minimum specific GPS/transit data |
| ALM |
Provides GPS almanac
information |
| GLL |
Provides latitude,
longitude, and UTC (Universal Time Coodinated) data |
| ZDA |
Contains UTC along
with day, month, year, and local time |
| GGA |
Contains UTC, fix,
and position data |
| GSA |
Provides GPS DOP and
active satellite information |
| VTG |
Provides "track
made good" and ground speed |
| ZDA |
Provides the current
time and data |
| Table 1These
are useful GPS NMEA messages used for navigation
applications. |
|
RMC message |
| $GPRMC,nnmmss.ss,A,IIII.II,a,yyyy.yy,a,x.x,x.x,xxxxxx,x.x,a*hh<CR><LF> |
| $GPRMC |
Address field |
| hhmmss.ss |
UTC of position fix (hours, minutes, seconds,
decimal seconds) |
| A |
GPS status: A means data is valid, V means data
is invalid |
| Llll.ll |
Latitude |
| a |
North/south |
| yyyy.yy |
Longitude |
| a |
East/west |
| x.x |
Speed over ground in knots |
| x.x |
Course over ground, degrees true |
| xxxxxx |
Date: ddmmyy (day, month, year) |
| x.x |
Magnetic variation |
| a |
East/west |
| *hh<CR><LF> |
Checksum |
| Figure 3Heres the
NMEA RMC message format, followed by definitions. |
Looking at the RMC message, the first chunk of data
encountered is $GPRMC. As the NMEA sentence describes,
this is the talker and sentence formatter. Universal
Time Coordinated UTC data follows the sentence formatter;
the time is given in hours, minutes, seconds, and decimal
seconds. Next is the GPS status indicator (A), which
indicates whether or not the incoming GPS data is valid.
The V in this field seems to indicate that the data
is valid, however, it means the opposite. An A in this
field means that the data is indeed valid.
There
are many reasons why a GPS receiver would output invalid
data. For example, the receiver might not have acquired
enough satellites for a position fix yet, foliage or
buildings might block the GPS signals, or the GPS almanac
or ephemeris data could be out of date. Invalid data
output from a receiver is almost always temporary, and
a V usually will become an A within seconds or minutes.
The
next two fields cover latitude and determine whether
the latitude is in the Northern or Southern Hemisphere.
Following the latitude fields are the corresponding
longitude and east/west indicators. The two fields after
that, speed (knots) over ground and course (degrees)
over ground, are handy. Next is the date, and then the
magnetic variation (east or west).
The
RMC message is available on almost all receivers that
output NMEA messages. As stated, GPS receivers supporting
NMEA messages output data at 1-s intervals at 4800 bps,
so processing data at 1200- to 1800-ms intervals ensures
enough time to fill up a receiver buffer and transfer
the data to a holding buffer. The data in the holding
buffer can be parsed and processed while new information
enters the receive buffer.
Listing
1 shows a C structure into which you can deposit the
parsed RMC message data. The [#defines] identify character
array lengths and are optional. The structure contains
the proper data types to contain the RMC data fields.
You can create similar structures for additional NMEA
messages that an application needs.
#define STRING10 10
#define STRING7 7
struct rmc
{
char UTC[STRING10];
char Status;
double Lat;
char NS;
double Lon;
char EW;
double Speed;
int Course;
char Date[STRING7];
char Var[STRING10];
};
|
| Listing 1Heres the
structure that holds parsed RMC messages. |
After
the GPS receiver deposits data in a buffer named InputQueue[],
the data is transferred to another buffer called InputMsgBuff[].
The latter is used to extract the RMC or other NMEA
messages of interest. To extract the data, create a
pointer and have it point to InputQueue[]. For transferring
data, you need to de-reference the pointer to Input-
MsgBuff[]. This is illustrated in the C code fragment
in Listing 2.
unsigned char *locptr; // local buffer pointer
int i = 0; // array index
/***************************************
* Transfer InputQueue data to InputMsgBuff[]
***************************************/
locptr = InputQueue;
/***************************************
* Check for NMEA message start character $.
* If $ is found, transfer message to InputMsgBuf.
****************************************/
if (*locptr == $)
{
while (*locptr != \0)
{
InputMsgBuff[i++] = *locptr;
}
InputMsgBuff[i] = \0;
}
|
| Listing
2This code transfers an NMEA message from
a raw input queue to a message processing buffer. |
When
a message is in a buffer, the talker and sentence formatter
can be identified and processed. This bit of code collects
a sequence of messages so multiple messages can be processed.
This allows you to create custom structures, spanning
the data from multiple messages. For example, a structure
can be created that holds speed, course, latitude, longitude,
the number of satellites in view, and dilution of precision
values.