|
GPS Code |
2008-06-25 |
|
As promised, here is source code for reading GPS data from the Streets and Trips USB GPS on OS X. This is the most C code I have written in a while, so don't go putting it into production! Here's how it works: nmea.h/.c - Structs representing nmea data, and code for reading data from the serial port, and parsing this out of a comma separated string. I have restricted myself to only parsing bits of the gga sentence, but it would be straightforward to extend this to other data and sentences. serial.h/.c - Code for opening and closing the serial port. main.c - A small main method that reads the nmea data and prints the lat, long and altitude to the console. If you want to try it out, don't forget to install the serial port driver as described in my previous post. Have fun with it! Tags:
programming |
|
|
GPS on Leopard |
2008-06-09 |
|
A while back I bought Microsoft Streets and Trips 2007 from the company store, and got a nice, small USB GPS with it. I messed around programming the GPS on Windows (post) and hooked it into my blog, but then I moved over to a Mac running Leopard as my daily machine and lost my neat GPS recording capability. No more! On Sunday I hacked together some code to pull data from the GPS on OS X.
I found a few posts from people trying to do the same thing, so I am going to outline the steps involved now, and show some code in a later post. 1. USB to Serial - The GPS device uses the RS232 serial standard over USB. This won't appear as a serial device without the right driver, so download the BF-810 USB to Serial adapter from here and install it. 2. Vendor and Product ID - The driver installed in step 1 needs some tweaks before it will work, and to make those tweaks you need to know two numbers: The vendor and product IDs. Plug in the GPS and fire up IORegistryExplorer, and then look under IOUSB group (command-6) for the GPS. It will be the entry with USB Vendor Name = Prolific Technology Inc. If you are lazy like me you can also find it by yanking the GPS out of the machine and watching it go red in the explorer. Note that the values here are in hex, so it is a great opportunity to dust off your hex to decimal skills. 3. Edit kext - Plug the vendor and product IDs for your device into the kernel extension Info.plist file /System/Library/Extensions/ProlificUsbSerial.kext/Contents/Info.plist. This is just a plain old xml file, so sudo fire up your editor of choice and replace whatever values are there under idProduct and idVendor with your own. 4. Reload kext - With our product and vendor IDs in place, it is now time to reload the driver. First up, run "sudo kextunload -b com.prolific.driver.PL2303". It is ok if this unload command fails. Now run "sudo kextload -b com.prolific.driver.PL2303". Provided the device is plugged in, you should now be able to see a device file called cu.usbserial in the /dev directory on your file system (ls /dev/cu*). 5. Time to code - Apple has a useful serial programming in C tutorial here. The demo accesses a modem, but the code only needs a few tweaks to pull NMEA data off the GPS. I started by stealing swathes of the demo and hacking on them to re-target it at the GPS. The important changes are: 5.1 Discovery - There is no need to discover the device dynamically, just hard code the device path and get rid of a couple of hundred lines of code right away: char* gpsPath = "/dev/cu.usbserial"; fileDescriptor = OpenSerialPort(gpsPath); 5.2 Config - The device is configured using the termios structure, and you'll need this to get the baud, parity, stop bits and word size right: cfsetspeed(&options, B4800); options.c_cflag &= ~PARENB; options.c_cflag &= ~CSTOPB; options.c_cflag &= ~CSIZE; options.c_cflag |= CS8; 5.3 Reading data and NMEA parsing - Data isn't read back from the device in a predictable sequence, so you will need to scan the input as it is read and work out when the sequence starts. Luckily the NMEA data structure is simple to parse: every line starts with a $, holds some comma separated values, and ends with a checksum. Parse away! Tags:
programming |
|
|
KML |
2008-03-12 |
|
I have done a little GPS hacking in the last year and am part-time interested in location, so as part of my Ruby blog re-write I implemented a KML feed. This lets me tag my blog posts with location coordinates. If this excites you then read on! If you aren't sure if you should be excited or not, then reading this introduction to KML will help you decide. You can see my feed here here. Now check out this map overlay here. Sweet! Here are my three step guide to rolling your own KML feed in Rails. I did this as part of my own blogging software, but these steps are generally applicable. First up, get some location data. I did this by putting an extra string field onto my blog entry. Then fill this field with data of the format "{longitude}, {latitude}". Next, write some view code to spit out data as KML. My .rhtml looks like this: <?xml version="1.0" encoding="UTF-8"?> <kml xmlns="http://earth.google.com/kml/2.1"> <Document> <% for thing in @things if thing and thing.location and thing.location.length > 0 then %> <Placemark> <name><%=thing.title -%></name> <description> <![CDATA[ <%= thing.content%> ]]> </description> <Point> <coordinates> <%= thing.location -%> </coordinates> </Point> </Placemark> <% end end %> </Document> </kml> Lastly, set the HTTP content type header like so: response.headers["type"] = "application/vnd.google-earth.kml-xml" Easy! Tags:
programming |
|
|
Rails 2 |
2007-12-05 |
|
I started playing around with Ruby on Rails in late June. I know this because I recorded the date June 30th at the top of my notes titled "Ruby stuff". The "Ruby stuff" page contains the following:
Starting the web server:
ruby script/server
Creating a new controller:
ruby script/generate controller controller_name
To run ruby in console mode, run
ruby script/console {production|development}
Development is the default if no argument is offered
That's it. I like taking notes when I use some new language or technology so I can come back months later and work out how the heck I ever got whatever-ing to work. In this case, I stopped taking notes after starting console mode. So Ruby on Rails is very easy to program: script/generate creates files ready to be filled up with Ruby; MVC is baked in and the M bit is automated down to the database; Rails provides convenient methods for accessing the model called finders that let me create a type Thing with a name property and then call Thing.find_by_name(…) . And because this is just recreational programming I don't care about perf, I don't even need to know the database is there, or what that dynamic method cost me. So I went off and wrote some new blog software, and even put in some new features: tags, multiple users, a kml feed (which I will post about later), and an RSS migrator. This was precipitated, btw, by Dominic quitting his .Net hosting. Back to my notes. The next page is title "Setting up rails app on dreamhost". There is no actual blood, sweat or tear stains on this page, but only because I wiped the monitor down. The page contains the following: set up the rails app with the command "rails directoryname" sync the app from svn change the home directory to /public, wait 10 mins stand on one foot edit the fcgi file kill any dispatch.fcgi processes stand on the other foot put the app into production by editing the config file kill any dispatch.fcgi processes … OK so it wasn't quite like that. But it was close. And it took a long time. Apparently Dominic has capistrano deployments working. I guess I need to look into those! Tags:
programming |
|
|
Webcam |
2007-05-30 |
|
I bought a cheap web cam at the supermarket on the weekend. After plugging it in I wondered how hard it would be to program. Particularly, I wondered if I could programmatically take pictures with the web cam and send the pictures up to my weblog along with the GPS information that already goes there. I figure so long as I have a database of everywhere I have been, I may as well have a database of what those places look like. And it was a long weekend, and it seemed like a good project for a long weekend... The easiest way I found to automatically capture images on Windows is to use the API in avicap.dll. capGetDriverDescriptionA lets me enumerate attached devices and return a device name, which I can then pass to capCreateCaptureWindowA to creates a capture window, which I can then hook up to the web camera using a series of windows messages (sample code here and here. Not elegant (why do I need to create a window to capture some video?), but it works.
That's the view from my couch, btw. For the moment I'm storing these in a DB via a SOAP service, but I wonder if there is a nice GPS + photos + google maps mashup in the offing... Tags:
programming |
|
|
Location |
2007-05-07 |
|
A while back I posted details of a little GPS program I built. The program is a Windows service that periodically takes my location (altitude, latitude and longitude) from a USB GPS device, and next time I am online reverse geo-codes the location and posts the result to my weblog via a web service. After a while I noticed the location information was a little bit off. My initial reaction was that some sort of conspiracy was afoot, since Microsoft Street and Trips was getting the location perfectly well. Of course, it turned out to be user error. The NMEA data coming out of the device looks like this: $GPRMC,215238.000,A,4737.2885,N,12219.4668,W,0.19,350.69,270107,,,A*74 I had taken this to be 47.37 etc degrees. It is actually 47 degrees and 37.2885 minutes. Solved! Tags:
programming |
|
|
GPS |
2007-01-28 |
|
Last week, in a bout of gadget lust, I bought Streets & Trips 2007, which includes a little USB GPS locator.
Not long after plugging it in I started to wonder if it was possible to pull GPS data directly off the device myself (rather than using Street and Trips), and so a hacking project was born. I decided to get my GPS location, somehow reverse geo-code it and publish my location to my weblog using a web service. Since my GPS device will only sometimes be plugged in, I decided to write a service that would pull my GPS location every few minutes and save it to disk. Likewise since my laptop will not always be connected to the internet, the same service would periodically try the geo-coding and publishing steps. Getting data from the device was remarkably simple. A few internet searches revealed that GPS devices use the NMEA protocol, and that the device can be treated as a serial port, allowing me to start pulling data with a few lines of C# code like this:
The NMEA data that is read into the buffer is an asci-encoded string formatted like so:
55
$GPGSA,A,3,16,07,06,21,10,18,,,,,,,2.4,1.3,2.0*39
$GPRMC,215238.000,A,4737.2885,N,12219.4668,W,0.19,350.69,270107,,,A*74
$GPGGA,215239.000,4737.2884,N,12219.4668,W,1,06,1.3,95.1,M,-17.3,M,,0000*55
$GPGSA,A,3,16,07,06,21,10,18,,,,,,,2.4,1.3,2.0*39
$
The GPRMC and GPGGA sections both contain latitude (47.37 N) and longitude (122.19 W), and the GPGGA also has altitude (95.1 M). Rather than worry about parsing this myself, I purloined some NMEA parsing code from this excellent sample by Scott Hanselman on MSDN's Coding4Fun. With my coordinates retrieved, my attention now turned to reverse geo-coding them to find a place name. I had hoped that local.live.com would have an API, but I settled for the REST service provided by www.geonames.org. It accepts latitude and longitude as part of a HTTP get request like http://ws.geonames.org/findNearbyPlaceName?lat=47.3&lng=9, and returns location data as XML:
Now with coordinates and a place name, all that remained was to push this up to a SOAP service on my own blog that saves the location and time to a local database, and then add the most recent entry to the sidebar of my blog. And now you know where I am. Tags:
programming |
|