39 #include <Ice/Current.h>
41 #include <SimoxUtility/algorithm/string/string_tools.h>
42 #include <VirtualRobot/Primitive.h>
43 #include <VirtualRobot/Robot.h>
44 #include <VirtualRobot/VirtualRobot.h>
45 #include <VirtualRobot/XML/RobotIO.h>
57 #include <ArmarXCore/interface/core/PackagePath.h>
73 #include <RobotAPI/libraries/armem_locations/aron/Location.aron.generated.h>
78 #include <armarx/navigation/algorithms/aron/Costmap.aron.generated.h>
79 #include <armarx/navigation/algorithms/aron/Room.aron.generated.h>
82 #include <armarx/navigation/core/aron/Graph.aron.generated.h>
83 #include <armarx/navigation/core/aron/Trajectory.aron.generated.h>
85 #include <armarx/navigation/human/aron/Human.aron.generated.h>
87 #include <armarx/navigation/memory/aron/LaserScannerFeatures.aron.generated.h>
92 #include <nlohmann/json_fwd.hpp>
115 def->optional(properties.snapshotToLoad,
117 "Snapshot to load at start up \n"
118 "(e.g. 'R003' to load 'PriorKnowledgeData/navigation-graphs/R003').");
120 def->optional(properties.packageToLoad,
122 "Package to load snapshot at start up \n"
123 "(e.g. 'PriorKnowledgeData').");
125 def->optional(properties.locationGraph.visuLocations,
126 "p.locationGraph.visuLocation",
127 "Enable visualization of locations.");
130 properties.locationGraph.visuRelativeLocations,
131 "p.locationGraph.visuRelativeLocation",
132 "Enable visualization of relative locations (currently supported: robots, objects).");
134 def->optional(properties.locationGraph.visuGraphEdges,
135 "p.locationGraph.visuGraphEdges",
136 "Enable visualization of navigation graph edges.");
139 properties.visuCostmaps,
"p.visuCostmaps",
"Enable visualization of costmaps.");
140 def->optional(properties.zOffsetCostmap,
142 "Adjust the height of the visualized costmap.");
144 def->optional(properties.visuHumans,
"p.visuHumans",
"Enable visualization of humans.");
146 def->optional(properties.visuTransparent,
148 "Enable visualization of humans a bit transparent.");
150 def->optional(properties.visuHumanMaxAgeMs,
151 "p.visuHumanMaxAgeMs",
152 "The maximum age of humans to be drawn in ms.");
154 def->optional(properties.visuRooms,
"p.visuRooms",
"Enable visualization of rooms.");
156 def->optional(properties.visuFrequency,
158 "Visualization frequeny of locations and graph edges [Hz].");
163 properties.coreSeg.parameterization.maxHistorySize,
164 "p.coreSeg.parameterization.maxHistorySize",
165 "Max history size of the " +
169 def->optional(properties.coreSeg.costmap.maxHistorySize,
170 "p.coreSeg.costmap.maxHistorySize",
171 "Max history size of the " +
176 properties.coreSeg.resultsGlobalPlanner.maxHistorySize,
177 "p.coreSeg.resultsGlobalPlanner.maxHistorySize",
178 "Max history size of the " +
182 def->optional(properties.coreSeg.resultsLocalPlanner.maxHistorySize,
183 "p.coreSeg.resultsLocalPlanner.maxHistorySize",
184 "Max history size of the " +
188 def->optional(properties.coreSeg.events.maxHistorySize,
189 "p.coreSeg.events.maxHistorySize",
190 "Max history size of the " +
194 def->optional(properties.coreSeg.exceptions.maxHistorySize,
195 "p.coreSeg.exceptions.maxHistorySize",
196 "Max history size of the " +
200 def->optional(properties.coreSeg.location.maxHistorySize,
201 "p.coreSeg.location.maxHistorySize",
202 "Max history size of the " +
206 def->optional(properties.coreSeg.graph.maxHistorySize,
207 "p.coreSeg.graph.maxHistorySize",
208 "Max history size of the " +
212 def->optional(properties.coreSeg.human.maxHistorySize,
213 "p.coreSeg.human.maxHistorySize",
214 "Max history size of the " +
219 properties.coreSeg.laserScannerFeatures.maxHistorySize,
220 "p.coreSeg.laserScannerFeatures.maxHistorySize",
221 "Max history size of the " +
225 def->optional(properties.coreSeg.rooms.maxHistorySize,
226 "p.coreSeg.rooms.maxHistorySize",
227 "Max history size of the " +
255 algorithms::arondto::Costmap::ToAronType())
260 navigation::core::arondto::GlobalTrajectory::ToAronType())
265 navigation::core::arondto::LocalTrajectory::ToAronType())
284 navigation::location::arondto::Location::ToAronType())
288 navigation::core::arondto::Graph::ToAronType())
293 navigation::human::arondto::Human::ToAronType())
298 navigation::memory::arondto::LaserScannerFeatures::ToAronType())
305 navigation::algorithms::arondto::Room::ToAronType())
328 tasks.visuTask->start();
350 return "navigation_memory";
360 tab.locationGraph.setup(*
this);
370 tab.locationGraph.update(*
this);
394 grid.
add(
Label(
"Visualize Locations"), {.row = row, .column = 0})
398 grid.
add(
Label(
"Visualize Graph Edges"), {.row = row, .column = 0})
410 if (reloadSnapshot.wasClicked())
412 owner.loadSnapshot();
414 if (visuLocations.hasValueChanged() or visuGraphEdges.hasValueChanged())
416 std::scoped_lock lock(owner.propertiesMutex);
417 owner.properties.locationGraph.visuLocations = visuLocations.getValue();
418 owner.properties.locationGraph.visuGraphEdges = visuGraphEdges.getValue();
435 std::scoped_lock lock(propertiesMutex);
436 pp = properties.locationGraph;
441 while (tasks.visuTask and not tasks.visuTask->isStopped())
446 std::scoped_lock lock(propertiesMutex);
447 pp = properties.locationGraph;
450 std::vector<viz::Layer> layers;
453 if (properties.locationGraph.visuRelativeLocations)
465 if (properties.locationGraph.visuRelativeLocations)
478 visu.drawCostmaps(layers, p.visuCostmaps, p.zOffsetCostmap);
482 visu.drawHumans(layers,
488 visu.drawRooms(layers, p.visuRooms);
492 metronome.waitForNextTick();
497 Component::loadSnapshot()
499 if (properties.snapshotToLoad.empty())
502 <<
"Not loading any predefined locations or graphs as the params was empty ...";
506 const std::vector<std::string> snapshotsToLoad =
509 for (
const auto& snapshotToLoad : snapshotsToLoad)
512 ARMARX_INFO <<
"Loading snapshots from snapshot '" << snapshotToLoad <<
"' in package '"
513 << properties.packageToLoad <<
"' ...";
516 properties.packageToLoad,
520 if (
auto graph = f.find(snapshotToLoad); graph.has_value())
522 const std::string graphId = graph->getID();
523 ARMARX_DEBUG <<
"Found graph " << graphId <<
" with path: " << graph->getFullPath();
531 std::filesystem::path locationsFilePath =
532 graph->getFullPath() /
"locations.json";
533 if (not std::filesystem::is_regular_file(locationsFilePath))
535 ARMARX_WARNING <<
"Found no locations file for graph '" << graphId <<
"'.";
549 std::ifstream ifs(locationsFilePath);
550 const std::string content((std::istreambuf_iterator<char>(ifs)),
551 (std::istreambuf_iterator<char>()));
554 nlohmann::json js = nlohmann::json::parse(content);
560 for (
const auto& location : locations)
563 if (location->type !=
567 <<
"Navigation memory received location '" + location->id.name +
568 "' which is not of type "
569 "'armarx::priorknowledge::util::LocationType:"
570 ":FRAMED_LOCATION' (e.g. you specified a "
571 "FRAMED_BOXED_LOCATION?). Only FramedLocations (i.e. "
572 "poses in 3D space) are navigatable. Ignoring this "
574 "but please check the location.json file.";
578 auto& framedLocation =
582 navigation::location::arondto::Location loc;
585 loc.framedPose.header.
frame = framedLocation.frame;
586 loc.framedPose.header.agent = framedLocation.agent;
587 loc.framedPose.pose = framedLocation.pose;
588 toAron(loc.names, framedLocation.names);
593 up.referencedTime = now;
595 up.arrivedTime = now;
597 up.instancesData = {loc.toAron()};
609 std::filesystem::path graphFilesPath = graph->getFullPath() /
"Graph";
611 if (not std::filesystem::is_directory(graphFilesPath))
613 ARMARX_INFO <<
"Found no `Graph/` folder for graph '" << graphId <<
"'.";
627 up.referencedTime = now;
628 up.arrivedTime = now;
631 up.instancesData = {g.toAron()};
633 ARMARX_DEBUG <<
"Sending empty graph `" << snapshotToLoad <<
"` to memory.";
638 ARMARX_DEBUG <<
"Loading graphs from " << graphFilesPath;
647 for (
const auto& graphFile : std::filesystem::directory_iterator(
650 if (std::filesystem::is_regular_file(graphFile.path()) and
654 const std::string graphName = graphFile.path().stem();
657 ARMARX_DEBUG <<
"Loading graph `" << graphName <<
" `from file `"
658 << graphFile.path() <<
"`.";
662 std::ifstream ifs(graphFile.path());
663 const std::string content((std::istreambuf_iterator<char>(ifs)),
664 (std::istreambuf_iterator<char>()));
666 const nlohmann::json j = nlohmann::json::parse(content);
668 const auto& jEdges = j.at(
"edges");
669 const auto& jVertices = j.at(
"vertices");
671 for (
const auto& jVertex : jVertices)
674 jVertex.at(
"locationID"));
676 armarx::navigation::core::arondto::Vertex
v;
677 v.vertexID = jVertex.at(
"vertexID");
678 toAron(
v.locationID, vertexLocationMemoryId);
680 v.locationID.instanceIndex = 0;
682 g.vertices.push_back(
v);
685 for (
const auto& jEdge : jEdges)
687 std::pair<std::int64_t, std::int64_t> edgeSourceTargetPair;
688 jEdge.get_to(edgeSourceTargetPair);
690 armarx::navigation::core::arondto::Edge e;
691 e.sourceVertexID = edgeSourceTargetPair.first;
692 e.targetVertexID = edgeSourceTargetPair.second;
693 g.edges.push_back(e);
698 up.referencedTime = now;
699 up.arrivedTime = now;
702 up.instancesData = {g.toAron()};
713 std::filesystem::path roomsFilePath = graph->getFullPath() /
"rooms.json";
714 if (not std::filesystem::is_regular_file(roomsFilePath))
716 ARMARX_INFO <<
"Found no rooms file for graph '" << graphId <<
"'.";
731 std::ifstream ifs(roomsFilePath);
732 const std::string content((std::istreambuf_iterator<char>(ifs)),
733 (std::istreambuf_iterator<char>()));
736 const nlohmann::json js = nlohmann::json::parse(content);
739 js.at(
"rooms").get<std::map<std::string, nlohmann::json>>();
740 ARMARX_INFO <<
"Found " << rooms.size() <<
" rooms.";
741 for (
const auto& [roomId, j] : rooms)
743 auto roomMemoryId = providerID;
746 const std::string roomMemoryIdStr = roomMemoryId.str();
748 if (j.find(
"polygon") == j.end())
751 <<
"' has no 'polygon' member. Skipping "
756 if (j.find(
"height") == j.end())
759 <<
"' has no 'height' member. "
760 "Skipping this entity.";
764 navigation::algorithms::arondto::Room room;
765 j.at(
"polygon").get_to(room.polygon);
766 j.at(
"height").get_to(room.height);
770 for (
auto& point : room.polygon)
778 up.referencedTime = now;
780 up.arrivedTime = now;
782 up.instancesData = {room.toAron()};
789 ARMARX_INFO <<
"Loaded NavigationMemory '" << snapshotToLoad <<
"' --> graph: '"
794 ARMARX_WARNING <<
"Could not load NavigationMemory '" << snapshotToLoad
795 <<
"'. Continue with empty memory.";
805 store(
const std::map<armem::MemoryID, core::Graph>& graphs,
806 const std::filesystem::path& baseDirectory)
808 ARMARX_INFO <<
"Creating export directory `" << baseDirectory <<
"`.";
809 std::filesystem::create_directories(baseDirectory);
811 for (
const auto& [memoryId, graph] : graphs)
813 const std::filesystem::path nestedSubDir =
814 std::filesystem::path(memoryId.providerSegmentName) / memoryId.coreSegmentName;
815 const std::filesystem::path dir = baseDirectory / nestedSubDir;
817 std::filesystem::create_directories(dir);
822 std::vector<std::pair<std::size_t, std::size_t>> outgoingEdges;
825 std::back_inserter(outgoingEdges),
827 { return std::make_pair(edge.m_source, edge.m_target); });
829 j[
"edges"] = outgoingEdges;
832 for (
const auto& vertex : graph.m_vertices)
836 fromAron(vertex.m_property.aron.locationID, locationId);
838 nlohmann::json jVertex;
840 jVertex[
"vertexID"] = vertex.m_property.aron.vertexID;
842 j[
"vertices"].push_back(jVertex);
846 const std::filesystem::path
filename = dir / (memoryId.entityName +
".json");
849 ofs << std::setw(4) << j;
856 store(
const std::map<armem::MemoryID, location::arondto::Location>& locations,
857 const std::filesystem::path& baseDirectory)
859 ARMARX_INFO <<
"Creating export directory `" << baseDirectory <<
"`.";
860 std::filesystem::create_directories(baseDirectory);
863 std::map<std::string, nlohmann::json> js;
865 for (
const auto& [memoryId, location] : locations)
867 auto& j = js[memoryId.providerSegmentName];
869 if (j.count(
"locations") == 0)
875 nlohmann::json framedPose;
877 framedPose[
"agent"] = location.framedPose.header.agent;
878 framedPose[
"frame"] = location.framedPose.header.frame;
881 std::vector<std::vector<float>> poseAsVec;
883 framedPose[
"pose"] = poseAsVec;
885 jLoc[
"framedPose"] = framedPose;
887 auto entityId = memoryId.getEntityID();
888 j[
"locations"][entityId.entityName] = jLoc;
892 for (
const auto& [providerId, j] : js)
894 const std::filesystem::path subDir = std::filesystem::path(providerId);
895 const std::filesystem::path dir = baseDirectory / subDir;
897 if (not std::filesystem::exists(dir))
899 std::filesystem::create_directories(dir);
902 const std::filesystem::path
filename = dir /
"locations.json";
905 ofs << std::setw(4) << j;
916 const Ice::Current& )
925 const std::map<armem::MemoryID, location::arondto::Location> locations =
926 [&locationCoreSegment]()
928 std::map<armem::MemoryID, location::arondto::Location> locations;
938 locations[entity.id()].fromAron(instance->data());
950 const auto graphs = [&graphCoreSegment]()
952 std::map<armem::MemoryID, core::Graph> graphs;
964 aron.fromAron(instance->data());
980 store(locations, baseDirectory);
989 Component::loadSpecialRooms()
995 const auto objectFinder = objClient.getObjectFinder();
996 const auto objectPoseMap = objClient.fetchObjectPosesAsMap();
998 for (
const auto& [providerName, objectPose] : objectPoseMap)
1000 const auto objectInfoOpt = objectFinder.findObject(objectPose.objectID);
1001 if (not objectInfoOpt)
1003 ARMARX_WARNING <<
"Could not find object with id '" << objectPose.objectID
1008 const auto& objectInfo = *objectInfoOpt;
1014 const auto articulatedModelPathOpt = objectInfo.getArticulatedModel();
1015 if (not articulatedModelPathOpt)
1018 <<
"' is not an articulated model.";
1022 const auto& articulatedModelPath = *articulatedModelPathOpt;
1023 if (not std::filesystem::is_regular_file(articulatedModelPath.absolutePath))
1026 <<
"' has no articulated model.";
1032 articulatedModelPath.absolutePath.string(), VirtualRobot::RobotIO::eStructure);
1034 <<
QUOTED(articulatedModelPath.absolutePath.string());
1037 articulatedObject->setJointValues(objectPose.objectJointValues);
1038 articulatedObject->setGlobalPose(objectPose.objectPoseGlobal);
1041 const auto affordances = articulatedObject->getAffordances();
1042 for (
const auto& affordanceLocation : affordances)
1044 for (
const auto affordance : affordanceLocation.affordances)
1051 for (
const std::shared_ptr<VirtualRobot::Primitive::Primitive>&
1052 primitive : affordance.primitiveRepresentation)
1054 if (primitive->type == VirtualRobot::Primitive::Box::TYPE)
1056 VirtualRobot::Primitive::Box* box =
1057 std::dynamic_pointer_cast<VirtualRobot::Primitive::Box>(
1063 const Eigen::Isometry3f& root_T_prim =
1064 affordanceLocation.pose.pose;
1065 const Eigen::Isometry3f global_T_prim =
1066 Eigen::Isometry3f{articulatedObject->getGlobalPose()} *
1069 const Eigen::Isometry3f prim_T_affordance{
1070 primitive->transform};
1071 const Eigen::Isometry3f global_T_affordance =
1072 global_T_prim * prim_T_affordance;
1074 const Eigen::Vector3f boxSize{
1075 box->width, box->height, box->depth};
1080 const Eigen::Vector3f corner1 = Eigen::Vector3f{
1081 boxSize.x() / 2, boxSize.y() / 2, -boxSize.z() / 2};
1082 const Eigen::Vector3f corner2 = Eigen::Vector3f{
1083 -boxSize.x() / 2, boxSize.y() / 2, -boxSize.z() / 2};
1084 const Eigen::Vector3f corner3 = Eigen::Vector3f{
1085 -boxSize.x() / 2, -boxSize.y() / 2, -boxSize.z() / 2};
1086 const Eigen::Vector3f corner4 = Eigen::Vector3f{
1087 boxSize.x() / 2, -boxSize.y() / 2, -boxSize.z() / 2};
1091 std::vector<Eigen::Vector3f> polygon;
1093 polygon.emplace_back(global_T_affordance * corner1);
1094 polygon.emplace_back(global_T_affordance * corner2);
1095 polygon.emplace_back(global_T_affordance * corner3);
1096 polygon.emplace_back(global_T_affordance * corner4);
1099 navigation::algorithms::arondto::Room room;
1100 room.name =
"inside";
1101 room.polygon = polygon;
1102 room.height = boxSize.z();
1109 objectPose.objectID.dataset() +
1110 "::" + objectPose.objectID.className();
1115 up.confidence = 1.0;
1116 up.referencedTime = now;
1118 up.arrivedTime = now;
1120 up.instancesData = {room.toAron()};
1135 const auto areas = objectInfo.file(
".json",
"_areas",
true);
1136 ARMARX_VERBOSE <<
"Checking for areas.json file at " << areas.absolutePath;
1137 if (std::filesystem::exists(areas.absolutePath))
1139 ARMARX_INFO <<
"Found areas.json file for object '" << objectPose.objectID
1143 std::ifstream ifs(areas.absolutePath);
1144 const auto json = nlohmann::json::parse(ifs);
1146 const std::map<std::string, nlohmann::json> jAreas = json.at(
"areas");
1147 ARMARX_INFO <<
"Found " << jAreas.size() <<
" areas.";
1149 for (
const auto& [areaName, jArea] : jAreas)
1151 const std::vector<Eigen::Vector2f> polygon =
1152 jArea.at(
"polygon").get<std::vector<Eigen::Vector2f>>();
1153 const float height = jArea.at(
"height").get<
float>();
1159 providerID.providerSegmentName =
1160 objectPose.objectID.dataset() +
"::" + objectPose.objectID.className();
1165 navigation::algorithms::arondto::Room room;
1166 room.name = objectPose.objectID.getClassID().withInstanceName(areaName).str();
1168 room.height = height;
1171 const Eigen::Isometry3f global_T_object{objectPose.objectPoseGlobal};
1172 for (
auto& point : room.polygon)
1175 point = global_T_object * point;
1189 up.confidence = 1.0;
1190 up.referencedTime = now;
1192 up.arrivedTime = now;
1193 up.entityID = providerID.withEntityName(areaName);
1194 up.instancesData = {room.toAron()};
1200 if (
c.updates.empty())
1206 ARMARX_INFO <<
"Sending " <<
c.updates.size() <<
" special rooms to memory";