Blue Theme Orange Theme Green Theme Red Theme
 
MindFusion's Components
Home | Forums | Videos | Photos | Downloads | Blogs | E-Books | Interviews | Jobs | Beginners | Training
 | Consulting  
Submit an Article Submit a Blog 
 Login Close
User Id:
Password:
 
Forgot Password
Forgot Username
Why Register
 Jump to
Skip Navigation Links
TechnologyExpand Technology
WebsiteExpand Website
 Resources  
Close
 Our Network  
Close
Search :       Advanced Search »
Home » C# Language » Mapping with a GPS and C#

Mapping with a GPS and C#

This article shall describe a very simple approach to working with a GPS device within the context of a C# application.

Author Rank:
Technologies: .NET Compact Framework, .NET 1.0/1.1, Common Controls, Controls, Windows Forms,Visual C# .NET
Total downloads : 588
Total page views :  45395
Rating :
 4.77/5
This article has been rated :  13 times
   Print Read/Post comments Post a comment  Rate  
   Email to a friend  Bookmark  Similar Articles  Author's other articles  
 
Become a Sponsor


Related EbooksTop Videos

Introduction:

This article shall describe a very simple approach to working with a GPS device within the context of a C# application. This article does not address how the GPS device works or everything that can be gleaned from the NEMA 0183 string outputted from most GPS devices; rather, the article is intended for those just interested in getting present position from a GPS and using that point to do something interesting like show you where you are on a map.

Nothing exotic or expensive was used in this project; the GPS source was a provided by my Garmin eTrex Legend handheld GPS purchased for about $100.00 (a nice little GPS but not the high end to be sure). Since my laptop provides no male serial ports, in order to connect the device I needed an adapter; for this I opted to purchase a Belkin Serial Port to USB adapter (an F5U109) which works great; the cable used to connect the device to a computer was provided with the device.

 

 

 

Figure 1: Getting Present Position from the GPS

 

To make matters more interesting that just outputting present position, I provided the means to map the point directly into Google Maps using the query string accepted on that site populated with the current latitude and longitude of the device. I had published something similar on C# Corner a while back but without the GPS interface provided.  Interestingly enough (but not surprising), if you compare the present position of the device as shown on the map versus the physical address when plotted on Google Maps, you will likely note that the GPS position is more accurate than the geocoded physical address.

 

NOTE: In order to retrieve present position from the GPS device, it is necessary to configure the device to output the NEMA 0183 complaint string.  Refer to your owner's manuals to determine how to set that up with whatever device you may be using.

 

 

 

Figure 2: Google Maps Showing the Plotted Present Position

 

Getting Started:

 

The solution contains a single Windows Forms project called "ReadGPS" which was written in C#; the application contains two forms (frmPP.cs, frmMap.cs) and, aside from the Program.cs file, all of the code necessary to drive the application is contained in those two form classes.

 

 

 

Figure 3: Solution Explorer with the Project Visible

 

Code:  Main Form (frmPP.cs):

 

All of the code necessary to derive present position from a GPS device is contained in this single form; the form shall be described entirely in this section.

 

The code for this form class begins with the following: 

 

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Text;

using System.Windows.Forms;

using System.IO.Ports;

 

namespace ReadGPS

{

    public partial class frmPP : Form

