Parsing GPS with Arduino – retro-post

I dug up one of my oldest blog posts from about 7 years ago.  In the post, I show how I had connected my Garmin eTrex GPS receiver to an Arduino board and used it to control a camera in a desktop application.

After pumping the data into the Arduino, I parsed the raw GPS data coming from the eTrex and streamed it out to a Python app on the desktop, via a serial port.  I was using the output to position a virtual camera in the OSSIMPlanet platform by formatting XML in Python and sending it to a listener built into the OSSIMPlanet app.  (OSSIMPlanet is a sort of pre-Google Earth, Google Earth on steroids product.)

I haven’t used it for years, but thought some of the methods from this old post may still apply if you have an Arduino + GPS or Arduino -> Python streaming requirement.   Enjoy the flashback – I know it’s inspired me to pick up a new Arduino to continue where I left off.


 

GPS Controls OSSIMPlanet - With OSSIMPlanet’s nifty camera control and listener functionality, as demonstrated in my last post, you’ve got so many neat opportunities. A couple nights ago I got a basic GPS NMEA parser working. Here’s a pic of the ultra-professional connection method I use to hook it to my arduino board 🙂 Oops, just realised that the picture … Continue reading GPS Controls OSSIMPlanet

Two wires to hook an eTrex data cable up to the Arduino
Two wires to hook an eTrex data cable up to the Arduino

Read Post

GPS Controls OSSIMPlanet

With OSSIMPlanet’s nifty camera control and listener functionality, as demonstrated in my last post, you’ve got so many neat opportunities. A couple nights ago I got a basic GPS NMEA parser working. Here’s a pic of the ultra-professional connection method I use to hook it to my arduino board 🙂

Two wires to hook an eTrex data cable up to the Arduino
Two wires to hook an eTrex data cable up to the Arduino

Oops, just realised that the picture shows the wires in the wrong spot (it was a late night photo). Pin 2 from the serial cable goes into the Power GND on left side of board. Pin 5 from serial cable goes into the Digital Pin 0 aka RX pin on lower right.

Note that I had a lot of confusion regarding the pin-out options for the Etrex. I looked at several diagrams and couldn’t get the right pins to work. It appears that you may actually need to swap the ground/TX pins to make it work – that’s what I had to do. This is something to do with how the serial connection works.. something I won’t pretend to understand – but swapping the wires worked, that’s all I know!

Of course you could always use your nifty new bluetooth GPS receiver, or plug your receiver directly into the PC and this would still work. But for me, I will have additional devices going into the arduino, where their signals will get mixed together before being sent to the PC.

Arduino setup

The arduino doesn’t do much here, except filter the strings coming from the GPS. It grabs only the $GPGGA string that has the location info I want. I specifically used the GPGGA because the Python NME parser code example I had used that one and I didn’t want to have to learn how to handle the $GPRMC strings.

Here’s the basic code I run on the Arduino:

Tmitchell: on etrex port - pin 1 (at notch end) is for TX and pin 3 for GND
On serial cable out Pin 2 -> GND, Pin 5 as TX (hooks to Digital 0=RX on board)
*/ 
#include <string.h>

#include <ctype.h>
int ledPin = 13;                  // LED test pin
int rxPin = 0;                    // RX PIN 
int txPin = 1;                    // TX TX
int byteGPS=-1;
char linea[70] = "";
char comandoGPR[7] = "$GPGGA";
char latdms[9], londms[10], latdir[1], londir[1] = "";
int latdd, londd, heading = 0;
int cont=0;
int bien=0;
int conta=0;
int indices[13];

