Talkin’ GPS Blues (part 1).

A long time ago, my great and good friend Glen pointed me in the direction of a Steven Jay Gould essay about his encounter with Richard Feynman. Gould’s point in that essay was that he thought Feynman wasted a lot of time trying to understand evolution from the ground up, time that Feynman could have spent making valuable contributions to the theory instead. My response is that I think I understand where Feynman was coming from; the only way he felt like he could contribute something was to start from first principles and work his way forward until he understood each step. I’m not anywhere near as smart as Feynman or Gould, but I feel much the same way as Feynman did. Hence, the long and rambling nature of this entry.

I have six GPS systems. That’s probably more than any one sane person needs, but we can leave that discussion for another time.

One of them is an old Garmin GPS12, which I have a data cable and serial-USB interface for. Two of them are USB GPS systems picked up cheap for projects that didn’t work out (a DeLorme GPS LT20 and an AmbiCom GPS-USB). The other three are Bluetooth devices (an AmbiCom BT-GPS, a Nokia LD-3W, and an DeLorme EarthMate “BlueLogger GPS”). That doesn’t count the GPS built in to the EVO, and seeing if something can be done with that under LINUX is going to be another part of this project.

It seems like it would be an interesting project to figure out how to make the various GPS units talk to the computers, and to figure out how to get GPS data into programs. I have some goals that I’m working in the direction of, but for right now, the problem of extracting GPS data programatically is interesting enough. All of this is based on the Project e netbook, running (at the moment) Ubuntu 10.04 NetBook Remix. Your mileage may vary. Actual highway mileage will probably be less.

Logically, the first thing to do is plug everything up and make sure we have connectivity. With the two USB GPS devices, that turned out to be much easier than I expected. First thing to do is plug them in. Second thing to do is run the LINUX dmesg command: the dmesg command prints kernal messages from the LINUX kernal to LINUX’s “standard output”. In this case, we’re using it to see what kind of messages we get when we plug in the GPS devices to our USB ports. If we type dmesg at a command prompt, we get back a bunch of stuff: I’ve deleted all but the last set of entries, which show what happens when we plug in the USB GPS:

[ 1056.748126] usb 4-1: new full speed USB device using uhci_hcd and address 2
[ 1056.910431] usb 4-1: configuration #1 chosen from 1 choice
[ 1056.997808] usbcore: registered new interface driver usbserial
[ 1056.998316] USB Serial support registered for generic
[ 1056.998612] usbcore: registered new interface driver usbserial_generic
[ 1056.998620] usbserial: USB Serial Driver core
[ 1057.009236] USB Serial support registered for pl2303
[ 1057.010006] pl2303 4-1:1.0: pl2303 converter detected
[ 1057.021576] usb 4-1: pl2303 converter now attached to ttyUSB0
[ 1057.021631] usbcore: registered new interface driver pl2303
[ 1057.021638] pl2303: Prolific PL2303 USB to serial adaptor driver

This is the dmesg output for the Ambicom GPS. For the DeLorme Earthmate LT-20 we get something similar:

[ 1247.780066] usb 4-1: new low speed USB device using uhci_hcd and address 3
[ 1247.963400] usb 4-1: configuration #1 chosen from 1 choice
[ 1248.022891] USB Serial support registered for DeLorme Earthmate USB
[ 1248.023514] USB Serial support registered for HID->COM RS232 Adapter
[ 1248.027524] USB Serial support registered for Nokia CA-42 V2 Adapter
[ 1248.029441] cypress 4-1:1.0: DeLorme Earthmate USB converter detected
[ 1248.201647] usb 4-1: DeLorme Earthmate USB converter now attached to ttyUSB0
[ 1248.201718] usbcore: registered new interface driver cypress
[ 1248.201726] cypress_m8: v1.09:Cypress USB to Serial Driver
[ 1248.282583] usbcore: registered new interface driver hiddev
[ 1248.284654] usbcore: registered new interface driver usbhid
[ 1248.286536] usbhid: v2.6:USB HID core driver

(In principle, we’d probably get a very similar set of messages if we connected the Garmin using the RS-232 interface cable and a RS-232/USB converter, such as the KeySpan. But that’s a little out of the scope of what I’m interested in doing right now.)

So we know we’ve got hardware connectivity, which is a good first sign, right? How do we talk to the devices?

I’m partial to the GPSD project. It provides a pretty simple interface; GPSD handles speaking to the hardware (whatever that hardware may be), and all you have to do is open a socket to port 2947 (or whatever port you’re using as the GPSD port). GPSD also provides the data in an easy to read and parse format. Also, GPSD is, as I understand it, what the Nokia N810/N810 use internally to provide location information to applications. Since code portability to the N8XX is a goal, it seems like a good idea to stick with it. (I have also seen allegations that Nokia’s GPSD implementation is broken, but I don’t have any details on that.)

