Opening the Serial Port
Some people use hyperterminal, ProCom+ or some other type of program to open and read serial port data. Windows Vista doesn’t have a terminal included anymore, so I used Visual Basic 2008 Express and the Serial Port Class from MSDN to create my own terminal to open and read serial port data. The information about the serial port class is located on MSDN.
The sample code listed on MSDN allows the user to configure every parameter for the serial port before actually opening it to read data. In my final code I made some modifications to this code to only allow the user to choose the COM port and the Speed of the Port and then use the defaults of 8N1 for the remainder of the port configuration. Also, the name for the class in the example code on MSDN was PortChat. I changed this name to OpenSerialPort since that is the only thing I’m using the class for.
Here is the code I used with the modifications. After I explain the function of the code, I’ll give instructions for how to call the class from the Main subroutine to read the raw GPS data from a Serial Port. In Parsing GPS Data – Step by Step (Part 3) I will explain the functions used to separate the raw GPS data into words and display it in a format that is useful for further calculations.
Imports System
Imports System.IO.Ports
Imports System.Threading
Public Class OpenSerialPort
Shared _continue As Boolean
Shared _serialPort As SerialPort
Public Shared Sub Main()
Dim name As String
Dim message As String
Dim sComparer As StringComparer =
StringComparer.OrdinalIgnoreCase
Dim readThread As Thread = New Thread(AddressOf Read)
' Create a new SerialPort object with default settings.
_serialPort = New SerialPort()
' Allow the user to set the appropriate properties.
_serialPort.PortName =
SetPortName(_serialPort.PortName)
_serialPort.BaudRate =
SetPortBaudRate(_serialPort.BaudRate)
_serialPort.Parity =
SetPortParity(_serialPort.Parity)
_serialPort.DataBits =
SetPortDataBits(_serialPort.DataBits)
_serialPort.StopBits =
SetPortStopBits(_serialPort.StopBits)
_serialPort.Handshake =
SetPortHandshake(_serialPort.Handshake)
' Set the read/write timeouts
_serialPort.ReadTimeout = 500
_serialPort.WriteTimeout = 500
_serialPort.Open()
_continue = True
readThread.Start()
name = Console.ReadLine()
Console.WriteLine("Type QUIT to exit")
While (_continue)
message = Console.ReadLine()
If sComparer.Equals("quit", message) Then
_continue = False
Else
_serialPort.WriteLine( _
String.Format("<{0}>: {1}", name, message))
End If
End While
readThread.Join()
_serialPort.Close()
End Sub
Public Shared Sub Read()
While (_continue)
Try
Dim message As String = _serialPort.ReadLine()
Console.WriteLine(message)
Catch ex As TimeoutException
' Do nothing
End Try
End While
End Sub
Public Shared Function SetPortName
(ByVal defaultPortName As String) As String
Dim newPortName As String
Console.WriteLine("Available Ports:")
Dim s As String
For Each s In SerialPort.GetPortNames()
Console.WriteLine(" {0}", s)
Next s
Console.Write("COM port({0}): ", defaultPortName)
newPortName = Console.ReadLine()
If newPortName = "" Then
newPortName = defaultPortName
End If
Return newPortName
End Function
Public Shared Function SetPortBaudRate
(ByVal defaultPortBaudRate As Integer) As Integer
Dim newBaudRate As String
Console.Write("Baud Rate({0}): ", defaultPortBaudRate)
newBaudRate = Console.ReadLine()
If newBaudRate = "" Then
newBaudRate = defaultPortBaudRate.ToString()
End If
Return Integer.Parse(newBaudRate)
End Function
Public Shared Function SetPortParity
(ByVal defaultPortParity As Parity) As Parity
Dim newParity As String
Console.WriteLine("Available Parity options:")
Dim s As String
For Each s In [Enum].GetNames(GetType(Parity))
Console.WriteLine(" {0}", s)
Next s
Console.Write("Parity({0}):",
defaultPortParity.ToString())
newParity = Console.ReadLine()
If newParity = "" Then
newParity = defaultPortParity.ToString()
End If
Return CType([Enum].Parse(GetType(Parity),
newParity), Parity)
End Function
Public Shared Function SetPortDataBits
(ByVal defaultPortDataBits As Integer) As Integer
Dim newDataBits As String
Console.Write("Data Bits({0}): ",
defaultPortDataBits)
newDataBits = Console.ReadLine()
If newDataBits = "" Then
newDataBits = defaultPortDataBits.ToString()
End If
Return Integer.Parse(newDataBits)
End Function
Public Shared Function SetPortStopBits
(ByVal defaultPortStopBits As StopBits) As StopBits
Dim newStopBits As String
Console.WriteLine("Available Stop Bits options:")
Dim s As String
For Each s In [Enum].GetNames(GetType(StopBits))
Console.WriteLine(" {0}", s)
Next s
Console.Write("Stop Bits({0}):", defaultPortStopBits.ToString())
newStopBits = Console.ReadLine()
If newStopBits = "" Then
newStopBits = defaultPortStopBits.ToString()
End If
Return CType([Enum].Parse(GetType(StopBits),
newStopBits), StopBits)
End Function
Public Shared Function SetPortHandshake
(ByVal defaultPortHandshake As Handshake) As Handshake
Dim newHandshake As String
Console.WriteLine("Available Handshake options:")
Dim s As String
For Each s In [Enum].GetNames(GetType(Handshake))
Console.WriteLine(" {0}", s)
Next s
Console.Write("Stop Bits({0}):",
defaultPortHandshake.ToString())
newHandshake = Console.ReadLine()
If newHandshake = "" Then
newHandshake = defaultPortHandshake.ToString()
End If
Return CType([Enum].Parse(GetType(Handshake),
newHandshake), Handshake)
End Function
End Class
The important parts of the OpenSerialPort Class are the Imports to insure you are using the System, System.IO, and System.Threading libraries. You can play around with this code by making modifications to only allow the user to choose the configuration options or to just use all of the defaults. It’s up to you. The other important part of this code as you will see in Part 3 is the “Public Shared Sub Read()”. This function as listed below compiles and reads the raw GPS data from the serial port. When you create the parsing function in Part 3, you will change Console.WriteLine(message) to Console.WriteLine(parse(message)).
Public Shared Sub Read() While (_continue) Try Dim message As String = _serialPort.ReadLine() Console.WriteLine(message) Catch ex As TimeoutException ' Do nothing End Try End While End Sub
Creating the Main Subroutine
When you create a new console application project in Visual Basic 2008 Express, you should already have the subMain file created for you. You will first have to add the SerialPortOpen class to the project, then modify the sub Main as follows to call the SerialPortOpen class from the Main subroutine.
Module gpsParser Sub Main() OpenSerialPort.Main() End Sub End Module
So, that’s it for opening the serial port and reading the raw GPS data. Make sure you have your GPS connected to the serial port then compile and run the program. You will then see the raw GPS data on a console window on your computer. In Parsing GPS Data – Step by Step (Part 3) we will create the functions required to break the GPS data in to words and only display the data we want to display and in a format that is useful to us for further calculations.
I spent a lot of time getting this gpsParser program to work and am familiar with the intricacies of the code. Feel free to ask questions if you don’t understand something and I will try my best to answer them.
Autonomous robots need a way to navigate from one point to another. Using a global positioning system (GPS) is one of the main ways to accomplish this. The readouts from a GPS are created in raw data format in a standard sentence derived from the National Marine Electronics Association (NMEA) 0183 standard.
This tutorial will show you how to use a Visual Basic 2008 program to open a serial port, read the GPS data, extract the useful information and format it in a useful format for our purposes and display the information for use in our autonomous robotics systems.
In the first part of this tutorial we need to analyze the GPS data to know exactly what data we are looking at and how we will use that data.
For our purposes of having our robot navigate by itself from one point to another, the NMEA Recommended Minimum sentence is used. NMEA data is sent as comma-delimited “sentences” which contain information based on the first word of the sentence. There are over fifty kinds of sentences, yet we only need to handle one to get the job done.
Here is an example of the sentence we will focus on for this tutorial:
$GPRMC,220516,A,5133.82,N,00042.24,W,173.8,231.8,130694,004.2,W*70
As you can see, the navigation information is there, but it is not really useful to us in using the data to make further calculations or integrating with our other robotics systems such as a compass or local sensors. Thanks to the NMEA, the raw data is given to us directly from the satellites separated by commas. This gives us a way to separate and pull out the data we need for our robotics system.
From this GPS sentence, the only parts of the data we need to use are the Validity Codes, Latitude, Longitude, Speed, Direction, and Magnetic Deviation. The other parts of the sentence; Time Stamp, Date Stamp, and checksum are not needed.
Let’s look at the parts of the sentence that is given to us and see what we can do with this data.
Signal Fix
This is a 3rd word in the sentence (looking at the commas, it is the third set of data with $GPRMC as the first word, Satellite Time as the second word, and either the letter “A” or the letter “V” as the third word).
If this word has the letter “V”, it means that there is no valid satellite fix and the rest of the data in the sentence is invalid, or “a bad fix”.
If this word has the letter “A”, it means that the satellites are locked in to the position and the rest of the data in the sentence is active, or “a good fix”.
Latitude and Longitude
These data elements are located in the 4th, 5th, 6th, and 7th words in NMEA sentence. The latitude is given as degrees, minutes and hemisphere.
Looking at the 4th and 5th words in the sentence (the latitude), we see:
5133.82, N
Broken down into data we can use, we see that the degrees are 51 degrees, the minutes are 33.82 and the hemisphere is the Northern hemisphere. Note: Because we are in the Northern hemisphere, we will need to insure this value remains a positive value so we can use the data in other calculations. If we were in the Southern hemisphere, this would be a negative value.
Looking at the 6th and 7th words in the sentence (the longitude), we see:
00042.24,W
Broken down into the data we can use, we see that the degrees are 0 degrees, the minutes are 42.24, and the hemisphere is the Western hemisphere. Note: Because we are in the Western hemisphere, we will need to insure this value is a negative value so we can use the data in other calculations. If we were in the Eastern hemisphere, this value would be positive.
Speed
Looking at the 8th word in the sentence (the speed), we see:
173.8
This is the speed the robot would be travelling at in knots. Since we are not sailors, we will want to convert this data into miles per hour. To do this in our GPS parsing program, we will multiply this value by 1.15077944802354 to convert it to miles per hour. So, 173.8 knots is equal to about 200 miles per hour. Of course, our robot will not be travelling that fast. The maximum speeds we will be expecting our robot to travel would be about 3 miles per hour.
Heading
Looking at the 9th word in the sentence (heading), we see:
231.8
Heading is the angle where our robotic vehicle is pointing compared to the angle of True North. This is a very important piece of data as when it is used in conjunction with the other readings, we can determine where we are at a where we are going.
Magnetic Variation
Looking at the 11th and 12th words in the sentence (magnetic variation or magnetic declination), we see:
004.2,W*70
This is a special part of the NMEA sentence because it’s the only words that are separated by an “*” instead of a comma. In our program we will treat this word differently in how we extract the data. The *70 at the end of the sentence is the checksum. Since the GPS already provides this, we do not need it for anything else, so we will just use the “W” in our program.
Magnetic declination is the difference between true north (the axis around which the earth rotates) and magnetic north (the direction the needle of a compass will point). Because magnetic north is different than true north, we will use this information to adjust our heading to insure we are going exactly where we want to go instead of getting lost.
Opening a Serial Port
Now that we know what the data is we are looking at, we have to open a serial port to read it. The next part of this tutorial will show you how, using the most recent Visual Basic serial port class.
GPS coordinates are commonly displayed as latitude and longitude. This is not a projection to a Cartesian coordinate system (x, y grid) such as state plane or UTM, but an angular coordinate system. Degrees of latitude and longitude measure the angle between a location and the reference line, namely the equator and Greenwich England. The equator is a fairly obvious reference line as it creates a plane bisecting the globe half way between the North Pole and the South Pole. It is relatively easy to locate since a person standing at the equator casts no shadow twice a year (vernal and autumnal equinox. About March 21 and September 21). Latitude is the angle formed by a line from the center of the earth to the equator and a line from the center of the earth to your location. Latitude is zero at the equator, North (positive) 90 degrees at the North Pole, and South (negative) 90 degrees at the South Pole.
Longitude has a much more complicated history as it is far more difficult to determine without GPS. Longitude is the angle formed by a line from the center of the earth to the prime meridian at Greenwich England and a line from the center of the earth to your location. (A meridian is a line of longitude running from pole to pole.) Since the earth rotates 360 degrees each day, it is necessary to know the time very accurately in order to relate the location of the sun to this angle. The English were very involved in shipping and development of an accurate, seagoing clock so that they could accurately calculate the correct longitude. They chose to use the Royal Observatory at Greenwich, London, England for their reference meridian. (Visit http://millennium-dome.com/info/conference.htm for more information) Longitude ranges from West (negative) 180 degrees to East (positive) 180 degrees.
Latitude and Longitude are frequently recorded as degrees, minutes and seconds. Ptolemy (about 150 AD) divided the degrees into 60 parts and those parts into 60 parts. “In the Latin translation of the text these subdivisions became partes minutae primae and partes minutae secundae from whence our “minutes” and “seconds” of arc are derived.” (Brown, The Story of Maps, pg 60) This can be cumbersome so you could use Decimal Degrees. GIS systems need to use this simpler format. This table below shows the precision of various units at the northern U.S. region. Note that one degree of longitude is about 69 miles at the equator and 0 miles at the poles. Latitude is always about 69 miles.
| Latitude | Longitude | |
| 1 degree | 69 miles | 42 miles |
| 1 minute | 6072 ft | 3696 ft |
| 1 second | 101.2 ft | 61.6 ft |
| Decimal Degrees | ||
| 0.1 | 36432 ft | 22176 ft |
| 0.01 | 3643.2 ft | 2217.6 ft |
| 0.001 | 364.32 ft | 221.76 ft |
| 0.0001 | 36.43 ft | 22.18 ft |
| 0.00001 | 3.64 ft | 2.22 ft |
| 0.000001 | 4.37 In | 2.66 In |
| 0.0000001 | 0.44 In | 0.27 In |
Conversion from degrees, minutes, seconds to decimal degrees
118 degrees 8 minutes 26.2353 seconds West. = -118.1406209154
118 + 8/60 + 26.2353/3600 = 118.1406209154 Make this negative if it is either west longitude or south latitude.
Conversion from decimal degrees to degrees, minutes, seconds
-118.1406209154 = 118 degrees 8 minutes 26.2353 seconds West
W If it is negative then it is either west longitude or south latitude.
118 The degrees are left of the decimal place
8 Multiply the decimal portion (0.1406209154) by 60 to get decimal minutes (8.4372549). The minutes are left of the decimal place.
26.2353 Multiply the decimal portion (0.4372549) by 60 to get decimal seconds
Two common projected coordinate systems
State Plane and Universal Transverse Mercator (UTM) coordinate systems are commonly used in the GIS/GPS industry. State plane coordinates are not usually used on personal GPS units as there are many separate State Plane coordinates systems and they vary enough that they can be difficult to explain. UTM is commonly found on USGS Topographic maps so can be useful for outdoorsmen who are using these maps. The units are meters from a reference point. We are in UTM Zone 11 North. Each zone covers 6 degrees of longitude. Its origin is at the equator and its central meridian (Zone 11’s central meridian is 117 degrees W). A false easting of 500,000 is used to make sure that all of the coordinates are positive. Units will be X meters East and Y meters North. (Note that there are 3.2808 feet/meter)
Datums
The two most common datums in use today are WGS 84 (World Geodetic System of 1984. A geocentric datum and geographic coordinate system created by the United States military) and NAD83 (North American Datum of 1983. A geocentric datum and graphic coordinate system based on the Geodetic Reference System 1980 ellipsoid (GRS80). Mainly used in North America, its measurements are obtained from both terrestrial and satellite data.) A less common datum is NAD27. (North American Datum of 1927. The primary local geodetic datum and geographic coordinate system used to map the United States during the middle part of the 20th century, referenced to the Clarke spheroid of 1866 and an initial point at Meades Ranch, Kansas. Features on USGS topographic maps, including the corners of 7.5-minute quadrangle maps, are referenced to NAD27. It is gradually being replaced by the North American Datum of 1983.)
Magnetic Declination
Magnetic Declination relates magnetic north (where a needle points) to true north (north pole). You can go to the NOAA website to calculate the current declination for you area. http://www.ngdc.noaa.gov/seg/geomag/jsp/struts/calcDeclination Declination does change over time and varies by location.
Compasses
Some GPS units have a digital compass built in (expensive) and others use calculated bearing from GPS coordinates collected along your path (course you have been following, not necessarily where you are going, and NOT where the unit is pointing). Using the compass on a GPS unit is often difficult to do well and thus ill advised. A high quality option that is fairly easy to use (instructions included) is the Silva Ranger CLQ Sighting Compass with Quadrants Bezel. This compass has a mirror and sighting notch to aid accurate sighting. The quadrant bezel reads in units like you normally find on legal descriptions and in 2 degree increments for fine resolution. There is also a geared adjustment of declination so that declination compensation becomes automatic and stable. Price is around $60.
Wide Area Augmentation System (WAAS)
WAAS is a system for correcting GPS coordinates so that their accuracy is adequate for precision flight operations at airports. The FAA is helping to develop this system and is now available on many GPS units that you buy over the counter. Visit the FAA’s website to read more about it. http://gps.faa.gov/Programs/WAAS/waas.htm This is a relatively inexpensive feature that is highly recommended.
The Robotics Society of Southern California meets every two weeks on the 2nd and 4th Saturdays of every month. Presentations and contests are usually held on the 2nd Saturday of the month.
There was a very interesting presentation about probabilistic robotics at the meeting yesterday. The virtual robot had a map of a room already loaded into the its brains. Then the robot was placed at a random point in the room. Based on probability, the robot was able to calculate its exact position in the room.
The science of probabilistic robotics is all about creating algorithms to determine the probability that certain conditions exist by taking into account several different sensor readings to determine location.


For my Artificial Intelligence robot project (ENZO), I will be using the HEDS-9100 optical encoder to get control over the exact speed and direction of my robot.
In the picture you will see the numbers on the encoder module (A00). This is the US Digital code for the characters per inch (CPI) resolution. The particular encoder module I am using is coded as G00. This means that the encoder is designed to operate at 360 CPI.
On Enzo, I am using 8 inch wheels that will be turning at about 200 rpm with a maximum speed of 2128 mm/sec. Enzo will probably not reach this speed with a load but the motors are 350W scooter motors and they are pretty powerful, so if he is going downhill, there’s a chance he could reach maximum speed. Enzo also has a speed reducing shaft running at about 1300 rpm. This is where I’ll be mounting the encoder module. The reason I chose the HEDS9100-G00 is because I needed an encoder operating a 600 clicks per revolution if I mounted it on the wheel itself. Since I am mounting on the reducer shaft, I needed an encoder with 100 clicks per revolution. At 100 clicks per revolution, it would meet the minimum requirement of 1 click per millimeter. The basic rule is that you can use an encoder up to about 5 times the minimum requirement, hence my 360 clicks per inch encoder as it is between 100 and 500 clicks per inch.
If you want to see more information about the encoder, here is the datasheet: heds_datasheet_1
Here’s a diagram of how the encoder will be mounted:


