Beefy Boxes and Bandwidth Generously Provided by pair Networks
Your skill will accomplish
what the force of many cannot

GPS tracking with Perl

by stevieb (Canon)
on May 17, 2017 at 00:56 UTC ( #1190414=CUFP: print w/replies, xml ) Need Help??

I finally got my little GPS unit for my Raspberry Pi, which cost me $50 CDN. It connects via the Rx and Tx pins of the serial interface. My new GPSD::Parse module (may not have indexed yet) is not Pi specific though. Any serial connected GPS device will work (even USB ones).

There aren't any non-core modules in use so it's exceptionally lightweight. The only requirement is to have gpsd daemon installed and running. I run it like this: sudo gpsd /dev/ttyS0 -n -F /var/log/gpsd.sock at startup.

Note that there is a much more extensive distribution Net::GPSD3 that does the same sort of thing, but I had a nightmare trying to install it with a whole long chain of dependencies, and it was a little confusing to use. I wrote this one for simplicity. All tests effectively skip until the next version, when I re-implement a test regime that uses a data file as the input instead of a network socket, which most may not have running. I also have immediate plans for new features, but I just wanted to get it up after 100% test coverage (locally) and 100% POD coverage so that I can see what it looks like on the CPAN.

I've put together a tiny demo of some basic output below, but the information that can be extracted is quite extensive. The documentation explains all of the various attributes and how to get at them. It even shows how to extract the entire raw JSON data returned from the device, or that raw data after it's been converted into a Perl data structure.

Tiny example. Of course in the real world, you'd put something like this in a loop, polling every second or whatever. Note that I've obfuscated the coordinates a tiny bit, but they are accurate right to my front door, literally:

use warnings; use strict; use GPSD::Parse; my $gps = GPSD::Parse->new; $gps->poll; print "poll time: " . $gps->time . "\nlattitude: " . $gps->tpv('lat') . "\nlongitude: " . $gps->tpv('lon') . "\ndirection: " . $gps->tpv('track') . "\naltitude: " . $gps->tpv('alt') . "\n";

I've also got this working in C on my Arduino Trinket Pro, which I'm going to use to make a hiking GPS so I can track my movements in the field.

Here's the output. The altitude defaults to metres.

poll time: 2017-05-17T00:48:16.000Z lattitude: 51.00000000 longitude: -114.000000000 direction: 324.87 altitude: 1084.9

Here's a list of items you can fetch in regards to the TPV (Time Position Velocity):

time => '2017-05-16T22:29:29.000Z' # date/time in UTC lon => '-114.000000000' # longitude lat => '51.000000' # latitude alt => '1084.9' # altitude (metres) climb => '0' # rate of ascent/decent (metres/sec) speed => '0' # rate of movement (metres/sec) track => '279.85' # heading (degrees from true north) device => '/dev/ttyS0' # GPS serial interface mode => 3 # NMEA mode epx => '3.636' # longitude error estimate (metres) epy => '4.676' # latitude error estimate (metres) epc => '8.16' # ascent/decent error estimate (meters) ept => '0.005' # timestamp error (sec) epv => '4.082' # altitude error estimate (meters) eps => '9.35' # speed error estimate (metres/sec) class => 'TPV' # data type (fixed as TPV) tag => 'ZDA' # identifier

...and information you can gather about the satellites you can see (using the satellites() method). Currently, after having the unit on for about 24 hours, I'm 'using' nine in total to pinpoint me:

PRN => 16 # PRN ID of the satellite # 1-63 are GNSS satellites # 64-96 are GLONASS satellites # 100-164 are SBAS satellites ss => 20 # signal strength (dB) az => 161 # azimuth (degrees from true north) used => 1 # currently being used in calculations el => 88 # elevation in degrees

Replies are listed 'Best First'.
Re: GPS tracking with Perl
by jmlynesjr (Deacon) on May 17, 2017 at 19:19 UTC

    Very nice, as usual!

    Is there a minimum number of birds for lock? Is this checked and reported?

    Aside: Check out the Amateur Packet Reporting System(APRS).


    There's never enough time to do it right, but always enough time to do it over...

      Very nice, as usual!

      Thanks, as usual! :)

      Is there a minimum number of birds for lock? Is this checked and reported?

      Minimum is have signal and locked to at least three birds for proper triangulation (at least with this unit). Even at three, I sometimes get sporadic values (very low values mind you) for speed and climb, even if I'm still. As soon as I'm locked onto four or more with this particular GPS unit, everything stabilizes and as I said, it's accurate across the board, from location (pinpoints my front door), elevation (I'm acutely aware of elevation in my area, plus I have other equipment that lines up perfectly.

      Aside: Check out the Amateur Packet Reporting System(APRS).

      Looks very interesting at a cursory look. Will definitely read more when I get home!

      ps. I just did a sweeping update today to add further features... metric/imperial for measurements, signed/unsigned option for lat/lon (ie. -114.xxxxxx to 114.xxxxxW), full testing without needing gpsd installed, direction() to convert the decimal heading into direction (NNE, SW etc), and updates to the docs. (v0.02, should be indexed shortly).

        fyi, although it can be done more cleanly (both code and output), I flip off my GPS and back on again, and within three seconds (literally), I achieve lock on four sats:

        use warnings; use strict; use GPSD::Parse; my $gps = GPSD::Parse->new; $gps->poll; my $sats = $gps->satellites; for my $sat (keys %$sats){ if (! $gps->satellites($sat, 'used')){ print "$sat: unused\n"; } else { print "$sat used:\n"; for (keys %{ $sats->{$sat} }){ print "\t$_: $sats->{$sat}{$_}\n"; } } }


        17: used az: 67 el: 74 used: 1 ss: 15 3: unused 11: unused 19: unused 22: unused 24: unused 28: used az: 99 ss: 14 el: 36 used: 1 30: unused 13: used el: 6 used: 1 ss: 13 az: 220 12: unused 6: used az: 165 used: 1 el: 30 ss: 23 15: unused 1: unused

        I have 100% test coverage between the cases that I'm using a socket (actual GPS), or replaying with a saved output file. I've got the docs in order, and have added a couple of examples. Usually it takes me a bit more time for a v1.00 release, but this was a very quick turnaround and I'm very happy with the results. I've tested the code on four machines; two Pi's one with a GPS, the other without, and same with two laptops (one with, one without). I'm just cleaning things up, and then I'm ready to move on to the video camera project. After that, I may consider actually constructing something.

Log In?

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: CUFP [id://1190414]
Approved by Athanasius
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others musing on the Monastery: (8)
As of 2022-01-18 14:02 GMT
Find Nodes?
    Voting Booth?
    In 2022, my preferred method to securely store passwords is:

    Results (53 votes). Check out past polls.