47 void CHMTSLAM::thread_LSLAM()
51 unsigned int nIter = 0;
64 "[thread_LSLAM] Thread started ID=" << std::this_thread::get_id());
104 if (nextObject->GetRuntimeClass() ==
106 actions = std::dynamic_pointer_cast<CActionCollection>(
111 std::dynamic_pointer_cast<CSensoryFrame>(nextObject);
114 "Element in the queue is neither CActionCollection nor " 123 std::lock_guard<std::mutex> LMHs_cs_lock(obj->
m_LMHs_cs);
125 for (
auto it = obj->
m_LMHs.begin(); it != obj->
m_LMHs.end();
128 std::lock_guard<std::mutex> LMH_individual_lock(
129 it->second.threadLocks.m_lock);
136 actions, observations);
141 if (it->second.m_posesPendingAddPartitioner.size() >
148 unsigned nPosesToInsert =
149 it->second.m_posesPendingAddPartitioner.size();
151 CHMTSLAM::areaAbstraction(
153 it->second.m_posesPendingAddPartitioner);
157 "[AreaAbstraction] Took %.03fms to insert %u " 159 1000 * tictac2.
Tac(), nPosesToInsert);
162 it->second.m_posesPendingAddPartitioner.clear();
179 if (!it->second.m_areasPendingTBI.empty())
182 it->second.m_areasPendingTBI.begin();
183 areaID != it->second.m_areasPendingTBI.end();
193 CHMTSLAM::TBI_main_method(
194 &it->second, *areaID);
198 "[TBI] Took %.03fms " 200 1000 * tictac2.
Tac());
211 it->second.m_areasPendingTBI.clear();
235 std::this_thread::sleep_for(5ms);
244 catch (
const std::exception& e)
269 void CHMTSLAM::LSLAM_process_message(
const CMessage& msg)
307 "[LSLAM_proc_msg_AA] Beginning of Msg from AA processing... " 312 ASSERT_(itLMH != m_LMHs.end());
318 for (
const auto& partition : myMsg.
partitions)
319 for (
auto itPose = partition.begin(); itPose != partition.end();
321 if (LMH->m_SFs.find(*itPose) == LMH->m_SFs.end())
323 "PoseID %i in AA's partition but not in LMH.\n",
327 for (
auto itA = LMH->m_nodeIDmemberships.begin();
328 itA != LMH->m_nodeIDmemberships.end(); ++itA)
330 if (LMH->m_currentRobotPose != itA->first)
337 for (
unsigned long itPose : *it)
338 if (itA->first == itPose)
345 "LMH's pose %i not found in AA's partitions.",
352 TNodeIDSet neighbors_before(LMH->m_neighbors);
357 std::lock_guard<std::mutex> lock(m_map_cs);
359 auto itCur = LMH->m_nodeIDmemberships.find(LMH->m_currentRobotPose);
360 ASSERT_(itCur != LMH->m_nodeIDmemberships.end());
362 if (!m_map.getNodeByID(itCur->second)
363 ->m_annotations.getElemental(
376 map<unsigned int, map<CHMHMapNode::TNodeID, unsigned int>> votes;
379 static int DEBUG_STEP = 0;
387 DEBUG_STEP = DEBUG_STEP + 0;
391 std::lock_guard<std::mutex> lock(m_map_cs);
392 std::vector<std::string> s;
397 "%s/HMAP_txt/HMAP_%05i_before.txt",
398 m_options.LOG_OUTPUT_DIR.c_str(), DEBUG_STEP));
402 "[LSLAM_proc_msg_AA] Saved HMAP_%05i_before.txt\n", DEBUG_STEP);
406 vector<TPoseIDList>::const_iterator it;
409 for (
unsigned long itPose : *it)
411 auto itP = LMH->m_nodeIDmemberships.find(itPose);
412 ASSERT_(itP != LMH->m_nodeIDmemberships.end());
414 votes[i][itP->second]++;
419 vector<CHMHMapNode::TNodeID> partIdx2Areas(
422 map<CHMHMapNode::TNodeID, pair<size_t, unsigned int>>
428 for (
size_t k = 0; k < myMsg.
partitions.size(); k++)
430 if (votes[k].
size() == 1)
433 if (votes[k].
begin()->second >
434 mostVotedFrom[votes[k].begin()->first].second)
436 mostVotedFrom[votes[k].begin()->first].first = k;
437 mostVotedFrom[votes[k].begin()->first].second =
438 votes[k].begin()->second;
446 for (
auto& v : mostVotedFrom)
447 v.second.second = std::numeric_limits<unsigned int>::max();
451 for (
size_t k = 0; k < myMsg.
partitions.size(); k++)
453 for (
auto it = votes[k].
begin(); it != votes[k].end(); ++it)
458 map<CHMHMapNode::TNodeID, pair<size_t, unsigned int>>::iterator
460 mostVotesIt = mostVotedFrom.find(it->first);
461 if (mostVotesIt == mostVotedFrom.end())
464 mostVotedFrom[it->first].first = k;
465 mostVotedFrom[it->first].second = it->second;
470 if (it->second > mostVotesIt->second.second)
472 mostVotesIt->second.first = k;
473 mostVotesIt->second.second = it->second;
480 for (
auto& it : mostVotedFrom) partIdx2Areas[it.second.first] = it.first;
483 for (i = 0; i < partIdx2Areas.size(); i++)
488 std::lock_guard<std::mutex> lock(m_map_cs);
493 newArea->m_hypotheses.insert(LMH->m_ID);
494 newArea->m_nodeType =
"Area";
495 newArea->m_label = generateUniqueAreaLabel();
498 CMultiMetricMap::Create(m_options.defaultMapsInitializers);
499 newArea->m_annotations.setMemoryReference(
502 auto emptyPoseGraph = CRobotPosesGraph::Create();
503 newArea->m_annotations.setMemoryReference(
507 partIdx2Areas[i] = newArea->getID();
513 for (
unsigned idx = 0; idx < partIdx2Areas.size(); idx++)
516 << idx <<
" -> AREA_ID " << partIdx2Areas[idx] <<
" ('" 517 << m_map.getNodeByID(partIdx2Areas[idx])->m_label <<
"')\n");
524 LMH->m_neighbors.clear();
525 for (i = 0; i < partIdx2Areas.size(); i++)
530 LMH->m_neighbors.insert(nodeId);
535 LMH->m_nodeIDmemberships[it] =
543 LMH->getMeans(lstPoses);
546 const CPose3D* curPoseMean = &lstPoses[LMH->m_currentRobotPose];
548 for (
auto it = lstPoses.begin(); it != lstPoses.end(); ++it)
551 LMH->m_currentRobotPose)
556 closestPose = it->first;
565 LMH->m_nodeIDmemberships[LMH->m_currentRobotPose];
568 LMH->m_nodeIDmemberships[LMH->m_currentRobotPose] =
569 LMH->m_nodeIDmemberships[closestPose];
573 LMH->m_nodeIDmemberships[LMH->m_currentRobotPose];
575 if (curAreaID != oldAreaID)
578 "[LSLAM_proc_msg_AA] Current area has changed: %i -> %i\n",
579 (
int)oldAreaID, (
int)curAreaID);
584 for (
auto pBef = neighbors_before.begin(); pBef != neighbors_before.end();
587 if (LMH->m_neighbors.find(*pBef) == LMH->m_neighbors.end())
593 "[LSLAM_proc_msg_AA] Old neighbors: ");
594 for (
unsigned long it : neighbors_before)
601 "[LSLAM_proc_msg_AA] Cur. neighbors: ");
602 for (
unsigned long m_neighbor : LMH->m_neighbors)
608 std::lock_guard<std::mutex> lock(m_map_cs);
618 "[LSLAM_proc_msg_AA] Area %i has been removed from the " 619 "neighbors & no longer exists in the HMAP.\n",
626 "[LSLAM_proc_msg_AA] Deleting area %i\n",
638 using TListNodesArcs = map<CHMHMapNode::Ptr, CHMHMapArc::Ptr>;
639 TListNodesArcs lstWithinLMH;
641 for (
auto a = arcs.begin(); a != arcs.end(); ++a)
645 if ((*a)->getNodeFrom() == *pBef)
647 nodeB = m_map.getNodeByID((*a)->getNodeTo());
651 nodeB = m_map.getNodeByID((*a)->getNodeFrom());
654 bool inNeib = LMH->m_neighbors.find(nodeB->getID()) !=
655 LMH->m_neighbors.end();
656 bool inBefNeib = neighbors_before.find(nodeB->getID()) !=
657 neighbors_before.end();
659 if (inNeib && inBefNeib)
660 lstWithinLMH[nodeB] = *a;
665 for (
auto a = arcs.begin(); a != arcs.end(); ++a)
672 if (arc->getNodeFrom() == *pBef)
674 nodeB = m_map.getNodeByID((*a)->getNodeTo());
679 nodeB = m_map.getNodeByID((*a)->getNodeFrom());
683 bool inNeib = LMH->m_neighbors.find(nodeB->getID()) !=
684 LMH->m_neighbors.end();
685 bool inBefNeib = neighbors_before.find(nodeB->getID()) !=
686 neighbors_before.end();
688 if (inNeib && inBefNeib)
702 for (
auto& na : lstWithinLMH)
737 arc->m_annotations.getElemental(
739 refPoseAt_b, LMH->m_ID,
true);
740 arc->m_annotations.getElemental(
742 refPoseAt_a, LMH->m_ID,
true);
746 pdf->inverse(Delta_b_a);
749 arc->m_annotations.getElemental(
751 refPoseAt_b, LMH->m_ID,
true);
752 arc->m_annotations.getElemental(
754 refPoseAt_a, LMH->m_ID,
true);
758 nodeB->m_annotations.getElemental(
760 node_refPoseAt_b, LMH->m_ID,
true);
761 ASSERT_(node_refPoseAt_b == refPoseAt_b);
764 node->m_annotations.getElemental(
766 node_refPoseAt_a, LMH->m_ID,
true);
767 ASSERT_(node_refPoseAt_a == refPoseAt_a);
775 arc_c_a->m_annotations
780 if (arc_c_a->getNodeTo() == node_c->getID())
785 arc_c_a->m_annotations.getElemental(
787 refPoseAt_a, LMH->m_ID,
true);
788 arc_c_a->m_annotations.getElemental(
790 refPoseAt_c, LMH->m_ID,
true);
794 pdf->inverse(Delta_a_c);
797 arc_c_a->m_annotations.getElemental(
799 refPoseAt_a, LMH->m_ID,
true);
800 arc_c_a->m_annotations.getElemental(
802 refPoseAt_c, LMH->m_ID,
true);
806 node_c->m_annotations.getElemental(
808 node_refPoseAt_c, LMH->m_ID,
true);
809 ASSERT_(node_refPoseAt_c == refPoseAt_c);
812 node->m_annotations.getElemental(
814 node_refPoseAt_a, LMH->m_ID,
true);
815 ASSERT_(node_refPoseAt_a == refPoseAt_a);
823 Delta_b_c.
cov(0, 0) = Delta_b_c.
cov(1, 1) =
828 "b_a: " << Delta_b_a.
mean << endl
829 <<
"a_c: " << Delta_a_c.
mean << endl
830 <<
"b_a + a_c: " << Delta_b_c.
mean 838 bool arcDeltaIsInverted;
840 m_map.findArcOfTypeBetweenNodes(
844 "RelativePose", arcDeltaIsInverted);
849 newArc = std::make_shared<CHMHMapArc>(
855 newArc->m_arcType =
"RelativePose";
856 arcDeltaIsInverted =
false;
859 if (!arcDeltaIsInverted)
861 newArc->m_annotations.set(
863 std::make_shared<CPose3DPDFGaussian>(
867 "[LSLAM_proc_msg_AA] Setting arc " 868 << nodeB->getID() <<
" -> " 869 << node_c->getID() <<
" : " 870 << Delta_b_c.
mean <<
" cov = " 872 newArc->m_annotations.setElemental(
874 refPoseAt_b, LMH->m_ID);
875 newArc->m_annotations.setElemental(
877 refPoseAt_c, LMH->m_ID);
882 Delta_b_c.
inverse(Delta_b_c_inv);
885 "[LSLAM_proc_msg_AA] Setting arc " 886 << nodeB->getID() <<
" <- " 887 << node_c->getID() <<
" : " 888 << Delta_b_c_inv.
mean <<
" cov = " 891 newArc->m_annotations.set(
893 std::make_shared<CPose3DPDFGaussian>(
896 newArc->m_annotations.setElemental(
898 refPoseAt_c, LMH->m_ID);
899 newArc->m_annotations.setElemental(
901 refPoseAt_b, LMH->m_ID);
906 arc->m_annotations.removeAll(LMH->m_ID);
908 if (!arc->m_annotations.size())
921 for (
auto& arc : al) arc.reset();
937 if (curAreaID != oldAreaID)
939 LMH->m_areasPendingTBI.insert(curAreaID);
942 "[LSLAM_proc_msg_AA] Current area changed: enqueing area %i for " 948 static size_t cntAddTBI = 0;
952 LMH->m_areasPendingTBI.insert(curAreaID);
955 "[LSLAM_proc_msg_AA] Current area %i enqued for TBI (routine " 978 if (partIdx2Areas.size() > 1)
980 std::lock_guard<std::mutex> lock(m_map_cs);
983 set<CHMHMapNode::TNodeID>
987 map<CHMHMapNode::TNodeID, pair<CHMHMapNode::TNodeID, float>>
988 lstClosestDoubtfulNeigbors;
990 for (
size_t idx_area_a = 0; idx_area_a < partIdx2Areas.size();
1009 if (!area_a->m_annotations.getElemental(
1013 poseID_trg = myMsg.
partitions[idx_area_a][0];
1015 area_a->m_annotations.setElemental(
1019 "[LSLAM_proc_msg_AA] Changing reference poseID of area " 1020 "'%i' to pose '%i'\n",
1021 (
int)area_a_ID, (
int)poseID_trg);
1037 TPoseID poseID_trg_old = poseID_trg;
1038 for (
auto p = myMsg.
partitions[idx_area_a].begin();
1039 !found && p != myMsg.
partitions[idx_area_a].end(); ++p)
1040 if (poseID_trg == *p)
1050 poseID_trg = myMsg.
partitions[idx_area_a][0];
1051 area_a->m_annotations.setElemental(
1056 "[LSLAM_proc_msg_AA] Changing reference poseID of area " 1057 "'%i' to pose '%i'\n",
1058 (
int)area_a_ID, (
int)poseID_trg);
1068 area_a->getArcs(arcs);
1069 for (
auto a = arcs.begin(); a != arcs.end(); ++a)
1083 if (nodeFrom == area_a_ID)
1086 if (LMH->m_neighbors.find(nodeTo) ==
1087 LMH->m_neighbors.end())
1091 LMH->getRelativePose(
1092 poseID_trg, poseID_trg_old, Anew_old_parts);
1099 theArc->m_annotations
1104 newDelta = Anew_old + *oldDelta;
1107 newDelta.
cov(0, 0) = newDelta.
cov(1, 1) =
1112 "[LSLAM_proc_msg_AA] Updating arc " 1113 << nodeFrom <<
" -> " << nodeTo
1114 <<
" OLD: " << oldDelta->mean <<
" cov = " 1115 << oldDelta->cov.inMatlabFormat() << endl);
1117 "[LSLAM_proc_msg_AA] Updating arc " 1118 << nodeFrom <<
" -> " << nodeTo
1119 <<
" NEW: " << newDelta.
mean <<
" cov = " 1122 theArc->m_annotations.set(
1124 std::make_shared<CPose3DPDFGaussian>(
1127 theArc->m_annotations.setElemental(
1135 if (LMH->m_neighbors.find(nodeFrom) ==
1136 LMH->m_neighbors.end())
1140 LMH->getRelativePose(
1141 poseID_trg_old, poseID_trg, Aold_new_parts);
1147 theArc->m_annotations
1153 newDelta = *oldDelta + Aold_new;
1157 newDelta.cov(0, 0) = newDelta.cov(1, 1) =
1159 newDelta.cov(3, 3) =
square(1.0_deg);
1162 "[LSLAM_proc_msg_AA] Updating arc " 1163 << nodeFrom <<
" <- " << nodeTo
1164 <<
" OLD: " << oldDelta->mean <<
" cov = " 1165 << oldDelta->cov.inMatlabFormat() << endl);
1167 "[LSLAM_proc_msg_AA] Updating arc " 1168 << nodeFrom <<
" <- " << nodeTo
1169 <<
" NEW: " << newDelta.mean <<
" cov = " 1170 << newDelta.cov.inMatlabFormat() << endl);
1172 theArc->m_annotations.set(
1174 std::make_shared<CPose3DPDFGaussian>(
1177 theArc->m_annotations.setElemental(
1189 for (
size_t idx_area_b = 0; idx_area_b < myMsg.
partitions.size();
1192 if (idx_area_a == idx_area_b)
1196 double closestDistPoseSrc = 0;
1200 for (
auto itP0 = myMsg.
partitions[idx_area_a].begin();
1201 itP0 != myMsg.
partitions[idx_area_a].end(); itP0++)
1203 const CPose3D& pose_trg = lstPoses[*itP0];
1205 for (
unsigned long itP : myMsg.
partitions[idx_area_b])
1207 const CPose3D& otherPose = lstPoses[itP];
1209 if (dst < closestDistPoseSrc ||
1212 poseID_closests = itP;
1213 closestDistPoseSrc = dst;
1223 if (closestDistPoseSrc <
1224 5 * m_options.SLAM_MIN_DIST_BETWEEN_OBS)
1230 if (!area_b->m_annotations.getElemental(
1235 area_b->m_annotations.setElemental(
1238 poseID_src = poseID_closests;
1241 "[LSLAM_proc_msg_AA] Changing reference poseID of " 1242 "area '%i' to pose '%i' (creat. annot)\n",
1243 (
int)area_b_ID, (
int)poseID_closests);
1248 if (lstInternalArcsToCreate.end() ==
1249 lstInternalArcsToCreate.
find(
1251 lstInternalArcsToCreate.end() ==
1252 lstInternalArcsToCreate.
find(
1255 lstInternalArcsToCreate.
insert(
1257 areasWithLink.insert(area_a_ID);
1258 areasWithLink.insert(area_b_ID);
1263 if (lstClosestDoubtfulNeigbors.find(area_b_ID) ==
1264 lstClosestDoubtfulNeigbors.end() ||
1265 closestDistPoseSrc <
1266 lstClosestDoubtfulNeigbors[area_b_ID].second)
1268 lstClosestDoubtfulNeigbors[area_b_ID].first = area_a_ID;
1269 lstClosestDoubtfulNeigbors[area_b_ID].second =
1284 for (
size_t idx_area = 0; idx_area < myMsg.
partitions.size();
1288 if (areasWithLink.find(area_ID) == areasWithLink.end())
1291 if (lstClosestDoubtfulNeigbors.find(area_ID) !=
1292 lstClosestDoubtfulNeigbors.end())
1296 area_ID, lstClosestDoubtfulNeigbors[area_ID].first));
1299 areasWithLink.insert(area_ID);
1300 areasWithLink.insert(
1301 lstClosestDoubtfulNeigbors[area_ID].first);
1306 "Area %i seems unconnected??", (
int)area_ID);
1317 "[LSLAM_proc_msg_AA] lstInternalArcsToCreate contains %i " 1319 (
int)lstInternalArcsToCreate.size());
1320 for (
auto arcCreat = lstInternalArcsToCreate.begin();
1321 arcCreat != lstInternalArcsToCreate.end(); ++arcCreat)
1328 (
int)closestAreaID, (
int)newAreaID);
1341 std::lock_guard<std::mutex> lock(m_map_cs);
1344 for (
auto arcCreat = lstInternalArcsToCreate.begin();
1345 arcCreat != lstInternalArcsToCreate.end(); ++arcCreat)
1350 m_map.getNodeByID(area_a_ID)->m_annotations.getElemental(
1355 m_map.getNodeByID(area_b_ID)->m_annotations.getElemental(
1360 LMH->getRelativePose(
1361 area_a_poseID_src, area_b_poseID_trg, relPoseParts);
1365 relPoseGauss.
copyFrom(relPoseParts);
1368 relPoseGauss.
cov(0, 0) = relPoseGauss.
cov(1, 1) =
square(0.04);
1369 relPoseGauss.
cov(3, 3) =
square(1.0_deg);
1373 "[LSLAM_proc_msg_AA] Creating arc %i[ref:%i] -> %i[ref:%i] = " 1374 "(%.03f,%.03f,%.03fdeg)\n",
1375 (
int)area_a_ID, (
int)area_a_poseID_src, (
int)area_b_ID,
1376 (
int)area_b_poseID_trg, relPoseGauss.
mean.
x(),
1381 bool arcDeltaIsInverted;
1383 area_a_ID, area_b_ID, LMH->m_ID,
"RelativePose",
1384 arcDeltaIsInverted);
1389 newArc = std::make_shared<CHMHMapArc>(
1395 newArc->m_arcType =
"RelativePose";
1396 arcDeltaIsInverted =
false;
1400 if (!arcDeltaIsInverted)
1403 "[LSLAM_proc_msg_AA] Updating int. arc " 1404 << area_a_ID <<
" -> " << area_b_ID <<
" : " 1405 << relPoseGauss.
mean 1407 newArc->m_annotations.set(
1409 std::make_shared<CPose3DPDFGaussian>(relPoseGauss),
1411 newArc->m_annotations.setElemental(
1414 newArc->m_annotations.setElemental(
1421 relPoseGauss.
inverse(relPoseInv);
1424 "[LSLAM_proc_msg_AA] Updating int. arc " 1425 << area_a_ID <<
" <- " << area_b_ID <<
" : " 1428 newArc->m_annotations.set(
1430 std::make_shared<CPose3DPDFGaussian>(relPoseInv),
1433 newArc->m_annotations.setElemental(
1436 newArc->m_annotations.setElemental(
1451 std::lock_guard<std::mutex> lock(m_map_cs);
1453 for (
auto pNei = LMH->m_neighbors.begin();
1454 pNei != LMH->m_neighbors.end(); ++pNei)
1462 nodeFrom->getArcs(lstArcs,
"RelativePose", LMH->m_ID);
1467 for (
auto a = lstArcs.begin(); a != lstArcs.end(); ++a)
1470 (*a)->getNodeFrom() == nodeFromID ? (*a)->getNodeTo()
1471 : (*a)->getNodeFrom();
1473 if (LMH->m_neighbors.find(nodeToID) != LMH->m_neighbors.end())
1478 if (lstInternalArcsToCreate.end() ==
1479 lstInternalArcsToCreate.
find(
1481 lstInternalArcsToCreate.end() ==
1482 lstInternalArcsToCreate.
find(
1486 arc->m_annotations.remove(
1490 "[LSLAM_proc_msg_AA] Deleting annotation of arc: " 1492 (
long unsigned)nodeFromID, (
long unsigned)nodeToID);
1495 if (!arc->m_annotations.getAnyHypothesis(
1500 "[LSLAM_proc_msg_AA] Deleting empty arc: " 1502 (
long unsigned)nodeFromID,
1503 (
long unsigned)nodeToID);
1515 std::lock_guard<std::mutex> lock(m_map_cs);
1516 std::vector<std::string> s;
1517 m_map.dumpAsText(s);
1522 "%s/HMAP_txt/HMAP_%05i_mid.txt", m_options.LOG_OUTPUT_DIR.c_str(),
1527 "[LSLAM_proc_msg_AA] Saved HMAP_%05i_mid.txt\n", DEBUG_STEP);
1539 for (
auto pNei1 = LMH->m_neighbors.begin();
1540 pNei1 != LMH->m_neighbors.end();)
1542 if (*pNei1 != curAreaID)
1546 std::lock_guard<std::mutex> lock(m_map_cs);
1547 m_map.findArcsOfTypeBetweenNodes(
1548 *pNei1, curAreaID, LMH->m_ID,
"RelativePose", lstArcs);
1550 if (lstArcs.empty())
1554 "[LSLAM_proc_msg_AA] Getting area '%u' out of LMH\n",
1555 static_cast<unsigned>(*pNei1));
1563 double ESS_bef = LMH->ESS();
1564 LMH->removeAreaFromLMH(
id);
1565 double ESS_aft = LMH->ESS();
1568 "[LSLAM_proc_msg_AA] ESS: %f -> %f\n", ESS_bef, ESS_aft);
1591 std::lock_guard<std::mutex> lock(m_map_cs);
1594 LMH->m_nodeIDmemberships[LMH->m_currentRobotPose];
1595 currentArea = m_map.getNodeByID(curAreaID);
1597 TPoseID refPoseCurArea_accordingAnnot;
1598 currentArea->m_annotations.getElemental(
1603 currentArea->getArcs(arcsToCurArea,
"RelativePose", LMH->m_ID);
1604 for (
auto& a : arcsToCurArea)
1608 arc->getNodeFrom() == curAreaID ? arc->getNodeTo()
1609 : arc->getNodeFrom();
1612 if (LMH->m_neighbors.find(otherAreaID) == LMH->m_neighbors.end())
1616 "[LSLAM_proc_msg_AA] Bringing in LMH area %i\n",
1634 pdf->getMean(Delta_c2a);
1637 TPoseID refPoseIDAtOtherArea, refPoseIDAtCurArea;
1639 if (arc->getNodeTo() == curAreaID)
1644 "[LSLAM_proc_msg_AA] Arc is inverted: " 1645 "(%.03f,%.03f,%.03fdeg) -> ",
1646 Delta_c2a.x(), Delta_c2a.y(),
RAD2DEG(Delta_c2a.yaw()));
1648 Delta_c2a =
CPose3D(0, 0, 0) - Delta_c2a;
1652 Delta_c2a.x(), Delta_c2a.y(),
RAD2DEG(Delta_c2a.yaw()));
1654 arc->m_annotations.getElemental(
1657 arc->m_annotations.getElemental(
1664 arc->m_annotations.getElemental(
1667 arc->m_annotations.getElemental(
1674 "[LSLAM_proc_msg_AA] Bringing in: refPoseCur=%i " 1675 "refPoseOther=%i -> Delta_c2a:(%.03f,%.03f,%.03fdeg)\n",
1676 (
int)refPoseIDAtCurArea, (
int)refPoseIDAtOtherArea,
1677 Delta_c2a.x(), Delta_c2a.y(),
RAD2DEG(Delta_c2a.yaw()));
1680 #if defined(_DEBUG) || (MRPT_ALWAYS_CHECKS_DEBUG) 1682 TPoseID refPoseOtherArea_accordingAnnot;
1683 area->m_annotations.getElemental(
1685 refPoseOtherArea_accordingAnnot, LMH->m_ID,
true);
1687 refPoseIDAtOtherArea ==
1688 refPoseOtherArea_accordingAnnot);
1691 refPoseIDAtCurArea == refPoseCurArea_accordingAnnot);
1700 lstNewPoseIDs.reserve(pg->size());
1703 const TPoseID& poseID = p.first;
1706 lstNewPoseIDs.push_back(poseID);
1711 LMH->m_particles.size());
1713 CPose3DPDFParticles::CParticleList::const_iterator itSrc;
1714 CLocalMetricHypothesis::CParticleList::iterator itTrg;
1717 itTrg = LMH->m_particles.begin();
1718 itTrg != LMH->m_particles.end(); itSrc++, itTrg++)
1722 itTrg->d->robotPoses[poseID] =
1723 itTrg->d->robotPoses[refPoseIDAtCurArea] +
1724 Delta_c2a +
CPose3D(itSrc->d);
1728 LMH->m_nodeIDmemberships[poseID] = otherAreaID;
1731 LMH->m_SFs[poseID] = poseInfo.
sf;
1734 LMH->m_neighbors.
insert(otherAreaID);
1741 LMH->m_posesPendingAddPartitioner.insert(
1742 LMH->m_posesPendingAddPartitioner.end(),
1743 lstNewPoseIDs.begin(), lstNewPoseIDs.end());
1747 areasDelayedMetricMapsInsertion.insert(otherAreaID);
1755 std::vector<std::string> s;
1760 "%s/HMAP_txt/HMAP_%05i_LMH_mid.txt",
1761 m_options.LOG_OUTPUT_DIR.c_str(), DEBUG_STEP));
1765 "[LSLAM_proc_msg_AA] Saved HMAP_%05i_LMH_mid.txt\n", DEBUG_STEP);
1772 std::make_shared<opengl::CSetOfObjects>();
1773 maps3D->setName(
"metric-maps");
1774 LMH->getMostLikelyParticle()->d->metricMaps.getAs3DObject(maps3D);
1775 sceneLSLAM.
insert(maps3D);
1779 std::make_shared<opengl::CSetOfObjects>();
1780 LSLAM_3D->setName(
"LSLAM_3D");
1781 LMH->getAs3DScene(LSLAM_3D);
1782 sceneLSLAM.
insert(LSLAM_3D);
1786 string filLocalAreas =
format(
1787 "%s/HMAP_txt/HMAP_%05i_LMH_mid.3Dscene",
1788 m_options.LOG_OUTPUT_DIR.c_str(), DEBUG_STEP);
1801 if (!currentArea->m_annotations.getElemental(
1805 if (new_poseID_origin != poseID_origin)
1809 LMH->changeCoordinateOrigin(new_poseID_origin);
1812 "[LSLAM_proc_msg_AA] LMH->changeCoordinateOrigin %lu->%lu took %f " 1814 poseID_origin, new_poseID_origin, tt.
Tac() * 1000);
1816 else if (areasDelayedMetricMapsInsertion.size())
1822 for (
unsigned long areaID : areasDelayedMetricMapsInsertion)
1825 for (
auto pn = LMH->m_nodeIDmemberships.begin();
1826 pn != LMH->m_nodeIDmemberships.end(); ++pn)
1828 if (pn->second == areaID)
1831 const TPoseID& poseToAdd = pn->first;
1833 LMH->m_SFs.find(poseToAdd)->second;
1836 for (
auto partIt = LMH->m_particles.begin();
1837 partIt != LMH->m_particles.end(); ++partIt)
1839 auto pose3D = partIt->d->robotPoses.find(poseToAdd);
1840 ASSERT_(pose3D != partIt->d->robotPoses.end());
1842 &partIt->d->metricMaps, &pose3D->second);
1850 "[LSLAM_proc_msg_AA] areasDelayedMetricMapsInsertion took %f ms\n",
1856 std::lock_guard<std::mutex> lock(m_map_cs);
1857 std::vector<std::string> s;
1858 m_map.dumpAsText(s);
1862 "%s/HMAP_txt/HMAP_%05i_after.txt", m_options.LOG_OUTPUT_DIR.c_str(),
1867 "[LSLAM_proc_msg_AA] Saved HMAP_%05i_after.txt\n", DEBUG_STEP);
1871 std::vector<std::string> s;
1876 "%s/HMAP_txt/HMAP_%05i_LMH_after.txt",
1877 m_options.LOG_OUTPUT_DIR.c_str(), DEBUG_STEP));
1881 "[LSLAM_proc_msg_AA] Saved HMAP_%05i_LMH_after.txt\n", DEBUG_STEP);
1886 "[LSLAM_proc_msg_AA] Msg from AA took %f ms ]\n",
1887 tictac.Tac() * 1000);
1903 "[LSLAM_proc_msg_TBI] Beginning of Msg from TBI processing... " 1908 std::map<CHMHMapNode::TNodeID, CHMHMapNode::TNodeID> alreadyClosedLoops;
1915 "[LSLAM_proc_msg_TBI] Processing TLC of areas: %u <-> %u... \n",
1916 (
unsigned)myMsg.
cur_area, (
unsigned)candidate->first);
1920 if (alreadyClosedLoops.find(myMsg.
cur_area) != alreadyClosedLoops.end())
1922 currentArea = alreadyClosedLoops[myMsg.
cur_area];
1923 cout <<
"[LSLAM_proc_msg_TBI] Using " << myMsg.
cur_area <<
" -> " 1924 << currentArea <<
" due to area being already merged." 1931 m_map.computeCoordinatesTransformationBetweenNodes(
1934 candidate->first, pdfPartsHMap, myMsg.
hypothesisID, 100, 0.10f,
1939 pdfDeltaMap.
copyFrom(pdfPartsHMap);
1946 pdfDeltaMap.
cov(3, 3) +=
square(5.0_deg);
1947 pdfDeltaMap.
cov(4, 4) +=
square(5.0_deg);
1948 pdfDeltaMap.
cov(5, 5) +=
square(5.0_deg);
1950 cout <<
"[LSLAM_proc_msg_TBI] HMap_delta=" << pdfDeltaMap.
mean 1951 <<
" std_x=" << sqrt(pdfDeltaMap.
cov(0, 0))
1952 <<
" std_y=" << sqrt(pdfDeltaMap.
cov(1, 1)) << endl;
1960 ASSERT_(!candidate->second.delta_new_cur.empty());
1961 const double chi2_thres =
1964 map<double, CPose3DPDFGaussian>
1968 for (
const auto& itSOG : candidate->second.delta_new_cur)
1972 cout <<
"[LSLAM_proc_msg_TBI] TLC_delta=" << pdfDelta.
mean 1973 <<
" std_x=" << sqrt(pdfDelta.
cov(0, 0))
1974 <<
" std_y=" << sqrt(pdfDelta.
cov(1, 1))
1975 <<
" std_phi=" <<
RAD2DEG(sqrt(pdfDelta.
cov(3, 3))) << endl;
1979 const double mahaDist2 =
1981 cout <<
"[LSLAM_proc_msg_TBI] maha_dist = " << mahaDist2 << endl;
1983 if (mahaDist2 < chi2_thres)
1985 const double log_lik = itSOG.log_w - 0.5 * mahaDist2;
1986 lstModesAndCompats[log_lik] = itSOG.val;
1987 cout <<
"[LSLAM_proc_msg_TBI] Added to list of candidates: " 1988 "log(overall_lik)= " 1994 if (!lstModesAndCompats.empty())
1997 lstModesAndCompats.rbegin()->second;
2010 "[LSLAM_proc_msg_TBI] Accepting TLC of areas: %u <-> %u with " 2011 "an overall log(lik)=%f \n",
2012 (
unsigned)currentArea, (
unsigned)candidate->first,
2013 lstModesAndCompats.rbegin()->first);
2023 "[LSLAM_proc_msg_TBI] TLC of areas %u <-> %u - DONE in %.03f " 2025 (
unsigned)currentArea, (
unsigned)candidate->first,
2026 1e3 * tictac.
Tac());
2029 alreadyClosedLoops[myMsg.
cur_area] = candidate->first;
2037 "[LSLAM_proc_msg_TBI] Msg from TBI took %f ms ]\n",
2038 tictac.Tac() * 1000);
A namespace of pseudo-random numbers generators of diferent distributions.
int random_seed
0 means randomize, use any other value to have repetitive experiments.
double Tac() noexcept
Stops the stopwatch.
CLSLAMAlgorithmBase * m_LSLAM_method
An instance of a local SLAM method, to be applied to each LMH - initialized by "initializeEmptyMap" o...
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...
CPose3D mean
The mean value.
std::list< T >::iterator find(const T &i)
void logFmt(const VerbosityLevel level, const char *fmt,...) const MRPT_printf_format_check(3
Alternative logging method, which mimics the printf behavior.
std::map< CHMHMapNode::TNodeID, TBI_info > loopClosureData
The meat is here: only feasible loop closures from "cur_area" are included here, with associated data...
#define THROW_EXCEPTION(msg)
int LOG_FREQUENCY
[LOGGING] One SLAM iteration out of "LOGGING_logFrequency", a log file will be generated.
void copyFrom(const CPose3DPDF &o) override
Copy operator, translating if necesary (for example, between particles and gaussian representations) ...
mrpt::graphs::TNodeID TNodeID
The type of the IDs of nodes.
double mahalanobisDistanceTo(const CPose3DPDFGaussian &theOther)
Computes the Mahalanobis distance between the centers of two Gaussians.
std::string std::string format(std::string_view fmt, ARGS &&... args)
size_t size(const MATRIXLIKE &m, const int dim)
CParticleList m_particles
The array of particles.
Classes related to the implementation of Hybrid Metric Topological (HMT) SLAM.
void randomize(const uint32_t seed)
Initialize the PRNG from the given random seed.
mrpt::poses::CPose3DPDFParticles pdf
The robot pose PDF.
uint64_t TPoseID
An integer number uniquely identifying each robot pose stored in HMT-SLAM.
void generateLogFiles(unsigned int nIteration)
Called from LSLAM thread when log files must be created.
A high-performance stopwatch, with typical resolution of nanoseconds.
double yaw() const
Get the YAW angle (in radians)
THypothesisID hypothesisID
The hypothesis ID (LMH) for these results.
void stringListAsString(const std::vector< std::string > &lst, std::string &out, const std::string &newline="\")
Convert a string list to one single string with new-lines.
An implementation of Hybrid Metric Topological SLAM (HMT-SLAM).
Declares a class for storing a collection of robot actions.
std::set< CHMHMapNode::TNodeID > TNodeIDSet
std::vector< TPoseID > TPoseIDList
double distanceTo(const CPoseOrPoint< OTHERCLASS, DIM2 > &b) const
Returns the Euclidean distance to another pose/point:
CArchiveStreamBase< STREAM > archiveFrom(STREAM &s)
Helper function to create a templatized wrapper CArchive object for a: MRPT's CStream, std::istream, std::ostream, std::stringstream.
double distanceEuclidean6D(const CPose3D &o) const
The euclidean distance between two poses taken as two 6-length vectors (angles in radians)...
mrpt::serialization::CSerializable::Ptr getNextObjectFromInputQueue()
Used from the LSLAM thread to retrieve the next object from the queue.
CHMHMapNode::TNodeID cur_area
The area for who the loop-closure has been computed.
#define ASSERT_(f)
Defines an assertion mechanism.
This base provides a set of functions for maths stuff.
This class implements a STL container with features of both, a std::set and a std::list.
std::atomic_bool m_terminationFlag_LSLAM
Threads termination flags:
#define CLASS_ID(T)
Access to runtime class ID for a defined class name.
A set of hypothesis IDs, used for arcs and nodes in multi-hypothesis hybrid maps. ...
std::string LOG_OUTPUT_DIR
[LOGGING] If it is not an empty string (""), a directory with that name will be created and log files...
std::list< T >::iterator erase_return_next(std::list< T > &cont, typename std::list< T >::iterator &it)
Calls the standard "erase" method of a STL container, but also returns an iterator to the next elemen...
std::mutex m_LMHs_cs
Critical section for accessing m_LMHs.
constexpr double DEG2RAD(const double x)
Degrees to radians.
CMessageQueue m_LSLAM_queue
void enableFollowCamera(bool enabled)
If disabled (default), the SceneViewer application will ignore the camera of the "main" viewport and ...
void inverse(CPose3DPDF &o) const override
Returns a new PDF such as: NEW_PDF = (0,0,0) - THIS_PDF.
std::map< TPoseID, mrpt::poses::CPose3D > TMapPoseID2Pose3D
std::vector< TPoseIDList > partitions
std::map< THypothesisID, CLocalMetricHypothesis > m_LMHs
The list of LMHs at each instant.
This namespace contains representation of robot actions and observations.
Declares a class for storing a "sensory frame", a set of "observations" taken by the robot approximat...
Auxiliary class used in mrpt::slam::CLocalMetricHypothesis for HMT-SLAM; this class stores a set of r...
THypothesisID hypothesisID
The hypothesis ID (LMH) for these results.
mrpt::hmtslam::CHMTSLAM::TOptions m_options
double x() const
Common members of all points & poses classes.
This class is used in HMT-SLAM to represent each of the Local Metric Hypotheses (LMHs).
#define MRPT_LOG_DEBUG_STREAM(__CONTENTS)
Use: MRPT_LOG_DEBUG_STREAM("Var=" << value << " foo=" << foo_var);
This CStream derived class allow using a file as a write-only, binary stream.
#define NODE_ANNOTATION_METRIC_MAPS
std::atomic_bool m_terminateThreads
Termination flag for signaling all threads to terminate.
Classes for 2D/3D geometry representation, both of single values and probability density distribution...
void pause(const std::string &msg=std::string("Press any key to continue...")) noexcept
Shows the message "Press any key to continue" (or other custom message) to the current standard outpu...
mrpt::math::CMatrixDouble66 cov
The 6x6 covariance matrix.
return_t square(const num_t x)
Inline function for the square of a number.
#define MRPT_LOG_INFO_STREAM(__CONTENTS)
This class is a "CSerializable" wrapper for "CMatrixFloat".
const_iterator begin() const
A class that contain generic messages, that can be sent and received from a "CClientTCPSocket" object...
double chi2inv(double P, unsigned int dim=1)
The "quantile" of the Chi-Square distribution, for dimension "dim" and probability 0<P<1 (the inverse...
#define ARC_ANNOTATION_DELTA_SRC_POSEID
A class used to store a 3D pose (a 3D translation + a rotation in 3D).
#define MRPT_LOG_ERROR(_STRING)
void LSLAM_process_message_from_TBI(const TMessageLSLAMfromTBI &myMsg)
No critical section locks are assumed at the entrance of this method.
constexpr double RAD2DEG(const double x)
Radians to degrees.
mrpt::obs::CSensoryFrame sf
The observations.
std::string inMatlabFormat(const std::size_t decimal_digits=6) const
Exports the matrix as a string compatible with Matlab/Octave.
The namespace for 3D scene representation and rendering.
This class allows the user to create, load, save, and render 3D scenes using OpenGL primitives...
#define NODE_ANNOTATION_REF_POSEID
Declares a class that represents a Probability Density function (PDF) of a 3D pose ...
Information kept for each robot pose used in CRobotPosesGraph.
std::pair< TNodeID, TNodeID > TPairNodeIDs
A pair of node IDs.
void Tic() noexcept
Starts the stopwatch.
void LSLAM_process_message(const mrpt::serialization::CMessage &msg)
Auxiliary method within thread_LSLAM.
#define NODE_ANNOTATION_POSES_GRAPH
virtual void processOneLMH(CLocalMetricHypothesis *LMH, const mrpt::obs::CActionCollection::Ptr &act, const mrpt::obs::CSensoryFrame::Ptr &sf)=0
Main entry point from HMT-SLAM: process some actions & observations.
#define THROW_EXCEPTION_FMT(_FORMAT_STRING,...)
CRandomGenerator & getRandomGenerator()
A static instance of a CRandomGenerator class, for use in single-thread applications.
bool insertObservationsInto(mrpt::maps::CMetricMap *theMap, const mrpt::poses::CPose3D *robotPose=nullptr) const
Insert all the observations in this SF into a metric map or any kind (see mrpt::maps::CMetricMap).
void insert(const CRenderizable::Ptr &newObject, const std::string &viewportName=std::string("main"))
Insert a new object into the scene, in the given viewport (by default, into the "main" viewport)...
#define ARC_ANNOTATION_DELTA_TRG_POSEID
bool isInputQueueEmpty()
Returns true if the input queue is empty (Note that the queue must not be empty to the user to enqueu...
A class for storing a sequence of arcs (a path).
#define ARC_ANNOTATION_DELTA
void LSLAM_process_message_from_AA(const TMessageLSLAMfromAA &myMsg)
No critical section locks are assumed at the entrance of this method.
Declares a class that represents a Probability Density function (PDF) of a 3D pose.
T * get()
Retrieve the next message in the queue, or nullptr if there is no message.
#define MRPT_UNUSED_PARAM(a)
Determines whether this is an X86 or AMD64 platform.