Protocol
Communication between a GPS unit and a PC or any other unit is far from standardised – or rather there are too many standards. Manufacturers such as Garmin have developed their own protocols, which work with their own software. While these proprietary protocols are reasonably well documented, they are 'proprietary', and they even vary between different models from the same manufacturer. NMEA (National Marine Electronics Association) standard 0183 covers marine instruments including GPS devices, and while it might not have all of the features of the proprietary protocols, it should work with every GPS. Before proceeding make sure you have a connecting cable and that the GPS is set to NMEA default protocol.NMEA
The basic idea of NMEA is very simple. Short packets of data are sent between a talker and a listener device.
Figure 1: The basic NMEA packet
The format of the packets is always the same (see Figure 1). The two letters represented by tt represent the talker device, i.e. the device sending the data. The type of data contained in the packet is indicated by the three letters “sss”. The actual data follows, separated by commas, and the end of the packet is always indicated by a carriage return line feed. In addition, an optional check sum can be (and usually is) transmitted in the format *hh just before the carriage return linefeed, but for simplicity we will ignore this as transmission errors are unlikely.
For example, a GPS talker, code “GP” might send the data shown in Figure 2.
Figure 2: Sample GPS transmission data
GLL is the code for “Geographic position Latitude/Longitude and the data fields are:
- Latitude
- N or S (North or South)
- Longitude
- E or W (East or West)
- Universal Time Coordinated (UTC)
- Status A – Data Valid, V – Data Invalid
- Checksum
Reading packets
When you switch on the GPS, by default it transmits a sequence of packets over and over and all you have to do is pick the packets that you want to read and decode.The basic idea of this program is to read the data coming from the GPS, and make a list of all of the packets it receives.
Most GPS devices use a serial interface to a PC. To use a serial port from Visual Basic we have to make use of the Microsoft Comm Control 6.0. To get started, open a new .EXE project and load the Comm Control onto the toolbar. Also place a textbox on the form and set it to multi-line with a vertical scroll bar.
The first task is to initialise the serial port and open it:
Private Sub Form_Load() ' Open the serial port MSComm1.CommPort = 1 MSComm1.Settings = “4800,N,8,1” MSComm1.PortOpen = True MSComm1.InputLen = 0 End SubThis assumes that the GPS is connected to COM1 and set to the default protcol. To close the serial port when the form is unloaded we need to add:
Private Sub Form_Unload(_ Cancel As Integer) MSComm1.PortOpen = False End End SubA button on the form is used to start reading the data stream. We have to cope with the fact that we might have got only a fragment of a packet at the start and end of the stream. We could go in for a complicated and complete parsing of the data stream, but a simpler (though slightly dirty) method is to split the packets up using the carriage return linefeed separators, and then throw away the first and last packets which are the only ones that might be fragments.
The entire process is going to be repeated every second, which is roughly the repeat time for the data that the GPS sends:
Private Sub Command1_Click() Dim mess As String Dim packets As Variant Dim list As New Dictionary Dim key As String Do delay (1)The delay routine is:
Public Sub delay(t As Single) t = t + Timer Do DoEvents Loop Until t < Timer End SubAfter waiting a second we read whatever data is sitting in the buffer and use Split to separate the packets:
mess = MSComm1.Input packets = Split(mess, vbCrLf)Now we can add each of these packets in turn to a dictionary object which is used to remove duplicates:
For i = 1 To UBound(packets) – 1 key = Left$(packets(i), 6) If list.Exists(key) Then list.Remove key End If list.Add key, packets(i) Next iYou have to remember to load a reference to the VBScript runtime library to make use of a dictionary object. The for loop runs from 1 to one less than the size of the array. This drops the first and last packet received.
Next the 6-character header, i.e. $ttsss, is stripped off the packet to act as a key for storage in the Dictionary. First we check to see if a packet of this type is already stored in the Dictionary. If it is we have to assume that the new one is more up-to-date and so we remove the existing packet from the dictionary and then add the new one.
Once this is complete the dictionary object contains all of the unique packets retrieved on this and any subsequent loops. Now all we have to do is transfer the packets into the textbox so that they can be examined.
packets = list.Items Text1.Text = “” For i = 0 To UBound(packets) Text1.Text = Text1.Text & _ packets(i) & vbCrLf Next i DoEvents Loop End SubThe Items method returns all of the packets in a string array and all we have to do is store them in the textbox. If you now run the program with the GPS switched on you will see a list of all the types of packets it transmits.
Reading position
The biggest problem with using NMEA is finding out what the meaning of each of the packets is and what format the data takes. You can find lists of standard packets by searching the web for NMEA, but there are still proprietary variations to take account of.Once you know the data format of a packet, getting the data from the GPS is relatively easy. As an example, consider the most basic of packets for any GPS – the GLL packet which gives your position as described earlier.
To read and display this data all we have to do is start a new project and create a form with six text boxes, one for each of the data fields and a button. Of course we also need the serial control as described in the previous example, and we need to open and close the port in the same way, i.e. use the same Form_Load and Unload handlers. The layout of the textboxes doesn't matter, but for simplicity I've used textN to store data field N.
In this case we don't need to read everything that the GPS has to throw at us, all we want is a single GLL packet, so the first job is just to read the serial port until we find a “GLL” header:
Private Sub Command1_Click() ' find GLL packet Dim mess As String Dim start As Integer Text6.Text = “Getting Data” Do DoEvents mess = MSComm1.Input start = InStr(1, mess, “GLL”) Loop Until start <> 0Now we have the right packet we can trim it to by removing the header:
' Trim to start of packet mess = Mid$(mess, start)Before parsing the rest of the packet we have to deal with the possibility that we might have only a fragment of the packet. To ensure we have the whole packet we need to read the serial buffer and add it to the string until we find a CR/LF pair:
Do DoEvents mess = mess & MSComm1.Input start = InStr(1, mess, vbCrLf) Loop Until start <> 0Next we throw away everything that follows the CR/LF:
mess = Left$(mess, start)All that remains to do is split the comma separated data into an array:
Dim info As Variant info = Split(mess, “,”)Now we can display each item of data:
Text1.Text = info(1) Text2.Text = info(2) Text3.Text = info(3) Text4.Text = info(4) Text5.Text = info(5)The sixth data item is “V” if the data is invalid, i.e. no satellite lock, and “A” if it's valid and needs to be treated slightly differently:
If info(6) = “V” Then Text6.Text = “Data not valid” Else Text6.Text = “Data valid” End If End SubNow if you run this and click the command button while the GPS is connected you should see the longitude, latitude and UTC time displayed. If there isn't a lock you won't see any data, and if you keep clicking the button you will see an updated display (see Figure 3).
Figure 3: You are here
Of course this is just the start. You can now build applications that read in your current position and make use of it in clever ways.
Comments