ekf_slam.cpp
Go to the documentation of this file.
3 #include <boost/math/distributions/chi_squared.hpp>
4 
5 using namespace tuw;
6 
7 EKFSLAM::EKFSLAM( const std::vector<double> beta ) :
8  SLAMTechnique ( EKF ),
9  beta_ ( beta ) {
10 }
11 
12 void EKFSLAM::init() {
13  reset_ = false;
14 
15  // initial mean
16  y = cv::Mat_<double> ( 3, 1, 0.0 );
17 
18  // initial covariance
19  C_Y = cv::Mat_<double> ( 3, 3, 0.0 );
20 
21  // initialize covariance submatrices pointing to the same data (no copy!)
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 ) );
24 
25  // reset marker landmark correspondences
26  f_kj.clear();
27 }
28 
29 void EKFSLAM::cycle ( std::vector<Pose2D> &yt, cv::Mat_<double> &C_Yt, const Command &ut, const MeasurementConstPtr &zt ) {
30  if ( reset_ ) init();
31 
32  // invariance check
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 );
37 
38  prediction ( ut );
39  if ( zt->getType() == tuw::Measurement::Type::MARKER && updateTimestamp ( zt->stamp() ) ) {
40  MeasurementMarkerConstPtr z = std::static_pointer_cast<MeasurementMarker const> ( zt );
41 
42  data_association ( z );
43  update();
44  integration ( z );
45  }
46 
47  // implicit return
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];
53  }
54  C_Yt = C_Y;
55 }
56 
57 void EKFSLAM::setConfig ( const void *config ) {
58  config_ = * ( ( tuw_marker_slam::EKFSLAMConfig* ) config );
59 }
60 
61 void EKFSLAM::prediction ( const Command &ut ) {
62  if ( !config_.enable_prediction ) return;
63 
64  // control noise
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() );
67 
68  // pre-calculate needed data
69  double dt = duration_last_update_.total_microseconds() /1000000.0;
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 );
75 
76  // calculate update and its derivatives (= jacobian matrices)
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,
82  r*c - r*c_dt,
83  ut.w() *dt );
84  G_x_ = cv::Matx<double, 3, 3> ( 1, 0, -r*c + r*c_dt,
85  0, 1, -r*s + r*s_dt,
86  0, 0, 1 );
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,
89  0, dt );
90  } else {
91  dx_ = cv::Vec<double, 3> ( ut.v() *dt*c,
92  ut.v() *dt*s,
93  0 );
94  G_x_ = cv::Matx<double, 3, 3> ( 1, 0, -ut.v() *dt*s,
95  0, 1, ut.v() *dt*c,
96  0, 0, 1 );
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,
99  0, dt );
100  }
101 
102  // convert from Matx/Vec to Mat_ in order to use +/* operations on submatrices
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() );
106 
107  // update mean and covariance
108  x = x + dx;
109  C_X = G_x*C_X*G_x.t() + R;
110  for ( size_t i = 3; i < C_Y.cols; i += 3 ) {
111  // references to submatrices
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 ) );
114 
115  // calculation & matrix update
116  C_XM_i = G_x*C_XM_i;
117  C_MX_i = C_XM_i.t();
118  }
119 
120  // normalize angle
121  x[2][0] = angle_normalize ( x[2][0] );
122 }
123 
125  // initialization
126  c_ij = std::vector<CorrDataPtr> ( zt->size() );
127  c_ji = std::vector<CorrDataPtr> ( y.rows/3 );
128  z_known.clear();
129  z_new.clear();
130 
131  // gamma is a threshold such that 100*(1-alpha)% of true measurements are rejected
132  boost::math::chi_squared chi_squared = boost::math::chi_squared ( 3 );
133  double gamma = boost::math::quantile(chi_squared, config_.alpha);
134 
135  // find correspondences based on measurement marker IDs
136  for ( size_t i = 0; i < zt->size(); i++ ) {
137  if ( zt->operator[] ( i ).ids.size() == 0 ) {
138  // invalid measurement
139  } else {
140  // valid measurement
141  std::map<int, size_t>::iterator it = f_kj.find ( zt->operator[] ( i ).ids[0] );
142 
143  if ( it != f_kj.end() ) {
144  // known landmark j
145  size_t j = it->second;
146  assert ( 0 < j && j < c_ji.size() );
147 
148  // create correspondence data
149  CorrDataPtr c = std::make_shared<CorrData>();
150  c->ij = std::pair<size_t, size_t> ( i, j );
151  measurement ( zt, c );
152 
153  // document founded correspondence
154  assert ( c_ij[i] == nullptr && c_ji[j] == nullptr );
155  c_ij[i] = c;
156  c_ji[j] = c;
157  z_known.push_back(i);
158  } else {
159  // new landmark
160  z_new.push_back( i );
161  }
162  }
163  }
164 
165  // complement correspondences based on probability
166  switch (config_.data_association_mode) {
167  case ID:
168  // Nothing to do anymore
169  break;
170  case NNSF_LOCAL:
171  NNSF_local ( zt, gamma );
172  break;
173  case NNSF_GLOBAL:
174  NNSF_global ( zt, gamma );
175  break;
176  default:
177  assert ( false );
178  }
179 }
180 
181 void EKFSLAM::NNSF_local ( const MeasurementMarkerConstPtr &zt, const double gamma ) {
182  std::vector<size_t> m_reject;
183 
184  // find correspondences based on Mahalanobis distance
185  for ( size_t i = 0; i < c_ij.size(); i++ ) {
186  assert ( c_ij[i] == nullptr || c_ij[i]->ij.first == i );
187 
188  // consider only measurements without marker IDs
189  if ( zt->operator[] ( i ).ids.size() > 0) continue;
190  assert ( c_ij[i] == nullptr );
191 
192  double min_d_2 = std::numeric_limits<double>::infinity();
193  CorrDataPtr min_c = nullptr;
194  for ( size_t j = 1; j < c_ji.size(); j++ ) {
195  assert ( c_ji[j] == nullptr || c_ji[j]->ij.second == j );
196 
197  // consider only landmarks without correspondences based on measurement marker IDs
198  if ( c_ji[j] != nullptr && zt->operator[] ( c_ji[j]->ij.first ).ids.size() > 0 ) continue;
199 
200  // create correspondence data
201  CorrDataPtr c = std::make_shared<CorrData>();
202  c->ij = std::pair<size_t, size_t> ( i, j );
203  measurement ( zt, c );
204 
205  // calculate Mahalanobis distance: d = sqrt(v^T S^(-1) v)
206  double d_2 = ( c->v.t() * c->S_inv * c->v ) [0];
207  if (d_2 < min_d_2) {
208  min_d_2 = d_2;
209  min_c = c;
210  }
211  }
212 
213  // update correspondences
214  if ( min_c == nullptr || min_d_2 > gamma ) continue;
215 
216  // new (possible) correspondence found
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() );
220 
221  if ( c_ji[min_j] != nullptr ) {
222  // landmark already correspond to another measurement
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 ) {
226  // old correspondence is fix -> reject current measurement
227  ROS_INFO ( "reject measurement %lu", min_i );
228  } else {
229  // old correspondence is just probably -> reject both measurements
230  ROS_INFO ( "reject measurement %lu (conservative approach)", i );
231 
232  if ( c_ij[old_i] != nullptr ) {
233  ROS_INFO ( "reject measurement %lu (conservative approach)", old_i );
234 
235  // remove already added old measurement from known measurements
236  std::vector<size_t>::iterator it = std::find ( z_known.begin(), z_known.end(), old_i );
237  assert ( it != z_known.end() );
238  z_known.erase( it );
239 
240  // reset old correspondence c_ij at the first time and
241  // remember old correspondence c_ji for later reset
242  c_ij[old_i] = nullptr;
243  m_reject.push_back( min_j );
244  }
245  }
246  } else {
247  // document founded correspondence
248  assert ( c_ij[min_i] == nullptr && c_ji[min_j] == nullptr );
249  c_ij[min_i] = min_c;
250  c_ji[min_j] = min_c;
251  z_known.push_back( min_i );
252  }
253  }
254 
255  // reset correspondences c_ji found but invalidated again during corresponde update
256  for (auto j: m_reject) c_ji[j] = nullptr;
257 }
258 
259 void EKFSLAM::NNSF_global ( const MeasurementMarkerConstPtr &zt, const double gamma ) {
260  // book keeping: measurements
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 );
264 
265  // consider only measurements without marker IDs
266  if ( zt->operator[] ( i ).ids.size() > 0 ) continue;
267  assert ( c_ij[i] == nullptr );
268 
269  map_i.push_back(i);
270  }
271 
272  // no further correspondences possible
273  if (map_i.size() == 0) return;
274 
275  // book keeping: landmarks
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 );
279 
280  // consider only landmarks without correspondences based on measurement marker IDs
281  assert ( c_ji[j] == nullptr || zt->operator[] ( c_ji[j]->ij.first ).ids.size() > 0);
282  if ( c_ji[j] != nullptr ) continue;
283 
284  map_j.push_back(j);
285  }
286 
287  // no further correspondences possible
288  if (map_j.size() == 0) return;
289 
290  // build assignment matrix (Mahalanobis distance)
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++ ) {
296  // create correspondence data
297  CorrDataPtr c = std::make_shared<CorrData>();
298  c->ij = std::pair<size_t, size_t> ( map_i[x], map_j[y] );
299  measurement ( zt, c );
300 
301  // calculate Mahalanobis distance: d = sqrt(v^T S^(-1) v)
302  double d_2 = ( c->v.t() * c->S_inv * c->v ) [0];
303  assert ( d_2 >= 0 );
304 
305  // book keeping: correspondence data
306  C[x][y] = c;
307  D_2[x][y] = d_2;
308  }
309  }
310 
311  // update correspondences
312  std::vector<std::pair<size_t, size_t>> assignment = Munkre::find_minimum_assignment(D_2);
313  for (size_t k = 0; k < assignment.size(); k++) {
314  // book keeping measurement and landmark
315  size_t x = assignment[k].first;
316  size_t y = assignment[k].second;
317 
318  if ( D_2[x][y] > gamma ) continue;
319 
320  // new correspondence found
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() );
325 
326  // document founded correspondence
327  assert ( c_ij[i] == nullptr && c_ji[j] == nullptr );
328  c_ij[i] = C[x][y];
329  c_ji[j] = C[x][y];
330  z_known.push_back( i );
331  }
332 }
333 
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 );
338 
339  // transformation matrix from robot coordinates in global coordinates
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 );
342 
343  // measurement prediction of landmark j
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];
349 
350  // predicted measurement
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] ) );
354 
355  // obtained measurement
356  cv::Vec<double, 3> z = cv::Vec<double, 3> ( zt->operator[] ( i ).length,
357  zt->operator[] ( i ).angle ,
358  zt->operator[] ( i ).orientation );
359 
360  // compare predicted and obtainend measurement
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] );
364  //corr->v[2] = 0;
365 
366  // pre-calculate needed data
367  assert ( q > 0 );
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;
376 
377  //H_ij = (dx 0 .. 0 dm 0 .. 0)
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,
380  0, 0, -1 );
381 
382  corr->dm = cv::Matx<double, 3, 3> ( dx_sq, dy_sq, 0,
383  -dy_q, dx_q, 0,
384  0, 0, 1 );
385 
386  // measurement noise
387  corr->Q = measurement_noise( zt->operator[]( i ) );
388 
389  // S_i = H_i*C_Y*H_i^T + Q
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 ) );
393 
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();
397 }
398 
400  double l = zi.length;
401  double a = zi.angle;
402  double o = zi.orientation;
403 
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 );
407 
408  return cv::Matx<double, 3,3> ( var_l, 0, 0,
409  0, var_a, 0,
410  0, 0, var_o );
411 }
412 
414  switch (config_.update_mode) {
415  case None:
416  // Nothing to do
417  break;
418  case Single:
419  update_single();
420  break;
421  case Combined:
422  update_combined();
423  break;
424  default:
425  assert ( false );
426  }
427 }
428 
430  if ( z_known.size() == 0 ) return;
431 
432  for ( auto i: z_known ) {
433  assert ( i < c_ij.size() && c_ij[i] != nullptr );
434 
435  // obtained measurement i corresponds to landmark j
436  int j = c_ij[i]->ij.second;
437  assert ( 0 < j && j < y.rows/3 && c_ji[j] == c_ij[i] );
438 
439  // fetch needed data
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 );
442 
443  // K_i = C_Y*H_i^T*S_i^(-1)
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 ) {
446  // reference to submatrix
447  cv::Mat_<double> K_i_k = cv::Mat_<double> ( K_i, cv::Range ( k, k + 3 ), cv::Range ( 0, 3 ) );
448 
449  // calculation & matrix update
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() );
453  K_i_k = tmp * S_inv;
454  }
455 
456  // I - K_i*H_i
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 ) {
459  // references to submatrices
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 ) );
462 
463  // calculation & matrix update
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 );
467  }
468 
469  // update mean and covariance
470  y = y + K_i*v;
471  C_Y = I_K_i_H_i*C_Y;
472 
473  // normalize angles
474  for ( size_t i = 2; i < y.rows; i += 3 )
475  y[i][0] = angle_normalize ( y[i][0] );
476 
477  // re-establish diagonalization
478  C_Y = 0.5 * ( C_Y + C_Y.t() );
479  }
480 }
481 
483  if ( z_known.size() == 0 ) return;
484 
485  // initialization
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 );
489  size_t k = 0;
490 
491  for ( auto i: z_known ) {
492  assert ( i < c_ij.size() && c_ij[i] != nullptr );
493 
494  // obtained measurement i corresponds to landmark j
495  int j = c_ij[i]->ij.second;
496  assert ( 0 < j && j < y.rows/3 && c_ji[j] == c_ij[i] );
497 
498  // references to submatrices
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 ) );
503 
504  // calculation & update
505  // H = (H_1j H_2j' ... H_Nj'')^T
506  // H_kj = (dx_kj 0 .. 0 dm_kj 0 .. 0)
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 );
511  k += 3;
512  }
513 
514  // calculation
515  cv::Mat_<double> S = R + H*C_Y*H.t();
516  cv::Mat_<double> K = C_Y*H.t() *S.inv();
517 
518  // update mean and covariance
519  y = y + K*v;
520  C_Y = ( cv::Mat_<double>::eye ( C_Y.rows, C_Y.cols ) - K*H ) *C_Y;
521 
522  // normalize angles
523  for ( size_t i = 2; i < y.rows; i += 3 )
524  y[i][0] = angle_normalize ( y[i][0] );
525 
526  // re-establish diagonalization
527  C_Y = 0.5 * ( C_Y + C_Y.t() );
528 }
529 
531  if ( !config_.enable_integration || z_new.size() == 0 ) return;
532 
533  for ( auto i: z_new ) {
534  // consider only measurements with marker IDs for new landmarks
535  assert ( zt->operator[] ( i ).ids.size() > 0 );
536 
537  // measurement noise
538  cv::Matx<double, 3,3> Q = measurement_noise( zt->operator[]( i ) );
539 
540  // number landmarks found in ascending order
541  int j = y.rows/3;
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 );
544 
545  // pre-calculate needed data
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 );
551 
552  // transformation matrix from robot coordinates in global coordinates
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 );
555 
556  // transformation matrix from sensor coordinates in robot coordinates
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 );
559 
560  // transformation matrix from sensor coordinates in global coordinates
561  cv::Matx<double, 4, 4> T_x_T_z = T_x * T_z;
562 
563  // derivation of T_x by theta
564  cv::Matx<double, 4, 4> T_x_theta = cv::Matx<double, 4, 4> ( -T_s, -T_c, 0, 0,
565  T_c, -T_s, 0, 0,
566  0, 0, 0, 1,
567  0, 0, 0, 0 );
568 
569  // adapt size of global mean
570  y.resize ( y.rows + 3 );
571 
572  // update gloabl mean with mean of landmark j: m_j = g(x, z) = T_x(x) * T_z * f(z)
573  // with f(z) = (r*cos(a), r*sin(a), o), r..radius, a..alpha, o..orientation
574  // (function f transforms measurements from spheric coordinates into cartesian coordinates)
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];
580 
581  // jacobian matrix of f
582  cv::Matx<double, 4, 3> F_z = cv::Matx<double, 4, 3> ( F_c, -r*F_s, 0,
583  F_s, r*F_c, 0,
584  0, 0, 1,
585  0, 0, 0 );
586 
587  // jacobian matrix of G in respect to x
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];
592 
593  // jacobian matrix of G in respect to z
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 ) );
595 
596  // create horizontal covariance of landmark j
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 ) {
599  // references to submatrices
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 ) );
602 
603  // calculation & matrix update
604  C_M_jk = G_x*C_XM_k;
605  }
606 
607  // append horizontal covariance of landmark j to global covariance
608  cv::Mat tmp_v[] = { C_Y, C_M_j };
609  cv::vconcat ( tmp_v, 2, C_Y );
610 
611  // create vertical covariance of landmark j
612  C_M_j = C_M_j.t();
613  C_M_j.resize ( C_M_j.rows + 3 );
614 
615  // reference to submatrix
616  cv::Mat_<double> C_M_jj = cv::Mat_<double> ( C_M_j, cv::Range ( 3*j, 3*j + 3 ), cv::Range ( 0, 3 ) );
617 
618  // calculation & matrix update
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;
621 
622  // append vertical covariance of landmark j to global covariance
623  cv::Mat tmp_h[] = { C_Y, C_M_j };
624  cv::hconcat ( tmp_h, 2, C_Y );
625 
626  // reinitialize covariance submatrices pointing to the same data (no copy!)
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 ) );
629  }
630 }
cv::Mat_< double > C_Y
mean vector of x
Definition: ekf_slam.h:160
cv::Mat_< double > C_X
covariance matrix of y = (x m1 m2 ...)
Definition: ekf_slam.h:161
void cycle(std::vector< Pose2D > &yt, cv::Mat_< double > &C_Yt, const Command &ut, const MeasurementConstPtr &zt)
Definition: ekf_slam.cpp:29
std::vector< size_t > z_known
landmark to measurement correspondences (ignore j = 0 since landmark numbering starts with 1) ...
Definition: ekf_slam.h:168
cv::Matx< double, 3, 3 > measurement_noise(const MeasurementMarker::Marker zi)
Definition: ekf_slam.cpp:399
void NNSF_local(const MeasurementMarkerConstPtr &zt, const double gamma)
Definition: ekf_slam.cpp:181
void update()
Definition: ekf_slam.cpp:413
XmlRpcServer s
std::vector< CorrDataPtr > c_ij
correspondences: f[k] = j <-> marker k corressponds to landmark j
Definition: ekf_slam.h:165
void data_association(const MeasurementMarkerConstPtr &zt)
Definition: ekf_slam.cpp:124
std::vector< CorrDataPtr > c_ji
measurement to landmark correspondences
Definition: ekf_slam.h:166
std::shared_ptr< CorrData > CorrDataPtr
Definition: ekf_slam.h:73
EKFSLAM(const std::vector< double > beta)
Definition: ekf_slam.cpp:7
void prediction(const Command &ut)
Definition: ekf_slam.cpp:61
const std::vector< double > beta_
parameters
Definition: ekf_slam.h:156
boost::posix_time::time_duration duration_last_update_
time of the last processed measurment
void update_single()
Definition: ekf_slam.cpp:429
Definition: ekf_slam.h:8
void update_combined()
Definition: ekf_slam.cpp:482
cv::Mat_< double > x
mean vector of y = (x m1 m2 ...)
Definition: ekf_slam.h:159
#define ROS_INFO(...)
void NNSF_global(const MeasurementMarkerConstPtr &zt, const double gamma)
Definition: ekf_slam.cpp:259
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)
Definition: munkre.cpp:5
std::shared_ptr< MeasurementMarker const > MeasurementMarkerConstPtr
TFSIMD_FORCE_INLINE const tfScalar & z() const
tuw_marker_slam::EKFSLAMConfig config_
Definition: ekf_slam.h:155
ROSCPP_DECL std::string append(const std::string &left, const std::string &right)
TFSIMD_FORCE_INLINE tfScalar length(const Quaternion &q)
void init()
Definition: ekf_slam.cpp:12
void integration(const MeasurementMarkerConstPtr &zt)
Definition: ekf_slam.cpp:530
void setConfig(const void *config)
Definition: ekf_slam.cpp:57
std::map< int, size_t > f_kj
covariance matrix of x
Definition: ekf_slam.h:163
void measurement(const MeasurementMarkerConstPtr &zt, const CorrDataPtr &corr)
Definition: ekf_slam.cpp:334
cv::Mat_< double > y
parameters for the implemented measurement noise model
Definition: ekf_slam.h:158
std::vector< size_t > z_new
measurements corresponding to known landmarks
Definition: ekf_slam.h:169


tuw_marker_slam
Author(s): Markus Macsek
autogenerated on Mon Jun 10 2019 15:39:09