![](/media/cache/img/default_profile.jpg.50x50_q85.jpg)
Delta Robot example
Dependencies: BufferedSerial Eigen
Fork of TCPSocket_Example by
ESKF.cpp
- Committer:
- je310
- Date:
- 2018-10-15
- Revision:
- 5:01e1e68309ae
File content as of revision 5:01e1e68309ae:
#include <ESKF.h> ESKF::ESKF(Matrix<float, 19,1> initialState, float sig2_a_n_, float sig2_omega_n_,float sig2_a_w_, float sig2_omega_w_){ trueState = initialState; sig2_a_n = sig2_a_n_; sig2_omega_n = sig2_omega_n_; sig2_a_w = sig2_a_w_; sig2_omega_w = sig2_omega_w_; //Build F_i, F_i.setZero(); F_i.block(3,0,12,12).setIdentity(); } ESKF::ESKF(){ } Matrix<float, 19,1> ESKF::makeState(Vector3f p,Vector3f v, Quaternionf q, Vector3f a_b, Vector3f omega_b,Vector3f g ){ } void ESKF::updateStateIMU(Vector3f a, Vector3f omega, float delta_t){ } Matrix<float, 3,3> ESKF::getRotationMatrixFromState(Matrix<float, 19,1> state){ Matrix<float,4,1> mat = state.block(6,0,4,1); Quaternionf quat(mat); return quat.matrix(); } Matrix<float,3,3> ESKF::getSkew(Vector3f in){ Matrix<float,3,3> out; out << 0, -in(2), in(1), in(2), 0, -in(0), -in(1), in(0), 0; return out; } Matrix<float,3,3> ESKF::AngAxToMat(Vector3f in){ float angle = in.norm(); Vector3f axis = in.normalized(); if(angle == 0) axis = Vector3f(1,0,0); AngleAxisf angAx(angle,axis); return angAx.toRotationMatrix(); } void ESKF::predictionUpdate(Vector3f a, Vector3f omega, float delta_t){ // build F_x Matrix<float, 3,3> I3 , I3dt; F_x = F_x.Zero(18,18); //page 59 I3 = I3.Identity(); I3dt = delta_t * I3; F_x.block(0,0,3,3) = I3; F_x.block(3,3,3,3) = I3; F_x.block(9,9,3,3) = I3; F_x.block(12,12,3,3) = I3; F_x.block(15,15,3,3) = I3; F_x.block(0,3,3,3) = I3dt; F_x.block(3,15,3,3) = I3dt; F_x.block(6,12,3,3) = -I3dt; Matrix<float, 3,3> rotation; rotation = getRotationMatrixFromState(nominalState); F_x.block(3,9,3,3) = -rotation*delta_t; // for the 2nd row and 3rd column F_x.block(3,6,3,3) = - rotation * getSkew(a - nominalState.block(9,0,3,1)) * delta_t; // for the 3rd row 3rd column F_x.block(6,6,3,3) = AngAxToMat((omega - nominalState.block(12,0,3,1))*delta_t).transpose(); // build Q_i, this is only a diagonal matrix augmented by a scalar, so could be more efficient to for loop the relevant entries. Q_i.setZero(); Q_i.block(0,0,3,3) = delta_t * delta_t * sig2_a_n * I3 ; Q_i.block(3,3,3,3) = I3 * sig2_omega_n * delta_t * delta_t; Q_i.block(6,6,3,3) = I3 * sig2_a_w * delta_t; Q_i.block(9,9,3,3) = I3 * sig2_omega_w * delta_t; //probably unnecessary copying here. Need to check if things are done inplace or otherwise. //.eval should fix this issue P = (F_x*P*F_x.transpose() + F_i*Q_i*F_i.transpose()).eval(); //this line is apparently not needed, according to the document. // I suspect it only meant in the first iteration????? //Matrix<float,18,18> errorState_new = F_x * errorState; //errorState = errorState_new; } Matrix<float,19,1> ESKF::measurementFunc(Matrix<float,19,1> in){ Matrix<float,19,1> func; func << 1,1,1 ,0,0,0 ,1,1,1,1 ,0,0,0 ,0,0,0 ,0,0,0; return (in.array()*func.array()).matrix(); } void ESKF::composeTrueState(){ } // this function puts the errorstate into the nominal state. as per page 62 void ESKF::injectObservedError(){ Matrix<float,19,1> newState; // compose position newState.block(0,0,3,1) = nominalState.block(0,0,3,1) + errorState.block(0,0,3,1); // compose Velocity newState.block(3,0,3,1) = nominalState.block(3,0,3,1) + errorState.block(3,0,3,1); // compose Quaternion - probably this can be done in less lines. Matrix<float,3,1> angAxMat = errorState.block(6,0,3,1); AngleAxisf AngAx(angAxMat.norm(),angAxMat.normalized()); Quaternionf qError(AngAx); Matrix<float,4,1> qMat = nominalState.block(6,0,4,1); Quaternionf qNom(qMat); newState.block(6,0,4,1) = (qNom*qError).coeffs(); //compose accelerometer drift newState.block(10,0,3,1) = nominalState.block(10,0,3,1) + errorState.block(9,0,3,1); //compose gyro drift. newState.block(13,0,3,1) = nominalState.block(13,0,3,1) + errorState.block(12,0,3,1); //compose gravity. (I don't think it changes anything.) newState.block(16,0,3,1) = nominalState.block(16,0,3,1) + errorState.block(15,0,3,1); //update the nominal state (I am doing a copy to be sure there is no aliasing problems etc) nominalState = newState; } void ESKF::resetError(){ // set the errorState to zero errorState.Zero(); // set up G matrix, can be simply an identity or with a more compicated term for the rotation section. G.setIdentity(); Matrix<float,3,3> rotCorrection; rotCorrection = - getSkew(0.5*errorState.block(6,0,3,1)); G.block(6,6,3,3) = (G.block(6,6,3,3) + rotCorrection).eval(); P = (G * P * G.transpose()).eval(); } // this function is called when you have a reference to correct the error state, in this case a mocap system. void ESKF::observeErrorState(Vector3f pos, Quaternionf rot){ Matrix<float,19,1> y; y.Zero(); y.block(0,0,3,1) = pos; y.block(6,0,4,1) <<rot.x() , rot.y() , rot.z() , rot.w(); // setup X_dx, essensially an identity, with some quaternion stuff in the middle. Optimise by initilising everything elsewhere. X_dx.Zero(); Matrix<float, 6,6> I6; I6 = I6.Identity(); Matrix<float,9,9> I9; I9 = I9.Identity(); X_dx.block(0,0,6,6) = I6; X_dx.block(10,9,9,9) = I9; Matrix<float,4,1> q(nominalState.block(6,0,4,1)); // getting quaternion, though in a mat, so we can divide by 2. q = q/2; X_dx.block(6,6,4,3) << -q.x() , -q.y() , -q.z(), q.w() , -q.z() , q.y(), q.z() , q.w() , -q.x(), -q.y() , q.x() , q.w(); // then set up H_x, though this is not told to us directly, it is described as: /*"Here, Hx , ∂h∂xt|x is the standard Jacobian of h() with respect to its own argument (i.e., the Jacobian one would use in a regular EKF). This first part of the chain rule depends on the measurement function of the particular sensor used, and is not presented here.*/ //I believe that if I am only providing position and a quaternion then the position part will be an identity, the quaternion part will be identity? H_x = H_x.Identity(); //compose the two halves of the hessian H = H_x*X_dx; Matrix<float,19,19> V; // the covariance of the measurement function. V.Zero(); K = P * H.transpose() * (H*P*H.transpose() + V).inverse(); Matrix<float,18,1> d_x_hat; composeTrueState(); d_x_hat = K *(y - measurementFunc(trueState)); Matrix<float,18,18> I18; I18 = I18.Identity(); P = ((I18 - K*H)*P).eval(); injectObservedError(); resetError(); }