3 #include <boost/math/distributions/chi_squared.hpp> 16 y = cv::Mat_<double> ( 3, 1, 0.0 );
19 C_Y = cv::Mat_<double> ( 3, 3, 0.0 );
22 x = cv::Mat_<double> (
y, cv::Range ( 0, 3 ), cv::Range ( 0, 1 ) );
23 C_X = cv::Mat_<double> (
C_Y, cv::Range ( 0, 3 ), cv::Range ( 0, 3 ) );
29 void EKFSLAM::cycle ( std::vector<Pose2D> &yt, cv::Mat_<double> &C_Yt,
const Command &ut,
const MeasurementConstPtr &zt ) {
33 assert (
y.rows % 3 == 0 &&
y.cols == 1 );
34 assert (
x.rows == 3 &&
x.cols == 1 );
35 assert (
C_Y.rows ==
C_Y.cols &&
C_Y.rows ==
y.rows );
36 assert (
C_X.rows ==
C_X.cols &&
C_X.rows ==
x.rows );
39 if ( zt->getType() == tuw::Measurement::Type::MARKER &&
updateTimestamp ( zt->stamp() ) ) {
48 yt.resize (
y.rows/3 );
49 for (
size_t i = 0; i < yt.size(); i++ ) {
50 yt[i].x() =
y[3*i + 0][0];
51 yt[i].y() =
y[3*i + 1][0];
52 yt[i].theta() =
y[3*i + 2][0];
58 config_ = * ( ( tuw_marker_slam::EKFSLAMConfig* ) config );
62 if ( !
config_.enable_prediction )
return;
65 cv::Matx<double, 2, 2> M = cv::Matx<double, 2, 2> (
config_.alpha_1*ut.v() *ut.v() +
config_.alpha_2*ut.w() *ut.w(), 0,
66 0,
config_.alpha_3*ut.v() *ut.v() +
config_.alpha_4*ut.w() *ut.w() );
70 double r = ut.v() /ut.w();
71 double s = sin (
x[2][0] );
72 double c = cos (
x[2][0] );
73 double s_dt = sin (
x[2][0] + ut.w() *dt );
74 double c_dt = cos (
x[2][0] + ut.w() *dt );
77 cv::Vec<double, 3> dx_;
78 cv::Matx<double, 3, 3> G_x_;
79 cv::Matx<double, 3, 2> G_u;
80 if ( std::abs ( ut.w() ) > __DBL_MIN__ ) {
81 dx_ = cv::Vec<double, 3> ( -r*s + r*s_dt,
84 G_x_ = cv::Matx<double, 3, 3> ( 1, 0, -r*c + r*c_dt,
87 G_u = cv::Matx<double, 3, 2> ( ( -s + s_dt ) /ut.w(), r * ( s - s_dt ) / ut.w() + r*c_dt*dt,
88 ( c - c_dt ) /ut.w(), -r * ( c - c_dt ) / ut.w() + r*s_dt*dt,
91 dx_ = cv::Vec<double, 3> ( ut.v() *dt*c,
94 G_x_ = cv::Matx<double, 3, 3> ( 1, 0, -ut.v() *dt*s,
97 G_u = cv::Matx<double, 3, 2> ( dt*c, -0.5*dt*dt*ut.v() *s,
98 dt*s, 0.5*dt*dt*ut.v() *c,
103 cv::Mat_<double> dx = cv::Mat_<double> ( dx_ );
104 cv::Mat_<double> G_x = cv::Mat_<double> ( G_x_ );
105 cv::Mat_<double> R = cv::Mat_<double> ( G_u * M * G_u.t() );
109 C_X = G_x*
C_X*G_x.t() + R;
110 for (
size_t i = 3; i <
C_Y.cols; i += 3 ) {
112 cv::Mat_<double> C_XM_i = cv::Mat_<double> (
C_Y, cv::Range ( 0, 3 ), cv::Range ( i, i + 3 ) );
113 cv::Mat_<double> C_MX_i = cv::Mat_<double> (
C_Y, cv::Range ( i, i + 3 ), cv::Range ( 0, 3 ) );
121 x[2][0] = angle_normalize ( x[2][0] );
126 c_ij = std::vector<CorrDataPtr> ( zt->size() );
127 c_ji = std::vector<CorrDataPtr> (
y.rows/3 );
132 boost::math::chi_squared chi_squared = boost::math::chi_squared ( 3 );
133 double gamma = boost::math::quantile(chi_squared,
config_.alpha);
136 for (
size_t i = 0; i < zt->size(); i++ ) {
137 if ( zt->operator[] ( i ).ids.size() == 0 ) {
141 std::map<int, size_t>::iterator it =
f_kj.find ( zt->operator[] ( i ).ids[0] );
143 if ( it !=
f_kj.end() ) {
145 size_t j = it->second;
146 assert ( 0 < j && j < c_ji.size() );
150 c->ij = std::pair<size_t, size_t> ( i, j );
154 assert (
c_ij[i] ==
nullptr && c_ji[j] ==
nullptr );
160 z_new.push_back( i );
166 switch (
config_.data_association_mode) {
182 std::vector<size_t> m_reject;
185 for (
size_t i = 0; i <
c_ij.size(); i++ ) {
186 assert (
c_ij[i] ==
nullptr ||
c_ij[i]->ij.first == i );
189 if ( zt->operator[] ( i ).ids.size() > 0)
continue;
190 assert (
c_ij[i] ==
nullptr );
192 double min_d_2 = std::numeric_limits<double>::infinity();
194 for (
size_t j = 1; j <
c_ji.size(); j++ ) {
195 assert (
c_ji[j] ==
nullptr ||
c_ji[j]->ij.second == j );
198 if (
c_ji[j] !=
nullptr && zt->operator[] (
c_ji[j]->ij.first ).ids.size() > 0 )
continue;
202 c->ij = std::pair<size_t, size_t> ( i, j );
206 double d_2 = ( c->v.t() * c->S_inv * c->v ) [0];
214 if ( min_c ==
nullptr || min_d_2 > gamma )
continue;
217 size_t min_i = min_c->ij.first;
218 size_t min_j = min_c->ij.second;
219 assert ( i == min_i && 0 < min_j && min_j <
c_ji.size() );
221 if (
c_ji[min_j] !=
nullptr ) {
223 size_t old_i =
c_ji[min_j]->ij.first;
224 ROS_INFO (
"measurements %lu and %lu correspond both to landmark %lu", old_i, min_i, min_j );
225 if ( zt->operator[] ( old_i ).ids.size() > 0 ) {
227 ROS_INFO (
"reject measurement %lu", min_i );
230 ROS_INFO (
"reject measurement %lu (conservative approach)", i );
232 if (
c_ij[old_i] !=
nullptr ) {
233 ROS_INFO (
"reject measurement %lu (conservative approach)", old_i );
236 std::vector<size_t>::iterator it = std::find (
z_known.begin(),
z_known.end(), old_i );
237 assert ( it !=
z_known.end() );
242 c_ij[old_i] =
nullptr;
243 m_reject.push_back( min_j );
248 assert (
c_ij[min_i] ==
nullptr &&
c_ji[min_j] ==
nullptr );
256 for (
auto j: m_reject)
c_ji[j] =
nullptr;
261 std::vector<size_t> map_i;
262 for (
size_t i = 0; i <
c_ij.size(); i++ ) {
263 assert (
c_ij[i] ==
nullptr ||
c_ij[i]->ij.first == i );
266 if ( zt->operator[] ( i ).ids.size() > 0 )
continue;
267 assert (
c_ij[i] ==
nullptr );
273 if (map_i.size() == 0)
return;
276 std::vector<size_t> map_j;
277 for (
size_t j = 1; j <
c_ji.size(); j++ ) {
278 assert (
c_ji[j] ==
nullptr ||
c_ji[j]->ij.second == j );
281 assert (
c_ji[j] ==
nullptr || zt->operator[] (
c_ji[j]->ij.first ).ids.size() > 0);
282 if (
c_ji[j] !=
nullptr )
continue;
288 if (map_j.size() == 0)
return;
291 std::vector<std::vector<CorrDataPtr>> C = std::vector<std::vector<CorrDataPtr>> ( map_i.size() );
292 cv::Mat_<double> D_2 = cv::Mat_<double> ( map_i.size(), map_j.size() );
293 for (
size_t x = 0;
x < map_i.size();
x++ ) {
294 C[
x] = std::vector<CorrDataPtr> ( map_j.size() );
295 for (
size_t y = 0;
y < map_j.size();
y++ ) {
298 c->ij = std::pair<size_t, size_t> ( map_i[
x], map_j[
y] );
302 double d_2 = ( c->v.t() * c->S_inv * c->v ) [0];
313 for (
size_t k = 0; k < assignment.size(); k++) {
315 size_t x = assignment[k].first;
316 size_t y = assignment[k].second;
318 if ( D_2[x][y] > gamma )
continue;
321 assert ( x < C.size() && y < C[
x].size() );
322 size_t i = C[
x][
y]->ij.first;
323 size_t j = C[
x][
y]->ij.second;
324 assert ( i <
c_ij.size() && 0 < j && j <
c_ji.size() );
327 assert (
c_ij[i] ==
nullptr &&
c_ji[j] ==
nullptr );
335 const size_t i = corr->ij.first;
336 const size_t j = corr->ij.second;
337 assert ( i < zt->size() && 0 < j && j <
y.rows/3 );
340 Pose2D p(
x[0][0],
x[1][0],
x[2][0] );
341 cv::Matx<double, 4, 4> T_x = cv::Matx44d ( p.theta_cos(), -p.theta_sin(), 0, p.x(), p.theta_sin(), p.theta_cos(), 0, p.y(), 0, 0, 1, p.theta(), 0, 0, 0, 1 );
344 cv::Vec<double, 4> homogenious_stage_vector =
append(zt->pose2d().state_vector(), 1);
345 cv::Vec<double, 4> sensor = T_x * homogenious_stage_vector;
346 cv::Vec<double, 2> delta = cv::Vec<double, 2> (
y[3*j + 0][0] - sensor[0],
347 y[3*j + 1][0] - sensor[1] );
348 double q = ( delta.t() * delta ) [0];
351 cv::Vec<double, 3> z_ = cv::Vec<double, 3> ( sqrt ( q ),
352 angle_difference ( atan2 ( delta[1], delta[0] ), sensor[2] ),
353 angle_difference (
y[3*j + 2][0], sensor[2] ) );
356 cv::Vec<double, 3>
z = cv::Vec<double, 3> ( zt->operator[] ( i ).
length,
357 zt->operator[] ( i ).angle ,
358 zt->operator[] ( i ).orientation );
361 corr->v[0] = z[0] - z_[0];
362 corr->v[1] = angle_difference ( z[1], z_[1] );
363 corr->v[2] = angle_difference ( z[2], z_[2] );
368 double s = sin (
x[2][0] );
369 double c = cos (
x[2][0] );
370 double ddeltax = zt->pose2d().x() *s + zt->pose2d().y() *c;
371 double ddeltay = -zt->pose2d().x() *c + zt->pose2d().y() *s;
372 double dx_sq = delta[0]/sqrt ( q );
373 double dy_sq = delta[1]/sqrt ( q );
374 double dx_q = delta[0]/q;
375 double dy_q = delta[1]/q;
378 corr->dx = cv::Matx<double, 3, 3> ( -dx_sq, -dy_sq, dx_sq*ddeltax + dy_sq*ddeltay,
379 dy_q, -dx_q, ddeltay*dx_q - ddeltax*dy_q - 1,
382 corr->dm = cv::Matx<double, 3, 3> ( dx_sq, dy_sq, 0,
390 cv::Matx<double, 3, 3> C_X_ = cv::Mat_<double> (
C_Y, cv::Range ( 0, 3 ), cv::Range ( 0, 3 ) );
391 cv::Matx<double, 3, 3> C_M = cv::Mat_<double> (
C_Y, cv::Range ( 3*j, 3*j + 3 ), cv::Range ( 3*j, 3*j + 3 ) );
392 cv::Matx<double, 3, 3> C_XM = cv::Mat_<double> (
C_Y, cv::Range ( 0, 3 ), cv::Range ( 3*j, 3*j + 3 ) );
394 cv::Matx<double, 3, 3> tmp = corr->dx*C_XM*corr->dm.t();
395 cv::Matx<double, 3, 3> S = corr->dx*C_X_*corr->dx.t() + tmp + tmp.t() + corr->dm*C_M*corr->dm.t() + corr->Q;
396 corr->S_inv = S.inv();
404 double var_l = std::max<double> (
beta_[0]*l*l +
beta_[1], 0 ) + std::max<double> ( std::min<double> ( beta_[2]*a*a + beta_[3], M_PI*M_PI ), 0 ) + std::max<double> ( std::min<double> ( beta_[4]*o*o + beta_[5], M_PI*M_PI ), 0 );
405 double var_a = std::min<double> ( std::max<double> ( beta_[6]/l/l + beta_[7], 0 ) + std::max<double> ( std::min<double> ( beta_[8]*a*a + beta_[9], M_PI*M_PI ), 0 ) + std::max<double> ( std::min<double> ( beta_[10]*o*o + beta_[11], M_PI*M_PI ), 0 ), M_PI*M_PI );
406 double var_o = std::min<double> ( std::max<double> ( beta_[12]*l*l + beta_[13], 0 ) + std::max<double> ( std::min<double> ( beta_[14]*a*a + beta_[15], M_PI*M_PI ), 0 ) + std::max<double> ( std::min<double> ( beta_[16]*o*o + beta_[17], M_PI*M_PI ), 0 ), M_PI*M_PI );
408 return cv::Matx<double, 3,3> ( var_l, 0, 0,
430 if (
z_known.size() == 0 )
return;
433 assert ( i <
c_ij.size() &&
c_ij[i] != nullptr );
436 int j =
c_ij[i]->ij.second;
437 assert ( 0 < j && j <
y.rows/3 &&
c_ji[j] ==
c_ij[i] );
440 cv::Mat_<double> v = cv::Mat_<double> (
c_ij[i]->v );
441 cv::Mat_<double> S_inv = cv::Mat_<double> (
c_ij[i]->S_inv );
444 cv::Mat_<double> K_i = cv::Mat_<double> (
C_Y.rows, 3, 0.0 );
445 for (
size_t k = 0; k < K_i.rows; k += 3 ) {
447 cv::Mat_<double> K_i_k = cv::Mat_<double> ( K_i, cv::Range ( k, k + 3 ), cv::Range ( 0, 3 ) );
450 cv::Matx<double, 3, 3> C_MX_k = cv::Mat_<double> (
C_Y, cv::Range ( k, k + 3 ), cv::Range ( 0, 3 ) );
451 cv::Matx<double, 3, 3> C_M_kj = cv::Mat_<double> (
C_Y, cv::Range ( k, k + 3 ), cv::Range ( 3*j, 3*j + 3 ) );
452 cv::Mat_<double> tmp = cv::Mat_<double> ( C_MX_k*
c_ij[i]->dx.t() + C_M_kj*
c_ij[i]->dm.t() );
457 cv::Mat_<double> I_K_i_H_i = cv::Mat_<double>::eye (
C_Y.rows,
C_Y.cols );
458 for (
size_t k = 0; k <
C_Y.rows; k += 3 ) {
460 cv::Mat_<double> I_K_i_H_i_k0 = cv::Mat_<double> ( I_K_i_H_i, cv::Range ( k, k + 3 ), cv::Range ( 0, 3 ) );
461 cv::Mat_<double> I_K_i_H_i_kj = cv::Mat_<double> ( I_K_i_H_i, cv::Range ( k, k + 3 ), cv::Range ( 3*j, 3*j + 3 ) );
464 cv::Matx<double, 3, 3> K_i_k = cv::Mat_<double> ( K_i, cv::Range ( k, k + 3 ), cv::Range ( 0, 3 ) );
465 I_K_i_H_i_k0 -= cv::Mat_<double> ( K_i_k *
c_ij[i]->dx );
466 I_K_i_H_i_kj -= cv::Mat_<double> ( K_i_k *
c_ij[i]->dm );
474 for (
size_t i = 2; i < y.rows; i += 3 )
475 y[i][0] = angle_normalize ( y[i][0] );
478 C_Y = 0.5 * ( C_Y + C_Y.t() );
483 if (
z_known.size() == 0 )
return;
486 cv::Mat_<double> v = cv::Mat_<double> ( 3*
z_known.size(), 1, 0.0 );
487 cv::Mat_<double> H = cv::Mat_<double> ( 3*
z_known.size(),
C_Y.cols, 0.0 );
488 cv::Mat_<double> R = cv::Mat_<double> ( 3*
z_known.size(), 3*
z_known.size(), 0.0 );
492 assert ( i <
c_ij.size() &&
c_ij[i] != nullptr );
495 int j =
c_ij[i]->ij.second;
496 assert ( 0 < j && j <
y.rows/3 &&
c_ji[j] ==
c_ij[i] );
499 cv::Mat_<double> v_k = cv::Mat_<double> ( v, cv::Range ( k, k + 3 ), cv::Range ( 0, 1 ) );
500 cv::Mat_<double> Hx_kj = cv::Mat_<double> ( H, cv::Range ( k, k + 3 ), cv::Range ( 0, 3 ) );
501 cv::Mat_<double> Hm_kj = cv::Mat_<double> ( H, cv::Range ( k, k + 3 ), cv::Range ( 3*j, 3*j + 3 ) );
502 cv::Mat_<double> R_k = cv::Mat_<double> ( R, cv::Range ( k, k + 3 ), cv::Range ( k, k + 3 ) );
507 v_k += cv::Mat_<double> (
c_ij[i]->v );
508 Hx_kj += cv::Mat_<double> (
c_ij[i]->dx );
509 Hm_kj += cv::Mat_<double> (
c_ij[i]->dm );
510 R_k += cv::Mat_<double> (
c_ij[i]->Q );
515 cv::Mat_<double> S = R + H*
C_Y*H.t();
516 cv::Mat_<double> K =
C_Y*H.t() *S.inv();
520 C_Y = ( cv::Mat_<double>::eye (
C_Y.rows,
C_Y.cols ) - K*H ) *
C_Y;
523 for (
size_t i = 2; i <
y.rows; i += 3 )
524 y[i][0] = angle_normalize (
y[i][0] );
531 if ( !
config_.enable_integration ||
z_new.size() == 0 )
return;
533 for (
auto i:
z_new ) {
535 assert ( zt->operator[] ( i ).ids.size() > 0 );
542 f_kj.insert ( std::pair<int,size_t> ( zt->operator[] ( i ).ids[0], j ) );
543 ROS_INFO (
"new landmark found: marker %d corresponds to landmark %d", zt->operator[] ( i ).ids[0], j );
546 double r = zt->operator[] ( i ).
length;
547 double T_s = sin (
x[2][0] );
548 double T_c = cos (
x[2][0] );
549 double F_s = sin ( zt->operator[] ( i ).angle );
550 double F_c = cos ( zt->operator[] ( i ).angle );
553 Pose2D px(
x[0][0],
x[1][0],
x[2][0] );
554 cv::Matx<double, 4, 4> T_x = cv::Matx44d ( px.theta_cos(), -px.theta_sin(), 0, px.x(), px.theta_sin(), px.theta_cos(), 0, px.y(), 0, 0, 1, px.theta(), 0, 0, 0, 1 );
557 Pose2D pz = zt->pose2d();
558 cv::Matx<double, 4, 4> T_z = cv::Matx44d ( pz.theta_cos(), -pz.theta_sin(), 0, pz.x(), pz.theta_sin(), pz.theta_cos(), 0, pz.y(), 0, 0, 1, pz.theta(), 0, 0, 0, 1 );
561 cv::Matx<double, 4, 4> T_x_T_z = T_x * T_z;
564 cv::Matx<double, 4, 4> T_x_theta = cv::Matx<double, 4, 4> ( -T_s, -T_c, 0, 0,
570 y.resize (
y.rows + 3 );
575 cv::Vec<double, 4> homogenious_stage_vector_i =
append(zt->operator[] ( i ).pose.state_vector(), 1);
576 cv::Vec<double, 4> m_j = T_x_T_z * homogenious_stage_vector_i;
577 y[3*j + 0][0] = m_j[0];
578 y[3*j + 1][0] = m_j[1];
579 y[3*j + 2][0] = m_j[2];
582 cv::Matx<double, 4, 3> F_z = cv::Matx<double, 4, 3> ( F_c, -r*F_s, 0,
588 cv::Mat_<double> G_x = cv::Mat_<double>::eye ( 3, 3 );
589 cv::Vec<double, 4> G_theta = T_x_theta * T_z * homogenious_stage_vector_i;
590 G_x[0][2] = G_theta[0];
591 G_x[1][2] = G_theta[1];
594 cv::Matx<double, 3, 3> G_z = cv::Mat_<double> ( cv::Mat_<double> ( T_x_T_z * F_z ), cv::Range ( 0, 3 ), cv::Range ( 0, 3 ) );
597 cv::Mat_<double> C_M_j = cv::Mat_<double> ( 3,
C_Y.cols, 0.0 );
598 for (
size_t k = 0; k < C_M_j.cols; k += 3 ) {
600 cv::Mat_<double> C_M_jk = cv::Mat_<double> ( C_M_j, cv::Range ( 0, 3 ), cv::Range ( k, k + 3 ) );
601 cv::Mat_<double> C_XM_k = cv::Mat_<double> (
C_Y, cv::Range ( 0, 3 ), cv::Range ( k, k + 3 ) );
608 cv::Mat tmp_v[] = {
C_Y, C_M_j };
609 cv::vconcat ( tmp_v, 2,
C_Y );
613 C_M_j.resize ( C_M_j.rows + 3 );
616 cv::Mat_<double> C_M_jj = cv::Mat_<double> ( C_M_j, cv::Range ( 3*j, 3*j + 3 ), cv::Range ( 0, 3 ) );
619 cv::Mat_<double> R = cv::Mat_<double> ( G_z*Q*G_z.t() );
620 C_M_jj = G_x*
C_X*G_x.t() + R;
623 cv::Mat tmp_h[] = {
C_Y, C_M_j };
624 cv::hconcat ( tmp_h, 2,
C_Y );
627 x = cv::Mat_<double> (
y, cv::Range ( 0, 3 ), cv::Range ( 0, 1 ) );
628 C_X = cv::Mat_<double> (
C_Y, cv::Range ( 0, 3 ), cv::Range ( 0, 3 ) );
cv::Mat_< double > C_Y
mean vector of x
cv::Mat_< double > C_X
covariance matrix of y = (x m1 m2 ...)
void cycle(std::vector< Pose2D > &yt, cv::Mat_< double > &C_Yt, const Command &ut, const MeasurementConstPtr &zt)
std::vector< size_t > z_known
landmark to measurement correspondences (ignore j = 0 since landmark numbering starts with 1) ...
cv::Matx< double, 3, 3 > measurement_noise(const MeasurementMarker::Marker zi)
void NNSF_local(const MeasurementMarkerConstPtr &zt, const double gamma)
std::vector< CorrDataPtr > c_ij
correspondences: f[k] = j <-> marker k corressponds to landmark j
void data_association(const MeasurementMarkerConstPtr &zt)
std::vector< CorrDataPtr > c_ji
measurement to landmark correspondences
std::shared_ptr< CorrData > CorrDataPtr
EKFSLAM(const std::vector< double > beta)
void prediction(const Command &ut)
const std::vector< double > beta_
parameters
boost::posix_time::time_duration duration_last_update_
time of the last processed measurment
cv::Mat_< double > x
mean vector of y = (x m1 m2 ...)
void NNSF_global(const MeasurementMarkerConstPtr &zt, const double gamma)
bool updateTimestamp(const boost::posix_time::ptime &t)
static std::vector< std::pair< size_t, size_t > > find_minimum_assignment(const cv::Mat_< double > costmatrix)
std::shared_ptr< MeasurementMarker const > MeasurementMarkerConstPtr
TFSIMD_FORCE_INLINE const tfScalar & z() const
tuw_marker_slam::EKFSLAMConfig config_
ROSCPP_DECL std::string append(const std::string &left, const std::string &right)
TFSIMD_FORCE_INLINE tfScalar length(const Quaternion &q)
void integration(const MeasurementMarkerConstPtr &zt)
void setConfig(const void *config)
std::map< int, size_t > f_kj
covariance matrix of x
void measurement(const MeasurementMarkerConstPtr &zt, const CorrDataPtr &corr)
cv::Mat_< double > y
parameters for the implemented measurement noise model
std::vector< size_t > z_new
measurements corresponding to known landmarks