17 #include <mrs_msgs/Float64ArrayStamped.h>
18 #include <mrs_msgs/Float64Stamped.h>
19 #include <mrs_msgs/BoolStamped.h>
25 template <
int n_states,
int n_inputs,
int n_measurements,
int n_biases>
30 static const int n = n_states;
31 static const int m = n_inputs;
32 static const int p = n_measurements;
47 typedef Eigen::Matrix<double, n, n>
A_t;
48 typedef Eigen::Matrix<double, n, m>
B_t;
49 typedef Eigen::Matrix<double, p, n>
H_t;
50 typedef Eigen::Matrix<double, n, p>
K_t;
52 typedef Eigen::Matrix<double, p, p>
C_t;
53 typedef Eigen::Matrix<double, n, n>
D_t;
55 using generateA_t = std::function<
A_t(
double)>;
56 using generateB_t = std::function<
B_t(
double)>;
72 const char*
what()
const throw()
74 return "LKF: could not compute matrix inversion!!! Fix your covariances (the measurement's is probably too low...)";
87 JLKF(
const generateA_t& generateA,
const generateB_t& generateB,
const H_t& H,
const ros::NodeHandle& nh,
const double& nis_thr,
88 const double& nis_avg_thr)
89 : m_generateA(generateA),
90 m_generateB(generateB),
94 m_nis_avg_thr(nis_avg_thr)
96 debug_nis_pub = m_nh.advertise<mrs_msgs::Float64ArrayStamped>(
"debug_nis", 1);
117 virtual statecov_t
predict(
const statecov_t& sc,
const u_t& u,
const Q_t& Q,
double dt)
const override
121 A_t A = m_generateA(dt);
122 B_t B = m_generateB(dt);
123 ret.x = state_predict(A, sc.x, B, u);
124 ret.P = covariance_predict(A, sc.P, Q, dt);
125 ret.nis_buffer = sc.nis_buffer;
143 virtual statecov_t
correct(
const statecov_t& sc,
const z_t& z,
const R_t& R)
const override
146 return correction_impl(sc, z, R, H);
152 static R_t invert_W(R_t W)
154 Eigen::ColPivHouseholderQR<R_t> qr(W);
155 if (!qr.isInvertible())
158 R_t ident = R_t::Identity(W.rows(), W.cols());
161 if (!qr.isInvertible())
164 throw inverse_exception();
167 const R_t W_inv = qr.inverse();
174 virtual K_t computeKalmanGain(
const statecov_t& sc, [[maybe_unused]]
const z_t& z,
const R_t& R,
const H_t& H,
double& nis, H_t& H_out,
175 const double& nis_thr,
const double& nis_avg_thr)
const
179 R_t W = H * sc.P * H.transpose() + R;
180 R_t W_inv = invert_W(W);
181 K_t K = sc.P * H.transpose() * W_inv;
182 z_t y = z - (H * sc.x);
185 nis = (y.transpose() * W_inv * y)(0, 0);
188 bool nis_over_thr =
false;
190 double nis_thr_tmp = nis_thr;
192 if (H(0, 0) > 0 && H(0, 3) != 0)
195 mrs_msgs::Float64ArrayStamped msg;
196 msg.header.stamp = sc.stamp;
198 msg.values.push_back(nis);
200 if (sc.nis_buffer !=
nullptr)
203 sc.nis_buffer->push_back(nis);
204 for (
auto it = sc.nis_buffer->begin(); it != sc.nis_buffer->end(); it++)
208 if (*it > nis_thr_tmp)
217 msg.values.push_back(nis_avg);
218 msg.values.push_back(nis_thr_tmp);
220 if (nis > nis_thr_tmp)
224 A_t mask = mask.Zero();
225 for (
int i = n_states - n_biases; i < n_states; i++)
229 const H_t H_bias_only = H * mask;
230 K = H_bias_only.transpose() * invert_W(H_bias_only * H_bias_only.transpose());
234 debug_nis_pub.publish(msg);
237 K_t test = H.transpose() * invert_W(H * H.transpose());
244 template <
int check = n>
245 typename std::enable_if<check >= 0, statecov_t>::type correction_impl(
const statecov_t& sc,
const z_t& z,
const R_t& R,
const H_t& H)
const
251 const K_t K = computeKalmanGain(sc, z, R, H, nis, H_out, m_nis_thr, m_nis_avg_thr);
252 ret.x = sc.x + K * (z - (H * sc.x));
253 ret.P = (P_t::Identity() - (K * H_out)) * sc.P;
254 ret.nis_buffer = sc.nis_buffer;
258 template <
int check = n>
259 typename std::enable_if < check<0, statecov_t>::type correction_impl(
const statecov_t& sc,
const z_t& z,
const R_t& R,
const H_t& H)
const
265 const K_t K = computeKalmanGain(sc, z, R, H, nis, H_out, m_nis_thr, m_nis_avg_thr);
266 ret.x = sc.x + K * (z - (H * sc.x));
267 ret.P = (P_t::Identity(sc.P.rows(), sc.P.cols()) - (K * H_out)) * sc.P;
268 ret.nis_buffer = sc.nis_buffer;
274 ros::NodeHandle m_nh;
275 ros::Publisher debug_nis_pub;
276 std::vector<double> m_nis_window;
278 double m_nis_avg_thr;
282 generateA_t m_generateA;
283 generateB_t m_generateB;
292 static P_t covariance_predict(
const A_t& A,
const P_t& P,
const Q_t& Q,
const double dt)
294 return A * P * A.transpose() + dt*Q;
299 template <
int check = n_inputs>
300 static inline typename std::enable_if<check == 0, x_t>::type state_predict(
const A_t& A,
const x_t& x, [[maybe_unused]]
const B_t& B,
301 [[maybe_unused]]
const u_t& u)
306 template <
int check = n_inputs>
307 static inline typename std::enable_if<check != 0, x_t>::type state_predict(
const A_t& A,
const x_t& x,
const B_t& B,
const u_t& u)
309 return A * x + B * u;