MultiRBTracker.cpp
Go to the documentation of this file.
00001 #include <boost/foreach.hpp>
00002 
00003 #include "rb_tracker/MultiRBTracker.h"
00004 
00005 #include "omip_common/OMIPUtils.h"
00006 
00007 #include <cmath>
00008 
00009 #include <pcl/correspondence.h>
00010 #include <pcl/registration/correspondence_rejection_sample_consensus.h>
00011 
00012 #include <pcl_conversions/pcl_conversions.h>
00013 
00014 #if ROS_VERSION_MINIMUM(1, 11, 1) // if current ros version is >= 1.11.1 (indigo)
00015 #else
00016 #include "rb_tracker/pcl_conversions_indigo.h"
00017 #endif
00018 
00019 #include <pcl/console/print.h>
00020 
00021 using namespace omip;
00022 
00023 inline void estimateRigidTransformation(
00024         const FeaturesDataBase::MapOfFeatureLocationPairs& last2locations,
00025         Eigen::Matrix4d &transformation_matrix)
00026 {
00027     // Convert to Eigen format
00028     const int npts = static_cast<int>(last2locations.size());
00029 
00030     Eigen::Matrix<double, 3, Eigen::Dynamic> cloud_src(3, npts);
00031     Eigen::Matrix<double, 3, Eigen::Dynamic> cloud_tgt(3, npts);
00032 
00033     FeaturesDataBase::MapOfFeatureLocationPairs::const_iterator locations_it =
00034             last2locations.begin();
00035     FeaturesDataBase::MapOfFeatureLocationPairs::const_iterator locations_it_end =
00036             last2locations.end();
00037     for (int i = 0; locations_it != locations_it_end; locations_it++, i++)
00038     {
00039         cloud_src(0, i) = locations_it->second.second.get<0>();
00040         cloud_src(1, i) = locations_it->second.second.get<1>();
00041         cloud_src(2, i) = locations_it->second.second.get<2>();
00042 
00043         cloud_tgt(0, i) = locations_it->second.first.get<0>();
00044         cloud_tgt(1, i) = locations_it->second.first.get<1>();
00045         cloud_tgt(2, i) = locations_it->second.first.get<2>();
00046     }
00047 
00048     // Call Umeyama directly from Eigen (PCL patched version until Eigen is released)
00049     transformation_matrix = Eigen::umeyama(cloud_src, cloud_tgt, false);
00050 }
00051 
00052 MultiRBTracker::MultiRBTracker(int max_num_rb,
00053                                double loop_period_ns,
00054                                int ransac_iterations,
00055                                double estimation_error_threshold,
00056                                double static_motion_threshold,
00057                                double new_rbm_error_threshold,
00058                                double max_error_to_reassign_feats,
00059                                int supporting_features_threshold,
00060                                int min_num_feats_for_new_rb,
00061                                int min_num_frames_for_new_rb,
00062                                int initial_cam_motion_constraint,
00063                                static_environment_tracker_t static_environment_tracker_type) :
00064     RecursiveEstimatorFilterInterface(loop_period_ns),
00065     _max_num_rb(max_num_rb),
00066     _ransac_iterations(ransac_iterations),
00067     _estimation_error_threshold(estimation_error_threshold),
00068     _static_motion_threshold(static_motion_threshold),
00069     _new_rbm_error_threshold(new_rbm_error_threshold),
00070     _max_error_to_reassign_feats(max_error_to_reassign_feats),
00071     _supporting_features_threshold(supporting_features_threshold),
00072     _min_num_feats_for_new_rb(min_num_feats_for_new_rb),
00073     _min_num_frames_for_new_rb(min_num_frames_for_new_rb),
00074     _min_num_points_in_segment(0),
00075     _min_probabilistic_value(0.0),
00076     _max_fitness_score(0.0),
00077     _min_num_supporting_feats_to_correct(7),
00078     _max_distance_ee(-1),
00079     _max_distance_irb(-1)
00080 {
00081 
00082     //_really_free_feats_file.open("really_free_feats_file.txt");
00083     this->_filter_name = "RBMFilter";
00084 
00085     if (this->_features_db)
00086         this->_features_db.reset();
00087 
00088     this->_features_db = FeaturesDataBase::Ptr(new FeaturesDataBase());
00089 
00090     this->_predicted_measurement = rbt_measurement_t(new FeatureCloudPCLwc());
00091 
00092     // The static environment exists always as initial hypothesis
00093     // We can track the static enviroment (visual odometry) using different computation methods: ICP or EKF
00094     _static_environment_filter = StaticEnvironmentFilter::Ptr(new StaticEnvironmentFilter(this->_loop_period_ns,
00095                                                                                       this->_features_db,
00096                                                                                       this->_static_motion_threshold));
00097     _static_environment_filter->setComputationType(static_environment_tracker_type);
00098     _static_environment_filter->setFeaturesDatabase(this->_features_db);
00099     _static_environment_filter->setMotionConstraint(initial_cam_motion_constraint);
00100 
00101     this->_kalman_filters.push_back(_static_environment_filter);
00102 }
00103 
00104 void MultiRBTracker::Init()
00105 {
00106     _static_environment_filter->setMeasurementDepthFactor(this->_meas_depth_factor);
00107     _static_environment_filter->setMinCovarianceMeasurementX(this->_min_cov_meas_x);
00108     _static_environment_filter->setMinCovarianceMeasurementY(this->_min_cov_meas_y);
00109     _static_environment_filter->setMinCovarianceMeasurementZ(this->_min_cov_meas_z);
00110     _static_environment_filter->setPriorCovariancePose(this->_prior_cov_pose);
00111     _static_environment_filter->setPriorCovarianceVelocity(this->_prior_cov_vel);
00112     _static_environment_filter->setCovarianceSystemAccelerationTx(this->_cov_sys_acc_tx);
00113     _static_environment_filter->setCovarianceSystemAccelerationTy(this->_cov_sys_acc_ty);
00114     _static_environment_filter->setCovarianceSystemAccelerationTz(this->_cov_sys_acc_tz);
00115     _static_environment_filter->setCovarianceSystemAccelerationRx(this->_cov_sys_acc_rx);
00116     _static_environment_filter->setCovarianceSystemAccelerationRy(this->_cov_sys_acc_ry);
00117     _static_environment_filter->setCovarianceSystemAccelerationRz(this->_cov_sys_acc_rz);
00118     _static_environment_filter->setNumberOfTrackedFeatures(this->_num_tracked_feats);
00119     _static_environment_filter->setMinNumberOfSupportingFeaturesToCorrectPredictedState(this->_min_num_supporting_feats_to_correct);
00120     _static_environment_filter->Init();
00121 }
00122 
00123 MultiRBTracker::~MultiRBTracker()
00124 {
00125 
00126 }
00127 
00128 void MultiRBTracker::setMeasurement(rbt_measurement_t acquired_measurement, const double& measurement_timestamp)
00129 {
00130     this->_previous_measurement_timestamp_ns = this->_measurement_timestamp_ns;
00131 
00132     {
00133         boost::mutex::scoped_lock(this->_measurement_timestamp_ns_mutex);
00134         this->_measurement_timestamp_ns = measurement_timestamp;
00135     }
00136 
00137     this->_features_db->clearListOfAliveFeatureIds();
00138     this->_measurement = acquired_measurement;
00139 
00140     int num_tracked_features = acquired_measurement->points.size();
00141 
00142     int tracked_features_index = 0;
00143     uint32_t feature_id;
00144     for (; tracked_features_index < num_tracked_features; tracked_features_index++)
00145     {
00146         feature_id = acquired_measurement->points[tracked_features_index].label;
00147         if(feature_id != 0)
00148         {
00149             Feature::Location feature_location = Feature::Location(acquired_measurement->points[tracked_features_index].x, acquired_measurement->points[tracked_features_index].y,
00150                                                                    acquired_measurement->points[tracked_features_index].z);
00151             this->addFeatureLocation(feature_id, feature_location);
00152         }
00153     }
00154     this->_features_db->step();
00155 }
00156 
00157 void MultiRBTracker::predictState(double time_interval_ns)
00158 {
00159     //First we update the filters using the internal state (system update)
00160     for (std::vector<RBFilter::Ptr>::iterator filter_it = this->_kalman_filters.begin(); filter_it != this->_kalman_filters.end(); filter_it++)
00161     {
00162         (*filter_it)->predictState(time_interval_ns);
00163         (*filter_it)->doNotUsePredictionFromHigherLevel();
00164     }
00165 }
00166 
00167 // NOTE: The location of the Features predicted by the static RBFilter is the initial location of these Features
00168 // When these predictions are used for the visual tracking the searching area for the Features is static until these Features can
00169 // be assigned to an existing RB (or a group of them create a new one)
00170 // The consequence is that the Features could go out of the searching area before they are detected as moving
00171 // There are two solutions:
00172 //      1- Use the static_motion_threshold in the estimation of the searching area. The searching area should cover motions of static_motion_threshold
00173 //         at the depth of the Feature (COMPLEX)
00174 //      2- Only for the static RBFilter the predicted locations retrieved here are the latest locations of the Features. This is ugly (treats the static
00175 //         RBFilter as an special one) but easier
00176 void MultiRBTracker::predictMeasurement()
00177 {
00178     std::vector<RBFilter::Ptr>::iterator filter_it = this->_kalman_filters.begin();
00179     for (; filter_it != this->_kalman_filters.end(); filter_it++)
00180     {
00181         (*filter_it)->predictMeasurement();
00182     }
00183 
00184     this->_predicted_measurement->points.clear();
00185 
00186     std::vector<Feature::Id> feature_ids;
00187     FeatureCloudPCLwc one_filter_predicted_measurement;
00188     filter_it = this->_kalman_filters.begin();
00189     filter_it++;
00190     for (; filter_it != this->_kalman_filters.end(); filter_it++)
00191     {
00192         one_filter_predicted_measurement = (*filter_it)->getPredictedMeasurement();
00193         for (size_t feat_idx = 0; feat_idx < one_filter_predicted_measurement.points.size(); feat_idx++)
00194         {
00195             this->_predicted_measurement->points.push_back(one_filter_predicted_measurement.points.at(feat_idx));
00196             feature_ids.push_back(one_filter_predicted_measurement.points.at(feat_idx).label);
00197         }
00198     }
00199 
00200     // The free Features are not in any RBFilter. We collect their latest locations
00201     std::vector<Feature::Id> free_features_ids = this->EstimateFreeFeatures(feature_ids);
00202     FeaturePCLwc free_feat;
00203     for (size_t feat_idx = 0; feat_idx < free_features_ids.size(); feat_idx++)
00204     {
00205         free_feat.x = this->_features_db->getFeatureLastX(free_features_ids.at(feat_idx));
00206         free_feat.y = this->_features_db->getFeatureLastY(free_features_ids.at(feat_idx));
00207         free_feat.z = this->_features_db->getFeatureLastZ(free_features_ids.at(feat_idx));
00208         free_feat.label = free_features_ids.at(feat_idx);
00209         free_feat.covariance[0] = 20;
00210         this->_predicted_measurement->points.push_back(free_feat);
00211     }
00212 }
00213 
00214 rbt_measurement_t MultiRBTracker::getPredictedMeasurement() const
00215 {
00216     this->_predicted_measurement->header.stamp = pcl_conversions::toPCL(ros::Time(this->_measurement_timestamp_ns/1e9+this->_loop_period_ns/1e9));
00217     return this->_predicted_measurement;
00218 }
00219 
00220 std::vector<Feature::Id> MultiRBTracker::estimateBestPredictionsAndSupportingFeatures()
00221 {
00222     std::vector<Feature::Id> all_filters_supporting_features;
00223     for (std::vector<RBFilter::Ptr>::iterator filter_it = this->_kalman_filters.begin(); filter_it != this->_kalman_filters.end();)
00224     {
00225         (*filter_it)->estimateBestPredictionAndSupportingFeatures();
00226         std::vector<Feature::Id> this_filter_supporting_features = (*filter_it)->getSupportingFeatures();
00227 
00228         // If there are no features supporting to the EKF we delete it (no re-finding of RBs/EKFs possible)
00229         // Don't delete the filter of the environment!!! (filter_it == this->_kalman_filters.begin())
00230         if (this_filter_supporting_features.size()  < (size_t)this->_supporting_features_threshold
00231                 && *filter_it != this->_static_environment_filter )
00232         {
00233             Eigen::Twistd last_pose_ec;
00234             TransformMatrix2Twist((*filter_it)->getPose(), last_pose_ec);
00235             ROS_ERROR_NAMED( "MultiRBTracker.estimateBestPredictionsAndSupportingFeatures",
00236                              "RBFilter %2d: Supporting feats:%3d (<%3d), Pose (vx,vy,vz,rx,ry,rz): % 2.2f,% 2.2f,% 2.2f,% 2.2f,% 2.2f,% 2.2f. REMOVED",
00237                              (int)(*filter_it)->getId(),
00238                              (int)this_filter_supporting_features.size() ,
00239                              (int)(this->_supporting_features_threshold),
00240                              last_pose_ec.vx(),
00241                              last_pose_ec.vy(),
00242                              last_pose_ec.vz(),
00243                              last_pose_ec.rx(),
00244                              last_pose_ec.ry(),
00245                              last_pose_ec.rz());
00246             filter_it = this->_kalman_filters.erase(filter_it);
00247         }
00248         else
00249         {
00250             all_filters_supporting_features.insert(all_filters_supporting_features.end(),
00251                                                    this_filter_supporting_features.begin(),
00252                                                    this_filter_supporting_features.end());
00253             filter_it++;
00254         }
00255     }
00256     return all_filters_supporting_features;
00257 }
00258 
00259 void MultiRBTracker::correctState()
00260 {
00261     // 1: Estimate the supporting features of each filter
00262     std::vector<Feature::Id> all_filters_supporting_features = this->estimateBestPredictionsAndSupportingFeatures();
00263 
00264     // 2: Estimate the free features
00265     std::vector<Feature::Id> free_feat_ids = this->EstimateFreeFeatures(all_filters_supporting_features);
00266 
00267     // 3: Try to assign free features to existing RBs
00268     std::vector<Feature::Id> really_free_feat_ids = this->ReassignFreeFeatures(free_feat_ids);
00269 
00270     ROS_INFO_NAMED("MultiRBTracker::correctState","Moving bodies: %3d, free features: %3d", (int)this->_kalman_filters.size(), (int)really_free_feat_ids.size());
00271 
00272     // 4: Correct the predicted state of each RBFilter using the last acquired Measurement
00273     for (std::vector<RBFilter::Ptr>::iterator filter_it = this->_kalman_filters.begin(); filter_it != this->_kalman_filters.end(); filter_it++)
00274     {
00275         (*filter_it)->correctState();
00276     }
00277 
00278     // 5: Try to create new filters for the "really free" features
00279     // NOTE: Keep this step after the correctState of the RBFilters, otherwise you will create a filter and correct it in the first iteration!
00280     if(this->_kalman_filters.size() < this->_max_num_rb)
00281     {
00282         this->TryToCreateNewFilter(really_free_feat_ids);
00283     }
00284 }
00285 
00286 void MultiRBTracker::ReflectState()
00287 {
00288     this->_state.rb_poses_and_vels.clear();
00289 
00290     std::vector<geometry_msgs::TwistWithCovariancePtr> tracked_poses_twist_with_cov = this->getPosesECWithCovariance();
00291     std::vector<geometry_msgs::TwistWithCovariancePtr> tracked_vels_twist_with_cov = this->getVelocitiesWithCovariance();
00292     std::vector<Eigen::Vector3d> centroids = this->getCentroids();
00293 
00294     RB_id_t RB_id;
00295 
00296     for (size_t poses_idx = 0; poses_idx < tracked_poses_twist_with_cov.size(); poses_idx++)
00297     {
00298         RB_id = this->getRBId(poses_idx);
00299 
00300         geometry_msgs::Point centroid;
00301         centroid.x = centroids.at(poses_idx).x();
00302         centroid.y = centroids.at(poses_idx).y();
00303         centroid.z = centroids.at(poses_idx).z();
00304 
00305         omip_msgs::RigidBodyPoseAndVelMsg rbpose_and_vel;
00306         rbpose_and_vel.rb_id = RB_id;
00307         rbpose_and_vel.pose_wc = *(tracked_poses_twist_with_cov.at(poses_idx));
00308         rbpose_and_vel.velocity_wc = *(tracked_vels_twist_with_cov.at(poses_idx));
00309         rbpose_and_vel.centroid = centroid;
00310         this->_state.rb_poses_and_vels.push_back(rbpose_and_vel);
00311     }
00312 }
00313 
00314 rbt_state_t MultiRBTracker::getState() const
00315 {
00316     return this->_state;
00317 }
00318 
00319 void MultiRBTracker::setDynamicReconfigureValues(rb_tracker::RBTrackerDynReconfConfig &config)
00320 {
00321     _static_environment_filter->setMotionConstraint(config.cam_motion_constraint);
00322     this->_min_num_feats_for_new_rb = config.min_feats_new_rb;
00323     this->_supporting_features_threshold = config.min_feats_survive_rb;
00324 }
00325 
00326 void MultiRBTracker::processMeasurementFromShapeTracker(const omip_msgs::ShapeTrackerStates &meas_from_st)
00327 {
00328     for(int idx = 0; idx < meas_from_st.shape_tracker_states.size(); idx++)
00329     {
00330         BOOST_FOREACH(RBFilter::Ptr filter, this->_kalman_filters)
00331         {
00332             if (filter->getId() == meas_from_st.shape_tracker_states.at(idx).rb_id )
00333             {
00334                 //Check if the flag indicates that this refinement is reliable
00335                 if((meas_from_st.shape_tracker_states.at(idx).number_of_points_of_model > _min_num_points_in_segment) &&
00336                         (meas_from_st.shape_tracker_states.at(idx).number_of_points_of_current_pc > _min_num_points_in_segment) &&
00337                         (meas_from_st.shape_tracker_states.at(idx).probabilistic_value > _min_probabilistic_value) &&
00338                         (meas_from_st.shape_tracker_states.at(idx).fitness_score < _max_fitness_score))
00339                 {
00340                     ROS_ERROR_STREAM("Integrating shape-based tracked pose RB " << meas_from_st.shape_tracker_states.at(idx).rb_id);
00341                     filter->integrateShapeBasedPose(meas_from_st.shape_tracker_states.at(idx).pose_wc, this->_measurement_timestamp_ns - meas_from_st.header.stamp.toNSec() );
00342                 }else{
00343                     ROS_ERROR_STREAM("Ignoring shape-based tracked pose RB " << meas_from_st.shape_tracker_states.at(idx).rb_id);
00344                 }
00345             }
00346         }
00347     }
00348 }
00349 
00350 void MultiRBTracker::CreateNewFilter(const std::vector<Eigen::Matrix4d>& initial_trajectory,
00351                                      const Eigen::Twistd& initial_velocity,
00352                                      const std::vector<Feature::Id>& initial_supporting_feats)
00353 {
00354     RBFilter::Ptr new_kf = RBFilter::Ptr(new RBFilter(this->_loop_period_ns,
00355                                                       initial_trajectory,
00356                                                       initial_velocity,
00357                                                       this->_features_db,
00358                                                       this->_estimation_error_threshold));
00359 
00360     new_kf->setMeasurementDepthFactor(this->_meas_depth_factor);
00361     new_kf->setMinCovarianceMeasurementX(this->_min_cov_meas_x);
00362     new_kf->setMinCovarianceMeasurementY(this->_min_cov_meas_y);
00363     new_kf->setMinCovarianceMeasurementZ(this->_min_cov_meas_z);
00364     new_kf->setPriorCovariancePose(this->_prior_cov_pose);
00365     new_kf->setPriorCovarianceVelocity(this->_prior_cov_vel);
00366     new_kf->setCovarianceSystemAccelerationTx(this->_cov_sys_acc_tx);
00367     new_kf->setCovarianceSystemAccelerationTy(this->_cov_sys_acc_ty);
00368     new_kf->setCovarianceSystemAccelerationTz(this->_cov_sys_acc_tz);
00369     new_kf->setCovarianceSystemAccelerationRx(this->_cov_sys_acc_rx);
00370     new_kf->setCovarianceSystemAccelerationRy(this->_cov_sys_acc_ry);
00371     new_kf->setCovarianceSystemAccelerationRz(this->_cov_sys_acc_rz);
00372     new_kf->setNumberOfTrackedFeatures(this->_num_tracked_feats);
00373     new_kf->setMinNumberOfSupportingFeaturesToCorrectPredictedState(this->_min_num_supporting_feats_to_correct);
00374 
00375     new_kf->Init();
00376 
00377     this->_kalman_filters.push_back(new_kf);
00378     BOOST_FOREACH(Feature::Id supporting_feat_id, initial_supporting_feats)
00379     {
00380         new_kf->addSupportingFeature(supporting_feat_id);
00381     }
00382 }
00383 
00384 std::vector<Feature::Id> MultiRBTracker::EstimateFreeFeatures(const std::vector<Feature::Id>& supporting_features)
00385 {
00386     // We check the set of free features = alive features - supporting features
00387     std::vector<Feature::Id> alive_feat_ids = this->_features_db->getListOfAliveFeatureIds();
00388     std::vector<Feature::Id> free_feat_ids;
00389     BOOST_FOREACH(Feature::Id alive_feat_id, alive_feat_ids)
00390     {
00391         // If the feature ID is not in the list of supporting features -> Free feature
00392         if (std::find(supporting_features.begin(), supporting_features.end(),alive_feat_id) == supporting_features.end())
00393         {
00394             free_feat_ids.push_back(alive_feat_id);
00395         }
00396     }
00397     _free_feat_ids = free_feat_ids;
00398     return free_feat_ids;
00399 }
00400 
00401 // NOTE: Here the features have an "extra" location compared to the moment when we predict the measurement for each filter (at the end of the iteration) (predictMeasurement)
00402 // Therefore, the "age of the feature" is +1 the age it would have when predicting the measurement
00403 // EXCEPT if the measurement prediction has to be called again in the loop!!!!!
00404 std::vector<Feature::Id> MultiRBTracker::ReassignFreeFeatures(const std::vector<Feature::Id>& free_feat_ids)
00405 {
00406     std::vector<Feature::Id> really_free_feat_ids;
00407 
00408     Feature::Ptr free_feat;
00409     Feature::Location free_feature_last_location;
00410     Feature::Location free_feature_pre_last_location;
00411     Feature::Location free_feature_predicted_location;
00412     double feat_error = 0.0;
00413     double prediction_error = 0.0;
00414     int best_ekf_idx = -1;
00415     Eigen::Matrix4d predicted_pose;
00416 
00417     // Check for each free feature if we can add it to one of the existing vision-based rigid bodies
00418     BOOST_FOREACH(Feature::Id free_feat_id, free_feat_ids)
00419     {
00420         free_feature_last_location = this->_features_db->getFeatureLastLocation(free_feat_id);
00421         free_feature_pre_last_location = this->_features_db->getFeatureNextToLastLocation(free_feat_id);
00422         free_feat = this->_features_db->getFeature(free_feat_id);
00423         feat_error = (double)this->_max_error_to_reassign_feats;
00424         best_ekf_idx = -1;
00425         Feature::Location best_predicted_location;
00426 
00427         // Get the prediction from each of the existing vision-based rigid bodies
00428         // TODO: Use the Mahalanobis distance between the uncertain feature location and its predicted location
00429         for (size_t filter_idx = 0; filter_idx < this->_kalman_filters.size();filter_idx++)
00430         {
00431             // Get the most likely prediction about the next feature state (the likelihood is estimated in estimateSupportingFeatures and copied to the others
00432             // so it is equivalent to get the belief pose from any hypothesis)
00433             //prediction_error = this->_kalman_filters.at(filter_idx)->PredictFeatureLocationNew(free_feat, false, true);
00434 
00435             predicted_pose = this->_kalman_filters.at(filter_idx)->getPose();
00436             this->_kalman_filters.at(filter_idx)->PredictFeatureLocation(free_feat, predicted_pose, false, free_feature_predicted_location,true);
00437             prediction_error = L2Distance(free_feature_last_location, free_feature_predicted_location);
00438 
00439             if (prediction_error < feat_error)
00440             {
00441                 feat_error = prediction_error;
00442                 best_ekf_idx = filter_idx;
00443                 best_predicted_location = free_feature_predicted_location;
00444             }
00445         }
00446 
00447         if (best_ekf_idx != -1)
00448         {
00449             this->_kalman_filters.at(best_ekf_idx)->addSupportingFeature(free_feat_id);
00450             this->_kalman_filters.at(best_ekf_idx)->addPredictedFeatureLocation(best_predicted_location,free_feature_pre_last_location, free_feat_id);
00451         }
00452         else
00453         {
00454             really_free_feat_ids.push_back(free_feat_id);
00455         }
00456     }
00457     _really_free_feat_ids = really_free_feat_ids;
00458     return really_free_feat_ids;
00459 }
00460 
00461 void MultiRBTracker::TryToCreateNewFilter(const std::vector<Feature::Id>& really_free_feat_ids)
00462 {
00463     // First check that the number of free features is over the minimum number to estimate motion
00464     if(really_free_feat_ids.size() > this->_min_num_feats_for_new_rb)
00465     {
00466         pcl::PointCloud<pcl::PointXYZ>::Ptr source = pcl::PointCloud<pcl::PointXYZ>::Ptr(new pcl::PointCloud<pcl::PointXYZ>());
00467         pcl::PointCloud<pcl::PointXYZ>::Ptr target = pcl::PointCloud<pcl::PointXYZ>::Ptr(new pcl::PointCloud<pcl::PointXYZ>());
00468         pcl::Correspondences initial_correspondeces, filtered_correspondences;
00469         int index = 0;
00470         std::map<int, int> index_to_feat_id;
00471         PointPCL point_pcl;
00472 
00473         //Iterate over the free features
00474         BOOST_FOREACH(Feature::Id free_feat_id, really_free_feat_ids)
00475         {
00476             // If the free feature is old enough, we add it to the source-target point clouds and add a correspondence
00477             if ((int)this->_features_db->getFeatureAge(free_feat_id) > this->_min_num_frames_for_new_rb)
00478             {
00479                 Feature::Location first = this->_features_db->getFeatureNToLastLocation(free_feat_id, this->_min_num_frames_for_new_rb);
00480                 Feature::Location second = this->_features_db->getFeatureLastLocation(free_feat_id);
00481                 Location2PointPCL(first, point_pcl);
00482                 source->push_back(point_pcl);
00483                 Location2PointPCL(second, point_pcl);
00484                 target->push_back(point_pcl);
00485                 initial_correspondeces.push_back(pcl::Correspondence(index, index, 0.0));
00486                 index_to_feat_id[index] = free_feat_id;
00487                 index++;
00488             }
00489         }
00490 
00491         // If enough of the free features are old enough, we try to estimate the motion
00492         if(index > this->_min_num_feats_for_new_rb)
00493         {
00494             //pcl::console::setVerbosityLevel(pcl::console::L_DEBUG);
00495             // PCL RANSAC
00496             pcl::registration::CorrespondenceRejectorSampleConsensus<pcl::PointXYZ> rejector;
00497             rejector.setInputSource(source);
00498             rejector.setInputTarget(target);
00499             rejector.setInlierThreshold(this->_new_rbm_error_threshold);
00500             rejector.setMaximumIterations(this->_ransac_iterations);
00501             rejector.getRemainingCorrespondences(initial_correspondeces, filtered_correspondences);
00502 
00503             Eigen::Matrix4f best_transformation = rejector.getBestTransformation();
00504 
00505             // If the number of free features that are inliers of the best transformation is over the minimum number to estimate motion
00506             // AND if the best transformation is not just noise:
00507             //      - Translation is larger than min_amount_translation meters
00508             //      - Rotation around the axis is larger than min_amount_rotation degrees
00509             Eigen::Transform<float, 3, Eigen::Affine> best_transformation2(best_transformation);
00510             double amount_translation = best_transformation2.translation().norm();
00511             Eigen::AngleAxisf best_axis_angle;
00512             double amount_rotation = best_axis_angle.fromRotationMatrix(best_transformation2.rotation()).angle();
00513 
00514             if ((int)filtered_correspondences.size() > this->_min_num_feats_for_new_rb && (
00515                         amount_translation > _min_amount_translation_for_new_rb ||
00516                         amount_rotation > _min_amount_rotation_for_new_rb*(M_PI/180.0) ) )
00517             {
00518                 std::vector<Eigen::Matrix4d> trajectory;
00519                 Feature::Location centroid_in_cf;
00520 
00521                 //Collect the ids of the matched features
00522                 //and compute the centroid of the supporting features N frames ago
00523                 //The centroid will be used to "place" the frame of the rigid body -> Initial transformation of the rigid body
00524                 //is a pure translation to the location of the centroid
00525                 std::vector<Feature::Id> ransac_best_trial_inliers;
00526                 BOOST_FOREACH(pcl::Correspondence filter_correspondence, filtered_correspondences)
00527                 {
00528                     int feature_id = index_to_feat_id.at(filter_correspondence.index_match);
00529                     ransac_best_trial_inliers.push_back(feature_id);
00530                     Feature::Location feat_loc = this->_features_db->getFeatureNToLastLocation(feature_id, this->_min_num_frames_for_new_rb-1);
00531                     boost::tuples::get<0>(centroid_in_cf) = boost::tuples::get<0>(centroid_in_cf) + boost::tuples::get<0>(feat_loc);
00532                     boost::tuples::get<1>(centroid_in_cf) = boost::tuples::get<1>(centroid_in_cf) + boost::tuples::get<1>(feat_loc);
00533                     boost::tuples::get<2>(centroid_in_cf) = boost::tuples::get<2>(centroid_in_cf) + boost::tuples::get<2>(feat_loc);
00534                 }
00535 
00536                 boost::tuples::get<0>(centroid_in_cf) = boost::tuples::get<0>(centroid_in_cf)/(double)filtered_correspondences.size();
00537                 boost::tuples::get<1>(centroid_in_cf) = boost::tuples::get<1>(centroid_in_cf)/(double)filtered_correspondences.size();
00538                 boost::tuples::get<2>(centroid_in_cf) = boost::tuples::get<2>(centroid_in_cf)/(double)filtered_correspondences.size();
00539 
00540                 Eigen::Matrix4d pre_translation = Eigen::Matrix4d::Identity();
00541                 pre_translation(0,3) = boost::tuples::get<0>(centroid_in_cf);
00542                 pre_translation(1,3) = boost::tuples::get<1>(centroid_in_cf);
00543                 pre_translation(2,3) = boost::tuples::get<2>(centroid_in_cf);
00544 
00545                 trajectory.push_back(pre_translation);
00546 
00547                 // Estimate the trajectory in the last _min_num_frames_for_new_rb frames
00548                 for(int frame = this->_min_num_frames_for_new_rb-2; frame >= 0; frame--)
00549                 {
00550                     FeaturesDataBase::MapOfFeatureLocationPairs one_frame_best_subset;
00551                     BOOST_FOREACH(Feature::Id matched_feat_id, ransac_best_trial_inliers)
00552                     {
00553                         one_frame_best_subset[matched_feat_id] = Feature::LocationPair(this->_features_db->getFeatureNToLastLocation(matched_feat_id, frame),
00554                                                                                        this->_features_db->getFeatureNToLastLocation(matched_feat_id, this->_min_num_frames_for_new_rb-1)
00555                                                                                        - centroid_in_cf);
00556                     }
00557                     Eigen::Matrix4d one_frame_best_transformation_matrix;
00558                     estimateRigidTransformation(one_frame_best_subset,one_frame_best_transformation_matrix);
00559                     trajectory.push_back(one_frame_best_transformation_matrix);
00560                 }
00561 
00562                 Eigen::Matrix4d last_delta = trajectory.at(trajectory.size()-1)*(trajectory.at(trajectory.size()-2).inverse());
00563                 Eigen::Twistd initial_velocity;
00564                 TransformMatrix2Twist(last_delta, initial_velocity);
00565 
00566                 double measured_loop_period_ns= this->_measurement_timestamp_ns - this->_previous_measurement_timestamp_ns;
00567                 initial_velocity /=(measured_loop_period_ns/1e9);
00568 
00569                 this->CreateNewFilter(trajectory, initial_velocity, ransac_best_trial_inliers);
00570             }else
00571             {
00572                 ROS_INFO_STREAM_NAMED("RBMTracker._createNewFilters", "Not enough Consensus to create a new Filter with the free Features ("<<
00573                                       filtered_correspondences.size() <<" inliers are too few, or the the amount of translation " <<
00574                                       amount_translation << " < " << _min_amount_translation_for_new_rb << " and the amount of rotation " <<
00575                                       amount_rotation << " < " << _min_amount_rotation_for_new_rb*(M_PI/180.0));
00576                 return;
00577             }
00578         }
00579     }
00580 }
00581 
00582 std::vector<Eigen::Matrix4d> MultiRBTracker::getPoses() const
00583 {
00584     std::vector<Eigen::Matrix4d> return_filter_results;
00585 
00586     BOOST_FOREACH(RBFilter::Ptr filter, this->_kalman_filters)
00587     {
00588         return_filter_results.push_back(filter->getPose());
00589     }
00590     return return_filter_results;
00591 }
00592 
00593 std::vector<geometry_msgs::PoseWithCovariancePtr> MultiRBTracker::getPosesWithCovariance() const
00594 {
00595     std::vector<geometry_msgs::PoseWithCovariancePtr> return_filter_results;
00596     BOOST_FOREACH(RBFilter::Ptr filter, this->_kalman_filters)
00597     {
00598         return_filter_results.push_back(filter->getPoseWithCovariance());
00599     }
00600     return return_filter_results;
00601 }
00602 
00603 std::vector<geometry_msgs::TwistWithCovariancePtr> MultiRBTracker::getPosesECWithCovariance() const
00604 {
00605     std::vector<geometry_msgs::TwistWithCovariancePtr> return_filter_results;
00606     BOOST_FOREACH(RBFilter::Ptr filter, this->_kalman_filters)
00607     {
00608         return_filter_results.push_back(filter->getPoseECWithCovariance());
00609     }
00610     return return_filter_results;
00611 }
00612 
00613 std::vector<geometry_msgs::TwistWithCovariancePtr> MultiRBTracker::getVelocitiesWithCovariance() const
00614 {
00615     std::vector<geometry_msgs::TwistWithCovariancePtr> return_filter_results;
00616     BOOST_FOREACH(RBFilter::Ptr filter, this->_kalman_filters)
00617     {
00618         return_filter_results.push_back(filter->getVelocityWithCovariance());
00619     }
00620     return return_filter_results;
00621 }
00622 
00623 void MultiRBTracker::addFeatureLocation(Feature::Id f_id, Feature::Location f_loc)
00624 {
00625     if (this->_features_db->addFeatureLocation(f_id, f_loc))
00626     {
00627         // addFeature::LocationOfFeature returns true if the feature is new
00628         _static_environment_filter->addSupportingFeature(f_id);
00629     }
00630 }
00631 
00632 RB_id_t MultiRBTracker::getRBId(int n) const
00633 {
00634     return this->_kalman_filters.at(n)->getId();
00635 }
00636 
00637 int MultiRBTracker::getNumberSupportingFeatures(int n) const
00638 {
00639     return this->_kalman_filters.at(n)->getNumberSupportingFeatures();
00640 }
00641 
00642 FeatureCloudPCL MultiRBTracker::getLabelledSupportingFeatures()
00643 {
00644     FeatureCloudPCL colored_pc;
00645     std::vector<RBFilter::Ptr>::iterator filter_it =this->_kalman_filters.begin();
00646     // TODO: The next line is to not show the supporting features of the static rigid body.
00647     // I commented it out for the ICRA paper: we want to plot all points
00648 
00649     filter_it++;
00650     for (; filter_it != this->_kalman_filters.end(); filter_it++)
00651     {
00652         std::vector<Feature::Id> this_filter_supporting_features = (*filter_it)->getSupportingFeatures();
00653         for (size_t feat_idx = 0; feat_idx < this_filter_supporting_features.size();feat_idx++)
00654         {
00655             if (this->_features_db->isFeatureStored(this_filter_supporting_features.at(feat_idx)))
00656             {
00657                 FeaturePCL temp_point;
00658                 RB_id_t label = (*filter_it)->getId();
00659                 temp_point.x = this->_features_db->getFeatureLastX(this_filter_supporting_features.at(feat_idx));
00660                 temp_point.y = this->_features_db->getFeatureLastY(this_filter_supporting_features.at(feat_idx));
00661                 temp_point.z = this->_features_db->getFeatureLastZ(this_filter_supporting_features.at(feat_idx));
00662 
00663                 temp_point.label = label;
00664                 colored_pc.points.push_back(temp_point);
00665             }
00666         }
00667     }
00668     return colored_pc;
00669 }
00670 
00671 FeatureCloudPCL MultiRBTracker::getFreeFeatures()
00672 {
00673     FeatureCloudPCL colored_pc;
00674     for (size_t feat_idx = 0; feat_idx < _really_free_feat_ids.size();feat_idx++)
00675     {
00676         if (this->_features_db->isFeatureStored(_really_free_feat_ids.at(feat_idx)))
00677         {
00678             FeaturePCL temp_point;
00679             temp_point.x = this->_features_db->getFeatureLastX(_really_free_feat_ids.at(feat_idx));
00680             temp_point.y = this->_features_db->getFeatureLastY(_really_free_feat_ids.at(feat_idx));
00681             temp_point.z = this->_features_db->getFeatureLastZ(_really_free_feat_ids.at(feat_idx));
00682 
00683             temp_point.label = _really_free_feat_ids.at(feat_idx);
00684             colored_pc.points.push_back(temp_point);
00685         }
00686     }
00687     return colored_pc;
00688 }
00689 
00690 FeatureCloudPCL MultiRBTracker::getPredictedFeatures()
00691 {
00692     FeatureCloudPCL colored_pc;
00693     std::vector<RBFilter::Ptr>::iterator filter_it =this->_kalman_filters.begin();
00694     filter_it++;
00695     for (; filter_it != this->_kalman_filters.end(); filter_it++)
00696     {
00697         FeatureCloudPCLwc::Ptr predicted_locations_pc = (*filter_it)->getFeaturesPredicted();
00698         for (size_t feat_idx = 0; feat_idx < predicted_locations_pc->points.size();feat_idx++)
00699         {
00700             FeaturePCL temp_point;
00701             temp_point.x = predicted_locations_pc->points[feat_idx].x;
00702             temp_point.y = predicted_locations_pc->points[feat_idx].y;
00703             temp_point.z = predicted_locations_pc->points[feat_idx].z;
00704             temp_point.label = predicted_locations_pc->points[feat_idx].label;
00705             colored_pc.points.push_back(temp_point);
00706         }
00707         (*filter_it)->resetFeaturesPredicted();
00708     }
00709     return colored_pc;
00710 }
00711 
00712 FeatureCloudPCL MultiRBTracker::getAtBirthFeatures()
00713 {
00714     FeatureCloudPCL colored_pc;
00715     std::vector<RBFilter::Ptr>::iterator filter_it =this->_kalman_filters.begin();
00716     filter_it++;
00717     for (; filter_it != this->_kalman_filters.end(); filter_it++)
00718     {
00719         FeatureCloudPCLwc::Ptr at_birth_locations_pc = (*filter_it)->getFeaturesAtBirth();
00720         for (size_t feat_idx = 0; feat_idx < at_birth_locations_pc->points.size();feat_idx++)
00721         {
00722             FeaturePCL temp_point;
00723             temp_point.x = at_birth_locations_pc->points[feat_idx].x;
00724             temp_point.y = at_birth_locations_pc->points[feat_idx].y;
00725             temp_point.z = at_birth_locations_pc->points[feat_idx].z;
00726             temp_point.label = at_birth_locations_pc->points[feat_idx].label;
00727             colored_pc.points.push_back(temp_point);
00728         }
00729         (*filter_it)->resetFeaturesAtBirth();
00730     }
00731     return colored_pc;
00732 }
00733 
00734 std::vector<Eigen::Vector3d> MultiRBTracker::getCentroids() const
00735 {
00736     std::vector<Eigen::Vector3d> centroids;
00737     centroids.push_back(Eigen::Vector3d(0., 0., 0.));
00738     std::vector<RBFilter::Ptr>::const_iterator filter_it = this->_kalman_filters.begin();
00739     filter_it++;    //Ignore the static environment
00740 
00741     for (; filter_it != this->_kalman_filters.end(); filter_it++)
00742     {
00743         //NEW: the first time we send as centroid the centroid we used for the trajectory estimation
00744         //In this way we can inform the next level of the initial pose of the rigid body
00745         if((*filter_it)->getTrajectory().size() < this->_min_num_frames_for_new_rb)
00746         {
00747             Feature::Location initial_location = (*filter_it)->getIntialLocationOfCentroid();
00748             centroids.push_back(Eigen::Vector3d(boost::tuples::get<0>(initial_location),
00749                                                 boost::tuples::get<1>(initial_location),
00750                                                 boost::tuples::get<2>(initial_location)));
00751         }else{
00752             Eigen::Vector3d temp_centroid = Eigen::Vector3d(0., 0., 0.);
00753             int supporting_feats_ctr = 0;
00754             std::vector<Feature::Id> this_filter_supporting_features = (*filter_it)->getSupportingFeatures();
00755             for (size_t feat_idx = 0; feat_idx < this_filter_supporting_features.size();feat_idx++)
00756             {
00757                 if (this->_features_db->isFeatureStored(this_filter_supporting_features.at(feat_idx)))
00758                 {
00759                     temp_centroid.x() += this->_features_db->getFeatureLastX(this_filter_supporting_features.at(feat_idx));
00760                     temp_centroid.y() += this->_features_db->getFeatureLastY(this_filter_supporting_features.at(feat_idx));
00761                     temp_centroid.z() += this->_features_db->getFeatureLastZ(this_filter_supporting_features.at(feat_idx));
00762                     supporting_feats_ctr++;
00763                 }
00764             }
00765             centroids.push_back(temp_centroid / (double)supporting_feats_ctr);
00766         }
00767     }
00768     return centroids;
00769 }
00770 
00771 void MultiRBTracker::addPredictedState(const rbt_state_t& predicted_state, const double &predicted_state_timestamp_ns)
00772 {    
00773     BOOST_FOREACH(omip_msgs::RigidBodyPoseAndVelMsg predicted_pose_and_vel, predicted_state.rb_poses_and_vels)
00774     {
00775         BOOST_FOREACH(RBFilter::Ptr filter, this->_kalman_filters)
00776         {
00777             if (filter->getId() == predicted_pose_and_vel.rb_id)
00778             {
00779                 //ROS_WARN_STREAM_NAMED("MultiRBTracker.addPredictedState", "Prediction for body " << predicted_pose_and_vel.rb_id);
00780                 filter->setPredictedState(predicted_pose_and_vel);
00781             }
00782         }
00783     }
00784 }
00785 
00786 FeaturesDataBase::Ptr MultiRBTracker::getFeaturesDatabase()
00787 {
00788     return this->_features_db;
00789 }
00790 


rb_tracker
Author(s): Roberto Martín-Martín
autogenerated on Sat Jun 8 2019 18:26:42