MultiRBTracker.cpp
Go to the documentation of this file.
1 #include <boost/foreach.hpp>
2 
4 
6 
7 #include <cmath>
8 
9 #include <pcl/correspondence.h>
10 #include <pcl/registration/correspondence_rejection_sample_consensus.h>
11 
13 
14 #if ROS_VERSION_MINIMUM(1, 11, 1) // if current ros version is >= 1.11.1 (indigo)
15 #else
17 #endif
18 
19 #include <pcl/console/print.h>
20 
21 using namespace omip;
22 
24  const FeaturesDataBase::MapOfFeatureLocationPairs& last2locations,
25  Eigen::Matrix4d &transformation_matrix)
26 {
27  // Convert to Eigen format
28  const int npts = static_cast<int>(last2locations.size());
29 
30  Eigen::Matrix<double, 3, Eigen::Dynamic> cloud_src(3, npts);
31  Eigen::Matrix<double, 3, Eigen::Dynamic> cloud_tgt(3, npts);
32 
33  FeaturesDataBase::MapOfFeatureLocationPairs::const_iterator locations_it =
34  last2locations.begin();
35  FeaturesDataBase::MapOfFeatureLocationPairs::const_iterator locations_it_end =
36  last2locations.end();
37  for (int i = 0; locations_it != locations_it_end; locations_it++, i++)
38  {
39  cloud_src(0, i) = locations_it->second.second.get<0>();
40  cloud_src(1, i) = locations_it->second.second.get<1>();
41  cloud_src(2, i) = locations_it->second.second.get<2>();
42 
43  cloud_tgt(0, i) = locations_it->second.first.get<0>();
44  cloud_tgt(1, i) = locations_it->second.first.get<1>();
45  cloud_tgt(2, i) = locations_it->second.first.get<2>();
46  }
47 
48  // Call Umeyama directly from Eigen (PCL patched version until Eigen is released)
49  transformation_matrix = Eigen::umeyama(cloud_src, cloud_tgt, false);
50 }
51 
53  double loop_period_ns,
54  int ransac_iterations,
55  double estimation_error_threshold,
56  double static_motion_threshold,
57  double new_rbm_error_threshold,
58  double max_error_to_reassign_feats,
59  int supporting_features_threshold,
60  int min_num_feats_for_new_rb,
61  int min_num_frames_for_new_rb,
62  int initial_cam_motion_constraint,
63  static_environment_tracker_t static_environment_tracker_type) :
64  RecursiveEstimatorFilterInterface(loop_period_ns),
65  _max_num_rb(max_num_rb),
66  _ransac_iterations(ransac_iterations),
67  _estimation_error_threshold(estimation_error_threshold),
68  _static_motion_threshold(static_motion_threshold),
69  _new_rbm_error_threshold(new_rbm_error_threshold),
70  _max_error_to_reassign_feats(max_error_to_reassign_feats),
71  _supporting_features_threshold(supporting_features_threshold),
72  _min_num_feats_for_new_rb(min_num_feats_for_new_rb),
73  _min_num_frames_for_new_rb(min_num_frames_for_new_rb),
74  _min_num_points_in_segment(0),
75  _min_probabilistic_value(0.0),
76  _max_fitness_score(0.0),
77  _min_num_supporting_feats_to_correct(7),
78  _max_distance_ee(-1),
79  _max_distance_irb(-1)
80 {
81 
82  //_really_free_feats_file.open("really_free_feats_file.txt");
83  this->_filter_name = "RBMFilter";
84 
85  if (this->_features_db)
86  this->_features_db.reset();
87 
89 
91 
92  // The static environment exists always as initial hypothesis
93  // We can track the static enviroment (visual odometry) using different computation methods: ICP or EKF
95  this->_features_db,
97  _static_environment_filter->setComputationType(static_environment_tracker_type);
98  _static_environment_filter->setFeaturesDatabase(this->_features_db);
99  _static_environment_filter->setMotionConstraint(initial_cam_motion_constraint);
100 
102 }
103 
105 {
106  _static_environment_filter->setMeasurementDepthFactor(this->_meas_depth_factor);
107  _static_environment_filter->setMinCovarianceMeasurementX(this->_min_cov_meas_x);
108  _static_environment_filter->setMinCovarianceMeasurementY(this->_min_cov_meas_y);
109  _static_environment_filter->setMinCovarianceMeasurementZ(this->_min_cov_meas_z);
110  _static_environment_filter->setPriorCovariancePose(this->_prior_cov_pose);
111  _static_environment_filter->setPriorCovarianceVelocity(this->_prior_cov_vel);
112  _static_environment_filter->setCovarianceSystemAccelerationTx(this->_cov_sys_acc_tx);
113  _static_environment_filter->setCovarianceSystemAccelerationTy(this->_cov_sys_acc_ty);
114  _static_environment_filter->setCovarianceSystemAccelerationTz(this->_cov_sys_acc_tz);
115  _static_environment_filter->setCovarianceSystemAccelerationRx(this->_cov_sys_acc_rx);
116  _static_environment_filter->setCovarianceSystemAccelerationRy(this->_cov_sys_acc_ry);
117  _static_environment_filter->setCovarianceSystemAccelerationRz(this->_cov_sys_acc_rz);
118  _static_environment_filter->setNumberOfTrackedFeatures(this->_num_tracked_feats);
119  _static_environment_filter->setMinNumberOfSupportingFeaturesToCorrectPredictedState(this->_min_num_supporting_feats_to_correct);
121 }
122 
124 {
125 
126 }
127 
128 void MultiRBTracker::setMeasurement(rbt_measurement_t acquired_measurement, const double& measurement_timestamp)
129 {
131 
132  {
133  boost::mutex::scoped_lock(this->_measurement_timestamp_ns_mutex);
134  this->_measurement_timestamp_ns = measurement_timestamp;
135  }
136 
137  this->_features_db->clearListOfAliveFeatureIds();
138  this->_measurement = acquired_measurement;
139 
140  int num_tracked_features = acquired_measurement->points.size();
141 
142  int tracked_features_index = 0;
143  uint32_t feature_id;
144  for (; tracked_features_index < num_tracked_features; tracked_features_index++)
145  {
146  feature_id = acquired_measurement->points[tracked_features_index].label;
147  if(feature_id != 0)
148  {
149  Feature::Location feature_location = Feature::Location(acquired_measurement->points[tracked_features_index].x, acquired_measurement->points[tracked_features_index].y,
150  acquired_measurement->points[tracked_features_index].z);
151  this->addFeatureLocation(feature_id, feature_location);
152  }
153  }
154  this->_features_db->step();
155 }
156 
157 void MultiRBTracker::predictState(double time_interval_ns)
158 {
159  //First we update the filters using the internal state (system update)
160  for (std::vector<RBFilter::Ptr>::iterator filter_it = this->_kalman_filters.begin(); filter_it != this->_kalman_filters.end(); filter_it++)
161  {
162  (*filter_it)->predictState(time_interval_ns);
163  (*filter_it)->doNotUsePredictionFromHigherLevel();
164  }
165 }
166 
167 // NOTE: The location of the Features predicted by the static RBFilter is the initial location of these Features
168 // When these predictions are used for the visual tracking the searching area for the Features is static until these Features can
169 // be assigned to an existing RB (or a group of them create a new one)
170 // The consequence is that the Features could go out of the searching area before they are detected as moving
171 // There are two solutions:
172 // 1- Use the static_motion_threshold in the estimation of the searching area. The searching area should cover motions of static_motion_threshold
173 // at the depth of the Feature (COMPLEX)
174 // 2- Only for the static RBFilter the predicted locations retrieved here are the latest locations of the Features. This is ugly (treats the static
175 // RBFilter as an special one) but easier
177 {
178  std::vector<RBFilter::Ptr>::iterator filter_it = this->_kalman_filters.begin();
179  for (; filter_it != this->_kalman_filters.end(); filter_it++)
180  {
181  (*filter_it)->predictMeasurement();
182  }
183 
184  this->_predicted_measurement->points.clear();
185 
186  std::vector<Feature::Id> feature_ids;
187  FeatureCloudPCLwc one_filter_predicted_measurement;
188  filter_it = this->_kalman_filters.begin();
189  filter_it++;
190  for (; filter_it != this->_kalman_filters.end(); filter_it++)
191  {
192  one_filter_predicted_measurement = (*filter_it)->getPredictedMeasurement();
193  for (size_t feat_idx = 0; feat_idx < one_filter_predicted_measurement.points.size(); feat_idx++)
194  {
195  this->_predicted_measurement->points.push_back(one_filter_predicted_measurement.points.at(feat_idx));
196  feature_ids.push_back(one_filter_predicted_measurement.points.at(feat_idx).label);
197  }
198  }
199 
200  // The free Features are not in any RBFilter. We collect their latest locations
201  std::vector<Feature::Id> free_features_ids = this->EstimateFreeFeatures(feature_ids);
202  FeaturePCLwc free_feat;
203  for (size_t feat_idx = 0; feat_idx < free_features_ids.size(); feat_idx++)
204  {
205  free_feat.x = this->_features_db->getFeatureLastX(free_features_ids.at(feat_idx));
206  free_feat.y = this->_features_db->getFeatureLastY(free_features_ids.at(feat_idx));
207  free_feat.z = this->_features_db->getFeatureLastZ(free_features_ids.at(feat_idx));
208  free_feat.label = free_features_ids.at(feat_idx);
209  free_feat.covariance[0] = 20;
210  this->_predicted_measurement->points.push_back(free_feat);
211  }
212 }
213 
215 {
217  return this->_predicted_measurement;
218 }
219 
221 {
222  std::vector<Feature::Id> all_filters_supporting_features;
223  for (std::vector<RBFilter::Ptr>::iterator filter_it = this->_kalman_filters.begin(); filter_it != this->_kalman_filters.end();)
224  {
225  (*filter_it)->estimateBestPredictionAndSupportingFeatures();
226  std::vector<Feature::Id> this_filter_supporting_features = (*filter_it)->getSupportingFeatures();
227 
228  // If there are no features supporting to the EKF we delete it (no re-finding of RBs/EKFs possible)
229  // Don't delete the filter of the environment!!! (filter_it == this->_kalman_filters.begin())
230  if (this_filter_supporting_features.size() < (size_t)this->_supporting_features_threshold
231  && *filter_it != this->_static_environment_filter )
232  {
233  Eigen::Twistd last_pose_ec;
234  TransformMatrix2Twist((*filter_it)->getPose(), last_pose_ec);
235  ROS_ERROR_NAMED( "MultiRBTracker.estimateBestPredictionsAndSupportingFeatures",
236  "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",
237  (int)(*filter_it)->getId(),
238  (int)this_filter_supporting_features.size() ,
239  (int)(this->_supporting_features_threshold),
240  last_pose_ec.vx(),
241  last_pose_ec.vy(),
242  last_pose_ec.vz(),
243  last_pose_ec.rx(),
244  last_pose_ec.ry(),
245  last_pose_ec.rz());
246  filter_it = this->_kalman_filters.erase(filter_it);
247  }
248  else
249  {
250  all_filters_supporting_features.insert(all_filters_supporting_features.end(),
251  this_filter_supporting_features.begin(),
252  this_filter_supporting_features.end());
253  filter_it++;
254  }
255  }
256  return all_filters_supporting_features;
257 }
258 
260 {
261  // 1: Estimate the supporting features of each filter
262  std::vector<Feature::Id> all_filters_supporting_features = this->estimateBestPredictionsAndSupportingFeatures();
263 
264  // 2: Estimate the free features
265  std::vector<Feature::Id> free_feat_ids = this->EstimateFreeFeatures(all_filters_supporting_features);
266 
267  // 3: Try to assign free features to existing RBs
268  std::vector<Feature::Id> really_free_feat_ids = this->ReassignFreeFeatures(free_feat_ids);
269 
270  ROS_INFO_NAMED("MultiRBTracker::correctState","Moving bodies: %3d, free features: %3d", (int)this->_kalman_filters.size(), (int)really_free_feat_ids.size());
271 
272  // 4: Correct the predicted state of each RBFilter using the last acquired Measurement
273  for (std::vector<RBFilter::Ptr>::iterator filter_it = this->_kalman_filters.begin(); filter_it != this->_kalman_filters.end(); filter_it++)
274  {
275  (*filter_it)->correctState();
276  }
277 
278  // 5: Try to create new filters for the "really free" features
279  // NOTE: Keep this step after the correctState of the RBFilters, otherwise you will create a filter and correct it in the first iteration!
280  if(this->_kalman_filters.size() < this->_max_num_rb)
281  {
282  this->TryToCreateNewFilter(really_free_feat_ids);
283  }
284 }
285 
287 {
288  this->_state.rb_poses_and_vels.clear();
289 
290  std::vector<geometry_msgs::TwistWithCovariancePtr> tracked_poses_twist_with_cov = this->getPosesECWithCovariance();
291  std::vector<geometry_msgs::TwistWithCovariancePtr> tracked_vels_twist_with_cov = this->getVelocitiesWithCovariance();
292  std::vector<Eigen::Vector3d> centroids = this->getCentroids();
293 
294  RB_id_t RB_id;
295 
296  for (size_t poses_idx = 0; poses_idx < tracked_poses_twist_with_cov.size(); poses_idx++)
297  {
298  RB_id = this->getRBId(poses_idx);
299 
300  geometry_msgs::Point centroid;
301  centroid.x = centroids.at(poses_idx).x();
302  centroid.y = centroids.at(poses_idx).y();
303  centroid.z = centroids.at(poses_idx).z();
304 
305  omip_msgs::RigidBodyPoseAndVelMsg rbpose_and_vel;
306  rbpose_and_vel.rb_id = RB_id;
307  rbpose_and_vel.pose_wc = *(tracked_poses_twist_with_cov.at(poses_idx));
308  rbpose_and_vel.velocity_wc = *(tracked_vels_twist_with_cov.at(poses_idx));
309  rbpose_and_vel.centroid = centroid;
310  this->_state.rb_poses_and_vels.push_back(rbpose_and_vel);
311  }
312 }
313 
315 {
316  return this->_state;
317 }
318 
319 void MultiRBTracker::setDynamicReconfigureValues(rb_tracker::RBTrackerDynReconfConfig &config)
320 {
321  _static_environment_filter->setMotionConstraint(config.cam_motion_constraint);
322  this->_min_num_feats_for_new_rb = config.min_feats_new_rb;
323  this->_supporting_features_threshold = config.min_feats_survive_rb;
324 }
325 
326 void MultiRBTracker::processMeasurementFromShapeTracker(const omip_msgs::ShapeTrackerStates &meas_from_st)
327 {
328  for(int idx = 0; idx < meas_from_st.shape_tracker_states.size(); idx++)
329  {
330  BOOST_FOREACH(RBFilter::Ptr filter, this->_kalman_filters)
331  {
332  if (filter->getId() == meas_from_st.shape_tracker_states.at(idx).rb_id )
333  {
334  //Check if the flag indicates that this refinement is reliable
335  if((meas_from_st.shape_tracker_states.at(idx).number_of_points_of_model > _min_num_points_in_segment) &&
336  (meas_from_st.shape_tracker_states.at(idx).number_of_points_of_current_pc > _min_num_points_in_segment) &&
337  (meas_from_st.shape_tracker_states.at(idx).probabilistic_value > _min_probabilistic_value) &&
338  (meas_from_st.shape_tracker_states.at(idx).fitness_score < _max_fitness_score))
339  {
340  ROS_ERROR_STREAM("Integrating shape-based tracked pose RB " << meas_from_st.shape_tracker_states.at(idx).rb_id);
341  filter->integrateShapeBasedPose(meas_from_st.shape_tracker_states.at(idx).pose_wc, this->_measurement_timestamp_ns - meas_from_st.header.stamp.toNSec() );
342  }else{
343  ROS_ERROR_STREAM("Ignoring shape-based tracked pose RB " << meas_from_st.shape_tracker_states.at(idx).rb_id);
344  }
345  }
346  }
347  }
348 }
349 
350 void MultiRBTracker::CreateNewFilter(const std::vector<Eigen::Matrix4d>& initial_trajectory,
351  const Eigen::Twistd& initial_velocity,
352  const std::vector<Feature::Id>& initial_supporting_feats)
353 {
355  initial_trajectory,
356  initial_velocity,
357  this->_features_db,
359 
360  new_kf->setMeasurementDepthFactor(this->_meas_depth_factor);
361  new_kf->setMinCovarianceMeasurementX(this->_min_cov_meas_x);
362  new_kf->setMinCovarianceMeasurementY(this->_min_cov_meas_y);
363  new_kf->setMinCovarianceMeasurementZ(this->_min_cov_meas_z);
364  new_kf->setPriorCovariancePose(this->_prior_cov_pose);
365  new_kf->setPriorCovarianceVelocity(this->_prior_cov_vel);
366  new_kf->setCovarianceSystemAccelerationTx(this->_cov_sys_acc_tx);
367  new_kf->setCovarianceSystemAccelerationTy(this->_cov_sys_acc_ty);
368  new_kf->setCovarianceSystemAccelerationTz(this->_cov_sys_acc_tz);
369  new_kf->setCovarianceSystemAccelerationRx(this->_cov_sys_acc_rx);
370  new_kf->setCovarianceSystemAccelerationRy(this->_cov_sys_acc_ry);
371  new_kf->setCovarianceSystemAccelerationRz(this->_cov_sys_acc_rz);
372  new_kf->setNumberOfTrackedFeatures(this->_num_tracked_feats);
373  new_kf->setMinNumberOfSupportingFeaturesToCorrectPredictedState(this->_min_num_supporting_feats_to_correct);
374 
375  new_kf->Init();
376 
377  this->_kalman_filters.push_back(new_kf);
378  BOOST_FOREACH(Feature::Id supporting_feat_id, initial_supporting_feats)
379  {
380  new_kf->addSupportingFeature(supporting_feat_id);
381  }
382 }
383 
384 std::vector<Feature::Id> MultiRBTracker::EstimateFreeFeatures(const std::vector<Feature::Id>& supporting_features)
385 {
386  // We check the set of free features = alive features - supporting features
387  std::vector<Feature::Id> alive_feat_ids = this->_features_db->getListOfAliveFeatureIds();
388  std::vector<Feature::Id> free_feat_ids;
389  BOOST_FOREACH(Feature::Id alive_feat_id, alive_feat_ids)
390  {
391  // If the feature ID is not in the list of supporting features -> Free feature
392  if (std::find(supporting_features.begin(), supporting_features.end(),alive_feat_id) == supporting_features.end())
393  {
394  free_feat_ids.push_back(alive_feat_id);
395  }
396  }
397  _free_feat_ids = free_feat_ids;
398  return free_feat_ids;
399 }
400 
401 // 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)
402 // Therefore, the "age of the feature" is +1 the age it would have when predicting the measurement
403 // EXCEPT if the measurement prediction has to be called again in the loop!!!!!
404 std::vector<Feature::Id> MultiRBTracker::ReassignFreeFeatures(const std::vector<Feature::Id>& free_feat_ids)
405 {
406  std::vector<Feature::Id> really_free_feat_ids;
407 
408  Feature::Ptr free_feat;
409  Feature::Location free_feature_last_location;
410  Feature::Location free_feature_pre_last_location;
411  Feature::Location free_feature_predicted_location;
412  double feat_error = 0.0;
413  double prediction_error = 0.0;
414  int best_ekf_idx = -1;
415  Eigen::Matrix4d predicted_pose;
416 
417  // Check for each free feature if we can add it to one of the existing vision-based rigid bodies
418  BOOST_FOREACH(Feature::Id free_feat_id, free_feat_ids)
419  {
420  free_feature_last_location = this->_features_db->getFeatureLastLocation(free_feat_id);
421  free_feature_pre_last_location = this->_features_db->getFeatureNextToLastLocation(free_feat_id);
422  free_feat = this->_features_db->getFeature(free_feat_id);
423  feat_error = (double)this->_max_error_to_reassign_feats;
424  best_ekf_idx = -1;
425  Feature::Location best_predicted_location;
426 
427  // Get the prediction from each of the existing vision-based rigid bodies
428  // TODO: Use the Mahalanobis distance between the uncertain feature location and its predicted location
429  for (size_t filter_idx = 0; filter_idx < this->_kalman_filters.size();filter_idx++)
430  {
431  // Get the most likely prediction about the next feature state (the likelihood is estimated in estimateSupportingFeatures and copied to the others
432  // so it is equivalent to get the belief pose from any hypothesis)
433  //prediction_error = this->_kalman_filters.at(filter_idx)->PredictFeatureLocationNew(free_feat, false, true);
434 
435  predicted_pose = this->_kalman_filters.at(filter_idx)->getPose();
436  this->_kalman_filters.at(filter_idx)->PredictFeatureLocation(free_feat, predicted_pose, false, free_feature_predicted_location,true);
437  prediction_error = L2Distance(free_feature_last_location, free_feature_predicted_location);
438 
439  if (prediction_error < feat_error)
440  {
441  feat_error = prediction_error;
442  best_ekf_idx = filter_idx;
443  best_predicted_location = free_feature_predicted_location;
444  }
445  }
446 
447  if (best_ekf_idx != -1)
448  {
449  this->_kalman_filters.at(best_ekf_idx)->addSupportingFeature(free_feat_id);
450  this->_kalman_filters.at(best_ekf_idx)->addPredictedFeatureLocation(best_predicted_location,free_feature_pre_last_location, free_feat_id);
451  }
452  else
453  {
454  really_free_feat_ids.push_back(free_feat_id);
455  }
456  }
457  _really_free_feat_ids = really_free_feat_ids;
458  return really_free_feat_ids;
459 }
460 
461 void MultiRBTracker::TryToCreateNewFilter(const std::vector<Feature::Id>& really_free_feat_ids)
462 {
463  // First check that the number of free features is over the minimum number to estimate motion
464  if(really_free_feat_ids.size() > this->_min_num_feats_for_new_rb)
465  {
466  pcl::PointCloud<pcl::PointXYZ>::Ptr source = pcl::PointCloud<pcl::PointXYZ>::Ptr(new pcl::PointCloud<pcl::PointXYZ>());
467  pcl::PointCloud<pcl::PointXYZ>::Ptr target = pcl::PointCloud<pcl::PointXYZ>::Ptr(new pcl::PointCloud<pcl::PointXYZ>());
468  pcl::Correspondences initial_correspondeces, filtered_correspondences;
469  int index = 0;
470  std::map<int, int> index_to_feat_id;
471  PointPCL point_pcl;
472 
473  //Iterate over the free features
474  BOOST_FOREACH(Feature::Id free_feat_id, really_free_feat_ids)
475  {
476  // If the free feature is old enough, we add it to the source-target point clouds and add a correspondence
477  if ((int)this->_features_db->getFeatureAge(free_feat_id) > this->_min_num_frames_for_new_rb)
478  {
479  Feature::Location first = this->_features_db->getFeatureNToLastLocation(free_feat_id, this->_min_num_frames_for_new_rb);
480  Feature::Location second = this->_features_db->getFeatureLastLocation(free_feat_id);
481  Location2PointPCL(first, point_pcl);
482  source->push_back(point_pcl);
483  Location2PointPCL(second, point_pcl);
484  target->push_back(point_pcl);
485  initial_correspondeces.push_back(pcl::Correspondence(index, index, 0.0));
486  index_to_feat_id[index] = free_feat_id;
487  index++;
488  }
489  }
490 
491  // If enough of the free features are old enough, we try to estimate the motion
492  if(index > this->_min_num_feats_for_new_rb)
493  {
494  //pcl::console::setVerbosityLevel(pcl::console::L_DEBUG);
495  // PCL RANSAC
496  pcl::registration::CorrespondenceRejectorSampleConsensus<pcl::PointXYZ> rejector;
497  rejector.setInputSource(source);
498  rejector.setInputTarget(target);
499  rejector.setInlierThreshold(this->_new_rbm_error_threshold);
500  rejector.setMaximumIterations(this->_ransac_iterations);
501  rejector.getRemainingCorrespondences(initial_correspondeces, filtered_correspondences);
502 
503  Eigen::Matrix4f best_transformation = rejector.getBestTransformation();
504 
505  // If the number of free features that are inliers of the best transformation is over the minimum number to estimate motion
506  // AND if the best transformation is not just noise:
507  // - Translation is larger than min_amount_translation meters
508  // - Rotation around the axis is larger than min_amount_rotation degrees
509  Eigen::Transform<float, 3, Eigen::Affine> best_transformation2(best_transformation);
510  double amount_translation = best_transformation2.translation().norm();
511  Eigen::AngleAxisf best_axis_angle;
512  double amount_rotation = best_axis_angle.fromRotationMatrix(best_transformation2.rotation()).angle();
513 
514  if ((int)filtered_correspondences.size() > this->_min_num_feats_for_new_rb && (
515  amount_translation > _min_amount_translation_for_new_rb ||
516  amount_rotation > _min_amount_rotation_for_new_rb*(M_PI/180.0) ) )
517  {
518  std::vector<Eigen::Matrix4d> trajectory;
519  Feature::Location centroid_in_cf;
520 
521  //Collect the ids of the matched features
522  //and compute the centroid of the supporting features N frames ago
523  //The centroid will be used to "place" the frame of the rigid body -> Initial transformation of the rigid body
524  //is a pure translation to the location of the centroid
525  std::vector<Feature::Id> ransac_best_trial_inliers;
526  BOOST_FOREACH(pcl::Correspondence filter_correspondence, filtered_correspondences)
527  {
528  int feature_id = index_to_feat_id.at(filter_correspondence.index_match);
529  ransac_best_trial_inliers.push_back(feature_id);
530  Feature::Location feat_loc = this->_features_db->getFeatureNToLastLocation(feature_id, this->_min_num_frames_for_new_rb-1);
531  boost::tuples::get<0>(centroid_in_cf) = boost::tuples::get<0>(centroid_in_cf) + boost::tuples::get<0>(feat_loc);
532  boost::tuples::get<1>(centroid_in_cf) = boost::tuples::get<1>(centroid_in_cf) + boost::tuples::get<1>(feat_loc);
533  boost::tuples::get<2>(centroid_in_cf) = boost::tuples::get<2>(centroid_in_cf) + boost::tuples::get<2>(feat_loc);
534  }
535 
536  boost::tuples::get<0>(centroid_in_cf) = boost::tuples::get<0>(centroid_in_cf)/(double)filtered_correspondences.size();
537  boost::tuples::get<1>(centroid_in_cf) = boost::tuples::get<1>(centroid_in_cf)/(double)filtered_correspondences.size();
538  boost::tuples::get<2>(centroid_in_cf) = boost::tuples::get<2>(centroid_in_cf)/(double)filtered_correspondences.size();
539 
540  Eigen::Matrix4d pre_translation = Eigen::Matrix4d::Identity();
541  pre_translation(0,3) = boost::tuples::get<0>(centroid_in_cf);
542  pre_translation(1,3) = boost::tuples::get<1>(centroid_in_cf);
543  pre_translation(2,3) = boost::tuples::get<2>(centroid_in_cf);
544 
545  trajectory.push_back(pre_translation);
546 
547  // Estimate the trajectory in the last _min_num_frames_for_new_rb frames
548  for(int frame = this->_min_num_frames_for_new_rb-2; frame >= 0; frame--)
549  {
550  FeaturesDataBase::MapOfFeatureLocationPairs one_frame_best_subset;
551  BOOST_FOREACH(Feature::Id matched_feat_id, ransac_best_trial_inliers)
552  {
553  one_frame_best_subset[matched_feat_id] = Feature::LocationPair(this->_features_db->getFeatureNToLastLocation(matched_feat_id, frame),
554  this->_features_db->getFeatureNToLastLocation(matched_feat_id, this->_min_num_frames_for_new_rb-1)
555  - centroid_in_cf);
556  }
557  Eigen::Matrix4d one_frame_best_transformation_matrix;
558  estimateRigidTransformation(one_frame_best_subset,one_frame_best_transformation_matrix);
559  trajectory.push_back(one_frame_best_transformation_matrix);
560  }
561 
562  Eigen::Matrix4d last_delta = trajectory.at(trajectory.size()-1)*(trajectory.at(trajectory.size()-2).inverse());
563  Eigen::Twistd initial_velocity;
564  TransformMatrix2Twist(last_delta, initial_velocity);
565 
566  double measured_loop_period_ns= this->_measurement_timestamp_ns - this->_previous_measurement_timestamp_ns;
567  initial_velocity /=(measured_loop_period_ns/1e9);
568 
569  this->CreateNewFilter(trajectory, initial_velocity, ransac_best_trial_inliers);
570  }else
571  {
572  ROS_INFO_STREAM_NAMED("RBMTracker._createNewFilters", "Not enough Consensus to create a new Filter with the free Features ("<<
573  filtered_correspondences.size() <<" inliers are too few, or the the amount of translation " <<
574  amount_translation << " < " << _min_amount_translation_for_new_rb << " and the amount of rotation " <<
575  amount_rotation << " < " << _min_amount_rotation_for_new_rb*(M_PI/180.0));
576  return;
577  }
578  }
579  }
580 }
581 
582 std::vector<Eigen::Matrix4d> MultiRBTracker::getPoses() const
583 {
584  std::vector<Eigen::Matrix4d> return_filter_results;
585 
586  BOOST_FOREACH(RBFilter::Ptr filter, this->_kalman_filters)
587  {
588  return_filter_results.push_back(filter->getPose());
589  }
590  return return_filter_results;
591 }
592 
593 std::vector<geometry_msgs::PoseWithCovariancePtr> MultiRBTracker::getPosesWithCovariance() const
594 {
595  std::vector<geometry_msgs::PoseWithCovariancePtr> return_filter_results;
596  BOOST_FOREACH(RBFilter::Ptr filter, this->_kalman_filters)
597  {
598  return_filter_results.push_back(filter->getPoseWithCovariance());
599  }
600  return return_filter_results;
601 }
602 
603 std::vector<geometry_msgs::TwistWithCovariancePtr> MultiRBTracker::getPosesECWithCovariance() const
604 {
605  std::vector<geometry_msgs::TwistWithCovariancePtr> return_filter_results;
606  BOOST_FOREACH(RBFilter::Ptr filter, this->_kalman_filters)
607  {
608  return_filter_results.push_back(filter->getPoseECWithCovariance());
609  }
610  return return_filter_results;
611 }
612 
613 std::vector<geometry_msgs::TwistWithCovariancePtr> MultiRBTracker::getVelocitiesWithCovariance() const
614 {
615  std::vector<geometry_msgs::TwistWithCovariancePtr> return_filter_results;
616  BOOST_FOREACH(RBFilter::Ptr filter, this->_kalman_filters)
617  {
618  return_filter_results.push_back(filter->getVelocityWithCovariance());
619  }
620  return return_filter_results;
621 }
622 
624 {
625  if (this->_features_db->addFeatureLocation(f_id, f_loc))
626  {
627  // addFeature::LocationOfFeature returns true if the feature is new
628  _static_environment_filter->addSupportingFeature(f_id);
629  }
630 }
631 
633 {
634  return this->_kalman_filters.at(n)->getId();
635 }
636 
638 {
639  return this->_kalman_filters.at(n)->getNumberSupportingFeatures();
640 }
641 
643 {
644  FeatureCloudPCL colored_pc;
645  std::vector<RBFilter::Ptr>::iterator filter_it =this->_kalman_filters.begin();
646  // TODO: The next line is to not show the supporting features of the static rigid body.
647  // I commented it out for the ICRA paper: we want to plot all points
648 
649  filter_it++;
650  for (; filter_it != this->_kalman_filters.end(); filter_it++)
651  {
652  std::vector<Feature::Id> this_filter_supporting_features = (*filter_it)->getSupportingFeatures();
653  for (size_t feat_idx = 0; feat_idx < this_filter_supporting_features.size();feat_idx++)
654  {
655  if (this->_features_db->isFeatureStored(this_filter_supporting_features.at(feat_idx)))
656  {
657  FeaturePCL temp_point;
658  RB_id_t label = (*filter_it)->getId();
659  temp_point.x = this->_features_db->getFeatureLastX(this_filter_supporting_features.at(feat_idx));
660  temp_point.y = this->_features_db->getFeatureLastY(this_filter_supporting_features.at(feat_idx));
661  temp_point.z = this->_features_db->getFeatureLastZ(this_filter_supporting_features.at(feat_idx));
662 
663  temp_point.label = label;
664  colored_pc.points.push_back(temp_point);
665  }
666  }
667  }
668  return colored_pc;
669 }
670 
672 {
673  FeatureCloudPCL colored_pc;
674  for (size_t feat_idx = 0; feat_idx < _really_free_feat_ids.size();feat_idx++)
675  {
676  if (this->_features_db->isFeatureStored(_really_free_feat_ids.at(feat_idx)))
677  {
678  FeaturePCL temp_point;
679  temp_point.x = this->_features_db->getFeatureLastX(_really_free_feat_ids.at(feat_idx));
680  temp_point.y = this->_features_db->getFeatureLastY(_really_free_feat_ids.at(feat_idx));
681  temp_point.z = this->_features_db->getFeatureLastZ(_really_free_feat_ids.at(feat_idx));
682 
683  temp_point.label = _really_free_feat_ids.at(feat_idx);
684  colored_pc.points.push_back(temp_point);
685  }
686  }
687  return colored_pc;
688 }
689 
691 {
692  FeatureCloudPCL colored_pc;
693  std::vector<RBFilter::Ptr>::iterator filter_it =this->_kalman_filters.begin();
694  filter_it++;
695  for (; filter_it != this->_kalman_filters.end(); filter_it++)
696  {
697  FeatureCloudPCLwc::Ptr predicted_locations_pc = (*filter_it)->getFeaturesPredicted();
698  for (size_t feat_idx = 0; feat_idx < predicted_locations_pc->points.size();feat_idx++)
699  {
700  FeaturePCL temp_point;
701  temp_point.x = predicted_locations_pc->points[feat_idx].x;
702  temp_point.y = predicted_locations_pc->points[feat_idx].y;
703  temp_point.z = predicted_locations_pc->points[feat_idx].z;
704  temp_point.label = predicted_locations_pc->points[feat_idx].label;
705  colored_pc.points.push_back(temp_point);
706  }
707  (*filter_it)->resetFeaturesPredicted();
708  }
709  return colored_pc;
710 }
711 
713 {
714  FeatureCloudPCL colored_pc;
715  std::vector<RBFilter::Ptr>::iterator filter_it =this->_kalman_filters.begin();
716  filter_it++;
717  for (; filter_it != this->_kalman_filters.end(); filter_it++)
718  {
719  FeatureCloudPCLwc::Ptr at_birth_locations_pc = (*filter_it)->getFeaturesAtBirth();
720  for (size_t feat_idx = 0; feat_idx < at_birth_locations_pc->points.size();feat_idx++)
721  {
722  FeaturePCL temp_point;
723  temp_point.x = at_birth_locations_pc->points[feat_idx].x;
724  temp_point.y = at_birth_locations_pc->points[feat_idx].y;
725  temp_point.z = at_birth_locations_pc->points[feat_idx].z;
726  temp_point.label = at_birth_locations_pc->points[feat_idx].label;
727  colored_pc.points.push_back(temp_point);
728  }
729  (*filter_it)->resetFeaturesAtBirth();
730  }
731  return colored_pc;
732 }
733 
734 std::vector<Eigen::Vector3d> MultiRBTracker::getCentroids() const
735 {
736  std::vector<Eigen::Vector3d> centroids;
737  centroids.push_back(Eigen::Vector3d(0., 0., 0.));
738  std::vector<RBFilter::Ptr>::const_iterator filter_it = this->_kalman_filters.begin();
739  filter_it++; //Ignore the static environment
740 
741  for (; filter_it != this->_kalman_filters.end(); filter_it++)
742  {
743  //NEW: the first time we send as centroid the centroid we used for the trajectory estimation
744  //In this way we can inform the next level of the initial pose of the rigid body
745  if((*filter_it)->getTrajectory().size() < this->_min_num_frames_for_new_rb)
746  {
747  Feature::Location initial_location = (*filter_it)->getIntialLocationOfCentroid();
748  centroids.push_back(Eigen::Vector3d(boost::tuples::get<0>(initial_location),
749  boost::tuples::get<1>(initial_location),
750  boost::tuples::get<2>(initial_location)));
751  }else{
752  Eigen::Vector3d temp_centroid = Eigen::Vector3d(0., 0., 0.);
753  int supporting_feats_ctr = 0;
754  std::vector<Feature::Id> this_filter_supporting_features = (*filter_it)->getSupportingFeatures();
755  for (size_t feat_idx = 0; feat_idx < this_filter_supporting_features.size();feat_idx++)
756  {
757  if (this->_features_db->isFeatureStored(this_filter_supporting_features.at(feat_idx)))
758  {
759  temp_centroid.x() += this->_features_db->getFeatureLastX(this_filter_supporting_features.at(feat_idx));
760  temp_centroid.y() += this->_features_db->getFeatureLastY(this_filter_supporting_features.at(feat_idx));
761  temp_centroid.z() += this->_features_db->getFeatureLastZ(this_filter_supporting_features.at(feat_idx));
762  supporting_feats_ctr++;
763  }
764  }
765  centroids.push_back(temp_centroid / (double)supporting_feats_ctr);
766  }
767  }
768  return centroids;
769 }
770 
771 void MultiRBTracker::addPredictedState(const rbt_state_t& predicted_state, const double &predicted_state_timestamp_ns)
772 {
773  BOOST_FOREACH(omip_msgs::RigidBodyPoseAndVelMsg predicted_pose_and_vel, predicted_state.rb_poses_and_vels)
774  {
775  BOOST_FOREACH(RBFilter::Ptr filter, this->_kalman_filters)
776  {
777  if (filter->getId() == predicted_pose_and_vel.rb_id)
778  {
779  //ROS_WARN_STREAM_NAMED("MultiRBTracker.addPredictedState", "Prediction for body " << predicted_pose_and_vel.rb_id);
780  filter->setPredictedState(predicted_pose_and_vel);
781  }
782  }
783  }
784 }
785 
787 {
788  return this->_features_db;
789 }
790 
StaticEnvironmentFilter::Ptr _static_environment_filter
EIGEN_MAKE_ALIGNED_OPERATOR_NEW typedef boost::shared_ptr< RBFilter > Ptr
Definition: RBFilter.h:105
boost::tuple< double, double, double > Location
#define ROS_INFO_NAMED(name,...)
virtual void correctState()
Third and final step when updating the filter. The predicted next state is corrected based on the dif...
int getNumberSupportingFeatures(int n) const
std::vector< Feature::Id > estimateBestPredictionsAndSupportingFeatures()
void ReflectState()
Prepare the corrected state to be published.
virtual void predictMeasurement()
Second step when updating the filter. The next measurement is predicted from the predicted next state...
double L2Distance(const Feature::Location &first, const Feature::Location &second)
OMIP_ADD_POINT4D uint32_t label
void TransformMatrix2Twist(const Eigen::Matrix4d &transformation_matrix, Eigen::Twistd &twist)
virtual void setMeasurement(rbt_measurement_t acquired_measurement, const double &measurement_timestamp)
Set the latest acquired measurement.
omip_msgs::RigidBodyPosesAndVelsMsg rbt_state_t
#define ROS_INFO_STREAM_NAMED(name, args)
long int RB_id_t
double _max_error_to_reassign_feats
std::vector< Eigen::Vector3d > getCentroids() const
virtual rbt_state_t getState() const
Get the currently belief state.
TFSIMD_FORCE_INLINE tfScalar angle(const Quaternion &q1, const Quaternion &q2)
virtual void setDynamicReconfigureValues(rb_tracker::RBTrackerDynReconfConfig &config)
Dynamic configuration.
boost::mutex _measurement_timestamp_ns_mutex
std::pair< Location, Location > LocationPair
void addFeatureLocation(Feature::Id f_id, Feature::Location f_loc)
boost::shared_ptr< FeaturesDataBase > Ptr
TFSIMD_FORCE_INLINE Quaternion inverse(const Quaternion &q)
std::vector< RBFilter::Ptr > _kalman_filters
FeatureCloudPCL getFreeFeatures()
virtual void processMeasurementFromShapeTracker(const omip_msgs::ShapeTrackerStates &meas_from_st)
Process the measurement coming from the ShapeTrackerNode that is a refinement/substitute of the featu...
double _estimation_error_threshold
void CreateNewFilter(const std::vector< Eigen::Matrix4d > &initial_trajectory, const Eigen::Twistd &initial_velocity, const std::vector< Feature::Id > &initial_supporting_feats)
FeatureCloudPCL getLabelledSupportingFeatures()
virtual rbt_measurement_t getPredictedMeasurement() const
Get the predicted next measurement.
boost::shared_ptr< StaticEnvironmentFilter > Ptr
boost::unordered_map< Feature::Id, Feature::LocationPair > MapOfFeatureLocationPairs
double _min_amount_rotation_for_new_rb
int _min_num_supporting_feats_to_correct
void estimateRigidTransformation(const FeaturesDataBase::MapOfFeatureLocationPairs &last2locations, Eigen::Matrix4d &transformation_matrix)
FeatureCloudPCL getAtBirthFeatures()
pcl::PointXYZL FeaturePCL
virtual void predictState(double time_interval_ns)
First step when updating the filter. The next state is predicted from current state and system model ...
FeaturesDataBase::Ptr _features_db
std::vector< geometry_msgs::TwistWithCovariancePtr > getPosesECWithCovariance() const
pcl::PointCloud< FeaturePCL > FeatureCloudPCL
std::vector< Feature::Id > ReassignFreeFeatures(const std::vector< Feature::Id > &free_feat_ids)
std::vector< geometry_msgs::TwistWithCovariancePtr > getVelocitiesWithCovariance() const
#define ROS_ERROR_NAMED(name,...)
RB_id_t getRBId(int n) const
pcl::PointCloud< FeaturePCLwc > FeatureCloudPCLwc
pcl::PointXYZ PointPCL
std::vector< Feature::Id > EstimateFreeFeatures(const std::vector< Feature::Id > &supporting_features)
FeatureCloudPCL getPredictedFeatures()
static_environment_tracker_t
#define ROS_ERROR_STREAM(args)
void Location2PointPCL(const Feature::Location &point_location, pcl::PointXYZ &point_pcl)
FeatureCloudPCLwc::Ptr rbt_measurement_t
std::vector< Feature::Id > _free_feat_ids
MultiRBTracker(int max_num_rb, double loop_period_ns, int ransac_iterations, double estimation_error_threshold, double static_motion_threshold, double new_rbm_error_threshold, double max_error_to_reassign_feats, int supporting_features_threshold, int min_num_feats_for_new_rb, int min_num_frames_for_new_rb, int initial_cam_motion_constraint, static_environment_tracker_t static_environment_tracker_type)
virtual void addPredictedState(const rbt_state_t &predicted_state, const double &predicted_state_timestamp_ns)
void TryToCreateNewFilter(const std::vector< Feature::Id > &really_free_feat_ids)
std::vector< Feature::Id > _really_free_feat_ids
std::vector< Eigen::Matrix4d > getPoses() const
double _min_amount_translation_for_new_rb
FeaturesDataBase::Ptr getFeaturesDatabase()
void toPCL(const ros::Time &stamp, pcl::uint64_t &pcl_stamp)
std::vector< geometry_msgs::PoseWithCovariancePtr > getPosesWithCovariance() const


rb_tracker
Author(s): Roberto Martín-Martín
autogenerated on Mon Jun 10 2019 14:06:11