Looking at the dmesg output, it looks like the GPS devices are showing up on dev/ttyUSB0. So we ought to be able to start up gpsd with

gpsd /dev/ttyUSB0

and get something useful.  How will we know if we’re getting something useful? Just typing that at a command prompt starts gpsd and returns us to the shell. Well, the gpsd distribution includes some useful utility programs. gpspipe connects to gpsd and pipes the received data to standard output. xgps actually displays the GPS information, including the satellites, in a X window. We can also just telnet to the gpsd port and issue commands to gpsd from there. So let us experiment. Type

gpsd /dev/ttyUSB0 -N -D2

at a command prompt. (The -N switch tells GPSD to stay running in the foreground, rather than going into the background and returning to a command prompt. The -D2 switch puts GPSD into a verbose debugging mode, where it sends messages to the screen telling us what’s going on. This is useful for getting things working, though not needed; GPSD should work just fine without those two switches.)

(Two side notes here. One is that I ended up having to reinstall gpsd and the gpsd-client packages (which I’ll talk about in a moment) as they don’t appear to be installed by default under Ubuntu. That’s just a fairly simple apt-get install gpsd and apt-get install gpsd-clients.) Two is that it appears once gpsd is installed, it starts automatically when a recognized GPS device is plugged in, at least on my system. I haven’t figured that out yet.)

Anyway, I’m using the Ambicom GPS for this example; for some reason, that hardware seems to work better than the Earthmate. Typing the gpsd command at a prompt gives us this output:

gpsd: launching (Version 2.92)
gpsd: listening on port gpsd
gpsd: running with effective group ID 1000
gpsd: running with effective user ID 1000
gpsd: stashing device /dev/ttyUSB0 at slot 0

How do we know we’re getting anything useful out of the GPS? Remember I referred to a gpsd-client pacakage above? The gpsd-client package contains a couple of test utilities. For example, there’s one called xgps, which displays GPS information obtained from gpsd in a graphical format. We can open a new command prompt and type

xgps

and get something like this:

(Click for larger version. Two notes on xgps and the illustration. Note one: xgps is set up for something like a 1024 x 768 screen. Since the netbook only has a 1024 x 600 display, the bottom of the xgps display is cut off, and I haven’t figured out how to resolve that issue. Note two: in this and the other screen snapshots, I’ve blurred out information that would tend to pinpoint my place of residence, for privacy reasons.)

When we do that, gpsd (assuming we’re running it in the foreground with debugging on) shows us this:

gpsd: client ::1 (0) connect on fd 6
gpsd: client(0): attaching channel 0 (type ANY)
gpsd: opening GPS data source at '/dev/ttyUSB0'
gpsd: speed 57600, 8N1
gpsd: garmin_gps Linux USB module not active.
gpsd: speed 9600, 8O1
gpsd: speed 57600, 8N1
gpsd: gpsd_activate(): opened GPS (fd 7)
gpsd: speed 4800, 8N1
gpsd: NTPD ntpd_link_activate: 0
gpsd: client(0): reusing channel 0 (type ANY), forced device true

This is a guess on my part, but what I’m thinking is that gpsd doesn’t actually start talking to the GPS hardware unless some program starts requesting data through gpsd; then gpsd opens up a communications path and starts polling for data.

There’s also another program called cgps, which works like xgps, but uses a terminal based interface:

(Click to embiggen. The stuff at the bottom is the data that cpgs is getting from gpsd. Again, I’ve obscured the full lat/long coordinates for privacy.)

“Ah,” I hear you asking. “But I don’t want wires. Wires are cumbersome. What of Bluetooth?” What of Bluetooth, indeed.

Step 1 is to pair your GPS device with your system running gpsd, if you haven’t already. There’s probably a command line way to do that, but I’m having trouble finding documentation at the moment. Because I’m lazy and not very bright, I just did the pairing from within the Ubuntu GUI. (Click on the Bluetooth icon at the top of the screen, select “Set up new device…” and step through the wizard. You’ll probably have to tell Ubuntu to use a fixed PIN, like 0000 or 1111, under “PIN Options” on the “Device Search” screen.)

Once you have the device paired, what next? There’s a dated, but seemingly still valid set of instructions on the Ubuntu forums here. It appears that what you want to do is make sure the GPS is powered on. Then picking up with step 2, run

hcitool scan

which will search for active Bluetooth devices and return their MAC address. Something like this:

dwight@Project-e:~$ hcitool scan
Scanning ...
00:17:F2:A7:78:21    Dwight Brown’s MacBook (6)
00:12:0E:A0:C9:4B    AmbiCom_BT_GPS

Next, the instructions say to run

sdptool browse <MAC address of the GPS device>

