00001 /* +---------------------------------------------------------------------------+ 00002 | The Mobile Robot Programming Toolkit (MRPT) C++ library | 00003 | | 00004 | http://mrpt.sourceforge.net/ | 00005 | | 00006 | Copyright (C) 2005-2010 University of Malaga | 00007 | | 00008 | This software was written by the Machine Perception and Intelligent | 00009 | Robotics Lab, University of Malaga (Spain). | 00010 | Contact: Jose-Luis Blanco <jlblanco@ctima.uma.es> | 00011 | | 00012 | This file is part of the MRPT project. | 00013 | | 00014 | MRPT is free software: you can redistribute it and/or modify | 00015 | it under the terms of the GNU General Public License as published by | 00016 | the Free Software Foundation, either version 3 of the License, or | 00017 | (at your option) any later version. | 00018 | | 00019 | MRPT is distributed in the hope that it will be useful, | 00020 | but WITHOUT ANY WARRANTY; without even the implied warranty of | 00021 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 00022 | GNU General Public License for more details. | 00023 | | 00024 | You should have received a copy of the GNU General Public License | 00025 | along with MRPT. If not, see <http://www.gnu.org/licenses/>. | 00026 | | 00027 +---------------------------------------------------------------------------+ */ 00028 #ifndef CRangeBearingKFSLAM_H 00029 #define CRangeBearingKFSLAM_H 00030 00031 #include <mrpt/utils/CDebugOutputCapable.h> 00032 #include <mrpt/math/CVectorTemplate.h> 00033 #include <mrpt/math/CMatrixTemplateNumeric.h> 00034 #include <mrpt/utils/CConfigFileBase.h> 00035 #include <mrpt/utils/CLoadableOptions.h> 00036 #include <mrpt/opengl.h> 00037 #include <mrpt/bayes/CKalmanFilterCapable.h> 00038 00039 #include <mrpt/utils/safe_pointers.h> 00040 #include <mrpt/utils/bimap.h> 00041 00042 #include <mrpt/slam/CSensoryFrame.h> 00043 #include <mrpt/slam/CActionCollection.h> 00044 #include <mrpt/slam/CObservationBearingRange.h> 00045 #include <mrpt/poses/CPoint3D.h> 00046 #include <mrpt/poses/CPose3DPDFGaussian.h> 00047 #include <mrpt/slam/CLandmark.h> 00048 #include <mrpt/slam/CSensFrameProbSequence.h> 00049 #include <mrpt/slam/CIncrementalMapPartitioner.h> 00050 #include <mrpt/slam/data_association.h> 00051 00052 namespace mrpt 00053 { 00054 namespace slam 00055 { 00056 using namespace mrpt::bayes; 00057 00058 /** An implementation of EKF-based SLAM with range-bearing sensors, odometry, a full 6D robot pose, and 3D landmarks. 00059 * The main method is "processActionObservation" which processes pairs of action/observation. 00060 * 00061 * The following Wiki page describes an front-end application based on this class: 00062 * http://babel.isa.uma.es/mrpt/index.php/Application:kf-slam 00063 * 00064 * \sa An implementation for 2D only: CRangeBearingKFSLAM2D 00065 */ 00066 class MRPTDLLIMPEXP CRangeBearingKFSLAM : 00067 public bayes::CKalmanFilterCapable<6 /* x y z yaw pitch roll*/,3 /* range yaw pitch */, 3 /* x y z */, 6 /* Ax Ay Az Ayaw Apitch Aroll */ > 00068 // <size_t VEH_SIZE, size_t OBS_SIZE, size_t FEAT_SIZE, size_t ACT_SIZE, size typename kftype = double> 00069 { 00070 public: 00071 /** Constructor. 00072 */ 00073 CRangeBearingKFSLAM( ); 00074 00075 /** Destructor: 00076 */ 00077 virtual ~CRangeBearingKFSLAM(); 00078 00079 void reset(); //!< Reset the state of the SLAM filter: The map is emptied and the robot put back to (0,0,0). 00080 00081 /** Process one new action and observations to update the map and robot pose estimate. See the description of the class at the top of this page. 00082 * \param action May contain odometry 00083 * \param SF The set of observations, must contain at least one CObservationBearingRange 00084 */ 00085 void processActionObservation( 00086 CActionCollectionPtr &action, 00087 CSensoryFramePtr &SF ); 00088 00089 /** Returns the complete mean and cov. 00090 * \param out_robotPose The mean & 6x6 covariance matrix of the robot 6D pose 00091 * \param out_landmarksPositions One entry for each of the M landmark positions (3D). 00092 * \param out_landmarkIDs Each element[index] (for indices of out_landmarksPositions) gives the corresponding landmark ID. 00093 * \param out_fullState The complete state vector (6+3M). 00094 * \param out_fullCovariance The full (6+3M)x(6+3M) covariance matrix of the filter. 00095 * \sa getCurrentRobotPose 00096 */ 00097 void getCurrentState( 00098 CPose3DPDFGaussian &out_robotPose, 00099 std::vector<CPoint3D> &out_landmarksPositions, 00100 std::map<unsigned int,CLandmark::TLandmarkID> &out_landmarkIDs, 00101 CVectorDouble &out_fullState, 00102 CMatrixDouble &out_fullCovariance 00103 ) const; 00104 00105 /** Returns the mean & 6x6 covariance matrix of the robot 6D pose. 00106 * \sa getCurrentState 00107 */ 00108 void getCurrentRobotPose( 00109 CPose3DPDFGaussian &out_robotPose ) const; 00110 00111 /** Returns a 3D representation of the landmarks in the map and the robot 3D position according to the current filter state. 00112 * \param out_objects 00113 */ 00114 void getAs3DObject( mrpt::opengl::CSetOfObjectsPtr &outObj ) const; 00115 00116 /** Load options from a ini-like file/text 00117 */ 00118 void loadOptions( const mrpt::utils::CConfigFileBase &ini ); 00119 00120 /** The options for the algorithm 00121 */ 00122 struct MRPTDLLIMPEXP TOptions : utils::CLoadableOptions 00123 { 00124 /** Default values 00125 */ 00126 TOptions(); 00127 00128 /** Load from a config file/text 00129 */ 00130 void loadFromConfigFile( 00131 const mrpt::utils::CConfigFileBase &source, 00132 const std::string §ion); 00133 00134 /** This method must display clearly all the contents of the structure in textual form, sending it to a CStream. 00135 */ 00136 void dumpToTextStream(CStream &out) const; 00137 00138 /** A 6-length vector with the std. deviation of the transition model in (x,y,z,yaw,pitch,roll) used only when there is no odometry (if there is odo, its uncertainty values will be used instead); x y z: In meters, yaw pitch roll: radians (but in degrees when loading from a configuration ini-file!) 00139 */ 00140 vector_float stds_Q_no_odo; 00141 00142 /** The std. deviation of the sensor (for the matrix R in the kalman filters), in meters and radians. 00143 */ 00144 float std_sensor_range, std_sensor_yaw, std_sensor_pitch; 00145 00146 /** Additional std. dev. to sum to the motion model in the z axis (useful when there is only 2D odometry and we want to put things hard to the algorithm) (default=0) 00147 */ 00148 float std_odo_z_additional; 00149 00150 /** If set to true (default=false), map will be partitioned using the method stated by partitioningMethod 00151 */ 00152 bool doPartitioningExperiment; 00153 00154 /** Default = 3 00155 */ 00156 float quantiles_3D_representation; 00157 00158 /** Applicable only if "doPartitioningExperiment=true". 00159 * 0: Automatically detect partition through graph-cut. 00160 * N>=1: Cut every "N" observations. 00161 */ 00162 int partitioningMethod; 00163 00164 // Data association: 00165 TDataAssociationMethod data_assoc_method; 00166 TDataAssociationMetric data_assoc_metric; 00167 double data_assoc_IC_chi2_thres; //!< Threshold in [0,1] for the chi2square test for individual compatibility between predictions and observations (default: 0.99) 00168 TDataAssociationMetric data_assoc_IC_metric; //!< Whether to use mahalanobis (->chi2 criterion) vs. Matching likelihood. 00169 double data_assoc_IC_ml_threshold;//!< Only if data_assoc_IC_metric==ML, the log-ML threshold (Default=0.0) 00170 00171 bool create_simplemap; //!< Whether to fill m_SFs (default=false) 00172 } options; 00173 00174 /** Information for data-association: 00175 * \sa getLastDataAssociation 00176 */ 00177 struct MRPTDLLIMPEXP TDataAssocInfo 00178 { 00179 TDataAssocInfo() : 00180 Y_pred_means(0,0), 00181 Y_pred_covs(0,0) 00182 { 00183 } 00184 00185 void clear() { 00186 results.clear(); 00187 predictions_IDs.clear(); 00188 newly_inserted_landmarks.clear(); 00189 } 00190 00191 // Predictions from the map: 00192 CMatrixTemplateNumeric<kftype> Y_pred_means,Y_pred_covs; 00193 mrpt::vector_size_t predictions_IDs; 00194 00195 /** Map from the 0-based index within the last observation and the landmark 0-based index in the map (the robot-map state vector) 00196 Only used for stats and so. */ 00197 std::map<size_t,size_t> newly_inserted_landmarks; 00198 00199 // DA results: 00200 TDataAssociationResults results; 00201 }; 00202 00203 /** Returns a read-only reference to the information on the last data-association */ 00204 const TDataAssocInfo & getLastDataAssociation() const { 00205 return m_last_data_association; 00206 } 00207 00208 00209 /** Return the last partition of the sequence of sensoryframes (it is NOT a partition of the map!!) 00210 * Only if options.doPartitioningExperiment = true 00211 * \sa getLastPartitionLandmarks 00212 */ 00213 void getLastPartition( std::vector<vector_uint> &parts ) 00214 { 00215 parts = m_lastPartitionSet; 00216 } 00217 00218 /** Return the partitioning of the landmarks in clusters accoring to the last partition. 00219 * Note that the same landmark may appear in different clusters (the partition is not in the space of landmarks) 00220 * Only if options.doPartitioningExperiment = true 00221 * \param landmarksMembership The i'th element of this vector is the set of clusters to which the i'th landmark in the map belongs to (landmark index != landmark ID !!). 00222 * \sa getLastPartition 00223 */ 00224 void getLastPartitionLandmarks( std::vector<vector_uint> &landmarksMembership ) const; 00225 00226 /** For testing only: returns the partitioning as "getLastPartitionLandmarks" but as if a fixed-size submaps (size K) were have been used. 00227 */ 00228 void getLastPartitionLandmarksAsIfFixedSubmaps( size_t K, std::vector<vector_uint> &landmarksMembership ); 00229 00230 00231 /** Computes the ratio of the missing information matrix elements which are ignored under a certain partitioning of the landmarks. 00232 * \sa getLastPartitionLandmarks, getLastPartitionLandmarksAsIfFixedSubmaps 00233 */ 00234 double computeOffDiagonalBlocksApproximationError( const std::vector<vector_uint> &landmarksMembership ) const; 00235 00236 00237 /** The partitioning of the entire map is recomputed again. 00238 * Only when options.doPartitioningExperiment = true. 00239 * This can be used after changing the parameters of the partitioning method. 00240 * After this method, you can call getLastPartitionLandmarks. 00241 * \sa getLastPartitionLandmarks 00242 */ 00243 void reconsiderPartitionsNow(); 00244 00245 00246 /** Provides access to the parameters of the map partitioning algorithm. 00247 */ 00248 CIncrementalMapPartitioner::TOptions * mapPartitionOptions() 00249 { 00250 return &mapPartitioner.options; 00251 } 00252 00253 /** Save the current state of the filter (robot pose & map) to a MATLAB script which displays all the elements in 2D 00254 */ 00255 void saveMapAndPath2DRepresentationAsMATLABFile( 00256 const std::string &fil, 00257 float stdCount=3.0f, 00258 const std::string &styleLandmarks = std::string("b"), 00259 const std::string &stylePath = std::string("r"), 00260 const std::string &styleRobot = std::string("r") ) const; 00261 00262 00263 00264 protected: 00265 00266 /** @name Virtual methods for Kalman Filter implementation 00267 @{ 00268 */ 00269 00270 /** Must return the action vector u. 00271 * \param out_u The action vector which will be passed to OnTransitionModel 00272 */ 00273 void OnGetAction( KFArray_ACT &out_u ) const; 00274 00275 /** Implements the transition model \f$ \hat{x}_{k|k-1} = f( \hat{x}_{k-1|k-1}, u_k ) \f$ 00276 * \param in_u The vector returned by OnGetAction. 00277 * \param inout_x At input has \f[ \hat{x}_{k-1|k-1} \f] , at output must have \f$ \hat{x}_{k|k-1} \f$ . 00278 * \param out_skip Set this to true if for some reason you want to skip the prediction step (to do not modify either the vector or the covariance). Default:false 00279 */ 00280 void OnTransitionModel( 00281 const KFArray_ACT &in_u, 00282 KFArray_VEH &inout_x, 00283 bool &out_skipPrediction 00284 ) const; 00285 00286 /** Implements the transition Jacobian \f$ \frac{\partial f}{\partial x} \f$ 00287 * \param out_F Must return the Jacobian. 00288 * The returned matrix must be \f$V \times V\f$ with V being either the size of the whole state vector (for non-SLAM problems) or VEH_SIZE (for SLAM problems). 00289 */ 00290 void OnTransitionJacobian( KFMatrix_VxV &out_F ) const; 00291 00292 /** Implements the transition noise covariance \f$ Q_k \f$ 00293 * \param out_Q Must return the covariance matrix. 00294 * The returned matrix must be of the same size than the jacobian from OnTransitionJacobian 00295 */ 00296 void OnTransitionNoise( KFMatrix_VxV &out_Q ) const; 00297 00298 /** This is called between the KF prediction step and the update step, and the application must return the observations and, when applicable, the data association between these observations and the current map. 00299 * 00300 * \param out_z N vectors, each for one "observation" of length OBS_SIZE, N being the number of "observations": how many observed landmarks for a map, or just one if not applicable. 00301 * \param out_data_association An empty vector or, where applicable, a vector where the i'th element corresponds to the position of the observation in the i'th row of out_z within the system state vector (in the range [0,getNumberOfLandmarksInTheMap()-1]), or -1 if it is a new map element and we want to insert it at the end of this KF iteration. 00302 * \param in_S The full covariance matrix of the observation predictions (i.e. the "innovation covariance matrix"). This is a M·O x M·O matrix with M=length of "in_lm_indices_in_S". 00303 * \param in_lm_indices_in_S The indices of the map landmarks (range [0,getNumberOfLandmarksInTheMap()-1]) that can be found in the matrix in_S. 00304 * 00305 * This method will be called just once for each complete KF iteration. 00306 * \note It is assumed that the observations are independent, i.e. there are NO cross-covariances between them. 00307 */ 00308 void OnGetObservationsAndDataAssociation( 00309 std::vector<KFArray_OBS> &out_z, 00310 vector_int &out_data_association, 00311 const vector<KFArray_OBS> &in_all_predictions, 00312 const KFMatrix &in_S, 00313 const vector_size_t &in_lm_indices_in_S, 00314 const KFMatrix_OxO &in_R 00315 ); 00316 00317 void OnObservationModel( 00318 const vector_size_t &idx_landmarks_to_predict, 00319 std::vector<KFArray_OBS> &out_predictions 00320 ) const; 00321 00322 /** Implements the observation Jacobians \f$ \frac{\partial h_i}{\partial x} \f$ and (when applicable) \f$ \frac{\partial h_i}{\partial y_i} \f$. 00323 * \param idx_landmark_to_predict The index of the landmark in the map whose prediction is expected as output. For non SLAM-like problems, this will be zero and the expected output is for the whole state vector. 00324 * \param Hx The output Jacobian \f$ \frac{\partial h_i}{\partial x} \f$. 00325 * \param Hy The output Jacobian \f$ \frac{\partial h_i}{\partial y_i} \f$. 00326 */ 00327 void OnObservationJacobians( 00328 const size_t &idx_landmark_to_predict, 00329 KFMatrix_OxV &Hx, 00330 KFMatrix_OxF &Hy 00331 ) const; 00332 00333 /** Computes A=A-B, which may need to be re-implemented depending on the topology of the individual scalar components (eg, angles). 00334 */ 00335 void OnSubstractObservationVectors(KFArray_OBS &A, const KFArray_OBS &B) const; 00336 00337 /** Return the observation NOISE covariance matrix, that is, the model of the Gaussian additive noise of the sensor. 00338 * \param out_R The noise covariance matrix. It might be non diagonal, but it'll usually be. 00339 */ 00340 void OnGetObservationNoise(KFMatrix_OxO &out_R) const; 00341 00342 /** This will be called before OnGetObservationsAndDataAssociation to allow the application to reduce the number of covariance landmark predictions to be made. 00343 * For example, features which are known to be "out of sight" shouldn't be added to the output list to speed up the calculations. 00344 * \param in_all_prediction_means The mean of each landmark predictions; the computation or not of the corresponding covariances is what we're trying to determined with this method. 00345 * \param out_LM_indices_to_predict The list of landmark indices in the map [0,getNumberOfLandmarksInTheMap()-1] that should be predicted. 00346 * \note This is not a pure virtual method, so it should be implemented only if desired. The default implementation returns a vector with all the landmarks in the map. 00347 * \sa OnGetObservations, OnDataAssociation 00348 */ 00349 void OnPreComputingPredictions( 00350 const vector<KFArray_OBS> &in_all_prediction_means, 00351 vector_size_t &out_LM_indices_to_predict ) const; 00352 00353 /** If applicable to the given problem, this method implements the inverse observation model needed to extend the "map" with a new "element". 00354 * \param in_z The observation vector whose inverse sensor model is to be computed. This is actually one of the vector<> returned by OnGetObservations(). 00355 * \param out_yn The F-length vector with the inverse observation model \f$ y_n=y(x,z_n) \f$. 00356 * \param out_dyn_dxv The \f$F \times V\f$ Jacobian of the inv. sensor model wrt the robot pose \f$ \frac{\partial y_n}{\partial x_v} \f$. 00357 * \param out_dyn_dhn The \f$F \times O\f$ Jacobian of the inv. sensor model wrt the observation vector \f$ \frac{\partial y_n}{\partial h_n} \f$. 00358 * 00359 * - O: OBS_SIZE 00360 * - V: VEH_SIZE 00361 * - F: FEAT_SIZE 00362 * 00363 * \note OnNewLandmarkAddedToMap will be also called after calling this method if a landmark is actually being added to the map. 00364 */ 00365 void OnInverseObservationModel( 00366 const KFArray_OBS & in_z, 00367 KFArray_FEAT & out_yn, 00368 KFMatrix_FxV & out_dyn_dxv, 00369 KFMatrix_FxO & out_dyn_dhn ) const; 00370 00371 /** If applicable to the given problem, do here any special handling of adding a new landmark to the map. 00372 * \param in_obsIndex The index of the observation whose inverse sensor is to be computed. It corresponds to the row in in_z where the observation can be found. 00373 * \param in_idxNewFeat The index that this new feature will have in the state vector (0:just after the vehicle state, 1: after that,...). Save this number so data association can be done according to these indices. 00374 * \sa OnInverseObservationModel 00375 */ 00376 void OnNewLandmarkAddedToMap( 00377 const size_t in_obsIdx, 00378 const size_t in_idxNewFeat ); 00379 00380 00381 /** This method is called after the prediction and after the update, to give the user an opportunity to normalize the state vector (eg, keep angles within -pi,pi range) if the application requires it. 00382 */ 00383 void OnNormalizeStateVector(); 00384 00385 /** @} 00386 */ 00387 00388 /** Set up by processActionObservation 00389 */ 00390 CActionCollectionPtr m_action; 00391 00392 /** Set up by processActionObservation 00393 */ 00394 CSensoryFramePtr m_SF; 00395 00396 /** The mapping between landmark IDs and indexes in the Pkk cov. matrix: 00397 */ 00398 mrpt::utils::bimap<CLandmark::TLandmarkID,unsigned int> m_IDs; 00399 00400 00401 /** Used for map partitioning experiments 00402 */ 00403 CIncrementalMapPartitioner mapPartitioner; 00404 00405 /** The sequence of all the observations and the robot path (kept for debugging, statistics,etc) 00406 */ 00407 CSensFrameProbSequence m_SFs; 00408 00409 std::vector<vector_uint> m_lastPartitionSet; 00410 00411 TDataAssocInfo m_last_data_association; //!< Last data association 00412 00413 }; // end class 00414 } // End of namespace 00415 } // End of namespace 00416 00417 #endif
| Page generated by Doxygen 1.7.1 for MRPT 0.8.1 SVN:exported at Sun Sep 19 14:53:45 UTC 2010 |
