This repository has been archived on 2020-04-08. You can view files and clone it, but cannot push or open issues or pull requests.
Files
Indoor/sensors/imu/PoseDetection3.h
frank 857d7a1553 fixed some issues
added new pose/turn detections
new helper classes
define-flags for libEigen
2018-09-04 10:49:00 +02:00

180 lines
4.2 KiB
C++

#ifndef POSEDETECTION3_H
#define POSEDETECTION3_H
#include "AccelerometerData.h"
#include "GyroscopeData.h"
#include "../../data/Timestamp.h"
#include "../../math/Matrix3.h"
#include "../../math/Quaternion.h"
#include "../../geo/Point3.h"
#include "PoseDetectionPlot.h"
#include "PoseProvider.h"
class PoseDetection3 : public PoseProvider {
private:
struct {
//Eigen::Matrix3f rotationMatrix = Eigen::Matrix3f::Identity();
Matrix3 rotationMatrix = Matrix3::identity();
bool isKnown = false;
Timestamp lastEstimation;
} orientation;
#ifdef WITH_DEBUG_PLOT
PoseDetectionPlot plot;
PoseDetectionPlotAngles plotAngles;
#endif
Vector3 lastGyroReading;
Timestamp lastGyroReadingTS;
public:
/** ctor */
PoseDetection3() {
#ifdef WITH_DEBUG_PLOT
plot.setName("PoseDetection3");
#endif
}
/** get the smartphone's rotation matrix */
const Matrix3& getMatrix() const override {
return orientation.rotationMatrix;
}
/** is the pose known and stable? */
bool isKnown() const override {
return orientation.isKnown;
}
bool first = true;
Quaternion qGyro = Quaternion(1, 0,0,0);
Quaternion qGyroUpdate;
Quaternion qAccel;
Quaternion qFiltered;
void addAccelerometer(const Timestamp& ts, const AccelerometerData& acc) {
const Vector3 vec(-acc.x, -acc.y, acc.z);
const Vector3 v = vec.normalized();
const float mag = -std::acos(v.dot(Vector3(0,0,1)));//-std::acos(v.z); << same
const Vector3 n = Vector3(v.y, -v.x, 0).normalized();
qAccel = Quaternion::fromAxisAngle(mag, n.x, n.y, n.z);
//const float magY = std::atan2(acc.x, acc.z);
//const float magX = std::atan2(acc.y, acc.z);
//qAccel = Quaternion::fromAxisAngle(magX, 1, 0, 0) * Quaternion::fromAxisAngle(-magY, 0, 1, 0);
//Vector3 dv = qAccel.toEuler();
//dv.z = 0;
//std::cout << dv.x << " " << dv.y << " " << dv.z << std::endl;
// for plotting
if (first) {
qGyro = qAccel;
first = false;
}
int i = 0; (void) i;
}
void addGyroscope(const Timestamp& ts, const GyroscopeData& gyro) {
Vector3 vec(gyro.x, gyro.y, gyro.z);
// ignore the first reading completely, just remember its timestamp
if (lastGyroReadingTS.isZero()) {lastGyroReadingTS = ts; return;}
// time-difference between previous and current reading
const Timestamp curDiff = ts - lastGyroReadingTS;
lastGyroReadingTS = ts;
// fast sensors might lead to delay = 0 ms. filter those values
if (curDiff.isZero()) {return;}
// current area
//const Vector3 curArea = (lastGyroReading * curDiff.sec());
// length of the rotation vector
const float theta = curDiff.sec() * lastGyroReading.norm();
const Vector3 v = lastGyroReading.normalized();
lastGyroReading = vec;
if (theta == 0) {return;}
qGyroUpdate = Quaternion::fromAxisAngle(theta, v.x, v.y, v.z);// qUpdate(cos(theta/2), v.x * sin(theta/2), v.y * sin(theta/2), v.z * sin(theta/2));
// update
qGyro = qGyroUpdate * qGyro;
update(ts);
}
Matrix3 getMatrixAcc() const {
Vector3 r = qAccel.toEuler();
return Matrix3::getRotationRad(r.x, r.y, r.z);
}
Matrix3 getMatrixGyro() const {
Vector3 r = qGyro.toEuler();
return Matrix3::getRotationRad(r.x, r.y, r.z);
}
private:
Vector3 curAngle_rad;
int cnt = 0;
void update(const Timestamp ts) {
//Quaternion qFused = qGyro;
//qFiltered = qAccel;
//Quaternion qFused = (qGyro * alpha) + (qAccel * (1-alpha));
qFiltered = Quaternion::lerp(qFiltered*qGyroUpdate, qAccel, 0.05);
//qFiltered = Quaternion::fromAxisAngle(qAccel.w*0.02, qAccel.x, qAccel.y, qAccel.z) * (qFiltered * qGyroUpdate) * 0.98;
Vector3 fused = qFiltered.toEuler();
//std::cout << fused.x <<" " << fused.y << " " << fused.z << std::endl;
// update
orientation.rotationMatrix = Matrix3::getRotationRad(fused.x, fused.y, fused.z); //getMatrixFor(cur);
orientation.isKnown = true;
orientation.lastEstimation = ts;
// debug-plot (if configured)
#ifdef WITH_DEBUG_PLOT
plot.add(ts, Vector3(0,0,0), orientation.rotationMatrix);
if (++cnt % 2 == 0) {
plotAngles.addAcc(ts, qAccel.toEuler().x, qAccel.toEuler().y);
plotAngles.addGyro(ts, qGyro.toEuler().x, qGyro.toEuler().y);
plotAngles.addFused(ts, fused.x, fused.y);
}
#endif
}
};
#endif // POSEDETECTION3_H