Using GPS for VB!

This article was originally published in VSJ, which is now part of Developer Fusion.
GPS – the Global Positioning Satellite system – is a wonder of the modern world, and (if you ignore the cost of a GPS unit) it's free to use. If anything, the facility has been under-used by programmers, and there are lots of innovative applications waiting to be implemented, including robot guidance and all manner of Geographical Information Systems (GIS).

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
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
Figure 2: Sample GPS transmission data

GLL is the code for “Geographic position Latitude/Longitude and the data fields are:

  1. Latitude
  2. N or S (North or South)
  3. Longitude
  4. E or W (East or West)
  5. Universal Time Coordinated (UTC)
  6. Status A – Data Valid, V – Data Invalid
  7. 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 Sub
This 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 Sub
A 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 Sub
After 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 i
You 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 Sub
The 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 <> 0
Now 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 <> 0
Next 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 Sub
Now 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
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.

You might also like...

Comments

About the author

Ian Elliot United Kingdom

Ian Elliot is a development programmer with I/O Workshops Ltd, a consultancy which solves real-world problems for clients with widely varying requirements.

Interested in writing for us? Find out more.

Contribute

Why not write for us? Or you could submit an event or a user group in your area. Alternatively just tell us what you think!

Our tools

We've got automatic conversion tools to convert C# to VB.NET, VB.NET to C#. Also you can compress javascript and compress css and generate sql connection strings.

“XML is like violence - if it's not working for you, you're not using enough of it.”