    {

 

Following the imports, the declaration of the namespace and the form class, the next order of business in the application is to declare a collection of member variables requiring form wide scope; these variables are contained in a defined region entitled, "Member Variables". The declaration of the variables follows:

   

#region Member Variables

 

// Local variables used to hold the present

// position as latitude and longitude

public string Latitude;

public string Longitude;

 

#endregion

 

The form designer contains a single serial port control along with some text boxes used to display present position as latitude and longitude, and two buttons, one of which is used to turn on and off automatic updating of present position and the other which serves to map the present position in Google Maps. The form also contains a timer control used to automatically update the coordinates, and a menu strip control which contains menu options used to change the COM port and to exit the application.

 

The next block of code in the form class is the constructor; in this instance, the constructor is used to try to open the serial port given its default configuration as set in the property pages at design time. For some of the properties associated with the control, it might make sense to allow for runtime configuration changes but, aside from the COM port used to attach the device to the computer, the control is properly configured to work with the GPS device; review the settings for the serial port control in the IDE to review the settings applied.

 

Aside from using the wrong port setting, there is little that can go wrong here but if the initial attempt to open the port fails, the constructor will display a message box showing the user the reason for the connection failure. A failure also disables the timer control used to command present position updates and alters the text on the button used to manually disable the update timer.

 

#region Constructor

/// <summary>

/// Constructor

/// </summary>

public frmPP()

{

    InitializeComponent();

    // Try to open the serial port

    try

    {

        serialPort1.Open();

    }

    catch (Exception ex)

    {

        MessageBox.Show(ex.Message);

        timer1.Enabled = false;

        button1.Text = "Update";

        return;

    }

}

#endregion

 

Following the constructor, the event handlers used within the application are coded. The first is the timer control’s tick event; this is the heart of the application in terms of getting the latitude and longitude extracted from the NEMA 0183 string outputted from the device.

 

The code first checks to see if the serial port is open and, if it is, it reads the output of the device into a string variable. The string is split on the dollar sign symbol to break it up into a string array with each of the subordinate string contained in the output. We are looking for a string beginning with "GPGGA"; this substring contains the latitude and longitude information we are looking for and it is comma delimited. 

 

The whole GPGGA section contains other information besides latitude and longitude (such as time of day information, elevation, the number of satellites tracked, etc.). There are only four parts of the GPGGA section that we want, those sections contain the coordinates and the ordinals defining the position. The rest of the code converts the returned values into decimal degrees and passes them to the latitude and longitude member variables.

 

If we have valid coordinates, the function also enables the button used to map the point into Google Maps. If the values returned are invalid, the form will display "GPS Unavailable" in the latitude and longitude text boxes. If the serial port is closed, the latitude and longitude text boxes will be used to display the message "COM Port Closed"; in either case, the mapping button is also disabled.

 

/// <summary>

/// Try to update present position if the port is setup correctly

/// and the GPS device is returning values

/// </summary>

/// <param name="sender"></param>

/// <param name="e"></param>

private void timer1_Tick(object sender, EventArgs e)

{

    if (serialPort1.IsOpen)

    {

        string data = serialPort1.ReadExisting();

        string[] strArr = data.Split('$');

        for (int i = 0; i < strArr.Length; i++)

        {

            string strTemp = strArr[i];

            string[] lineArr = strTemp.Split(',');

            if (lineArr[0] == "GPGGA")

            {

                try

                {

              //Latitude

                      Double dLat = Convert.ToDouble(lineArr[2]);

                      int pt = dLat.ToString().IndexOf('.');

 

              double degreesLat =      

              Convert.ToDouble(dLat.ToString().Substring(0, pt – 2));

                            

                      double minutesLat =

              Convert.ToDouble(dLat.ToString().Substring(pt – 2));

 

              double DecDegsLat = degreesLat + (minutesLat / 60.0);

 

                      Latitude = lineArr[3].ToString() + DecDegsLat;

 

                      //Longitude

                      Double dLon = Convert.ToDouble(lineArr[4]);

                      pt = dLon.ToString().IndexOf('.');

 

                      double degreesLon =

              Convert.ToDouble(dLon.ToString().Substring(0, pt - 2));

 

                      double minutesLon =

              Convert.ToDouble(dLon.ToString().Substring(pt - 2));

 

              double DecDegsLon = degreesLon + (minutesLon / 60.0);

 

              Longitude = lineArr[5].ToString() + DecDegsLon;

 

                           //Display

                           txtLat.Text = Latitude;

                           txtLong.Text = Longitude;

 

                           btnMapIt.Enabled = true;

                }

                catch

                {

                    //Can't Read GPS values

                    txtLat.Text = "GPS Unavailable";

                    txtLong.Text = "GPS Unavailable";

                    btnMapIt.Enabled = false;

                }

            }

        }

    }

    else

    {

        txtLat.Text = "COM Port Closed";

        txtLong.Text = "COM Port Closed";

        btnMapIt.Enabled = false;

    }

}

 

The following button click event handler is used to enable or disable the timer used to automatically update the present position value shown in the form. The click event handler will also alter the text displayed on the button in response to enabling or disabling the timer.

 

/// <summary>

/// Enable or disable the timer to start continuous

/// updates or disable all updates

/// </summary>

/// <param name="sender"></param>

/// <param name="e"></param>

private void button1_Click(object sender, EventArgs e)

{

    if (timer1.Enabled == true)

    {

        timer1.Enabled = false;

    }  

    else

    {

        timer1.Enabled = true;

    }

 

    if (button1.Text == "Update")

        button1.Text = "Stop Updates";

    else

        button1.Text = "Update";

}

 

The next bit of code is merely used to exit the application in response to the the exit menu option click event.

 

/// <summary>

/// Exit the application

/// </summary>

/// <param name="sender"></param>

/// <param name="e"></param>

private void exitToolStripMenuItem_Click(object sender, EventArgs e)

{

    this.Dispose();

}

 

The following bit of code is used to swap the serial port over to COM1.

 

/// <summary>

/// Swap serialPort1 to port COM1

/// </summary>

/// <param name="sender"></param>

/// <param name="e"></param>

private void toolStripMenuItem2_Click(object sender, EventArgs e)

{

    try

    {

        serialPort1.Close();

        serialPort1.PortName = "COM1";

        serialPort1.Open();

    }

    catch (Exception ex)

    {

        MessageBox.Show(ex.Message, "COM1");

    }

}

 

The following bit of code is used to swap the serial port over to COM2.

 

/// <summary>

/// Swap serialPort1 to port COM2

/// </summary>

/// <param name="sender"></param>

/// <param name="e"></param>

private void toolStripMenuItem3_Click(object sender, EventArgs e)

{

    try

    {

        serialPort1.Close();

        serialPort1.PortName = "COM2";

        serialPort1.Open();

    }

    catch (Exception ex)

    {

        MessageBox.Show(ex.Message, "COM2");

    }

}

 

The following bit of code is used to swap the serial port over to COM3.

 

/// <summary>

/// Swap serialPort1 to port COM3

/// </summary>

/// <param name="sender"></param>

/// <param name="e"></param>

private void toolStripMenuItem4_Click(object sender, EventArgs e)

{

    try

    {

        serialPort1.Close();

        serialPort1.PortName = "COM3";

        serialPort1.Open();

    }

    catch (Exception ex)

    {

        MessageBox.Show(ex.Message, "COM3");

    }

}

 

The following bit of code is used to swap the serial port over to COM4.

 

/// <summary>

/// Swap serialPort1 to port COM4

/// </summary>

/// <param name="sender"></param>

/// <param name="e"></param>

private void toolStripMenuItem5_Click(object sender, EventArgs e)

{

    try

    {

        serialPort1.Close();

        serialPort1.PortName = "COM4";

        serialPort1.Open();

    }

    catch (Exception ex)

    {

        MessageBox.Show(ex.Message, "COM4");

    }

}

 

The following bit of code is used to swap the serial port over to COM5.

 

/// <summary>

/// Swap serialPort1 to port COM5

/// </summary>

/// <param name="sender"></param>

/// <param name="e"></param>

private void toolStripMenuItem6_Click(object sender, EventArgs e)

{

    try

    {

        serialPort1.Close();

        serialPort1.PortName = "COM5";

        serialPort1.Open();

    }

    catch (Exception ex)

    {

        MessageBox.Show(ex.Message, "COM5");

    }

}

 

The next bit of code is used to open up the Map form; the map form accepts a latitude and longitude as arguments. These arguments are passed to the new form and used to display the current location on the map.

 

/// <summary>

/// Open a map of the present position

/// </summary>

/// <param name="sender"></param>

/// <param name="e"></param>

private void btnMapIt_Click(object sender, EventArgs e)

{

    frmMap f = new frmMap(Latitude, Longitude);

    f.Show();

}

 

That wraps up the sum of the code used to communicate with the GPS device and to display the present position latitude and longitude from the NEMA 0183 string.

 

Code:  Map Form (frmMap.cs)

 

This form class is used to display the position captured from the GPS device through Google Maps. The form contains only a single web browser control. The code contained in the class is used to form a query string around the latitude and longitude passed to the form whenever it is instantiated.  Once the query string is assembled, the browser is commanded to navigate to the location indicated in that string.

 

The code is pretty simple and it is presented here in its entirety:

 

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Text;

using System.Windows.Forms;

 

namespace ReadGPS

{

