diff --git a/source/RobotAPI/components/ArViz/ArVizStorage.cpp b/source/RobotAPI/components/ArViz/ArVizStorage.cpp
index decbf95c39a16482ee3bc6975396812397c3d37e..434310e1d26d935d5bd8b5c15444960518a41a28 100644
--- a/source/RobotAPI/components/ArViz/ArVizStorage.cpp
+++ b/source/RobotAPI/components/ArViz/ArVizStorage.cpp
@@ -22,19 +22,23 @@
 
 #include "ArVizStorage.h"
 
-#include <ArmarXCore/core/logging/Logging.h>
-#include <ArmarXCore/core/util/IceBlobToObject.h>
-#include <ArmarXCore/core/util/ObjectToIceBlob.h>
-#include <ArmarXCore/core/system/ArmarXDataPath.h>
+#include <algorithm>
+#include <optional>
 
 #include <SimoxUtility/json/json.hpp>
 
-#include <iomanip>
-#include <optional>
+#include <ArmarXCore/core/logging/Logging.h>
+#include <ArmarXCore/core/system/ArmarXDataPath.h>
+#include <ArmarXCore/core/time.h>
+#include <ArmarXCore/core/time/DateTime.h>
+#include <ArmarXCore/core/time/Duration.h>
+#include <ArmarXCore/core/util/IceBlobToObject.h>
+#include <ArmarXCore/core/util/ObjectToIceBlob.h>
 
 namespace armarx
 {
-    static std::filesystem::path getAbsolutePath(const std::filesystem::path& path)
+    static std::filesystem::path
+    getAbsolutePath(const std::filesystem::path& path)
     {
         if (path.is_absolute())
         {
@@ -56,53 +60,53 @@ namespace armarx
         }
     }
 
-
-    std::string ArVizStorage::getDefaultName() const
+    std::string
+    ArVizStorage::getDefaultName() const
     {
         return "ArVizStorage";
     }
 
-
-    armarx::PropertyDefinitionsPtr ArVizStorage::createPropertyDefinitions()
+    armarx::PropertyDefinitionsPtr
+    ArVizStorage::createPropertyDefinitions()
     {
-        armarx::PropertyDefinitionsPtr defs(new ComponentPropertyDefinitions(getConfigIdentifier()));
+        armarx::PropertyDefinitionsPtr defs(
+            new ComponentPropertyDefinitions(getConfigIdentifier()));
 
-        defs->optional(topicName, "TopicName",
-                       "Layer updates are sent over this topic.");
+        defs->optional(
+            properties_.topicName, "TopicName", "Layer updates are sent over this topic.");
 
-        defs->optional(maxHistorySize, "MaxHistorySize",
+        defs->optional(properties_.maxHistorySize,
+                       "MaxHistorySize",
                        "How many layer updates are saved in the history until they are compressed")
-                .setMin(0);
+            .setMin(0);
 
-        defs->defineOptionalProperty<std::string>(
-                    "HistoryPath", "RobotAPI/ArVizStorage",
-                    "Destination path where the history is serialized to");
+        defs->optional(properties_.historyPath,
+                       "HistoryPath",
+                       "Destination path where the history is serialized to");
 
         return defs;
     }
 
-
-    void ArVizStorage::onInitComponent()
+    void
+    ArVizStorage::onInitComponent()
     {
-        std::filesystem::path historyPathProp = getProperty<std::string>("HistoryPath").getValue();
-        historyPath = getAbsolutePath(historyPathProp);
-        if (!std::filesystem::exists(historyPath))
+        properties_.historyPath = getAbsolutePath(properties_.historyPath);
+        if (!std::filesystem::exists(properties_.historyPath))
         {
-            ARMARX_INFO << "Creating history path: " << historyPath;
+            ARMARX_INFO << "Creating history path: " << properties_.historyPath;
             std::error_code error;
-            std::filesystem::create_directory(historyPath, error);
+            std::filesystem::create_directory(properties_.historyPath, error);
             if (error)
             {
-                ARMARX_WARNING << "Could not create directory for history: \n"
-                               << error.message();
+                ARMARX_WARNING << "Could not create directory for history: \n" << error.message();
             }
         }
 
-        usingTopic(topicName);
+        usingTopic(properties_.topicName);
     }
 
-
-    void ArVizStorage::onConnectComponent()
+    void
+    ArVizStorage::onConnectComponent()
     {
         revision = 0;
         currentState.clear();
@@ -113,8 +117,8 @@ namespace armarx
         recordingMetaData.id = "";
     }
 
-
-    void ArVizStorage::onDisconnectComponent()
+    void
+    ArVizStorage::onDisconnectComponent()
     {
         if (recordingTask)
         {
@@ -123,20 +127,51 @@ namespace armarx
         }
     }
 
-
-    void ArVizStorage::onExitComponent()
+    void
+    ArVizStorage::onExitComponent()
     {
     }
 
-
-    void ArVizStorage::updateLayers(viz::data::LayerUpdateSeq const& updates, const Ice::Current&)
+    void
+    ArVizStorage::updateLayers(viz::data::LayerUpdateSeq const& updates, const Ice::Current&)
     {
         std::unique_lock<std::mutex> lock(historyMutex);
 
         revision += 1;
+
         IceUtil::Time now = IceUtil::Time::now();
         long nowInMicroSeconds = now.toMicroSeconds();
 
+        if (not updates.empty())
+        {
+            const std::string& componentName = updates.front().component;
+
+            auto& history = updateHistoryForComponents[componentName];
+            history.push_back(armarx::Clock::Now());
+
+            const auto maxHistoryDur = armarx::Duration::SecondsDouble(1);
+
+            const DateTime referenceNow = Clock::Now();
+            const auto isOutdated = [&referenceNow,
+                                     &maxHistoryDur](const DateTime& timestamp) -> bool
+            { return (referenceNow - timestamp) > maxHistoryDur; };
+
+            // trim history
+            history.erase(std::remove_if(history.begin(), history.end(), isOutdated),
+                          history.end());
+
+            ARMARX_VERBOSE << deactivateSpam(1, componentName) << componentName << ": "
+                           << history.size() / maxHistoryDur.toSecondsDouble() << " Hz";
+
+            if (history.size() > properties_.componentWarnFrequency)
+            {
+                ARMARX_WARNING << "Component `" << componentName << "`"
+                               << "sends data at a too high rate ("
+                               << history.size() / maxHistoryDur.toSecondsDouble() << ")";
+            }
+        }
+
+
         for (auto& update : updates)
         {
             if (update.component.empty())
@@ -157,8 +192,7 @@ namespace armarx
             bool found = false;
             for (auto& layer : currentState)
             {
-                if (layer.update.component == update.component
-                    && layer.update.name == update.name)
+                if (layer.update.component == update.component && layer.update.name == update.name)
                 {
                     layer = historyEntry;
                     found = true;
@@ -172,7 +206,7 @@ namespace armarx
         }
 
         long currentHistorySize = history.size();
-        if (currentHistorySize >= maxHistorySize)
+        if (currentHistorySize >= properties_.maxHistorySize)
         {
             {
                 std::unique_lock<std::mutex> lock(recordingMutex);
@@ -190,7 +224,9 @@ namespace armarx
         }
     }
 
-    viz::data::CommitResult ArVizStorage::commitAndReceiveInteractions(viz::data::CommitInput const& input, const Ice::Current&)
+    viz::data::CommitResult
+    ArVizStorage::commitAndReceiveInteractions(viz::data::CommitInput const& input,
+                                               const Ice::Current&)
     {
         viz::data::CommitResult result;
 
@@ -215,8 +251,8 @@ namespace armarx
                 bool found = false;
                 for (viz::data::TimestampedLayerUpdate& layer : currentState)
                 {
-                    if (layer.update.component == update.component
-                        && layer.update.name == update.name)
+                    if (layer.update.component == update.component &&
+                        layer.update.name == update.name)
                     {
                         layer = historyEntry;
                         found = true;
@@ -231,7 +267,7 @@ namespace armarx
 
             // Trim the history if max size has been exceeded
             long currentHistorySize = history.size();
-            if (currentHistorySize >= maxHistorySize)
+            if (currentHistorySize >= properties_.maxHistorySize)
             {
                 {
                     std::unique_lock<std::mutex> lock(recordingMutex);
@@ -252,21 +288,23 @@ namespace armarx
             if (input.interactionComponent.size() > 0)
             {
                 auto interactionsEnd = interactionBuffer.end();
-                auto foundInteractionsBegin = std::partition(interactionBuffer.begin(), interactionsEnd,
-                    [&input](viz::data::InteractionFeedback const& interaction)
-                {
-                    if (interaction.component == input.interactionComponent)
-                    {
-                        for (std::string const& layer : input.interactionLayers)
-                        {
-                            if (interaction.layer == layer)
-                            {
-                                return false;
-                            }
-                        }
-                    }
-                    return true;
-                });
+                auto foundInteractionsBegin =
+                    std::partition(interactionBuffer.begin(),
+                                   interactionsEnd,
+                                   [&input](viz::data::InteractionFeedback const& interaction)
+                                   {
+                                       if (interaction.component == input.interactionComponent)
+                                       {
+                                           for (std::string const& layer : input.interactionLayers)
+                                           {
+                                               if (interaction.layer == layer)
+                                               {
+                                                   return false;
+                                               }
+                                           }
+                                       }
+                                       return true;
+                                   });
 
                 result.interactions.assign(foundInteractionsBegin, interactionsEnd);
                 interactionBuffer.erase(foundInteractionsBegin, interactionsEnd);
@@ -276,9 +314,8 @@ namespace armarx
         return result;
     }
 
-
-
-    viz::data::LayerUpdates ArVizStorage::pullUpdatesSince(Ice::Long revision, const Ice::Current&)
+    viz::data::LayerUpdates
+    ArVizStorage::pullUpdatesSince(Ice::Long revision, const Ice::Current&)
     {
         viz::data::LayerUpdates result;
 
@@ -297,12 +334,16 @@ namespace armarx
         return result;
     }
 
-    static const int ALL_TRANSFORM_FLAGS = viz::data::InteractionFeedbackType::TRANSFORM_BEGIN_FLAG
-                                           | viz::data::InteractionFeedbackType::TRANSFORM_DURING_FLAG
-                                           | viz::data::InteractionFeedbackType::TRANSFORM_END_FLAG;
+    static const int ALL_TRANSFORM_FLAGS =
+        viz::data::InteractionFeedbackType::TRANSFORM_BEGIN_FLAG |
+        viz::data::InteractionFeedbackType::TRANSFORM_DURING_FLAG |
+        viz::data::InteractionFeedbackType::TRANSFORM_END_FLAG;
 
-    viz::data::LayerUpdates ArVizStorage::pullUpdatesSinceAndSendInteractions(
-            Ice::Long revision, viz::data::InteractionFeedbackSeq const& interactions, const Ice::Current& c)
+    viz::data::LayerUpdates
+    ArVizStorage::pullUpdatesSinceAndSendInteractions(
+        Ice::Long revision,
+        viz::data::InteractionFeedbackSeq const& interactions,
+        const Ice::Current& c)
     {
         viz::data::LayerUpdates result;
 
@@ -312,9 +353,8 @@ namespace armarx
         {
             for (viz::data::InteractionFeedback& entry : interactionBuffer)
             {
-                if (entry.component == interaction.component
-                        && entry.layer == interaction.layer
-                        && entry.element == interaction.element)
+                if (entry.component == interaction.component && entry.layer == interaction.layer &&
+                    entry.element == interaction.element)
                 {
                     int previousTransformFlags = entry.type & ALL_TRANSFORM_FLAGS;
                     int interactionTransformFlags = interaction.type & ALL_TRANSFORM_FLAGS;
@@ -333,7 +373,7 @@ namespace armarx
             // Interaction did not exist, add it to the buffer
             interactionBuffer.push_back(interaction);
 
-            for_end: ;
+        for_end:;
         }
 
         result.updates.reserve(currentState.size());
@@ -349,7 +389,8 @@ namespace armarx
         return result;
     }
 
-    void ArVizStorage::record()
+    void
+    ArVizStorage::record()
     {
         while (!recordingTask->isStopped())
         {
@@ -365,12 +406,13 @@ namespace armarx
             recordingBuffer.clear();
         }
     }
-}
+} // namespace armarx
 
 namespace armarx::viz::data
 {
 
-    void to_json(nlohmann::json& j, RecordingBatchHeader const& batch)
+    void
+    to_json(nlohmann::json& j, RecordingBatchHeader const& batch)
     {
         j["index"] = batch.index;
         j["firstRevision"] = batch.firstRevision;
@@ -379,16 +421,18 @@ namespace armarx::viz::data
         j["lastTimestampInMicroSeconds"] = batch.lastTimestampInMicroSeconds;
     }
 
-    void from_json(nlohmann::json const& j, RecordingBatchHeader& batch)
+    void
+    from_json(nlohmann::json const& j, RecordingBatchHeader& batch)
     {
-        batch.index = j["index"] ;
+        batch.index = j["index"];
         batch.firstRevision = j["firstRevision"];
         batch.lastRevision = j["lastRevision"];
         batch.firstTimestampInMicroSeconds = j["firstTimestampInMicroSeconds"];
         batch.lastTimestampInMicroSeconds = j["lastTimestampInMicroSeconds"];
     }
 
-    void to_json(nlohmann::json& j, Recording const& recording)
+    void
+    to_json(nlohmann::json& j, Recording const& recording)
     {
         j["id"] = recording.id;
         j["firstRevision"] = recording.firstRevision;
@@ -398,7 +442,8 @@ namespace armarx::viz::data
         j["batchHeaders"] = recording.batchHeaders;
     }
 
-    void from_json(nlohmann::json const& j, Recording& recording)
+    void
+    from_json(nlohmann::json const& j, Recording& recording)
     {
         recording.id = j["id"];
         recording.firstRevision = j["firstRevision"];
@@ -408,10 +453,10 @@ namespace armarx::viz::data
         j["batchHeaders"].get_to(recording.batchHeaders);
     }
 
-}
+} // namespace armarx::viz::data
 
-static bool writeCompleteFile(std::string const& filename,
-                              const void* data, std::size_t size)
+static bool
+writeCompleteFile(std::string const& filename, const void* data, std::size_t size)
 {
     FILE* file = fopen(filename.c_str(), "wb");
     if (!file)
@@ -427,12 +472,13 @@ static bool writeCompleteFile(std::string const& filename,
     return true;
 }
 
-static std::string readCompleteFile(std::filesystem::path const& path)
+static std::string
+readCompleteFile(std::filesystem::path const& path)
 {
     FILE* f = fopen(path.string().c_str(), "rb");
     fseek(f, 0, SEEK_END);
     long fsize = ftell(f);
-    fseek(f, 0, SEEK_SET);  /* same as rewind(f); */
+    fseek(f, 0, SEEK_SET); /* same as rewind(f); */
 
     std::string result(fsize, '\0');
     std::size_t read = fread(result.data(), 1, fsize, f);
@@ -442,7 +488,8 @@ static std::string readCompleteFile(std::filesystem::path const& path)
     return result;
 }
 
-static std::optional<armarx::viz::data::Recording> readRecordingInfo(std::filesystem::path const& recordingDirectory)
+static std::optional<armarx::viz::data::Recording>
+readRecordingInfo(std::filesystem::path const& recordingDirectory)
 {
     std::optional<::armarx::viz::data::Recording> result;
 
@@ -472,12 +519,14 @@ static std::optional<armarx::viz::data::Recording> readRecordingInfo(std::filesy
     }
 }
 
-static std::string batchFileName(armarx::viz::data::RecordingBatchHeader const& batchHeader)
+static std::string
+batchFileName(armarx::viz::data::RecordingBatchHeader const& batchHeader)
 {
     return std::to_string(batchHeader.firstRevision) + ".bin";
 }
 
-void armarx::ArVizStorage::recordBatch(armarx::viz::data::RecordingBatch& batch)
+void
+armarx::ArVizStorage::recordBatch(armarx::viz::data::RecordingBatch& batch)
 {
     if (batch.updates.empty())
     {
@@ -492,7 +541,7 @@ void armarx::ArVizStorage::recordBatch(armarx::viz::data::RecordingBatch& batch)
     batch.header.lastRevision = last.revision;
     batch.header.firstTimestampInMicroSeconds = first.timestampInMicroseconds;
     batch.header.lastTimestampInMicroSeconds = last.timestampInMicroseconds;
-    if (firstBatch) 
+    if (firstBatch)
     {
         batch.initialState = currentState;
         firstBatch = false;
@@ -523,7 +572,8 @@ void armarx::ArVizStorage::recordBatch(armarx::viz::data::RecordingBatch& batch)
     }
     recordingMetaData.lastTimestampInMicroSeconds = last.timestampInMicroseconds;
 
-    armarx::viz::data::RecordingBatchHeader& newBatch = recordingMetaData.batchHeaders.emplace_back();
+    armarx::viz::data::RecordingBatchHeader& newBatch =
+        recordingMetaData.batchHeaders.emplace_back();
     newBatch.index = recordingMetaData.batchHeaders.size() - 1;
     newBatch.firstRevision = first.revision;
     newBatch.lastRevision = last.revision;
@@ -543,26 +593,26 @@ void armarx::ArVizStorage::recordBatch(armarx::viz::data::RecordingBatch& batch)
     ARMARX_INFO << "Recorded ArViz batch to: " << filePath;
 }
 
-std::string armarx::ArVizStorage::startRecording(std::string const& newRecordingPrefix, const Ice::Current&)
+std::string
+armarx::ArVizStorage::startRecording(std::string const& newRecordingPrefix, const Ice::Current&)
 {
     {
         std::unique_lock<std::mutex> lock(recordingMutex);
         if (recordingMetaData.id.size() > 0)
         {
-            ARMARX_WARNING << "Could not start recording with prefix " << newRecordingPrefix
-                           << "\nbecause there is already a recording running for the recording ID: "
-                           << recordingMetaData.id;
+            ARMARX_WARNING
+                << "Could not start recording with prefix " << newRecordingPrefix
+                << "\nbecause there is already a recording running for the recording ID: "
+                << recordingMetaData.id;
             return recordingMetaData.id;
         }
 
         IceUtil::Time now = IceUtil::Time::now();
         std::ostringstream id;
-        id << newRecordingPrefix
-           << '_'
-           << now.toString("%Y-%m-%d_%H-%M-%S");
+        id << newRecordingPrefix << '_' << now.toString("%Y-%m-%d_%H-%M-%S");
         std::string newRecordingID = id.str();
 
-        recordingPath = historyPath / newRecordingID;
+        recordingPath = properties_.historyPath / newRecordingID;
         if (!std::filesystem::exists(recordingPath))
         {
             ARMARX_INFO << "Creating directory for recording with ID '" << newRecordingID
@@ -594,7 +644,8 @@ std::string armarx::ArVizStorage::startRecording(std::string const& newRecording
     return "";
 }
 
-void armarx::ArVizStorage::stopRecording(const Ice::Current&)
+void
+armarx::ArVizStorage::stopRecording(const Ice::Current&)
 {
     if (!recordingTask)
     {
@@ -616,12 +667,14 @@ void armarx::ArVizStorage::stopRecording(const Ice::Current&)
     recordingMetaData.firstTimestampInMicroSeconds = -1;
 }
 
-armarx::viz::data::RecordingsInfo armarx::ArVizStorage::getAllRecordings(const Ice::Current&)
+armarx::viz::data::RecordingsInfo
+armarx::ArVizStorage::getAllRecordings(const Ice::Current&)
 {
     viz::data::RecordingsInfo recordingsInfo;
     viz::data::RecordingSeq result;
 
-    for (std::filesystem::directory_entry const& entry : std::filesystem::directory_iterator(historyPath))
+    for (std::filesystem::directory_entry const& entry :
+         std::filesystem::directory_iterator(properties_.historyPath))
     {
         ARMARX_DEBUG << "Checking: " << entry.path();
 
@@ -638,17 +691,20 @@ armarx::viz::data::RecordingsInfo armarx::ArVizStorage::getAllRecordings(const I
     }
 
     recordingsInfo.recordings = result;
-    recordingsInfo.recordingsPath = historyPath;
+    recordingsInfo.recordingsPath = properties_.historyPath;
 
     return recordingsInfo;
 }
 
-armarx::viz::data::RecordingBatch armarx::ArVizStorage::getRecordingBatch(std::string const& recordingID, Ice::Long batchIndex, const Ice::Current&)
+armarx::viz::data::RecordingBatch
+armarx::ArVizStorage::getRecordingBatch(std::string const& recordingID,
+                                        Ice::Long batchIndex,
+                                        const Ice::Current&)
 {
     viz::data::RecordingBatch result;
     result.header.index = -1;
 
-    std::filesystem::path recordingPath = historyPath / recordingID;
+    std::filesystem::path recordingPath = properties_.historyPath / recordingID;
     std::optional<viz::data::Recording> recording = readRecordingInfo(recordingPath);
     if (!recording)
     {
@@ -669,8 +725,7 @@ armarx::viz::data::RecordingBatch armarx::ArVizStorage::getRecordingBatch(std::s
     if (!std::filesystem::exists(batchFile))
     {
         ARMARX_WARNING << "Could not find batch file for recording '" << recordingID
-                       << "' with index " << batchIndex
-                       << "\nPath: " << batchFile;
+                       << "' with index " << batchIndex << "\nPath: " << batchFile;
         return result;
     }
 
diff --git a/source/RobotAPI/components/ArViz/ArVizStorage.h b/source/RobotAPI/components/ArViz/ArVizStorage.h
index 36d4d85564f5817d042b7607c11295cd527e2d69..60305bfd987fe1c75e04f86ab0665095a788447f 100644
--- a/source/RobotAPI/components/ArViz/ArVizStorage.h
+++ b/source/RobotAPI/components/ArViz/ArVizStorage.h
@@ -22,15 +22,16 @@
 
 #pragma once
 
-#include <RobotAPI/interface/ArViz.h>
-#include <ArmarXCore/core/Component.h>
-#include <ArmarXCore/core/services/tasks/RunningTask.h>
-
-#include <mutex>
 #include <atomic>
 #include <condition_variable>
 #include <filesystem>
+#include <mutex>
 
+#include "ArmarXCore/core/time/DateTime.h"
+#include <ArmarXCore/core/Component.h>
+#include <ArmarXCore/core/services/tasks/RunningTask.h>
+
+#include <RobotAPI/interface/ArViz.h>
 
 namespace armarx
 {
@@ -53,12 +54,11 @@ namespace armarx
      * @brief Stores visualization elements drawn by ArViz clients.
      *
      */
-    class ArVizStorage
-        : virtual public armarx::Component
-        , virtual public armarx::viz::StorageAndTopicInterface
+    class ArVizStorage :
+        virtual public armarx::Component,
+        virtual public armarx::viz::StorageAndTopicInterface
     {
     public:
-
         /// armarx::ManagedIceObject::getDefaultName()
         std::string getDefaultName() const override;
 
@@ -83,17 +83,19 @@ namespace armarx
         void updateLayers(viz::data::LayerUpdateSeq const& updates, const Ice::Current&) override;
 
         // StorageInterface interface
-        viz::data::CommitResult commitAndReceiveInteractions(viz::data::CommitInput const& input, const Ice::Current&) override;
+        viz::data::CommitResult commitAndReceiveInteractions(viz::data::CommitInput const& input,
+                                                             const Ice::Current&) override;
 
         viz::data::LayerUpdates pullUpdatesSince(Ice::Long revision, const Ice::Current&) override;
-        viz::data::LayerUpdates pullUpdatesSinceAndSendInteractions(
-                Ice::Long revision,
-                viz::data::InteractionFeedbackSeq const& interactions,
-                const Ice::Current&) override;
+        viz::data::LayerUpdates
+        pullUpdatesSinceAndSendInteractions(Ice::Long revision,
+                                            viz::data::InteractionFeedbackSeq const& interactions,
+                                            const Ice::Current&) override;
         std::string startRecording(std::string const& prefix, const Ice::Current&) override;
         void stopRecording(const Ice::Current&) override;
         viz::data::RecordingsInfo getAllRecordings(const Ice::Current&) override;
-        viz::data::RecordingBatch getRecordingBatch(const std::string&, Ice::Long, const Ice::Current&) override;
+        viz::data::RecordingBatch
+        getRecordingBatch(const std::string&, Ice::Long, const Ice::Current&) override;
 
     private:
         void record();
@@ -101,9 +103,15 @@ namespace armarx
         void recordBatch(viz::data::RecordingBatch& batch);
 
     private:
-        std::string topicName = "ArVizTopic";
-        int maxHistorySize = 1000;
-        std::filesystem::path historyPath;
+        struct Properties
+        {
+            std::string topicName = "ArVizTopic";
+            int maxHistorySize = 1000;
+            std::filesystem::path historyPath = "RobotAPI/ArVizStorage";
+
+            float componentWarnFrequency = 25;
+
+        } properties_;
 
         std::mutex historyMutex;
 
@@ -124,5 +132,8 @@ namespace armarx
         viz::data::Recording recordingMetaData;
         std::condition_variable recordingCondition;
         RunningTask<ArVizStorage>::pointer_type recordingTask;
+
+
+        std::map<std::string, std::vector<armarx::DateTime>> updateHistoryForComponents;
     };
-}
+} // namespace armarx
diff --git a/source/RobotAPI/components/ArViz/Coin/VisualizationRobot.cpp b/source/RobotAPI/components/ArViz/Coin/VisualizationRobot.cpp
index 12dc68399fc92b3d32816dd212d75fc4b0cdab8c..71dad203ab70fab4b411ad891b55b781b9fc7e39 100644
--- a/source/RobotAPI/components/ArViz/Coin/VisualizationRobot.cpp
+++ b/source/RobotAPI/components/ArViz/Coin/VisualizationRobot.cpp
@@ -1,12 +1,11 @@
 #include "VisualizationRobot.h"
 
-#include <fstream>
-#include <regex>
-
 #include <VirtualRobot/SceneObject.h>
 #include <VirtualRobot/Visualization/CoinVisualization/CoinVisualization.h>
 #include <VirtualRobot/XML/RobotIO.h>
 
+#include <ArmarXCore/core/time/Duration.h>
+#include <ArmarXCore/core/time/ScopedStopWatch.h>
 #include <ArmarXCore/core/logging/Logging.h>
 #include <ArmarXCore/core/system/ArmarXDataPath.h>
 #include <ArmarXCore/core/system/cmake/CMakePackageFinder.h>
@@ -114,17 +113,23 @@ namespace armarx::viz::coin
                     else
                     {
                         // 2) We do not have unused instances in the pool ==> Clone one
-                        ARMARX_DEBUG << "Cloning robot from cache " << VAROUT(project) << ", "
+                        ARMARX_INFO << "Cloning robot from cache " << VAROUT(project) << ", "
                                      << VAROUT(filename);
 
-                        if (instancePool.robots.size() > 0)
+                        if (!instancePool.robots.empty())
                         {
                             VirtualRobot::RobotPtr const& robotToClone =
                                 instancePool.robots.front();
                             float scaling = 1.0f;
                             bool preventCloningMeshesIfScalingIs1 = true;
-                            result.robot = robotToClone->clone(
+
+                            {
+                                armarx::core::time::ScopedStopWatch sw([](const armarx::Duration& duration){
+                                    ARMARX_DEBUG << "Cloning took " << duration.toSecondsDouble() << " seconds."; 
+                                });
+                                result.robot = robotToClone->clone(
                                 nullptr, scaling, preventCloningMeshesIfScalingIs1);
+                            }
 
                             // Insert the cloned robot into the instance pool
                             instancePool.robots.push_back(result.robot);
diff --git a/source/RobotAPI/libraries/ArmarXObjects/ObjectPoseClient.cpp b/source/RobotAPI/libraries/ArmarXObjects/ObjectPoseClient.cpp
index e577eb166ebc77bbbb66dc4ecfe47b9728b2a2be..f6c3146f7877990053cc372670f9fb5800c047bc 100644
--- a/source/RobotAPI/libraries/ArmarXObjects/ObjectPoseClient.cpp
+++ b/source/RobotAPI/libraries/ArmarXObjects/ObjectPoseClient.cpp
@@ -72,6 +72,20 @@ namespace armarx::objpose
 
         return std::nullopt;
     }
+
+    std::optional<ObjectPose>
+    ObjectPoseClient::fetchObjectPoseFromProvider(const ObjectID& objectID, const std::string& providerName) const
+    {
+        const auto objectPoses = fetchObjectPosesFromProvider(providerName);
+        const auto *object = findObjectPoseByID(objectPoses, objectID);
+
+        if(object != nullptr)
+        {
+            return *object;
+        }
+
+        return std::nullopt;
+    }
     
 
     ObjectPoseSeq
diff --git a/source/RobotAPI/libraries/ArmarXObjects/ObjectPoseClient.h b/source/RobotAPI/libraries/ArmarXObjects/ObjectPoseClient.h
index 8a1cb31f23f30b37724177aaff7ba30e77ec5604..f2bfb04410bd1d0ba0a3cec4bc9eed14edd26dfb 100644
--- a/source/RobotAPI/libraries/ArmarXObjects/ObjectPoseClient.h
+++ b/source/RobotAPI/libraries/ArmarXObjects/ObjectPoseClient.h
@@ -76,7 +76,19 @@ namespace armarx::objpose
          * @return The object's pose, if known.
          */
         std::optional<ObjectPose>
-        fetchObjectPose(const ObjectID& objectID) const;
+        fetchObjectPose(const ObjectID& objectID) const; 
+        
+        /**
+         * @brief Fetch the pose of a single object and a single provider.
+         *
+         * This is a network call. If you need multiple object poses, use
+         * `fetchObjectPoses()` instead.
+         *
+         * @param objectID The object's ID.
+         * @return The object's pose, if known.
+         */
+        std::optional<ObjectPose>
+        fetchObjectPoseFromProvider(const ObjectID& objectID, const std::string& providerName) const;
 
         /**
          * @brief Fetch object poses from a specific provider.
diff --git a/source/RobotAPI/libraries/GraspingUtility/GraspTrajectory.cpp b/source/RobotAPI/libraries/GraspingUtility/GraspTrajectory.cpp
index 7ab4f089abe260f55ff832fb7777d4c16f8b2dc3..800a22e47d9afaa7cf564bda93ea20b68234d574 100644
--- a/source/RobotAPI/libraries/GraspingUtility/GraspTrajectory.cpp
+++ b/source/RobotAPI/libraries/GraspingUtility/GraspTrajectory.cpp
@@ -34,9 +34,11 @@
 
 #include "ArmarXCore/core/logging/Logging.h"
 #include <ArmarXCore/core/exceptions/Exception.h>
+#include <ArmarXCore/core/exceptions/local/ExpressionException.h>
 #include <ArmarXCore/core/rapidxml/wrapper/RapidXmlReader.h>
 #include <ArmarXCore/core/rapidxml/wrapper/RapidXmlWriter.h>
 #include <ArmarXCore/core/system/cmake/CMakePackageFinder.h>
+#include <ArmarXCore/core/time/Duration.h>
 
 #include <ArmarXGui/libraries/StructuralJson/JPathNavigator.h>
 #include <ArmarXGui/libraries/StructuralJson/StructuralJsonParser.h>
@@ -44,6 +46,7 @@
 #include <RobotAPI/interface/units/GraspCandidateProviderInterface.h>
 #include <RobotAPI/libraries/SimpleJsonLogger/SimpleJsonLogger.h>
 
+
 namespace armarx
 {
 
@@ -138,6 +141,8 @@ namespace armarx
     GraspTrajectoryPtr
     GraspTrajectory::ReadFromFile(const std::string& filename)
     {
+        ARMARX_IMPORTANT << filename;
+
         ARMARX_TRACE;
         const auto ext = std::filesystem::path(filename).extension();
         if (ext == ".xml")
@@ -159,15 +164,37 @@ namespace armarx
     inline void
     from_json(const nlohmann::json& j, GraspTrajectoryKeypoint& kp)
     {
-        const std::optional<std::string> shape =
-            j.contains("shape") ? std::optional<std::string>(j.at("shape").get<std::string>())
-                                : std::nullopt;
+        ARMARX_TRACE;
+        std::optional<std::string> shape;
 
-        const std::map<std::string, float> targetHandValues =
-            j.contains("HandValues") ? j.at("HandValues").get<std::map<std::string, float>>()
-                                     : std::map<std::string, float>{};
+        if (j.contains("shape"))
+        {
+            if (not j.at("shape").is_null())
+            {
+                shape = j.at("shape");
+            }
+        }
+
+        ARMARX_TRACE;
+        std::optional<std::map<std::string, float>> targetHandValues;
 
-        kp = GraspTrajectoryKeypoint(j.at("Pose"), targetHandValues, shape);
+        if (j.contains("fingerValues"))
+        {
+            if (not j.at("fingerValues").is_null())
+            {
+                targetHandValues = j.at("fingerValues");
+            }
+        }
+
+        // VERY hacky!
+        const Eigen::Matrix<float, 4, 4, Eigen::RowMajor> aronTf = j.at("pose");
+        const Eigen::Matrix4f tf = aronTf.transpose();
+
+        ARMARX_IMPORTANT << tf;
+
+        ARMARX_TRACE;
+        kp = GraspTrajectoryKeypoint(
+            tf, targetHandValues.value_or(std::map<std::string, float>{}), shape);
     }
 
     GraspTrajectoryPtr
@@ -179,9 +206,27 @@ namespace armarx
         const nlohmann::json j = nlohmann::json::parse(ifs);
 
         std::vector<GraspTrajectoryKeypoint> traj;
-        traj = j;
+        traj = j.at("keypoints");
 
-        return std::make_shared<GraspTrajectory>(traj);
+        const armarx::Duration duration =
+            armarx::Duration::MicroSeconds(j.at("duration").at("microSeconds").get<std::int64_t>());
+
+        // at the moment, we assume that all keypoints are sampled equidistant
+
+        ARMARX_CHECK_NOT_EMPTY(traj);
+        const float dtSeconds = duration.toSecondsDouble() / (traj.size() - 1);
+
+        for (auto& kp : traj)
+        {
+            kp.dt = dtSeconds;
+        }
+
+        const std::string frame = j.at("frame").at("frame");
+
+        auto graspTrajectory = std::make_shared<GraspTrajectory>(traj);
+        graspTrajectory->setFrame(frame);
+
+        return graspTrajectory;
     }
 
     GraspTrajectoryPtr
@@ -557,7 +602,8 @@ namespace armarx
             traj->addKeypoint(
                 ::math::Helpers::TranslateAndRotatePose(kp->getTargetPose(), translation, rotation),
                 kp->handJointsTarget,
-                kp->dt);
+                kp->dt,
+                kp->shape);
         }
         return traj;
     }
@@ -566,12 +612,13 @@ namespace armarx
     GraspTrajectory::getTransformed(const Eigen::Matrix4f& transform) const
     {
         ARMARX_TRACE;
-        GraspTrajectoryPtr traj(
-            new GraspTrajectory(transform * getStartPose(), getKeypoint(0)->handJointsTarget));
+        GraspTrajectoryPtr traj(new GraspTrajectory(
+            transform * getStartPose(), getKeypoint(0)->handJointsTarget, getKeypoint(0)->shape));
         for (size_t i = 1; i < keypoints.size(); i++)
         {
             const KeypointPtr& kp = keypoints.at(i);
-            traj->addKeypoint(transform * kp->getTargetPose(), kp->handJointsTarget, kp->dt);
+            traj->addKeypoint(
+                transform * kp->getTargetPose(), kp->handJointsTarget, kp->dt, kp->shape);
         }
         return traj;
     }
@@ -620,7 +667,7 @@ namespace armarx
             const GraspTrajectory::KeypointPtr& kp = getKeypoint(i);
             Eigen::Matrix4f target_pose = kp->getTargetPose();
             target_pose.block<3, 3>(0, 0) = flip_yz * target_pose.block<3, 3>(0, 0) * flip_yz;
-            output_trajectory->addKeypoint(target_pose, kp->handJointsTarget, kp->dt);
+            output_trajectory->addKeypoint(target_pose, kp->handJointsTarget, kp->dt, kp->shape);
         }
         return output_trajectory;
     }
@@ -721,4 +768,16 @@ namespace armarx
         feedForwardOriVelocity(0, 0, 0)
     {
     }
+
+    void
+    GraspTrajectory::setFrame(const std::string& frame)
+    {
+        frame_ = frame;
+    }
+
+    const std::optional<std::string>&
+    GraspTrajectory::getFrame() const
+    {
+        return frame_;
+    }
 } // namespace armarx
diff --git a/source/RobotAPI/libraries/GraspingUtility/GraspTrajectory.h b/source/RobotAPI/libraries/GraspingUtility/GraspTrajectory.h
index 718642c2ae5028e4cbf7cbee4cabf6fcc4373497..15786c619c4833f5e77e23148cc04dfa8294e9c6 100644
--- a/source/RobotAPI/libraries/GraspingUtility/GraspTrajectory.h
+++ b/source/RobotAPI/libraries/GraspingUtility/GraspTrajectory.h
@@ -175,11 +175,16 @@ namespace armarx
         static GraspTrajectoryPtr ReadFromJSON(const std::string& filename);
         static GraspTrajectoryPtr ReadFromString(const std::string& xml);
 
+        void setFrame(const std::string& frame);
+        const std::optional<std::string>& getFrame() const;
+
     private:
         void updateKeypointMap();
 
     private:
         std::vector<KeypointPtr> keypoints;
         std::map<float, size_t> keypointMap;
+
+        std::optional<std::string> frame_;
     };
 } // namespace armarx
diff --git a/source/RobotAPI/libraries/armem/client/Writer.cpp b/source/RobotAPI/libraries/armem/client/Writer.cpp
index e9b06f66e1e297296a2f47c39cdf6474c0015795..727c1ff1941fa92001c3946e1b3b8b290166a174 100644
--- a/source/RobotAPI/libraries/armem/client/Writer.cpp
+++ b/source/RobotAPI/libraries/armem/client/Writer.cpp
@@ -5,7 +5,6 @@
 
 #include "../error.h"
 
-
 namespace armarx::armem::client
 {
 
@@ -13,7 +12,10 @@ namespace armarx::armem::client
     {
     }
 
-    data::AddSegmentResult Writer::addSegment(const std::string& coreSegmentName, const std::string& providerSegmentName, bool clearWhenExists)
+    data::AddSegmentResult
+    Writer::addSegment(const std::string& coreSegmentName,
+                       const std::string& providerSegmentName,
+                       bool clearWhenExists) const
     {
         data::AddSegmentInput input;
         input.coreSegmentName = coreSegmentName;
@@ -22,24 +24,30 @@ namespace armarx::armem::client
         return addSegment(input);
     }
 
-    data::AddSegmentResult Writer::addSegment(const MemoryID& providerSegmentID, bool clearWhenExists)
+    data::AddSegmentResult
+    Writer::addSegment(const MemoryID& providerSegmentID, bool clearWhenExists) const
     {
-        return addSegment(providerSegmentID.coreSegmentName, providerSegmentID.providerSegmentName, clearWhenExists);
+        return addSegment(providerSegmentID.coreSegmentName,
+                          providerSegmentID.providerSegmentName,
+                          clearWhenExists);
     }
 
-    data::AddSegmentResult Writer::addSegment(const std::pair<std::string, std::string>& names, bool clearWhenExists)
+    data::AddSegmentResult
+    Writer::addSegment(const std::pair<std::string, std::string>& names, bool clearWhenExists) const
     {
         return addSegment(names.first, names.second, clearWhenExists);
     }
 
-    data::AddSegmentResult Writer::addSegment(const data::AddSegmentInput& input)
+    data::AddSegmentResult
+    Writer::addSegment(const data::AddSegmentInput& input) const
     {
         data::AddSegmentsResult results = addSegments({input});
         ARMARX_CHECK_EQUAL(results.size(), 1);
         return results.at(0);
     }
 
-    data::AddSegmentsResult Writer::addSegments(const data::AddSegmentsInput& inputs)
+    data::AddSegmentsResult
+    Writer::addSegments(const data::AddSegmentsInput& inputs) const
     {
         ARMARX_CHECK_NOT_NULL(memory);
         data::AddSegmentsResult results = memory->addSegments(inputs);
@@ -47,8 +55,8 @@ namespace armarx::armem::client
         return results;
     }
 
-
-    CommitResult Writer::commit(const Commit& commit)
+    CommitResult
+    Writer::commit(const Commit& commit) const
     {
         ARMARX_CHECK_NOT_NULL(memory);
 
@@ -63,15 +71,15 @@ namespace armarx::armem::client
         return result;
     }
 
-
-    data::CommitResult Writer::commit(const data::Commit& _commit)
+    data::CommitResult
+    Writer::commit(const data::Commit& _commit) const
     {
         data::Commit commit = _commit;
         return this->_commit(commit);
     }
 
-
-    EntityUpdateResult Writer::commit(const EntityUpdate& update)
+    EntityUpdateResult
+    Writer::commit(const EntityUpdate& update) const
     {
         armem::Commit commit;
         commit.updates.push_back(update);
@@ -81,10 +89,10 @@ namespace armarx::armem::client
         return result.results.at(0);
     }
 
-    EntityUpdateResult Writer::commit(
-        const MemoryID& entityID,
-        const std::vector<aron::data::DictPtr>& instancesData,
-        Time referencedTime)
+    EntityUpdateResult
+    Writer::commit(const MemoryID& entityID,
+                   const std::vector<aron::data::DictPtr>& instancesData,
+                   Time referencedTime) const
     {
         EntityUpdate update;
         update.entityID = entityID;
@@ -99,7 +107,8 @@ namespace armarx::armem::client
         this->memory = memory;
     }
 
-    data::CommitResult Writer::_commit(data::Commit& commit)
+    data::CommitResult
+    Writer::_commit(data::Commit& commit) const
     {
         ARMARX_CHECK_NOT_NULL(memory);
 
@@ -119,11 +128,11 @@ namespace armarx::armem::client
         }
 
         data::CommitResult result;
-        auto handleError = [&commit, &result](const std::string & what)
+        auto handleError = [&commit, &result](const std::string& what)
         {
             for (const auto& _ : commit.updates)
             {
-                (void) _;
+                (void)_;
                 data::EntityUpdateResult& r = result.results.emplace_back();
                 r.success = false;
                 r.errorMessage = "Memory component not registered.\n" + std::string(what);
@@ -149,18 +158,20 @@ namespace armarx::armem::client
 
         return result;
     }
-}
+} // namespace armarx::armem::client
 
-
-std::ostream& armarx::armem::data::operator<<(std::ostream& os, const AddSegmentInput& rhs)
+std::ostream&
+armarx::armem::data::operator<<(std::ostream& os, const AddSegmentInput& rhs)
 {
     return os << "AddSegmentInput: "
-           << "\n- core segment:     \t'" << rhs.coreSegmentName << "'"
-           << "\n- provider segment: \t'" << rhs.providerSegmentName << "'"
-           << "\n- clear when exists:\t"  << rhs.clearWhenExists << ""
-           << "\n";
+              << "\n- core segment:     \t'" << rhs.coreSegmentName << "'"
+              << "\n- provider segment: \t'" << rhs.providerSegmentName << "'"
+              << "\n- clear when exists:\t" << rhs.clearWhenExists << ""
+              << "\n";
 }
-std::ostream& armarx::armem::data::operator<<(std::ostream& os, const AddSegmentsInput& rhs)
+
+std::ostream&
+armarx::armem::data::operator<<(std::ostream& os, const AddSegmentsInput& rhs)
 {
     for (size_t i = 0; i < rhs.size(); ++i)
     {
@@ -168,15 +179,18 @@ std::ostream& armarx::armem::data::operator<<(std::ostream& os, const AddSegment
     }
     return os;
 }
-std::ostream& armarx::armem::data::operator<<(std::ostream& os, const AddSegmentResult& rhs)
+
+std::ostream&
+armarx::armem::data::operator<<(std::ostream& os, const AddSegmentResult& rhs)
 {
     return os << "AddSegmentResult:"
-           << "\n- success:       \t" << rhs.success
-           << "\n- segment ID:    \t'" << rhs.segmentID << "'"
-           << "\n- error message: \t"  << rhs.errorMessage
-           << "\n";
+              << "\n- success:       \t" << rhs.success << "\n- segment ID:    \t'" << rhs.segmentID
+              << "'"
+              << "\n- error message: \t" << rhs.errorMessage << "\n";
 }
-std::ostream& armarx::armem::data::operator<<(std::ostream& os, const AddSegmentsResult& rhs)
+
+std::ostream&
+armarx::armem::data::operator<<(std::ostream& os, const AddSegmentsResult& rhs)
 {
     for (size_t i = 0; i < rhs.size(); ++i)
     {
diff --git a/source/RobotAPI/libraries/armem/client/Writer.h b/source/RobotAPI/libraries/armem/client/Writer.h
index 61eeef93be3164d79d09f6c5aa3371cb362b58b2..65d405a3736e62e39971e08928bd098c0e469636 100644
--- a/source/RobotAPI/libraries/armem/client/Writer.h
+++ b/source/RobotAPI/libraries/armem/client/Writer.h
@@ -32,28 +32,28 @@ namespace armarx::armem::client
 
         data::AddSegmentResult addSegment(const std::string& coreSegmentName,
                                           const std::string& providerSegmentName,
-                                          bool clearWhenExists = false);
+                                          bool clearWhenExists = false) const;
         data::AddSegmentResult addSegment(const MemoryID& providerSegmentID,
-                                          bool clearWhenExists = false);
+                                          bool clearWhenExists = false) const;
         data::AddSegmentResult addSegment(const std::pair<std::string, std::string>& names,
-                                          bool clearWhenExists = false);
-        data::AddSegmentResult addSegment(const data::AddSegmentInput& input);
-        data::AddSegmentsResult addSegments(const data::AddSegmentsInput& input);
+                                          bool clearWhenExists = false) const;
+        data::AddSegmentResult addSegment(const data::AddSegmentInput& input) const;
+        data::AddSegmentsResult addSegments(const data::AddSegmentsInput& input) const;
 
 
         /**
          * @brief Writes a `Commit` to the memory.
          */
-        CommitResult commit(const Commit& commit);
+        CommitResult commit(const Commit& commit) const;
         /// Commit a single entity update.
-        EntityUpdateResult commit(const EntityUpdate& update);
+        EntityUpdateResult commit(const EntityUpdate& update) const;
         /// Commit a single entity update.
         EntityUpdateResult commit(const MemoryID& entityID,
                                   const std::vector<aron::data::DictPtr>& instancesData,
-                                  Time referencedTime);
+                                  Time referencedTime) const;
 
         // with bare-ice types
-        data::CommitResult commit(const data::Commit& commit);
+        data::CommitResult commit(const data::Commit& commit) const;
 
 
         void setWritingMemory(server::WritingMemoryInterfacePrx memory);
@@ -65,7 +65,7 @@ namespace armarx::armem::client
 
     private:
         /// Sets `timeSent` on all entity updates and performs the commit,
-        data::CommitResult _commit(data::Commit& commit);
+        data::CommitResult _commit(data::Commit& commit) const;
 
 
     public:
diff --git a/source/RobotAPI/libraries/armem_objects/client/articulated_object/ArticulatedObjectReader.h b/source/RobotAPI/libraries/armem_objects/client/articulated_object/ArticulatedObjectReader.h
index ab0c5aa6d30a0bc0b377981c22f65d0d3b8c3ade..4bdcaac5bde3e0920c8e59f72cc06abd49875d55 100644
--- a/source/RobotAPI/libraries/armem_objects/client/articulated_object/ArticulatedObjectReader.h
+++ b/source/RobotAPI/libraries/armem_objects/client/articulated_object/ArticulatedObjectReader.h
@@ -15,8 +15,9 @@ namespace armarx::armem::articulated_object
                                                     const std::optional<std::string>& providerName,
                                                     const std::string& instanceName = "");
 
-        bool synchronizeArticulatedObject(VirtualRobot::Robot& object,
-                                          const armem::Time& timestamp,
-                                          const std::optional<std::string>& providerName);
+        [[nodiscard]] bool
+        synchronizeArticulatedObject(VirtualRobot::Robot& object,
+                                     const armem::Time& timestamp,
+                                     const std::optional<std::string>& providerName);
     };
 } // namespace armarx::armem::articulated_object
diff --git a/source/RobotAPI/libraries/armem_objects/client/articulated_object/Reader.cpp b/source/RobotAPI/libraries/armem_objects/client/articulated_object/Reader.cpp
index 16c83498cd59f65418d00f649031b750d4d44969..f21151f1982a28f852bc2b79215709cb0520e4f1 100644
--- a/source/RobotAPI/libraries/armem_objects/client/articulated_object/Reader.cpp
+++ b/source/RobotAPI/libraries/armem_objects/client/articulated_object/Reader.cpp
@@ -26,7 +26,6 @@
 
 #include "utils.h"
 
-namespace fs = ::std::filesystem;
 
 namespace armarx::armem::articulated_object
 {
@@ -100,7 +99,7 @@ namespace armarx::armem::articulated_object
     std::optional<ArticulatedObject>
     Reader::get(const std::string& name,
                 const armem::Time& timestamp,
-                const std::optional<std::string>& providerName)
+                const std::optional<std::string>& providerName) const
     {
         ARMARX_TRACE;
 
@@ -125,7 +124,7 @@ namespace armarx::armem::articulated_object
     Reader::get(const ArticulatedObjectDescription& description,
                 const armem::Time& timestamp,
                 const std::string& instanceName,
-                const std::optional<std::string>& providerName)
+                const std::optional<std::string>& providerName) const
     {
         ARMARX_TRACE;
 
@@ -142,7 +141,7 @@ namespace armarx::armem::articulated_object
     bool
     Reader::synchronize(ArticulatedObject& obj,
                         const armem::Time& timestamp,
-                        const std::optional<std::string>& providerName)
+                        const std::optional<std::string>& providerName) const
     {
         ARMARX_TRACE;
 
@@ -164,7 +163,7 @@ namespace armarx::armem::articulated_object
 
     std::vector<robot::RobotDescription>
     Reader::queryDescriptions(const armem::Time& timestamp,
-                              const std::optional<std::string>& providerName)
+                              const std::optional<std::string>& providerName) const
     {
         ARMARX_TRACE;
         // Query all entities from provider.
@@ -209,7 +208,7 @@ namespace armarx::armem::articulated_object
     std::optional<robot::RobotDescription>
     Reader::queryDescription(const std::string& name,
                              const armem::Time& timestamp,
-                             const std::optional<std::string>& providerName)
+                             const std::optional<std::string>& providerName) const
     {
         ARMARX_TRACE;
 
@@ -256,7 +255,7 @@ namespace armarx::armem::articulated_object
     std::optional<robot::RobotState>
     Reader::queryState(const std::string& instanceName,
                        const armem::Time& timestamp,
-                       const std::optional<std::string>& providerName)
+                       const std::optional<std::string>& providerName) const
     {
         ARMARX_TRACE;
 
diff --git a/source/RobotAPI/libraries/armem_objects/client/articulated_object/Reader.h b/source/RobotAPI/libraries/armem_objects/client/articulated_object/Reader.h
index 0eb5bd104f4de49f3b7dfa6cc14ce232a99933fc..50c342c0cfc87614505df230ecdc3fce9cd8b43b 100644
--- a/source/RobotAPI/libraries/armem_objects/client/articulated_object/Reader.h
+++ b/source/RobotAPI/libraries/armem_objects/client/articulated_object/Reader.h
@@ -26,13 +26,17 @@
 
 #include <VirtualRobot/VirtualRobot.h>
 
-#include <ArmarXCore/core/application/properties/PropertyDefinitionContainer.h>
+#include "ArmarXCore/core/application/properties/forward_declarations.h"
 
-#include <RobotAPI/libraries/armem/client/MemoryNameSystem.h>
 #include <RobotAPI/libraries/armem/client/Reader.h>
+#include <RobotAPI/libraries/armem/client/forward_declarations.h>
 
 #include "interfaces.h"
 
+// #include <ArmarXCore/core/application/properties/PropertyDefinitionContainer.h>
+// #include <RobotAPI/libraries/armem/client/MemoryNameSystem.h>
+
+
 namespace armarx::armem::articulated_object
 {
 
@@ -40,7 +44,7 @@ namespace armarx::armem::articulated_object
     {
     public:
         Reader() = default;
-        virtual ~Reader() = default;
+        ~Reader() override = default;
 
         void
         registerPropertyDefinitions(armarx::PropertyDefinitionsPtr& def)
@@ -49,30 +53,30 @@ namespace armarx::armem::articulated_object
 
         void connect(armem::client::MemoryNameSystem& memoryNameSystem);
 
-        bool synchronize(ArticulatedObject& obj,
+        [[nodiscard]] bool synchronize(ArticulatedObject& obj,
                          const armem::Time& timestamp,
-                         const std::optional<std::string>& providerName) override;
+                         const std::optional<std::string>& providerName) const override;
 
         std::optional<ArticulatedObject>
         get(const std::string& name,
             const armem::Time& timestamp,
-            const std::optional<std::string>& providerName) override;
+            const std::optional<std::string>& providerName) const override;
         ArticulatedObject get(const ArticulatedObjectDescription& description,
                               const armem::Time& timestamp,
                               const std::string& instanceName,
-                              const std::optional<std::string>& providerName) override;
+                              const std::optional<std::string>& providerName) const override;
 
         std::optional<robot::RobotState> queryState(const std::string& instanceName,
                                                     const armem::Time& timestamp,
-                                                    const std::optional<std::string>& providerName);
+                                                    const std::optional<std::string>& providerName) const;
         std::optional<robot::RobotDescription>
         queryDescription(const std::string& name,
                          const armem::Time& timestamp,
-                         const std::optional<std::string>& providerName);
+                         const std::optional<std::string>& providerName) const;
 
         std::vector<robot::RobotDescription>
         queryDescriptions(const armem::Time& timestamp,
-                          const std::optional<std::string>& providerName);
+                          const std::optional<std::string>& providerName) const;
 
         std::string getProviderName() const;
         void setProviderName(const std::string& providerName);
diff --git a/source/RobotAPI/libraries/armem_objects/client/articulated_object/Writer.cpp b/source/RobotAPI/libraries/armem_objects/client/articulated_object/Writer.cpp
index c507fd90594bb6b300080f737d6263a5025417dc..4df7921025ba582a4a913a0fa88906959137b3bb 100644
--- a/source/RobotAPI/libraries/armem_objects/client/articulated_object/Writer.cpp
+++ b/source/RobotAPI/libraries/armem_objects/client/articulated_object/Writer.cpp
@@ -103,7 +103,7 @@ namespace armarx::armem::articulated_object
     }
 
     std::optional<armem::MemoryID>
-    Writer::storeOrGetClass(const ArticulatedObject& obj)
+    Writer::storeOrGetClass(const ArticulatedObject& obj) const
     {
         ARMARX_TRACE;
 
@@ -129,7 +129,7 @@ namespace armarx::armem::articulated_object
     }
 
     std::optional<armem::MemoryID>
-    Writer::storeClass(const ArticulatedObject& obj)
+    Writer::storeClass(const ArticulatedObject& obj) const
     {
         std::lock_guard g{memoryWriterMutex};
 
@@ -190,7 +190,7 @@ namespace armarx::armem::articulated_object
     }
 
     bool
-    Writer::storeInstance(const ArticulatedObject& obj)
+    Writer::storeInstance(const ArticulatedObject& obj) const
     {
         std::lock_guard g{memoryWriterMutex};
 
@@ -259,7 +259,7 @@ namespace armarx::armem::articulated_object
     }
 
     bool
-    Writer::store(const ArticulatedObject& obj)
+    Writer::store(const ArticulatedObject& obj) const
     {
         const std::optional<armem::MemoryID> classId = storeOrGetClass(obj);
 
diff --git a/source/RobotAPI/libraries/armem_objects/client/articulated_object/Writer.h b/source/RobotAPI/libraries/armem_objects/client/articulated_object/Writer.h
index 6245ef374edc289afa452900ee97e769ed4eae8b..bf1c7d9459654c422f27c26b8cab9c9e6ae9b20f 100644
--- a/source/RobotAPI/libraries/armem_objects/client/articulated_object/Writer.h
+++ b/source/RobotAPI/libraries/armem_objects/client/articulated_object/Writer.h
@@ -39,16 +39,16 @@ namespace armarx::armem::articulated_object
     {
     public:
         Writer() = default;
-        virtual ~Writer() = default;
+        ~Writer() override = default;
 
         void registerPropertyDefinitions(armarx::PropertyDefinitionsPtr& def);
         void connect(armem::client::MemoryNameSystem& memoryNameSystem);
 
 
-        bool store(const ArticulatedObject& obj) override;
+        bool store(const ArticulatedObject& obj) const override;
 
-        bool storeInstance(const ArticulatedObject& obj);
-        std::optional<armem::MemoryID> storeClass(const ArticulatedObject& obj);
+        bool storeInstance(const ArticulatedObject& obj) const;
+        std::optional<armem::MemoryID> storeClass(const ArticulatedObject& obj) const;
 
         // const std::string& getPropertyPrefix() const override;
 
@@ -57,7 +57,7 @@ namespace armarx::armem::articulated_object
 
 
     private:
-        std::optional<armem::MemoryID> storeOrGetClass(const ArticulatedObject& obj);
+        std::optional<armem::MemoryID> storeOrGetClass(const ArticulatedObject& obj) const;
 
         void updateKnownObjects(const armem::MemoryID& subscriptionID,
                                 const std::vector<armem::MemoryID>& snapshotIDs);
@@ -85,13 +85,13 @@ namespace armarx::armem::articulated_object
         const std::string propertyPrefix = "mem.obj.articulated.";
 
         armem::client::Writer memoryWriter;
-        std::mutex memoryWriterMutex;
+        mutable std::mutex memoryWriterMutex;
 
         armem::client::Reader memoryReader;
-        std::mutex memoryReaderMutex;
+        mutable std::mutex memoryReaderMutex;
 
         // key: name of object: RobotDescription::name
-        std::unordered_map<std::string, MemoryID> knownObjects;
+        mutable std::unordered_map<std::string, MemoryID> knownObjects;
     };
 
 
diff --git a/source/RobotAPI/libraries/armem_objects/client/articulated_object/interfaces.h b/source/RobotAPI/libraries/armem_objects/client/articulated_object/interfaces.h
index 6031eba4bfd1288d6567b946a0dd359018482792..899cb1e79ac7ada7991e064b2a1ae1c20310749a 100644
--- a/source/RobotAPI/libraries/armem_objects/client/articulated_object/interfaces.h
+++ b/source/RobotAPI/libraries/armem_objects/client/articulated_object/interfaces.h
@@ -11,19 +11,26 @@ namespace armarx::armem::articulated_object
     public:
         virtual ~ReaderInterface() = default;
 
-        virtual bool synchronize(ArticulatedObject& obj, const armem::Time& timestamp, const std::optional<std::string>& providerName) = 0;
-
-        virtual ArticulatedObject get(const ArticulatedObjectDescription& description, const armem::Time& timestamp, const std::string& instanceName, const std::optional<std::string>& providerName) = 0;
-        virtual std::optional<ArticulatedObject> get(const std::string& name, const armem::Time& timestamp, const std::optional<std::string>& providerName) = 0;
+        virtual bool synchronize(ArticulatedObject& obj,
+                                 const armem::Time& timestamp,
+                                 const std::optional<std::string>& providerName) const = 0;
+
+        virtual ArticulatedObject get(const ArticulatedObjectDescription& description,
+                                      const armem::Time& timestamp,
+                                      const std::string& instanceName,
+                                      const std::optional<std::string>& providerName) const = 0;
+        virtual std::optional<ArticulatedObject>
+        get(const std::string& name,
+            const armem::Time& timestamp,
+            const std::optional<std::string>& providerName) const = 0;
     };
 
-
     class WriterInterface
     {
     public:
         virtual ~WriterInterface() = default;
 
-        virtual bool store(const ArticulatedObject& obj) = 0;
+        virtual bool store(const ArticulatedObject& obj) const = 0;
     };
 
-}  // namespace armarx::armem::articulated_object
+} // namespace armarx::armem::articulated_object
diff --git a/source/RobotAPI/libraries/armem_robot_state/server/proprioception/converters/ConverterRegistry.cpp b/source/RobotAPI/libraries/armem_robot_state/server/proprioception/converters/ConverterRegistry.cpp
index 0c6baa3b770e2136543be7885b1e856a7e93bb78..4c2d920267eb05f799f66e08f26d3ae48b1ee811 100644
--- a/source/RobotAPI/libraries/armem_robot_state/server/proprioception/converters/ConverterRegistry.cpp
+++ b/source/RobotAPI/libraries/armem_robot_state/server/proprioception/converters/ConverterRegistry.cpp
@@ -13,6 +13,7 @@ namespace armarx::armem::server::robot_state::proprioception
         add<Armar6Converter>("Armar6");
         add<Armar6Converter>("ArmarDE");
         add<Armar6Converter>("Armar7");
+        add<Armar6Converter>("Frankie");
     }