changes from the laptop
- some should be the same as previous commit (sorry!) - some should be new: LINT checks, ...?
This commit is contained in:
123
sensors/offline/FilePlayer.h
Normal file
123
sensors/offline/FilePlayer.h
Normal file
@@ -0,0 +1,123 @@
|
||||
#ifndef FILEPLAYER_H
|
||||
#define FILEPLAYER_H
|
||||
|
||||
#include "FileReader.h"
|
||||
#include <thread>
|
||||
|
||||
namespace Offline {
|
||||
|
||||
/**
|
||||
* this class can be used to "play" previously recorded [so-called "offline"] files.
|
||||
* one can attach itself as listener and is informed whenever new sensor data is available.
|
||||
* one may choose whether to use full-speed playback [as many events as possible] or
|
||||
* live-speed playback with the same timing the values were recorded with
|
||||
*/
|
||||
class FilePlayer {
|
||||
|
||||
private:
|
||||
|
||||
FileReader* reader;
|
||||
|
||||
bool realtime = false;
|
||||
bool enabled;
|
||||
std::thread thread;
|
||||
|
||||
/** the listener to inform */
|
||||
Listener* listener = nullptr;
|
||||
|
||||
public:
|
||||
|
||||
/** empty ctor */
|
||||
FilePlayer() : reader(nullptr), listener(nullptr) {
|
||||
;
|
||||
}
|
||||
|
||||
/** ctor */
|
||||
FilePlayer(FileReader* reader, Listener* l) : reader(reader), listener(l) {
|
||||
;
|
||||
}
|
||||
|
||||
/** whether to use realtime playback or "as fast as possible" */
|
||||
void setRealtime(const bool rt) {
|
||||
this->realtime = rt;
|
||||
}
|
||||
|
||||
/** set the offline-file-reader to use as data source */
|
||||
void setReader(FileReader* r) {
|
||||
this->reader = r;
|
||||
}
|
||||
|
||||
/** set the event listener to inform */
|
||||
void setListener(Listener* l) {
|
||||
this->listener = l;
|
||||
}
|
||||
|
||||
/** start playback */
|
||||
void start() {
|
||||
|
||||
// sanity check
|
||||
Assert::isNotNull(reader, "call FilePlayer::setReader() first");
|
||||
Assert::isNotNull(listener, "call FilePlayer::setListener() first");
|
||||
Assert::isFalse(reader->getEntries().empty(), "FileReader has no loaded entries for playback within the FilePlayer!");
|
||||
|
||||
enabled = true;
|
||||
thread = std::thread(&FilePlayer::loop, this);
|
||||
|
||||
}
|
||||
|
||||
/** stop playback */
|
||||
void stop() {
|
||||
enabled = false;
|
||||
}
|
||||
|
||||
/** wait for termination */
|
||||
void join() {
|
||||
thread.join();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
/** background loop */
|
||||
void loop() {
|
||||
|
||||
// get all sensor events from the offline file
|
||||
const std::vector<Entry> events = reader->getEntries();
|
||||
|
||||
// process every event
|
||||
for (const Entry& e : events) {
|
||||
|
||||
// aborted?
|
||||
if (!enabled) {break;}
|
||||
|
||||
// timestamp
|
||||
const Timestamp ts = Timestamp::fromMS(e.ts);
|
||||
|
||||
// event index
|
||||
const size_t idx = e.idx;
|
||||
|
||||
#warning "some sensors todo:"
|
||||
switch(e.type) {
|
||||
case Sensor::ACC: listener->onAccelerometer(ts, reader->getAccelerometer()[idx].data); break;
|
||||
case Sensor::BARO: listener->onBarometer(ts, reader->getBarometer()[idx].data); break;
|
||||
case Sensor::BEACON: break;//listener->onBe(ts, reader->getBarometer()[idx].data); break;
|
||||
case Sensor::COMPASS: listener->onCompass(ts, reader->getCompass()[idx].data); break;
|
||||
case Sensor::GPS: listener->onGPS(ts, reader->getGPS()[idx].data); break;
|
||||
case Sensor::GRAVITY: listener->onGravity(ts, reader->getGravity()[idx].data); break;
|
||||
case Sensor::GYRO: listener->onGyroscope(ts, reader->getGyroscope()[idx].data); break;
|
||||
case Sensor::LIN_ACC: break;//listener->on(ts, reader->getBarometer()[idx].data); break;
|
||||
case Sensor::WIFI: listener->onWiFi(ts, reader->getWiFiGroupedByTime()[idx].data); break;
|
||||
default: throw Exception("code error. found not-yet-implemented sensor");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// done
|
||||
enabled = false;
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // FILEPLAYER_H
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "../../grid/factory/v2/GridFactory.h"
|
||||
#include "../../grid/factory/v2/Importance.h"
|
||||
#include "../../floorplan/v2/Floorplan.h"
|
||||
#include "../../floorplan/v2/FloorplanHelper.h"
|
||||
|
||||
#include "Splitter.h"
|
||||
#include "Sensors.h"
|
||||
@@ -30,10 +31,16 @@
|
||||
|
||||
namespace Offline {
|
||||
|
||||
/**
|
||||
* read and parse previously recorded ["offline"] files
|
||||
*/
|
||||
class FileReader {
|
||||
|
||||
public:
|
||||
|
||||
using GroundTruth = Interpolator<Timestamp, Point3>;
|
||||
|
||||
/** all entries grouped by sensor */
|
||||
std::vector<TS<int>> groundTruth;
|
||||
std::vector<TS<WiFiMeasurements>> wifi;
|
||||
std::vector<TS<BeaconMeasurement>> beacon;
|
||||
@@ -45,13 +52,11 @@ namespace Offline {
|
||||
std::vector<TS<GPSData>> gps;
|
||||
std::vector<TS<CompassData>> compass;
|
||||
|
||||
/** ALL entries */
|
||||
/** all entries in linear order as they appeared while recording */
|
||||
std::vector<Entry> entries;
|
||||
|
||||
static constexpr char sep = ';';
|
||||
|
||||
Listener* listener = nullptr;
|
||||
|
||||
public:
|
||||
|
||||
/** empty ctor. call open() */
|
||||
@@ -65,11 +70,26 @@ namespace Offline {
|
||||
}
|
||||
|
||||
/** open the given file */
|
||||
void open(const std::string& file, Listener* listener = nullptr) {
|
||||
this->listener = listener;
|
||||
void open(const std::string& file) {
|
||||
clear();
|
||||
parse(file);
|
||||
}
|
||||
|
||||
/** remove all parsed entries */
|
||||
void clear() {
|
||||
entries.clear();
|
||||
groundTruth.clear();
|
||||
wifi.clear();
|
||||
beacon.clear();
|
||||
acc.clear();
|
||||
gyro.clear();
|
||||
gps.clear();
|
||||
compass.clear();
|
||||
barometer.clear();
|
||||
lin_acc.clear();
|
||||
gravity.clear();
|
||||
}
|
||||
|
||||
const std::vector<Entry>& getEntries() const {return entries;}
|
||||
|
||||
|
||||
@@ -93,6 +113,35 @@ namespace Offline {
|
||||
|
||||
const std::vector<TS<GravityData>>& getGravity() const {return gravity;}
|
||||
|
||||
/** get an interpolateable ground-truth based on the time-clicks during recording */
|
||||
GroundTruth getGroundTruth(const Floorplan::IndoorMap* map, const std::vector<int> groundTruthPoints) const {
|
||||
|
||||
// sanity check: given path [indices to ground-truth points within the map]
|
||||
// must have the same size as the number of clicks during recording
|
||||
Assert::equal(groundTruthPoints.size(), groundTruth.size(), "mismatch of ground-truth points between given path and recording");
|
||||
|
||||
// allows getting a position on the ground-truth given a timestamp
|
||||
GroundTruth interpol;
|
||||
|
||||
// all ground-truth points within the map
|
||||
static std::unordered_map<int, Point3> gt = FloorplanHelper::getGroundTruthPoints(map);
|
||||
|
||||
// process each "tap smartphone when reaching ground-truth-point"
|
||||
for (const TS<int>& entry : groundTruth) {
|
||||
const Timestamp ts = Timestamp::fromMS(entry.ts);
|
||||
const int idx = entry.data; // starting at 0, incrementing over time [1st point, 2nd points, 3d points, ...]
|
||||
const int id = groundTruthPoints[idx]; // convert point number to point-id within floorplan
|
||||
const auto& it = gt.find(id);
|
||||
if (it == gt.end()) {throw Exception("missing ground-truth point ID:" + std::to_string(id));}
|
||||
const Point3 pos = it->second;
|
||||
interpol.add(ts, pos);
|
||||
}
|
||||
|
||||
// done
|
||||
return interpol;
|
||||
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void parse(const std::string& file) {
|
||||
@@ -165,7 +214,7 @@ namespace Offline {
|
||||
entries.push_back(Entry(Sensor::GRAVITY, ts, gravity.size()-1));
|
||||
|
||||
// inform listener
|
||||
if (listener) {listener->onGravity(Timestamp::fromMS(ts), gravData);}
|
||||
//if (listener) {listener->onGravity(Timestamp::fromMS(ts), gravData);}
|
||||
|
||||
}
|
||||
|
||||
@@ -184,7 +233,7 @@ namespace Offline {
|
||||
entries.push_back(Entry(Sensor::ACC, ts, acc.size()-1));
|
||||
|
||||
// inform listener
|
||||
if (listener) {listener->onAccelerometer(Timestamp::fromMS(ts), accData);}
|
||||
//if (listener) {listener->onAccelerometer(Timestamp::fromMS(ts), accData);}
|
||||
|
||||
}
|
||||
|
||||
@@ -203,7 +252,7 @@ namespace Offline {
|
||||
entries.push_back(Entry(Sensor::GYRO, ts, gyro.size()-1));
|
||||
|
||||
// inform listener
|
||||
if (listener) {listener->onGyroscope(Timestamp::fromMS(ts), gyroData);}
|
||||
//if (listener) {listener->onGyroscope(Timestamp::fromMS(ts), gyroData);}
|
||||
|
||||
}
|
||||
|
||||
@@ -230,7 +279,7 @@ namespace Offline {
|
||||
entries.push_back(Entry(Sensor::WIFI, ts, this->wifi.size()-1));
|
||||
|
||||
// inform listener
|
||||
if (listener) {listener->onWiFi(Timestamp::fromMS(ts), wifi);}
|
||||
//if (listener) {listener->onWiFi(Timestamp::fromMS(ts), wifi);}
|
||||
|
||||
}
|
||||
|
||||
@@ -273,7 +322,7 @@ namespace Offline {
|
||||
entries.push_back(Entry(Sensor::BARO, ts, barometer.size()-1));
|
||||
|
||||
// inform listener
|
||||
if (listener) {listener->onBarometer(Timestamp::fromMS(ts), baro);}
|
||||
//if (listener) {listener->onBarometer(Timestamp::fromMS(ts), baro);}
|
||||
|
||||
}
|
||||
|
||||
@@ -290,7 +339,7 @@ namespace Offline {
|
||||
entries.push_back(Entry(Sensor::COMPASS, ts, this->compass.size()-1));
|
||||
|
||||
// inform listener
|
||||
if (listener) {listener->onCompass(Timestamp::fromMS(ts), compass);}
|
||||
//if (listener) {listener->onCompass(Timestamp::fromMS(ts), compass);}
|
||||
|
||||
}
|
||||
|
||||
@@ -311,12 +360,13 @@ namespace Offline {
|
||||
entries.push_back(Entry(Sensor::GPS, ts, this->gps.size()-1));
|
||||
|
||||
// inform listener
|
||||
if (listener) {listener->onGPS(Timestamp::fromMS(ts), gps);}
|
||||
//if (listener) {listener->onGPS(Timestamp::fromMS(ts), gps);}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
|
||||
const Interpolator<uint64_t, Point3> getGroundTruthPath(Floorplan::IndoorMap* map, std::vector<int> gtPath) const {
|
||||
|
||||
// finde alle positionen der waypoints im gtPath aus map
|
||||
|
||||
Reference in New Issue
Block a user