-
-
Save ncoder-1/8313815ac387e6757f751dc8960f03d7 to your computer and use it in GitHub Desktop.
// Example C++17 gpsd program using libgpsmm | |
// Has no actual purpose other than output some of libgpsmm struct variables of your choosing. | |
// reference declarations: https://fossies.org/dox/gpsd-3.22/index.html | |
// | |
// compiles without warning as follows: | |
// g++ -std=c++17 -Wall -pedantic -pthread $(pkg-config --cflags --libs libgps) gpsd-example.cpp -o gpsd-example | |
// clang++ -std=c++17 -Wall -pedantic -pthread $(pkg-config --cflags --libs libgps) gpsd-example.cpp -o gpsd-example | |
// Free for the taking. | |
// Version 1.84 | |
#include <libgpsmm.h> | |
#include <ctime> | |
#include <iomanip> | |
#include <iostream> | |
#include <sstream> | |
#include <thread> | |
enum TimeFormat { LOCALTIME, UTC, UNIX, ISO_8601 }; | |
auto TimespecToTimeStr(const timespec& gpsd_time, TimeFormat time_format = LOCALTIME) { | |
// example showing different ways of formating GPSD's timespec, depending on requirement | |
std::ostringstream oss; | |
switch (time_format) { | |
case LOCALTIME: { | |
// convert timespec_t into localtime (dd-mm-YY HH:MM:SS) | |
const auto tm = *std::localtime(&gpsd_time.tv_sec); | |
oss << std::put_time(&tm, "%d-%m-%Y %H:%M:%S"); | |
break; | |
} | |
case UTC: { | |
// convert timespec_t into UTC (dd-mm-YY HH:MM:SS) | |
const auto tm = *std::gmtime(&gpsd_time.tv_sec); | |
oss << std::put_time(&tm, "%d-%m-%Y %H:%M:%S"); | |
break; | |
} | |
case UNIX: | |
// returns seconds since the Epoch | |
oss << gpsd_time.tv_sec; | |
break; | |
case ISO_8601: { | |
// convert timespec_t into ISO8601 UTC time (yyyy-MM-dd'T'HH:mm:ss'Z') | |
constexpr size_t kScrSize{128}; | |
std::array<char, kScrSize> scr{}; | |
timespec_to_iso8601(gpsd_time, scr.data(), kScrSize); | |
oss << scr.data(); | |
break; | |
} | |
} | |
return oss.str(); | |
} | |
auto main() -> int { | |
gpsmm gps_rec("localhost", DEFAULT_GPSD_PORT); | |
if (gps_rec.stream(WATCH_ENABLE | WATCH_JSON) == nullptr) { | |
std::cerr << "No GPSD running.\n"; | |
return 1; | |
} | |
constexpr auto kWaitingTime{1000000}; // 1000000 is 1 second | |
for (;;) { | |
if (!gps_rec.waiting(kWaitingTime)) { | |
continue; | |
} | |
struct gps_data_t* gpsd_data; | |
if ((gps_rec.read()) == nullptr) { | |
std::cerr << "GPSD read error.\n"; | |
return 1; | |
} | |
while (((gpsd_data = gps_rec.read()) == nullptr) || (gpsd_data->fix.mode < MODE_2D)) { | |
// Do nothing until fix, block execution for 1 second (busy wait mitigation) | |
std::this_thread::sleep_for(std::chrono::seconds(1)); | |
} | |
const auto latitude{gpsd_data->fix.latitude}; | |
const auto longitude{gpsd_data->fix.longitude}; | |
const auto hdop{gpsd_data->dop.hdop}; | |
const auto vdop{gpsd_data->dop.vdop}; | |
const auto pdop{gpsd_data->dop.pdop}; | |
const auto s_vis{gpsd_data->satellites_visible}; | |
const auto s_used{gpsd_data->satellites_used}; | |
const auto time_str{TimespecToTimeStr(gpsd_data->fix.time, ISO_8601)}; // you can change the 2nd argument to LOCALTIME, UTC, UNIX or ISO8601 | |
std::cout << std::setprecision(8) << std::fixed; // set output to fixed floating point, 8 decimal precision | |
std::cout << time_str << "," << latitude << "," << longitude << "," << hdop << "," << vdop << "," << pdop << "," << s_vis << "," << s_used << '\n'; | |
} | |
} |
added busy wait mitigation in loop and timespec formatting examples
Hi, yes it works great.
However, when the GPS is stationary and not moving the latitude and longitude can drift by over 20 meters in several minutes and over longer periods of time by even more. When the process is restarted it goes down to under 1 meter and then drifts again. This is consistent across all C/C++ releases from C++11-17. I tried to destruct and reconstruct the object at run-time - did not help. Only restarting the process does.
Does anyone know what the problem is and how to correct it?
Thanks
Hi @garyv100, I have a unit running right now, I'll have a look if I see the drift here.
Hi @ncoder-1, in addition to monitoring lat and long I also calculate the distance between the initial location and the current one - easier to see the drift.
@garyv100, just want to make sure though, the drift is getting further and further away from the real location or is it closing in on the real location over time? Currently here looking at it, after 15 minutes from a USB GPS (and a cold boot), it started around 50 meters off until it had about 8 or so satellites and now it's been dead on the right location and no drift.
@ncoder-1, the way I measure the drift is I take initial good gps location (usually 10 satellites or more and that is fast) and save it into variable and then monitor and calculate the distance between the initial location and all subsequent once as time goes by while keeping the receiver stationary, Within 15min I can see sometimes over 20 meter drift.
@garyv100, I've had a USB unit (u-blox driver) running for about 40 minutes and a raw UART (nmea driver) running for about 20 minutes and both aren't showing the drift (other than the normal cold boot drift which is quickly corrected as satellites are received). I suggest you post an issue here: https://gitlab.com/gpsd/gpsd/issues and the main gpsd dev (also named Gary) can maybe help if it's a driver issue with your hardware or within the gpsd code itself. I suggest you link this gist so he can get some context as well. Wish I could be of more help.
edit: are you seeing the same behavior with gpsd's cgps tool?
@ncoder-1, I am using VK-162 GPS Receiver Dongle Navigation Module USB Interface G-mouse Antenna DEN. I think this is the problem. Not the Linux drivers or software. Can you recommend a different receiver for Linux?
Thank you for your help.
Gary
@garyv100, I use a GR-8013 USB GPS (one of the rare USB ones that also have PPS) and also the ND-100S which both work well with gpsd.
@ncoder-1, I tried to lookup GR-8013 USB GPS, but I am coming up w/ all kind of stuff. If you could send me the link - it would be great.
Thanks,
Gary
@garyv100, they are quite rare now, but this is the one I have: https://www.globalsources.com/gsol/I/PC-PDA/p/sm/1147069913.htm#1147069913
@ncoder-1, Thank you!
updated to support gpsd 3.20 (which removed timestamp_t in favor of timespec_t) and updated for c++17.