void setup() {
  pinMode(ledPin, OUTPUT);       // Initialize LED pin
  pinMode(rxPin, INPUT);
  pinMode(txPin, OUTPUT);
  Serial.begin(4800);
  for (int i=0;i<70;i++){       // Initialize a buffer for received data
    linea[i]=' ';
  }   
}
void loop() {
  digitalWrite(ledPin, HIGH);
  byteGPS=Serial.read();         // Read a byte of the serial port
  if (byteGPS == -1) {           // See if the port is empty yet
    delay(100); 
  } else {
    linea[conta]=byteGPS;        // If there is serial port data, it is put in the buffer
    conta++;                      
    if (byteGPS==13){            // If the received byte is = to 13, end of transmission
      digitalWrite(ledPin, LOW); 
      cont=0;
      bien=0;
      for (int i=1;i<7;i++){     // Verifies if the received command starts with $GPR
        if (linea[i]==comandoGPR[i-1]){
          bien++;
        }
      }
      if(bien==6){               // If yes, continue and process the data
        for (int i=0;i<70;i++){
          if (linea[i]==','){    // check for the position of the  "," separator
            indices[cont]=i;
            cont++;
          }
          if (linea[i]=='*'){    // ... and the "*"
            indices[12]=i;
            cont++;
          }
        }
          Serial.print(linea);  // This is the important line :)
      }
      conta=0;                    // Reset the buffer
      for (int i=0;i<70;i++){    //  
        linea[i]=' ';   
      }                 
    }
  }
}

 

I had originally hoped to do the XML prep in the arduino, but skipped it for now due to my poor understanding of variable types in the processing language. So for now I’ve still got a lot of cruft leftover in the above, that I didn’t need from the original tutorial code. But as I add more sensors I’ll want to do more mixing in the board itself.

So the arduino board just sends a raw NMEA $GPGGA string to the serial port, where Python takes over.

Python Serial Reader and OSSIM Controller

I then use a Python script that checks for strings coming from the arduino board. It does a bit of filtering, but not much error checking at the moment. This is the first time I’ve used Python to connect to the serial port, so it was fun to learn and so simple!

I found this GPGGA parser code and incorporated it into my script. I won’t paste it here as it is quite long. But here is the rest of my script – reading from Serial, parsing results, then reformatting and sending to OSSIMPlanet… comments, cruft and crummy coding.. all yours for free!

Be sure to have OSSIMPlanet running and set its Preferences to listen on port 5000 first.

# Uses PySerial
import serial

# GPGGA Parsing code next

class GPGGAParser(object):
import logging

# Open connection to Arduino
s = serial.Serial('/dev/cu.usbserial-A6001VQr', 4800, timeout=1) heading = 0
# initialising here so I can rotate the heading during each cycle.. just for fun

# Read Arduino output

while (1>0):
char = s.read(1)
while (char <> '$'):
char = s.read(1)
else:
sentence = '$' + s.read(70)
# Parse output
#############
print sentence.strip()
if (len(sentence.strip())<=30) or (sentence[1:5] <> 'GPGG'):
continue
else:
parsed = GPGGAParser(sentence)

if (parsed.latitude <> 0 and parsed.longitude <> 0):

#####################
# Reformat to XML
## Hacked method first
heading += 10 # during testing I never moved,
# so I made it hover over my location and
# slowly spin 10 degrees each second
if (heading >= 360): heading = heading-360
pitch = 70
altitude_mult = 10
ossimxml = '<Set target=":navigator" vref="wgs84"><Camera><longitude>%s</longitude><latitude>%s</latitude><altitude>%s</altitude><heading>%s</heading><pitch>%s</pitch><roll>0</roll><altitudeMode>absolute</altitudeMode></Camera></Set>' % (parsed.longitude, parsed.latitude, parsed.altitude * altitude_mult, heading, pitch)
print ossimxml # show xml being sent to ossimplanet
## Proper DOM tools second - will do this "right" at some point :)
## But not written yet

#######
# Open connection to OSSIMPlanet listener
import socket
ossim = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
ossim.connect(("127.0.0.1", 5000))
# Send view updates
# Optional: connect to OSSIMPlanet broadcaster
## adjust coordinates based on current view
## I will do this when using nunchuks, but for now nothing
ossim.send(ossimxml)
ossim.close()
# Lather, rinse, repeat....

That’s about it. In OSSIMPlanet the updates are practically instantaneous, but I wait 1 sec for new GPS data to come in. When I start using the nunchuks I’ll want to do more updates faster to emulate the movement smoother. But that’s for another day…

%d bloggers like this: