GPS logger raspberry

 

Pin assignment

NEO-M8N  GPS Module with Shell

NEO-M8N GPS Module

このgpsはcompass HMC5883も内蔵され、I2Cで計測できる。

HMC5883も2種類ありaddressが0x1Eと0x0Dがあるが、これは0x1E版である。

先日購入した単体のHMC5883は5個とも0x0Dであった、以前のプログラムが5個とも全く動かないので、焦ったが0x0D版は改良されている模様だ。

Python code (gpsLogger.py)

#! /usr/bin/python
# Written by Dan Mandle http://dan.mandle.me September 2012 License: GPL 2.0
 
import os
from gps import *
from time import *
import time
import threading
 
gpsd = None #seting the global variable
 
os.system('clear') #clear the terminal (optional)
 
class GpsPoller(threading.Thread):
 def __init__(self):
 threading.Thread.__init__(self)
 global gpsd #bring it in scope
 gpsd = gps(mode=WATCH_ENABLE) #starting the stream of info
 self.current_value = None
 self.running = True #setting the thread running to true
 
 def run(self):
 global gpsd
 while gpsp.running:
 gpsd.next() #this will continue to loop and grab EACH set of gpsd info to clear the buffer
 
if __name__ == '__main__':
 gpsp = GpsPoller() # create the thread
 try:
 gpsp.start() # start it up
 while True:
 #It may take a second or two to get good data print gpsd.fix.latitude,', ',gpsd.fix.longitude,' Time: ',gpsd.utc
 
 os.system('clear')
 
 print
 print ' GPS reading'
 print '----------------------------------------'
 print 'latitude ' , gpsd.fix.latitude
 print 'longitude ' , gpsd.fix.longitude
 print 'time utc ' , gpsd.utc,' + ', gpsd.fix.time
 print 'altitude (m)' , gpsd.fix.altitude
 print 'eps ' , gpsd.fix.eps
 print 'epx ' , gpsd.fix.epx
 print 'epv ' , gpsd.fix.epv
 print 'ept ' , gpsd.fix.ept
 print 'speed (m/s) ' , gpsd.fix.speed
 print 'climb ' , gpsd.fix.climb
 print 'track ' , gpsd.fix.track
 print 'mode ' , gpsd.fix.mode
 print
 print 'sats ' , gpsd.satellites
 
 f = open('GpsLog.csv','a')
 f.write(str(gpsd.fix.time ) + "," + str(gpsd.fix.latitude) + "," + str(gpsd.fix.longitude) + "\n")
 f.close() 
 time.sleep(5) #set to whatever
 
 except (KeyboardInterrupt, SystemExit): #when you press ctrl+c
 print "\nKilling Thread..."
 gpsp.running = False
 gpsp.join() # wait for the thread to finish what it's doing
 print "Done.\nExiting."

 

startup設定

crontab -e
@reboot /home/pi/start.sh

sudo chmod +x start.sh
#!/bin/sh
echo "start gps logger"
python /home/pi/gpsLogger.py

 

serial設定

  1. sudo raspi-config でserialをenableにする2
  2. sudo nano /boot/config.txt
  3. # 末尾にこの行を追記
    dtoverlay=pi3-miniuart-bt
  4. sudo reboot

 

serial設定の確認

sudo apt-get install minicom

sudo minicom -D /dev/ttyAMA0 -b9600

sudo cat /dev/ttyAMA0
ここまででgps serial受信出来ればOK

 

 

GPS tools のinstall

sudo apt-get install gpsd gpsd-clients
gpsd /dev/ttyAMA0
sudo nano /etc/default/gpsd
以下の2行を追加します。

GPSD_OPTIONS="/dev/ttyAMA0"
DEVICES="/dev/ttyAMA0"

xgps

cgps -s

gsp ログデータを地図上に表示する。

sudo apt-get install gpsprune

gpsprune

 

駐車場で実測

 

specでは2mとなっているが、ここでは予想外に正確であった。十分に2mは満足させている、所によっては数10cmもある。

測定方法:駐車場の外周を回った後、内側の白線に沿って1周した。

GPS logger for raspberry pi
GPS logger for raspberry pi

 

同じ駐車場をarduinoのTinyGPS++ で実測

赤は計測値、黄色は実際の歩行ルート

GPS logger for arduino
GPS logger for arduino

駐車場の1マスは約3mx2mという事で数千円のgpsの精度と見ると、よく出来ているので感心した。
ここは周りに何もないので精度が出たが、建物や木陰ではとんでもない値となるので注意が必要です。

arduino code(TinyGPS++のFullExample)

#include <TinyGPS++.h>
//#include <SoftwareSerial.h>
/*
 This sample code demonstrates the normal use of a TinyGPS++ (TinyGPSPlus) object.
 It requires the use of SoftwareSerial, and assumes that you have a
 4800-baud serial GPS device hooked up on pins 4(rx) and 3(tx).
*/
static const int RXPin = 4, TXPin = 3;
static const uint32_t GPSBaud = 4800;