I’m not 100% clear on what sdptool does; it appears to return information about the services supported by the Bluetooth device, and what “channels” the services are supported on. The man page is so clear a four year old child could understand it. I’m in luck, since I have ready access to a four year old child….

dwight@Project-e:~$ sdptool browse 00:12:0E:A0:C9:4B
Browsing 00:12:0E:A0:C9:4B ...
dwight@Project-e:~$

Awesome. Could it just be an issue with the AmbiCom device? Maybe. When I run sdptool browse with the MAC address of the Mac, it returns:


dwight@Project-e:~$ sdptool browse 00:17:F2:A7:78:21
Browsing 00:17:F2:A7:78:21 ...
Service Name: OBEX Object Push
Service RecHandle: 0x10002
Service Class ID List:
"OBEX Object Push" (0x1105)
Protocol Descriptor List:
"L2CAP" (0x00000100)
"RFCOMM" (0x0003)
Channel: 10
"OBEX" (0x0008)
Language Base Attr List:
code_ISO639: 0x656e
encoding: 0x6a
base_offset: 0x100
Profile Descriptor List:
"OBEX Object Push" (0x1105)
Version: 0x0100

Service Name: OBEX File Transfer
Service RecHandle: 0x10003
Service Class ID List:
"OBEX File Transfer" (0x1106)
Protocol Descriptor List:
"L2CAP" (0x00000100)
"RFCOMM" (0x0003)
Channel: 15
"OBEX" (0x0008)
Language Base Attr List:
code_ISO639: 0x656e
encoding: 0x6a
base_offset: 0x100
Profile Descriptor List:
"OBEX File Transfer" (0x1106)
Version: 0x0100

Service Name: Bluetooth Audio Gateway
Service RecHandle: 0x10001
Service Class ID List:
"Headset Audio Gateway" (0x1112)
"Generic Audio" (0x1203)
Protocol Descriptor List:
"L2CAP" (0x0100)
"RFCOMM" (0x0003)
Channel: 1
Language Base Attr List:
code_ISO639: 0x656e
encoding: 0x6a
base_offset: 0x100
Profile Descriptor List:
"Dialup Networking" (0x1103)
Version: 0x1108

Service Name: Bluetooth-PDA-Sync
Service RecHandle: 0x10004
Service Class ID List:
"Serial Port" (0x1101)
Protocol Descriptor List:
"L2CAP" (0x0100)
"RFCOMM" (0x0003)
Channel: 3
Language Base Attr List:
code_ISO639: 0x656e
encoding: 0x6a
base_offset: 0x100
Profile Descriptor List:
"Serial Port" (0x1101)
Version: 0x0100

Service Name: AVRCP Target
Service RecHandle: 0x10005
Service Class ID List:
"AV Remote Target" (0x110c)
Protocol Descriptor List:
"L2CAP" (0x0100)
PSM: 23
"AVCTP" (0x0017)
uint16: 0x100
Profile Descriptor List:
"AV Remote" (0x110e)
Version: 0x0103

dwight@Project-e:~$

So it could just be an issue with the AmbiCom device and sdptool. Just for grins, let’s assume that the AmbiCom uses channel 1 for communications; that seems standard on GPS devices. So we’ll issue a command that I got from this website:


rfcomm bind /dev/rfcomm0 [MAC address of the GPS device] [channel]

rfcomm, according to the manual page, is “used to set up, maintain, and inspect the RFCOMM configuration of the Bluetooth subsystem in the Linux kernel”. So if I understand what this command is doing correctly, it sets up a new device, /dev/rfcomm0, and binds it to the proper channel on the Bluetooth GPS, thus establishing communication with the device.

dwight@Project-e:~$ rfcomm bind /dev/rfcomm0 00:12:0E:A0:C9:4B 1
Can't create device: Operation not permitted
dwight@Project-e:~$ sudo rfcomm bind /dev/rfcomm0 00:12:0E:A0:C9:4B 1
[sudo] password for dwight:
dwight@Project-e:~$

Yeah, so it kind of looks like rfcomm wants to be running as root to do that. What now? How do we know it works? Well, one simple way is just to cat /dev/rfcomm0:


dwight@Project-e:~$ cat /dev/rfcomm0
$PSGSA,1,,,,,,,,,,,,,,,,00000,,0*4B
W,2,09,0.9,247.4,M,-22.5,M,1.8,0000*41
$GPGSA,A,3,22,32,12,30,24,14,25,11,31,,,,1.5,0.9,1.2*3B
$GPRMC,012105.000,A,30XX.XXXX,N,097XX.XXXX,W,0.08,60.91,100111,,,D*49
$GPGGA,012106.000,30XX.XXXX,N,097X.XXXX,W,2,09,0.9,247.4,M,-22.5,M,0.8,0000*43
...
^C
dwight@Project-e:~$

