10 #ifndef CLOOPCLOSERERD_IMPL_H
11 #define CLOOPCLOSERERD_IMPL_H
22 template <
class GRAPH_T>
24 : m_visualize_curr_node_covariance(false),
25 m_curr_node_covariance_color(160, 160, 160, 255),
26 m_partitions_full_update(false),
27 m_is_first_time_node_reg(true),
28 m_dijkstra_node_count_thresh(3)
30 this->initializeLoggers(
"CLoopCloserERD");
36 template <
class GRAPH_T>
43 for (
auto it = m_node_optimal_paths.begin();
44 it != m_node_optimal_paths.end(); ++it)
53 template <
class GRAPH_T>
61 this->m_time_logger.enter(
"updateState");
73 getObservation<CObservation2DRangeScan>(observations, observation);
76 m_last_laser_scan2D = scan;
80 if (!m_first_laser_scan)
82 m_first_laser_scan = m_last_laser_scan2D;
86 size_t num_registered =
87 absDiff(this->m_last_total_num_nodes, this->m_graph->nodeCount());
88 bool registered_new_node = num_registered > 0;
90 if (registered_new_node)
93 registered_new_node =
true;
97 if (!this->m_override_registered_nodes_check)
99 if (!((num_registered == 1) ^
100 (num_registered == 2 && m_is_first_time_node_reg)))
103 "Invalid number of registered nodes since last call to "
106 << num_registered <<
"\" new nodes.");
117 if (m_is_first_time_node_reg)
120 "Assigning first laserScan to the graph root node.");
121 this->m_nodes_to_laser_scans2D[this->m_graph->root] =
123 m_is_first_time_node_reg =
false;
127 this->m_nodes_to_laser_scans2D[this->m_graph->nodeCount() - 1] =
130 if (m_laser_params.use_scan_matching)
133 this->addScanMatchingEdges(this->m_graph->nodeCount() - 1);
137 m_partitions_full_update =
138 ((this->m_graph->nodeCount() %
139 m_lc_params.full_partition_per_nodes) == 0 ||
140 this->m_just_inserted_lc)
143 this->updateMapPartitions(
144 m_partitions_full_update,
145 num_registered == 2);
149 this->checkPartitionsForLC(&partitions_for_LC);
150 this->evaluatePartitionsForLC(partitions_for_LC);
152 if (m_visualize_curr_node_covariance)
154 this->execDijkstraProjection();
157 this->m_last_total_num_nodes = this->m_graph->nodeCount();
160 this->m_time_logger.leave(
"updateState");
165 template <
class GRAPH_T>
168 std::set<mrpt::graphs::TNodeID>* nodes_set)
174 int fetched_nodeIDs = 0;
175 for (
int nodeID_i =
static_cast<int>(curr_nodeID) - 1;
176 ((fetched_nodeIDs <= this->m_laser_params.prev_nodes_for_ICP) &&
181 nodes_set->insert(nodeID_i);
186 template <
class GRAPH_T>
192 using namespace mrpt;
200 std::set<TNodeID> nodes_set;
201 this->fetchNodeIDsForScanMatching(curr_nodeID, &nodes_set);
205 node_it != nodes_set.end(); ++node_it)
211 "Fetching laser scan for nodes: " << *node_it <<
"==> "
215 this->getICPEdge(*node_it, curr_nodeID, &rel_edge, &icp_info);
216 if (!found_edge)
continue;
223 m_laser_params.goodness_threshold_win.addNewMeasurement(
226 double goodness_thresh =
227 m_laser_params.goodness_threshold_win.getMedian() *
228 m_consec_icp_constraint_factor;
229 bool accept_goodness = icp_info.
goodness > goodness_thresh;
231 "Curr. Goodness: " << icp_info.
goodness
232 <<
"|\t Threshold: " << goodness_thresh <<
" => "
233 << (accept_goodness ?
"ACCEPT" :
"REJECT"));
237 bool accept_mahal_distance = this->mahalanobisDistanceOdometryToICPEdge(
238 *node_it, curr_nodeID, rel_edge);
241 if (accept_goodness && accept_mahal_distance)
243 this->registerNewEdge(*node_it, curr_nodeID, rel_edge);
249 template <
class GRAPH_T>
257 this->m_time_logger.enter(
"getICPEdge");
274 "TGetICPEdgeAdParams:\n"
281 bool from_success = this->getPropsOfNodeID(
282 from, &from_pose, from_scan, from_params);
285 bool to_success = this->getPropsOfNodeID(to, &to_pose, to_scan, to_params);
287 if (!from_success || !to_success)
291 << from <<
" or node #" << to
292 <<
" doesn't contain a valid LaserScan. Ignoring this...");
305 initial_estim = to_pose - from_pose;
309 "from_pose: " << from_pose <<
"| to_pose: " << to_pose
310 <<
"| init_estim: " << initial_estim);
312 range_ops_t::getICPEdge(
313 *from_scan, *to_scan, rel_edge, &initial_estim, icp_info);
316 this->m_time_logger.leave(
"getICPEdge");
321 template <
class GRAPH_T>
324 const std::map<mrpt::graphs::TNodeID, node_props_t>& group_params,
336 search = group_params.find(nodeID);
338 if (search == group_params.end())
344 *node_props = search->second;
354 template <
class GRAPH_T>
363 bool filled_pose =
false;
364 bool filled_scan =
false;
371 *pose = node_props->
pose;
375 if (node_props->
scan)
377 scan = node_props->
scan;
384 !(filled_pose ^ filled_scan),
386 "Either BOTH or NONE of the filled_pose, filled_scan should be set."
388 static_cast<unsigned long>(nodeID)));
397 this->m_graph->nodes.find(nodeID);
398 if (search != this->m_graph->nodes.end())
400 *pose = search->second;
411 this->m_nodes_to_laser_scans2D.find(nodeID);
412 if (search != this->m_nodes_to_laser_scans2D.end())
414 scan = search->second;
419 return filled_pose && filled_scan;
422 template <
class GRAPH_T>
427 this->m_time_logger.enter(
"LoopClosureEvaluation");
430 using namespace mrpt;
433 partitions_for_LC->clear();
437 map<int, std::vector<uint32_t>>
::iterator finder;
439 if (m_partitions_full_update)
441 m_partitionID_to_prev_nodes_list.clear();
447 partitions_it != m_curr_partitions.end();
448 ++partitions_it, ++partitionID)
452 if (m_lc_params.LC_check_curr_partition_only)
454 bool curr_node_in_curr_partition =
456 partitions_it->begin(), partitions_it->end(),
457 this->m_graph->nodeCount() - 1)) != partitions_it->end());
458 if (!curr_node_in_curr_partition)
465 finder = m_partitionID_to_prev_nodes_list.find(partitionID);
466 if (finder == m_partitionID_to_prev_nodes_list.end())
469 m_partitionID_to_prev_nodes_list.insert(
470 make_pair(partitionID, *partitions_it));
474 if (*partitions_it == finder->second)
484 finder->second = *partitions_it;
489 int curr_node_index = 1;
490 size_t prev_nodeID = *(partitions_it->begin());
492 it = partitions_it->begin() + 1;
493 it != partitions_it->end(); ++it, ++curr_node_index)
495 size_t curr_nodeID = *it;
499 if ((curr_nodeID - prev_nodeID) > m_lc_params.LC_min_nodeid_diff)
503 int num_after_nodes = partitions_it->size() - curr_node_index;
504 int num_before_nodes = partitions_it->size() - num_after_nodes;
505 if (num_after_nodes >= m_lc_params.LC_min_remote_nodes &&
506 num_before_nodes >= m_lc_params.LC_min_remote_nodes)
509 "Found potential loop closures:"
511 <<
"\tPartitionID: " << partitionID << endl
517 <<
"\t" << prev_nodeID <<
" ==> " << curr_nodeID << endl
518 <<
"\tNumber of LC nodes: " << num_after_nodes);
519 partitions_for_LC->push_back(*partitions_it);
526 prev_nodeID = curr_nodeID;
529 "Successfully checked partition: " << partitionID);
532 this->m_time_logger.leave(
"LoopClosureEvaluation");
536 template <
class GRAPH_T>
541 using namespace mrpt;
545 this->m_time_logger.enter(
"LoopClosureEvaluation");
547 if (partitions.size() == 0)
return;
550 "Evaluating partitions for loop closures...\n%s\n",
551 this->header_sep.c_str());
555 p_it != partitions.end(); ++p_it)
557 std::vector<uint32_t> partition(*p_it);
560 std::vector<uint32_t> groupA, groupB;
561 this->splitPartitionToGroups(
562 partition, &groupA, &groupB,
567 this->generateHypotsPool(groupA, groupB, &hypots_pool);
570 CMatrixDouble consist_matrix(hypots_pool.size(), hypots_pool.size());
571 this->generatePWConsistenciesMatrix(
572 groupA, groupB, hypots_pool, &consist_matrix);
576 this->evalPWConsistenciesMatrix(
577 consist_matrix, hypots_pool, &valid_hypots);
580 if (valid_hypots.size())
584 it != valid_hypots.end(); ++it)
586 this->registerHypothesis(**it);
592 it != hypots_pool.end(); ++it)
599 this->m_time_logger.leave(
"LoopClosureEvaluation");
604 template <
class GRAPH_T>
614 valid_hypots->clear();
619 bool valid_lambda_ratio = this->computeDominantEigenVector(
622 if (!valid_lambda_ratio)
return;
630 double dot_product = 0;
631 for (
int i = 0; i !=
w.size(); ++i)
638 double potential_dot_product =
639 ((
w.transpose() * u) /
w.squaredNorm()).
value();
641 "current: %f | potential_dot_product: %f", dot_product,
642 potential_dot_product);
643 if (potential_dot_product > dot_product)
646 dot_product = potential_dot_product;
656 cout <<
"Outcome of discretization: " <<
w.transpose() << endl;
662 for (
int wi = 0; wi !=
w.size(); ++wi)
669 valid_hypots->push_back(this->findHypotByID(hypots_pool, wi));
678 template <
class GRAPH_T>
680 std::vector<uint32_t>& partition, std::vector<uint32_t>* groupA,
681 std::vector<uint32_t>* groupB,
int max_nodes_in_group )
685 using namespace mrpt;
693 max_nodes_in_group == -1 || max_nodes_in_group > 0,
695 "Value %d not permitted for max_nodes_in_group"
696 "Either use a positive integer, "
697 "or -1 for non-restrictive partition size",
698 max_nodes_in_group));
703 size_t index_to_split = 1;
705 it != partition.end(); ++it, ++index_to_split)
709 if ((curr_nodeID - prev_nodeID) > m_lc_params.LC_min_nodeid_diff)
714 prev_nodeID = curr_nodeID;
716 ASSERTDEB_(partition.size() > index_to_split);
719 *groupA = std::vector<uint32_t>(
720 partition.begin(), partition.begin() + index_to_split);
721 *groupB = std::vector<uint32_t>(
722 partition.begin() + index_to_split, partition.end());
724 if (max_nodes_in_group != -1)
727 if (groupA->size() >
static_cast<size_t>(max_nodes_in_group))
729 *groupA = std::vector<uint32_t>(
730 groupA->begin(), groupA->begin() + max_nodes_in_group);
733 if (groupB->size() >
static_cast<size_t>(max_nodes_in_group))
735 *groupB = std::vector<uint32_t>(
736 groupB->end() - max_nodes_in_group, groupB->end());
744 template <
class GRAPH_T>
746 const std::vector<uint32_t>& groupA,
const std::vector<uint32_t>& groupB,
751 using namespace mrpt;
756 "generateHypotsPool: Given hypotsp_t pointer is invalid.");
757 generated_hypots->clear();
762 <<
" - size: " << groupA.size() << endl);
765 <<
" - size: " << groupB.size() << endl);
779 size_t nodes_count = groupA.size();
783 nodes_count ==
params.size(),
785 "Size mismatch between nodeIDs in group [%lu]"
786 " and corresponding properties map [%lu]",
787 nodes_count,
params.size()));
793 int hypot_counter = 0;
794 int invalid_hypots = 0;
798 b_it = groupB.begin();
799 b_it != groupB.end(); ++b_it)
802 a_it = groupA.begin();
803 a_it != groupA.end(); ++a_it)
812 hypot->id = hypot_counter++;
827 fillNodePropsFromGroupParams(
831 fillNodePropsFromGroupParams(
853 bool found_edge = this->getICPEdge(
854 *b_it, *a_it, &edge, &icp_info, icp_ad_params);
856 hypot->setEdge(edge);
863 double goodness_thresh =
864 m_laser_params.goodness_threshold_win.getMedian() *
865 m_lc_icp_constraint_factor;
866 bool accept_goodness = icp_info.
goodness > goodness_thresh;
868 "generateHypotsPool:\nCurr. Goodness: "
869 << icp_info.
goodness <<
"|\t Threshold: " << goodness_thresh
870 <<
" => " << (accept_goodness ?
"ACCEPT" :
"REJECT")
873 if (!found_edge || !accept_goodness)
875 hypot->is_valid =
false;
878 generated_hypots->push_back(hypot);
884 delete icp_ad_params;
888 "Generated pool of hypotheses...\tsize = "
889 << generated_hypots->size()
890 <<
"\tinvalid hypotheses: " << invalid_hypots);
897 template <
class GRAPH_T>
903 using namespace mrpt;
908 this->m_time_logger.enter(
"DominantEigenvectorComputation");
910 double lambda1, lambda2;
911 bool is_valid_lambda_ratio =
false;
913 if (use_power_method)
916 "\nPower method for computing the first two "
917 "eigenvectors/eigenvalues hasn't been implemented yet\n");
922 consist_matrix.eigenVectors(eigvecs, eigvals);
928 eigvecs.size() == eigvals.size() &&
929 consist_matrix.size() == eigvals.size(),
931 "Size of eigvecs \"%lu\","
933 "consist_matrix \"%lu\" don't match",
934 static_cast<unsigned long>(eigvecs.size()),
935 static_cast<unsigned long>(eigvals.size()),
936 static_cast<unsigned long>(consist_matrix.size())));
938 eigvecs.extractCol(eigvecs.cols() - 1, *eigvec);
939 lambda1 = eigvals(eigvals.rows() - 1, eigvals.cols() - 1);
940 lambda2 = eigvals(eigvals.rows() - 2, eigvals.cols() - 2);
944 for (
int i = 0; i != eigvec->size(); ++i)
946 (*eigvec)(i) = abs((*eigvec)(i));
954 "Bad lambda2 value: "
955 << lambda2 <<
" => Skipping current evaluation." << endl);
958 double curr_lambda_ratio = lambda1 / lambda2;
960 "lambda1 = " << lambda1 <<
" | lambda2 = " << lambda2
961 <<
"| ratio = " << curr_lambda_ratio << endl);
963 is_valid_lambda_ratio =
964 (curr_lambda_ratio > m_lc_params.LC_eigenvalues_ratio_thresh);
966 this->m_time_logger.leave(
"DominantEigenvectorComputation");
967 return is_valid_lambda_ratio;
972 template <
class GRAPH_T>
974 const std::vector<uint32_t>& groupA,
const std::vector<uint32_t>& groupB,
976 const paths_t* groupA_opt_paths ,
977 const paths_t* groupB_opt_paths )
981 using namespace mrpt;
988 consist_matrix,
"Invalid pointer to the Consistency matrix is given");
990 static_cast<unsigned long>(consist_matrix->rows()) ==
991 hypots_pool.size() &&
992 static_cast<unsigned long>(consist_matrix->rows()) ==
994 "Consistency matrix dimensions aren't equal to the hypotheses pool "
998 ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"
1000 <<
"In generatePWConsistencyMatrix:\n"
1003 <<
"\tHypots pool Size: " << hypots_pool.size());
1007 b1_it != groupB.end(); ++b1_it)
1013 b2_it != groupB.end(); ++b2_it)
1019 a1_it != groupA.end(); ++a1_it)
1023 this->findHypotByEnds(hypots_pool,
b2,
a1);
1029 a2_it != groupA.end(); ++a2_it)
1033 this->findHypotByEnds(hypots_pool,
b1,
a2);
1040 if (hypot_b2_a1->is_valid && hypot_b1_a2->is_valid)
1046 extracted_hypots.push_back(hypot_b2_a1);
1047 extracted_hypots.push_back(hypot_b1_a2);
1049 paths_t* curr_opt_paths = NULL;
1050 if (groupA_opt_paths || groupB_opt_paths)
1052 curr_opt_paths =
new paths_t();
1059 if (groupA_opt_paths)
1061 const path_t*
p = this->findPathByEnds(
1062 *groupA_opt_paths,
a1,
a2,
1064 curr_opt_paths->push_back(*
p);
1068 curr_opt_paths->push_back(
path_t());
1071 if (groupB_opt_paths)
1073 const path_t*
p = this->findPathByEnds(
1074 *groupB_opt_paths,
b1,
b2,
1076 curr_opt_paths->push_back(*
p);
1080 curr_opt_paths->push_back(
path_t());
1084 consistency = this->generatePWConsistencyElement(
1085 a1,
a2,
b1,
b2, extracted_hypots, curr_opt_paths);
1087 delete curr_opt_paths;
1102 int id1 = hypot_b2_a1->id;
1103 int id2 = hypot_b1_a2->id;
1105 (*consist_matrix)(id1, id2) = consistency;
1106 (*consist_matrix)(id2, id1) = consistency;
1123 template <
class GRAPH_T>
1130 using namespace std;
1131 using namespace mrpt;
1159 const path_t* path_a1_a2;
1160 if (!opt_paths || opt_paths->begin()->isEmpty())
1163 "Running dijkstra [a1] " <<
a1 <<
" => [a2] " <<
a2);
1164 execDijkstraProjection(
a1,
a2);
1165 path_a1_a2 = this->queryOptimalPath(
a2);
1170 path_a1_a2 = &(*opt_paths->begin());
1176 const path_t* path_b1_b2;
1177 if (!opt_paths || opt_paths->rend()->isEmpty())
1180 "Running djkstra [b1] " <<
b1 <<
" => [b2] " <<
b2);
1181 execDijkstraProjection(
b1,
b2);
1182 path_b1_b2 = this->queryOptimalPath(
b2);
1186 path_b1_b2 = &(*opt_paths->rbegin());
1194 hypot_t* hypot_b1_a2 = this->findHypotByEnds(hypots,
b1,
a2);
1196 hypot_t* hypot_b2_a1 = this->findHypotByEnds(hypots,
b2,
a1);
1201 res_transform += hypot_b1_a2->getInverseEdge();
1203 res_transform += hypot_b2_a1->getEdge();
1206 "\n-----------Resulting Transformation----------- Hypots: #"
1207 << hypot_b1_a2->id <<
", #" << hypot_b2_a1->id << endl
1208 <<
"a1 --> a2 => b1 --> b2 => a1: " <<
a1 <<
" --> " <<
a2 <<
" => "
1209 <<
b1 <<
" --> " <<
b2 <<
" => " <<
a1 << endl
1210 << res_transform << endl
1212 <<
"DIJKSTRA: " <<
a1 <<
" --> " <<
a2 <<
": "
1214 <<
"DIJKSTRA: " <<
b1 <<
" --> " <<
b2 <<
": "
1216 <<
"hypot_b1_a2(inv):\n"
1217 << hypot_b1_a2->getInverseEdge() << endl
1219 << hypot_b2_a1->getEdge() << endl);
1223 res_transform.getMeanVal().getAsVector(T);
1227 res_transform.getCovariance(cov_mat);
1233 double exponent = (-T.transpose() * cov_mat * T).
value();
1234 double consistency_elem = exp(exponent);
1241 return consistency_elem;
1245 template <
class GRAPH_T>
1251 using namespace mrpt;
1257 cit != vec_paths.end(); ++cit)
1259 if (cit->getSource() ==
src && cit->getDestination() ==
dst)
1265 if (throw_exc && !
res)
1269 "Path for %lu => %lu is not found. Exiting...\n",
1270 static_cast<unsigned long>(
src),
1271 static_cast<unsigned long>(
dst)));
1277 template <
class GRAPH_T>
1284 using namespace std;
1287 v_cit != vec_hypots.end(); v_cit++)
1289 if ((*v_cit)->hasEnds(from, to))
1308 template <
class GRAPH_T>
1311 const hypotsp_t& vec_hypots,
const size_t&
id,
bool throw_exc )
1316 v_cit != vec_hypots.end(); v_cit++)
1318 if ((*v_cit)->id ==
id)
1335 template <
class GRAPH_T>
1341 using namespace std;
1342 using namespace mrpt;
1350 this->m_time_logger.enter(
"Dijkstra Projection");
1352 "----------- Done with Dijkstra Projection... ----------";
1358 (ending_node >= 0 && ending_node < this->m_graph->nodeCount()));
1360 starting_node != ending_node,
"Starting and Ending nodes coincede");
1363 stringstream ss_debug(
"");
1364 ss_debug <<
"Executing Dijkstra Projection: " << starting_node <<
" => ";
1367 ss_debug <<
"..." << endl;
1371 ss_debug << ending_node << endl;
1374 if (this->m_graph->nodeCount() < m_dijkstra_node_count_thresh)
1380 std::vector<bool> visited_nodes(this->m_graph->nodeCount(),
false);
1381 m_node_optimal_paths.clear();
1384 std::map<TNodeID, std::set<TNodeID>> neighbors_of;
1385 this->m_graph->getAdjacencyMatrix(neighbors_of);
1390 std::set<path_t*> pool_of_paths;
1392 std::set<TNodeID> starting_node_neighbors(neighbors_of.at(starting_node));
1394 starting_node_neighbors.begin();
1395 n_it != starting_node_neighbors.end(); ++n_it)
1398 this->getMinUncertaintyPath(
1399 starting_node, *n_it, path_between_neighbors);
1401 pool_of_paths.insert(path_between_neighbors);
1404 visited_nodes.at(starting_node) =
true;
1422 it != visited_nodes.end(); ++it)
1435 if (visited_nodes.at(ending_node))
1438 this->m_time_logger.leave(
"Dijkstra Projection");
1443 path_t* optimal_path = this->popMinUncertaintyPath(&pool_of_paths);
1468 if (!visited_nodes.at(dest))
1470 m_node_optimal_paths[dest] = optimal_path;
1471 visited_nodes.at(dest) =
true;
1477 &pool_of_paths, *optimal_path, neighbors_of.at(dest));
1482 this->m_time_logger.leave(
"Dijkstra Projection");
1486 template <
class GRAPH_T>
1488 std::set<path_t*>* pool_of_paths,
const path_t& current_path,
1489 const std::set<mrpt::graphs::TNodeID>& neighbors)
const
1492 using namespace std;
1504 neigh_it != neighbors.end(); ++neigh_it)
1506 if (*neigh_it == second_to_last_node)
continue;
1509 path_t path_between_nodes;
1510 this->getMinUncertaintyPath(
1511 node_to_append_from, *neigh_it, &path_between_nodes);
1515 *path_to_append = current_path;
1516 *path_to_append += path_between_nodes;
1518 pool_of_paths->insert(path_to_append);
1524 template <
class GRAPH_T>
1528 using namespace std;
1532 search = m_node_optimal_paths.find(node);
1533 if (search != m_node_optimal_paths.end())
1535 path = search->second;
1543 template <
class GRAPH_T>
1546 path_t* path_between_nodes)
const
1550 using namespace std;
1553 this->m_graph->edgeExists(from, to) ||
1554 this->m_graph->edgeExists(to, from),
1556 "\nEdge between the provided nodeIDs"
1557 "(%lu <-> %lu) does not exist\n",
1564 path_between_nodes->
clear();
1568 double curr_determinant = 0;
1570 std::pair<edges_citerator, edges_citerator> fwd_edges_pair =
1571 this->m_graph->getEdges(from, to);
1581 edges_it != fwd_edges_pair.second; ++edges_it)
1586 curr_edge.copyFrom(edges_it->second);
1590 curr_edge.getInformationMatrix(inf_mat);
1595 curr_edge.cov_inv = inf_mat;
1606 *path_between_nodes = curr_path;
1610 std::pair<edges_citerator, edges_citerator> bwd_edges_pair =
1611 this->m_graph->getEdges(to, from);
1621 edges_it != bwd_edges_pair.second; ++edges_it)
1626 (edges_it->second).
inverse(curr_edge);
1630 curr_edge.getInformationMatrix(inf_mat);
1635 curr_edge.cov_inv = inf_mat;
1646 *path_between_nodes = curr_path;
1653 template <
class GRAPH_T>
1655 typename std::set<path_t*>* pool_of_paths)
const
1658 using namespace std;
1661 path_t* optimal_path = NULL;
1662 double curr_determinant = 0;
1664 it != pool_of_paths->end(); ++it)
1669 if (curr_determinant < (*it)->getDeterminant())
1677 pool_of_paths->erase(optimal_path);
1679 return optimal_path;
1683 template <
class GRAPH_T>
1690 using namespace std;
1695 this->m_graph->nodes.at(to) - this->m_graph->nodes.at(from);
1697 (rel_edge.getMeanVal() - initial_estim).getAsVector(mean_diff);
1701 rel_edge.getCovariance(cov_mat);
1704 double mahal_distance =
1706 bool mahal_distance_null = std::isnan(mahal_distance);
1707 if (!mahal_distance_null)
1709 m_laser_params.mahal_distance_ICP_odom_win.addNewMeasurement(
1716 m_laser_params.mahal_distance_ICP_odom_win.getMedian() * 4;
1718 (threshold >= mahal_distance && !mahal_distance_null) ?
true :
false;
1730 template <
class GRAPH_T>
1735 this->registerNewEdge(hypot.from, hypot.to, hypot.getEdge());
1738 template <
class GRAPH_T>
1745 using namespace std;
1746 parent_t::registerNewEdge(from, to, rel_edge);
1749 m_edge_types_to_nums[
"ICP2D"]++;
1752 if (
absDiff(to, from) > m_lc_params.LC_min_nodeid_diff)
1754 m_edge_types_to_nums[
"LC"]++;
1755 this->m_just_inserted_lc =
true;
1760 this->m_just_inserted_lc =
false;
1764 this->m_graph->insertEdge(from, to, rel_edge);
1769 template <
class GRAPH_T>
1774 parent_t::setWindowManagerPtr(win_manager);
1777 if (this->m_win_manager)
1779 if (this->m_win_observer)
1781 this->m_win_observer->registerKeystroke(
1782 m_laser_params.keystroke_laser_scans,
1783 "Toggle LaserScans Visualization");
1784 this->m_win_observer->registerKeystroke(
1785 m_lc_params.keystroke_map_partitions,
1786 "Toggle Map Partitions Visualization");
1790 "Fetched the window manager, window observer successfully.");
1793 template <
class GRAPH_T>
1795 const std::map<std::string, bool>& events_occurred)
1798 parent_t::notifyOfWindowEvents(events_occurred);
1801 if (events_occurred.at(m_laser_params.keystroke_laser_scans))
1803 this->toggleLaserScansVisualization();
1806 if (events_occurred.at(m_lc_params.keystroke_map_partitions))
1808 this->toggleMapPartitionsVisualization();
1814 template <
class GRAPH_T>
1817 using namespace mrpt;
1823 this->m_win_manager->assignTextMessageParameters(
1824 &m_lc_params.offset_y_map_partitions,
1825 &m_lc_params.text_index_map_partitions);
1829 mrpt::make_aligned_shared<CSetOfObjects>();
1830 map_partitions_obj->setName(
"map_partitions");
1833 scene->insert(map_partitions_obj);
1834 this->m_win->unlockAccess3DScene();
1835 this->m_win->forceRepaint();
1838 template <
class GRAPH_T>
1841 using namespace mrpt;
1848 std::stringstream title;
1849 title <<
"# Partitions: " << m_curr_partitions.size();
1850 this->m_win_manager->addTextMessage(
1851 5, -m_lc_params.offset_y_map_partitions, title.str(),
1853 m_lc_params.text_index_map_partitions);
1864 map_partitions_obj = std::dynamic_pointer_cast<CSetOfObjects>(
obj);
1867 int partitionID = 0;
1868 bool partition_contains_last_node =
false;
1869 bool found_last_node =
1872 "Searching for the partition of the last nodeID: "
1873 << (this->m_graph->nodeCount() - 1));
1876 p_it != m_curr_partitions.end(); ++p_it, ++partitionID)
1879 std::vector<uint32_t> nodes_list = *p_it;
1883 nodes_list.begin(), nodes_list.end(),
1884 this->m_graph->nodeCount() - 1) != nodes_list.end())
1886 partition_contains_last_node =
true;
1888 found_last_node =
true;
1892 partition_contains_last_node =
false;
1901 map_partitions_obj->getByName(partition_obj_name);
1908 curr_partition_obj = std::dynamic_pointer_cast<CSetOfObjects>(
obj);
1909 if (m_lc_params.LC_check_curr_partition_only)
1911 curr_partition_obj->setVisibility(partition_contains_last_node);
1917 "\tCreating a new CSetOfObjects partition object for partition "
1920 curr_partition_obj = mrpt::make_aligned_shared<CSetOfObjects>();
1921 curr_partition_obj->setName(partition_obj_name);
1922 if (m_lc_params.LC_check_curr_partition_only)
1925 curr_partition_obj->setVisibility(partition_contains_last_node);
1930 CSphere::Ptr balloon_obj = mrpt::make_aligned_shared<CSphere>();
1931 balloon_obj->setName(balloon_obj_name);
1932 balloon_obj->setRadius(m_lc_params.balloon_radius);
1933 balloon_obj->setColor_u8(m_lc_params.balloon_std_color);
1934 balloon_obj->enableShowName();
1936 curr_partition_obj->insert(balloon_obj);
1942 mrpt::make_aligned_shared<CSetOfLines>();
1943 connecting_lines_obj->setName(
"connecting_lines");
1944 connecting_lines_obj->setColor_u8(
1945 m_lc_params.connecting_lines_color);
1946 connecting_lines_obj->setLineWidth(0.1f);
1948 curr_partition_obj->insert(connecting_lines_obj);
1953 map_partitions_obj->insert(curr_partition_obj);
1960 std::pair<double, double> centroid_coords;
1961 this->computeCentroidOfNodesVector(nodes_list, ¢roid_coords);
1964 centroid_coords.first, centroid_coords.second,
1965 m_lc_params.balloon_elevation);
1974 curr_partition_obj->getByName(balloon_obj_name);
1975 balloon_obj = std::dynamic_pointer_cast<CSphere>(
obj);
1976 balloon_obj->setLocation(balloon_location);
1977 if (partition_contains_last_node)
1978 balloon_obj->setColor_u8(m_lc_params.balloon_curr_color);
1980 balloon_obj->setColor_u8(m_lc_params.balloon_std_color);
1993 curr_partition_obj->getByName(
"connecting_lines");
1994 connecting_lines_obj = std::dynamic_pointer_cast<CSetOfLines>(
obj);
1996 connecting_lines_obj->clear();
1999 it != nodes_list.end(); ++it)
2001 CPose3D curr_pose(this->m_graph->nodes.at(*it));
2005 curr_node_location, balloon_location);
2006 connecting_lines_obj->appendLine(connecting_line);
2012 if (!found_last_node)
2015 THROW_EXCEPTION(
"Last inserted nodeID was not found in any partition.");
2023 size_t prev_size = m_last_partitions.size();
2024 size_t curr_size = m_curr_partitions.size();
2025 if (curr_size < prev_size)
2028 for (
size_t partitionID = curr_size; partitionID != prev_size;
2033 "partition_%lu",
static_cast<unsigned long>(partitionID));
2036 map_partitions_obj->getByName(partition_obj_name);
2040 partition_obj_name.c_str())
2042 map_partitions_obj->removeObject(
obj);
2047 this->m_win->unlockAccess3DScene();
2048 this->m_win->forceRepaint();
2051 template <
class GRAPH_T>
2055 ASSERTDEBMSG_(this->m_win,
"No CDisplayWindow3D* was provided");
2056 ASSERTDEBMSG_(this->m_win_manager,
"No CWindowManager* was provided");
2062 if (m_lc_params.visualize_map_partitions)
2065 scene->getByName(
"map_partitions");
2066 obj->setVisibility(!
obj->isVisible());
2070 this->dumpVisibilityErrorMsg(
"visualize_map_partitions");
2073 this->m_win->unlockAccess3DScene();
2074 this->m_win->forceRepaint();
2079 template <
class GRAPH_T>
2081 const std::vector<uint32_t>& nodes_list,
2082 std::pair<double, double>* centroid_coords)
const
2088 double centroid_x = 0;
2089 double centroid_y = 0;
2091 node_it != nodes_list.end(); ++node_it)
2093 pose_t curr_node_pos = this->m_graph->nodes.at(*node_it);
2094 centroid_x += curr_node_pos.x();
2095 centroid_y += curr_node_pos.y();
2099 centroid_coords->first =
2100 centroid_x /
static_cast<double>(nodes_list.size());
2101 centroid_coords->second =
2102 centroid_y /
static_cast<double>(nodes_list.size());
2107 template <
class GRAPH_T>
2113 if (m_laser_params.visualize_laser_scans)
2116 this->m_win->get3DSceneAndLock();
2119 mrpt::make_aligned_shared<mrpt::opengl::CPlanarLaserScan>();
2120 laser_scan_viz->enablePoints(
true);
2121 laser_scan_viz->enableLine(
true);
2122 laser_scan_viz->enableSurface(
true);
2123 laser_scan_viz->setSurfaceColor(
2124 m_laser_params.laser_scans_color.R,
2125 m_laser_params.laser_scans_color.G,
2126 m_laser_params.laser_scans_color.B,
2127 m_laser_params.laser_scans_color.A);
2129 laser_scan_viz->setName(
"laser_scan_viz");
2131 scene->insert(laser_scan_viz);
2132 this->m_win->unlockAccess3DScene();
2133 this->m_win->forceRepaint();
2139 template <
class GRAPH_T>
2145 if (m_laser_params.visualize_laser_scans && m_last_laser_scan2D)
2148 this->m_win->get3DSceneAndLock();
2151 scene->getByName(
"laser_scan_viz");
2153 std::dynamic_pointer_cast<mrpt::opengl::CPlanarLaserScan>(
obj);
2154 laser_scan_viz->setScan(*m_last_laser_scan2D);
2158 this->m_graph->nodes.find(this->m_graph->nodeCount() - 1);
2159 if (search != this->m_graph->nodes.end())
2161 laser_scan_viz->setPose(search->second);
2164 laser_scan_viz->setPose(
2166 laser_scan_viz->getPoseX(), laser_scan_viz->getPoseY(),
2172 this->m_win->unlockAccess3DScene();
2173 this->m_win->forceRepaint();
2179 template <
class GRAPH_T>
2183 ASSERTDEBMSG_(this->m_win,
"No CDisplayWindow3D* was provided");
2184 ASSERTDEBMSG_(this->m_win_manager,
"No CWindowManager* was provided");
2190 if (m_laser_params.visualize_laser_scans)
2193 scene->getByName(
"laser_scan_viz");
2194 obj->setVisibility(!
obj->isVisible());
2198 this->dumpVisibilityErrorMsg(
"visualize_laser_scans");
2201 this->m_win->unlockAccess3DScene();
2202 this->m_win->forceRepaint();
2207 template <
class GRAPH_T>
2209 std::map<std::string, int>* edge_types_to_num)
const
2212 *edge_types_to_num = m_edge_types_to_nums;
2216 template <
class GRAPH_T>
2220 parent_t::initializeVisuals();
2222 this->m_time_logger.enter(
"Visuals");
2225 m_laser_params.has_read_config,
2226 "Configuration parameters aren't loaded yet");
2227 if (m_laser_params.visualize_laser_scans)
2229 this->initLaserScansVisualization();
2231 if (m_lc_params.visualize_map_partitions)
2233 this->initMapPartitionsVisualization();
2236 if (m_visualize_curr_node_covariance)
2238 this->initCurrCovarianceVisualization();
2241 this->m_time_logger.leave(
"Visuals");
2244 template <
class GRAPH_T>
2248 parent_t::updateVisuals();
2250 this->m_time_logger.enter(
"Visuals");
2252 if (m_laser_params.visualize_laser_scans)
2254 this->updateLaserScansVisualization();
2256 if (m_lc_params.visualize_map_partitions)
2258 this->updateMapPartitionsVisualization();
2260 if (m_visualize_curr_node_covariance)
2262 this->updateCurrCovarianceVisualization();
2265 this->m_time_logger.leave(
"Visuals");
2269 template <
class GRAPH_T>
2273 using namespace std;
2277 this->m_win_manager->assignTextMessageParameters(
2278 &m_offset_y_curr_node_covariance,
2279 &m_text_index_curr_node_covariance);
2282 this->m_win_manager->addTextMessage(
2283 5, -m_offset_y_curr_node_covariance, title,
2285 m_text_index_curr_node_covariance);
2288 CEllipsoid::Ptr cov_ellipsis_obj = mrpt::make_aligned_shared<CEllipsoid>();
2289 cov_ellipsis_obj->setName(
"cov_ellipsis_obj");
2290 cov_ellipsis_obj->setColor_u8(m_curr_node_covariance_color);
2291 cov_ellipsis_obj->setLocation(0, 0, 0);
2295 scene->insert(cov_ellipsis_obj);
2296 this->m_win->unlockAccess3DScene();
2297 this->m_win->forceRepaint();
2302 template <
class GRAPH_T>
2306 using namespace std;
2313 path_t* path = queryOptimalPath(curr_node);
2318 pose_t curr_position = this->m_graph->nodes.at(curr_node);
2321 "In updateCurrCovarianceVisualization\n"
2322 "Covariance matrix:\n"
2330 std::dynamic_pointer_cast<CEllipsoid>(
obj);
2333 cov_ellipsis_obj->setLocation(curr_position.x(), curr_position.y(), 0);
2336 cov_ellipsis_obj->setCovMatrix(mat, 2);
2338 this->m_win->unlockAccess3DScene();
2339 this->m_win->forceRepaint();
2344 template <
class GRAPH_T>
2352 "Cannot toggle visibility of specified object.\n "
2353 "Make sure that the corresponding visualization flag ( %s "
2354 ") is set to true in the .ini file.\n",
2356 std::this_thread::sleep_for(std::chrono::milliseconds(sleep_time));
2361 template <
class GRAPH_T>
2365 parent_t::loadParams(source_fname);
2367 m_partitioner.options.loadFromConfigFileName(
2368 source_fname,
"EdgeRegistrationDeciderParameters");
2369 m_laser_params.loadFromConfigFileName(
2370 source_fname,
"EdgeRegistrationDeciderParameters");
2371 m_lc_params.loadFromConfigFileName(
2372 source_fname,
"EdgeRegistrationDeciderParameters");
2376 m_consec_icp_constraint_factor =
source.read_double(
2377 "EdgeRegistrationDeciderParameters",
"consec_icp_constraint_factor",
2379 m_lc_icp_constraint_factor =
source.read_double(
2380 "EdgeRegistrationDeciderParameters",
"lc_icp_constraint_factor", 0.70,
2384 int min_verbosity_level =
source.read_int(
2385 "EdgeRegistrationDeciderParameters",
"class_verbosity", 1,
false);
2390 template <
class GRAPH_T>
2394 using namespace std;
2396 cout <<
"------------------[Pair-wise Consistency of ICP Edges - "
2397 "Registration Procedure Summary]------------------"
2400 parent_t::printParams();
2401 m_partitioner.options.dumpToConsole();
2402 m_laser_params.dumpToConsole();
2403 m_lc_params.dumpToConsole();
2405 cout <<
"Scan-matching ICP Constraint factor: "
2406 << m_consec_icp_constraint_factor << endl;
2407 cout <<
"Loop-closure ICP Constraint factor: "
2408 << m_lc_icp_constraint_factor << endl;
2414 template <
class GRAPH_T>
2421 std::stringstream class_props_ss;
2422 class_props_ss <<
"Pair-wise Consistency of ICP Edges - Registration "
2423 "Procedure Summary: "
2425 class_props_ss << this->header_sep << std::endl;
2428 const std::string time_res = this->m_time_logger.getStatsAsText();
2429 const std::string output_res = this->getLogAsString();
2432 report_str->clear();
2433 parent_t::getDescriptiveReport(report_str);
2435 *report_str += class_props_ss.str();
2436 *report_str += this->report_sep;
2438 *report_str += time_res;
2439 *report_str += this->report_sep;
2441 *report_str += output_res;
2442 *report_str += this->report_sep;
2447 template <
class GRAPH_T>
2451 partitions_out = this->getCurrentPartitions();
2454 template <
class GRAPH_T>
2455 const std::vector<std::vector<uint32_t>>&
2458 return m_curr_partitions;
2461 template <
class GRAPH_T>
2463 bool full_update ,
bool is_first_time_node_reg )
2467 using namespace std;
2468 this->m_time_logger.enter(
"updateMapPartitions");
2475 "updateMapPartitions: Full partitioning of map was issued");
2478 m_partitioner.clear();
2479 nodes_to_scans = this->m_nodes_to_laser_scans2D;
2484 if (is_first_time_node_reg)
2486 nodes_to_scans.insert(
2488 this->m_graph->root,
2489 this->m_nodes_to_laser_scans2D.at(this->m_graph->root)));
2493 nodes_to_scans.insert(
2495 this->m_graph->nodeCount() - 1,
2496 this->m_nodes_to_laser_scans2D.at(
2497 this->m_graph->nodeCount() - 1)));
2503 for (
auto it = nodes_to_scans.begin(); it != nodes_to_scans.end(); ++it)
2508 "nodeID \"" << it->first <<
"\" has invalid laserScan");
2514 const auto& search = this->m_graph->nodes.find(it->first);
2515 if (search == this->m_graph->nodes.end())
2522 const auto curr_constraint =
constraint_t(search->second);
2529 m_partitioner.addMapFrame(sf, *pose3d);
2533 size_t curr_size = m_curr_partitions.size();
2534 m_last_partitions.resize(curr_size);
2535 for (
size_t i = 0; i < curr_size; i++)
2537 m_last_partitions[i] = m_curr_partitions[i];
2540 m_partitioner.updatePartitions(m_curr_partitions);
2543 this->m_time_logger.leave(
"updateMapPartitions");
2550 template <
class GRAPH_T>
2552 : laser_scans_color(0, 20, 255),
2553 keystroke_laser_scans(
"l"),
2554 has_read_config(false)
2561 template <
class GRAPH_T>
2566 template <
class GRAPH_T>
2568 std::ostream& out)
const
2572 out <<
"Use scan-matching constraints = "
2573 << (use_scan_matching ?
"TRUE" :
"FALSE") << std::endl;
2574 out <<
"Num. of previous nodes to check ICP against = "
2575 << prev_nodes_for_ICP << std::endl;
2576 out <<
"Visualize laser scans = "
2577 << (visualize_laser_scans ?
"TRUE" :
"FALSE") << std::endl;
2581 template <
class GRAPH_T>
2588 source.read_bool(section,
"use_scan_matching",
true,
false);
2589 prev_nodes_for_ICP =
source.read_int(
2591 "prev_nodes_for_ICP",
2593 visualize_laser_scans =
source.read_bool(
2594 "VisualizationParameters",
"visualize_laser_scans",
true,
false);
2596 has_read_config =
true;
2602 template <
class GRAPH_T>
2604 : keystroke_map_partitions(
"b"),
2605 balloon_elevation(3),
2606 balloon_radius(0.5),
2607 balloon_std_color(153, 0, 153),
2608 balloon_curr_color(62, 0, 80),
2609 connecting_lines_color(balloon_std_color),
2610 has_read_config(false)
2614 template <
class GRAPH_T>
2619 template <
class GRAPH_T>
2621 std::ostream& out)
const
2624 using namespace std;
2627 ss <<
"Min. node difference for loop closure = "
2628 << LC_min_nodeid_diff << endl;
2629 ss <<
"Remote NodeIDs to consider the potential loop closure = "
2630 << LC_min_remote_nodes << endl;
2631 ss <<
"Min EigenValues ratio for accepting a hypotheses set = "
2632 << LC_eigenvalues_ratio_thresh << endl;
2633 ss <<
"Check only current node's partition for loop closures = "
2634 << (LC_check_curr_partition_only ?
"TRUE" :
"FALSE") << endl;
2635 ss <<
"New registered nodes required for full partitioning = "
2636 << full_partition_per_nodes << endl;
2637 ss <<
"Visualize map partitions = "
2638 << (visualize_map_partitions ?
"TRUE" :
"FALSE") << endl;
2644 template <
class GRAPH_T>
2649 LC_min_nodeid_diff =
source.read_int(
2650 "GeneralConfiguration",
"LC_min_nodeid_diff", 30,
false);
2651 LC_min_remote_nodes =
2652 source.read_int(section,
"LC_min_remote_nodes", 3,
false);
2653 LC_eigenvalues_ratio_thresh =
2654 source.read_double(section,
"LC_eigenvalues_ratio_thresh", 2,
false);
2655 LC_check_curr_partition_only =
2656 source.read_bool(section,
"LC_check_curr_partition_only",
true,
false);
2657 full_partition_per_nodes =
2658 source.read_int(section,
"full_partition_per_nodes", 50,
false);
2659 visualize_map_partitions =
source.read_bool(
2660 "VisualizationParameters",
"visualize_map_partitions",
true,
false);
2662 has_read_config =
true;
This class allows loading and storing values and vectors of different types from a configuration text...
This class allows loading and storing values and vectors of different types from "....
Class acts as a container for storing pointers to mrpt::gui::CDisplayWindow3D, mrpt::graphslam::CWind...
Edge Registration Decider scheme specialized in Loop Closing.
void evaluatePartitionsForLC(const partitions_t &partitions)
Evaluate the given partitions for loop closures.
void generateHypotsPool(const std::vector< uint32_t > &groupA, const std::vector< uint32_t > &groupB, hypotsp_t *generated_hypots, const TGenerateHypotsPoolAdParams *ad_params=NULL)
Generate the hypothesis pool for all the inter-group constraints between two groups of nodes.
bool computeDominantEigenVector(const mrpt::math::CMatrixDouble &consist_matrix, mrpt::math::dynamic_vector< double > *eigvec, bool use_power_method=false)
void updateCurrCovarianceVisualization()
const partitions_t & getCurrentPartitions() const
void registerNewEdge(const mrpt::graphs::TNodeID &from, const mrpt::graphs::TNodeID &to, const constraint_t &rel_edge)
void splitPartitionToGroups(std::vector< uint32_t > &partition, std::vector< uint32_t > *groupA, std::vector< uint32_t > *groupB, int max_nodes_in_group=5)
Split an existing partition to Groups.
bool getPropsOfNodeID(const mrpt::graphs::TNodeID &nodeID, global_pose_t *pose, mrpt::obs::CObservation2DRangeScan::Ptr &scan, const node_props_t *node_props=NULL) const
Fill the pose and LaserScan for the given nodeID.
void getMinUncertaintyPath(const mrpt::graphs::TNodeID from, const mrpt::graphs::TNodeID to, path_t *path) const
Given two nodeIDs compute and return the path connecting them.
typename GRAPH_T::global_pose_t global_pose_t
virtual bool updateState(mrpt::obs::CActionCollection::Ptr action, mrpt::obs::CSensoryFrame::Ptr observations, mrpt::obs::CObservation::Ptr observation)
virtual void addScanMatchingEdges(const mrpt::graphs::TNodeID &curr_nodeID)
Addd ICP constraints from X previous nodeIDs up to the given nodeID.
void initCurrCovarianceVisualization()
static const path_t * findPathByEnds(const paths_t &vec_paths, const mrpt::graphs::TNodeID &src, const mrpt::graphs::TNodeID &dst, bool throw_exc=true)
Given a vector of TUncertaintyPath objects, find the one that has the given source and destination no...
std::vector< path_t > paths_t
bool fillNodePropsFromGroupParams(const mrpt::graphs::TNodeID &nodeID, const std::map< mrpt::graphs::TNodeID, node_props_t > &group_params, node_props_t *node_props)
Fill the TNodeProps instance using the parameters from the map.
std::vector< hypot_t * > hypotsp_t
mrpt::graphslam::TUncertaintyPath< GRAPH_T > * popMinUncertaintyPath(std::set< path_t * > *pool_of_paths) const
Find the minimum uncertainty path from te given pool of TUncertaintyPath instances.
std::map< std::string, int > m_edge_types_to_nums
Keep track of the registered edge types.
typename parent_t::nodes_to_scans2D_t nodes_to_scans2D_t
void updateLaserScansVisualization()
void initLaserScansVisualization()
void loadParams(const std::string &source_fname)
void setWindowManagerPtr(mrpt::graphslam::CWindowManager *win_manager)
static hypot_t * findHypotByEnds(const hypotsp_t &vec_hypots, const mrpt::graphs::TNodeID &from, const mrpt::graphs::TNodeID &to, bool throw_exc=true)
Given a vector of THypothesis objects, find the one that has the given start and end nodes.
void registerHypothesis(const hypot_t &h)
Wrapper around the registerNewEdge method which accepts a THypothesis object instead.
std::vector< std::vector< uint32_t > > partitions_t
Typedef for referring to a list of partitions.
bool mahalanobisDistanceOdometryToICPEdge(const mrpt::graphs::TNodeID &from, const mrpt::graphs::TNodeID &to, const constraint_t &rel_edge)
brief Compare the suggested ICP edge against the initial node difference.
void updateMapPartitionsVisualization()
Update the map partitions visualization.
static hypot_t * findHypotByID(const hypotsp_t &vec_hypots, const size_t &id, bool throw_exc=true)
Given a vector of THypothesis objects, find the one that has the given ID.
void getEdgesStats(std::map< std::string, int > *edge_types_to_num) const
void execDijkstraProjection(mrpt::graphs::TNodeID starting_node=0, mrpt::graphs::TNodeID ending_node=INVALID_NODEID)
compute the minimum uncertainty of each node position with regards to the graph root.
virtual ~CLoopCloserERD()
void computeCentroidOfNodesVector(const std::vector< uint32_t > &nodes_list, std::pair< double, double > *centroid_coords) const
Compute the Centroid of a group of a vector of node positions.
typename mrpt::graphs::detail::THypothesis< GRAPH_T > hypot_t
typename GRAPH_T::edges_map_t::const_iterator edges_citerator
void dumpVisibilityErrorMsg(std::string viz_flag, int sleep_time=500)
void updateMapPartitions(bool full_update=false, bool is_first_time_node_reg=false)
Split the currently registered graph nodes into partitions.
void toggleLaserScansVisualization()
togle the LaserScans visualization on and off
void getDescriptiveReport(std::string *report_str) const
typename GRAPH_T::constraint_t::type_value pose_t
type of underlying poses (2D/3D).
void generatePWConsistenciesMatrix(const std::vector< uint32_t > &groupA, const std::vector< uint32_t > &groupB, const hypotsp_t &hypots_pool, mrpt::math::CMatrixDouble *consist_matrix, const paths_t *groupA_opt_paths=NULL, const paths_t *groupB_opt_paths=NULL)
Compute the pair-wise consistencies Matrix.
void notifyOfWindowEvents(const std::map< std::string, bool > &events_occurred)
virtual void fetchNodeIDsForScanMatching(const mrpt::graphs::TNodeID &curr_nodeID, std::set< mrpt::graphs::TNodeID > *nodes_set)
Fetch a list of nodes with regards prior to the given nodeID for which to try and add scan matching e...
void checkPartitionsForLC(partitions_t *partitions_for_LC)
Check the registered so far partitions for potential loop closures.
void initMapPartitionsVisualization()
Initialize the visualization of the map partition objects.
double generatePWConsistencyElement(const mrpt::graphs::TNodeID &a1, const mrpt::graphs::TNodeID &a2, const mrpt::graphs::TNodeID &b1, const mrpt::graphs::TNodeID &b2, const hypotsp_t &hypots, const paths_t *opt_paths=NULL)
Return the pair-wise consistency between the observations of the given nodes.
void addToPaths(std::set< path_t * > *pool_of_paths, const path_t &curr_path, const std::set< mrpt::graphs::TNodeID > &neibors) const
Append the paths starting from the current node.
virtual bool getICPEdge(const mrpt::graphs::TNodeID &from, const mrpt::graphs::TNodeID &to, constraint_t *rel_edge, mrpt::slam::CICP::TReturnInfo *icp_info=NULL, const TGetICPEdgeAdParams *ad_params=NULL)
Get the ICP Edge between the provided nodes.
void evalPWConsistenciesMatrix(const mrpt::math::CMatrixDouble &consist_matrix, const hypotsp_t &hypots_pool, hypotsp_t *valid_hypots)
Evalute the consistencies matrix, fill the valid hypotheses.
typename GRAPH_T::constraint_t constraint_t
Handy typedefs.
void toggleMapPartitionsVisualization()
Toggle the map partitions visualization objects.
Column vector, like Eigen::MatrixX*, but automatically initialized to zeros since construction.
std::shared_ptr< CActionCollection > Ptr
std::shared_ptr< CObservation2DRangeScan > Ptr
std::shared_ptr< CObservation > Ptr
Declares a class for storing a "sensory frame", a set of "observations" taken by the robot approximat...
void insert(const CObservation::Ptr &obs)
Inserts a new observation to the list: The pointer to the objects is copied, thus DO NOT delete the p...
std::shared_ptr< CSensoryFrame > Ptr
std::shared_ptr< CEllipsoid > Ptr
std::shared_ptr< COpenGLScene > Ptr
std::shared_ptr< CPlanarLaserScan > Ptr
std::shared_ptr< CRenderizable > Ptr
std::shared_ptr< CSetOfLines > Ptr
std::shared_ptr< CSetOfObjects > Ptr
std::shared_ptr< CSphere > Ptr
A class used to store a 3D pose (a 3D translation + a rotation in 3D).
mrpt::math::TPose3D asTPose() const
static CPose3DPDF * createFrom2D(const CPosePDF &o)
This is a static transformation method from 2D poses to 3D PDFs, preserving the representation type (...
#define MRPT_UNUSED_PARAM(a)
Determines whether this is an X86 or AMD64 platform.
const Scalar * const_iterator
#define ASSERTDEB_(f)
Defines an assertion mechanism - only when compiled in debug.
#define THROW_EXCEPTION(msg)
#define ASSERTDEBMSG_(f, __ERROR_MSG)
#define THROW_EXCEPTION_FMT(_FORMAT_STRING,...)
GLsizei GLsizei GLuint * obj
GLubyte GLubyte GLubyte GLubyte w
GLenum const GLfloat * params
GLenum GLsizei GLenum format
GLsizei const GLfloat * value
GLsizei const GLchar ** string
GLsizei GLsizei GLchar * source
std::string format(const char *fmt,...) MRPT_printf_format_check(1
A std::string version of C sprintf.
MAT::Scalar mahalanobisDistance2(const VECTORLIKE1 &X, const VECTORLIKE2 &MU, const MAT &COV)
Computes the squared mahalanobis distance of a vector X given the mean MU and the covariance inverse ...
std::string getSTLContainerAsString(const T &t)
Return a STL container in std::string form.
const_iterator find(const KEY &key) const
uint64_t TNodeID
A generic numeric type for unique IDs of nodes or entities.
Internal auxiliary classes.
SLAM methods related to graphs of pose constraints.
Classes for creating GUI windows for 2D and 3D visualization.
This base provides a set of functions for maths stuff.
bool approximatelyEqual(T1 a, T1 b, T2 epsilon)
Compare 2 floats and determine whether they are equal.
CMatrixFixedNumeric< double, 3, 3 > CMatrixDouble33
T absDiff(const T &lhs, const T &rhs)
Absolute difference between two numbers.
This namespace contains representation of robot actions and observations.
The namespace for 3D scene representation and rendering.
Eigen::Matrix< dataType, 4, 4 > inverse(Eigen::Matrix< dataType, 4, 4 > &pose)
Classes for 2D/3D geometry representation, both of single values and probability density distribution...
VerbosityLevel
Enumeration of available verbosity levels.
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
double DEG2RAD(const double x)
Degrees to radians.
An edge hypothesis between two nodeIDs.
void resizeWindow(size_t new_size)
Resize the window.
Holds the data of an information path.
void addToPath(const mrpt::graphs::TNodeID &node, const constraint_t &edge)
add a new link in the current path.
void assertIsBetweenNodeIDs(const mrpt::graphs::TNodeID &from, const mrpt::graphs::TNodeID &to) const
Assert that the current path is between the given nodeIDs.
const mrpt::graphs::TNodeID & getDestination() const
Return the Destination node of this path.
std::vector< mrpt::graphs::TNodeID > nodes_traversed
Nodes that the Path comprises of.
constraint_t curr_pose_pdf
Current path position + corresponding covariance.
Struct for passing additional parameters to the generateHypotsPool call.
std::map< mrpt::graphs::TNodeID, node_props_t > group_t
Struct for passing additional parameters to the getICPEdge call.
node_props_t to_params
Ad.
pose_t init_estim
Initial ICP estimation.
node_props_t from_params
Ad.
void getAsString(std::string *str) const
void loadFromConfigFile(const mrpt::config::CConfigFileBase &source, const std::string §ion)
This method load the options from a ".ini"-like file or memory-stored string list.
void dumpToTextStream(std::ostream &out) const
This method should clearly display all the contents of the structure in textual form,...
TSlidingWindow goodness_threshold_win
Keep track of ICP Goodness values for ICP between nearby nodes and adapt the Goodness threshold based...
TSlidingWindow mahal_distance_ICP_odom_win
Keep track of the mahalanobis distance between the initial pose difference and the suggested new edge...
void loadFromConfigFile(const mrpt::config::CConfigFileBase &source, const std::string §ion)
This method load the options from a ".ini"-like file or memory-stored string list.
void dumpToTextStream(std::ostream &out) const
This method should clearly display all the contents of the structure in textual form,...
mrpt::obs::CObservation2DRangeScan::Ptr scan
GRAPH_T::global_pose_t pose
A RGB color - floats in the range [0,1].
3D segment, consisting of two points.
The ICP algorithm return information.
float goodness
A goodness measure for the alignment, it is a [0,1] range indicator of percentage of correspondences.
#define MRPT_LOG_ERROR_STREAM(__CONTENTS)
#define MRPT_LOG_DEBUG_FMT(_FMT_STRING,...)
Use: MRPT_LOG_DEBUG_FMT("i=%u", i);
#define MRPT_LOG_DEBUG_STREAM(__CONTENTS)
Use: MRPT_LOG_DEBUG_STREAM("Var=" << value << " foo=" << foo_var);
#define MRPT_LOG_DEBUG(_STRING)
Use: MRPT_LOG_DEBUG("message");
#define MRPT_LOG_INFO(_STRING)
#define MRPT_LOG_WARN_STREAM(__CONTENTS)