Main MRPT website > C++ reference for MRPT 1.9.9
CRangeBearingKFSLAM.cpp
Go to the documentation of this file.
1 /* +------------------------------------------------------------------------+
2  | Mobile Robot Programming Toolkit (MRPT) |
3  | http://www.mrpt.org/ |
4  | |
5  | Copyright (c) 2005-2017, Individual contributors, see AUTHORS file |
6  | See: http://www.mrpt.org/Authors - All rights reserved. |
7  | Released under BSD License. See details in http://www.mrpt.org/License |
8  +------------------------------------------------------------------------+ */
9 
10 #include "slam-precomp.h" // Precompiled headers
11 
12 // ----------------------------------------------------------------------------------------
13 // For the theory behind this implementation, see the technical report in:
14 //
15 // http://www.mrpt.org/6D-SLAM
16 // ----------------------------------------------------------------------------------------
17 
19 #include <mrpt/poses/CPosePDF.h>
23 #include <mrpt/math/utils.h>
25 #include <mrpt/math/wrap2pi.h>
26 #include <mrpt/utils/CTicTac.h>
27 #include <mrpt/system/os.h>
28 
31 #include <mrpt/opengl/CEllipsoid.h>
32 
33 using namespace mrpt::slam;
34 using namespace mrpt::obs;
35 using namespace mrpt::maps;
36 using namespace mrpt::math;
37 using namespace mrpt::poses;
38 using namespace mrpt::utils;
39 using namespace mrpt::system;
40 using namespace mrpt;
41 using namespace std;
42 
43 /*---------------------------------------------------------------
44  Constructor
45  ---------------------------------------------------------------*/
47  : options(),
48  m_action(),
49  m_SF(),
50  m_IDs(),
51  mapPartitioner(),
52  m_SFs(),
53  m_lastPartitionSet()
54 {
55  reset();
56 }
57 
58 /*---------------------------------------------------------------
59  reset
60  ---------------------------------------------------------------*/
62 {
63  m_action.reset();
64  m_SF.reset();
65  m_IDs.clear();
66  m_SFs.clear();
68  m_lastPartitionSet.clear();
69 
70  // -----------------------
71  // INIT KF STATE
72  m_xkk.assign(get_vehicle_size(), 0); // State: 6D pose (x,y,z)=(0,0,0)
73  m_xkk[3] = 1.0; // (qr,qx,qy,qz)=(1,0,0,0)
74 
75  // Initial cov: nullptr diagonal -> perfect knowledge.
77  m_pkk.zeros();
78  // -----------------------
79 
80  // Use SF-based matching (faster & easier for bearing-range observations
81  // with ID).
83 }
84 
85 /*---------------------------------------------------------------
86  Destructor
87  ---------------------------------------------------------------*/
89 /*---------------------------------------------------------------
90  getCurrentRobotPose
91  ---------------------------------------------------------------*/
93  CPose3DQuatPDFGaussian& out_robotPose) const
94 {
96 
97  ASSERT_(m_xkk.size() >= 7);
98 
99  // Copy xyz+quat: (explicitly unroll the loop)
100  out_robotPose.mean.m_coords[0] = m_xkk[0];
101  out_robotPose.mean.m_coords[1] = m_xkk[1];
102  out_robotPose.mean.m_coords[2] = m_xkk[2];
103  out_robotPose.mean.m_quat[0] = m_xkk[3];
104  out_robotPose.mean.m_quat[1] = m_xkk[4];
105  out_robotPose.mean.m_quat[2] = m_xkk[5];
106  out_robotPose.mean.m_quat[3] = m_xkk[6];
107 
108  // and cov:
109  m_pkk.extractMatrix(0, 0, out_robotPose.cov);
110 
111  MRPT_END
112 }
113 
114 /*---------------------------------------------------------------
115  getCurrentRobotPoseMean
116  ---------------------------------------------------------------*/
118 {
120  ASSERTDEB_(m_xkk.size() >= 7)
121  // Copy xyz+quat: (explicitly unroll the loop)
122  q.m_coords[0] = m_xkk[0];
123  q.m_coords[1] = m_xkk[1];
124  q.m_coords[2] = m_xkk[2];
125  q.m_quat[0] = m_xkk[3];
126  q.m_quat[1] = m_xkk[4];
127  q.m_quat[2] = m_xkk[5];
128  q.m_quat[3] = m_xkk[6];
129 
130  return q;
131 }
132 
133 /*---------------------------------------------------------------
134  getCurrentState
135  ---------------------------------------------------------------*/
137  CPose3DQuatPDFGaussian& out_robotPose,
138  std::vector<TPoint3D>& out_landmarksPositions,
139  std::map<unsigned int, CLandmark::TLandmarkID>& out_landmarkIDs,
140  CVectorDouble& out_fullState, CMatrixDouble& out_fullCovariance) const
141 {
142  MRPT_START
143 
144  ASSERT_(size_t(m_xkk.size()) >= get_vehicle_size());
145 
146  // Copy xyz+quat: (explicitly unroll the loop)
147  out_robotPose.mean.m_coords[0] = m_xkk[0];
148  out_robotPose.mean.m_coords[1] = m_xkk[1];
149  out_robotPose.mean.m_coords[2] = m_xkk[2];
150  out_robotPose.mean.m_quat[0] = m_xkk[3];
151  out_robotPose.mean.m_quat[1] = m_xkk[4];
152  out_robotPose.mean.m_quat[2] = m_xkk[5];
153  out_robotPose.mean.m_quat[3] = m_xkk[6];
154 
155  // and cov:
156  m_pkk.extractMatrix(0, 0, out_robotPose.cov);
157 
158  // Landmarks:
159  ASSERT_(((m_xkk.size() - get_vehicle_size()) % get_feature_size()) == 0);
160  size_t i, nLMs = (m_xkk.size() - get_vehicle_size()) / get_feature_size();
161  out_landmarksPositions.resize(nLMs);
162  for (i = 0; i < nLMs; i++)
163  {
164  out_landmarksPositions[i].x =
165  m_xkk[get_vehicle_size() + i * get_feature_size() + 0];
166  out_landmarksPositions[i].y =
167  m_xkk[get_vehicle_size() + i * get_feature_size() + 1];
168  out_landmarksPositions[i].z =
169  m_xkk[get_vehicle_size() + i * get_feature_size() + 2];
170  } // end for i
171 
172  // IDs:
173  out_landmarkIDs = m_IDs.getInverseMap(); // m_IDs_inverse;
174 
175  // Full state:
176  out_fullState.resize(m_xkk.size());
177  for (KFVector::Index i = 0; i < m_xkk.size(); i++)
178  out_fullState[i] = m_xkk[i];
179 
180  // Full cov:
181  out_fullCovariance = m_pkk;
182 
183  MRPT_END
184 }
185 
186 /*---------------------------------------------------------------
187  processActionObservation
188  ---------------------------------------------------------------*/
191 {
192  MRPT_START
193 
194  m_action = action;
195  m_SF = SF;
196 
197  // Sanity check:
198  ASSERT_(
199  m_IDs.size() ==
200  (m_pkk.getColCount() - get_vehicle_size()) / get_feature_size());
201 
202  // ===================================================================================================================
203  // Here's the meat!: Call the main method for the KF algorithm, which will
204  // call all the callback methods as required:
205  // ===================================================================================================================
207 
208  // =============================================================
209  // ADD TO SFs SEQUENCE
210  // =============================================================
212  this->getCurrentRobotPose(q);
213  CPose3DPDFGaussian::Ptr auxPosePDF =
215 
217  {
218  m_SFs.insert(CPose3DPDF::Ptr(auxPosePDF), SF);
219  }
220 
221  // =============================================================
222  // UPDATE THE PARTITION GRAPH EXPERIMENT
223  // =============================================================
225  {
226  if (options.partitioningMethod == 0)
227  {
228  // Use spectral-graph technique:
229  mapPartitioner.addMapFrame(SF, auxPosePDF);
230 
231  vector<vector_uint> partitions;
232  mapPartitioner.updatePartitions(partitions);
233  m_lastPartitionSet = partitions;
234  }
235  else
236  {
237  // Fixed partitions every K observations:
238  vector<vector_uint> partitions;
239  vector_uint tmpCluster;
240 
242  size_t K = options.partitioningMethod;
243 
244  for (size_t i = 0; i < m_SFs.size(); i++)
245  {
246  tmpCluster.push_back(i);
247  if ((i % K) == 0)
248  {
249  partitions.push_back(tmpCluster);
250  tmpCluster.clear();
251  tmpCluster.push_back(i); // This observation "i" is shared
252  // between both clusters
253  }
254  }
255  m_lastPartitionSet = partitions;
256  }
257 
258  printf(
259  "Partitions: %u\n",
260  static_cast<unsigned>(m_lastPartitionSet.size()));
261  }
262 
263  MRPT_END
264 }
265 
266 /** Return the last odometry, as a pose increment.
267  */
269 {
270  CActionRobotMovement2D::Ptr actMov2D =
271  m_action->getBestMovementEstimation();
272  CActionRobotMovement3D::Ptr actMov3D =
273  m_action->getActionByClass<CActionRobotMovement3D>();
274  if (actMov3D && !options.force_ignore_odometry)
275  {
276  return CPose3DQuat(actMov3D->poseChange.mean);
277  }
278  else if (actMov2D && !options.force_ignore_odometry)
279  {
280  CPose2D estMovMean;
281  actMov2D->poseChange->getMean(estMovMean);
282  return CPose3DQuat(CPose3D(estMovMean));
283  }
284  else
285  {
286  return CPose3DQuat();
287  }
288 }
289 
290 /** Must return the action vector u.
291  * \param out_u The action vector which will be passed to OnTransitionModel
292  */
293 void CRangeBearingKFSLAM::OnGetAction(KFArray_ACT& u) const
294 {
295  // Get odometry estimation:
296  const CPose3DQuat theIncr = getIncrementFromOdometry();
297 
298  for (KFArray_ACT::Index i = 0; i < u.size(); i++) u[i] = theIncr[i];
299 }
300 
301 /** This virtual function musts implement the prediction model of the Kalman
302  * filter.
303  */
305  const KFArray_ACT& u, KFArray_VEH& xv, bool& out_skipPrediction) const
306 {
307  MRPT_START
308 
309  // Do not update the vehicle pose & its covariance until we have some
310  // landmarks in the map,
311  // otherwise, we are imposing a lower bound to the best uncertainty from now
312  // on:
313  if (size_t(m_xkk.size()) == get_vehicle_size())
314  {
315  out_skipPrediction = true;
316  }
317 
318  // Current pose: copy xyz+quat
319  CPose3DQuat robotPose = getCurrentRobotPoseMean();
320 
321  // Increment pose: copy xyz+quat (explicitly unroll the loop)
323  odoIncrement.m_coords[0] = u[0];
324  odoIncrement.m_coords[1] = u[1];
325  odoIncrement.m_coords[2] = u[2];
326  odoIncrement.m_quat[0] = u[3];
327  odoIncrement.m_quat[1] = u[4];
328  odoIncrement.m_quat[2] = u[5];
329  odoIncrement.m_quat[3] = u[6];
330 
331  // Pose composition:
332  robotPose += odoIncrement;
333 
334  // Output:
335  for (size_t i = 0; i < xv.static_size; i++) xv[i] = robotPose[i];
336 
337  MRPT_END
338 }
339 
340 /** This virtual function musts calculate the Jacobian F of the prediction
341  * model.
342  */
343 void CRangeBearingKFSLAM::OnTransitionJacobian(KFMatrix_VxV& F) const
344 {
345  MRPT_START
346 
347  // Current pose: copy xyz+quat
348  CPose3DQuat robotPose = getCurrentRobotPoseMean();
349 
350  // Odometry:
351  const CPose3DQuat theIncr = getIncrementFromOdometry();
352 
353  // Compute jacobians:
355 
356  CPose3DQuatPDF::jacobiansPoseComposition(
357  robotPose, // x
358  theIncr, // u
359  F, // df_dx,
360  df_du);
361 
362  MRPT_END
363 }
364 
365 /** This virtual function musts calculate de noise matrix of the prediction
366  * model.
367  */
368 void CRangeBearingKFSLAM::OnTransitionNoise(KFMatrix_VxV& Q) const
369 {
370  MRPT_START
371 
372  // The uncertainty of the 2D odometry, projected from the current position:
373  CActionRobotMovement2D::Ptr act2D = m_action->getBestMovementEstimation();
375  m_action->getActionByClass<CActionRobotMovement3D>();
376 
377  if (act3D && act2D) THROW_EXCEPTION("Both 2D & 3D odometry are present!?!?")
378 
379  CPose3DQuatPDFGaussian odoIncr;
380 
381  if ((!act3D && !act2D) || options.force_ignore_odometry)
382  {
383  // Use constant Q:
384  Q.zeros();
385  ASSERT_(size_t(options.stds_Q_no_odo.size()) == size_t(Q.getColCount()))
386 
387  for (size_t i = 0; i < get_vehicle_size(); i++)
388  Q.set_unsafe(i, i, square(options.stds_Q_no_odo[i]));
389  return;
390  }
391  else
392  {
393  if (act2D)
394  {
395  // 2D odometry:
396  CPosePDFGaussian odoIncr2D;
397  odoIncr2D.copyFrom(*act2D->poseChange);
398  odoIncr = CPose3DQuatPDFGaussian(CPose3DPDFGaussian(odoIncr2D));
399  }
400  else
401  {
402  // 3D odometry:
403  odoIncr = CPose3DQuatPDFGaussian(act3D->poseChange);
404  }
405  }
406 
407  odoIncr.cov(2, 2) += square(options.std_odo_z_additional);
408 
409  // Current pose: copy xyz+quat
410  CPose3DQuat robotPose = getCurrentRobotPoseMean();
411 
412  // Transform from odometry increment to "relative to the robot":
413  odoIncr.changeCoordinatesReference(robotPose);
414 
415  Q = odoIncr.cov;
416 
417  MRPT_END
418 }
419 
421  const vector_size_t& idx_landmarks_to_predict,
422  vector_KFArray_OBS& out_predictions) const
423 {
424  MRPT_START
425 
426  // Mean of the prior of the robot pose:
427  CPose3DQuat robotPose = getCurrentRobotPoseMean();
428 
429  // Get the sensor pose relative to the robot:
431  m_SF->getObservationByClass<CObservationBearingRange>();
432  ASSERTMSG_(
433  obs,
434  "*ERROR*: This method requires an observation of type "
435  "CObservationBearingRange")
436  const CPose3DQuat sensorPoseOnRobot =
437  CPose3DQuat(obs->sensorLocationOnRobot);
438 
439  /* -------------------------------------------
440  Equations, obtained using matlab, of the relative 3D position of a
441  landmark (xi,yi,zi), relative
442  to a robot 6D pose (x0,y0,z0,y,p,r)
443  Refer to technical report "6D EKF derivation...", 2008
444 
445  x0 y0 z0 y p r % Robot's 6D pose
446  x0s y0s z0s ys ps rs % Sensor's 6D pose relative to robot
447  xi yi zi % Absolute 3D landmark coordinates:
448 
449  Hx : dh_dxv -> Jacobian of the observation model wrt the robot pose
450  Hy : dh_dyi -> Jacobian of the observation model wrt each landmark
451  mean position
452 
453  Sizes:
454  h: Lx3
455  Hx: 3Lx6
456  Hy: 3Lx3
457 
458  L=# of landmarks in the map (ALL OF THEM)
459  ------------------------------------------- */
460 
461  const size_t vehicle_size = get_vehicle_size();
462  // const size_t obs_size = get_observation_size();
463  const size_t feature_size = get_feature_size();
464 
465  const CPose3DQuat sensorPoseAbs = robotPose + sensorPoseOnRobot;
466 
467  const size_t N = idx_landmarks_to_predict.size();
468  out_predictions.resize(N);
469  for (size_t i = 0; i < N; i++)
470  {
471  const size_t row_in = feature_size * idx_landmarks_to_predict[i];
472 
473  // Landmark absolute 3D position in the map:
474  const TPoint3D mapEst(
475  m_xkk[vehicle_size + row_in + 0], m_xkk[vehicle_size + row_in + 1],
476  m_xkk[vehicle_size + row_in + 2]);
477 
478  // Generate Range, yaw, pitch
479  // ---------------------------------------------------
480  sensorPoseAbs.sphericalCoordinates(
481  mapEst,
482  out_predictions[i][0], // range
483  out_predictions[i][1], // yaw
484  out_predictions[i][2] // pitch
485  );
486  }
487 
488  MRPT_END
489 }
490 
492  const size_t& idx_landmark_to_predict, KFMatrix_OxV& Hx,
493  KFMatrix_OxF& Hy) const
494 {
495  MRPT_START
496 
497  // Mean of the prior of the robot pose:
498  const CPose3DQuat robotPose = getCurrentRobotPoseMean();
499 
500  // Get the sensor pose relative to the robot:
502  m_SF->getObservationByClass<CObservationBearingRange>();
503  ASSERTMSG_(
504  obs,
505  "*ERROR*: This method requires an observation of type "
506  "CObservationBearingRange")
507  const CPose3DQuat sensorPoseOnRobot =
508  CPose3DQuat(obs->sensorLocationOnRobot);
509 
510  const size_t vehicle_size = get_vehicle_size();
511  // const size_t obs_size = get_observation_size();
512  const size_t feature_size = get_feature_size();
513 
514  // Compute the jacobians, needed below:
515  // const CPose3DQuat sensorPoseAbs= robotPose + sensorPoseOnRobot;
516  CPose3DQuat sensorPoseAbs(UNINITIALIZED_QUATERNION);
518  CMatrixFixedNumeric<kftype, 7, 7> H_senpose_senrelpose(
519  UNINITIALIZED_MATRIX); // Not actually used
520 
521  CPose3DQuatPDF::jacobiansPoseComposition(
522  robotPose, sensorPoseOnRobot, H_senpose_vehpose, H_senpose_senrelpose,
523  &sensorPoseAbs);
524 
525  const size_t row_in = feature_size * idx_landmark_to_predict;
526 
527  // Landmark absolute 3D position in the map:
528  const TPoint3D mapEst(
529  m_xkk[vehicle_size + row_in + 0], m_xkk[vehicle_size + row_in + 1],
530  m_xkk[vehicle_size + row_in + 2]);
531 
532  // The Jacobian wrt the sensor pose must be transformed later on:
533  KFMatrix_OxV Hx_sensor;
534  double obsData[3];
535  sensorPoseAbs.sphericalCoordinates(
536  mapEst,
537  obsData[0], // range
538  obsData[1], // yaw
539  obsData[2], // pitch
540  &Hy, &Hx_sensor);
541 
542  // Chain rule: Hx = d sensorpose / d vehiclepose * Hx_sensor
543  Hx.multiply(Hx_sensor, H_senpose_vehpose);
544 
545  MRPT_END
546 }
547 
548 /** This is called between the KF prediction step and the update step, and the
549  * application must return the observations and, when applicable, the data
550  * association between these observations and the current map.
551  *
552  * \param out_z N vectors, each for one "observation" of length OBS_SIZE, N
553  * being the number of "observations": how many observed landmarks for a map, or
554  * just one if not applicable.
555  * \param out_data_association An empty vector or, where applicable, a vector
556  * where the i'th element corresponds to the position of the observation in the
557  * i'th row of out_z within the system state vector (in the range
558  * [0,getNumberOfLandmarksInTheMap()-1]), or -1 if it is a new map element and
559  * we want to insert it at the end of this KF iteration.
560  * \param in_S The full covariance matrix of the observation predictions (i.e.
561  * the "innovation covariance matrix"). This is a M·O x M·O matrix with M=length
562  * of "in_lm_indices_in_S".
563  * \param in_lm_indices_in_S The indices of the map landmarks (range
564  * [0,getNumberOfLandmarksInTheMap()-1]) that can be found in the matrix in_S.
565  *
566  * This method will be called just once for each complete KF iteration.
567  * \note It is assumed that the observations are independent, i.e. there are NO
568  * cross-covariances between them.
569  */
571  vector_KFArray_OBS& Z, vector_int& data_association,
572  const vector_KFArray_OBS& all_predictions, const KFMatrix& S,
573  const vector_size_t& lm_indices_in_S, const KFMatrix_OxO& R)
574 {
575  MRPT_START
576 
577  // static const size_t vehicle_size = get_vehicle_size();
578  static const size_t obs_size = get_observation_size();
579 
580  // Z: Observations
582 
584  m_SF->getObservationByClass<CObservationBearingRange>();
585  ASSERTMSG_(
586  obs,
587  "*ERROR*: This method requires an observation of type "
588  "CObservationBearingRange")
589 
590  const size_t N = obs->sensedData.size();
591  Z.resize(N);
592 
593  size_t row;
594  for (row = 0, itObs = obs->sensedData.begin();
595  itObs != obs->sensedData.end(); ++itObs, ++row)
596  {
597  // Fill one row in Z:
598  Z[row][0] = itObs->range;
599  Z[row][1] = itObs->yaw;
600  Z[row][2] = itObs->pitch;
601  }
602 
603  // Data association:
604  // ---------------------
605  data_association.assign(N, -1); // Initially, all new landmarks
606 
607  // For each observed LM:
608  vector_size_t obs_idxs_needing_data_assoc;
609  obs_idxs_needing_data_assoc.reserve(N);
610 
611  {
614  size_t row;
615  for (row = 0, itObs = obs->sensedData.begin(),
616  itDA = data_association.begin();
617  itObs != obs->sensedData.end(); ++itObs, ++itDA, ++row)
618  {
619  // Fill data asociation: Using IDs!
620  if (itObs->landmarkID < 0)
621  obs_idxs_needing_data_assoc.push_back(row);
622  else
623  {
625  unsigned int>::iterator itID;
626  if ((itID = m_IDs.find_key(itObs->landmarkID)) != m_IDs.end())
627  *itDA = itID->second; // This row in Z corresponds to the
628  // i'th map element in the state
629  // vector:
630  }
631  }
632  }
633 
634  // ---- Perform data association ----
635  // Only for observation indices in "obs_idxs_needing_data_assoc"
636  if (obs_idxs_needing_data_assoc.empty())
637  {
638  // We don't need to do DA:
640 
641  // Save them for the case the external user wants to access them:
642  for (size_t idxObs = 0; idxObs < data_association.size(); idxObs++)
643  {
644  int da = data_association[idxObs];
645  if (da >= 0)
647  data_association[idxObs];
648  }
649  }
650  else
651  {
652  // Build a Z matrix with the observations that need dat.assoc:
653  const size_t nObsDA = obs_idxs_needing_data_assoc.size();
654 
655  CMatrixTemplateNumeric<kftype> Z_obs_means(nObsDA, obs_size);
656  for (size_t i = 0; i < nObsDA; i++)
657  {
658  const size_t idx = obs_idxs_needing_data_assoc[i];
659  for (unsigned k = 0; k < obs_size; k++)
660  Z_obs_means.get_unsafe(i, k) = Z[idx][k];
661  }
662 
663  // Vehicle uncertainty
665  m_pkk.extractMatrix(0, 0, Pxx);
666 
667  // Build predictions:
668  // ---------------------------
669  const size_t nPredictions = lm_indices_in_S.size();
671 
672  // S is the covariance of the predictions:
674 
675  // The means:
676  m_last_data_association.Y_pred_means.setSize(nPredictions, obs_size);
677  for (size_t q = 0; q < nPredictions; q++)
678  {
679  const size_t i = lm_indices_in_S[q];
680  for (size_t w = 0; w < obs_size; w++)
681  m_last_data_association.Y_pred_means.get_unsafe(q, w) =
682  all_predictions[i][w];
684  i); // for the conversion of indices...
685  }
686 
687  // Do Dat. Assoc :
688  // ---------------------------
689  if (nPredictions)
690  {
691  CMatrixDouble Z_obs_cov = CMatrixDouble(R);
692 
694  Z_obs_means, // Z_obs_cov,
699  true, // Use KD-tree
703 
704  // Return pairings to the main KF algorithm:
707  it != m_last_data_association.results.associations.end(); ++it)
708  data_association[it->first] = it->second;
709  }
710  }
711  // ---- End of data association ----
712 
713  MRPT_END
714 }
715 
716 /** This virtual function musts normalize the state vector and covariance matrix
717  * (only if its necessary).
718  */
720 {
721  MRPT_START
722 
723  // m_xkk[3:6] must be a normalized quaternion:
724  const double T = std::sqrt(
725  square(m_xkk[3]) + square(m_xkk[4]) + square(m_xkk[5]) +
726  square(m_xkk[6]));
727  ASSERTMSG_(T > 0, "Vehicle pose quaternion norm is not >0!!")
728 
729  const double T_ = (m_xkk[3] < 0 ? -1.0 : 1.0) / T; // qr>=0
730  m_xkk[3] *= T_;
731  m_xkk[4] *= T_;
732  m_xkk[5] *= T_;
733  m_xkk[6] *= T_;
734 
735  MRPT_END
736 }
737 
738 /*---------------------------------------------------------------
739  loadOptions
740  ---------------------------------------------------------------*/
742 {
743  // Main
744  options.loadFromConfigFile(ini, "RangeBearingKFSLAM");
745  KF_options.loadFromConfigFile(ini, "RangeBearingKFSLAM_KalmanFilter");
746  // partition algorithm:
747  mapPartitioner.options.loadFromConfigFile(ini, "RangeBearingKFSLAM");
748 }
749 
750 /*---------------------------------------------------------------
751  loadOptions
752  ---------------------------------------------------------------*/
754  const mrpt::utils::CConfigFileBase& source, const std::string& section)
755 {
756  source.read_vector(section, "stds_Q_no_odo", stds_Q_no_odo, stds_Q_no_odo);
757  ASSERT_(stds_Q_no_odo.size() == 7)
758 
760  source.read_float(section, "std_sensor_range", std_sensor_range);
762  source.read_float(
763  section, "std_sensor_yaw_deg", RAD2DEG(std_sensor_yaw)));
765  source.read_float(
766  section, "std_sensor_pitch_deg", RAD2DEG(std_sensor_pitch)));
767 
768  std_odo_z_additional = source.read_float(
769  section, "std_odo_z_additional", std_odo_z_additional);
770 
773 
775 
777 
779  section, "data_assoc_method", data_assoc_method);
781  section, "data_assoc_metric", data_assoc_metric);
783  section, "data_assoc_IC_metric", data_assoc_IC_metric);
784 
787 
789 }
790 
791 /*---------------------------------------------------------------
792  Constructor
793  ---------------------------------------------------------------*/
795  : stds_Q_no_odo(get_vehicle_size(), 0),
796  std_sensor_range(0.01f),
797  std_sensor_yaw(DEG2RAD(0.2f)),
798  std_sensor_pitch(DEG2RAD(0.2f)),
799  std_odo_z_additional(0),
800  doPartitioningExperiment(false),
801  quantiles_3D_representation(3),
802  partitioningMethod(0),
803  data_assoc_method(assocNN),
804  data_assoc_metric(metricMaha),
805  data_assoc_IC_chi2_thres(0.99),
806  data_assoc_IC_metric(metricMaha),
807  data_assoc_IC_ml_threshold(0.0),
808  create_simplemap(false),
809  force_ignore_odometry(false)
810 {
811  stds_Q_no_odo[0] = stds_Q_no_odo[1] = stds_Q_no_odo[2] = 0.10f;
813  0.05f;
814 }
815 
816 /*---------------------------------------------------------------
817  dumpToTextStream
818  ---------------------------------------------------------------*/
820 {
821  out.printf(
822  "\n----------- [CRangeBearingKFSLAM::TOptions] ------------ \n\n");
823 
824  out.printf(
825  "doPartitioningExperiment = %c\n",
826  doPartitioningExperiment ? 'Y' : 'N');
827  out.printf(
828  "partitioningMethod = %i\n", partitioningMethod);
829  out.printf(
830  "data_assoc_method = %s\n",
832  .c_str());
833  out.printf(
834  "data_assoc_metric = %s\n",
836  .c_str());
837  out.printf(
838  "data_assoc_IC_chi2_thres = %.06f\n",
839  data_assoc_IC_chi2_thres);
840  out.printf(
841  "data_assoc_IC_metric = %s\n",
843  .c_str());
844  out.printf(
845  "data_assoc_IC_ml_threshold = %.06f\n",
846  data_assoc_IC_ml_threshold);
847 
848  out.printf("\n");
849 }
850 
852  const KFArray_OBS& in_z, KFArray_FEAT& yn, KFMatrix_FxV& dyn_dxv,
853  KFMatrix_FxO& dyn_dhn) const
854 {
855  MRPT_START
856 
858  m_SF->getObservationByClass<CObservationBearingRange>();
859  ASSERTMSG_(
860  obs,
861  "*ERROR*: This method requires an observation of type "
862  "CObservationBearingRange")
863  const CPose3DQuat sensorPoseOnRobot =
864  CPose3DQuat(obs->sensorLocationOnRobot);
865 
866  // Mean of the prior of the robot pose:
867  const CPose3DQuat robotPose = getCurrentRobotPoseMean();
868 
869  // const CPose3DQuat sensorPoseAbs= robotPose + sensorPoseOnRobot;
870  CPose3DQuat sensorPoseAbs(UNINITIALIZED_QUATERNION);
872  CMatrixFixedNumeric<kftype, 7, 7> dsensorabs_dsenrelpose(
873  UNINITIALIZED_MATRIX); // Not actually used
874 
875  CPose3DQuatPDF::jacobiansPoseComposition(
876  robotPose, sensorPoseOnRobot, dsensorabs_dvehpose,
877  dsensorabs_dsenrelpose, &sensorPoseAbs);
878 
879  kftype hn_r = in_z[0];
880  kftype hn_y = in_z[1];
881  kftype hn_p = in_z[2];
882 
883  kftype chn_y = cos(hn_y);
884  kftype shn_y = sin(hn_y);
885  kftype chn_p = cos(hn_p);
886  kftype shn_p = sin(hn_p);
887 
888  /* -------------------------------------------
889  syms H h_range h_yaw h_pitch real;
890  H=[ h_range ; h_yaw ; h_pitch ];
891 
892  syms X xi_ yi_ zi_ real;
893  xi_ = h_range * cos(h_yaw) * cos(h_pitch);
894  yi_ = h_range * sin(h_yaw) * cos(h_pitch);
895  zi_ = -h_range * sin(h_pitch);
896 
897  X=[xi_ yi_ zi_];
898  jacob_inv_mod=jacobian(X,H)
899  ------------------------------------------- */
900 
901  // The new point, relative to the sensor:
902  const TPoint3D yn_rel_sensor(
903  hn_r * chn_y * chn_p, hn_r * shn_y * chn_p, -hn_r * shn_p);
904 
905  // The Jacobian of the 3D point in the coordinate system of the sensor:
906  /*
907  [ cos(h_pitch)*cos(h_yaw), -h_range*cos(h_pitch)*sin(h_yaw),
908  -h_range*cos(h_yaw)*sin(h_pitch)]
909  [ cos(h_pitch)*sin(h_yaw), h_range*cos(h_pitch)*cos(h_yaw),
910  -h_range*sin(h_pitch)*sin(h_yaw)]
911  [ -sin(h_pitch), 0,
912  -h_range*cos(h_pitch)]
913  */
914  const kftype values_dynlocal_dhn[] = {chn_p * chn_y,
915  -hn_r * chn_p * shn_y,
916  -hn_r * chn_y * shn_p,
917  chn_p * shn_y,
918  hn_r * chn_p * chn_y,
919  -hn_r * shn_p * shn_y,
920  -shn_p,
921  0,
922  -hn_r * chn_p};
923  const KFMatrix_FxO dynlocal_dhn(values_dynlocal_dhn);
924 
925  KFMatrix_FxF jacob_dyn_dynrelsensor(UNINITIALIZED_MATRIX);
926  KFMatrix_FxV jacob_dyn_dsensorabs(UNINITIALIZED_MATRIX);
927 
928  sensorPoseAbs.composePoint(
929  yn_rel_sensor.x, yn_rel_sensor.y,
930  yn_rel_sensor.z, // yn rel. to the sensor
931  yn[0], yn[1], yn[2], // yn in global coords
932  &jacob_dyn_dynrelsensor, &jacob_dyn_dsensorabs);
933 
934  // dyn_dhn = jacob_dyn_dynrelsensor * dynlocal_dhn;
935  dyn_dhn.multiply_AB(jacob_dyn_dynrelsensor, dynlocal_dhn);
936 
937  // dyn_dxv =
938  dyn_dxv.multiply_AB(
939  jacob_dyn_dsensorabs, dsensorabs_dvehpose); // dsensorabs_dsenrelpose);
940 
941  MRPT_END
942 }
943 
944 /** If applicable to the given problem, do here any special handling of adding a
945  * new landmark to the map.
946  * \param in_obsIndex The index of the observation whose inverse sensor is to
947  * be computed. It corresponds to the row in in_z where the observation can be
948  * found.
949  * \param in_idxNewFeat The index that this new feature will have in the state
950  * vector (0:just after the vehicle state, 1: after that,...). Save this number
951  * so data association can be done according to these indices.
952  * \sa OnInverseObservationModel
953  */
955  const size_t in_obsIdx, const size_t in_idxNewFeat)
956 {
957  MRPT_START
958 
960  m_SF->getObservationByClass<CObservationBearingRange>();
961  ASSERTMSG_(
962  obs,
963  "*ERROR*: This method requires an observation of type "
964  "CObservationBearingRange")
965 
966  // ----------------------------------------------
967  // introduce in the lists of ID<->index in map:
968  // ----------------------------------------------
969  ASSERT_(in_obsIdx < obs->sensedData.size())
970 
971  if (obs->sensedData[in_obsIdx].landmarkID >= 0)
972  {
973  // The sensor provides us a LM ID... use it:
974  m_IDs.insert(obs->sensedData[in_obsIdx].landmarkID, in_idxNewFeat);
975  }
976  else
977  {
978  // Features do not have IDs... use indices:
979  m_IDs.insert(in_idxNewFeat, in_idxNewFeat);
980  }
981 
982  MRPT_END
983 }
984 
985 /*---------------------------------------------------------------
986  getAs3DObject
987  ---------------------------------------------------------------*/
989  mrpt::opengl::CSetOfObjects::Ptr& outObj) const
990 {
991  outObj->clear();
992 
993  // ------------------------------------------------
994  // Add the XYZ corner for the current area:
995  // ------------------------------------------------
996  outObj->insert(opengl::stock_objects::CornerXYZ());
997 
998  // 3D ellipsoid for robot pose:
999  CPointPDFGaussian pointGauss;
1000  pointGauss.mean.x(m_xkk[0]);
1001  pointGauss.mean.y(m_xkk[1]);
1002  pointGauss.mean.z(m_xkk[2]);
1004  m_pkk.extractMatrix(0, 0, 3, 3, COV);
1005  pointGauss.cov = COV;
1006 
1007  {
1008  opengl::CEllipsoid::Ptr ellip =
1009  mrpt::make_aligned_shared<opengl::CEllipsoid>();
1010 
1011  ellip->setPose(pointGauss.mean);
1012  ellip->setCovMatrix(pointGauss.cov);
1013  ellip->enableDrawSolid3D(false);
1014  ellip->setQuantiles(options.quantiles_3D_representation);
1015  ellip->set3DsegmentsCount(10);
1016  ellip->setColor(1, 0, 0);
1017 
1018  outObj->insert(ellip);
1019  }
1020 
1021  // 3D ellipsoids for landmarks:
1022  const size_t nLMs = this->getNumberOfLandmarksInTheMap();
1023  for (size_t i = 0; i < nLMs; i++)
1024  {
1025  pointGauss.mean.x(
1026  m_xkk[get_vehicle_size() + get_feature_size() * i + 0]);
1027  pointGauss.mean.y(
1028  m_xkk[get_vehicle_size() + get_feature_size() * i + 1]);
1029  pointGauss.mean.z(
1030  m_xkk[get_vehicle_size() + get_feature_size() * i + 2]);
1031  m_pkk.extractMatrix(
1034  get_feature_size(), COV);
1035  pointGauss.cov = COV;
1036 
1037  opengl::CEllipsoid::Ptr ellip =
1038  mrpt::make_aligned_shared<opengl::CEllipsoid>();
1039 
1040  ellip->setName(format("%u", static_cast<unsigned int>(i)));
1041  ellip->enableShowName(true);
1042  ellip->setPose(pointGauss.mean);
1043  ellip->setCovMatrix(pointGauss.cov);
1044  ellip->enableDrawSolid3D(false);
1045  ellip->setQuantiles(options.quantiles_3D_representation);
1046  ellip->set3DsegmentsCount(10);
1047 
1048  ellip->setColor(0, 0, 1);
1049 
1050  // Set color depending on partitions?
1052  {
1053  // This is done for each landmark:
1054  map<int, bool> belongToPartition;
1055  const CSimpleMap* SFs =
1056  &m_SFs; // mapPartitioner.getSequenceOfFrames();
1057 
1058  for (size_t p = 0; p < m_lastPartitionSet.size(); p++)
1059  {
1060  for (size_t w = 0; w < m_lastPartitionSet[p].size(); w++)
1061  {
1062  // Check if landmark #i is in the SF of
1063  // m_lastPartitionSet[p][w]:
1064  CLandmark::TLandmarkID i_th_ID = m_IDs.inverse(i);
1065 
1066  // Look for the lm_ID in the SF:
1067  CPose3DPDF::Ptr pdf;
1068  CSensoryFrame::Ptr SF_i;
1069  SFs->get(m_lastPartitionSet[p][w], pdf, SF_i);
1070 
1072  SF_i->getObservationByClass<CObservationBearingRange>();
1073 
1074  for (size_t o = 0; o < obs->sensedData.size(); o++)
1075  {
1076  if (obs->sensedData[o].landmarkID == i_th_ID)
1077  {
1078  belongToPartition[p] = true;
1079  break;
1080  }
1081  } // end for o
1082  } // end for w
1083  } // end for p
1084 
1085  // Build label:
1086  string strParts("[");
1087 
1088  for (map<int, bool>::iterator it = belongToPartition.begin();
1089  it != belongToPartition.end(); ++it)
1090  {
1091  if (it != belongToPartition.begin()) strParts += string(",");
1092  strParts += format("%i", it->first);
1093  }
1094 
1095  ellip->setName(ellip->getName() + strParts + string("]"));
1096  }
1097 
1098  outObj->insert(ellip);
1099  }
1100 }
1101 
1102 /*---------------------------------------------------------------
1103  getLastPartitionLandmarks
1104  ---------------------------------------------------------------*/
1106  size_t K, std::vector<vector_uint>& landmarksMembership)
1107 {
1108  // temporary copy:
1109  std::vector<vector_uint> tmpParts = m_lastPartitionSet;
1110 
1111  // Fake "m_lastPartitionSet":
1112 
1113  // Fixed partitions every K observations:
1114  vector<vector_uint> partitions;
1115  vector_uint tmpCluster;
1116 
1117  for (size_t i = 0; i < m_SFs.size(); i++)
1118  {
1119  tmpCluster.push_back(i);
1120  if ((i % K) == 0)
1121  {
1122  partitions.push_back(tmpCluster);
1123  tmpCluster.clear();
1124  tmpCluster.push_back(
1125  i); // This observation "i" is shared between both clusters
1126  }
1127  }
1128  m_lastPartitionSet = partitions;
1129 
1130  // Call the actual method:
1131  getLastPartitionLandmarks(landmarksMembership);
1132 
1133  // Replace copy:
1134  m_lastPartitionSet = tmpParts; //-V519
1135 }
1136 
1137 /*---------------------------------------------------------------
1138  getLastPartitionLandmarks
1139  ---------------------------------------------------------------*/
1141  std::vector<vector_uint>& landmarksMembership) const
1142 {
1143  landmarksMembership.clear();
1144 
1145  // All the computation is made based on "m_lastPartitionSet"
1146 
1147  if (!options.doPartitioningExperiment) return;
1148 
1149  const size_t nLMs = this->getNumberOfLandmarksInTheMap();
1150  for (size_t i = 0; i < nLMs; i++)
1151  {
1152  map<int, bool> belongToPartition;
1153  const CSimpleMap* SFs =
1154  &m_SFs; // mapPartitioner.getSequenceOfFrames();
1155 
1156  for (size_t p = 0; p < m_lastPartitionSet.size(); p++)
1157  {
1158  for (size_t w = 0; w < m_lastPartitionSet[p].size(); w++)
1159  {
1160  // Check if landmark #i is in the SF of
1161  // m_lastPartitionSet[p][w]:
1162  CLandmark::TLandmarkID i_th_ID = m_IDs.inverse(i);
1163 
1164  // Look for the lm_ID in the SF:
1165  CPose3DPDF::Ptr pdf;
1166  CSensoryFrame::Ptr SF_i;
1167  SFs->get(m_lastPartitionSet[p][w], pdf, SF_i);
1168 
1170  SF_i->getObservationByClass<CObservationBearingRange>();
1171 
1172  for (size_t o = 0; o < obs->sensedData.size(); o++)
1173  {
1174  if (obs->sensedData[o].landmarkID == i_th_ID)
1175  {
1176  belongToPartition[p] = true;
1177  break;
1178  }
1179  } // end for o
1180  } // end for w
1181  } // end for p
1182 
1183  // Build membership list:
1184  vector_uint membershipOfThisLM;
1185 
1186  for (map<int, bool>::iterator it = belongToPartition.begin();
1187  it != belongToPartition.end(); ++it)
1188  membershipOfThisLM.push_back(it->first);
1189 
1190  landmarksMembership.push_back(membershipOfThisLM);
1191  } // end for i
1192 }
1193 
1194 /*---------------------------------------------------------------
1195  computeOffDiagonalBlocksApproximationError
1196  ---------------------------------------------------------------*/
1198  const std::vector<vector_uint>& landmarksMembership) const
1199 {
1200  MRPT_START
1201 
1202  // Compute the information matrix:
1204  size_t i;
1205  for (i = 0; i < get_vehicle_size(); i++)
1206  fullCov(i, i) = max(fullCov(i, i), 1e-6);
1207 
1208  CMatrixTemplateNumeric<kftype> H(fullCov.inv());
1209  H.array().abs(); // Replace by absolute values:
1210 
1211  double sumOffBlocks = 0;
1212  unsigned int nLMs = landmarksMembership.size();
1213 
1214  ASSERT_(
1215  (get_vehicle_size() + nLMs * get_feature_size()) ==
1216  fullCov.getColCount());
1217 
1218  for (i = 0; i < nLMs; i++)
1219  {
1220  for (size_t j = i + 1; j < nLMs; j++)
1221  {
1222  // Sum the cross cov. between LM(i) and LM(j)??
1223  // --> Only if there is no common cluster:
1224  if (0 == math::countCommonElements(
1225  landmarksMembership[i], landmarksMembership[j]))
1226  {
1227  size_t col = get_vehicle_size() + i * get_feature_size();
1228  size_t row = get_vehicle_size() + j * get_feature_size();
1229  sumOffBlocks += 2 * H.block(row, col, 2, 2).sum();
1230  }
1231  }
1232  }
1233 
1234  return sumOffBlocks /
1235  H.block(
1237  H.rows() - get_vehicle_size(), H.cols() - get_vehicle_size())
1238  .sum(); // Starting (7,7)-end
1239  MRPT_END
1240 }
1241 
1242 /*---------------------------------------------------------------
1243  reconsiderPartitionsNow
1244  ---------------------------------------------------------------*/
1246 {
1248 
1249  vector<vector_uint> partitions; // A different buffer for making this
1250  // thread-safe some day...
1251 
1252  mapPartitioner.updatePartitions(partitions);
1253 
1254  m_lastPartitionSet = partitions;
1255 }
1256 
1257 /*---------------------------------------------------------------
1258  saveMapAndPathRepresentationAsMATLABFile
1259  ---------------------------------------------------------------*/
1261  const string& fil, float stdCount, const string& styleLandmarks,
1262  const string& stylePath, const string& styleRobot) const
1263 {
1264  FILE* f = os::fopen(fil.c_str(), "wt");
1265  if (!f) return;
1266 
1267  CMatrixDouble cov(2, 2);
1268  CVectorDouble mean(2);
1269 
1270  // Header:
1271  os::fprintf(
1272  f,
1273  "%%--------------------------------------------------------------------"
1274  "\n");
1275  os::fprintf(f, "%% File automatically generated using the MRPT method:\n");
1276  os::fprintf(
1277  f,
1278  "%% "
1279  "'CRangeBearingKFSLAM::saveMapAndPath2DRepresentationAsMATLABFile'\n");
1280  os::fprintf(f, "%%\n");
1281  os::fprintf(f, "%% ~ MRPT ~\n");
1282  os::fprintf(
1283  f, "%% Jose Luis Blanco Claraco, University of Malaga @ 2008\n");
1284  os::fprintf(f, "%% http://www.mrpt.org/ \n");
1285  os::fprintf(
1286  f,
1287  "%%--------------------------------------------------------------------"
1288  "\n");
1289 
1290  // Main code:
1291  os::fprintf(f, "hold on;\n\n");
1292 
1293  const size_t nLMs = this->getNumberOfLandmarksInTheMap();
1294 
1295  for (size_t i = 0; i < nLMs; i++)
1296  {
1297  size_t idx = get_vehicle_size() + i * get_feature_size();
1298 
1299  cov(0, 0) = m_pkk(idx + 0, idx + 0);
1300  cov(1, 1) = m_pkk(idx + 1, idx + 1);
1301  cov(0, 1) = cov(1, 0) = m_pkk(idx + 0, idx + 1);
1302 
1303  mean[0] = m_xkk[idx + 0];
1304  mean[1] = m_xkk[idx + 1];
1305 
1306  // Command to draw the 2D ellipse:
1307  os::fprintf(
1308  f, "%s",
1309  math::MATLAB_plotCovariance2D(cov, mean, stdCount, styleLandmarks)
1310  .c_str());
1311  }
1312 
1313  // Now: the robot path:
1314  // ------------------------------
1315  if (m_SFs.size())
1316  {
1317  os::fprintf(f, "\nROB_PATH=[");
1318  for (size_t i = 0; i < m_SFs.size(); i++)
1319  {
1320  CSensoryFrame::Ptr dummySF;
1321  CPose3DPDF::Ptr pdf3D;
1322  m_SFs.get(i, pdf3D, dummySF);
1323 
1324  CPose3D p;
1325  pdf3D->getMean(p);
1326 
1327  os::fprintf(f, "%.04f %.04f", p.x(), p.y());
1328  if (i < (m_SFs.size() - 1)) os::fprintf(f, ";");
1329  }
1330  os::fprintf(f, "];\n");
1331 
1332  os::fprintf(
1333  f, "plot(ROB_PATH(:,1),ROB_PATH(:,2),'%s');\n", stylePath.c_str());
1334  }
1335 
1336  // The robot pose:
1337  cov(0, 0) = m_pkk(0, 0);
1338  cov(1, 1) = m_pkk(1, 1);
1339  cov(0, 1) = cov(1, 0) = m_pkk(0, 1);
1340 
1341  mean[0] = m_xkk[0];
1342  mean[1] = m_xkk[1];
1343 
1344  os::fprintf(
1345  f, "%s",
1346  math::MATLAB_plotCovariance2D(cov, mean, stdCount, styleRobot).c_str());
1347 
1348  os::fprintf(f, "\naxis equal;\n");
1349  os::fclose(f);
1350 }
1351 
1352 /** Computes A=A-B, which may need to be re-implemented depending on the
1353  * topology of the individual scalar components (eg, angles).
1354  */
1356  KFArray_OBS& A, const KFArray_OBS& B) const
1357 {
1358  A -= B;
1361 }
1362 
1363 /** Return the observation NOISE covariance matrix, that is, the model of the
1364  * Gaussian additive noise of the sensor.
1365  * \param out_R The noise covariance matrix. It might be non diagonal, but
1366  * it'll usually be.
1367  */
1369 {
1370  out_R(0, 0) = square(options.std_sensor_range);
1371  out_R(1, 1) = square(options.std_sensor_yaw);
1372  out_R(2, 2) = square(options.std_sensor_pitch);
1373 }
1374 
1375 /** This will be called before OnGetObservationsAndDataAssociation to allow the
1376  * application to reduce the number of covariance landmark predictions to be
1377  * made.
1378  * For example, features which are known to be "out of sight" shouldn't be
1379  * added to the output list to speed up the calculations.
1380  * \param in_all_prediction_means The mean of each landmark predictions; the
1381  * computation or not of the corresponding covariances is what we're trying to
1382  * determined with this method.
1383  * \param out_LM_indices_to_predict The list of landmark indices in the map
1384  * [0,getNumberOfLandmarksInTheMap()-1] that should be predicted.
1385  * \note This is not a pure virtual method, so it should be implemented only if
1386  * desired. The default implementation returns a vector with all the landmarks
1387  * in the map.
1388  * \sa OnGetObservations, OnDataAssociation
1389  */
1391  const vector_KFArray_OBS& prediction_means,
1392  vector_size_t& out_LM_indices_to_predict) const
1393 {
1395  m_SF->getObservationByClass<CObservationBearingRange>();
1396  ASSERTMSG_(
1397  obs,
1398  "*ERROR*: This method requires an observation of type "
1399  "CObservationBearingRange")
1400 
1401 #define USE_HEURISTIC_PREDICTION
1402 
1403 #ifdef USE_HEURISTIC_PREDICTION
1404  const double sensor_max_range = obs->maxSensorDistance;
1405  const double fov_yaw = obs->fieldOfView_yaw;
1406  const double fov_pitch = obs->fieldOfView_pitch;
1407 
1408  const double max_vehicle_loc_uncertainty =
1409  4 * std::sqrt(
1410  m_pkk.get_unsafe(0, 0) + m_pkk.get_unsafe(1, 1) +
1411  m_pkk.get_unsafe(2, 2));
1412 #endif
1413 
1414  out_LM_indices_to_predict.clear();
1415  for (size_t i = 0; i < prediction_means.size(); i++)
1416  {
1417 #ifndef USE_HEURISTIC_PREDICTION
1418  out_LM_indices_to_predict.push_back(i);
1419 #else
1420  // Heuristic: faster but doesn't work always!
1421  if (prediction_means[i][0] <
1422  (15 + sensor_max_range + max_vehicle_loc_uncertainty +
1423  4 * options.std_sensor_range) &&
1424  fabs(prediction_means[i][1]) <
1425  (DEG2RAD(30) + 0.5 * fov_yaw + 4 * options.std_sensor_yaw) &&
1426  fabs(prediction_means[i][2]) <
1427  (DEG2RAD(30) + 0.5 * fov_pitch + 4 * options.std_sensor_pitch))
1428  {
1429  out_LM_indices_to_predict.push_back(i);
1430  }
1431 #endif
1432  }
1433 }
Nearest-neighbor.
void changeCoordinatesReference(const CPose3DQuat &newReferenceBase)
this = p (+) this.
double x() const
Common members of all points & poses classes.
Definition: CPoseOrPoint.h:135
void copyFrom(const CPosePDF &o) override
Copy operator, translating if necesary (for example, between particles and gaussian representations) ...
void getCurrentRobotPose(mrpt::poses::CPose3DQuatPDFGaussian &out_robotPose) const
Returns the mean & the 7x7 covariance matrix of the robot 6D pose (with rotation as a quaternion)...
std::string MATLAB_plotCovariance2D(const CMatrixFloat &cov22, const CVectorFloat &mean, const float &stdCount, const std::string &style=std::string("b"), const size_t &nEllipsePoints=30)
Generates a string with the MATLAB commands required to plot an confidence interval (ellipse) for a 2...
Definition: math.cpp:1840
void reset()
Reset the state of the SLAM filter: The map is emptied and the robot put back to (0,0,0).
Classes for serialization, sockets, ini-file manipulation, streams, list of properties-values, timewatch, extensions to STL.
mrpt::poses::CPose3DQuat getIncrementFromOdometry() const
Return the last odometry, as a pose increment.
void OnObservationJacobians(const size_t &idx_landmark_to_predict, KFMatrix_OxV &Hx, KFMatrix_OxF &Hy) const
Implements the observation Jacobians and (when applicable) .
std::vector< uint32_t > vector_uint
Definition: types_simple.h:29
Mahalanobis distance.
const_iterator end() const
Definition: bimap.h:52
This namespace provides a OS-independent interface to many useful functions: filenames manipulation...
Definition: math_frwds.h:30
bool force_ignore_odometry
Whether to ignore the input odometry and behave as if there was no odometry at all (default: false) ...
This class stores a sequence of <Probabilistic Pose,SensoryFrame> pairs, thus a "metric map" can be t...
Definition: CSimpleMap.h:35
std::shared_ptr< CPose3DPDFGaussian > Ptr
void markAllNodesForReconsideration()
Mark all nodes for reconsideration in the next call to "updatePartitions", instead of considering jus...
int void fclose(FILE *f)
An OS-independent version of fclose.
Definition: os.cpp:272
void reconsiderPartitionsNow()
The partitioning of the entire map is recomputed again.
void OnPreComputingPredictions(const vector_KFArray_OBS &in_all_prediction_means, vector_size_t &out_LM_indices_to_predict) const
This will be called before OnGetObservationsAndDataAssociation to allow the application to reduce the...
mrpt::math::CMatrixFixedNumeric< double, FEAT_SIZE, VEH_SIZE > KFMatrix_FxV
CPoint3D mean
The mean value.
size_t countCommonElements(const CONTAINER1 &a, const CONTAINER2 &b)
Counts the number of elements that appear in both STL-like containers (comparison through the == oper...
static size_type size()
Definition: CPose3DQuat.h:385
void OnObservationModel(const vector_size_t &idx_landmarks_to_predict, vector_KFArray_OBS &out_predictions) const
#define THROW_EXCEPTION(msg)
GLdouble GLdouble GLdouble GLdouble q
Definition: glext.h:3721
bool useMapMatching
If set to true (default), adjacency matrix is computed from maps matching; otherwise, the method CObservation::likelihoodWith will be called directly from the SFs.
void updatePartitions(std::vector< vector_uint > &partitions)
This method executed only the neccesary part of the partition to take into account the lastest added ...
void processActionObservation(mrpt::obs::CActionCollection::Ptr &action, mrpt::obs::CSensoryFrame::Ptr &SF)
Process one new action and observations to update the map and robot pose estimate.
Scalar * iterator
Definition: eigen_plugins.h:26
This file implements several operations that operate element-wise on individual or pairs of container...
void OnNormalizeStateVector()
This method is called after the prediction and after the update, to give the user an opportunity to n...
Column vector, like Eigen::MatrixX*, but automatically initialized to zeros since construction...
Definition: eigen_frwds.h:42
mrpt::math::CMatrixDouble77 cov
The 7x7 covariance matrix.
void saveMapAndPath2DRepresentationAsMATLABFile(const std::string &fil, float stdCount=3.0f, const std::string &styleLandmarks=std::string("b"), const std::string &stylePath=std::string("r"), const std::string &styleRobot=std::string("r")) const
Save the current state of the filter (robot pose & map) to a MATLAB script which displays all the ele...
mrpt::utils::bimap< mrpt::maps::CLandmark::TLandmarkID, unsigned int > m_IDs
The mapping between landmark IDs and indexes in the Pkk cov.
void OnGetAction(KFArray_ACT &out_u) const
Must return the action vector u.
void OnTransitionJacobian(KFMatrix_VxV &out_F) const
Implements the transition Jacobian .
double computeOffDiagonalBlocksApproximationError(const std::vector< vector_uint > &landmarksMembership) const
Computes the ratio of the missing information matrix elements which are ignored under a certain parti...
void sphericalCoordinates(const mrpt::math::TPoint3D &point, double &out_range, double &out_yaw, double &out_pitch, mrpt::math::CMatrixFixedNumeric< double, 3, 3 > *out_jacob_dryp_dpoint=nullptr, mrpt::math::CMatrixFixedNumeric< double, 3, 7 > *out_jacob_dryp_dpose=nullptr) const
Computes the spherical coordinates of a 3D point as seen from the 6D pose specified by this object...
STL namespace.
void runOneKalmanIteration()
The main entry point, executes one complete step: prediction + update.
const Scalar * const_iterator
Definition: eigen_plugins.h:27
KFMatrix m_pkk
The system full covariance matrix.
mrpt::poses::CPose3DQuat getCurrentRobotPoseMean() const
Get the current robot pose mean, as a 3D+quaternion pose.
int64_t TLandmarkID
The type for the IDs of landmarks.
Definition: CLandmark.h:41
TDataAssocInfo m_last_data_association
Last data association.
void getLastPartitionLandmarks(std::vector< vector_uint > &landmarksMembership) const
Return the partitioning of the landmarks in clusters accoring to the last partition.
GLubyte GLubyte GLubyte GLubyte w
Definition: glext.h:4178
void OnNewLandmarkAddedToMap(const size_t in_obsIdx, const size_t in_idxNewFeat)
If applicable to the given problem, do here any special handling of adding a new landmark to the map...
mrpt::math::CMatrixTemplateNumeric< kftype > Y_pred_means
Declares a class that represents a Probability Density function (PDF) of a 3D pose using a quaternion...
This class allows loading and storing values and vectors of different types from a configuration text...
T square(const T x)
Inline function for the square of a number.
Definition: bits.h:55
mrpt::math::CMatrixFixedNumeric< double, OBS_SIZE, OBS_SIZE > KFMatrix_OxO
void loadFromConfigFile(const mrpt::utils::CConfigFileBase &source, const std::string &section) override
This method load the options from a ".ini"-like file or memory-stored string list.
void composePoint(const double lx, const double ly, const double lz, double &gx, double &gy, double &gz, mrpt::math::CMatrixFixedNumeric< double, 3, 3 > *out_jacobian_df_dpoint=nullptr, mrpt::math::CMatrixFixedNumeric< double, 3, 7 > *out_jacobian_df_dpose=nullptr) const
Computes the 3D point G such as .
Represents a probabilistic 3D (6D) movement.
void loadFromConfigFile(const mrpt::utils::CConfigFileBase &source, const std::string &section) override
This method load the options from a ".ini"-like file or memory-stored string list.
void clear()
Clear the contents of the bi-map.
Definition: bimap.h:68
This base class is used to provide a unified interface to files,memory buffers,..Please see the deriv...
Definition: CStream.h:41
const std::map< VALUE, KEY > & getInverseMap() const
Return a read-only reference to the internal map KEY->VALUES.
Definition: bimap.h:66
void OnTransitionNoise(KFMatrix_VxV &out_Q) const
Implements the transition noise covariance .
void wrapToPiInPlace(T &a)
Modifies the given angle to translate it into the ]-pi,pi] range.
Definition: wrap2pi.h:64
A numeric matrix of compile-time fixed size.
This base provides a set of functions for maths stuff.
Definition: CArrayNumeric.h:19
Declares a class that represents a Probability Density function (PDF) of a 2D pose ...
#define MRPT_END
std::shared_ptr< CActionRobotMovement2D > Ptr
TKF_options KF_options
Generic options for the Kalman Filter algorithm itself.
A helper class that can convert an enum value into its textual representation, and viceversa...
Definition: TEnumType.h:38
int partitioningMethod
Applicable only if "doPartitioningExperiment=true".
TDataAssociationMetric
Different metrics for data association, used in mrpt::slam::data_association For a comparison of both...
mrpt::math::CMatrixDouble33 cov
The 3x3 covariance matrix.
CMatrixTemplateNumeric< double > CMatrixDouble
Declares a matrix of double numbers (non serializable).
void OnSubstractObservationVectors(KFArray_OBS &A, const KFArray_OBS &B) const
Computes A=A-B, which may need to be re-implemented depending on the topology of the individual scala...
mrpt::aligned_containers< KFArray_OBS >::vector_t vector_KFArray_OBS
CONTAINER::Scalar sum(const CONTAINER &v)
Computes the sum of all the elements.
A bidirectional version of std::map, declared as bimap<KEY,VALUE> and which actually contains two std...
Definition: bimap.h:34
const_iterator find_key(const KEY &k) const
Definition: bimap.h:144
std::shared_ptr< CPose3DPDF > Ptr
Definition: CPose3DPDF.h:45
std::shared_ptr< CSetOfObjects > Ptr
Definition: CSetOfObjects.h:32
This namespace contains representation of robot actions and observations.
void loadOptions(const mrpt::utils::CConfigFileBase &ini)
Load options from a ini-like file/text.
bool inverse(const VALUE &v, KEY &out_k) const
Get the key associated the given value, VALUE->KEY, returning false if not present.
Definition: bimap.h:124
std::string format(const char *fmt,...) MRPT_printf_format_check(1
A std::string version of C sprintf.
Definition: format.cpp:19
mrpt::slam::CIncrementalMapPartitioner::TOptions options
CIncrementalMapPartitioner mapPartitioner
Used for map partitioning experiments.
std::shared_ptr< CSensoryFrame > Ptr
Definition: CSensoryFrame.h:56
TDataAssociationMetric data_assoc_IC_metric
Whether to use mahalanobis (->chi2 criterion) vs.
double x
X,Y,Z coordinates.
std::shared_ptr< CActionRobotMovement3D > Ptr
size_t size() const
Returns the count of pairs (pose,sensory data)
Definition: CSimpleMap.cpp:65
A class used to store a 3D pose as a translation (x,y,z) and a quaternion (qr,qx,qy,qz).
Definition: CPose3DQuat.h:48
void get(size_t index, mrpt::poses::CPose3DPDF::Ptr &out_posePDF, mrpt::obs::CSensoryFrame::Ptr &out_SF) const
Access to the i&#39;th pair, first one is index &#39;0&#39;.
Definition: CSimpleMap.cpp:78
#define DEG2RAD
mrpt::maps::CSimpleMap m_SFs
The sequence of all the observations and the robot path (kept for debugging, statistics,etc)
GLsizei const GLchar ** string
Definition: glext.h:4101
double data_assoc_IC_ml_threshold
Only if data_assoc_IC_metric==ML, the log-ML threshold (Default=0.0)
Classes for 2D/3D geometry representation, both of single values and probability density distribution...
Definition: CPoint.h:17
mrpt::math::CArrayDouble< 3 > m_coords
The translation vector [x,y,z].
Definition: CPose3DQuat.h:54
int fprintf(FILE *fil, const char *format,...) noexcept MRPT_printf_format_check(2
An OS-independent version of fprintf.
Definition: os.cpp:405
double kftype
The numeric type used in the Kalman Filter (default=double)
void OnGetObservationNoise(KFMatrix_OxO &out_R) const
Return the observation NOISE covariance matrix, that is, the model of the Gaussian additive noise of ...
#define MRPT_START
mrpt::math::CArrayNumeric< double, OBS_SIZE > KFArray_OBS
#define RAD2DEG
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
uint64_t TLandmarkID
Unique IDs for landmarks.
#define ASSERTDEB_(f)
Defines an assertion mechanism - only when compiled in debug.
std::shared_ptr< CActionCollection > Ptr
mrpt::obs::CSensoryFrame::Ptr m_SF
Set up by processActionObservation.
void getCurrentState(mrpt::poses::CPose3DQuatPDFGaussian &out_robotPose, std::vector< mrpt::math::TPoint3D > &out_landmarksPositions, std::map< unsigned int, mrpt::maps::CLandmark::TLandmarkID > &out_landmarkIDs, mrpt::math::CVectorDouble &out_fullState, mrpt::math::CMatrixDouble &out_fullCovariance) const
Returns the complete mean and cov.
mrpt::slam::CRangeBearingKFSLAM::TOptions options
A class used to store a 2D pose, including the 2D coordinate point and a heading (phi) angle...
Definition: CPose2D.h:40
const float R
A class used to store a 3D pose (a 3D translation + a rotation in 3D).
Definition: CPose3D.h:88
std::shared_ptr< CObservationBearingRange > Ptr
void loadFromConfigFile(const mrpt::utils::CConfigFileBase &iniFile, const std::string &section) override
This method load the options from a ".ini"-like file or memory-stored string list.
CSetOfObjects::Ptr CornerXYZ(float scale=1.0)
Returns three arrows representing a X,Y,Z 3D corner.
std::map< observation_index_t, prediction_index_t > associations
For each observation (with row index IDX_obs in the input "Z_observations"), its association in the p...
mrpt::math::CMatrixFixedNumeric< double, FEAT_SIZE, OBS_SIZE > KFMatrix_FxO
GLenum GLenum GLvoid * row
Definition: glext.h:3576
This observation represents a number of range-bearing value pairs, each one for a detected landmark...
void dumpToTextStream(mrpt::utils::CStream &out) const override
This method should clearly display all the contents of the structure in textual form, sending it to a CStream.
void OnTransitionModel(const KFArray_ACT &in_u, KFArray_VEH &inout_x, bool &out_skipPrediction) const
Implements the transition model .
void getAs3DObject(mrpt::opengl::CSetOfObjects::Ptr &outObj) const
Returns a 3D representation of the landmarks in the map and the robot 3D position according to the cu...
GLsizei GLsizei GLchar * source
Definition: glext.h:4082
#define ASSERT_(f)
void OnGetObservationsAndDataAssociation(vector_KFArray_OBS &out_z, vector_int &out_data_association, const vector_KFArray_OBS &in_all_predictions, const KFMatrix &in_S, const vector_size_t &in_lm_indices_in_S, const KFMatrix_OxO &in_R)
This is called between the KF prediction step and the update step, and the application must return th...
Declares a class that represents a Probability Density function (PDF) of a 3D pose ...
mrpt::math::CMatrixFixedNumeric< double, OBS_SIZE, VEH_SIZE > KFMatrix_OxV
std::vector< size_t > vector_size_t
Definition: types_simple.h:26
void OnInverseObservationModel(const KFArray_OBS &in_z, KFArray_FEAT &out_yn, KFMatrix_FxV &out_dyn_dxv, KFMatrix_FxO &out_dyn_dhn) const
If applicable to the given problem, this method implements the inverse observation model needed to ex...
bool create_simplemap
Whether to fill m_SFs (default=false)
FILE * fopen(const char *fileName, const char *mode) noexcept
An OS-independent version of fopen.
Definition: os.cpp:254
std::vector< int32_t > vector_int
Definition: types_simple.h:24
mrpt::math::CMatrixFixedNumeric< double, VEH_SIZE, VEH_SIZE > KFMatrix_VxV
Eigen::Matrix< typename MATRIX::Scalar, MATRIX::ColsAtCompileTime, MATRIX::ColsAtCompileTime > cov(const MATRIX &v)
Computes the covariance matrix from a list of samples in an NxM matrix, where each row is a sample...
Definition: ops_matrices.h:148
bool doPartitioningExperiment
If set to true (default=false), map will be partitioned using the method stated by partitioningMethod...
mrpt::math::CQuaternionDouble m_quat
The quaternion.
Definition: CPose3DQuat.h:56
void insert(const KEY &k, const VALUE &v)
Insert a new pair KEY<->VALUE in the bi-map.
Definition: bimap.h:75
#define MRPT_LOAD_CONFIG_VAR( variableName, variableType, configFileObject, sectionNameStr)
An useful macro for loading variables stored in a INI-like file under a key with the same name that t...
Lightweight 3D point.
mrpt::math::CMatrixTemplateNumeric< kftype > Y_pred_covs
unsigned int addMapFrame(const mrpt::obs::CSensoryFrame::Ptr &frame, const mrpt::poses::CPosePDF::Ptr &robotPose2D)
void insert(const mrpt::poses::CPose3DPDF *in_posePDF, const mrpt::obs::CSensoryFrame &in_SF)
Add a new pair to the sequence.
Definition: CSimpleMap.cpp:177
mrpt::obs::CActionCollection::Ptr m_action
Set up by processActionObservation.
TDataAssociationMethod
Different algorithms for data association, used in mrpt::slam::data_association.
virtual ~CRangeBearingKFSLAM()
Destructor:
mrpt::math::CArrayNumeric< double, FEAT_SIZE > KFArray_FEAT
std::vector< vector_uint > m_lastPartitionSet
#define ASSERTMSG_(f, __ERROR_MSG)
GLfloat GLfloat p
Definition: glext.h:6305
double data_assoc_IC_chi2_thres
Threshold in [0,1] for the chi2square test for individual compatibility between predictions and obser...
void data_association_full_covariance(const mrpt::math::CMatrixDouble &Z_observations_mean, const mrpt::math::CMatrixDouble &Y_predictions_mean, const mrpt::math::CMatrixDouble &Y_predictions_cov, TDataAssociationResults &results, const TDataAssociationMethod method=assocJCBB, const TDataAssociationMetric metric=metricMaha, const double chi2quantile=0.99, const bool DAT_ASOC_USE_KDTREE=true, const std::vector< prediction_index_t > &predictions_IDs=std::vector< prediction_index_t >(), const TDataAssociationMetric compatibilityTestMetric=metricMaha, const double log_ML_compat_test_threshold=0.0)
Computes the data-association between the prediction of a set of landmarks and their observations...
EIGEN_STRONG_INLINE double mean() const
Computes the mean of the entire matrix.
void clear()
Remove all stored pairs.
Definition: CSimpleMap.cpp:70
A gaussian distribution for 3D points.
virtual int printf(const char *fmt,...) MRPT_printf_format_check(2
Writes a string to the stream in a textual form.
Definition: CStream.cpp:597
void getLastPartitionLandmarksAsIfFixedSubmaps(size_t K, std::vector< vector_uint > &landmarksMembership)
For testing only: returns the partitioning as "getLastPartitionLandmarks" but as if a fixed-size subm...
mrpt::math::CVectorFloat stds_Q_no_odo
A 7-length vector with the std.
std::shared_ptr< CEllipsoid > Ptr
Definition: CEllipsoid.h:49
size_t size() const
Definition: bimap.h:61



Page generated by Doxygen 1.8.14 for MRPT 1.9.9 Git: ae4571287 Thu Nov 23 00:06:53 2017 +0100 at dom oct 27 23:51:55 CET 2019