00001
00008
00009
00010
00011
00012 #ifndef ECL_SLAM_EKF_BASE_HPP_
00013 #define ECL_SLAM_EKF_BASE_HPP_
00014
00015
00016
00017
00018
00019 #include <vector>
00020 #include <ecl/exceptions/standard_exception.hpp>
00021 #include <ecl/time/duration.hpp>
00022 #include <ecl/time/stopwatch.hpp>
00023 #include <ecl/linear_algebra.hpp>
00024
00025
00026
00027
00028
00029 namespace ecl {
00030
00031
00032
00033
00044 template<unsigned int MeasurementDimension, unsigned int PoseDimension,
00045 unsigned int ObservationDimension, unsigned int FeatureDimension>
00046 class SlamEkfBase {
00047 public:
00048 static const unsigned int measurement_dimension = MeasurementDimension;
00049 static const unsigned int pose_dimension = PoseDimension;
00050 static const unsigned int observation_dimension = ObservationDimension;
00051 static const unsigned int feature_dimension = FeatureDimension;
00053 typedef linear_algebra::Matrix<double,measurement_dimension,1> Measurement;
00054 typedef linear_algebra::Matrix<double,pose_dimension,1> Pose;
00055 typedef linear_algebra::Matrix<double,pose_dimension,pose_dimension> PoseVariance;
00056 typedef linear_algebra::Matrix<double,measurement_dimension,measurement_dimension> OdometryNoise;
00057 typedef linear_algebra::Matrix<double,pose_dimension,pose_dimension> OdometryMotionJacobian;
00058 typedef linear_algebra::Matrix<double,measurement_dimension,pose_dimension> OdometryNoiseJacobian;
00060 typedef linear_algebra::Matrix<double,observation_dimension,1> Observation;
00061 typedef linear_algebra::Matrix<double,observation_dimension,pose_dimension+feature_dimension> ObservationJacobian;
00062 typedef linear_algebra::Matrix<double,observation_dimension,observation_dimension> ObservationNoise;
00063 typedef linear_algebra::Matrix<double,feature_dimension,1> Feature;
00064 typedef linear_algebra::Matrix<double,feature_dimension,feature_dimension> FeatureVariance;
00065 typedef linear_algebra::Matrix<double,feature_dimension,feature_dimension> FeatureVarianceJacobian;
00066 typedef linear_algebra::Matrix<double,feature_dimension,pose_dimension> FeatureCoVarianceJacobian;
00068
00069
00070
00071 SlamEkfBase(const unsigned int &initial_capacity = 30);
00072 virtual ~SlamEkfBase() {};
00073 void init();
00074 void init(const unsigned int &initial_capacity);
00075
00076
00077
00078
00079 int insert(const Feature &initial_state, const FeatureVariance &initial_variance) ecl_assert_throw_decl(StandardException);
00080 int insert(const Feature &initial_state,
00081 const FeatureVariance &initial_variance,
00082 const FeatureVarianceJacobian &variance_jacobian,
00083 const FeatureCoVarianceJacobian &covariance_jacobian
00084 ) ecl_assert_throw_decl(StandardException);
00085 bool remove(const unsigned int &correspondence);
00086 void reserve(const unsigned int& new_capacity) ecl_assert_throw_decl(StandardException);
00087 void completeCovariance( linear_algebra::MatrixXd & cov );
00088
00089
00090
00091
00092 Pose pose() { return state.block(0,0,pose_dimension,1); }
00093 Feature feature(const unsigned int &correspondence ) { return state.block(correspondence, 0, feature_dimension, 1); }
00094 unsigned int size() const { return number_features; }
00096 linear_algebra::VectorXd state;
00097 linear_algebra::MatrixXd covariance;
00098
00099 private:
00100 unsigned int number_features;
00101 unsigned int capacity();
00102 };
00103
00104
00105
00106
00113 template<unsigned int MeasurementDimension, unsigned int PoseDimension, unsigned int ObservationDimension, unsigned int FeatureDimension>
00114 SlamEkfBase<MeasurementDimension, PoseDimension, ObservationDimension, FeatureDimension>::SlamEkfBase(const unsigned int &initial_capacity) :
00115 number_features(0.0)
00116 { init(initial_capacity); }
00122 template<unsigned int MeasurementDimension, unsigned int PoseDimension, unsigned int ObservationDimension, unsigned int FeatureDimension>
00123 void SlamEkfBase<MeasurementDimension, PoseDimension, ObservationDimension, FeatureDimension>::init() {
00124 unsigned int dimension = state.rows();
00125 state = linear_algebra::VectorXd::Zero(dimension);
00126 covariance = linear_algebra::MatrixXd::Zero(dimension,dimension);
00127 number_features = 0;
00128 }
00135 template<unsigned int MeasurementDimension, unsigned int PoseDimension, unsigned int ObservationDimension, unsigned int FeatureDimension>
00136 void SlamEkfBase<MeasurementDimension, PoseDimension, ObservationDimension, FeatureDimension>::init(const unsigned int &initial_capacity) {
00137 unsigned int dimension = pose_dimension + initial_capacity*feature_dimension;
00138 state = linear_algebra::VectorXd::Zero(dimension);
00139 covariance = linear_algebra::MatrixXd::Zero(dimension,dimension);
00140 number_features = 0;
00141 }
00142
00143
00144
00165 template<unsigned int MeasurementDimension, unsigned int PoseDimension, unsigned int ObservationDimension, unsigned int FeatureDimension>
00166 int SlamEkfBase<MeasurementDimension, PoseDimension, ObservationDimension, FeatureDimension>::insert(
00167 const linear_algebra::Matrix<double,feature_dimension,1> &initial_state,
00168 const linear_algebra::Matrix<double,feature_dimension,feature_dimension> &initial_variance) ecl_assert_throw_decl(StandardException) {
00169
00170 ecl_assert_throw(number_features < capacity(), StandardException(LOC,MemoryError,"The filter does not have any spare storage space (use reserve() to allocate more)."));
00171 bool found_unused_correspondence = false;
00172 unsigned int index = pose_dimension;
00173
00174 while ( (!found_unused_correspondence) && ( index < static_cast<unsigned int>(state.rows()) ) ) {
00175 if ( covariance(index,index) == 0.0 ) {
00176 found_unused_correspondence = true;
00177 } else {
00178 index += feature_dimension;
00179 }
00180 }
00181 if ( found_unused_correspondence ) {
00182 state.block(index,0,feature_dimension,1) = initial_state;
00183 covariance.block(index,index,feature_dimension,feature_dimension) = initial_variance;
00184 ++number_features;
00185 return index;
00186 } else {
00187 return -1;
00188 }
00189 }
00190
00191
00192 template<unsigned int MeasurementDimension, unsigned int PoseDimension, unsigned int ObservationDimension, unsigned int FeatureDimension>
00193 void SlamEkfBase<MeasurementDimension, PoseDimension, ObservationDimension, FeatureDimension>::completeCovariance( linear_algebra::MatrixXd & cov )
00194 {
00195
00196 int target_matrix_size = pose_dimension + feature_dimension*number_features;
00197 int current_matrix_size = covariance.rows();
00198 int cnt_rows(0);
00199 int cnt_cols(0);
00200
00201 cov.resize( target_matrix_size, target_matrix_size );
00202
00203 for( int i=0; i<current_matrix_size; i++ )
00204 {
00205 if( covariance(i,i) == 0.0 )
00206 {
00207 continue;
00208 }
00209 cnt_cols=0;
00210 for( int j=0; j<current_matrix_size; j++ )
00211 {
00212 if( covariance(j,j) == 0.0 )
00213 {
00214 continue;
00215 }
00216 else
00217 {
00218 cov(cnt_rows,cnt_cols++) = covariance(i,j);
00219 }
00220 }
00221
00222
00223 cnt_rows += 1;
00224 }
00225
00226
00227 }
00228
00229
00248 template<unsigned int MeasurementDimension, unsigned int PoseDimension, unsigned int ObservationDimension, unsigned int FeatureDimension>
00249 int SlamEkfBase<MeasurementDimension, PoseDimension, ObservationDimension, FeatureDimension>::insert(
00250 const Feature &initial_state,
00251 const FeatureVariance &initial_variance,
00252 const FeatureVarianceJacobian &variance_jacobian,
00253 const FeatureCoVarianceJacobian &covariance_jacobian
00254 ) ecl_assert_throw_decl(StandardException) {
00255
00256 ecl_assert_throw(number_features < capacity(), StandardException(LOC,MemoryError,"The filter does not have any spare storage space (use reserve() to allocate more)."));
00257 bool found_unused_correspondence = false;
00258 int index = pose_dimension;
00259
00260
00261
00262 while ( (!found_unused_correspondence) && ( index < state.rows() ) ) {
00263 if ( covariance(index,index) == 0.0 ) {
00264 found_unused_correspondence = true;
00265 } else {
00266 index += feature_dimension;
00267 }
00268 }
00269
00270
00271
00272 if ( found_unused_correspondence ) {
00273 state.block(index,0,feature_dimension,1) = initial_state;
00274
00275
00276
00277 covariance.block(index,index,feature_dimension,feature_dimension) =
00278 covariance_jacobian*covariance.block(0,0,pose_dimension,pose_dimension)*covariance_jacobian.transpose() +
00279 variance_jacobian*initial_variance*variance_jacobian.transpose();
00280
00281
00282
00283
00284 linear_algebra::Matrix<double,feature_dimension,pose_dimension> landmark_robot_covariance = covariance_jacobian*covariance.block(0,0,3,3);
00285 covariance.block(index,0,feature_dimension,pose_dimension) = landmark_robot_covariance;
00286 covariance.block(0,index,pose_dimension,feature_dimension) = landmark_robot_covariance.transpose();
00287
00288
00289
00290 for ( unsigned int i = 0; i < capacity(); ++i ) {
00291 int idx = pose_dimension + feature_dimension*i;
00292 if ( idx != index ) {
00293 FeatureVarianceJacobian landmark_covariance = covariance_jacobian*covariance.block(0,idx,pose_dimension,feature_dimension);
00294 covariance.block(index,idx,feature_dimension,feature_dimension) = landmark_covariance;
00295 covariance.block(idx,index,feature_dimension,feature_dimension) = landmark_covariance.transpose();
00296 }
00297 }
00298 ++number_features;
00299 return index;
00300 } else {
00301 return -1;
00302 }
00303 }
00304
00317 template<unsigned int MeasurementDimension, unsigned int PoseDimension, unsigned int ObservationDimension, unsigned int FeatureDimension>
00318 bool SlamEkfBase<MeasurementDimension, PoseDimension, ObservationDimension, FeatureDimension>::remove(const unsigned int &correspondence) {
00319 for ( unsigned int i = 0; i < feature_dimension; ++i ) {
00320 state[correspondence+i] = 0.0;
00321 }
00322 for ( unsigned int i = 0; i < feature_dimension; ++i ) {
00323 for ( int j = 0; j < covariance.cols(); ++j ) {
00324 covariance(correspondence+i,j) = 0.0;
00325 covariance(j,correspondence+i) = 0.0;
00326 }
00327 }
00328 --number_features;
00329 return true;
00330 }
00341 template<unsigned int MeasurementDimension, unsigned int PoseDimension, unsigned int ObservationDimension, unsigned int FeatureDimension>
00342 void SlamEkfBase<MeasurementDimension, PoseDimension, ObservationDimension, FeatureDimension>::reserve(const unsigned int& new_capacity) ecl_assert_throw_decl(StandardException) {
00343
00344 unsigned int current_capacity = capacity();
00345 unsigned int current_dimension = pose_dimension+current_capacity*feature_dimension;
00346 unsigned int new_dimension = pose_dimension+new_capacity*feature_dimension;
00347
00348 ecl_assert_throw( new_capacity > current_capacity, StandardException(LOC,InvalidInputError,"This class has a simple policy for safety, new size should be greater than the current size (unless reinitialising)."));
00349
00350 state.conservativeResize(new_dimension);
00351 for ( unsigned int i = current_dimension; i < new_dimension; ++i ) {
00352 state[i] = 0.0;
00353 }
00354 covariance.conservativeResize(new_dimension,new_dimension);
00355
00356 for ( unsigned int i = 0; i < current_dimension; ++i ) {
00357 for ( unsigned int j = current_dimension; j < new_dimension; ++j ) {
00358 covariance(i,j) = 0.0;
00359 }
00360 }
00361 for ( unsigned int i = current_dimension; i < new_dimension; ++i ) {
00362 for ( unsigned int j = 0; j < new_dimension; ++j ) {
00363 covariance(i,j) = 0.0;
00364 }
00365 }
00366 }
00367
00368
00369
00370
00371
00372 template<unsigned int MeasurementDimension, unsigned int PoseDimension, unsigned int ObservationDimension, unsigned int FeatureDimension>
00373 unsigned int SlamEkfBase<MeasurementDimension, PoseDimension, ObservationDimension, FeatureDimension>::capacity() {
00374 return (state.size()-pose_dimension)/feature_dimension;
00375 }
00376
00377 }
00378
00379 #endif