Looks like we’re getting something there. How about we fire up gpsd and xgps?


dwight@Project-e:~$ gpsd /dev/rfcomm0 -N -D2
gpsd: launching (Version 2.92)
gpsd: listening on port gpsd
gpsd: running with effective group ID 1000
gpsd: running with effective user ID 1000
gpsd: stashing device /dev/rfcomm0 at slot 0
gpsd: client ::1 (0) connect on fd 6
gpsd: client(0): attaching channel 0 (type ANY)
gpsd: opening GPS data source at '/dev/rfcomm0'
gpsd: speed 57600, 8N1
gpsd: garmin_gps Linux USB module not active.
gpsd: speed 9600, 8O1
gpsd: speed 57600, 8N1
gpsd: gpsd_activate(): opened GPS (fd 7)
gpsd: NTPD ntpd_link_activate: 0
gpsd: => Probing device subtype 0
gpsd: can't use GGA time until after ZDA or RMC has supplied a year.
gpsd: client(0): reusing channel 0 (type ANY), forced device true
gpsd: => Probing device subtype 1
gpsd: => Probing device subtype 2
gpsd: => Probing device subtype 3
gpsd: => Probing device subtype 4
gpsd: => Probing device subtype 5
gpsd: => Probing device subtype 6
gpsd: SiRF binary packet seen when NMEA expected.
gpsd: NTPD ntpd_link_activate: 1
gpsd: client(0): reusing channel 0 (type ANY), forced device true
gpsd: NTPD ntpd_link_activate: 1
gpsd: client(0): reusing channel 0 (type ANY), forced device true
gpsd: SiRF binary packet seen when NMEA expected.
gpsd: NTPD ntpd_link_activate: 1
gpsd: client(0): reusing channel 0 (type ANY), forced device true
gpsd: NTPD ntpd_link_activate: 1
gpsd: client(0): reusing channel 0 (type ANY), forced device true
gpsd: SiRF binary packet seen when NMEA expected.
gpsd: NTPD ntpd_link_activate: 1
gpsd: client(0): reusing channel 0 (type ANY), forced device true

And xgps?

What about cgps? Anything interesting out of that?

So we’ve got GPS communication, over wires and over wireless. One thing I can’t explain is the huge difference in estimated horizontal and vertical error between the wired and Bluetooth GPS systems. I had both of them in the same position (well, within inches of the same position, one that provided a view of the GPS satellite constellation), so I can only figure it was something going on relative to the hardware on each of the AmbiCom units. This is worth additional investigation.

In part 2, I want to start using scripts in Perl and Python (and possibly Java) to start pulling GPS data out of gpsd and to do something useful with it. In the meantime, I welcome comments from anyone who’s familiar with the mysteries of gpsd, GPS hardware, Bluetooth devices under LINUX, or any of the other things I’ve covered. I also welcome comments from anyone who thinks I’m full of it.

4 Responses to “Talkin’ GPS Blues (part 1).”

  1. Joe D says:

    Here’s another approach.

    http://www.instructables.com/id/Weekly-Project%3a-Noggin-Logger–A-Wearable-GPS-Data/

    It’s a small GPS unit that saves the data to a SD card, for later munging and analysis. I keep thinking I’ll get one of those for my bike rides.

  2. stainles says:

    Joe:

    That’s very interesting. I especially like the fact that it saves the data to SD cards.

    Unfortunately, the link to SparkFun’s website doesn’t work, and I haven’t had a chance to check and see if they just moved the device elsewhere, or aren’t selling it any longer.

    The EarthMate BlueLogger GPS I mentioned is reasonably small (it’d fit into the back pocket of a cycling jersey), also apparently has some level of logging capability, and you can get that for $39 at Discount Electronics. I say “apparently” because I haven’t played much with the logging feature; it appears you need to run the special Windows software that comes with the unit to set up logging. If there’s a way to set up the logging feature under OS X or LINUX, I haven’t found it yet.

    I may try installing it under Parallels on the Mac, enabling the logging, and going out for a ride next weekend, if the weather’s nice. I need to get my butt back on the bike…

  3. Joe D says:

    Ack, I hadn’t realized they’d discontinued that. I just grabbed my bookmark.

    There is another one on Sparkfun: http://www.sparkfun.com/products/8823

    But for $150, I’m thinking I could find something pre-built for a lot cheaper.

  4. stainles says:

    Yeah, for $150, I’m thinking I could probably put something together in much the same form factor with an Ardunio and an off-the-shelf GPS module. Heck, Fry’s has Basic Stamp microcontrollers and a GPS module for those that would probably work as well. The only problem I can see is the ability to write to the SD card, and I’m pretty sure there’s hardware add-ons for that.