2#include "tools/OrientationEKF.h"
3#include "tools/SO3Util.h"
8OrientationEKF::OrientationEKF()
13OrientationEKF::~OrientationEKF()
17void OrientationEKF::reset()
19 timestepFilterInit =
false;
20 gyroFilterValid =
true;
21 alignedToGravity =
false;
23 sensorTimeStampGyro = 0;
24 sensorTimeStampMag = 0;
25 previousAccelNorm = 0.0;
26 movingAverageAccelNormChange = 0.0;
28 so3SensorFromWorld.setIdentity();
29 so3LastMotion.setIdentity();
38 mR.setDiagonal(0.0625);
41 mRaccel.setDiagonal(0.5625);
52 down.set(0.0, 0.0, EARTH_GRAVITY);
53 north.set(0.0, 1.0, 0.0);
56bool OrientationEKF::isReady()
58 return alignedToGravity;
61double OrientationEKF::getHeadingDegrees()
63 double x = so3SensorFromWorld.get(2, 0);
64 double y = so3SensorFromWorld.get(2, 1);
65 double mag = sqrt(x * x + y * y);
72 double heading = -90.0 - atan2(y, x) * RAD_TO_DEG;
84void OrientationEKF::setHeadingDegrees(
double heading)
86 double currentHeading = getHeadingDegrees();
87 double deltaHeading = heading - currentHeading;
88 double s = sin(deltaHeading * DEG_TO_RAD);
89 double c = cos(deltaHeading * DEG_TO_RAD);
91 Matrix3x3d setHeadingDegreesTempM1(c, -s, 0.0, s, c, 0.0, 0.0, 0.0, 1.0);
92 Matrix3x3d::mult(so3SensorFromWorld, setHeadingDegreesTempM1, so3SensorFromWorld);
95void OrientationEKF::processGyro(
Vector3d gyro, int64_t sensorTimeStamp)
97 double kTimeThreshold = 0.04;
98 double kdTdefault = 0.01;
99 if (sensorTimeStampGyro != 0)
101 double dT = (double)(sensorTimeStamp - sensorTimeStampGyro) * 1.e-09;
102 if (dT > kTimeThreshold)
103 dT = gyroFilterValid ? filteredGyroTimestep : kdTdefault;
105 filterGyroTimestep(dT);
107 mu.set(gyro.x * -dT, gyro.y * -dT, gyro.z * -dT);
108 SO3Util::sO3FromMu(mu, so3LastMotion);
111 processGyroTempM1.set(so3SensorFromWorld);
112 Matrix3x3d::mult(so3LastMotion, so3SensorFromWorld, processGyroTempM1);
113 so3SensorFromWorld.set(processGyroTempM1);
115 updateCovariancesAfterMotion();
118 processGyroTempM2.set(mQ);
119 processGyroTempM2.scale(dT * dT);
120 mP.plusEquals(processGyroTempM2);
122 sensorTimeStampGyro = sensorTimeStamp;
126void OrientationEKF::processAcc(
Vector3d acc, int64_t sensorTimeStamp)
128 mz.set(acc.x, acc.y, acc.z);
129 updateAccelerationCovariance(mz.length());
130 if (alignedToGravity)
132 accObservationFunctionForNumericalJacobian(so3SensorFromWorld, mNu);
134 double eps = 1.0E-07;
135 for (
int dof = 0; dof < 3; dof++)
139 delta.setComponent(dof, eps);
143 SO3Util::sO3FromMu(delta, processAcc1);
144 Matrix3x3d::mult(processAcc1, so3SensorFromWorld, processAcc2);
147 accObservationFunctionForNumericalJacobian(processAcc2, withDelta);
150 Vector3d::sub(mNu, withDelta, processAccV);
151 processAccV.scale(1.0 / eps);
152 mH.setColumn(dof, processAccV);
158 mH.transpose(processAccTempM3);
159 Matrix3x3d::mult(mP, processAccTempM3, processAccTempM4);
160 Matrix3x3d::mult(mH, processAccTempM4, processAccTempM5);
161 Matrix3x3d::add(processAccTempM5, mRaccel, mS);
163 mS.invert(processAccTempM3);
164 mH.transpose(processAccTempM4);
165 Matrix3x3d::mult(processAccTempM4, processAccTempM3, processAccTempM5);
166 Matrix3x3d::mult(mP, processAccTempM5, mK);
168 Matrix3x3d::mult(mK, mNu, mx);
170 Matrix3x3d::mult(mK, mH, processAccTempM3);
171 processAccTempM4.setIdentity();
172 processAccTempM4.minusEquals(processAccTempM3);
173 Matrix3x3d::mult(processAccTempM4, mP, processAccTempM3);
174 mP.set(processAccTempM3);
176 SO3Util::sO3FromMu(mx, so3LastMotion);
178 Matrix3x3d::mult(so3LastMotion, so3SensorFromWorld, so3SensorFromWorld);
180 updateCovariancesAfterMotion();
184 SO3Util::sO3FromTwoVec(down, mz, so3SensorFromWorld);
185 alignedToGravity =
true;
189void OrientationEKF::processMag(
Vector3d mag, int64_t sensorTimeStamp)
191 mz.set(mag.x, mag.y, mag.z);
195 so3SensorFromWorld.getColumn(2, downInSensorFrame);
198 Vector3d::cross(mz, downInSensorFrame, perpToDownAndMag);
199 perpToDownAndMag.normalize();
202 Vector3d::cross(downInSensorFrame, perpToDownAndMag, magHorizontal);
204 magHorizontal.normalize();
205 mz.set(magHorizontal);
213 if (sensorTimeStampMag != 0)
215 magObservationFunctionForNumericalJacobian(so3SensorFromWorld, mNu);
218 double eps = 1.0E-07;
220 for (
int dof = 0; dof < 3; dof++)
224 delta.setComponent(dof, eps);
226 SO3Util::sO3FromMu(delta, processMagTempM1);
227 Matrix3x3d::mult(processMagTempM1, so3SensorFromWorld, processMagTempM2);
230 magObservationFunctionForNumericalJacobian(processMagTempM2, withDelta);
232 Vector3d::sub(mNu, withDelta, processMagTempV);
233 processMagTempV.scale(1.0 / eps);
235 mH.setColumn(dof, processMagTempV);
238 mH.transpose(processMagTempM4);
239 Matrix3x3d::mult(mP, processMagTempM4, processMagTempM5);
240 Matrix3x3d::mult(mH, processMagTempM5, processMagTempM6);
241 Matrix3x3d::add(processMagTempM6, mR, mS);
243 mS.invert(processMagTempM4);
244 mH.transpose(processMagTempM5);
245 Matrix3x3d::mult(processMagTempM5, processMagTempM4, processMagTempM6);
246 Matrix3x3d::mult(mP, processMagTempM6, mK);
248 Matrix3x3d::mult(mK, mNu, mx);
249 Matrix3x3d::mult(mK, mH, processMagTempM4);
250 processMagTempM5.setIdentity();
251 processMagTempM5.minusEquals(processMagTempM4);
252 Matrix3x3d::mult(processMagTempM5, mP, processMagTempM4);
253 mP.set(processMagTempM4);
255 SO3Util::sO3FromMu(mx, so3LastMotion);
257 Matrix3x3d::mult(so3LastMotion, so3SensorFromWorld, processMagTempM4);
258 so3SensorFromWorld.set(processMagTempM4);
260 updateCovariancesAfterMotion();
264 magObservationFunctionForNumericalJacobian(so3SensorFromWorld, mNu);
265 SO3Util::sO3FromMu(mx, so3LastMotion);
267 Matrix3x3d::mult(so3LastMotion, so3SensorFromWorld, processMagTempM4);
268 so3SensorFromWorld.set(processMagTempM4);
270 updateCovariancesAfterMotion();
272 sensorTimeStampMag = sensorTimeStamp;
275void OrientationEKF::filterGyroTimestep(
double timestep)
277 float kFilterCoeff = 0.95;
278 float kMinSamples = 10.0;
279 if (!timestepFilterInit)
281 filteredGyroTimestep = timestep;
282 numGyroTimestepSamples = 1;
283 timestepFilterInit =
true;
287 filteredGyroTimestep = (kFilterCoeff * filteredGyroTimestep + (1.0 - kFilterCoeff) * timestep);
288 if (++numGyroTimestepSamples > kMinSamples)
289 gyroFilterValid =
true;
293void OrientationEKF::updateCovariancesAfterMotion()
295 so3LastMotion.transpose(updateCovariancesAfterMotionTempM1);
296 Matrix3x3d::mult(mP, updateCovariancesAfterMotionTempM1, updateCovariancesAfterMotionTempM2);
298 Matrix3x3d::mult(so3LastMotion, updateCovariancesAfterMotionTempM2, mP);
299 so3LastMotion.setIdentity();
302void OrientationEKF::accObservationFunctionForNumericalJacobian(
Matrix3x3d so3SensorFromWorldPred,
Vector3d &result)
304 Matrix3x3d::mult(so3SensorFromWorldPred, down, mh);
305 SO3Util::sO3FromTwoVec(mh, mz, accObservationFunctionForNumericalJacobianTempM);
307 SO3Util::muFromSO3(accObservationFunctionForNumericalJacobianTempM, result);
310void OrientationEKF::magObservationFunctionForNumericalJacobian(
Matrix3x3d so3SensorFromWorldPred,
Vector3d &result)
312 Matrix3x3d::mult(so3SensorFromWorldPred, north, mh);
313 SO3Util::sO3FromTwoVec(mh, mz, magObservationFunctionForNumericalJacobianTempM);
315 SO3Util::muFromSO3(magObservationFunctionForNumericalJacobianTempM, result);
318void OrientationEKF::updateAccelerationCovariance(
double currentAccelNorm)
320 double currentAccelNormChange = fabs(currentAccelNorm - previousAccelNorm);
321 previousAccelNorm = currentAccelNorm;
322 const double kSmoothingFactor = 0.5;
323 movingAverageAccelNormChange = kSmoothingFactor * movingAverageAccelNormChange + (1.0 - kSmoothingFactor) * currentAccelNormChange;
324 const double kMaxAccelNormChange = 0.15;
325 const double kMinAccelNoiseSigma = 0.75;
326 const double kMaxAccelNoiseSigma = 7.0;
327 double normChangeRatio = movingAverageAccelNormChange / kMaxAccelNormChange;
328 double accelNoiseSigma = std::min(kMaxAccelNoiseSigma, kMinAccelNoiseSigma + normChangeRatio * (kMaxAccelNoiseSigma - kMinAccelNoiseSigma));
329 mRaccel.setDiagonal(accelNoiseSigma * accelNoiseSigma);
332double* OrientationEKF::getMatrix()
334 return MatrixFromSo3(so3SensorFromWorld);
337double* OrientationEKF::getPredictedMatrix(
double secondsAfterLastGyroEvent)
339 double dT = secondsAfterLastGyroEvent;
341 pmu.set(lastGyro.x * -dT, lastGyro.y * -dT, lastGyro.z * -dT);
343 SO3Util::sO3FromMu(pmu, so3PredictedMotion);
346 Matrix3x3d::mult(so3PredictedMotion, so3SensorFromWorld, so3PredictedState);
348 return MatrixFromSo3(so3PredictedState);
351double* OrientationEKF::MatrixFromSo3(
Matrix3x3d so3)
353 for (
int r = 0; r < 3; r++)
355 for (
int c = 0; c < 3; c++)
357 rotationMatrix[(4 * c + r)] = so3.get(r, c);
360 double tmp62_61 = (rotationMatrix[11] = 0.0); rotationMatrix[7] = tmp62_61; rotationMatrix[3] = tmp62_61;
361 double tmp86_85 = (rotationMatrix[14] = 0.0); rotationMatrix[13] = tmp86_85; rotationMatrix[12] = tmp86_85;
363 rotationMatrix[15] = 1.0;
365 return rotationMatrix;