    public partial class frmMap : Form

    {

        public frmMap(string lat, string lon)

        {

            InitializeComponent();

 

            if (lat == string.Empty || lon == string.Empty)

            {

                this.Dispose();

            }

 

            try

            {

                StringBuilder queryAddress = new StringBuilder();

                queryAddress.Append("http://maps.google.com/maps?q=");

 

                if (lat != string.Empty)

                {

                    queryAddress.Append(lat + "%2C");

                }

 

                if (lon != string.Empty)

                {

                    queryAddress.Append(lon);

                }

                webBrowser1.Navigate(queryAddress.ToString());

            }

            catch (Exception ex)

            {

                MessageBox.Show(ex.Message.ToString(), "Error");

            }

        }

    }

}

 

Summary:

 

This article was intended to demonstrate a convenient means for capturing present position information from a GPS device linked to a computer through a serial port. Reviewing the contents of the NEMA 0183 standard and picking out additional information could easily extend the project from the information captured from a GPS device.


Login to add your contents and source code to this article
 [Top] Rate this article
 About the author
 
Scott Lysle
Freelance software developer residing in Alabama. Bachelors, Masters Degrees from Wichita State University. I spent the first half of my career working on aircraft controls and displays and in that time I worked on the cockpits for the OH-58 AHIP, the AH-1W, the V-22, the F-22, the C-130J, the C-5 AMP, AWACS, JPATS, and a few others. Since 1997 I have been largely involved with Windows and web development, GIS application development, consumer electronics development (embedded linux/java), but still sometimes work on aircraft and military projects, the most recent of which was the presidential transport helicopter. I tend to work primarily with C/C++, Java, VB, and C#.
Looking for C# Consulting?
C# Consulting is founded in 2002 by the founders of C# Corner. Unlike a traditional consulting company, our consultants are well-known experts in .NET and many of them are MVPs, authors, and trainers. We specialize in Microsoft .NET development and utilize Agile Development and Extreme Programming practices to provide fast pace quick turnaround results. Our software development model is a mix of Agile Development, traditional SDLC, and Waterfall models.
Click here to learn more about C# Consulting.
 
Introducing MaxV - one click. infinite control. Hyper-V Hosting from MaximumASP.
Finally – a virtual platform that delivers next-generation Windows Server 2008 Hyper-V virtualization technology from a managed hosting partner you can truly depend on. Visit www.maximumasp.com/max for a FREE 30 day trial. Hurry offer ends soon. Climb aboard the MaxV platform and take advantage of High Availability, Intelligent Monitoring, Recurrent Backups, and Scalability – with no hassle or hidden fees. As a managed hosting partner focused solely on Microsoft technologies since 2000, MaximumASP is uniquely qualified to provide the superior support that our business is built on. Unparalleled expertise with Microsoft technologies lead to working directly with Microsoft as first to offer IIS 7 and SQL 2008 betas in a hosted environment; partnering in the Go Live Program for Hyper-V; and product co-launches built on WS 2008 with Hyper-V technology.
Dynamic PDF
ceTE software specializes in components for dynamic PDF generation and manipulation. The DynamicPDF™ product line allows you to dynamically generate PDF documents, merge PDF documents and new content to existing PDF documents from within your applications.
Go.NET
Build custom interactive diagrams, network, workflow editors, flowcharts, or software design tools. Includes many predefined kinds of nodes, links, and basic shapes. Supports layers, scrolling, zooming, selection, drag-and-drop, clipboard, in-place editing, tooltips, grids, printing, overview window, palette. 100% implemented in C# as a managed .NET Control. Document/View/Tool architecture with many properties&events. Optional automatic layout.
Dundas Software
Dundas Chart for .NET is the most advanced .NET charting package available today.  With an extremely complete feature set, elegant architecture and easy implementation, Dundas Chart can quickly add advanced Charting functionality to enhance and transform ASP.NET and Windows Forms applications.  Whether you are implementing charting into internal projects, or building applications for clients, Dundas Chart offers advanced technology and advanced results to get the most out of data.
Clickatell's SMS Gateway
Clickatell's Developer Solutions allow you to SMS enable any website or application via a range of API's. Learn More about our API connections.
Free access to .NET Memory Management video
Everything you need to know about Garbage Collection, Temporary Objects, Fragmentation, Finalization and common causes of memory leaks in .NET. Watch the video here.
Microsoft Visual Studio 2010
Microsoft Visual Studio 2010 offers more to developers than any other Visual Studio release. Work more productively and collaboratively-with greater control over your work at every step. The Beta 2 can give you a head start on achieving efficiency.