So many GPS receivers nowadays keep the consumer far removed from the data that they use.  I wanted to get a GPS receiver module but most of them were more than I was willing to spend for a part that I didn't actually have a project for.  SparkFun started selling the GP-635T, which seems to do as much as the more expensive modules but is the least expensive one I've seen so far, and it has a super-simple TTL interface that spits out standard NMEA sentences.

First Version

At first I tried to hook it up using Arduino's SoftwareSerial library, but even at 9600 baud a bunch of data was getting lost.  I plugged the -635's TX straight into the Arduino's RX and all of the sudden I was getting all the data as clean as could be.  The only problem with using the hardware UART is that it's shared with the USB port, so I can't really have any two-way communication.  On the Arduino I used one line of code (other than initialization stuff):

if (Serial.available() ) Serial.write(Serial.read() );

Anything that the -635 gave me I spat right back to the USB port (I didn't hook up the -635's RX pin, so I wasn't echoing data back to it).  This worked perfectly well to give a computer program all of the data that was being produced by the -635, but, honestly, if I wanted a USB GPS receiver I could have just gotten the GP-635U instead of the -635T.  For the time being, though, I focused on developing the computer program to display all of the data.

Up to 12 satellites can be used in calculating the location, and information about 16 is provided (Satellites used in the calculation are highlighted blue in the above screenshot).

Second Version

Although writing code for Windows programs is fun (I think), I wanted to try to make the Arduino do more of the work. I hooked up a 20x4 LCD screen that I had lying around and processed one of the NMEA sentences on the Arduino.  Since a 20x4 screen doesn't have much room I just focused on the RMC (Recommended Minimum Specific GNSS Data) sentence, which gives you the date, time, location, speed, and heading.

The -635 is in the pink baggie taped to the top right of the board in the picture.  Only one wire is hooked from the -635 to the Arduino (pin 0).  The LCD takes a bunch of pins, but since there's no user input I don't really care.  Later I could add a button or two that would let you change what data are displayed or the units used (it defaults to knots, anything else has to be derived from that).

Most of the data displayed on the LCD are simply passed more-or-less directly from the -635, except for the heading which I convert from angle to cardinal heading (it defaults to N if not moving).  Location is displayed in DDD*MM.MMMMM format.

According to the -635's datasheet, you're supposed to be able to change some settings, such as refresh rate (defaults to 1Hz), baud rate, and so on.  It doesn't say how, though.  I've tried sending some input messages to it, but at best I get an "invalid message" response, and at worst I'm just ignored.  I emailed the manufacturer of the actual GPS unit (u-blox) and they directed me to a couple of not helpful documents.  At least they wrote back promptly.

As for the code on the Aduino, I'm embarrassed about the procedure that digests the GPRMC message.  It's not robust, and it pretty much tears apart the sentence with brute force.  The code I used on the computer version (in VB.NET) is much prettier, more compact, more generic, and more robust.  I do appreciate comments on my code (as long as it's a comment or suggestion, and not just a "here's how you should do it").

Code

#include <LiquidCrystal.h>
String inBuffer = ""; //Buffer to hold incoming serial data
LiquidCrystal lcd(12, 11, 10, 5, 4, 3, 2);

void setup(){
Serial.begin(9600); //GP-635T defaults to 9600 8N1
pinMode(13, OUTPUT); //LCD backlight pin
digitalWrite(13, HIGH); //Turn on LCD backlight
lcd.begin(20, 4); //Tell the LiquidCrystal library how big our screen is
}

void loop(){
//If any bytes are available, read them into the buffer
while (Serial.available() > 0){
inBuffer.concat((char)Serial.read() );
}
int msgStart = inBuffer.indexOf('$'); //Find beginning of message
int msgEnd = inBuffer.indexOf("\r\n"); //Find end of message
if ( (msgStart >= 0) && (msgEnd > msgStart) ){ //If we found a beginning and and end and the end is after the beginning...
String curMsg = inBuffer.substring(msgStart, msgEnd+1); //Extract the first message
digestMessage(curMsg); //Process the message we found
inBuffer = inBuffer.substring(msgEnd+1); //Remove the current message from the buffer
}
}

void digestMessage(String toDigest){
Serial.println(toDigest); //Spit all messages back to the USB port for the computer
if (toDigest.startsWith("$GPRMC") ){ //Recommended Minimum Specific GNSS Data
String gpsTime, gpsStatus, gpsLatitude, gpsNS, gpsLongitude, gpsEW, gpsSpeed, gpsCourse, gpsDate; //Raw extracted values
String curTime, curLatitude, curLongitude, curDate; //Reformatted values
int firstComma, secondComma; //Locations of field-separator commas
firstComma = toDigest.indexOf(','); //Find the first comma
secondComma = toDigest.indexOf(',', firstComma+1); //Find the next comma after the first
if ( (secondComma > firstComma) && firstComma >= 0){ //If we found one comma and the second one is after the first one...
gpsTime = toDigest.substring(firstComma+1, secondComma); //Extract the time field
curTime = gpsTime.substring(0,2) + ':' + gpsTime.substring(2,4) + ':' + gpsTime.substring(4,6); //Format the time field (HHMMSS.SSS) to HH:MM:SS
}
/*
* The same process is repeated for the rest of the fields.
* NMEA specifies how many fields are in each message, what is in each field,
* and what order the data appear in, so we can be more-or-less comfortable with
* assuming what data we find in a given field.
* Note that this procedure does not verify the checksum of the sentence...
* something to add in the future.
*/
firstComma = toDigest.indexOf(',', secondComma);
secondComma = toDigest.indexOf(',', firstComma+1);
if ( (secondComma > firstComma) && firstComma >= 0)
gpsStatus = toDigest.substring(firstComma+1, secondComma);
firstComma = toDigest.indexOf(',', secondComma);
secondComma = toDigest.indexOf(',', firstComma+1);
if ( (secondComma > firstComma) && firstComma >= 0)
gpsLatitude = toDigest.substring(firstComma+1, secondComma);
firstComma = toDigest.indexOf(',', secondComma);
secondComma = toDigest.indexOf(',', firstComma+1);
if ( (secondComma > firstComma) && firstComma >= 0)
gpsNS = toDigest.substring(firstComma+1, secondComma);
if ( (gpsLatitude.length() > 4) && (gpsNS.length() > 0) )
curLatitude = gpsLatitude.substring(0,2) + "*" + gpsLatitude.substring(2) + "' " + gpsNS;
firstComma = toDigest.indexOf(',', secondComma);
secondComma = toDigest.indexOf(',', firstComma+1);
if ( (secondComma > firstComma) && firstComma >= 0)
gpsLongitude = toDigest.substring(firstComma+1, secondComma);
firstComma = toDigest.indexOf(',', secondComma);
secondComma = toDigest.indexOf(',', firstComma+1);
if ( (secondComma > firstComma) && firstComma >= 0)
gpsEW = toDigest.substring(firstComma+1, secondComma);
if ( (gpsLongitude.length() > 4) && (gpsEW.length() > 0) )
curLongitude = gpsLongitude.substring(0,3) + "*" + gpsLongitude.substring(3) + "' " + gpsEW;
firstComma = toDigest.indexOf(',', secondComma);
secondComma = toDigest.indexOf(',', firstComma+1);
if ( (secondComma > firstComma) && firstComma >= 0)
gpsSpeed = toDigest.substring(firstComma+1, secondComma);
firstComma = toDigest.indexOf(',', secondComma);
secondComma = toDigest.indexOf(',', firstComma+1);
if ( (secondComma > firstComma) && firstComma >= 0)
gpsCourse = toDigest.substring(firstComma+1, secondComma);
firstComma = toDigest.indexOf(',', secondComma);
secondComma = toDigest.indexOf(',', firstComma+1);
if ( (secondComma > firstComma) && firstComma >= 0){
gpsDate = toDigest.substring(firstComma+1, secondComma);
curDate = gpsDate.substring(2,4) + "/" + gpsDate.substring(0, 2) + "/20" + gpsDate.substring(4);
}
lcd.clear(); //Clear the LCD screen
if (gpsStatus.equals("A") ){ //If we have a valid GPS fix...
//Display the data.
//We have to use setCursor because, for some reason, the LCD library treats the LCD rows as
//0, 2, 1, 3 on a 4-line screen

lcd.print(curDate + " " + curTime);
lcd.setCursor(0, 1);
lcd.print("Lat: " + curLatitude);
lcd.setCursor(0, 2);
lcd.print("Lng: " + curLongitude);
lcd.setCursor(0, 3);
lcd.print(degToCardinal(gpsCourse) + " @ " + gpsSpeed + " knots");
} else {
lcd.print("Invalid GPS Fix"); //GPS reports no fix or an invalid fix
}
}
}

/*

* Converts a degree heading to a cardinal compass heading
*/
String degToCardinal(String degs){
char degsC[64];
float degsF;
degs.toCharArray(degsC, degs.length() + 1);
degsF = atof(degsC);
if (degsF > 337.5)
return "N";
if (degsF > 292.5)
return "NW";
if (degsF > 247.5)
return "W";
if (degsF > 202.5)
return "SW";
if (degsF > 157.5)
return "S";
if (degsF > 112.5)
return "SE";
if (degsF > 67.5)
return "E";
if (degsF > 22.5)
return "NE";
if (degsF >= 0)
return "N";
return "?"; //If, somehow, we didn't find a valid heading (less than zero, perhaps)
}

Views: 1521

Tags: Arduino, GP-635T, GPS, LCD

Comment by Guy Nicholas on December 20, 2013 at 12:17pm

Greetings, I am trying to change the comm rate on the GPS by sending the message listed in this doc: http://www.gui-soft.com/public_share/ublox-commands.pdf

In my Arduino setup function I do
Serial.begin(9600);

Serial.write(baud115200);

Serial.end();

Serial.begin(115200);

but I get nothing.  Did you ever figure out how to get this thing to accept commands?

Regards, Guy

Comment by Jonathan Dean on December 25, 2013 at 12:59am

It's been a while, but I seem to recall that I did have some success sending it commands. I never tried changing the baud rate because 9600 was fine. I do remember that it accepted strings, not binary values, so I don't know what the data in that PDF you mentioned is actually supposed to be telling it. You may want to check here for the u-blox 6 protocol specification, specifically on page 89 of the PDF (or 77 according to what's printed on the page): according to it, you want proprietary message UBX,41. So your message to the device would be something like "$PUBX,41,1,0007,0007,115200,0,*ZZ" followed by a carriage return and linefeed. The ZZ is the calculated checksum (in two-digit hexadecimal), but I didn't bother to calculate it; you can read about that in the same document. Also, the two 0007 values are the input and output protocol masks. Section 4 of the u-blox document talks about that. You could take that string and convert it to a byte array if you wanted, but the end result would be the same, and it's easier to see (and make changes to) the strings.

I hope that helps you get going in the right direction. If I were you, I'd consider why you need to up the baud rate. The device defaults to one update per second, but even at its max of 5Hz I think 9600 is plenty fast. For instance, the example message collection in the SparkFun datasheet is about 600 bytes. If you received that message 5 times per second, that's only 3,000 bytes. You can customize what messages you want to receive to further reduce how much it spits out at you, making the data transfer even smaller. The only reason to crank up the data rate would be if you were polling like mad, but given the limitations of the device (and GPS in general) that you wouldn't get any additional useful data by being so frantic.

Good luck to you!

Comment

You need to be a member of GarageLab (arduino, electronics, robotics, hacking) to add comments!

Join GarageLab (arduino, electronics, robotics, hacking)

Latest Activity

Shannon Bradley and Marcelo Rodrigues are now friends
yesterday
Terry Renner is now a member of GarageLab (arduino, electronics, robotics, hacking)
yesterday
Andy S posted a discussion

Arduino MEGA boolean?

Hi everyone,been banging my head against the wall a few days now.i have a small project, where i…See More
yesterday
Bobby Marshall posted a video

SELFIE Mirror

Meet the S.E.L.F.I.E., the "The Self Enhancing Live Feed Image Engine". Find out how it works: http://istrategylabs.com/2014/04/take-an-instant-selfie-with-t...
yesterday
GarageLab posted a blog post
Tuesday
pj jones posted a status
"Designing an Home Automation Project"
Monday
Profile Iconpj jones, Robert Kribel and Lars Goldschlager joined GarageLab (arduino, electronics, robotics, hacking)
Monday
Fontaine Pierre commented on GarageLab's blog post Tutorial: Using GPS Shield as an Anti-Theft Device
"Hi, Is it possible to make a car tracker with this GPS + GSM shield to send a message if limits…"
Friday
GarageLab posted a blog post
Friday
Profile Iconeslam mohamed haredy, Wesley Castillo and Lise Pape joined GarageLab (arduino, electronics, robotics, hacking)
Apr 10
Terry Dark left a comment for Beula Isaac
"Hi Beulah, Greetings from down under (Australia) Please tell me about yourself and your interests…"
Apr 9
Terry Dark and Beula Isaac are now friends
Apr 9
GarageLab posted blog posts
Apr 9
GarageLab posted a blog post

Festo's BionicKangaroo gets the hop on energy-efficiency

The BionicKangaroo features pneumatic actuators that provide the jumping power and at the same time…See More
Apr 7
Profile IconAnthony Parker, John Nicosia and Tom Devey joined GarageLab (arduino, electronics, robotics, hacking)
Apr 7
wani sageer posted photos
Apr 6
GarageLab posted a blog post

Using a 3D Printer to Draw Tattoos: InkD

 It’s one thing to allow a professional tattoo artist to ink your arm. It’s another thing…See More
Apr 4
GarageLab posted a blog post

Dispensing Solder Paste With A 3D Printer

There’s a strange middle ground in PCB production when it comes to making a few boards. Dispensing…See More
Apr 3
Duong Nguyen is now a member of GarageLab (arduino, electronics, robotics, hacking)
Apr 3
GarageLab posted blog posts
Apr 1

© 2014   Created by Marcelo Rodrigues.

Badges  |  Report an Issue  |  Terms of Service