diff --git a/source/RobotAPI/components/armem/server/ObjectMemory/ObjectMemory.cpp b/source/RobotAPI/components/armem/server/ObjectMemory/ObjectMemory.cpp index b6d997f6882daa1b9ee95d97fb4502ae181aa9ab..0c5d82c8da19676c0ab3b544ea381ed7ae5f8776 100644 --- a/source/RobotAPI/components/armem/server/ObjectMemory/ObjectMemory.cpp +++ b/source/RobotAPI/components/armem/server/ObjectMemory/ObjectMemory.cpp @@ -86,8 +86,6 @@ namespace armarx::armem::server::obj { workingMemory.name() = defaultMemoryName; - instance::SegmentAdapter::init(); - const auto initSegmentWithCatch = [&](const std::string & segmentName, const auto&& fn) { try @@ -108,11 +106,15 @@ namespace armarx::armem::server::obj } }; + // Class segment needs to be initialized before instance segment, + // as the instance segment may refer to and search through the class segment. initSegmentWithCatch("class", [&]() { classSegment.init(); }); + instance::SegmentAdapter::init(); + initSegmentWithCatch("articulated object class", [&]() { articulatedObjectClassSegment.init(); @@ -185,28 +187,34 @@ namespace armarx::armem::server::obj { using namespace armarx::RemoteGui::Client; - tab.instance.setup(*this); - tab.clazz.setup(classSegment); + tab.reset(new RemoteGuiTab); + + tab->instance.setup(*this); + tab->clazz.setup(classSegment); HBoxLayout segments = { - tab.instance.group, - tab.clazz.group + tab->instance.group, + tab->clazz.group }; VBoxLayout root = { segments, VSpacer() }; - RemoteGui_createTab(Component::getName(), root, &tab); + RemoteGui_createTab(Component::getName(), root, tab.get()); } + void ObjectMemory::RemoteGui_update() { - // Non-atomic variables need to be guarded by a mutex if accessed by multiple threads - tab.instance.update(*this); - tab.clazz.update(classSegment); + tab->instance.update(*this); + tab->clazz.update(classSegment); + + if (tab->clazz.data.rebuild) + { + createRemoteGuiTab(); + } } } - diff --git a/source/RobotAPI/components/armem/server/ObjectMemory/ObjectMemory.h b/source/RobotAPI/components/armem/server/ObjectMemory/ObjectMemory.h index 2dfd668d1e43df914ff7b2f02205e699ad2ea5e9..a513016a3da9f0376a092768e4a977974493ca32 100644 --- a/source/RobotAPI/components/armem/server/ObjectMemory/ObjectMemory.h +++ b/source/RobotAPI/components/armem/server/ObjectMemory/ObjectMemory.h @@ -122,7 +122,7 @@ namespace armarx::armem::server::obj instance::SegmentAdapter::RemoteGui instance; clazz::Segment::RemoteGui clazz; }; - RemoteGuiTab tab; + std::unique_ptr<RemoteGuiTab> tab; }; diff --git a/source/RobotAPI/libraries/ArmarXObjects/ObjectFinder.cpp b/source/RobotAPI/libraries/ArmarXObjects/ObjectFinder.cpp index 8e86d96dc398d707ab4e8629e4b971519db8dc65..2e026dd211cf6906d8b54b468ad6eebfff12141b 100644 --- a/source/RobotAPI/libraries/ArmarXObjects/ObjectFinder.cpp +++ b/source/RobotAPI/libraries/ArmarXObjects/ObjectFinder.cpp @@ -55,6 +55,12 @@ namespace armarx } + bool ObjectFinder::isDatasetDirValid(const path& path) const + { + return path.filename() != "Scenes" and std::filesystem::is_directory(path); + } + + std::optional<ObjectInfo> ObjectFinder::findObject(const std::string& dataset, const std::string& name) const { init(); @@ -67,8 +73,8 @@ namespace armarx return ObjectInfo(packageName, packageDataDir, dataset, name); } // Search for object in datasets. - const auto& datasets = getDatasets(); - for (const path& dataset : datasets) + const std::vector<std::string>& datasets = getDatasets(); + for (const std::string& dataset : datasets) { if (fs::is_directory(_rootDirAbs() / dataset / name)) { @@ -106,7 +112,7 @@ namespace armarx { // init(); // Done by called methods. std::vector<std::string> datasets; - for (const auto& dir : getDatasetDirectories()) + for (const path& dir : getDatasetDirectories()) { datasets.push_back(dir.filename()); } @@ -123,9 +129,9 @@ namespace armarx const bool local = false; std::vector<path> dirs = simox::fs::list_directory(_rootDirAbs(), local); std::vector<path> datasetDirs; - for (const auto& p : dirs) + for (const path& p : dirs) { - if (std::filesystem::is_directory(p)) + if (isDatasetDirValid(p)) { datasetDirs.push_back(p); } @@ -144,7 +150,7 @@ namespace armarx std::vector<ObjectInfo> objects; for (const path& datasetDir : simox::fs::list_directory(_rootDirAbs(), local)) { - if (fs::is_directory(_rootDirAbs() / datasetDir)) + if (isDatasetDirValid(_rootDirAbs() / datasetDir)) { std::vector<ObjectInfo> dataset = findAllObjectsOfDataset(datasetDir, checkPaths); for (const auto& o : dataset) @@ -169,7 +175,7 @@ namespace armarx std::vector<armem::articulated_object::ArticulatedObjectDescription> objects; for (const path& datasetDir : simox::fs::list_directory(_rootDirAbs(), local)) { - if (fs::is_directory(_rootDirAbs() / datasetDir)) + if (isDatasetDirValid(_rootDirAbs() / datasetDir)) { const auto dataset = findAllArticulatedObjectsOfDataset(datasetDir, checkPaths); objects.insert(objects.end(), dataset.begin(), dataset.end()); @@ -221,7 +227,9 @@ namespace armarx return objects; } - std::unordered_map<std::string, std::vector<armem::articulated_object::ArticulatedObjectDescription>> ObjectFinder::findAllArticulatedObjectsByDataset(bool checkPaths) const + + std::unordered_map<std::string, std::vector<armem::articulated_object::ArticulatedObjectDescription>> + ObjectFinder::findAllArticulatedObjectsByDataset(bool checkPaths) const { init(); if (!_ready()) @@ -234,7 +242,7 @@ namespace armarx std::unordered_map<std::string, std::vector<armem::articulated_object::ArticulatedObjectDescription>> datasets; for (const path& datasetDir : simox::fs::list_directory(_rootDirAbs(), local)) { - if (fs::is_directory(_rootDirAbs() / datasetDir)) + if (isDatasetDirValid(_rootDirAbs() / datasetDir)) { const auto dataset = findAllArticulatedObjectsOfDataset(datasetDir, checkPaths); datasets[datasetDir] = dataset; @@ -244,7 +252,8 @@ namespace armarx } - std::vector<armem::articulated_object::ArticulatedObjectDescription> ObjectFinder::findAllArticulatedObjectsOfDataset(const std::string& dataset, bool checkPaths) const + std::vector<armem::articulated_object::ArticulatedObjectDescription> + ObjectFinder::findAllArticulatedObjectsOfDataset(const std::string& dataset, bool checkPaths) const { init(); if (!_ready()) @@ -252,7 +261,7 @@ namespace armarx return {}; } path datasetDir = _rootDirAbs() / dataset; - if (!fs::is_directory(datasetDir)) + if (!isDatasetDirValid(datasetDir)) { ARMARX_WARNING << "Expected dataset directory for dataset '" << dataset << "': \n" << datasetDir; diff --git a/source/RobotAPI/libraries/ArmarXObjects/ObjectFinder.h b/source/RobotAPI/libraries/ArmarXObjects/ObjectFinder.h index 2b342f3ac1151d0589bbc4b0212c3aed2fde798d..0bef0667120ee99e7d65f575f1c9b61b446ffe6f 100644 --- a/source/RobotAPI/libraries/ArmarXObjects/ObjectFinder.h +++ b/source/RobotAPI/libraries/ArmarXObjects/ObjectFinder.h @@ -89,14 +89,18 @@ namespace armarx private: + void init() const; + bool isDatasetDirValid(const std::filesystem::path& path) const; path _rootDirAbs() const; path _rootDirRel() const; bool _ready() const; + private: + /// Name of package containing the object models (ArmarXObjects by default). mutable std::string packageName; @@ -105,5 +109,6 @@ namespace armarx * Empty if package could not be found. */ mutable path packageDataDir; + }; } diff --git a/source/RobotAPI/libraries/ArmarXObjects/ObjectID.cpp b/source/RobotAPI/libraries/ArmarXObjects/ObjectID.cpp index adb8260199706797be7b36b65e4fd504ad2e8a63..f2d76a501ecf8e1f53dcf9bf80a2e8a0f66d7536 100644 --- a/source/RobotAPI/libraries/ArmarXObjects/ObjectID.cpp +++ b/source/RobotAPI/libraries/ArmarXObjects/ObjectID.cpp @@ -57,6 +57,11 @@ namespace armarx return _className == rhs._className && _dataset == rhs._dataset; } + ObjectID ObjectID::withInstanceName(const std::string& instanceName) const + { + return ObjectID(_dataset, _className, instanceName); + } + bool ObjectID::operator==(const ObjectID& rhs) const { return _className == rhs._className diff --git a/source/RobotAPI/libraries/ArmarXObjects/ObjectID.h b/source/RobotAPI/libraries/ArmarXObjects/ObjectID.h index 73e2c6ca5f8d272fd90257fd5aedfd839266174d..389b203a6ecc67f2f6cd074ce103c5b52687a2be 100644 --- a/source/RobotAPI/libraries/ArmarXObjects/ObjectID.h +++ b/source/RobotAPI/libraries/ArmarXObjects/ObjectID.h @@ -43,6 +43,8 @@ namespace armarx /// Indicates whether dataset and class name are equal. bool equalClass(const ObjectID& rhs) const; + ObjectID withInstanceName(const std::string& instanceName) const; + /// Indicates whether dataset, class name and instance name are equal. bool operator==(const ObjectID& rhs) const; inline bool operator!=(const ObjectID& rhs) const diff --git a/source/RobotAPI/libraries/armem/CMakeLists.txt b/source/RobotAPI/libraries/armem/CMakeLists.txt index c4ad28ab1f6880f59adb4ca7eda5e4e8a8a65007..9ebc8f2abc95547925b756254e0725d3c1dc2ce0 100644 --- a/source/RobotAPI/libraries/armem/CMakeLists.txt +++ b/source/RobotAPI/libraries/armem/CMakeLists.txt @@ -18,6 +18,7 @@ set(LIB_FILES core/Time.cpp core/ice_conversions.cpp core/aron_conversions.cpp + core/json_conversions.cpp core/base/detail/MemoryItem.cpp core/base/detail/MaxHistorySize.cpp @@ -40,8 +41,9 @@ set(LIB_FILES core/workingmemory/EntitySnapshot.cpp core/workingmemory/Memory.cpp core/workingmemory/ProviderSegment.cpp - core/workingmemory/Visitor.cpp core/workingmemory/ice_conversions.cpp + core/workingmemory/visitor/Visitor.cpp + core/workingmemory/visitor/FunctionalVisitor.cpp core/longtermmemory/CoreSegment.cpp core/longtermmemory/Entity.cpp @@ -111,6 +113,7 @@ set(LIB_HEADERS core/SuccessHeader.h core/Time.h core/aron_conversions.h + core/json_conversions.h core/ice_conversions.h core/ice_conversions_templates.h @@ -137,8 +140,10 @@ set(LIB_HEADERS core/workingmemory/EntitySnapshot.h core/workingmemory/Memory.h core/workingmemory/ProviderSegment.h - core/workingmemory/Visitor.h core/workingmemory/ice_conversions.h + core/workingmemory/visitor.h + core/workingmemory/visitor/Visitor.h + core/workingmemory/visitor/FunctionalVisitor.h core/longtermmemory/CoreSegment.h core/longtermmemory/Entity.h diff --git a/source/RobotAPI/libraries/armem/core/json_conversions.cpp b/source/RobotAPI/libraries/armem/core/json_conversions.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e4da9d89b5e04351e5e528132406a962470364e3 --- /dev/null +++ b/source/RobotAPI/libraries/armem/core/json_conversions.cpp @@ -0,0 +1,26 @@ +#include "json_conversions.h" + +#include <RobotAPI/libraries/armem/core/MemoryID.h> + + +void armarx::armem::to_json(nlohmann::json& j, const MemoryID& bo) +{ + j["memoryName"] = bo.memoryName; + j["coreSegmentName"] = bo.coreSegmentName; + j["providerSegmentName"] = bo.providerSegmentName; + j["entityName"] = bo.entityName; + j["timestamp_usec"] = bo.timestamp.toMicroSeconds(); + j["timestamp_datetime"] = toDateTimeMilliSeconds(bo.timestamp); + j["instanceIndex"] = bo.instanceIndex; +} + +void armarx::armem::from_json(const nlohmann::json& j, MemoryID& bo) +{ + j.at("memoryName").get_to(bo.memoryName); + j.at("coreSegmentName").get_to(bo.coreSegmentName); + j.at("providerSegmentName").get_to(bo.providerSegmentName); + j.at("entityName").get_to(bo.entityName); + bo.timestamp = Time::microSeconds(j.at("timestamp_usec").get<int64_t>()); + // j.at("timestamp_datetime").get_to(toDateTimeMilliSeconds(bo.timestamp)); + j.at("instanceIndex").get_to(bo.instanceIndex); +} diff --git a/source/RobotAPI/libraries/armem/core/json_conversions.h b/source/RobotAPI/libraries/armem/core/json_conversions.h new file mode 100644 index 0000000000000000000000000000000000000000..86e508c228fe57063216c2f1c6fa7710066992bc --- /dev/null +++ b/source/RobotAPI/libraries/armem/core/json_conversions.h @@ -0,0 +1,12 @@ +#pragma once + +#include <SimoxUtility/json/json.hpp> + + +namespace armarx::armem +{ + class MemoryID; + + void to_json(nlohmann::json& j, const MemoryID& bo); + void from_json(const nlohmann::json& j, MemoryID& bo); +} diff --git a/source/RobotAPI/libraries/armem/core/workingmemory/visitor.h b/source/RobotAPI/libraries/armem/core/workingmemory/visitor.h new file mode 100644 index 0000000000000000000000000000000000000000..815ee1b34908dc5916e7d909e709bc735409f63c --- /dev/null +++ b/source/RobotAPI/libraries/armem/core/workingmemory/visitor.h @@ -0,0 +1,4 @@ +#pragma once + +#include "visitor/FunctionalVisitor.h" +#include "visitor/Visitor.h" diff --git a/source/RobotAPI/libraries/armem/core/workingmemory/visitor/FunctionalVisitor.cpp b/source/RobotAPI/libraries/armem/core/workingmemory/visitor/FunctionalVisitor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..53016fc6c83d9ef6e24a2e75942a12bced7d0eaa --- /dev/null +++ b/source/RobotAPI/libraries/armem/core/workingmemory/visitor/FunctionalVisitor.cpp @@ -0,0 +1,23 @@ +#include "FunctionalVisitor.h" + +#include <ArmarXCore/core/exceptions/local/ExpressionException.h> + +#include <RobotAPI/libraries/armem/core/workingmemory/Memory.h> +#include <RobotAPI/libraries/armem/core/error.h> + + +namespace armarx::armem::wm +{ + + FunctionalVisitor::FunctionalVisitor() + { + } + + + FunctionalVisitor::~FunctionalVisitor() + { + } + + + +} diff --git a/source/RobotAPI/libraries/armem/core/workingmemory/visitor/FunctionalVisitor.h b/source/RobotAPI/libraries/armem/core/workingmemory/visitor/FunctionalVisitor.h new file mode 100644 index 0000000000000000000000000000000000000000..1c1b46e138c7eb2d713ba15b76ba77a2588ea0ce --- /dev/null +++ b/source/RobotAPI/libraries/armem/core/workingmemory/visitor/FunctionalVisitor.h @@ -0,0 +1,101 @@ +#pragma once + +#include <functional> + +#include "Visitor.h" + + +namespace armarx::armem::wm +{ + + /** + * @brief A `Visitor` which can be parametrized by `std::function` + * instead of inheriting and overriding. + */ + class FunctionalVisitor : public Visitor + { + public: + + FunctionalVisitor(); + virtual ~FunctionalVisitor() override; + + + bool visitEnter(Memory& memory) override + { + return memoryFn ? memoryFn(memory) : Visitor::visitEnter(memory); + } + bool visitEnter(CoreSegment& coreSegment) override + { + return coreSegmentFn ? coreSegmentFn(coreSegment) : Visitor::visitEnter(coreSegment); + } + bool visitEnter(ProviderSegment& providerSegment) override + { + return providerSegmentFn ? providerSegmentFn(providerSegment) : Visitor::visitEnter(providerSegment); + } + bool visitEnter(Entity& entity) override + { + return entityFn ? entityFn(entity) : Visitor::visitEnter(entity); + } + bool visitEnter(EntitySnapshot& snapshot) override + { + return snapshotFn ? snapshotFn(snapshot) : Visitor::visitEnter(snapshot); + } + + bool visit(EntityInstance& instance) override + { + return instanceFn ? instanceFn(instance) : Visitor::visit(instance); + } + + + + // Const versions + + + bool visitEnter(const Memory& memory) override + { + return memoryFn ? memoryConstFn(memory) : Visitor::visitEnter(memory); + } + bool visitEnter(const CoreSegment& coreSegment) override + { + return coreSegmentFn ? coreSegmentConstFn(coreSegment) : Visitor::visitEnter(coreSegment); + } + bool visitEnter(const ProviderSegment& providerSegment) override + { + return providerSegmentFn ? providerSegmentConstFn(providerSegment) : Visitor::visitEnter(providerSegment); + } + bool visitEnter(const Entity& entity) override + { + return entityFn ? entityConstFn(entity) : Visitor::visitEnter(entity); + } + bool visitEnter(const EntitySnapshot& snapshot) override + { + return memoryFn ? snapshotConstFn(snapshot) : Visitor::visitEnter(snapshot); + } + + bool visit(const EntityInstance& instance) override + { + return instanceFn ? instanceConstFn(instance) : Visitor::visit(instance); + } + + + std::function<bool(Memory& memory)> memoryFn; + std::function<bool(const Memory& memory)> memoryConstFn; + + std::function<bool(CoreSegment& coreSegment)> coreSegmentFn; + std::function<bool(const CoreSegment& coreSegment)> coreSegmentConstFn; + + std::function<bool(ProviderSegment& providerSegment)> providerSegmentFn; + std::function<bool(const ProviderSegment& providerSegment)> providerSegmentConstFn; + + std::function<bool(Entity& entity)> entityFn; + std::function<bool(const Entity& entity)> entityConstFn; + + std::function<bool(EntitySnapshot& snapshot)> snapshotFn; + std::function<bool(const EntitySnapshot& snapshot)> snapshotConstFn; + + std::function<bool(EntityInstance& instance)> instanceFn; + std::function<bool(const EntityInstance& instance)> instanceConstFn; + + }; + +} diff --git a/source/RobotAPI/libraries/armem/core/workingmemory/Visitor.cpp b/source/RobotAPI/libraries/armem/core/workingmemory/visitor/Visitor.cpp similarity index 100% rename from source/RobotAPI/libraries/armem/core/workingmemory/Visitor.cpp rename to source/RobotAPI/libraries/armem/core/workingmemory/visitor/Visitor.cpp diff --git a/source/RobotAPI/libraries/armem/core/workingmemory/Visitor.h b/source/RobotAPI/libraries/armem/core/workingmemory/visitor/Visitor.h similarity index 98% rename from source/RobotAPI/libraries/armem/core/workingmemory/Visitor.h rename to source/RobotAPI/libraries/armem/core/workingmemory/visitor/Visitor.h index c0a3854a242c030113eeb46409c172563660294a..fa789fcf0b6876ec5d9fa0ff1a3944b4e3bf3fd3 100644 --- a/source/RobotAPI/libraries/armem/core/workingmemory/Visitor.h +++ b/source/RobotAPI/libraries/armem/core/workingmemory/visitor/Visitor.h @@ -12,7 +12,7 @@ namespace armarx::armem::wm /** - * @brief A visitor for the hierarchical Memory data structure. + * @brief A visitor for the hierarchical memory data structure. */ class Visitor { diff --git a/source/RobotAPI/libraries/armem_objects/CMakeLists.txt b/source/RobotAPI/libraries/armem_objects/CMakeLists.txt index 8c0f625f022e3efeb7cf7763841a25e6469b6ac8..51296814ff03036d197a96683b15827ef9af5fe5 100644 --- a/source/RobotAPI/libraries/armem_objects/CMakeLists.txt +++ b/source/RobotAPI/libraries/armem_objects/CMakeLists.txt @@ -20,6 +20,8 @@ armarx_add_library( aron_conversions.h aron_forward_declarations.h + SceneSnapshot.h + server/class/FloorVis.h server/class/Segment.h @@ -46,6 +48,8 @@ armarx_add_library( SOURCES aron_conversions.cpp + SceneSnapshot.cpp + server/class/FloorVis.cpp server/class/Segment.cpp diff --git a/source/RobotAPI/libraries/armem_objects/SceneSnapshot.cpp b/source/RobotAPI/libraries/armem_objects/SceneSnapshot.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d8ae0a10b97825f924d7e1605dc4687dcce9bfee --- /dev/null +++ b/source/RobotAPI/libraries/armem_objects/SceneSnapshot.cpp @@ -0,0 +1,53 @@ +#include "SceneSnapshot.h" + +#include <SimoxUtility/json.h> + +#include <RobotAPI/libraries/ArmarXObjects/ObjectID.h> + +// #include <RobotAPI/libraries/armem/core/json_conversions.h> + + +namespace armarx::armem::obj +{ + + ObjectID SceneSnapshot::Object::getClassID() const + { + return ObjectID(className); + } + +} + + +void armarx::armem::obj::to_json(nlohmann::json& j, const SceneSnapshot::Object& rhs) +{ + // j["instanceID"] = rhs.instanceID; + j["class"] = rhs.className; + j["collection"] = rhs.collection; + j["position"] = rhs.position; + j["orientation"] = rhs.orientation; +} + + +void armarx::armem::obj::from_json(const nlohmann::json& j, SceneSnapshot::Object& rhs) +{ + // j.at("instanceID").get_to(rhs.instanceID); + j.at("class").get_to(rhs.className); + j.at("collection").get_to(rhs.collection); + j.at("position").get_to(rhs.position); + j.at("orientation").get_to(rhs.orientation); +} + + + +void armarx::armem::obj::to_json(nlohmann::json& j, const SceneSnapshot& rhs) +{ + j["objects"] = rhs.objects; +} + + +void armarx::armem::obj::from_json(const nlohmann::json& j, SceneSnapshot& rhs) +{ + j.at("objects").get_to(rhs.objects); +} + + diff --git a/source/RobotAPI/libraries/armem_objects/SceneSnapshot.h b/source/RobotAPI/libraries/armem_objects/SceneSnapshot.h new file mode 100644 index 0000000000000000000000000000000000000000..2baa2cd3c323794aa4112bbc5df8c3353073dc61 --- /dev/null +++ b/source/RobotAPI/libraries/armem_objects/SceneSnapshot.h @@ -0,0 +1,57 @@ +/* + * This file is part of ArmarX. + * + * ArmarX is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * ArmarX is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * @package RobotAPI::ArmarXObjects::ObjectMemory + * @author Rainer Kartmann ( rainer dot kartmann at kit dot edu ) + * @date 2021 + * @copyright http://www.gnu.org/licenses/gpl-2.0.txt + * GNU General Public License + */ +#pragma once + +#include <SimoxUtility/json/json.hpp> + +#include <Eigen/Geometry> + + +namespace armarx +{ + class ObjectID; +} +namespace armarx::armem::obj +{ + + struct SceneSnapshot + { + struct Object + { + std::string className; + std::string collection; + + Eigen::Vector3f position = Eigen::Vector3f::Zero(); + Eigen::Quaternionf orientation = Eigen::Quaternionf::Identity(); + + ObjectID getClassID() const; + }; + std::vector<Object> objects; + }; + + void to_json(nlohmann::json& j, const SceneSnapshot::Object& rhs); + void from_json(const nlohmann::json& j, SceneSnapshot::Object& rhs); + + void to_json(nlohmann::json& j, const SceneSnapshot& rhs); + void from_json(const nlohmann::json& j, SceneSnapshot& rhs); + +} diff --git a/source/RobotAPI/libraries/armem_objects/server/articulated_object_class/Segment.cpp b/source/RobotAPI/libraries/armem_objects/server/articulated_object_class/Segment.cpp index 422b8e6be1fa3b50fe0ffc154ce2612528c3a578..aa4afc7b071fb30d36640fef9fd498b12b25f08f 100644 --- a/source/RobotAPI/libraries/armem_objects/server/articulated_object_class/Segment.cpp +++ b/source/RobotAPI/libraries/armem_objects/server/articulated_object_class/Segment.cpp @@ -9,7 +9,7 @@ #include "RobotAPI/libraries/aron/common/aron_conversions.h" #include <RobotAPI/libraries/armem/core/aron_conversions.h> -#include <RobotAPI/libraries/armem/core/workingmemory/Visitor.h> +#include <RobotAPI/libraries/armem/core/workingmemory/visitor.h> #include "RobotAPI/libraries/armem/core/MemoryID.h" #include <RobotAPI/libraries/armem/client/Writer.h> #include <RobotAPI/libraries/armem/client/query/Builder.h> diff --git a/source/RobotAPI/libraries/armem_objects/server/attachments/Segment.cpp b/source/RobotAPI/libraries/armem_objects/server/attachments/Segment.cpp index 338bc804b12c0569542e57ed283741e4145893a5..d1daccd0b3db38814b94a2e7624b53aede655204 100644 --- a/source/RobotAPI/libraries/armem_objects/server/attachments/Segment.cpp +++ b/source/RobotAPI/libraries/armem_objects/server/attachments/Segment.cpp @@ -9,7 +9,7 @@ #include "RobotAPI/libraries/aron/common/aron_conversions.h" #include <RobotAPI/libraries/armem/core/aron_conversions.h> -#include <RobotAPI/libraries/armem/core/workingmemory/Visitor.h> +#include <RobotAPI/libraries/armem/core/workingmemory/visitor.h> #include "RobotAPI/libraries/armem/core/MemoryID.h" #include <RobotAPI/libraries/armem/client/Writer.h> #include <RobotAPI/libraries/armem/client/query/Builder.h> diff --git a/source/RobotAPI/libraries/armem_objects/server/class/Segment.cpp b/source/RobotAPI/libraries/armem_objects/server/class/Segment.cpp index 93989e18d6c5cd39d0f878cd2caea652fadb41b3..323a4df0d37cbf5d8177e763dddb9b58091bf4de 100644 --- a/source/RobotAPI/libraries/armem_objects/server/class/Segment.cpp +++ b/source/RobotAPI/libraries/armem_objects/server/class/Segment.cpp @@ -79,7 +79,10 @@ namespace armarx::armem::server::obj::clazz std::vector<ObjectInfo> infos = objectFinder.findAllObjects(checkPaths); const MemoryID providerID = coreSegment->id().withProviderSegmentName(objectFinder.getPackageName()); - coreSegment->addProviderSegment(providerID.providerSegmentName); + if (not coreSegment->hasProviderSegment(providerID.providerSegmentName)) + { + coreSegment->addProviderSegment(providerID.providerSegmentName); + } ARMARX_INFO << "Loading up to " << infos.size() << " object classes from '" << objectFinder.getPackageName() << "' ..."; @@ -225,12 +228,16 @@ namespace armarx::armem::server::obj::clazz { using namespace armarx::RemoteGui::Client; + reloadButton.setLabel("Reload"); + maxHistorySize.setValue(std::max(1, int(segment.p.maxHistorySize))); maxHistorySize.setRange(1, 1e6); infiniteHistory.setValue(segment.p.maxHistorySize == -1); GridLayout grid; int row = 0; + grid.add(reloadButton, {row, 0}, {1, 2}); + row++; grid.add(Label("Max History Size"), {row, 0}).add(maxHistorySize, {row, 1}); row++; grid.add(Label("Infinite History Size"), {row, 0}).add(infiniteHistory, {row, 1}); @@ -243,6 +250,12 @@ namespace armarx::armem::server::obj::clazz void Segment::RemoteGui::Data::update(Segment& segment) { + if (reloadButton.wasClicked()) + { + std::scoped_lock lock(segment.memoryMutex); + segment.loadByObjectFinder(); + rebuild = true; + } if (infiniteHistory.hasValueChanged() || maxHistorySize.hasValueChanged()) { std::scoped_lock lock(segment.memoryMutex); diff --git a/source/RobotAPI/libraries/armem_objects/server/class/Segment.h b/source/RobotAPI/libraries/armem_objects/server/class/Segment.h index 7356e6a1d9e490840f7c19b5e41e27506ddf2ecf..88eaedbefb6529b873dfe6033e6a2857672c0586 100644 --- a/source/RobotAPI/libraries/armem_objects/server/class/Segment.h +++ b/source/RobotAPI/libraries/armem_objects/server/class/Segment.h @@ -76,11 +76,14 @@ namespace armarx::armem::server::obj::clazz { armarx::RemoteGui::Client::GroupBox group; + armarx::RemoteGui::Client::Button reloadButton; armarx::RemoteGui::Client::IntSpinBox maxHistorySize; armarx::RemoteGui::Client::CheckBox infiniteHistory; void setup(const Segment& segment); void update(Segment& segment); + + bool rebuild = false; }; Data data; diff --git a/source/RobotAPI/libraries/armem_objects/server/instance/Segment.cpp b/source/RobotAPI/libraries/armem_objects/server/instance/Segment.cpp index aa2125dada86d895e7fe063cbdc20501623576b7..eb81a73dc3fa4b949dbdf880a9023b51d02d7320 100644 --- a/source/RobotAPI/libraries/armem_objects/server/instance/Segment.cpp +++ b/source/RobotAPI/libraries/armem_objects/server/instance/Segment.cpp @@ -1,12 +1,17 @@ #include "Segment.h" #include <RobotAPI/libraries/armem_objects/aron_conversions.h> +#include <RobotAPI/libraries/armem_objects/SceneSnapshot.h> #include <RobotAPI/libraries/armem/core/aron_conversions.h> -#include <RobotAPI/libraries/armem/core/workingmemory/Visitor.h> +#include <RobotAPI/libraries/armem/core/error.h> +#include <RobotAPI/libraries/armem/core/workingmemory/visitor.h> #include <RobotAPI/libraries/armem/client/Writer.h> #include <RobotAPI/libraries/armem/client/query/Builder.h> #include <RobotAPI/libraries/armem/client/query/query_fns.h> +#include <RobotAPI/libraries/armem/util/util.h> + +#include <RobotAPI/libraries/aron/common/aron_conversions.h> #include <RobotAPI/libraries/ArmarXObjects/ObjectFinder.h> #include <RobotAPI/libraries/ArmarXObjects/aron_conversions.h> @@ -17,10 +22,17 @@ #include <RobotAPI/libraries/core/remoterobot/RemoteRobot.h> #include <ArmarXCore/core/time/TimeUtil.h> +#include <ArmarXCore/core/system/cmake/CMakePackageFinder.h> + +#include <SimoxUtility/math/pose/pose.h> +#include <SimoxUtility/json.h> + +#include <Eigen/Geometry> #include <sstream> + namespace armarx::armem::server::obj::instance { @@ -37,6 +49,7 @@ namespace armarx::armem::server::obj::instance { try { + objectInfo->setLogError(false); // Don't log missing files return objectInfo->loadOOBB(); } catch (const std::ios_base::failure& e) @@ -59,6 +72,7 @@ namespace armarx::armem::server::obj::instance }); } + void Segment::defineProperties(armarx::PropertyDefinitionsPtr defs, const std::string& prefix) { defs->optional(p.coreSegmentName, prefix + "CoreSegmentName", "Name of the object instance core segment."); @@ -67,15 +81,30 @@ namespace armarx::armem::server::obj::instance "If true, no new snapshots are stored while an object is attached to a robot node.\n" "If false, new snapshots are stored, but the attachment is kept in the new snapshots."); + defs->optional(p.sceneSnapshotsPackage, prefix + "scene.Package", + "ArmarX package containing the scene snapshots.\n" + "Scene snapshots are expected to be located in Package/data/Package/Scenes/*.json."); + defs->optional(p.sceneSnapshotToLoad, prefix + "scene.SnapshotToLoad", + "Scene snapshot to load on startup (e.g. 'Scene_2021-06-24_20-20-03').\n" + "You can also specify paths relative to 'Package/Scenes/'."); + decay.defineProperties(defs, prefix + "decay."); } + void Segment::init() { ARMARX_CHECK_NOT_NULL(iceMemory.workingMemory); coreSegment = &iceMemory.workingMemory->addCoreSegment(p.coreSegmentName, arondto::ObjectInstance::toInitialAronType()); coreSegment->setMaxHistorySize(p.maxHistorySize); + + + if (not p.sceneSnapshotToLoad.empty()) + { + bool lockMemory = false; + commitSceneSnapshotFromFilename(p.sceneSnapshotToLoad, lockMemory); + } } @@ -156,42 +185,45 @@ namespace armarx::armem::server::obj::instance } } - commitObjectPoses(providerName, newObjectPoses); + commitObjectPoses(newObjectPoses, providerName); return stats; } - void Segment::commitObjectPoses(const std::string& providerName, const ObjectPoseSeq& objectPoses) + + void Segment::commitObjectPoses(const ObjectPoseSeq& objectPoses, const std::string& providerName) { ARMARX_CHECK_NOT_NULL(coreSegment); + Time now = TimeUtil::GetTime(); - // Update memory. - const MemoryID providerSegmentID = coreSegment->id().withProviderSegmentName(providerName); - if (!coreSegment->hasProviderSegment(providerSegmentID.providerSegmentName)) - { - coreSegment->addProviderSegment(providerSegmentID.providerSegmentName); - } + const MemoryID coreSegmentID = coreSegment->id(); Commit commit; for (const objpose::ObjectPose& pose : objectPoses) { EntityUpdate& update = commit.updates.emplace_back(); + + const MemoryID providerID = coreSegmentID.withProviderSegmentName( + providerName.empty() ? pose.providerName : providerName); + + update.entityID = providerID.withEntityName(pose.objectID.str()); + update.timeArrived = now; + update.timeCreated = pose.timestamp; + update.confidence = pose.confidence; + + arondto::ObjectInstance dto; + toAron(dto, pose); + // Search for object class. + if (auto instance = findClassInstance(pose.objectID)) { - update.entityID = providerSegmentID.withEntityName(pose.objectID.str()); - update.timeArrived = TimeUtil::GetTime(); - update.timeCreated = pose.timestamp; - update.confidence = pose.confidence; - - arondto::ObjectInstance dto; - toAron(dto, pose); - // Search for object class. - if (auto instance = findClassInstance(pose.objectID)) - { - toAron(dto.classID, instance->id()); - } - update.instancesData.push_back(dto.toAron()); + toAron(dto.classID, instance->id()); } - + else + { + toAron(dto.classID, MemoryID()); + } + toAron(dto.sourceID, MemoryID()); + update.instancesData.push_back(dto.toAron()); } iceMemory.commit(commit); } @@ -203,12 +235,14 @@ namespace armarx::armem::server::obj::instance return *coreSegment; } + const wm::CoreSegment& Segment::getCoreSegment() const { ARMARX_CHECK_NOT_NULL(coreSegment); return *coreSegment; } + objpose::ObjectPoseSeq Segment::getObjectPoses(IceUtil::Time now) { ObjectPoseSeq objectPoses = getLatestObjectPoses(); @@ -217,6 +251,7 @@ namespace armarx::armem::server::obj::instance } + objpose::ObjectPoseSeq Segment::getObjectPosesByProvider( const std::string& providerName, IceUtil::Time now) @@ -227,6 +262,7 @@ namespace armarx::armem::server::obj::instance return filterObjectPoses(objectPoses); } + armem::wm::Entity* Segment::findObjectEntity(const ObjectID& objectID, const std::string& providerName) { ARMARX_CHECK_NOT_NULL(coreSegment); @@ -329,12 +365,14 @@ namespace armarx::armem::server::obj::instance objectPose.updateAttached(agent); } + objpose::ObjectPoseSeq Segment::getLatestObjectPoses() const { ARMARX_CHECK_NOT_NULL(coreSegment); return getLatestObjectPoses(*coreSegment); } + objpose::ObjectPoseSeq Segment::getLatestObjectPoses(const armem::wm::CoreSegment& coreSeg) { ObjectPoseSeq result; @@ -342,6 +380,7 @@ namespace armarx::armem::server::obj::instance return result; } + objpose::ObjectPoseSeq Segment::getLatestObjectPoses(const armem::wm::ProviderSegment& provSeg) { ObjectPoseSeq result; @@ -349,6 +388,7 @@ namespace armarx::armem::server::obj::instance return result; } + objpose::ObjectPose Segment::getLatestObjectPose(const armem::wm::Entity& entity) { ObjectPose result; @@ -356,6 +396,7 @@ namespace armarx::armem::server::obj::instance return result; } + void Segment::getLatestObjectPoses(const armem::wm::CoreSegment& coreSeg, ObjectPoseSeq& out) { for (const auto& [_, provSegment] : coreSeg) @@ -364,6 +405,7 @@ namespace armarx::armem::server::obj::instance } } + void Segment::getLatestObjectPoses(const armem::wm::ProviderSegment& provSegment, ObjectPoseSeq& out) { for (const auto& [_, entity] : provSegment) @@ -376,6 +418,7 @@ namespace armarx::armem::server::obj::instance } } + void Segment::getLatestObjectPose(const armem::wm::Entity& entity, ObjectPose& out) { for (const armem::wm::EntityInstance& instance : entity.getLatestSnapshot()) @@ -402,11 +445,13 @@ namespace armarx::armem::server::obj::instance return data; } + std::optional<simox::OrientedBoxf> Segment::getObjectOOBB(const ObjectID& id) { return oobbCache.get(id); } + objpose::ProviderInfo Segment::getProviderInfo(const std::string& providerName) { try @@ -427,7 +472,6 @@ namespace armarx::armem::server::obj::instance } - objpose::AttachObjectToRobotNodeOutput Segment::attachObjectToRobotNode(const objpose::AttachObjectToRobotNodeInput& input) { @@ -517,6 +561,7 @@ namespace armarx::armem::server::obj::instance return output; } + objpose::DetachObjectFromRobotNodeOutput Segment::detachObjectFromRobotNode( const objpose::DetachObjectFromRobotNodeInput& input) { @@ -581,6 +626,7 @@ namespace armarx::armem::server::obj::instance virtual bool visitEnter(armem::wm::Entity& entity) override; }; + bool DetachVisitor::visitEnter(armem::wm::Entity& entity) { const arondto::ObjectInstance data = owner.getLatestInstanceData(entity); @@ -590,7 +636,6 @@ namespace armarx::armem::server::obj::instance // Store non-attached pose in new snapshot. owner.storeDetachedSnapshot(entity, data, now, commitAttachedPose); } - return false; // Stop descending. } @@ -613,6 +658,7 @@ namespace armarx::armem::server::obj::instance return output; } + void Segment::storeDetachedSnapshot( armem::wm::Entity& entity, const arondto::ObjectInstance& data, @@ -648,14 +694,17 @@ namespace armarx::armem::server::obj::instance } - std::optional<wm::EntityInstance> Segment::findClassInstance(const ObjectID& objectID) + std::optional<wm::EntityInstance> Segment::findClassInstance(const ObjectID& objectID) const { const ObjectID classID = { objectID.dataset(), objectID.className() }; try { for (const auto& [_, provSeg] : iceMemory.workingMemory->getCoreSegment("Class")) { - return provSeg.getEntity(classID.str()).getLatestSnapshot().getInstance(0); + if (provSeg.hasEntity(classID.str())) + { + return provSeg.getEntity(classID.str()).getLatestSnapshot().getInstance(0); + } } return std::nullopt; } @@ -667,6 +716,181 @@ namespace armarx::armem::server::obj::instance } + void Segment::storeScene(const std::string& filename, const armem::obj::SceneSnapshot& scene) + { + if (const std::optional<std::filesystem::path> path = resolveSceneFilename(filename)) + { + const nlohmann::json j = scene; + ARMARX_INFO << "Storing scene snapshot at: \n" << path.value() << "\n\n" << j.dump(2); + try + { + nlohmann::write_json(path.value(), j, 2); + } + catch (const std::ios_base::failure& e) + { + ARMARX_WARNING << "Storing scene snapshot failed: \n" << e.what(); + } + } + } + + + std::optional<armem::obj::SceneSnapshot> Segment::loadScene(const std::string& filename) + { + if (const std::optional<std::filesystem::path> path = resolveSceneFilename(filename)) + { + return loadScene(path.value()); + } + else + { + return std::nullopt; + } + } + + + std::optional<armem::obj::SceneSnapshot> Segment::loadScene(const std::filesystem::path& path) + { + ARMARX_INFO << "Loading scene snapshot from: \n" << path; + nlohmann::json j; + try + { + j = nlohmann::read_json(path); + } + catch (const std::ios_base::failure& e) + { + ARMARX_WARNING << "Loading scene snapshot failed: \n" << e.what(); + return std::nullopt; + } + + armem::obj::SceneSnapshot snapshot = j; + return snapshot; + } + + + const std::string Segment::timestampPlaceholder = "%TIMESTAMP"; + + + std::optional<std::filesystem::path> Segment::resolveSceneFilename(const std::string& _filename) + { + std::string filename = _filename; + + filename = simox::alg::replace_all(filename, timestampPlaceholder, + Time::now().toString("%Y-%m-%d_%H-%M-%S")); + if (not simox::alg::ends_with(filename, ".json")) + { + filename += ".json"; + } + + if (!finder) + { + finder.reset(new CMakePackageFinder(p.sceneSnapshotsPackage)); + if (not finder->packageFound()) + { + ARMARX_WARNING << "Could not find CMake package " << p.sceneSnapshotsPackage << "."; + } + } + if (finder->packageFound()) + { + std::filesystem::path dataDir = finder->getDataDir(); + std::filesystem::path path = dataDir / p.sceneSnapshotsPackage / "Scenes" / filename; + return path; + } + else + { + return std::nullopt; + } + } + + + armem::obj::SceneSnapshot Segment::getSceneSnapshot() const + { + armem::obj::SceneSnapshot scene; + + wm::FunctionalVisitor visitor; + visitor.entityFn = [&scene](wm::Entity & entity) + { + try + { + const wm::EntityInstance& entityInstance = entity.getLatestSnapshot().getInstance(0); + std::optional<arondto::ObjectInstance> objectInstance = tryCast<arondto::ObjectInstance>(entityInstance); + if (objectInstance) + { + armem::obj::SceneSnapshot::Object& object = scene.objects.emplace_back(); + // object.instanceID = entityInstance.id(); + object.className = ObjectID(objectInstance->classID.entityName).getClassID().str(); + object.collection = ""; + object.position = simox::math::position(objectInstance->pose.objectPoseGlobal); + object.orientation = simox::math::orientation(objectInstance->pose.objectPoseGlobal); + } + } + catch (const armem::error::ArMemError& e) + { + ARMARX_WARNING_S << e.what(); + } + return false; + }; + + visitor.applyTo(*coreSegment); + return scene; + } + + + void Segment::commitSceneSnapshot(const armem::obj::SceneSnapshot& scene, const std::string& sceneName) + { + const Time now = TimeUtil::GetTime(); + std::map<ObjectID, int> idCounters; + + objpose::ObjectPoseSeq objectPoses; + + for (const auto& object : scene.objects) + { + const ObjectID classID = object.getClassID(); + + objpose::ObjectPose& pose = objectPoses.emplace_back(); + + pose.providerName = sceneName; + pose.objectType = objpose::ObjectTypeEnum::KnownObject; + pose.objectID = classID.withInstanceName(std::to_string(idCounters[classID]++)); + + pose.objectPoseGlobal = simox::math::pose(object.position, object.orientation); + pose.objectPoseRobot = pose.objectPoseGlobal; + pose.objectPoseOriginal = pose.objectPoseGlobal; + pose.objectPoseOriginalFrame = armarx::GlobalFrame; + + pose.robotConfig = {}; + pose.robotPose = Eigen::Matrix4f::Identity(); + + pose.confidence = 1.0; + pose.localOOBB = getObjectOOBB(classID); + pose.timestamp = now; + } + + commitObjectPoses(objectPoses); + } + + + void Segment::commitSceneSnapshotFromFilename(const std::string& filename, bool lockMemory) + { + ARMARX_INFO << "Loading scene snapshot '" << filename << "' ..."; + if (auto path = resolveSceneFilename(filename)) + { + if (const auto snapshot = loadScene(path.value())) + { + std::filesystem::path filename = path->filename(); + filename.replace_extension(); // Removes extension + + if (lockMemory) + { + std::scoped_lock lock(memoryMutex); + commitSceneSnapshot(snapshot.value(), filename.string()); + } + else + { + commitSceneSnapshot(snapshot.value(), filename.string()); + } + } + } + } + void Segment::RemoteGui::setup(const Segment& data) { @@ -677,8 +901,21 @@ namespace armarx::armem::server::obj::instance infiniteHistory.setValue(data.p.maxHistorySize == -1); discardSnapshotsWhileAttached.setValue(data.p.discardSnapshotsWhileAttached); + storeLoadLine.setValue("Scene_" + timestampPlaceholder); + loadButton.setLabel("Load Scene"); + storeButton.setLabel("Store Scene"); + + HBoxLayout storeLoadLineLayout({Label(data.p.sceneSnapshotsPackage + "/Scenes/"), storeLoadLine, Label(".json")}); + HBoxLayout storeLoadButtonsLayout({loadButton, storeButton}); + GridLayout grid; int row = 0; + + grid.add(storeLoadLineLayout, {row, 0}, {1, 2}); + row++; + grid.add(storeLoadButtonsLayout, {row, 0}, {1, 2}); + row++; + grid.add(Label("Max History Size"), {row, 0}).add(maxHistorySize, {row, 1}); row++; grid.add(Label("Infinite History Size"), {row, 0}).add(infiniteHistory, {row, 1}); @@ -690,8 +927,25 @@ namespace armarx::armem::server::obj::instance group.addChild(grid); } + void Segment::RemoteGui::update(Segment& data) { + if (loadButton.wasClicked()) + { + bool lockMemory = true; + data.commitSceneSnapshotFromFilename(storeLoadLine.getValue(), lockMemory); + } + + if (storeButton.wasClicked()) + { + armem::obj::SceneSnapshot scene; + { + std::scoped_lock lock(data.memoryMutex); + scene = data.getSceneSnapshot(); + } + data.storeScene(storeLoadLine.getValue(), scene); + } + if (infiniteHistory.hasValueChanged() || maxHistorySize.hasValueChanged() || discardSnapshotsWhileAttached.hasValueChanged()) { diff --git a/source/RobotAPI/libraries/armem_objects/server/instance/Segment.h b/source/RobotAPI/libraries/armem_objects/server/instance/Segment.h index 5b7c268bb28530b82906bc07cee31431d6738f5c..0ac63b410d8d5593ac3c6b9be1fb9ea1cc58eb4d 100644 --- a/source/RobotAPI/libraries/armem_objects/server/instance/Segment.h +++ b/source/RobotAPI/libraries/armem_objects/server/instance/Segment.h @@ -1,8 +1,9 @@ #pragma once +#include <filesystem> #include <map> -#include <string> #include <optional> +#include <string> #include <SimoxUtility/caching/CacheMap.h> #include <SimoxUtility/shapes/OrientedBox.h> @@ -23,6 +24,11 @@ #include "Decay.h" +namespace armarx::armem::obj +{ + struct SceneSnapshot; +} + namespace armarx::armem::server::obj::instance { @@ -53,7 +59,7 @@ namespace armarx::armem::server::obj::instance const std::string& providerName, const objpose::data::ProvidedObjectPoseSeq& providedPoses, std::optional<Time> discardUpdatesUntil = std::nullopt); - void commitObjectPoses(const std::string& providerName, const ObjectPoseSeq& objectPoses); + void commitObjectPoses(const ObjectPoseSeq& objectPoses, const std::string& providerName = ""); wm::CoreSegment& getCoreSegment(); @@ -129,12 +135,24 @@ namespace armarx::armem::server::obj::instance bool commitAttachedPose); - std::optional<wm::EntityInstance> findClassInstance(const ObjectID& objectID); + std::optional<wm::EntityInstance> findClassInstance(const ObjectID& objectID) const; friend struct DetachVisitor; + private: + + void storeScene(const std::string& filename, const armem::obj::SceneSnapshot& scene); + std::optional<armem::obj::SceneSnapshot> loadScene(const std::string& filename); + std::optional<armem::obj::SceneSnapshot> loadScene(const std::filesystem::path& path); + std::optional<std::filesystem::path> resolveSceneFilename(const std::string& filename); + + armem::obj::SceneSnapshot getSceneSnapshot() const; + void commitSceneSnapshot(const armem::obj::SceneSnapshot& scene, const std::string& sceneName); + void commitSceneSnapshotFromFilename(const std::string& filename, bool lockMemory); + + public: RobotStateComponentInterfacePrx robotStateComponent; @@ -162,6 +180,10 @@ namespace armarx::armem::server::obj::instance // -1 would be infinite, but this can let the RAM grow quickly. long maxHistorySize = 25; bool discardSnapshotsWhileAttached = true; + + /// Package containing the scene snapshots + std::string sceneSnapshotsPackage = "ArmarXObjects"; + std::string sceneSnapshotToLoad = ""; }; Properties p; @@ -172,6 +194,9 @@ namespace armarx::armem::server::obj::instance /// Class name -> dataset name. simox::caching::CacheMap<std::string, std::string> classNameToDatasetCache; + std::unique_ptr<CMakePackageFinder> finder; + + static const std::string timestampPlaceholder; public: @@ -179,6 +204,10 @@ namespace armarx::armem::server::obj::instance { armarx::RemoteGui::Client::GroupBox group; + armarx::RemoteGui::Client::LineEdit storeLoadLine; + armarx::RemoteGui::Client::Button storeButton; + armarx::RemoteGui::Client::Button loadButton; + armarx::RemoteGui::Client::IntSpinBox maxHistorySize; armarx::RemoteGui::Client::CheckBox infiniteHistory; armarx::RemoteGui::Client::CheckBox discardSnapshotsWhileAttached; diff --git a/source/RobotAPI/libraries/armem_objects/server/instance/SegmentAdapter.cpp b/source/RobotAPI/libraries/armem_objects/server/instance/SegmentAdapter.cpp index 3773c087bf70fa68981be86696b01c6fae7645d6..46a7a4fba84f5c81799d6e7330359b4e2ad7a52f 100644 --- a/source/RobotAPI/libraries/armem_objects/server/instance/SegmentAdapter.cpp +++ b/source/RobotAPI/libraries/armem_objects/server/instance/SegmentAdapter.cpp @@ -484,9 +484,9 @@ namespace armarx::armem::server::obj::instance std::scoped_lock lock(adapter.visuMutex); this->visu.update(adapter.visu); } + this->segment.update(adapter.segment); { std::scoped_lock lock(adapter.memoryMutex); - this->segment.update(adapter.segment); this->decay.update(adapter.segment.decay); } { diff --git a/source/RobotAPI/libraries/armem_robot_state/server/description/Segment.cpp b/source/RobotAPI/libraries/armem_robot_state/server/description/Segment.cpp index c4dc03c66eadfa840923bf32c5fc03533749f55b..5a299161453d2480fb82601d74e563e5227f8a10 100644 --- a/source/RobotAPI/libraries/armem_robot_state/server/description/Segment.cpp +++ b/source/RobotAPI/libraries/armem_robot_state/server/description/Segment.cpp @@ -18,7 +18,7 @@ #include <RobotAPI/libraries/armem/client/query/Builder.h> #include <RobotAPI/libraries/armem/client/query/query_fns.h> #include <RobotAPI/libraries/armem/core/aron_conversions.h> -#include <RobotAPI/libraries/armem/core/workingmemory/Visitor.h> +#include <RobotAPI/libraries/armem/core/workingmemory/visitor.h> #include <RobotAPI/libraries/armem/server/MemoryToIceAdapter.h> #include <RobotAPI/libraries/armem_robot/aron/Robot.aron.generated.h> diff --git a/source/RobotAPI/libraries/armem_robot_state/server/localization/Segment.cpp b/source/RobotAPI/libraries/armem_robot_state/server/localization/Segment.cpp index 3137127aa112528fdf39351b9bfc52e4c4ece3b8..a9975f431c0a22b2a3367f42c7311d7f894f0b2d 100644 --- a/source/RobotAPI/libraries/armem_robot_state/server/localization/Segment.cpp +++ b/source/RobotAPI/libraries/armem_robot_state/server/localization/Segment.cpp @@ -26,7 +26,7 @@ #include <RobotAPI/libraries/armem/client/query/Builder.h> #include <RobotAPI/libraries/armem/client/query/query_fns.h> #include <RobotAPI/libraries/armem/core/aron_conversions.h> -#include <RobotAPI/libraries/armem/core/workingmemory/Visitor.h> +#include <RobotAPI/libraries/armem/core/workingmemory/visitor.h> #include <RobotAPI/libraries/armem/server/MemoryToIceAdapter.h> #include <RobotAPI/libraries/armem_robot/robot_conversions.h> diff --git a/source/RobotAPI/libraries/armem_robot_state/server/proprioception/Segment.cpp b/source/RobotAPI/libraries/armem_robot_state/server/proprioception/Segment.cpp index 5ec63c12d9c3f6485839ff138b1ebe409dd1adc8..7f95e43878aee62619f8c4997db25460e11ed8cd 100644 --- a/source/RobotAPI/libraries/armem_robot_state/server/proprioception/Segment.cpp +++ b/source/RobotAPI/libraries/armem_robot_state/server/proprioception/Segment.cpp @@ -10,7 +10,7 @@ #include "RobotAPI/libraries/aron/common/aron_conversions.h" #include <RobotAPI/libraries/armem/core/aron_conversions.h> -#include <RobotAPI/libraries/armem/core/workingmemory/Visitor.h> +#include <RobotAPI/libraries/armem/core/workingmemory/visitor.h> #include "RobotAPI/libraries/armem/core/MemoryID.h" #include <RobotAPI/libraries/armem/client/Writer.h> #include <RobotAPI/libraries/armem/client/query/Builder.h>