add distance interval
This commit is contained in:
parent
e61cec10a1
commit
5a2189be15
4 changed files with 48 additions and 37 deletions
|
@ -57,7 +57,7 @@ class TelnetPrint : public Print {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Is only called for Strings, not char arrays
|
// Is only called for Strings, not char arrays?
|
||||||
/*virtual size_t write(const char *buffer, size_t size) {
|
/*virtual size_t write(const char *buffer, size_t size) {
|
||||||
for(uint8_t i = 0; i < MAX_TELNET_CLIENTS; i++){
|
for(uint8_t i = 0; i < MAX_TELNET_CLIENTS; i++){
|
||||||
if (clients[i] && clients[i].connected()){
|
if (clients[i] && clients[i].connected()){
|
||||||
|
|
8
config.h
8
config.h
|
@ -1,12 +1,16 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
/* GENERAL */
|
/* GENERAL */
|
||||||
// interval of the measurements in ms. 0 for "as fast as possible"
|
// interval of the measurements in millisec / meters
|
||||||
#define MEASUREMENT_INTERVAL 10000
|
#define MEASUREMENT_INTERVAL 10000 // 0 for "as fast as possible"
|
||||||
|
#define MEASUREMENT_DISTANCE_ENABLED true
|
||||||
|
#define MEASUREMENT_DISTANCE 25
|
||||||
|
|
||||||
// pull this pin down to disable measurements (eg for quickly bulk uploading stored measurements)
|
// pull this pin down to disable measurements (eg for quickly bulk uploading stored measurements)
|
||||||
#define PIN_MEASURE_MODE D14
|
#define PIN_MEASURE_MODE D14
|
||||||
// pull this pin down to disable uploads (eg for higher measurement rates when no realtime data is required)
|
// pull this pin down to disable uploads (eg for higher measurement rates when no realtime data is required)
|
||||||
#define PIN_UPLOAD_MODE D15
|
#define PIN_UPLOAD_MODE D15
|
||||||
|
|
||||||
// should be higher than the number of sensors to avoid storage overflowing. tradeoff with the measurement interval
|
// should be higher than the number of sensors to avoid storage overflowing. tradeoff with the measurement interval
|
||||||
#define MAX_UPLOADS_PER_CYCLE 4
|
#define MAX_UPLOADS_PER_CYCLE 4
|
||||||
|
|
||||||
|
|
25
gps.h
25
gps.h
|
@ -3,24 +3,22 @@
|
||||||
#include <Time.h>
|
#include <Time.h>
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
// TODO: refactor updateXXX members to be protected and called by getXXX ?
|
|
||||||
|
|
||||||
class Gps {
|
class Gps {
|
||||||
protected:
|
protected:
|
||||||
TinyGPSPlus gps;
|
TinyGPSPlus gps;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void begin() {
|
void begin() {
|
||||||
Serial.begin(GPS_BAUD);
|
Serial.begin(GPS_BAUD);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* parse all available bytes from the Serial input
|
* parse all available bytes from the Serial input
|
||||||
* should be called frequently to avoid buffer overflows
|
* should be called frequently to avoid buffer overflows
|
||||||
*/
|
*/
|
||||||
void pollGPS() {
|
void pollGPS() {
|
||||||
while (Serial.available() > 0)
|
while (Serial.available() > 0)
|
||||||
gps.encode(Serial.read());
|
gps.encode(Serial.read());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -31,14 +29,14 @@ class Gps {
|
||||||
// abort if the GPS device does not push valid data within one update cycle
|
// abort if the GPS device does not push valid data within one update cycle
|
||||||
static const unsigned int timeout = 2 * GPS_INTERVAL;
|
static const unsigned int timeout = 2 * GPS_INTERVAL;
|
||||||
unsigned long start = millis();
|
unsigned long start = millis();
|
||||||
|
|
||||||
do {
|
do {
|
||||||
pollGPS();
|
pollGPS();
|
||||||
if (millis() - start > timeout) return false;
|
if (millis() - start > timeout) return false;
|
||||||
} while (!gps.location.isUpdated()); // TODO: check if is valid?
|
} while (!gps.location.isUpdated() && !gps.location.isValid());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* poll until we have a valid date & time.
|
* poll until we have a valid date & time.
|
||||||
* retries at most once, returns success state
|
* retries at most once, returns success state
|
||||||
|
@ -48,23 +46,22 @@ class Gps {
|
||||||
static const unsigned int timeout = 2 * GPS_INTERVAL;
|
static const unsigned int timeout = 2 * GPS_INTERVAL;
|
||||||
unsigned long start = millis();
|
unsigned long start = millis();
|
||||||
|
|
||||||
// TODO: check if is valid?
|
|
||||||
do {
|
do {
|
||||||
pollGPS();
|
pollGPS();
|
||||||
if (millis() - start > timeout) return false;
|
if (millis() - start > timeout) return false;
|
||||||
} while ( !(gps.date.isUpdated() && gps.time.isUpdated()) );
|
} while ( !(gps.date.isUpdated() && gps.time.isUpdated() && gps.time.isValid() && gps.time.isValid()) );
|
||||||
|
|
||||||
// in case we didnt timeout, resync the local clock (Time.h)
|
// in case we didnt timeout, resync the local clock (Time.h)
|
||||||
setTime(gps.time.hour(), gps.time.minute(), gps.time.second(),
|
setTime(gps.time.hour(), gps.time.minute(), gps.time.second(),
|
||||||
gps.date.day(), gps.date.month(), gps.date.year());
|
gps.date.day(), gps.date.month(), gps.date.year());
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
TinyGPSLocation& getLocation() {
|
TinyGPSLocation& getLocation() {
|
||||||
return gps.location;
|
return gps.location;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fill a char[20] with an iso8601 formatted date from now
|
* fill a char[20] with an iso8601 formatted date from now
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
#include <TinyGPS++.h>
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "gps.h"
|
#include "gps.h"
|
||||||
#include "wifi.h"
|
#include "wifi.h"
|
||||||
|
@ -14,6 +15,10 @@ TelnetPrint telnet = TelnetPrint();
|
||||||
OsemApi api = OsemApi();
|
OsemApi api = OsemApi();
|
||||||
Gps gps = Gps();
|
Gps gps = Gps();
|
||||||
|
|
||||||
|
unsigned long cycleStart;
|
||||||
|
WifiState wifiState; // global, as both measure and upload need the state
|
||||||
|
TinyGPSLocation location;
|
||||||
|
|
||||||
bool storeMeasurement(float lat, float lng, float value, const char* timeStamp, const char* sensorID) {
|
bool storeMeasurement(float lat, float lng, float value, const char* timeStamp, const char* sensorID) {
|
||||||
Measurement m;
|
Measurement m;
|
||||||
m.lat = lat;
|
m.lat = lat;
|
||||||
|
@ -24,22 +29,21 @@ bool storeMeasurement(float lat, float lng, float value, const char* timeStamp,
|
||||||
return storage.add(m);
|
return storage.add(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
void measure(WifiState& wifiState) {
|
void measure(WifiState& wifiState, TinyGPSLocation& loc) {
|
||||||
char dateString[20];
|
char dateString[20];
|
||||||
|
|
||||||
// measure WiFi
|
// measure WiFi
|
||||||
wifiState = wifi.scan(WIFI_SSID);
|
wifiState = wifi.scan(WIFI_SSID);
|
||||||
|
|
||||||
// update gps position
|
// update gps position if we can't get a fix, skip the measurements
|
||||||
// TODO: how to handle lost GPS fix?
|
|
||||||
// TODO: check if is data is valid?
|
|
||||||
if(!gps.updateLocation() || !gps.updateTime()) {
|
if(!gps.updateLocation() || !gps.updateTime()) {
|
||||||
DEBUG_OUT << "GPS timed out" << EOL;
|
DEBUG_OUT << "GPS timed out, skipping measurements" << EOL;
|
||||||
digitalWrite(BUILTIN_LED, LOW);
|
digitalWrite(BUILTIN_LED, LOW); // turn status LED on
|
||||||
} else {
|
return;
|
||||||
digitalWrite(BUILTIN_LED, HIGH);
|
|
||||||
}
|
}
|
||||||
TinyGPSLocation loc = gps.getLocation();
|
|
||||||
|
digitalWrite(BUILTIN_LED, HIGH);
|
||||||
|
loc = gps.getLocation();
|
||||||
gps.getISODate(dateString);
|
gps.getISODate(dateString);
|
||||||
|
|
||||||
// print state
|
// print state
|
||||||
|
@ -100,13 +104,22 @@ void upload(WifiState& wifiState) {
|
||||||
// delay for a given duration (ms), rollover-safe implementation
|
// delay for a given duration (ms), rollover-safe implementation
|
||||||
// offset may be a duration which has been "used up" before, so the delay is adaptive,
|
// offset may be a duration which has been "used up" before, so the delay is adaptive,
|
||||||
// meaning that the interval of a adaptiveDelay() call is constant
|
// meaning that the interval of a adaptiveDelay() call is constant
|
||||||
void adaptiveDelay(unsigned long ms, unsigned long offset = 0) {
|
// returns earlier, if we moved more than MEASUREMENT_DISTANCE meters from our last fix
|
||||||
|
void adaptiveDelay(unsigned long ms, TinyGPSLocation& lastLoc, unsigned long offset = 0) {
|
||||||
unsigned long start = millis();
|
unsigned long start = millis();
|
||||||
for (;;) {
|
for (;;) {
|
||||||
// for some reason, operations have to be performed in this loop for
|
// for some reason, operations have to be performed in this loop for
|
||||||
// proper operation, so we just do the polling to be done anyway
|
// proper operation, so we just do the polling to be done anyway
|
||||||
gps.pollGPS();
|
gps.pollGPS();
|
||||||
telnet.pollClients();
|
telnet.pollClients();
|
||||||
|
|
||||||
|
// update our location. if we moved MEASUREMENT_DISTANCE meters or more, return
|
||||||
|
TinyGPSLocation newLoc = gps.getLocation();
|
||||||
|
double distanceToPrevLoc = TinyGPSPlus::distanceBetween(lastLoc.lat(), lastLoc.lng(), newLoc.lat(), newLoc.lng());
|
||||||
|
if (MEASUREMENT_DISTANCE_ENABLED && distanceToPrevLoc >= MEASUREMENT_DISTANCE) {
|
||||||
|
DEBUG_OUT << "moved " << distanceToPrevLoc << "m, delay stopped." << EOL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
unsigned long now = millis();
|
unsigned long now = millis();
|
||||||
unsigned long elapsed = now - start + offset;
|
unsigned long elapsed = now - start + offset;
|
||||||
|
@ -135,6 +148,7 @@ void setup() {
|
||||||
// wait until we got a first fix from GPS, and thus an initial time
|
// wait until we got a first fix from GPS, and thus an initial time
|
||||||
DEBUG_OUT << "Getting GPS fix..";
|
DEBUG_OUT << "Getting GPS fix..";
|
||||||
while (!gps.updateLocation()) { DEBUG_OUT << "."; }
|
while (!gps.updateLocation()) { DEBUG_OUT << "."; }
|
||||||
|
location = gps.getLocation();
|
||||||
DEBUG_OUT << " done!" << EOL;
|
DEBUG_OUT << " done!" << EOL;
|
||||||
digitalWrite(BUILTIN_LED, HIGH);
|
digitalWrite(BUILTIN_LED, HIGH);
|
||||||
|
|
||||||
|
@ -144,26 +158,22 @@ void setup() {
|
||||||
DEBUG_OUT << "SPIFF bytes free: " << bytesFree << EOL << EOL;
|
DEBUG_OUT << "SPIFF bytes free: " << bytesFree << EOL << EOL;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long cycleStart;
|
|
||||||
WifiState wifiState; // global, as both measure and upload need the state
|
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
cycleStart = millis();
|
cycleStart = millis();
|
||||||
|
|
||||||
if (digitalRead(PIN_MEASURE_MODE) == HIGH)
|
if (digitalRead(PIN_MEASURE_MODE) == HIGH)
|
||||||
measure(wifiState);
|
measure(wifiState, location);
|
||||||
|
|
||||||
if (digitalRead(PIN_UPLOAD_MODE) == HIGH)
|
if (digitalRead(PIN_UPLOAD_MODE) == HIGH)
|
||||||
upload(wifiState);
|
upload(wifiState);
|
||||||
|
|
||||||
if (digitalRead(PIN_MEASURE_MODE) == HIGH) {
|
if (digitalRead(PIN_MEASURE_MODE) == HIGH) {
|
||||||
// run the measurements in a fixed interval, using an adaptive delay
|
// run the measurements in a fixed interval, using an adaptive delay
|
||||||
// IDEA: dont use time but distance interval? -> TinyGPSPlus::distanceBetween()
|
// the interval is defined by a duration and/or distance from our last fix
|
||||||
adaptiveDelay(MEASUREMENT_INTERVAL, millis() - cycleStart);
|
return adaptiveDelay(MEASUREMENT_INTERVAL, location, millis() - cycleStart);
|
||||||
} else {
|
|
||||||
// run as fast as possible when not measuring.
|
|
||||||
// adaptiveDelay has to be called anyway, as some polling functions are run within
|
|
||||||
adaptiveDelay(0);
|
|
||||||
}
|
}
|
||||||
|
// run as fast as possible when not measuring.
|
||||||
|
// smartDelay has to be called anyway, as some polling functions are run within
|
||||||
|
adaptiveDelay(0, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue