180 lines
4.2 KiB
C++
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
|