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 :)

http://spatialguru.com/files/arduino_gps-2sml.jpg

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
......<snip>

# 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 1sec 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...

http://spatialguru.com/files/ossimsnap2.png

Comments

Tyler Mitchell:

David - great to hear you had such easy success :) I certainly love having some hardware with serial ports to play around with sticking wires in and out of. I look forward to hearing about your future adventures.

David Kwast:

It works!!!

http://picasaweb.google.com/lh/photo/y16-n8nLlU2OTCiFkHB8Yg?authkey=Gv1sRgCJ_F4KONwIztMQ&feat=directlink

I did a simple program based on yours. My arduino justs receive a byte and send it to the Serial Monitor through USB. It worked in the first try. It is my second day with arduino!!!

Thank you

Here is my code:

void setup()
{
Serial.begin(4800);
}

int byteGPS=-1;

void loop()
{
byteGPS=Serial.read(); // Read a byte of the serial port
if (byteGPS == -1) { // See if the port is empty yet
delay(100);
}
else{
Serial.print(byteGPS, BYTE);
}
}

Sam:

Ok, I think I got it working. My problem was that I was down in my basement messing with this and my GPS module wouldn't update causing the script to spit out errors. Once this is going should OSSIM planet be zoomed into the GPS coordinates? As of right now it is doing nothing. I have the listener set to "data".

sam:

I seemed to have gotten this working. It runs once, then stops with this error: "Traceback (most recent call last):
File "/Users/hexus/Desktop/gpsscript1.py", line 67, in
parsed = GPGGAParser(sentence)
TypeError: object.__new__() takes no parameters"
Any ideas?

Tyler Mitchell:

Sam - Thanks for the feedback. You likely just the PySerial module:
http://pyserial.wiki.sourceforge.net/pySerial

Sam:

First of all thanks for this awesome code. I attempted to execute this script but I get this "import" error: "no module named serial". Any ideas?

Tyler Mitchell:

Cassandra, perhaps it is trying to connect at the wrong baud rate/speed. You would change the "4800" in this line. Try 9600 maybe?

s = serial.Serial('/dev/cu.usbserial-A6001VQr', 4800, timeout=1)

cassandra:

Hi,
first of all, tank for your grat job.
I tried to reveive from arduino data from my lorentz receiver, but when I open serial moniotr during data procesing I read strange symbols that I don't understand..
I miss something or tht's an error for a newbie? :)
data seems to come to pc, but they are Y(square)YY..
thnks for any suggestion.
Cassandra.

Tyler Mitchell:

Andy, the script will not return anything if the GPS is not actually receiving a satellite lock. Maybe that is your problem? Or are you getting a failure? I'm sure there is still a lot to improve in that script :)

Andy:

Hello

Great code but.. I got a GPSmap 76 so mot so different from your Etrex. But as i connected the GPS to the Arduino I do get sometimes the right values but most of the time I don't get an data...
Whats the matter?

Best regards,
Andy

Tyler Mitchell:

You might notice strange failures while trying to upload the program to Arduino, if you have an active GPS plugged into digital pin 0. This is because that pin is also shared with the serial communications of the arduino board, which gets used when uploading new apps. Simply remove your GPS from the board while doing this and all should be well.

Post new comment

The content of this field is kept private and will not be shown publicly.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd>
  • Lines and paragraphs break automatically.

More information about formatting options

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.