mirror of
https://github.com/danog/Telegram.git
synced 2024-12-02 09:27:55 +01:00
173 lines
4.8 KiB
Plaintext
173 lines
4.8 KiB
Plaintext
//
|
|
// KFEstimator.m
|
|
// kalman-ios
|
|
//
|
|
// Created by Gareth Cross on 12/27/2013.
|
|
// Copyright (c) 2013 gareth. All rights reserved.
|
|
//
|
|
|
|
#import "KFEstimator.h"
|
|
#include <mach/mach_time.h>
|
|
|
|
#include "AttitudeESKF.hpp"
|
|
#include <deque>
|
|
|
|
static uint64_t getTime_ns()
|
|
{
|
|
static mach_timebase_info_data_t s_timebase_info;
|
|
|
|
// get the time scale
|
|
if (s_timebase_info.denom == 0) {
|
|
mach_timebase_info(&s_timebase_info);
|
|
}
|
|
|
|
return ((mach_absolute_time() * (uint64_t)s_timebase_info.numer) / (uint64_t)s_timebase_info.denom);
|
|
}
|
|
|
|
static double getTime()
|
|
{
|
|
// mach_absolute_time() returns billionth of seconds
|
|
const double kOneBillion = 1000000000.0;
|
|
return getTime_ns() / kOneBillion;
|
|
}
|
|
|
|
static float constrain(float v, float vmin, float vmax)
|
|
{
|
|
if (v > vmax) return vmax;
|
|
if (v < vmin) return vmin;
|
|
return v;
|
|
}
|
|
|
|
static BOOL skipCalibration = true;
|
|
|
|
@interface KFEstimator ()
|
|
{
|
|
double lastT;
|
|
|
|
NSDate * lastDisturbance;
|
|
|
|
int staticPts;
|
|
matrix<3> mean_g, mean_m;
|
|
matrix<3> max_m, min_m;
|
|
float max_x, min_x, max_y, min_y;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation KFEstimator
|
|
|
|
- (id)init
|
|
{
|
|
self = [super init];
|
|
if (self != nil)
|
|
{
|
|
self.gyroCalibrated = NO;
|
|
self.compassCalibrated = NO;
|
|
|
|
max_m = matrix<3>(-10000.0f, -10000.0f, -10000.0f);
|
|
min_m = matrix<3>( 10000.0f, 10000.0f, 10000.0f);
|
|
|
|
max_x = max_y = -1.0f;
|
|
min_x = min_y = 1.0f;
|
|
|
|
_eskf = new AttitudeESKF();
|
|
|
|
if (skipCalibration) {
|
|
_eskf->m_b = matrix<3> (0.037, -0.0029, -0.0002);
|
|
_eskf->m_mc = matrix<3> (201.5953f, -291.3410f, 93.4031f);
|
|
_eskf->m_mi = matrix<3> (0.35f, 0, 0.936f);
|
|
|
|
_eskf->m_Q(0,0) = _eskf->m_Q(1,1) = _eskf->m_Q(2,2) = 1.0e-4f;
|
|
|
|
_eskf->m_R(0,0) = _eskf->m_R(1,1) = _eskf->m_R(2,2) = 0.02f;
|
|
_eskf->m_R = _eskf->m_R * 20;
|
|
|
|
// compass
|
|
_eskf->m_R(3,3) = 1.0410; _eskf->m_R(3,4) = 0.0650; _eskf->m_R(3,5) = 0.0737;
|
|
_eskf->m_R(4,3) = 0.0650; _eskf->m_R(4,4) = 1.2123; _eskf->m_R(4,5) = -0.1402;
|
|
_eskf->m_R(5,3) = 0.0737; _eskf->m_R(5,4) = -0.1402; _eskf->m_R(5,5) = 1.5370;
|
|
|
|
//_eskf->m_R = _eskf->m_R * 0.01f;
|
|
|
|
self.gyroCalibrated = YES;
|
|
self.compassCalibrated = YES;
|
|
}
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (void)dealloc
|
|
{
|
|
if (_eskf) {
|
|
delete _eskf;
|
|
}
|
|
}
|
|
|
|
- (void)readAccel:(CMAcceleration)acceleration
|
|
rates:(CMRotationRate)rotationRate
|
|
field:(CMMagneticField)magneticField
|
|
{
|
|
double T = getTime();
|
|
float delta = (float)MAX(MIN(T - lastT, 0.1), 0.01);
|
|
lastT = T;
|
|
|
|
auto ar = matrix<3>(-acceleration.x, -acceleration.y, -acceleration.z);
|
|
auto gr = matrix<3>(-rotationRate.x, -rotationRate.y, -rotationRate.z);
|
|
auto mr = matrix<3>(-magneticField.x, -magneticField.y, -magneticField.z);
|
|
|
|
// get rough estimates of angles
|
|
float phi = asin(-constrain(ar(1), -1.0f, 1.0f)); // pitch
|
|
float theta = atan2(ar(0), ar(2)); // roll
|
|
|
|
if (!self.gyroCalibrated)
|
|
{
|
|
if (fabsf(phi) > 0.06f || fabsf(theta) > 0.06f || fabsf(gr(0)) > 0.1f || fabsf(gr(1)) > 0.1f || fabsf(gr(2)) > 0.1f) {
|
|
lastDisturbance = [NSDate date];
|
|
NSLog(@"Disturbed!");
|
|
}
|
|
|
|
if (lastDisturbance.timeIntervalSinceNow < -2.0 || !lastDisturbance)
|
|
{
|
|
// at 'rest', record point
|
|
|
|
mean_g = (mean_g * staticPts + gr) / (staticPts + 1);
|
|
mean_m = (mean_m * staticPts + mr) / (staticPts + 1);
|
|
}
|
|
|
|
// 300 calibration points, the above method has ~ converged to the real mean
|
|
if (staticPts++ == 300)
|
|
{
|
|
matrix <6,6> R; // these params were determined in advanced using samples + matlab
|
|
matrix <3,3> Q;
|
|
|
|
// gyroscope
|
|
Q(0,0) = Q(1,1) = Q(2,2) = 0.0001f;
|
|
|
|
// accelerometer
|
|
R(0,0) = R(1,1) = R(2,2) = 0.01f;
|
|
R = R * 10;
|
|
|
|
// compass
|
|
R(3,3) = 1.041; R(3,4) = 0.065; R(3,5) = 0.074;
|
|
R(4,3) = 0.065; R(4,4) = 1.212; R(4,5) = -0.0140;
|
|
R(5,3) = 0.074; R(5,4) = -0.014; R(5,5) = 1.537;
|
|
|
|
_eskf->Q() = Q;
|
|
_eskf->R() = R; // scale R up to smooth results
|
|
|
|
_eskf->setGyroBias(mean_g);
|
|
|
|
NSLog(@"Gyro calibrated, gyro bias: %f, %f, %f", mean_g(0), mean_g(1), mean_g(2));
|
|
self.gyroCalibrated = YES;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// we may now estimate everything
|
|
_eskf->predict(gr, delta);
|
|
_eskf->update(ar, mr, false); // true = use compass, false = integrate freely on yaw axis
|
|
}
|
|
}
|
|
|
|
@end
|