// The TinyGPS++ object
TinyGPSPlus gps;

// The serial connection to the GPS device
//SoftwareSerial ss(RXPin, TXPin);

void setup()
{
 Serial.begin(9600);
 Serial2.begin(9600);

Serial.println(F("FullExample.ino"));
 Serial.println(F("An extensive example of many interesting TinyGPS++ features"));
 Serial.print(F("Testing TinyGPS++ library v. ")); Serial.println(TinyGPSPlus::libraryVersion());
 Serial.println(F("by Mikal Hart"));
 Serial.println();
 Serial.println(F("Sats HDOP Latitude Longitude Fix Date Time Date Alt Course Speed Card Distance Course Card Chars Sentences Checksum"));
 Serial.println(F(" (deg) (deg) Age Age (m) --- from GPS ---- ---- to London ---- RX RX Fail"));
 Serial.println(F("---------------------------------------------------------------------------------------------------------------------------------------"));
}

void loop()
{
 static const double LONDON_LAT = 51.508131, LONDON_LON = -0.128002;

printInt(gps.satellites.value(), gps.satellites.isValid(), 5);
 printInt(gps.hdop.value(), gps.hdop.isValid(), 5);
 printFloat(gps.location.lat(), gps.location.isValid(), 11, 6);
 printFloat(gps.location.lng(), gps.location.isValid(), 12, 6);
 printInt(gps.location.age(), gps.location.isValid(), 5);
 printDateTime(gps.date, gps.time);
 printFloat(gps.altitude.meters(), gps.altitude.isValid(), 7, 2);
 printFloat(gps.course.deg(), gps.course.isValid(), 7, 2);
 printFloat(gps.speed.kmph(), gps.speed.isValid(), 6, 2);
 printStr(gps.course.isValid() ? TinyGPSPlus::cardinal(gps.course.value()) : "*** ", 6);

unsigned long distanceKmToLondon =
 (unsigned long)TinyGPSPlus::distanceBetween(
 gps.location.lat(),
 gps.location.lng(),
 LONDON_LAT, 
 LONDON_LON) / 1000;
 printInt(distanceKmToLondon, gps.location.isValid(), 9);

double courseToLondon =
 TinyGPSPlus::courseTo(
 gps.location.lat(),
 gps.location.lng(),
 LONDON_LAT, 
 LONDON_LON);

printFloat(courseToLondon, gps.location.isValid(), 7, 2);

const char *cardinalToLondon = TinyGPSPlus::cardinal(courseToLondon);

printStr(gps.location.isValid() ? cardinalToLondon : "*** ", 6);

printInt(gps.charsProcessed(), true, 6);
 printInt(gps.sentencesWithFix(), true, 10);
 printInt(gps.failedChecksum(), true, 9);
 Serial.println();
 
 smartDelay(1000);

if (millis() > 5000 && gps.charsProcessed() < 10)
 Serial.println(F("No GPS data received: check wiring"));
}

// This custom version of delay() ensures that the gps object
// is being "fed".
static void smartDelay(unsigned long ms)
{
 unsigned long start = millis();
 do 
 {
 while (Serial2.available())
 gps.encode(Serial2.read());
 } while (millis() - start < ms);
}

static void printFloat(float val, bool valid, int len, int prec)
{
 if (!valid)
 {
 while (len-- > 1)
 Serial.print('*');
 Serial.print(' ');
 }
 else
 {
 Serial.print(val, prec);
 int vi = abs((int)val);
 int flen = prec + (val < 0.0 ? 2 : 1); // . and -
 flen += vi >= 1000 ? 4 : vi >= 100 ? 3 : vi >= 10 ? 2 : 1;
 for (int i=flen; i<len; ++i)
 Serial.print(' ');
 }
 smartDelay(0);
}

static void printInt(unsigned long val, bool valid, int len)
{
 char sz[32] = "*****************";
 if (valid)
 sprintf(sz, "%ld", val);
 sz[len] = 0;
 for (int i=strlen(sz); i<len; ++i)
 sz[i] = ' ';
 if (len > 0) 
 sz[len-1] = ' ';
 Serial.print(sz);
 smartDelay(0);
}

static void printDateTime(TinyGPSDate &d, TinyGPSTime &t)
{
 if (!d.isValid())
 {
 Serial.print(F("********** "));
 }
 else
 {
 char sz[32];
 sprintf(sz, "%02d/%02d/%02d ", d.month(), d.day(), d.year());
 Serial.print(sz);
 }
 
 if (!t.isValid())
 {
 Serial.print(F("******** "));
 }
 else
 {
 char sz[32];
 sprintf(sz, "%02d:%02d:%02d ", t.hour(), t.minute(), t.second());
 Serial.print(sz);
 }

printInt(d.age(), d.isValid(), 5);
 smartDelay(0);
}

static void printStr(const char *str, int len)
{
 int slen = strlen(str);
 for (int i=0; i<len; ++i)
 Serial.print(i<slen ? str[i] : ' ');
 smartDelay(0);
}

 

 

 

コメントを残す

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください