diff --git a/source/RobotAPI/components/ObjectPoseObserver/ObjectPoseObserver.cpp b/source/RobotAPI/components/ObjectPoseObserver/ObjectPoseObserver.cpp
index 31c31934b335d79b7eb426e6606179c21d910546..a29e434694593cdb0f87f4e524b1fbafbbc25cf3 100644
--- a/source/RobotAPI/components/ObjectPoseObserver/ObjectPoseObserver.cpp
+++ b/source/RobotAPI/components/ObjectPoseObserver/ObjectPoseObserver.cpp
@@ -34,6 +34,7 @@
 #include <RobotAPI/libraries/core/FramedPose.h>
 #include <RobotAPI/libraries/ArmarXObjects/ice_conversions.h>
 
+
 namespace armarx
 {
 
@@ -47,6 +48,7 @@ namespace armarx
         armarx::PropertyDefinitionsPtr defs(new ObjectPoseObserverPropertyDefinitions(getConfigIdentifier()));
 
         defs->defineOptionalProperty<std::string>("ObjectPoseTopicName", "ObjectPoseTopic", "Name of the Object Pose Topic.");
+        defs->defineOptionalProperty<std::string>("KinematicUnitObserverName", "KinematicUnitObserver", "Name of the kinematic unit observer.");
 
         defs->optional(visu.enabled, "visu.enabled", "Enable or disable visualization of objects.");
         defs->optional(visu.inGlobalFrame, "visu.inGlobalFrame", "If true, show global poses. If false, show poses in robot frame.");
@@ -54,8 +56,11 @@ namespace armarx
         defs->optional(visu.oobbs, "visu.oobbs", "Enable showing oriented bounding boxes.");
         defs->optional(visu.objectFrames, "visu.objectFrames", "Enable showing object frames.");
         defs->optional(visu.objectFramesScale, "visu.objectFramesScale", "Scaling of object frames.");
-        defs->optional(calibration.robotNode, "calibration.robotNode", "Robot node which can be calibrated");
-        defs->optional(calibration.offset, "calibration.offset", "Offset for the node to be calibrated");
+        defs->optional(calibration.robotNode, "calibration.robotNode", "Robot node which can be calibrated.");
+        defs->optional(calibration.offset, "calibration.offset", "Offset for the node to be calibrated.");
+        defs->optional(robotHead.checkHeadVelocity, "head.checkHeadVelocity", "If true, check whether the head is moving.");
+        defs->optional(robotHead.maxJointVelocity, "head.maxJointVelocity", "If a head joint's velocity is higher, the head is considered moving.");
+        defs->optional(robotHead.discardIntervalAfterMoveMS, "head.discardIntervalAfterMoveMS", "For how long new updates are ignored after moving the head.");
 
         return defs;
     }
@@ -79,6 +84,9 @@ namespace armarx
             robot = RobotState::addRobot("robot", VirtualRobot::RobotIO::RobotDescription::eStructure);
         }
 
+        getProxyFromProperty(robotHead.kinematicUnitObserver, "KinematicUnitObserverName", false, "", false);
+        robotHead.fetchDatafields();
+
         createRemoteGuiTab();
         RemoteGui_startRunningTask();
     }
@@ -159,7 +167,25 @@ namespace armarx
     {
         ARMARX_VERBOSE << "Received object poses from '" << providerName << "'.";
 
-        objpose::ObjectPoseSeq objectPoses;
+        IceUtil::Time discardUpdatesUntil;
+        if (robotHead.checkHeadVelocity)
+        {
+            std::scoped_lock lock(robotHeadMutex);
+            if (robotHead.isMoving())
+            {
+                robotHead.discardUpdatesUntil = TimeUtil::GetTime() + IceUtil::Time::milliSeconds(robotHead.discardIntervalAfterMoveMS);
+                // ARMARX_IMPORTANT << "Ignoring update because robot head is moving! until " << robotHead.discardUpdatesUntil;
+                return;
+            }
+            if (TimeUtil::GetTime() < robotHead.discardUpdatesUntil)
+            {
+                // ARMARX_IMPORTANT << "Ignoring update because robot head is moved until: " << robotHead.discardUpdatesUntil;
+                return;
+            }
+            discardUpdatesUntil = robotHead.discardUpdatesUntil;
+        }
+
+        objpose::ObjectPoseSeq newObjectPoses;
         {
             std::scoped_lock lock(dataMutex);
             RobotState::synchronizeLocalClone(robot);
@@ -171,28 +197,68 @@ namespace armarx
                 robotNode->setJointValue(value + calibration.offset);
             }
 
+            // This stays empty on the first report.
+            objpose::ObjectPoseSeq previousPoses;
+            if (auto it = this->objectPoses.find(providerName); it != this->objectPoses.end())
+            {
+                previousPoses = it->second;
+            }
+
             for (const objpose::data::ProvidedObjectPose& provided : providedPoses)
             {
-                objpose::ObjectPose& pose = objectPoses.emplace_back();
-                pose.fromProvidedPose(provided, robot);
-                if (pose.objectID.dataset().empty())
+                IceUtil::Time timestamp = IceUtil::Time::microSeconds(provided.timestampMicroSeconds);
+
+                std::optional<objpose::ObjectPose> previousPose;
+                for (const objpose::ObjectPose& prev : previousPoses)
                 {
-                    // Try to find the data set. (It might be good to cache this.)
-                    if (std::optional<ObjectInfo> objectInfo = objectFinder.findObject(pose.objectID))
+                    if (prev.objectID == fromIce(provided.objectID))
                     {
-                        pose.objectID = { objectInfo->dataset(), pose.objectID.className(), pose.objectID.instanceName() };
+                        previousPose = prev;
                     }
                 }
-                if (!provided.localOOBB)
+
+                if (robotHead.checkHeadVelocity && timestamp < discardUpdatesUntil)
                 {
-                    pose.localOOBB = getObjectOOBB(pose.objectID);
+                    if (previousPose)
+                    {
+                        // Keep the old one
+                        newObjectPoses.push_back(*previousPose);
+                    }
+                    else
+                    {
+                        // Discard the new pose.
+                        // ARMARX_IMPORTANT << "Ignoring update of object " << provided.objectID << " because robot head is moved.\n"
+                        //                  << "timestamp " << timestamp << " < " << robotHead.discardUpdatesUntil;
+                    }
+                }
+                else if (previousPose && timestamp == previousPose->timestamp)
+                {
+                    // Keep the old one.
+                    newObjectPoses.push_back(*previousPose);
+                }
+                else
+                {
+                    objpose::ObjectPose& newPose = newObjectPoses.emplace_back();
+                    newPose.fromProvidedPose(provided, robot);
+                    if (newPose.objectID.dataset().empty())
+                    {
+                        // Try to find the data set. (It might be good to cache this.)
+                        if (std::optional<ObjectInfo> objectInfo = objectFinder.findObject(newPose.objectID))
+                        {
+                            newPose.objectID = { objectInfo->dataset(), newPose.objectID.className(), newPose.objectID.instanceName() };
+                        }
+                    }
+                    if (!provided.localOOBB)
+                    {
+                        newPose.localOOBB = getObjectOOBB(newPose.objectID);
+                    }
                 }
             }
         }
 
         {
             std::scoped_lock lock(dataMutex);
-            this->objectPoses[providerName] = objectPoses;
+            this->objectPoses[providerName] = newObjectPoses;
             handleProviderUpdate(providerName);
         }
     }
@@ -760,5 +826,55 @@ namespace armarx
         }
     }
 
+    void ObjectPoseObserver::RobotHead::fetchDatafields()
+    {
+        if (kinematicUnitObserver)
+        {
+            for (const std::string& jointName : jointNames)
+            {
+                std::string error = "";
+                try
+                {
+                    DatafieldRefBasePtr datafield = kinematicUnitObserver->getDatafieldRefByName(jointVelocitiesChannelName, jointName);
+                    DatafieldRefPtr casted = DatafieldRefPtr::dynamicCast(datafield);
+                    if (casted)
+                    {
+                        jointVelocitiesDatafields.push_back(casted);
+                    }
+                }
+                catch (const InvalidDatafieldException& e)
+                {
+                    error = e.what();
+                }
+                catch (const InvalidChannelException& e)
+                {
+                    error = e.what();
+                }
+                if (error.size() > 0)
+                {
+                    ARMARX_WARNING_S << "Could not get datafield for joint '" << jointName << "' in channel '" << jointVelocitiesChannelName << "': \n "
+                                     << error;
+                }
+            }
+        }
+    }
+
+    bool ObjectPoseObserver::RobotHead::isMoving() const
+    {
+        for (DatafieldRefPtr df : jointVelocitiesDatafields)
+        {
+            if (df)
+            {
+                float jointVelocity = df->getFloat();
+                // ARMARX_IMPORTANT_S << "Is " << df->datafieldName << " " << VAROUT(std::abs(jointVelocity)) << " > " << VAROUT(maxJointVelocity) << "?";
+                if (std::abs(jointVelocity) > maxJointVelocity)
+                {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
 }
 
diff --git a/source/RobotAPI/components/ObjectPoseObserver/ObjectPoseObserver.h b/source/RobotAPI/components/ObjectPoseObserver/ObjectPoseObserver.h
index 70a0e80abdb6983e58205c44d3a3c3ccc2ea3de3..1d5809452645dd1b7952a87ced9d8d05898fc44d 100644
--- a/source/RobotAPI/components/ObjectPoseObserver/ObjectPoseObserver.h
+++ b/source/RobotAPI/components/ObjectPoseObserver/ObjectPoseObserver.h
@@ -27,10 +27,12 @@
 #include <SimoxUtility/caching/CacheMap.h>
 
 #include <ArmarXCore/observers/Observer.h>
+#include <ArmarXCore/observers/variant/DatafieldRef.h>
 
 #include <ArmarXGui/libraries/ArmarXGuiComponentPlugins/LightweightRemoteGuiComponentPlugin.h>
 
 #include <RobotAPI/interface/objectpose/ObjectPoseObserver.h>
+#include <RobotAPI/interface/observers/KinematicUnitObserverInterface.h>
 #include <RobotAPI/libraries/RobotAPIComponentPlugins/ArVizComponentPlugin.h>
 #include <RobotAPI/libraries/RobotAPIComponentPlugins/RobotStateComponentPlugin.h>
 #include <RobotAPI/libraries/ArmarXObjects/ObjectFinder.h>
@@ -158,6 +160,25 @@ namespace armarx
 
         VirtualRobot::RobotPtr robot;
 
+        struct RobotHead
+        {
+            bool checkHeadVelocity = true;
+
+            std::string jointVelocitiesChannelName = "jointvelocities";
+            std::vector<std::string> jointNames = {"Neck_1_Yaw", "Neck_2_Pitch"};
+            float maxJointVelocity = 0.05;
+            int discardIntervalAfterMoveMS = 100;
+
+            KinematicUnitObserverInterfacePrx kinematicUnitObserver;
+            std::vector<DatafieldRefPtr> jointVelocitiesDatafields;
+            IceUtil::Time discardUpdatesUntil = IceUtil::Time::seconds(-1);
+
+            void fetchDatafields();
+            bool isMoving() const;
+        };
+        RobotHead robotHead;
+        std::mutex robotHeadMutex;
+
 
         objpose::ProviderInfoMap providers;
 
@@ -190,6 +211,8 @@ namespace armarx
         Calibration calibration;
 
 
+
+
         struct RemoteGuiTab : RemoteGui::Client::Tab
         {
             RemoteGui::Client::CheckBox visuEnabled;
diff --git a/source/RobotAPI/components/armem/ArMemDebugMemory/ArMemDebugMemory.cpp b/source/RobotAPI/components/armem/ArMemDebugMemory/ArMemDebugMemory.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..859bbd4a23a6dd324ae884bd1aa0cf4cb6dcb804
--- /dev/null
+++ b/source/RobotAPI/components/armem/ArMemDebugMemory/ArMemDebugMemory.cpp
@@ -0,0 +1,130 @@
+/*
+ * 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::ArMemDebugMemory
+ * @author     Rainer Kartmann ( rainer dot kartmann at kit dot edu )
+ * @date       2020
+ * @copyright  http://www.gnu.org/licenses/gpl-2.0.txt
+ *             GNU General Public License
+ */
+
+#include "ArMemDebugMemory.h"
+
+#include <ArmarXCore/core/exceptions/local/ExpressionException.h>
+
+#include <SimoxUtility/algorithm/string.h>
+
+#include <RobotAPI/libraries/armem/core/error.h>
+#include <RobotAPI/libraries/armem/server/MemoryRemoteGui.h>
+
+namespace armarx
+{
+    ArMemDebugMemoryPropertyDefinitions::ArMemDebugMemoryPropertyDefinitions(std::string prefix) :
+        armarx::ComponentPropertyDefinitions(prefix)
+    {
+    }
+
+    ArMemDebugMemory::ArMemDebugMemory()
+    {
+    }
+
+    armarx::PropertyDefinitionsPtr ArMemDebugMemory::createPropertyDefinitions()
+    {
+        armarx::PropertyDefinitionsPtr defs = new ArMemDebugMemoryPropertyDefinitions(getConfigIdentifier());
+
+        defs->topic(debugObserver);
+        return defs;
+    }
+
+
+    std::string ArMemDebugMemory::getDefaultName() const
+    {
+        return "ArMemDebugMemory";
+    }
+
+
+    void ArMemDebugMemory::onInitComponent()
+    {
+        memory.name() = memoryName;
+    }
+
+
+    void ArMemDebugMemory::onConnectComponent()
+    {
+        RemoteGui__createTab();
+        RemoteGui_startRunningTask();
+    }
+
+
+    void ArMemDebugMemory::onDisconnectComponent()
+    {
+    }
+
+
+    void ArMemDebugMemory::onExitComponent()
+    {
+    }
+
+
+
+    // WRITING
+    armem::data::AddSegmentsResult ArMemDebugMemory::addSegments(const armem::data::AddSegmentsInput& input, const Ice::Current&)
+    {
+        armem::data::AddSegmentsResult result = ComponentPluginUser::addSegments(input, addCoreSegmentOnUsage);
+        tab.rebuild = true;
+        return result;
+    }
+
+
+    armem::data::CommitResult ArMemDebugMemory::commit(const armem::data::Commit& commit, const Ice::Current&)
+    {
+        armem::data::CommitResult result = ComponentPluginUser::commit(commit);
+        tab.rebuild = true;
+        return result;
+    }
+
+
+    // READING
+
+    // Inherited from Plugin
+
+
+
+    // REMOTE GUI
+
+    void ArMemDebugMemory::RemoteGui__createTab()
+    {
+        using namespace armarx::RemoteGui::Client;
+
+        armem::server::MemoryRemoteGui mrg;
+        {
+            std::scoped_lock lock(memoryMutex);
+            tab.memoryGroup = mrg.makeGroupBox(memory);
+        }
+
+        VBoxLayout root = {tab.memoryGroup, VSpacer()};
+        RemoteGui_createTab(getName(), root, &tab);
+    }
+
+
+    void ArMemDebugMemory::RemoteGui_update()
+    {
+        if (tab.rebuild.exchange(false))
+        {
+            RemoteGui__createTab();
+        }
+    }
+
+}
diff --git a/source/RobotAPI/components/armem/ArMemDebugMemory/ArMemDebugMemory.h b/source/RobotAPI/components/armem/ArMemDebugMemory/ArMemDebugMemory.h
new file mode 100644
index 0000000000000000000000000000000000000000..568f22c1674e319cdfc0d4eca37618ee314a9835
--- /dev/null
+++ b/source/RobotAPI/components/armem/ArMemDebugMemory/ArMemDebugMemory.h
@@ -0,0 +1,115 @@
+/*
+ * 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::ArMemDebugMemory
+ * @author     Rainer Kartmann ( rainer dot kartmann at kit dot edu )
+ * @date       2020
+ * @copyright  http://www.gnu.org/licenses/gpl-2.0.txt
+ *             GNU General Public License
+ */
+
+#pragma once
+
+
+#include <ArmarXCore/core/Component.h>
+
+#include <ArmarXCore/interface/observers/ObserverInterface.h>
+#include <ArmarXGui/libraries/ArmarXGuiComponentPlugins/LightweightRemoteGuiComponentPlugin.h>
+#include <RobotAPI/libraries/RobotAPIComponentPlugins/ArVizComponentPlugin.h>
+
+#include <RobotAPI/libraries/armem/server/ComponentPlugin.h>
+
+
+namespace armarx
+{
+    /**
+     * @class ArMemDebugMemoryPropertyDefinitions
+     * @brief Property definitions of `ArMemDebugMemory`.
+     */
+    class ArMemDebugMemoryPropertyDefinitions :
+        public armarx::ComponentPropertyDefinitions
+    {
+    public:
+        ArMemDebugMemoryPropertyDefinitions(std::string prefix);
+    };
+
+
+    /**
+     * @defgroup Component-ArMemDebugMemory ArMemDebugMemory
+     * @ingroup RobotAPI-Components
+     * A description of the component ArMemDebugMemory.
+     *
+     * @class ArMemDebugMemory
+     * @ingroup Component-ArMemDebugMemory
+     * @brief Brief description of class ArMemDebugMemory.
+     *
+     * Detailed description of class ArMemDebugMemory.
+     */
+    class ArMemDebugMemory :
+        virtual public armarx::Component
+        , virtual public armem::server::ComponentPluginUser
+        , virtual public LightweightRemoteGuiComponentPluginUser
+    // , virtual public armarx::ArVizComponentPluginUser
+    {
+    public:
+        ArMemDebugMemory();
+
+        /// @see armarx::ManagedIceObject::getDefaultName()
+        std::string getDefaultName() const override;
+
+        // WritingInterface interface
+    public:
+        armem::data::AddSegmentsResult addSegments(const armem::data::AddSegmentsInput& input, const Ice::Current&) override;
+        armem::data::CommitResult commit(const armem::data::Commit& commit, const Ice::Current&) override;
+
+        // LightweightRemoteGuiComponentPluginUser interface
+    public:
+        void RemoteGui__createTab();
+        void RemoteGui_update() override;
+
+
+    protected:
+        /// @see armarx::ManagedIceObject::onInitComponent()
+        void onInitComponent() override;
+
+        /// @see armarx::ManagedIceObject::onConnectComponent()
+        void onConnectComponent() override;
+
+        /// @see armarx::ManagedIceObject::onDisconnectComponent()
+        void onDisconnectComponent() override;
+
+        /// @see armarx::ManagedIceObject::onExitComponent()
+        void onExitComponent() override;
+
+        /// @see PropertyUser::createPropertyDefinitions()
+        armarx::PropertyDefinitionsPtr createPropertyDefinitions() override;
+
+
+    private:
+        /// Debug observer. Used to visualize e.g. time series.
+        armarx::DebugObserverInterfacePrx debugObserver;
+
+        std::string memoryName = "DebugMemory";
+        bool addCoreSegmentOnUsage = true;
+
+        struct RemoteGuiTab : RemoteGui::Client::Tab
+        {
+            std::atomic_bool rebuild = false;
+            RemoteGui::Client::GroupBox memoryGroup;
+        };
+        RemoteGuiTab tab;
+
+    };
+}
diff --git a/source/RobotAPI/components/armem/ArMemDebugMemory/CMakeLists.txt b/source/RobotAPI/components/armem/ArMemDebugMemory/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..017e1709df01b4becba5b6aef90fa3dc031399a0
--- /dev/null
+++ b/source/RobotAPI/components/armem/ArMemDebugMemory/CMakeLists.txt
@@ -0,0 +1,37 @@
+armarx_component_set_name("ArMemDebugMemory")
+
+find_package(IVT QUIET)
+armarx_build_if(IVT_FOUND "IVT not available")
+
+
+set(COMPONENT_LIBS
+    ArmarXCore ArmarXCoreInterfaces  # for DebugObserverInterface
+    ArmarXGuiComponentPlugins
+    RobotAPICore RobotAPIInterfaces armem
+    # RobotAPIComponentPlugins  # for ArViz and other plugins
+
+    ${IVT_LIBRARIES}
+)
+
+set(SOURCES
+    ArMemDebugMemory.cpp
+)
+set(HEADERS
+    ArMemDebugMemory.h
+)
+
+
+armarx_add_component("${SOURCES}" "${HEADERS}")
+if (IVT_FOUND)
+    target_include_directories(${ARMARX_COMPONENT_NAME} PUBLIC ${IVT_INCLUDE_DIRS})
+endif()
+
+
+# add unit tests
+# add_subdirectory(test)
+
+#generate the application
+armarx_generate_and_add_component_executable()
+
+
+
diff --git a/source/RobotAPI/components/armem/ArMemExampleMemory/xmls/ExampleData.xml b/source/RobotAPI/components/armem/ArMemDebugMemory/xmls/ExampleData.xml
similarity index 100%
rename from source/RobotAPI/components/armem/ArMemExampleMemory/xmls/ExampleData.xml
rename to source/RobotAPI/components/armem/ArMemDebugMemory/xmls/ExampleData.xml
diff --git a/source/RobotAPI/components/armem/ArMemExampleMemory/CMakeLists.txt b/source/RobotAPI/components/armem/ArMemExampleMemory/CMakeLists.txt
index 6cbc35ed322c3c1a941b7ef1c1cecc3e8d9ead81..c02d06dd2fc8aae51f745685e8fcb29a2b3fc696 100644
--- a/source/RobotAPI/components/armem/ArMemExampleMemory/CMakeLists.txt
+++ b/source/RobotAPI/components/armem/ArMemExampleMemory/CMakeLists.txt
@@ -31,12 +31,12 @@ armarx_enable_aron_file_generation_for_target(
     TARGET_NAME
         ${ARMARX_COMPONENT_NAME}
     ARON_FILES
-        xmls/ExampleData.xml
+        aron/ExampleData.xml
 )
 
 
 # add unit tests
-# add_subdirectory(test)
+add_subdirectory(test)
 
 #generate the application
 armarx_generate_and_add_component_executable()
diff --git a/source/RobotAPI/components/armem/ArMemExampleMemory/aron/ExampleData.xml b/source/RobotAPI/components/armem/ArMemExampleMemory/aron/ExampleData.xml
new file mode 100644
index 0000000000000000000000000000000000000000..0cd92acebcb91a793a58a7ce09896ac8c2f91214
--- /dev/null
+++ b/source/RobotAPI/components/armem/ArMemExampleMemory/aron/ExampleData.xml
@@ -0,0 +1,86 @@
+<!--Some fancy comment -->
+<?xml version="1.0" encoding="UTF-8" ?>
+<AronTypeDefinition>
+  <CodeIncludes>
+    <Include include="<Eigen/Core>" />
+    <Include include="<Image/ByteImage.h>" />
+  </CodeIncludes>
+  <GenerateTypes>
+    <GenerateType name='armarx::armem::aron::example::ExampleData'>
+      <ObjectChild key='the_int'>
+        <Int />
+      </ObjectChild>
+      <ObjectChild key='the_long'>
+        <Long />
+      </ObjectChild>
+      <ObjectChild key='the_float'>
+        <Float />
+      </ObjectChild>
+      <ObjectChild key='the_double'>
+        <Double />
+      </ObjectChild>
+      <ObjectChild key='the_string'>
+        <String />
+      </ObjectChild>
+      <ObjectChild key='the_bool'>
+        <Bool />
+      </ObjectChild>
+
+
+      <ObjectChild key='the_eigen_position'>
+        <EigenMatrix rows="3" cols="1" type="float" />
+      </ObjectChild>
+      <ObjectChild key='the_eigen_pose'>
+        <EigenMatrix rows="4" cols="4" type="float" />
+      </ObjectChild>
+      <ObjectChild key='the_ivt_image'>
+        <IVTCByteImage type="GrayScale" />
+      </ObjectChild>
+
+
+      <ObjectChild key='the_float_list'>
+        <List>
+          <Float />
+        </List>
+      </ObjectChild>
+      <ObjectChild key='the_int_list'>
+        <List>
+          <Int />
+        </List>
+      </ObjectChild>
+      <ObjectChild key='the_string_list'>
+        <List>
+          <String />
+        </List>
+      </ObjectChild>
+
+      <ObjectChild key='the_object_list'>
+        <List>
+          <Object name='ListClass'>
+            <ObjectChild key='element_int'>
+              <Int />
+            </ObjectChild>
+            <ObjectChild key='element_float'>
+              <Float />
+            </ObjectChild>
+            <ObjectChild key='element_string'>
+              <String />
+            </ObjectChild>
+          </Object>
+        </List>
+      </ObjectChild>
+
+      <ObjectChild key='the_float_dict'>
+        <Dict>
+          <Float />
+        </Dict>
+      </ObjectChild>
+      <ObjectChild key='the_int_dict'>
+        <Dict>
+          <Int />
+        </Dict>
+      </ObjectChild>
+
+    </GenerateType>
+  </GenerateTypes>
+</AronTypeDefinition>
diff --git a/source/RobotAPI/components/armem/ArMemExampleMemory/test/ArMemExampleMemoryTest.cpp b/source/RobotAPI/components/armem/ArMemExampleMemory/test/ArMemExampleMemoryTest.cpp
index e8a7cc5fc9bfd76db190055f788e78c4d1212f55..1665316aa33d755c2dcd06e88e0a7bc37aebf864 100644
--- a/source/RobotAPI/components/armem/ArMemExampleMemory/test/ArMemExampleMemoryTest.cpp
+++ b/source/RobotAPI/components/armem/ArMemExampleMemory/test/ArMemExampleMemoryTest.cpp
@@ -27,11 +27,33 @@
 #include <RobotAPI/Test.h>
 #include "../ArMemExampleMemory.h"
 
+#include <RobotAPI/components/armem/ArMemExampleMemory/aron/ExampleData.aron.generated.h>
+#include <RobotAPI/libraries/armem/core.h>
+
 #include <iostream>
 
-BOOST_AUTO_TEST_CASE(testExample)
+
+using armarx::armem::aron::example::ExampleData;
+namespace armem = armarx::armem;
+
+/*
+BOOST_AUTO_TEST_CASE(test_ExampleData)
+{
+    ExampleData data;
+    BOOST_CHECK(true);
+}
+*/
+
+
+BOOST_AUTO_TEST_CASE(test_ExampleData_type)
 {
-    armarx::ArMemExampleMemory instance;
+    armarx::aron::typenavigator::AronObjectTypeNavigatorPtr type = ExampleData::toInitialAronType();
+
+    BOOST_CHECK_EQUAL(type->getAcceptedTypes().size(), 15);
+
+    armem::Memory memory;
+    armem::CoreSegment& core = memory.addCoreSegment("ExampleData", type);
+    armem::ProviderSegment& prov = core.addProviderSegment("Provider");
 
-    BOOST_CHECK_EQUAL(true, true);
+    BOOST_CHECK_EQUAL(core.aronType(), prov.aronType());
 }
diff --git a/source/RobotAPI/components/armem/CMakeLists.txt b/source/RobotAPI/components/armem/CMakeLists.txt
index dfd5208e5a20c95daf7ffa45d6966e98f2afc9ff..6d4b4b0bf0e91cff4278a646479140f9afd27b59 100644
--- a/source/RobotAPI/components/armem/CMakeLists.txt
+++ b/source/RobotAPI/components/armem/CMakeLists.txt
@@ -1,3 +1,4 @@
 add_subdirectory(ArMemExampleMemory)
+add_subdirectory(ArMemDebugMemory)
 add_subdirectory(ArMemExampleClient)
 add_subdirectory(ArMemMemoryNameSystem)
diff --git a/source/RobotAPI/components/units/ObstacleAvoidingPlatformUnit/ObstacleAvoidingPlatformUnit.cpp b/source/RobotAPI/components/units/ObstacleAvoidingPlatformUnit/ObstacleAvoidingPlatformUnit.cpp
index 60672d5da0b446160b6e0a075a52303a44d10c79..950edbf74b1bdc1516614b7dfc8ac5c9a9598845 100644
--- a/source/RobotAPI/components/units/ObstacleAvoidingPlatformUnit/ObstacleAvoidingPlatformUnit.cpp
+++ b/source/RobotAPI/components/units/ObstacleAvoidingPlatformUnit/ObstacleAvoidingPlatformUnit.cpp
@@ -359,8 +359,8 @@ armarx::ObstacleAvoidingPlatformUnit::get_velocities()
     ARMARX_CHECK(modulated_vel.allFinite()) << "Velocity contains non-finite values.";
     ARMARX_CHECK(std::isfinite(target_rot_vel)) << "Rotation velocity is non-finite.";
 
-    ARMARX_DEBUG << "Target velocity:  " << target_vel.transpose() << "; " << target_rot_vel;
-    ARMARX_DEBUG << "Modulated velocity:  " << modulated_vel.transpose();
+    ARMARX_DEBUG << "Target velocity:  " << target_vel.transpose() << "; norm: " << target_vel.norm() << "; " << target_rot_vel;
+    ARMARX_DEBUG << "Modulated velocity:  " << modulated_vel.transpose() << modulated_vel.norm();
 
     const auto r = Eigen::Rotation2D(m_control_data.agent_ori).toRotationMatrix().inverse();
 
@@ -802,14 +802,16 @@ armarx::ObstacleAvoidingPlatformUnit::createPropertyDefinitions()
 
     // Settings.
     def->optional(m_control_data.adaptive_max_vel_exp, "adaptive_max_vel_exponent",
-                  "Adaptive max vel exponent.  0 = disable.");
+                  "Adaptive max vel exponent.  This throttles the max_vel adaptively "
+                  "depending on the angle between target velocity and modulated velocity.  "
+                  "0 = disable.");
 
     // Control parameters.
     def->optional(m_control_data.kp, "control.pos.kp");
     def->optional(m_rot_pid_controller.Kp, "control.rot.kp");
     def->optional(m_rot_pid_controller.Ki, "control.rot.ki");
     def->optional(m_rot_pid_controller.Kd, "control.rot.kd");
-    def->optional(m_control_loop.cycle_time, "control.pose.cycle_time");
+    def->optional(m_control_loop.cycle_time, "control.pose.cycle_time", "Control loop cycle time.");
 
     // Obstacle avoidance parameter.
     def->optional(m_control_data.agent_safety_margin, "doa.agent_safety_margin");
diff --git a/source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointCartesianWaypointController.cpp b/source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointCartesianWaypointController.cpp
index fb07832483bfea3d9ae69d9aece2bb20fbe90289..6ad411f67b743fecaf8ed8fa82a31f0d3e0d0b8c 100644
--- a/source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointCartesianWaypointController.cpp
+++ b/source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointCartesianWaypointController.cpp
@@ -182,7 +182,10 @@ namespace armarx
                 _publishWpsNum = r.wps.size();
                 _rtHasWps = !r.wps.empty();
                 _rtWpController->swapWaypoints(r.wps);
-                _rtWpController->skipToClosestWaypoint(r.skipRad2mmFactor);
+                if (r.cfg.skipToClosestWaypoint)
+                {
+                    _rtWpController->skipToClosestWaypoint(r.skipRad2mmFactor);
+                }
             }
             _publishIsAtForceLimit = false;
         }
diff --git a/source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointCartesianWaypointController.h b/source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointCartesianWaypointController.h
index b09e6f605d46dd1be00301765a974fd6b084f7a7..9ed0b775c33ca9bc3a32c239d6635fd9d021044e 100644
--- a/source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointCartesianWaypointController.h
+++ b/source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointCartesianWaypointController.h
@@ -77,6 +77,7 @@ namespace armarx
             float skipRad2mmFactor = 500;
             bool wpsUpdated = false;
             bool cfgUpdated = false;
+            bool skipToClosestWaypoint = true;
         };
 
         struct RtToNonRtData
diff --git a/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleControllerManagement.cpp b/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleControllerManagement.cpp
index 3ccb1f9be38f93ae8d7a3ee96ac6cfb58957f631..f03a527d7a2b87c5c5752e2f16cdaa0baaee13c4 100644
--- a/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleControllerManagement.cpp
+++ b/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleControllerManagement.cpp
@@ -209,6 +209,17 @@ namespace armarx::RobotUnitModule
                 ARMARX_TRACE;
                 return nullptr;
             }
+            ARMARX_INFO << "wiating until controller '" << instanceName << "' is deleted";
+        }
+        while (getArmarXManager()->getIceManager()->isObjectReachable(instanceName))
+        {
+            ARMARX_TRACE;
+            if (isShuttingDown())
+            {
+                ARMARX_TRACE;
+                return nullptr;
+            }
+            ARMARX_INFO << "wiating until controller '" << instanceName << "' is removed from ice";
         }
         return NJointControllerInterfacePrx::uncheckedCast(
                    createNJointController(className, instanceName, config, true, false)->getProxy(-1, true));
diff --git a/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleLogging.cpp b/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleLogging.cpp
index 0ed1a250ab31b69f64afd236ad20462aab05fc95..26fe846c4c2b6165d0a4f5f57d95f47dd874f6ab 100644
--- a/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleLogging.cpp
+++ b/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleLogging.cpp
@@ -37,7 +37,47 @@
 #include "../util/ControlThreadOutputBuffer.h"
 
 #include <boost/algorithm/string/predicate.hpp>
-
+namespace armarx::RobotUnitModule::details
+{
+    struct DoLoggingDurations
+    {
+        struct DurationsEntry
+        {
+            DurationsEntry()
+            {
+                t = IceUtil::Time::seconds(0);
+            }
+            IceUtil::Time t;
+            void start()
+            {
+                t -= IceUtil::Time::now();
+                ++n;
+            }
+            void stop()
+            {
+                t += IceUtil::Time::now();
+            }
+            double ms() const
+            {
+                return t.toMilliSecondsDouble();
+            }
+            std::size_t n = 0;
+        };
+        DurationsEntry header;
+        DurationsEntry header_csv;
+        DurationsEntry header_stream;
+        DurationsEntry sens;
+        DurationsEntry sens_csv;
+        DurationsEntry sens_stream;
+        DurationsEntry sens_stream_elem;
+        DurationsEntry ctrl;
+        DurationsEntry ctrl_csv;
+        DurationsEntry ctrl_stream;
+        DurationsEntry ctrl_stream_elem;
+        DurationsEntry backlog;
+        DurationsEntry msg;
+    };
+}
 namespace armarx::RobotUnitModule
 {
     void Logging::addMarkerToRtLog(const RemoteReferenceCounterBasePtr& token, const std::string& marker, const Ice::Current&)
@@ -373,6 +413,8 @@ namespace armarx::RobotUnitModule
                 else if make_case(Ice::Long,   Long)
                 else if make_case(Ice::Float,  Float)
                 else if make_case(Ice::Double, Double)
+                else if make_case(std::uint16_t,   Long)
+                else if make_case(std::uint32_t,   Long)
                 else
                 {
                     ARMARX_CHECK_EXPRESSION(false)
@@ -435,15 +477,11 @@ namespace armarx::RobotUnitModule
         ARMARX_TRACE;
         throwIfInControlThread(BOOST_CURRENT_FUNCTION);
         defaultLogHandle = nullptr;
-        if (rtLoggingTask)
+        if (rtLoggingTask.joinable())
         {
             ARMARX_DEBUG << "shutting down rt logging task";
-            rtLoggingTask->stop();
-            while (rtLoggingTask->isFunctionExecuting() || rtLoggingTask->isRunning())
-            {
-                ARMARX_FATAL << deactivateSpam(0.1) << "RT LOGGING TASK IS RUNNING AFTER IT WAS STOPPED!";
-            }
-            rtLoggingTask = nullptr;
+            stopRtLoggingTask = true;
+            rtLoggingTask.join();
             ARMARX_DEBUG << "shutting down rt logging task done";
         }
     }
@@ -455,8 +493,25 @@ namespace armarx::RobotUnitModule
         controlThreadId = LogSender::getThreadId();
         ControlThreadOutputBuffer::RtLoggingInstance = &(_module<ControlThreadDataBuffer>().getControlThreadOutputBuffer());
 
-        ARMARX_INFO << "starting rt logging with timestep " << rtLoggingTimestep;
-        rtLoggingTask->start();
+        ARMARX_INFO << "starting rt logging with timestep " << rtLoggingTimestepMs;
+        stopRtLoggingTask = false;
+        rtLoggingTask = std::thread{[&]{
+                using clock_t = std::chrono::steady_clock;
+                const auto now = []{return clock_t::now();};
+                while (!stopRtLoggingTask)
+                {
+                    const auto start = now();
+                    doLogging();
+                    const std::uint64_t ms = std::chrono::duration_cast<std::chrono::milliseconds>(now() - start).count();
+                    if (ms < rtLoggingTimestepMs)
+                    {
+                        std::this_thread::sleep_for(std::chrono::milliseconds{rtLoggingTimestepMs - ms});
+                        continue;
+                    }
+                    ARMARX_WARNING << deactivateSpam(10) << "logging thread took " << ms
+                                   << " ms > " << rtLoggingTimestepMs << " ms (message printed every 10 seconds)";
+                }
+            }};
     }
 
     void Logging::doLogging()
@@ -468,6 +523,7 @@ namespace armarx::RobotUnitModule
         // entries are removed last
 
         //remove backlog entries
+        const auto start_time_remove_backlog_entries = IceUtil::Time::now();
         {
             while (!backlog.empty() && backlog.front().writeTimestamp + rtLoggingBacklogRetentionTime < now)
             {
@@ -475,6 +531,8 @@ namespace armarx::RobotUnitModule
             }
         }
         //log all
+        const auto start_time_log_all = IceUtil::Time::now();
+        details::DoLoggingDurations dlogdurs;
         {
             ARMARX_TRACE;
             if (!rtLoggingEntries.empty() || !rtDataStreamingEntry.empty())
@@ -486,12 +544,14 @@ namespace armarx::RobotUnitModule
             _module<ControlThreadDataBuffer>().getControlThreadOutputBuffer().foreachNewLoggingEntry(
                 [&](const auto & data, auto i, auto num)
             {
-                doLogging(now, data, i, num);
+                ARMARX_TRACE;
+                doLogging(dlogdurs, now, data, i, num);
             }
             );
         }
         ARMARX_DEBUG_S << ::deactivateSpam() << "the last " << backlog.size() << " iterations are stored";
         //flush all files
+        const auto start_time_flush_all_files = IceUtil::Time::now();
         {
             for (auto& pair : rtLoggingEntries)
             {
@@ -500,6 +560,7 @@ namespace armarx::RobotUnitModule
         }
 
         //remove entries
+        const auto start_time_remove_entries = IceUtil::Time::now();
         {
             ARMARX_TRACE;
             std::vector<std::string> toRemove;
@@ -519,6 +580,7 @@ namespace armarx::RobotUnitModule
             }
         }
         //deal with data streaming
+        const auto start_time_data_streaming = IceUtil::Time::now();
         {
             ARMARX_TRACE;
             std::vector<RobotUnitDataStreaming::ReceiverPrx> toRemove;
@@ -531,45 +593,82 @@ namespace armarx::RobotUnitModule
                 }
                 else
                 {
-                    data.send(prx);
+                    data.send(prx, rtDataStreamingMsgID);
                 }
             }
+            ++rtDataStreamingMsgID;
             for (const auto& prx : toRemove)
             {
                 rtDataStreamingEntry.erase(prx);
             }
         }
+        const auto end_time = IceUtil::Time::now();
+        const auto time_total = (end_time                   - now).toMilliSecondsDouble();
+        ARMARX_DEBUG_S << "rtlogging time required:        " << time_total << "ms\n"
+                       << "    time_remove_backlog_entries " << (start_time_log_all         - start_time_remove_backlog_entries).toMilliSecondsDouble() << "ms\n"
+                       << "    time_log_all                " << (start_time_flush_all_files - start_time_log_all).toMilliSecondsDouble()                << "ms\n"
+                       << "        header                  " << dlogdurs.header.ms()           << "ms\t(" << dlogdurs.header.n           << " calls)\n"
+                       << "            csv                 " << dlogdurs.header_csv.ms()       << "ms\t(" << dlogdurs.header_csv.n       << " calls)\n"
+                       << "            stream              " << dlogdurs.header_stream.ms()    << "ms\t(" << dlogdurs.header_stream.n    << " calls)\n"
+                       << "        sens                    " << dlogdurs.sens.ms()             << "ms\t(" << dlogdurs.sens.n             << " calls)\n"
+                       << "            csv                 " << dlogdurs.sens_csv.ms()         << "ms\t(" << dlogdurs.sens_csv.n         << " calls)\n"
+                       << "            stream              " << dlogdurs.sens_stream.ms()      << "ms\t(" << dlogdurs.sens_stream.n      << " calls)\n"
+                       << "                per elem        " << dlogdurs.sens_stream_elem.ms() << "ms\t(" << dlogdurs.sens_stream_elem.n << " calls)\n"
+                       << "        ctrl                    " << dlogdurs.ctrl.ms()             << "ms\t(" << dlogdurs.ctrl.n             << " calls)\n"
+                       << "            csv                 " << dlogdurs.ctrl_csv.ms()         << "ms\t(" << dlogdurs.ctrl_csv.n         << " calls)\n"
+                       << "            stream              " << dlogdurs.ctrl_stream.ms()      << "ms\t(" << dlogdurs.ctrl_stream.n      << " calls)\n"
+                       << "                per elem        " << dlogdurs.ctrl_stream_elem.ms() << "ms\t(" << dlogdurs.ctrl_stream_elem.n << " calls)\n"
+                       << "        backlog                 " << dlogdurs.backlog.ms()          << "ms\t(" << dlogdurs.backlog.n          << " calls)\n"
+                       << "        msg                     " << dlogdurs.msg.ms()              << "ms\t(" << dlogdurs.msg.n              << " calls)\n"
+                       << "    time_flush_all_files        " << (start_time_remove_entries  - start_time_flush_all_files).toMilliSecondsDouble()        << "ms\n"
+                       << "    time_remove_entries         " << (start_time_data_streaming  - start_time_remove_entries).toMilliSecondsDouble()         << "ms\n"
+                       << "    time_data_streaming         " << (end_time                   - start_time_data_streaming).toMilliSecondsDouble()         << "ms\n";
     }
 
-    void Logging::doLogging(const IceUtil::Time& now, const
+    void Logging::doLogging(details::DoLoggingDurations& durations,
+                            const IceUtil::Time& now, const
                             ControlThreadOutputBuffer::Entry& data,
                             std::size_t i, std::size_t num)
     {
+
         ARMARX_TRACE;
         //header
         {
+            durations.header.start();
             ARMARX_TRACE;
             //base (marker;iteration;timestamp)
-            for (auto& [_, e] : rtLoggingEntries)
+            if (!rtLoggingEntries.empty())
             {
-                e->stream << "\n"
-                          << e->marker << ";"
-                          << data.iteration << ";"
-                          << data.sensorValuesTimestamp.toMicroSeconds() << ";"
-                          << data.timeSinceLastIteration.toMicroSeconds();
-                e->marker.clear();
+                durations.header_csv.start();
+                for (auto& [_, e] : rtLoggingEntries)
+                {
+                    e->stream << "\n"
+                              << e->marker << ";"
+                              << data.iteration << ";"
+                              << data.sensorValuesTimestamp.toMicroSeconds() << ";"
+                              << data.timeSinceLastIteration.toMicroSeconds();
+                    e->marker.clear();
+                }
+                durations.header_csv.stop();
             }
             //streaming
-            for (auto& [_, e] : rtDataStreamingEntry)
+            if (!rtDataStreamingEntry.empty())
             {
-                e.processHeader(data);
+                durations.header_stream.start();
+                for (auto& [_, e] : rtDataStreamingEntry)
+                {
+                    e.processHeader(data);
+                }
+                durations.header_stream.stop();
             }
+            durations.header.stop();
         }
         //process devices
         {
             //sens
             {
                 ARMARX_TRACE;
+                durations.sens.start();
                 //sensors
                 for (std::size_t idxDev = 0; idxDev < data.sensors.size(); ++ idxDev)
                 {
@@ -577,23 +676,37 @@ namespace armarx::RobotUnitModule
                     //dimensions of sensor value (e.g. vel, tor, f_x, f_y, ...)
                     for (std::size_t idxField = 0; idxField < val->getNumberOfDataFields(); ++ idxField)
                     {
-                        const auto  str = val->getDataFieldAs<std::string>(idxField);
-                        for (auto& [_, entry] : rtLoggingEntries)
+                        if (!rtLoggingEntries.empty())
                         {
-                            if (entry->loggedSensorDeviceValues.at(idxDev).at(idxField))
+                            durations.sens_csv.start();
+                            const auto  str = val->getDataFieldAs<std::string>(idxField);
+                            for (auto& [_, entry] : rtLoggingEntries)
                             {
-                                entry->stream  << ";" << str;
+                                if (entry->loggedSensorDeviceValues.at(idxDev).at(idxField))
+                                {
+                                    entry->stream  << ";" << str;
+                                }
                             }
+                            durations.sens_csv.stop();
                         }
-                        for (auto& [_, data] : rtDataStreamingEntry)
+                        if (!rtDataStreamingEntry.empty())
                         {
-                            data.processSens(*val, idxDev, idxField);
+                            durations.sens_stream.start();
+                            for (auto& [_, data] : rtDataStreamingEntry)
+                            {
+                                durations.sens_stream_elem.start();
+                                data.processSens(*val, idxDev, idxField);
+                                durations.sens_stream_elem.stop();
+                            }
+                            durations.sens_stream.stop();
                         }
                     }
                 }
+                durations.sens.stop();
             }
             //ctrl
             {
+                durations.ctrl.start();
                 ARMARX_TRACE;
                 //joint controllers
                 for (std::size_t idxDev = 0; idxDev < data.control.size(); ++ idxDev)
@@ -606,36 +719,52 @@ namespace armarx::RobotUnitModule
                         //dimensions of control value (e.g. v_platform_x, v_platform_y, v_platform_rotate)
                         for (std::size_t idxField = 0; idxField < val->getNumberOfDataFields(); ++ idxField)
                         {
-                            std::string str;
-                            val->getDataFieldAs(idxField, str);
-                            for (auto& [_, entry] : rtLoggingEntries)
+                            if (!rtLoggingEntries.empty())
                             {
-                                if (entry->loggedControlDeviceValues.at(idxDev).at(idxVal).at(idxField))
+                                durations.ctrl_csv.start();
+                                std::string str;
+                                val->getDataFieldAs(idxField, str); // expensive function
+                                for (auto& [_, entry] : rtLoggingEntries)
                                 {
-                                    entry->stream  << ";" << str;
+                                    if (entry->loggedControlDeviceValues.at(idxDev).at(idxVal).at(idxField))
+                                    {
+                                        entry->stream  << ";" << str;
+                                    }
                                 }
+                                durations.ctrl_csv.stop();
                             }
-                            for (auto& [_, data] : rtDataStreamingEntry)
+                            if (!rtDataStreamingEntry.empty())
                             {
-                                data.processCtrl(*val, idxDev, idxVal, idxField);
+                                durations.ctrl_stream.start();
+                                for (auto& [_, data] : rtDataStreamingEntry)
+                                {
+                                    durations.ctrl_stream_elem.start();
+                                    data.processCtrl(*val, idxDev, idxVal, idxField);
+                                    durations.ctrl_stream_elem.stop();
+                                }
+                                durations.ctrl_stream.stop();
                             }
                         }
                     }
                 }
+                durations.ctrl.stop();
             }
         }
         //finish processing
         {
             //store data to backlog
             {
+                durations.backlog.start();
                 ARMARX_TRACE;
                 if (data.writeTimestamp + rtLoggingBacklogRetentionTime >= now)
                 {
                     backlog.emplace_back(data, true); //true for minimal copy
                 }
+                durations.backlog.stop();
             }
             //print + reset messages
             {
+                durations.msg.start();
                 ARMARX_TRACE;
                 for (const ::armarx::detail::RtMessageLogEntryBase* ptr : data.messages.getEntries())
                 {
@@ -645,6 +774,7 @@ namespace armarx::RobotUnitModule
                     }
                     ptr->print(controlThreadId);
                 }
+                durations.msg.stop();
             }
         }
     }
@@ -673,8 +803,8 @@ namespace armarx::RobotUnitModule
     {
         ARMARX_TRACE;
         throwIfInControlThread(BOOST_CURRENT_FUNCTION);
-        rtLoggingTimestep = getProperty<std::size_t>("RTLogging_PeriodMs");
-        ARMARX_CHECK_LESS(0, rtLoggingTimestep) << "The property RTLoggingPeriodMs must not be 0";
+        rtLoggingTimestepMs = getProperty<std::size_t>("RTLogging_PeriodMs");
+        ARMARX_CHECK_LESS(0, rtLoggingTimestepMs) << "The property RTLoggingPeriodMs must not be 0";
 
         messageBufferSize = getProperty<std::size_t>("RTLogging_MessageBufferSize");
         messageBufferMaxSize = getProperty<std::size_t>("RTLogging_MaxMessageBufferSize");
@@ -697,7 +827,7 @@ namespace armarx::RobotUnitModule
         {
             ARMARX_TRACE;
             std::size_t ctrlThreadPeriodUs = static_cast<std::size_t>(getControlThreadTargetPeriod().toMicroSeconds());
-            std::size_t logThreadPeriodUs = rtLoggingTimestep * 1000;
+            std::size_t logThreadPeriodUs = rtLoggingTimestepMs * 1000;
             std::size_t nBuffers = (logThreadPeriodUs / ctrlThreadPeriodUs + 1) * 100;
 
             const auto bufferSize = _module<ControlThreadDataBuffer>().getControlThreadOutputBuffer().initialize(
@@ -762,24 +892,20 @@ namespace armarx::RobotUnitModule
                 defaultLogHandle = startRtLogging(loggingpath, getLoggingNames());
             }
         }
-        //setup thread (don't start it
-        rtLoggingTask = new RTLoggingTaskT([&] {doLogging();}, rtLoggingTimestep, false, getName() + "_RTLoggingTask");
-        rtLoggingTask->setDelayWarningTolerance(rtLoggingTimestep * 10);
     }
 
-    void Logging::DataStreamingEntry::processHeader(const ControlThreadOutputBuffer::Entry& e)
+    void Logging::DataStreamingEntry::clearResult()
     {
-        ARMARX_TRACE;
-        if (stopStreaming)
+        for (auto& e : result)
         {
-            return;
+            entryBuffer.emplace_back(std::move(e));
         }
-        result.emplace_back();
-        auto& data = result.back();
-        data.iterationId                 = e.iteration;
-        data.timestampUSec               = e.sensorValuesTimestamp.toMicroSeconds();
-        data.timesSinceLastIterationUSec = e.timeSinceLastIteration.toMicroSeconds();
+        result.clear();
+    }
 
+    RobotUnitDataStreaming::TimeStep Logging::DataStreamingEntry::allocateResultElement() const
+    {
+        RobotUnitDataStreaming::TimeStep data;
         data.bools  .resize(numBools);
         data.bytes  .resize(numBytes);
         data.shorts .resize(numShorts);
@@ -787,43 +913,87 @@ namespace armarx::RobotUnitModule
         data.longs  .resize(numLongs);
         data.floats .resize(numFloats);
         data.doubles.resize(numDoubles);
+        return data;
+    }
+
+    RobotUnitDataStreaming::TimeStep Logging::DataStreamingEntry::getResultElement()
+    {
+        if (entryBuffer.empty())
+        {
+            return allocateResultElement();
+        }
+        auto e = std::move(entryBuffer.back());
+        entryBuffer.pop_back();
+        return e;
+    }
+
+    void Logging::DataStreamingEntry::processHeader(const ControlThreadOutputBuffer::Entry& e)
+    {
+        ARMARX_TRACE;
+        if (stopStreaming)
+        {
+            return;
+        }
+        result.emplace_back(getResultElement());
 
+        auto& data = result.back();
+        data.iterationId                 = e.iteration;
+        data.timestampUSec               = e.sensorValuesTimestamp.toMicroSeconds();
+        data.timesSinceLastIterationUSec = e.timeSinceLastIteration.toMicroSeconds();
     }
 
-    void WriteTo(const Logging::DataStreamingEntry::OutVal& out,
+    void WriteTo(const auto& dentr,
+                 const Logging::DataStreamingEntry::OutVal& out,
                  const auto& val,
                  std::size_t fidx,
                  auto& data)
     {
         ARMARX_TRACE;
         using enum_t = Logging::DataStreamingEntry::ValueT;
-        switch (out.value)
-        {
-            case enum_t::Bool   :
-                bool b;
-                val.getDataFieldAs(fidx, b);
-                data.bools.at(out.idx) = b;
-                return;
-            case enum_t::Byte   :
-                val.getDataFieldAs(fidx, data.bytes.at(out.idx));
-                return;
-            case enum_t::Short  :
-                val.getDataFieldAs(fidx, data.shorts.at(out.idx));
-                return;
-            case enum_t::Int    :
-                val.getDataFieldAs(fidx, data.ints.at(out.idx));
-                return;
-            case enum_t::Long   :
-                val.getDataFieldAs(fidx, data.longs.at(out.idx));
-                return;
-            case enum_t::Float  :
-                val.getDataFieldAs(fidx, data.floats.at(out.idx));
-                return;
-            case enum_t::Double :
-                val.getDataFieldAs(fidx, data.doubles.at(out.idx));
-                return;
-            case enum_t::Skipped:
-                return;
+        try
+        {
+            ARMARX_TRACE;
+            switch (out.value)
+            {
+                case enum_t::Bool   :
+                    bool b;
+                    val.getDataFieldAs(fidx, b);
+                    data.bools.at(out.idx) = b;
+                    return;
+                case enum_t::Byte   :
+                    val.getDataFieldAs(fidx, data.bytes.at(out.idx));
+                    return;
+                case enum_t::Short  :
+                    val.getDataFieldAs(fidx, data.shorts.at(out.idx));
+                    return;
+                case enum_t::Int    :
+                    val.getDataFieldAs(fidx, data.ints.at(out.idx));
+                    return;
+                case enum_t::Long   :
+                    val.getDataFieldAs(fidx, data.longs.at(out.idx));
+                    return;
+                case enum_t::Float  :
+                    val.getDataFieldAs(fidx, data.floats.at(out.idx));
+                    return;
+                case enum_t::Double :
+                    val.getDataFieldAs(fidx, data.doubles.at(out.idx));
+                    return;
+                case enum_t::Skipped:
+                    return;
+            }
+        }
+        catch (...)
+        {
+            ARMARX_ERROR << GetHandledExceptionString()
+                         << "\ntype " << static_cast<int>(out.value)
+                         << "\n" << VAROUT(data.bools.size())   << " " << VAROUT(dentr.numBools)
+                         << "\n" << VAROUT(data.bytes.size())   << " " << VAROUT(dentr.numBytes)
+                         << "\n" << VAROUT(data.shorts.size())  << " " << VAROUT(dentr.numShorts)
+                         << "\n" << VAROUT(data.ints.size())    << " " << VAROUT(dentr.numInts)
+                         << "\n" << VAROUT(data.longs.size())   << " " << VAROUT(dentr.numLongs)
+                         << "\n" << VAROUT(data.floats.size())  << " " << VAROUT(dentr.numFloats)
+                         << "\n" << VAROUT(data.doubles.size()) << " " << VAROUT(dentr.numDoubles);
+            throw;
         }
     }
 
@@ -840,7 +1010,7 @@ namespace armarx::RobotUnitModule
         }
         auto& data = result.back();
         const OutVal& o = ctrlDevs.at(didx).at(vidx).at(fidx);
-        WriteTo(o, val, fidx, data);
+        WriteTo(*this, o, val, fidx, data);
     }
 
     void Logging::DataStreamingEntry::processSens(
@@ -855,28 +1025,49 @@ namespace armarx::RobotUnitModule
         }
         auto& data = result.back();
         const OutVal& o = sensDevs.at(didx).at(fidx);
-        WriteTo(o, val, fidx, data);
+        WriteTo(*this, o, val, fidx, data);
     }
 
-    void Logging::DataStreamingEntry::send(const RobotUnitDataStreaming::ReceiverPrx& r)
+    void Logging::DataStreamingEntry::send(const RobotUnitDataStreaming::ReceiverPrx& r,
+                                           std::uint64_t msgId)
     {
         ARMARX_TRACE;
-        try
-        {
-            r->update(result);
-            connectionFailures = 0;
-            result.clear();
-        }
-        catch (...)
+        const auto start_send = IceUtil::Time::now();
+        updateCalls.emplace_back(r->begin_update(result, static_cast<Ice::Long>(msgId)));
+        const auto start_clear = IceUtil::Time::now();
+        clearResult();
+        const auto end = IceUtil::Time::now();
+        ARMARX_DEBUG_S << "Logging::DataStreamingEntry::send"
+                       << "\n    update " << (start_clear - start_send).toMilliSecondsDouble() << "ms (" << result.size() << " timesteps)"
+                       << "\n    clear  " << (end - start_clear).toMilliSecondsDouble() << "ms";
+
+        //now execute all ready callbacks
+        std::size_t i = 0;
+        for (; i < updateCalls.size(); ++i)
         {
-            ARMARX_TRACE;
-            ++connectionFailures;
-            if (connectionFailures > rtStreamMaxClientErrors)
+            try
+            {
+                if (!updateCalls.at(i)->isCompleted())
+                {
+                    break;
+                }
+                r->end_update(updateCalls.at(i));
+                connectionFailures = 0;
+            }
+            catch (...)
             {
-                stopStreaming = true;
-                ARMARX_WARNING_S << "DataStreaming Receiver was not reachable for "
-                                 << connectionFailures << " iterations! Removing receiver";
+                ARMARX_TRACE;
+                ++connectionFailures;
+                if (connectionFailures > rtStreamMaxClientErrors)
+                {
+                    stopStreaming = true;
+                    ARMARX_WARNING_S << "DataStreaming Receiver was not reachable for "
+                                     << connectionFailures << " iterations! Removing receiver";
+                    updateCalls.clear();
+                    break;
+                }
             }
         }
+        updateCalls.erase(updateCalls.begin(), updateCalls.begin() + i);
     }
 }
diff --git a/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleLogging.h b/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleLogging.h
index 6271ef1784a4cd79e8e3b37addcb4e679e946bc2..975979177d45d71530317ea6f282929d72f6924c 100644
--- a/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleLogging.h
+++ b/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleLogging.h
@@ -25,6 +25,7 @@
 #include <atomic>
 #include <map>
 #include <vector>
+#include <deque>
 #include <fstream>
 
 #include <ArmarXCore/core/services/tasks/TaskUtil.h>
@@ -34,6 +35,11 @@
 #include "RobotUnitModuleBase.h"
 #include "../util/ControlThreadOutputBuffer.h"
 
+namespace armarx::RobotUnitModule::details
+{
+    struct DoLoggingDurations;
+}
+
 namespace armarx::RobotUnitModule
 {
     class LoggingPropertyDefinitions: public ModuleBasePropertyDefinitions
@@ -168,7 +174,8 @@ namespace armarx::RobotUnitModule
     private:
         /// @brief Executes the logging loop.
         void doLogging();
-        void doLogging(const IceUtil::Time& now,
+        void doLogging(details::DoLoggingDurations& durations,
+                       const IceUtil::Time& now,
                        const ControlThreadOutputBuffer::Entry& data,
                        std::size_t i, std::size_t num);
         static bool MatchName(const std::string& pattern, const std::string& name);
@@ -177,8 +184,6 @@ namespace armarx::RobotUnitModule
         // ///////////////////////////////////////// Data ///////////////////////////////////////// //
         // //////////////////////////////////////////////////////////////////////////////////////// //
     private:
-        using RTLoggingTaskT = SimplePeriodicTask<std::function<void(void)>>;
-
         /// @brief Data structure holding information about an logging entry.
         struct CSVLoggingEntry
         {
@@ -233,6 +238,14 @@ namespace armarx::RobotUnitModule
             std::vector<std::vector<std::vector<OutVal>>> ctrlDevs;
 
             RobotUnitDataStreaming::TimeStepSeq           result;
+            std::deque<RobotUnitDataStreaming::TimeStep>  entryBuffer;
+            std::deque<Ice::AsyncResultPtr>               updateCalls;
+            void clearResult();
+            RobotUnitDataStreaming::TimeStep getResultElement();
+            RobotUnitDataStreaming::TimeStep allocateResultElement() const;
+
+
+
             void processHeader(const ControlThreadOutputBuffer::Entry& e);
             void processCtrl(const ControlTargetBase& val,
                              std::size_t didx,
@@ -241,12 +254,14 @@ namespace armarx::RobotUnitModule
             void processSens(const SensorValueBase& val,
                              std::size_t didx,
                              std::size_t fidx);
-            void send(const RobotUnitDataStreaming::ReceiverPrx& r);
+            void send(const RobotUnitDataStreaming::ReceiverPrx& r, uint64_t msgId);
         };
         std::map<RobotUnitDataStreaming::ReceiverPrx, DataStreamingEntry> rtDataStreamingEntry;
+        std::uint64_t rtDataStreamingMsgID = 0;
 
         /// @brief The thread executing the logging functions.
-        RTLoggingTaskT::pointer_type rtLoggingTask;
+        std::thread rtLoggingTask;
+        std::atomic_bool stopRtLoggingTask{false};
         /// @brief All entries for logging.
         std::map<std::string, std::shared_ptr<CSVLoggingEntry>> rtLoggingEntries;
         /// @brief Handle for the default log. (This log can be enabled via a property and logs everything)
@@ -282,7 +297,7 @@ namespace armarx::RobotUnitModule
         /// @brief The maximal number of Message entries
         std::size_t messageBufferMaxNumberEntries {0};
         /// @brief The logging thread's period
-        std::size_t rtLoggingTimestep {0};
+        std::size_t rtLoggingTimestepMs {0};
         /// @brief The time an entry shold remain in the backlog.
         IceUtil::Time rtLoggingBacklogRetentionTime;
     };
diff --git a/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModulePublisher.cpp b/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModulePublisher.cpp
index 763bab62f2773dbb26e45efbc3e38ae7b4839561..6f24dde1d0f5cf513b1c8520a5deabe1ad6ca91e 100644
--- a/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModulePublisher.cpp
+++ b/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModulePublisher.cpp
@@ -277,8 +277,7 @@ namespace armarx::RobotUnitModule
         {
             if (robotUnitObserver->getState() >= eManagedIceObjectStarted)
             {
-                robotUnitObserver->offerOrUpdateDataFieldsFlatCopy(robotUnitObserver->controlDevicesChannel, ctrlDevMap);
-                robotUnitObserver->updateChannel(robotUnitObserver->controlDevicesChannel);
+                robotUnitObserver->offerOrUpdateDataFieldsFlatCopy_async(robotUnitObserver->controlDevicesChannel, std::move(ctrlDevMap));
             }
         }
 
@@ -338,8 +337,7 @@ namespace armarx::RobotUnitModule
                         out << pair.first << ": " << (pair.second ? pair.second->ice_id() + Variant::typeToString(pair.second->getType()) : "NULL")  << "\n";
                     }
                 };
-                robotUnitObserver->offerOrUpdateDataFieldsFlatCopy(robotUnitObserver->sensorDevicesChannel, sensorDevMap);
-                robotUnitObserver->updateChannel(robotUnitObserver->sensorDevicesChannel);
+                robotUnitObserver->offerOrUpdateDataFieldsFlatCopy_async(robotUnitObserver->sensorDevicesChannel, std::move(sensorDevMap));
             }
         }
 
@@ -583,13 +581,11 @@ namespace armarx::RobotUnitModule
             {
                 if (observerPublishTimingInformation)
                 {
-                    robotUnitObserver->offerOrUpdateDataFieldsFlatCopy(robotUnitObserver->additionalChannel, additionalMap);
-                    robotUnitObserver->updateChannel(robotUnitObserver->additionalChannel);
+                    robotUnitObserver->offerOrUpdateDataFieldsFlatCopy_async(robotUnitObserver->additionalChannel, std::move(additionalMap));
                 }
                 if (observerPublishAdditionalInformation)
                 {
-                    robotUnitObserver->offerOrUpdateDataFieldsFlatCopy(robotUnitObserver->timingChannel, timingMap);
-                    robotUnitObserver->updateChannel(robotUnitObserver->timingChannel);
+                    robotUnitObserver->offerOrUpdateDataFieldsFlatCopy_async(robotUnitObserver->timingChannel, std::move(timingMap));
                 }
             }
         }
diff --git a/source/RobotAPI/components/units/RobotUnit/RobotUnitObserver.cpp b/source/RobotAPI/components/units/RobotUnit/RobotUnitObserver.cpp
index bb04d0b1538db48e35e43745dd8020c3418ab0ac..004d3361faf19b3acfdfd99e0278d0246c004449 100644
--- a/source/RobotAPI/components/units/RobotUnit/RobotUnitObserver.cpp
+++ b/source/RobotAPI/components/units/RobotUnit/RobotUnitObserver.cpp
@@ -4,52 +4,12 @@
 
 namespace armarx
 {
-
-    RobotUnitObserver::RobotUnitObserver()
-    {
-
-    }
-
-    void RobotUnitObserver::offerOrUpdateDataFieldsFlatCopy(const std::string& channelName, const StringVariantBaseMap& valueMap)
+    void RobotUnitObserver::offerOrUpdateDataFieldsFlatCopy_async(const std::string& channelName, StringVariantBaseMap&& valueMap)
     {
-        if (!existsChannel(channelName))
-        {
-            offerChannel(channelName, "");
-        }
-        try
+        addWorkerJob("RobotUnitObserver::offerOrUpdateDataFieldsFlatCopy_async", [this, channelName, vmap = std::move(valueMap)]
         {
-            // fastest way is to just try to set the datafields
-            setDataFieldsFlatCopy(channelName, valueMap, true);
-        }
-        catch (exceptions::user::InvalidDataFieldException& e)
-        {
-            ARMARX_INFO << deactivateSpam() << "Creating datafields for channel " << channelName;
-            // on failure: do it the slow way
-            for (const auto& value : valueMap)
-            {
-                const std::string& datafieldName = value.first;
-
-                if (!existsDataField(channelName, datafieldName))
-                {
-                    try
-                    {
-                        offerDataFieldWithDefault(channelName, datafieldName, *VariantPtr::dynamicCast(value.second), "");
-                    }
-                    catch (exceptions::user::DatafieldExistsAlreadyException& e)
-                    {
-                        setDataFieldFlatCopy(channelName, datafieldName, VariantPtr::dynamicCast(value.second));
-                    }
-                }
-                else
-                {
-                    setDataFieldFlatCopy(channelName, datafieldName, VariantPtr::dynamicCast(value.second));
-                }
-            }
-        }
-    }
-
-    void RobotUnitObserver::onInitObserver()
-    {
+            offerOrUpdateDataFieldsFlatCopy(channelName, vmap);
+        });
     }
 
     void RobotUnitObserver::onConnectObserver()
@@ -59,5 +19,4 @@ namespace armarx
         offerChannel(timingChannel, "Channel for timings of the different phases of the robot unit");
         offerChannel(additionalChannel, "Additional custom datafields");
     }
-
-} // namespace armarx
+}
diff --git a/source/RobotAPI/components/units/RobotUnit/RobotUnitObserver.h b/source/RobotAPI/components/units/RobotUnit/RobotUnitObserver.h
index 728d1682cba7f127b003c070179dc1ef0a52ada9..2fdfb990e824b343cb88337c8316363ceb964a3e 100644
--- a/source/RobotAPI/components/units/RobotUnit/RobotUnitObserver.h
+++ b/source/RobotAPI/components/units/RobotUnit/RobotUnitObserver.h
@@ -20,12 +20,13 @@ namespace armarx
         const std::string timingChannel = "TimingInformation";
         const std::string controlDevicesChannel = "ControlDevices";
         const std::string sensorDevicesChannel = "SensorDevices";
-        RobotUnitObserver();
 
-        void offerOrUpdateDataFieldsFlatCopy(const std::string& channelName, StringVariantBaseMap const& valueMap);
+        RobotUnitObserver() = default;
+
+        void offerOrUpdateDataFieldsFlatCopy_async(const std::string& channelName, StringVariantBaseMap&& valueMap);
         // Observer interface
     protected:
-        void onInitObserver() override;
+        void onInitObserver()    override {}
         void onConnectObserver() override;
 
         friend class RobotUnitModule::Publisher;
diff --git a/source/RobotAPI/components/units/RobotUnit/util/ControlThreadOutputBuffer.cpp b/source/RobotAPI/components/units/RobotUnit/util/ControlThreadOutputBuffer.cpp
index 8f038519bc03b014aef5219bb939e1acf03d55af..2dd62115bcf3ff0895cb3ecaa04fb2d2614d2294 100644
--- a/source/RobotAPI/components/units/RobotUnit/util/ControlThreadOutputBuffer.cpp
+++ b/source/RobotAPI/components/units/RobotUnit/util/ControlThreadOutputBuffer.cpp
@@ -73,6 +73,7 @@ namespace armarx
 
     void ControlThreadOutputBuffer::foreachNewLoggingEntry(ConsumerFunctor consumer)
     {
+        ARMARX_TRACE;
         ARMARX_CHECK_EXPRESSION(isInitialized);
         if (writePosition - onePastLoggingReadPosition >= numEntries)
         {
@@ -85,7 +86,11 @@ namespace armarx
         }
         //the number of new entries
         auto numNewEntries = writePosition - onePastLoggingReadPosition;
-        ARMARX_CHECK_EXPRESSION(numNewEntries < numEntries);
+        if (numNewEntries >= numEntries)
+        {
+            ARMARX_ERROR << " more new entries (" << numNewEntries << ") than space (" << numEntries << ") -> Skipping everything else";
+            return;
+        }
         //consume all
         const std::size_t num = writePosition - onePastLoggingReadPosition;
         for (
@@ -94,6 +99,7 @@ namespace armarx
             ++onePastLoggingReadPosition, ++offset
         )
         {
+            ARMARX_TRACE;
             auto& entry = entries.at(toBounds(onePastLoggingReadPosition));
             consumer(entry, offset, num);
             entry.messages.reset(messageBufferSize, messageBufferEntries, entry.iteration);
@@ -109,8 +115,13 @@ namespace armarx
                                << numNewEntries << " /" << newNumNewEntries << " / " << numEntries;
             }
             numNewEntries = newNumNewEntries;
-            ARMARX_CHECK_EXPRESSION(numNewEntries < numEntries);
+            if (numNewEntries >= numEntries)
+            {
+                ARMARX_ERROR << " more new entries (" << numNewEntries << ") than space (" << numEntries << ") -> Skipping everything else";
+                return;
+            }
         }
+
     }
 
     std::size_t ControlThreadOutputBuffer::initialize(std::size_t numEntries,
diff --git a/source/RobotAPI/gui-plugins/ArMemMemoryViewer/ArMemMemoryViewerWidget.ui b/source/RobotAPI/gui-plugins/ArMemMemoryViewer/ArMemMemoryViewerWidget.ui
index a92856396a36ed42467a1f0d11c37838a7aece7e..0eb55660336c5ec4d72f869ff0faa3cadb8ff2ca 100644
--- a/source/RobotAPI/gui-plugins/ArMemMemoryViewer/ArMemMemoryViewerWidget.ui
+++ b/source/RobotAPI/gui-plugins/ArMemMemoryViewer/ArMemMemoryViewerWidget.ui
@@ -460,7 +460,7 @@
        <property name="title">
         <string>Entity Instance (click on an instance on the left)</string>
        </property>
-       <layout class="QHBoxLayout" name="horizontalLayout_4">
+       <layout class="QVBoxLayout" name="verticalLayout_5">
         <property name="leftMargin">
          <number>0</number>
         </property>
@@ -490,8 +490,50 @@
             <string>Value</string>
            </property>
           </column>
+          <item>
+           <property name="text">
+            <string>id</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>data</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>metadata</string>
+           </property>
+          </item>
          </widget>
         </item>
+        <item>
+         <layout class="QHBoxLayout" name="horizontalLayout_2">
+          <item>
+           <spacer name="horizontalSpacer_2">
+            <property name="orientation">
+             <enum>Qt::Horizontal</enum>
+            </property>
+            <property name="sizeHint" stdset="0">
+             <size>
+              <width>40</width>
+              <height>20</height>
+             </size>
+            </property>
+           </spacer>
+          </item>
+          <item>
+           <widget class="QCheckBox" name="instanceUseTypeInfoCheckBox">
+            <property name="text">
+             <string>Use Type Info</string>
+            </property>
+            <property name="checked">
+             <bool>true</bool>
+            </property>
+           </widget>
+          </item>
+         </layout>
+        </item>
        </layout>
       </widget>
      </item>
diff --git a/source/RobotAPI/gui-plugins/ArMemMemoryViewer/ArMemMemoryViewerWidgetController.cpp b/source/RobotAPI/gui-plugins/ArMemMemoryViewer/ArMemMemoryViewerWidgetController.cpp
index 28ddc277f4cc817f8c22cbf51bca8e5d7d250ba8..ddef1da66e7c6cd6195b8437d2c932a26250f9cc 100644
--- a/source/RobotAPI/gui-plugins/ArMemMemoryViewer/ArMemMemoryViewerWidgetController.cpp
+++ b/source/RobotAPI/gui-plugins/ArMemMemoryViewer/ArMemMemoryViewerWidgetController.cpp
@@ -28,10 +28,9 @@
 #include <QTimer>
 
 #include <ArmarXCore/observers/variant/Variant.h>
+#include <ArmarXCore/core/time/TimeUtil.h>
 
 #include <RobotAPI/libraries/armem/core/ice_conversions.h>
-#include <RobotAPI/libraries/armem_gui/QTreeWidgetAronDataVisitor.h>
-
 #include <RobotAPI/libraries/armem_gui/gui_utils.h>
 
 
@@ -50,6 +49,38 @@ namespace armarx
         }
     }
 
+    static QSplitter* useSplitter(QLayout* layout)
+    {
+        ARMARX_CHECK(layout);
+
+        QSplitter* splitter;
+        if (dynamic_cast<QHBoxLayout*>(layout))
+        {
+            splitter = new QSplitter(Qt::Orientation::Horizontal);
+        }
+        else if (dynamic_cast<QVBoxLayout*>(layout))
+        {
+            splitter = new QSplitter(Qt::Orientation::Vertical);
+        }
+        else
+        {
+            splitter = new QSplitter();
+        }
+
+        while (layout->count() > 0)
+        {
+            int index = 0;
+            if (layout->itemAt(index)->widget())
+            {
+                QLayoutItem* item = layout->takeAt(index);
+                splitter->addWidget(item->widget());
+            }
+        }
+        layout->addWidget(splitter);
+
+        return splitter;
+    }
+
 
     QString ArMemMemoryViewerWidgetController::GetWidgetName()
     {
@@ -62,20 +93,6 @@ namespace armarx
         widget.setupUi(getWidget());
 
         // Setup widgets
-        {
-            QSplitter* splitter = new QSplitter();
-            while (widget.treesLayout->count() > 0)
-            {
-                int index = 0; //widget.treesLayout->count() - 1;
-                if (widget.treesLayout->itemAt(index)->widget())
-                {
-                    QLayoutItem* item = widget.treesLayout->takeAt(index);
-                    splitter->addWidget(item->widget());
-                }
-            }
-            widget.treesLayout->addWidget(splitter);
-        }
-
         widget.statusLabel->clear();
 
 
@@ -89,7 +106,6 @@ namespace armarx
         replaceWidget(widget._memoryTreeWidget, memoryTree, widget.memoryGroupBox->layout());
         ARMARX_CHECK_NULL(widget._memoryTreeWidget);
 
-
         queryTabs = new armem::gui::QueryWidget();
         widget._queryTabWidget = nullptr;
 
@@ -103,6 +119,10 @@ namespace armarx
         ARMARX_CHECK_NULL(widget._instanceTree);
 
 
+        useSplitter(widget.treesLayout);
+        useSplitter(widget.memoryGroupBox->layout());
+
+
         // Connect signals
         connect(this, &This::connected, this, &This::updateMemory);
         connect(widget.updateButton, &QPushButton::pressed, this, &This::updateMemory);
@@ -113,7 +133,10 @@ namespace armarx
         connect(widget.updateFrequencySpinBox, &QDoubleSpinBox::editingFinished, this, &This::updateTimerFrequency);
 
         connect(memoryTree, &armem::gui::MemoryTreeWidget::updated, this, &This::memoryTreeUpdated);
-        connect(memoryTree, &armem::gui::MemoryTreeWidget::instanceSelected, this, &This::updateInstanceTree);
+        connect(memoryTree, &armem::gui::MemoryTreeWidget::updated, this, &This::updateInstanceTree);
+        connect(memoryTree, &armem::gui::MemoryTreeWidget::itemSelected, this, &This::updateInstanceTree);
+
+        connect(widget.instanceUseTypeInfoCheckBox, &QCheckBox::toggled, instanceTree, &armem::gui::InstanceTreeWidget::setUseTypeInfo);
         connect(instanceTree, &armem::gui::InstanceTreeWidget::updated, this, &This::instanceTreeUpdated);
     }
 
@@ -188,7 +211,7 @@ namespace armarx
             return;
         }
 
-        armem::Time start = armem::Time::now();
+        TIMING_START(MemoryQuery);
         {
             armem::client::QueryInput input = queryTabs->queryInput();
             armem::client::QueryResult result = memoryReader.query(input);
@@ -201,11 +224,11 @@ namespace armarx
                 widget.statusLabel->setText(QString::fromStdString(result.errorMessage));
             }
         }
-        ARMARX_VERBOSE << "Memory query took " << (armem::Time::now() - start).toMilliSecondsDouble() << " ms.";
+        TIMING_END_STREAM(MemoryQuery, ARMARX_VERBOSE);
 
         if (debugObserver)
         {
-            debugObserver->setDebugDatafield(debugObserverChannelName, "Memory Query [ms]", new Variant((armem::Time::now() - start).toMilliSecondsDouble()));
+            debugObserver->setDebugDatafield(debugObserverChannelName, "Memory Query [ms]", new Variant(MemoryQuery.toMilliSecondsDouble()));
         }
 
         if (this->memoryData)
@@ -218,24 +241,49 @@ namespace armarx
         }
     }
 
-    void ArMemMemoryViewerWidgetController::updateInstanceTree(const armem::MemoryID& id)
+    void ArMemMemoryViewerWidgetController::updateInstanceTree()
     {
-        if (memoryData)
+        if (memoryData && memoryTree->selectedID())
         {
-            instanceTree->update(id, *memoryData);
+            armem::MemoryID id = *memoryTree->selectedID();
+
+            if (!id.hasEntityName())
+            {
+                return;
+            }
+            const armem::EntitySnapshot* snapshot = nullptr;
+            if (!id.hasTimestamp())
+            {
+                snapshot = &memoryData->getEntity(id).getLatestSnapshot();
+                id.timestamp = snapshot->time();
+            }
+            if (!id.hasInstanceIndex())
+            {
+                if (!snapshot)
+                {
+                    snapshot = &memoryData->getEntitySnapshot(id);
+                }
+                if (snapshot->size() > 0)
+                {
+                    id.instanceIndex = 0;
+                }
+            }
+            if (id.hasInstanceIndex())
+            {
+                instanceTree->update(id, *memoryData);
+            }
         }
     }
 
     void ArMemMemoryViewerWidgetController::updateMemoryTree(armem::Memory& memory)
     {
-        armem::Time start = armem::Time::now();
-
+        TIMING_START(GuiUpdate);
         memoryTree->update(memory);
+        TIMING_END_STREAM(GuiUpdate, ARMARX_VERBOSE);
 
-        ARMARX_VERBOSE << "GUI update took " << (armem::Time::now() - start).toMilliSecondsDouble() << " ms.";
         if (debugObserver)
         {
-            debugObserver->setDebugDatafield(debugObserverChannelName, "GUI Update [ms]", new Variant((armem::Time::now() - start).toMilliSecondsDouble()));
+            debugObserver->setDebugDatafield(debugObserverChannelName, "GUI Update [ms]", new Variant(GuiUpdate.toMilliSecondsDouble()));
         }
     }
 
diff --git a/source/RobotAPI/gui-plugins/ArMemMemoryViewer/ArMemMemoryViewerWidgetController.h b/source/RobotAPI/gui-plugins/ArMemMemoryViewer/ArMemMemoryViewerWidgetController.h
index 48f0c0b6bf8ff00a99ca0e9adfadddea7ccbd9ef..973a3e24e18d5633fd32a008ea69fd681d06377a 100644
--- a/source/RobotAPI/gui-plugins/ArMemMemoryViewer/ArMemMemoryViewerWidgetController.h
+++ b/source/RobotAPI/gui-plugins/ArMemMemoryViewer/ArMemMemoryViewerWidgetController.h
@@ -99,7 +99,7 @@ namespace armarx
         void updateTimerFrequency();
         void toggleTimer(bool start);
         void updateMemory();
-        void updateInstanceTree(const armem::MemoryID& id);
+        void updateInstanceTree();
 
 
     signals:
diff --git a/source/RobotAPI/gui-plugins/CMakeLists.txt b/source/RobotAPI/gui-plugins/CMakeLists.txt
index d215b7276e4d6eaf4c420493466e54630d1faff7..48c9062175974a656810cb82721bdca203b2769c 100644
--- a/source/RobotAPI/gui-plugins/CMakeLists.txt
+++ b/source/RobotAPI/gui-plugins/CMakeLists.txt
@@ -27,3 +27,5 @@ add_subdirectory(GraspCandidateViewer)
 add_subdirectory(BoxToGraspCandidates)
 
 
+
+add_subdirectory(DebugRobotUnitDataStreaming)
\ No newline at end of file
diff --git a/source/RobotAPI/gui-plugins/CartesianWaypointControlGui/CartesianWaypointControlGuiWidget.ui b/source/RobotAPI/gui-plugins/CartesianWaypointControlGui/CartesianWaypointControlGuiWidget.ui
index 85819912107bc3006fb94cec8a71428f57e0481f..fef69f4366e204f0a27fa3857e0221d7d7dba2bb 100644
--- a/source/RobotAPI/gui-plugins/CartesianWaypointControlGui/CartesianWaypointControlGuiWidget.ui
+++ b/source/RobotAPI/gui-plugins/CartesianWaypointControlGui/CartesianWaypointControlGuiWidget.ui
@@ -135,6 +135,13 @@
              </property>
             </spacer>
            </item>
+           <item>
+            <widget class="QPushButton" name="pushButtonCopyCurrentPose">
+             <property name="text">
+              <string>copy current pose</string>
+             </property>
+            </widget>
+           </item>
            <item>
             <widget class="QLabel" name="labelParsingSuccess">
              <property name="text">
@@ -524,6 +531,16 @@
            </item>
           </layout>
          </item>
+         <item row="7" column="2" colspan="6">
+          <widget class="QCheckBox" name="checkBoxSkipWaypoints">
+           <property name="text">
+            <string>Skip waypoints</string>
+           </property>
+           <property name="checked">
+            <bool>true</bool>
+           </property>
+          </widget>
+         </item>
         </layout>
        </widget>
       </item>
diff --git a/source/RobotAPI/gui-plugins/CartesianWaypointControlGui/CartesianWaypointControlGuiWidgetController.cpp b/source/RobotAPI/gui-plugins/CartesianWaypointControlGui/CartesianWaypointControlGuiWidgetController.cpp
index 7f245db4be10b20612849486bb388071c1504875..303aa4ecdeabc7030e74b432858cb9c063b7f5bc 100644
--- a/source/RobotAPI/gui-plugins/CartesianWaypointControlGui/CartesianWaypointControlGuiWidgetController.cpp
+++ b/source/RobotAPI/gui-plugins/CartesianWaypointControlGui/CartesianWaypointControlGuiWidgetController.cpp
@@ -23,6 +23,8 @@
 #include <random>
 #include <string>
 
+#include <QClipboard>
+
 #include <SimoxUtility/json.h>
 
 #include <ArmarXCore/util/CPPUtility/container.h>
@@ -38,13 +40,14 @@ namespace armarx
         using T = CartesianWaypointControlGuiWidgetController;
         std::lock_guard g{_allMutex};
         _ui.setupUi(getWidget());
-        connect(_ui.radioButtonWPJson, &QPushButton::clicked, this, &T::triggerParsing);
-        connect(_ui.radioButton4f,     &QPushButton::clicked, this, &T::triggerParsing);
-        connect(_ui.textEditWPs,       &QTextEdit::textChanged, this, &T::triggerParsing);
+        connect(_ui.radioButtonWPJson,         &QPushButton::clicked,   this, &T::triggerParsing);
+        connect(_ui.radioButton4f,             &QPushButton::clicked,   this, &T::triggerParsing);
+        connect(_ui.textEditWPs,               &QTextEdit::textChanged, this, &T::triggerParsing);
 
-        connect(_ui.pushButtonExecute,      &QPushButton::clicked, this, &T::on_pushButtonExecute_clicked);
-        connect(_ui.pushButtonZeroFT,       &QPushButton::clicked, this, &T::on_pushButtonZeroFT_clicked);
-        connect(_ui.pushButtonSendSettings, &QPushButton::clicked, this, &T::on_pushButtonSendSettings_clicked);
+        connect(_ui.pushButtonExecute,         &QPushButton::clicked,   this, &T::on_pushButtonExecute_clicked);
+        connect(_ui.pushButtonZeroFT,          &QPushButton::clicked,   this, &T::on_pushButtonZeroFT_clicked);
+        connect(_ui.pushButtonSendSettings,    &QPushButton::clicked,   this, &T::on_pushButtonSendSettings_clicked);
+        connect(_ui.pushButtonCopyCurrentPose, &QPushButton::clicked,   this, &T::copyCurrentPose);
 
         connectCreateAcivateDeactivateDelete(
             _ui.pushButtonCreateController,
@@ -88,6 +91,28 @@ namespace armarx
         }
     }
 
+    void CartesianWaypointControlGuiWidgetController::copyCurrentPose()
+    {
+        std::lock_guard g{_allMutex};
+        if (!_robot)
+        {
+            return;
+        }
+        synchronizeLocalClone(_robot);
+        const auto rns = _robot->getRobotNodeSet(_ui.comboBoxChain->currentText().toStdString());
+        if (!rns)
+        {
+            return;
+        }
+        const auto tcp = rns->getTCP();
+        if (!tcp)
+        {
+            return;
+        }
+        const auto str = simox::json::eigen4f2posquatJson(tcp->getPoseInRootFrame());
+        QApplication::clipboard()->setText(QString::fromStdString(str));
+    }
+
     void CartesianWaypointControlGuiWidgetController::on_pushButtonZeroFT_clicked()
     {
         std::lock_guard g{_allMutex};
@@ -148,26 +173,27 @@ namespace armarx
         std::lock_guard g{_allMutex};
         NJointCartesianWaypointControllerRuntimeConfig cfg;
 
-        cfg.wpCfg.maxPositionAcceleration     = static_cast<float>(_ui.doubleSpinBoxMaxAccPos->value());
-        cfg.wpCfg.maxOrientationAcceleration  = static_cast<float>(_ui.doubleSpinBoxMaxAccOri->value());
-        cfg.wpCfg.maxNullspaceAcceleration    = static_cast<float>(_ui.doubleSpinBoxMaxAccNull->value());
+        cfg.wpCfg.maxPositionAcceleration       = static_cast<float>(_ui.doubleSpinBoxMaxAccPos->value());
+        cfg.wpCfg.maxOrientationAcceleration    = static_cast<float>(_ui.doubleSpinBoxMaxAccOri->value());
+        cfg.wpCfg.maxNullspaceAcceleration      = static_cast<float>(_ui.doubleSpinBoxMaxAccNull->value());
 
-        cfg.wpCfg.kpJointLimitAvoidance       = static_cast<float>(_ui.doubleSpinBoxLimitAvoidKP->value());
-        cfg.wpCfg.jointLimitAvoidanceScale    = static_cast<float>(_ui.doubleSpinBoxLimitAvoidScale->value());
+        cfg.wpCfg.kpJointLimitAvoidance         = static_cast<float>(_ui.doubleSpinBoxLimitAvoidKP->value());
+        cfg.wpCfg.jointLimitAvoidanceScale      = static_cast<float>(_ui.doubleSpinBoxLimitAvoidScale->value());
 
-        cfg.wpCfg.thresholdOrientationNear    = static_cast<float>(_ui.doubleSpinBoxOriNear->value());
-        cfg.wpCfg.thresholdOrientationReached = static_cast<float>(_ui.doubleSpinBoxOriReached->value());
-        cfg.wpCfg.thresholdPositionNear       = static_cast<float>(_ui.doubleSpinBoxPosNear->value());
-        cfg.wpCfg.thresholdPositionReached    = static_cast<float>(_ui.doubleSpinBoxPosReached->value());
+        cfg.wpCfg.thresholdOrientationNear      = static_cast<float>(_ui.doubleSpinBoxOriNear->value());
+        cfg.wpCfg.thresholdOrientationReached   = static_cast<float>(_ui.doubleSpinBoxOriReached->value());
+        cfg.wpCfg.thresholdPositionNear         = static_cast<float>(_ui.doubleSpinBoxPosNear->value());
+        cfg.wpCfg.thresholdPositionReached      = static_cast<float>(_ui.doubleSpinBoxPosReached->value());
 
-        cfg.wpCfg.maxOriVel                   = static_cast<float>(_ui.doubleSpinBoxOriMaxVel->value());
-        cfg.wpCfg.maxPosVel                   = static_cast<float>(_ui.doubleSpinBoxPosMaxVel->value());
-        cfg.wpCfg.kpOri                       = static_cast<float>(_ui.doubleSpinBoxOriKP->value());
-        cfg.wpCfg.kpPos                       = static_cast<float>(_ui.doubleSpinBoxPosKP->value());
+        cfg.wpCfg.maxOriVel                     = static_cast<float>(_ui.doubleSpinBoxOriMaxVel->value());
+        cfg.wpCfg.maxPosVel                     = static_cast<float>(_ui.doubleSpinBoxPosMaxVel->value());
+        cfg.wpCfg.kpOri                         = static_cast<float>(_ui.doubleSpinBoxOriKP->value());
+        cfg.wpCfg.kpPos                         = static_cast<float>(_ui.doubleSpinBoxPosKP->value());
 
-        cfg.forceThreshold                    = static_cast<float>(_ui.doubleSpinBoxFTLimit->value());
+        cfg.forceThreshold                      = static_cast<float>(_ui.doubleSpinBoxFTLimit->value());
         cfg.optimizeNullspaceIfTargetWasReached = _ui.checkBoxKeepOptimizing->isChecked();
         cfg.forceThresholdInRobotRootZ          = _ui.checkBoxLimitinZ->isChecked();
+        cfg.skipToClosestWaypoint               = _ui.checkBoxSkipWaypoints->isChecked();
 
         return cfg;
     }
diff --git a/source/RobotAPI/gui-plugins/CartesianWaypointControlGui/CartesianWaypointControlGuiWidgetController.h b/source/RobotAPI/gui-plugins/CartesianWaypointControlGui/CartesianWaypointControlGuiWidgetController.h
index f5358b49ea1dfbb097abd2d9432b403ee823f46c..01c59683c8dd3081e50ac58aa180d9c1a1d7ced0 100644
--- a/source/RobotAPI/gui-plugins/CartesianWaypointControlGui/CartesianWaypointControlGuiWidgetController.h
+++ b/source/RobotAPI/gui-plugins/CartesianWaypointControlGui/CartesianWaypointControlGuiWidgetController.h
@@ -76,6 +76,7 @@ namespace armarx
         void on_pushButtonZeroFT_clicked();
         void on_pushButtonSendSettings_clicked();
         void createController() override;
+        void copyCurrentPose();
 
         void triggerParsing();
 
diff --git a/source/RobotAPI/gui-plugins/DebugRobotUnitDataStreaming/CMakeLists.txt b/source/RobotAPI/gui-plugins/DebugRobotUnitDataStreaming/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..04cb7202b49e8c7f215334bd07e001a50f5e819b
--- /dev/null
+++ b/source/RobotAPI/gui-plugins/DebugRobotUnitDataStreaming/CMakeLists.txt
@@ -0,0 +1,17 @@
+set(LIB_NAME "DebugRobotUnitDataStreamingGuiPlugin")
+armarx_set_target("${LIB_NAME}")
+
+armarx_build_if(ArmarXGui_FOUND "ArmarXGui not available")
+
+# do not rename this variable, it is used in armarx_gui_library()...
+set(SOURCES DebugRobotUnitDataStreamingWidgetController.cpp)
+set(HEADERS DebugRobotUnitDataStreamingWidgetController.h)
+set(GUI_UIS DebugRobotUnitDataStreamingWidget.ui)
+
+set(COMPONENT_LIBS
+    RobotAPIComponentPlugins
+    SimpleConfigDialog)
+
+if(ArmarXGui_FOUND)
+    armarx_gui_plugin("${LIB_NAME}" "${SOURCES}" "" "${GUI_UIS}" "" "${COMPONENT_LIBS}")
+endif()
diff --git a/source/RobotAPI/gui-plugins/DebugRobotUnitDataStreaming/DebugRobotUnitDataStreamingWidget.ui b/source/RobotAPI/gui-plugins/DebugRobotUnitDataStreaming/DebugRobotUnitDataStreamingWidget.ui
new file mode 100644
index 0000000000000000000000000000000000000000..cbf9340e13c887af2e06fc39c6621698b5a09560
--- /dev/null
+++ b/source/RobotAPI/gui-plugins/DebugRobotUnitDataStreaming/DebugRobotUnitDataStreamingWidget.ui
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>DebugRobotUnitDataStreamingWidget</class>
+ <widget class="QWidget" name="DebugRobotUnitDataStreamingWidget">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>400</width>
+    <height>300</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>DebugRobotUnitDataStreamingWidget</string>
+  </property>
+  <layout class="QGridLayout" name="gridLayout">
+   <item row="0" column="1">
+    <widget class="QSpinBox" name="spinBoxNumberOfStreams">
+     <property name="maximum">
+      <number>100</number>
+     </property>
+    </widget>
+   </item>
+   <item row="1" column="0">
+    <spacer name="verticalSpacer">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>247</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item row="0" column="0">
+    <widget class="QLabel" name="label">
+     <property name="text">
+      <string>number of streams</string>
+     </property>
+    </widget>
+   </item>
+   <item row="0" column="4">
+    <spacer name="horizontalSpacer">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>185</width>
+       <height>20</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item row="0" column="2">
+    <widget class="QCheckBox" name="checkBoxStreamSens">
+     <property name="text">
+      <string>Sens</string>
+     </property>
+     <property name="checked">
+      <bool>true</bool>
+     </property>
+    </widget>
+   </item>
+   <item row="0" column="3">
+    <widget class="QCheckBox" name="checkBoxStreamCtrl">
+     <property name="text">
+      <string>Ctrl</string>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/source/RobotAPI/gui-plugins/DebugRobotUnitDataStreaming/DebugRobotUnitDataStreamingWidgetController.cpp b/source/RobotAPI/gui-plugins/DebugRobotUnitDataStreaming/DebugRobotUnitDataStreamingWidgetController.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..18c9dc655ed8af90cb5f557d0f2ac6fb09c12643
--- /dev/null
+++ b/source/RobotAPI/gui-plugins/DebugRobotUnitDataStreaming/DebugRobotUnitDataStreamingWidgetController.cpp
@@ -0,0 +1,100 @@
+/*
+ * 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::gui-plugins::DebugRobotUnitDataStreamingWidgetController
+ * \author     Raphael Grimm ( raphael dot grimm at kit dot edu )
+ * \date       2021
+ * \copyright  http://www.gnu.org/licenses/gpl-2.0.txt
+ *             GNU General Public License
+ */
+
+#include "DebugRobotUnitDataStreamingWidgetController.h"
+
+#include <string>
+
+namespace armarx
+{
+
+    void DebugRobotUnitDataStreamingWidgetController::loadSettings(QSettings* settings)
+    {
+        getRobotUnitComponentPlugin().setRobotUnitName(
+            settings->value("ru", "Armar6Unit").toString().toStdString());
+    }
+
+    void DebugRobotUnitDataStreamingWidgetController::saveSettings(QSettings* settings)
+    {
+        settings->setValue("ru", QString::fromStdString(getRobotUnitComponentPlugin().getRobotUnitName()));
+    }
+
+    QPointer<QDialog> DebugRobotUnitDataStreamingWidgetController::getConfigDialog(QWidget* parent)
+    {
+        if (!dialog)
+        {
+            dialog = new SimpleConfigDialog(parent);
+            dialog->addProxyFinder<RobotUnitInterfacePrx>("ru", "Robot Unit", "*Unit");
+        }
+        return qobject_cast<SimpleConfigDialog*>(dialog);
+    }
+
+    void DebugRobotUnitDataStreamingWidgetController::configured()
+    {
+        getRobotUnitComponentPlugin().setRobotUnitName(dialog->get("ru"));
+    }
+
+    DebugRobotUnitDataStreamingWidgetController::DebugRobotUnitDataStreamingWidgetController()
+    {
+        widget.setupUi(getWidget());
+        startTimer(10);
+    }
+
+    void DebugRobotUnitDataStreamingWidgetController::onDisconnectComponent()
+    {
+        std::lock_guard f{mutex};
+        rec.clear();
+    }
+
+    void DebugRobotUnitDataStreamingWidgetController::timerEvent(QTimerEvent* event)
+    {
+        const std::size_t n = widget.spinBoxNumberOfStreams->value();
+        if(!getRobotUnit())
+        {
+            return;
+        }
+        if (rec.size() > n)
+        {
+            rec.resize(n);
+        }
+        std::lock_guard f{mutex};
+        RobotUnitDataStreaming::Config cfg;
+        if(widget.checkBoxStreamSens->isChecked())
+        {
+            cfg.loggingNames.emplace_back("sens");
+        }
+        if(widget.checkBoxStreamCtrl->isChecked())
+        {
+            cfg.loggingNames.emplace_back("ctrl");
+        }
+        while (rec.size() < n)
+        {
+            rec.emplace_back(getRobotUnitComponentPlugin()
+                             .startDataSatreming(cfg));
+            ARMARX_INFO << rec.back()->getDataDescriptionString();
+        }
+        for (auto& r : rec)
+        {
+            r->getDataBuffer().clear();
+        }
+    }
+}
diff --git a/source/RobotAPI/gui-plugins/DebugRobotUnitDataStreaming/DebugRobotUnitDataStreamingWidgetController.h b/source/RobotAPI/gui-plugins/DebugRobotUnitDataStreaming/DebugRobotUnitDataStreamingWidgetController.h
new file mode 100644
index 0000000000000000000000000000000000000000..436985349fdc03139f6ded9a0a0b6a5327c1fdab
--- /dev/null
+++ b/source/RobotAPI/gui-plugins/DebugRobotUnitDataStreaming/DebugRobotUnitDataStreamingWidgetController.h
@@ -0,0 +1,100 @@
+/*
+ * 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::gui-plugins::DebugRobotUnitDataStreamingWidgetController
+ * @author     Raphael Grimm ( raphael dot grimm at kit dot edu )
+ * @date       2021
+ * @copyright  http://www.gnu.org/licenses/gpl-2.0.txt
+ *             GNU General Public License
+ */
+#pragma once
+
+#include <ArmarXCore/core/system/ImportExportComponent.h>
+
+#include <ArmarXGui/libraries/SimpleConfigDialog/SimpleConfigDialog.h>
+#include <ArmarXGui/libraries/ArmarXGuiBase/ArmarXGuiPlugin.h>
+#include <ArmarXGui/libraries/ArmarXGuiBase/ArmarXComponentWidgetController.h>
+
+#include <RobotAPI/gui-plugins/DebugRobotUnitDataStreaming/ui_DebugRobotUnitDataStreamingWidget.h>
+#include <RobotAPI/libraries/RobotAPIComponentPlugins/RobotUnitComponentPlugin.h>
+
+namespace armarx
+{
+    /**
+    \page RobotAPI-GuiPlugins-DebugRobotUnitDataStreaming DebugRobotUnitDataStreaming
+    \brief The DebugRobotUnitDataStreaming allows visualizing ...
+
+    \image html DebugRobotUnitDataStreaming.png
+    The user can
+
+    API Documentation \ref DebugRobotUnitDataStreamingWidgetController
+
+    \see DebugRobotUnitDataStreamingGuiPlugin
+    */
+
+
+    /**
+     * \class DebugRobotUnitDataStreamingGuiPlugin
+     * \ingroup ArmarXGuiPlugins
+     * \brief DebugRobotUnitDataStreamingGuiPlugin brief description
+     *
+     * Detailed description
+     */
+
+    /**
+     * \class DebugRobotUnitDataStreamingWidgetController
+     * \brief DebugRobotUnitDataStreamingWidgetController brief one line description
+     *
+     * Detailed description
+     */
+    class ARMARXCOMPONENT_IMPORT_EXPORT
+        DebugRobotUnitDataStreamingWidgetController:
+        public armarx::ArmarXComponentWidgetControllerTemplate < DebugRobotUnitDataStreamingWidgetController >,
+            public virtual RobotUnitComponentPluginUser
+    {
+        Q_OBJECT
+    public:
+        explicit DebugRobotUnitDataStreamingWidgetController();
+        
+        void loadSettings(QSettings* settings) override;
+        void saveSettings(QSettings* settings) override;
+        QPointer<QDialog> getConfigDialog(QWidget* parent) override;
+        void configured() override;
+
+        /**
+         * Returns the Widget name displayed in the ArmarXGui to create an
+         * instance of this class.
+         */
+        static QString GetWidgetName()
+        {
+            return "Debugging.DebugRobotUnitDataStreaming";
+        }
+        
+        void onInitComponent()       override {}
+        void onConnectComponent()    override {}
+        void onDisconnectComponent() override;
+        void onExitComponent()       override {}
+        
+    protected:
+        void timerEvent(QTimerEvent* event) override;
+
+    private:
+        std::mutex                                     mutex;
+        Ui::DebugRobotUnitDataStreamingWidget          widget;
+        std::vector<RobotUnitDataStreamingReceiverPtr> rec;
+        QPointer<SimpleConfigDialog>                   dialog;};
+}
+
+
diff --git a/source/RobotAPI/gui-plugins/FTSensorCalibrationGui/FTSensorCalibrationGuiWidgetController.cpp b/source/RobotAPI/gui-plugins/FTSensorCalibrationGui/FTSensorCalibrationGuiWidgetController.cpp
index 6252b2b9a4af2d0d9a18e32d12d876099d6a80bd..288e480893d5f9865a83781fcde00ed799d7ccf7 100644
--- a/source/RobotAPI/gui-plugins/FTSensorCalibrationGui/FTSensorCalibrationGuiWidgetController.cpp
+++ b/source/RobotAPI/gui-plugins/FTSensorCalibrationGui/FTSensorCalibrationGuiWidgetController.cpp
@@ -222,9 +222,9 @@ namespace armarx
                 {
                     _logfile << s.iterationId << ';' << s.timestampUSec;
                     //logging
-                    RobotUnitDataStreamingReceiver::visitEntries(log, s, _adc);
-                    RobotUnitDataStreamingReceiver::visitEntries(log, s, _adc_temp);
-                    RobotUnitDataStreamingReceiver::visitEntries(log, s, _joints);
+                    RobotUnitDataStreamingReceiver::VisitEntries(log, s, _adc);
+                    RobotUnitDataStreamingReceiver::VisitEntries(log, s, _adc_temp);
+                    RobotUnitDataStreamingReceiver::VisitEntries(log, s, _joints);
                     _logfile << '\n';
                 }
                 std::vector<float> vals;
@@ -234,8 +234,8 @@ namespace armarx
                     {
                         vals.emplace_back(n);
                     };
-                    RobotUnitDataStreamingReceiver::visitEntries(pback, last, _adc);
-                    RobotUnitDataStreamingReceiver::visitEntries(pback, last, _adc_temp);
+                    RobotUnitDataStreamingReceiver::VisitEntries(pback, last, _adc);
+                    RobotUnitDataStreamingReceiver::VisitEntries(pback, last, _adc_temp);
                 }
                 //calc + compensate
 
diff --git a/source/RobotAPI/gui-plugins/RobotUnitPlugin/QWidgets/NJointControllerClassesWidget.cpp b/source/RobotAPI/gui-plugins/RobotUnitPlugin/QWidgets/NJointControllerClassesWidget.cpp
index 7df85b9141364c93721785486e19de74da364655..27cf1dca60f0d527637c9c3901998caf4324eb54 100644
--- a/source/RobotAPI/gui-plugins/RobotUnitPlugin/QWidgets/NJointControllerClassesWidget.cpp
+++ b/source/RobotAPI/gui-plugins/RobotUnitPlugin/QWidgets/NJointControllerClassesWidget.cpp
@@ -316,7 +316,8 @@ namespace armarx
                 QPushButton* button = new QPushButton {"Create"};
                 headerW->layout()->addWidget(button);
                 button->setToolTip("Create a new controller instance of this class");
-                connect(button, SIGNAL(clicked(bool)), this, SLOT(createCtrl()));
+                connect(button, &QPushButton::clicked, this, &NJointControllerClassesWidgetEntry::createCtrl);
+                connect(nameEdit, &QLineEdit::returnPressed, this, &NJointControllerClassesWidgetEntry::createCtrl);
             }
             //descr
             {
diff --git a/source/RobotAPI/interface/core/RobotStateObserverInterface.ice b/source/RobotAPI/interface/core/RobotStateObserverInterface.ice
index 6f0abb5b36e73a1b5bda9550d45d5a3bad9ad5c8..1a6115fbe83d4c534876f27d54113156ba2c8d8f 100644
--- a/source/RobotAPI/interface/core/RobotStateObserverInterface.ice
+++ b/source/RobotAPI/interface/core/RobotStateObserverInterface.ice
@@ -29,7 +29,7 @@
 
 module armarx
 {
-    interface RobotStateObserverInterface extends ObserverInterface
+    ["amd"] interface RobotStateObserverInterface extends ObserverInterface
     {
         ["cpp:const"]
         idempotent DatafieldRefBase getPoseDatafield(string nodeName);
diff --git a/source/RobotAPI/interface/units/RobotUnit/NJointCartesianWaypointController.ice b/source/RobotAPI/interface/units/RobotUnit/NJointCartesianWaypointController.ice
index 44cba9dad29c8b6d56d0dd1143f5aa724e8f23f6..712399c5f77ec1a7c116b3e77b0ad2e4df616a87 100644
--- a/source/RobotAPI/interface/units/RobotUnit/NJointCartesianWaypointController.ice
+++ b/source/RobotAPI/interface/units/RobotUnit/NJointCartesianWaypointController.ice
@@ -36,6 +36,7 @@ module armarx
         float forceThreshold = -1; // < 0 -> no limit
         bool forceThresholdInRobotRootZ = true;
         bool optimizeNullspaceIfTargetWasReached = false;
+        bool skipToClosestWaypoint = true;
     };
 
     class NJointCartesianWaypointControllerConfig extends NJointControllerConfig
diff --git a/source/RobotAPI/interface/units/RobotUnit/RobotUnitInterface.ice b/source/RobotAPI/interface/units/RobotUnit/RobotUnitInterface.ice
index c7871f0860fbe343a1704b2022f54a8ed6cd8674..dac07929c87809b5b51552cf79ab07ffe0b51e0d 100644
--- a/source/RobotAPI/interface/units/RobotUnit/RobotUnitInterface.ice
+++ b/source/RobotAPI/interface/units/RobotUnit/RobotUnitInterface.ice
@@ -222,7 +222,7 @@ module armarx
 
         interface Receiver
         {
-            void update(TimeStepSeq data);
+            ["amd"] void update(TimeStepSeq data, long msgSequenceNbr);
         };
 
         struct Config
diff --git a/source/RobotAPI/libraries/GraspingUtility/GraspCandidateProvider.cpp b/source/RobotAPI/libraries/GraspingUtility/GraspCandidateProvider.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..99a80a53febe01e9f91cdedee69e4bbc91a35555
--- /dev/null
+++ b/source/RobotAPI/libraries/GraspingUtility/GraspCandidateProvider.cpp
@@ -0,0 +1,103 @@
+
+
+//#include <ArmarXCore/core/application/properties/PluginAll.h>
+//#include <ArmarXGui/libraries/RemoteGui/ConfigIntrospection.h>
+
+
+#include "GraspCandidateProvider.h"
+
+////boilerplate (properties / cycle)
+//namespace arches
+//{
+//    std::string GraspCandidateCollisionFilter::getDefaultName() const
+//    {
+//        return "GraspCandidateCollisionFilter";
+//    }
+
+//    armarx::PropertyDefinitionsPtr
+//    GraspCandidateCollisionFilter::createPropertyDefinitions()
+//    {
+//        armarx::PropertyDefinitionsPtr ptr =
+//            new visionx::PointCloudProcessorPropertyDefinitions(getConfigIdentifier());
+//        ptr->optional(_cfg_buf.getWriteBuffer(), "", "");
+//        ptr->optional(_provider.ref_frame_name_default,
+//                      "ReferenceFrame",
+//                      "ReferenceFrame (if not set, autodetection is performed)");
+//        ptr->optional(_upstream_gc_provider_csv,
+//                      "UpstreamGraspCandidateProviderCSV",
+//                      "Upstream Provider(s) (if empty all)");
+//        ptr->topic(_gc_topic,
+//                   "GraspCandidatesTopicName",
+//                   "GraspCandidatesTopic",
+//                   "Name of the Grasp Candidate Topic");
+//        ptr->topic(_service_request_topic,
+//                   "ServiceRequestsTopicName",
+//                   "ServiceRequests",
+//                   "Name of the ServiceRequestsTopic");
+//        return ptr;
+//    }
+
+//    void GraspCandidateCollisionFilter::onInitPointCloudProcessor()
+//    {
+//        ARMARX_TRACE;
+//        ARMARX_INFO << "init...";
+//        setDebugObserverBatchModeEnabled(true);
+//        getProperty(_provider.name, "ProviderName");
+//        ARMARX_INFO << "init...done!";
+//    }
+//    void GraspCandidateCollisionFilter::onConnectPointCloudProcessor()
+//    {
+//        ARMARX_TRACE;
+//        ARMARX_INFO << "connect...";
+//        ARMARX_INFO << "prov frame";
+//        {
+//            ARMARX_TRACE;
+//            _provider.info = getPointCloudProvider(_provider.name, true);
+//            _provider.proxy = _provider.info.proxy;
+//            ARMARX_CHECK_NOT_NULL(_provider.proxy) << VAROUT(_provider.name);
+//            _provider.ref_frame_name_used =
+//                _provider.ref_frame_name_default.empty() ?
+//                getPointCloudFrame(_provider.name, _provider.ref_frame_name_default) :
+//                _provider.ref_frame_name_default;
+//            ARMARX_CHECK_EXPRESSION(!_provider.ref_frame_name_used.empty())
+//                    << VAROUT(_provider.name) << " default = "
+//                    << VAROUT(_provider.ref_frame_name_default);
+//            ARMARX_INFO << "Provider '" << _provider.name
+//                        << "' has ref frame '" << _provider.ref_frame_name_used << "'";
+//        }
+//        ARMARX_INFO << "robot";
+//        _robot = addRobot("grounding", VirtualRobot::RobotIO::eStructure);
+//        ARMARX_INFO << "gui";
+//        createOrUpdateRemoteGuiTab(_cfg_buf);
+//        ARMARX_INFO << "configure gc observer";
+//        getGraspCandidateObserverComponentPlugin().setUpstreamGraspCandidateProvidersFromCSV(_upstream_gc_provider_csv);
+//        ARMARX_INFO << "configure colision checker!";
+//        //        _gc_col_checker.reset(getRobotNameHelper(), _robot);
+//        ARMARX_INFO << "start reporting gc config!";
+//        startPeriodicTask("reportConfigTask", [&]()
+//        {
+//            _gc_topic->reportProviderInfo(getName(), getProviderInfo());
+//        }, 1000, false);
+//        ARMARX_INFO << "connect...done!";
+//    }
+
+//    void GraspCandidateCollisionFilter::requestService(
+//        const std::string& providerName,
+//        Ice::Int relativeTimeoutMS,
+//        const Ice::Current&)
+//    {
+//        if (providerName == getName() || providerName == "AllGraspProviders")
+//        {
+//            ///TODO do not ignore this!
+//            _service_request_topic->requestService(getProperty<std::string>("ServiceRequestsTopicName").getValue(), relativeTimeoutMS);
+//        }
+//    }
+//    armarx::grasping::ProviderInfoPtr GraspCandidateCollisionFilter::getProviderInfo() const
+//    {
+//        armarx::grasping::ProviderInfoPtr info = new armarx::grasping::ProviderInfo();
+//        info->objectType = armarx::grasping::AnyObject;
+//        return info;
+//    }
+//}
+
+
diff --git a/source/RobotAPI/libraries/GraspingUtility/GraspCandidateProvider.h b/source/RobotAPI/libraries/GraspingUtility/GraspCandidateProvider.h
new file mode 100644
index 0000000000000000000000000000000000000000..7b2095c08364c4d0a5cd870f908ff6e45d38e6b9
--- /dev/null
+++ b/source/RobotAPI/libraries/GraspingUtility/GraspCandidateProvider.h
@@ -0,0 +1,64 @@
+#pragma once
+
+////plugins
+//#include <ArmarXCore/libraries/ArmarXCoreComponentPlugins/DebugObserverComponentPlugin.h>
+//#include <ArmarXGui/libraries/ArmarXGuiComponentPlugins/RemoteGuiComponentPlugin.h>
+//#include <RobotAPI/libraries/RobotAPIComponentPlugins/ArVizComponentPlugin.h>
+//#include <RobotAPI/libraries/RobotAPIComponentPlugins/RobotStateComponentPlugin.h>
+//#include <RobotAPI/libraries/RobotAPIComponentPlugins/GraspCandidateObserverComponentPlugin.h>
+
+////other
+//#include <ArmarXCore/util/CPPUtility/ConfigIntrospection/create_macro.h>
+//#include <RobotAPI/interface/observers/GraspCandidateObserverInterface.h>
+
+namespace armarx
+{
+    //    class GraspCandidateCollisionFilter :
+    //        virtual public visionx::PointCloudProcessor,
+    //        virtual public armarx::RemoteGuiComponentPluginUser,
+    //        virtual public armarx::DebugObserverComponentPluginUser,
+    //        virtual public armarx::ArVizComponentPluginUser,
+    //        virtual public armarx::RobotStateComponentPluginUser,
+    //        virtual public armarx::GraspCandidateObserverComponentPluginUser,
+    //        public arches::time_util<std::chrono::high_resolution_clock>
+    //    {
+    //    public:
+    //        using clock_t      = std::chrono::high_resolution_clock;
+    //        using time_point_t = typename clock_t::time_point;
+    //        using config_t     = arches::cfg::GCColFilter::config;
+
+    //        std::string getDefaultName() const override;
+
+    //        void requestService(const std::string& providerName, Ice::Int relativeTimeoutMS, const Ice::Current&);
+    //        armarx::grasping::ProviderInfoPtr getProviderInfo() const;
+    //    protected:
+    //        void onInitPointCloudProcessor()                           override;
+    //        void onConnectPointCloudProcessor()                        override;
+    //        void onDisconnectPointCloudProcessor()                     override {}
+    //        void onExitPointCloudProcessor()                           override {}
+    //        armarx::PropertyDefinitionsPtr createPropertyDefinitions() override;
+    //    private:
+    //        void process() override;
+    //        template<class PointT>
+    //        void process();
+
+
+    //    private:
+    //        struct provider_data
+    //        {
+    //            std::string                             ref_frame_name_default;
+    //            std::string                             ref_frame_name_used;
+    //            std::string                             name;
+    //            visionx::PointCloudProviderInfo         info;
+    //            visionx::PointCloudProviderInterfacePrx proxy;
+    //        };
+    //        provider_data                                      _provider;
+    //        armarx::WriteBufferedTripleBuffer<config_t>        _cfg_buf;
+    //        VirtualRobot::RobotPtr                             _robot;
+    //        //        grasp_candidate_collision_checker                  _gc_col_checker;
+    //        std::string                                        _upstream_gc_provider_csv;
+    //        std::size_t                                        _old_num_visualized;
+    //        armarx::grasping::GraspCandidatesTopicInterfacePrx _gc_topic;
+    //        armarx::RequestableServiceListenerInterfacePrx     _service_request_topic;
+    //    };
+}
diff --git a/source/RobotAPI/libraries/RobotAPIComponentPlugins/CMakeLists.txt b/source/RobotAPI/libraries/RobotAPIComponentPlugins/CMakeLists.txt
index 3c9bbe17dda9debf6b63cc753f70cc9685e49fb1..8e61ccd8332b8ef0c8cc4fc891dd2548a68a5682 100644
--- a/source/RobotAPI/libraries/RobotAPIComponentPlugins/CMakeLists.txt
+++ b/source/RobotAPI/libraries/RobotAPIComponentPlugins/CMakeLists.txt
@@ -8,6 +8,7 @@ set(LIBS
     DebugDrawer
     diffik
     RobotStatechartHelpers
+    RobotUnitDataStreamingReceiver
 )
 
 set(LIB_FILES
diff --git a/source/RobotAPI/libraries/RobotAPIComponentPlugins/RobotStateComponentPlugin.cpp b/source/RobotAPI/libraries/RobotAPIComponentPlugins/RobotStateComponentPlugin.cpp
index e711da48631a7562fbc748ff2ef5d0d26d6fd84c..026024a9fb704181271f09f69ec4b94306a3d295 100644
--- a/source/RobotAPI/libraries/RobotAPIComponentPlugins/RobotStateComponentPlugin.cpp
+++ b/source/RobotAPI/libraries/RobotAPIComponentPlugins/RobotStateComponentPlugin.cpp
@@ -212,12 +212,12 @@ namespace armarx::plugins
 
     void RobotStateComponentPlugin::preOnInitComponent()
     {
-        if (!_robotStateComponent && _robotStateComponentName.empty())
+        if (!_deactivated && !_robotStateComponent && _robotStateComponentName.empty())
         {
             parent<Component>().getProperty(_robotStateComponentName, makePropertyName(_propertyName));
         }
 
-        if (!_robotStateComponent)
+        if (!_deactivated && !_robotStateComponent)
         {
             parent<Component>().usingProxy(_robotStateComponentName);
         }
@@ -225,11 +225,14 @@ namespace armarx::plugins
 
     void RobotStateComponentPlugin::preOnConnectComponent()
     {
-        if (!_robotStateComponent)
+        if (!_deactivated && !_robotStateComponent)
         {
             parent<Component>().getProxy(_robotStateComponent, _robotStateComponentName);
         }
-        _nameHelper = std::make_shared<RobotNameHelper>(_robotStateComponent->getRobotInfo());
+        if (!_deactivated)
+        {
+            _nameHelper = std::make_shared<RobotNameHelper>(_robotStateComponent->getRobotInfo());
+        }
     }
 
     void RobotStateComponentPlugin::postOnDisconnectComponent()
@@ -274,6 +277,11 @@ namespace armarx::plugins
         return _robotStateComponentName;
     }
 
+    void RobotStateComponentPlugin::deactivate()
+    {
+        _deactivated = true;
+    }
+
     Eigen::Matrix4f RobotStateComponentPlugin::transformFromTo(
         const std::string& from,
         const std::string& to,
diff --git a/source/RobotAPI/libraries/RobotAPIComponentPlugins/RobotStateComponentPlugin.h b/source/RobotAPI/libraries/RobotAPIComponentPlugins/RobotStateComponentPlugin.h
index 1f267bd715ac192c2152c2534e3a97ce9b8ff8d1..d60ed34f0964b4dc8592c88b055fb32e7bab4608 100644
--- a/source/RobotAPI/libraries/RobotAPIComponentPlugins/RobotStateComponentPlugin.h
+++ b/source/RobotAPI/libraries/RobotAPIComponentPlugins/RobotStateComponentPlugin.h
@@ -57,6 +57,7 @@ namespace armarx::plugins
         void setRobotStateComponentName(const std::string& name);
         void setRobotStateComponent(const RobotStateComponentInterfacePrx& rsc);
         const std::string& getRobotStateComponentName() const;
+        void deactivate();
         //get / add
     public:
         bool hasRobot(const std::string& id) const;
@@ -153,6 +154,7 @@ namespace armarx::plugins
         mutable std::recursive_mutex     _robotsMutex;
         std::map<std::string, RobotData> _robots;
         RobotNameHelperPtr               _nameHelper;
+        bool                             _deactivated = false;
     };
 }
 
diff --git a/source/RobotAPI/libraries/RobotAPIComponentPlugins/RobotUnitComponentPlugin.cpp b/source/RobotAPI/libraries/RobotAPIComponentPlugins/RobotUnitComponentPlugin.cpp
index 1e94a395814376eb08b20e45f5d043f21fa6dbb4..7c120b3cc4db3aabbf6b184e5d747d3014ae0a61 100644
--- a/source/RobotAPI/libraries/RobotAPIComponentPlugins/RobotUnitComponentPlugin.cpp
+++ b/source/RobotAPI/libraries/RobotAPIComponentPlugins/RobotUnitComponentPlugin.cpp
@@ -2,23 +2,86 @@
 
 namespace armarx::plugins
 {
+    RobotUnitDataStreamingReceiverPtr
+    RobotUnitComponentPlugin::startDataSatreming(
+        const RobotUnitDataStreaming::Config& cfg)
+    {
+        //ok to create smart ptr from parent, since ice handels this
+        return make_shared<RobotUnitDataStreamingReceiver>(
+                   &parent(), getRobotUnit(), cfg);
+    }
+
+    void RobotUnitComponentPlugin::postOnDisconnectComponent()
+    {
+        if (!_ctrls.empty())
+        {
+            ARMARX_CHECK_NOT_NULL(_robotUnit);
+            std::vector<std::string> cs(_ctrls.begin(), _ctrls.end());
+            _robotUnit->deactivateAndDeleteNJointControllers(cs);
+        }
+        _robotUnit = nullptr;
+    }
+
+    NJointControllerInterfacePrx RobotUnitComponentPlugin::createNJointController(
+        const std::string& className,
+        const std::string& instanceName,
+        const armarx::NJointControllerConfigPtr& config,
+        bool doManageController)
+    {
+        ARMARX_CHECK_NOT_NULL(_robotUnit);
+        ARMARX_INFO << ARMARX_STREAM_PRINTER
+        {
+            out << "creating ";
+            if (doManageController)
+            {
+                out << "and managing ";
+            }
+            out << " controller '" << instanceName
+                << "' of class '" << instanceName << "'";
+        };
+        const auto prx = _robotUnit->createOrReplaceNJointController(className, instanceName, config);
+        ARMARX_CHECK_NOT_NULL(prx);
+        if (doManageController)
+        {
+            manageController(instanceName);
+        }
+        return prx;
+    }
+
+    void RobotUnitComponentPlugin::manageController(const armarx::NJointControllerInterfacePrx& ctrl)
+    {
+        ARMARX_CHECK_NOT_NULL(ctrl);
+        manageController(ctrl->getInstanceName());
+    }
+
+    void RobotUnitComponentPlugin::manageController(const std::string& ctrl)
+    {
+        _ctrls.emplace(ctrl);
+    }
+
     void RobotUnitComponentPlugin::preOnInitComponent()
     {
-        if (_robotUnitName.empty())
+        if (!_deactivated)
         {
-            parent<Component>().getProperty(_robotUnitName, PROPERTY_NAME);
+            if (_robotUnitName.empty())
+            {
+                parent<Component>().getProperty(_robotUnitName, PROPERTY_NAME);
+            }
+            parent<Component>().usingProxy(_robotUnitName);
         }
-        parent<Component>().usingProxy(_robotUnitName);
     }
 
     void RobotUnitComponentPlugin::preOnConnectComponent()
     {
-        parent<Component>().getProxy(_robotUnit, _robotUnitName);
+        if (!_deactivated)
+        {
+            parent<Component>().getProxy(_robotUnit, _robotUnitName);
+        }
     }
 
     void RobotUnitComponentPlugin::postCreatePropertyDefinitions(armarx::PropertyDefinitionsPtr& properties)
     {
-        if (!properties->hasDefinition(PROPERTY_NAME))
+        if (!_deactivated && !properties->hasDefinition(PROPERTY_NAME))
         {
             properties->defineRequiredProperty<std::string>(
                 PROPERTY_NAME,
@@ -33,14 +96,22 @@ namespace armarx::plugins
 
     void RobotUnitComponentPlugin::setRobotUnitName(const std::string& name)
     {
-        ARMARX_CHECK_NOT_EMPTY(name);
-        ARMARX_CHECK_EMPTY(_robotUnitName);
-        _robotUnitName = name;
+        if (!_deactivated)
+        {
+            ARMARX_CHECK_NOT_EMPTY(name);
+            ARMARX_CHECK_EMPTY(_robotUnitName);
+            _robotUnitName = name;
+        }
     }
     const std::string& RobotUnitComponentPlugin::getRobotUnitName() const
     {
         return _robotUnitName;
     }
+
+    void RobotUnitComponentPlugin::deactivate()
+    {
+        _deactivated = true;
+    }
 }
 
 namespace armarx
diff --git a/source/RobotAPI/libraries/RobotAPIComponentPlugins/RobotUnitComponentPlugin.h b/source/RobotAPI/libraries/RobotAPIComponentPlugins/RobotUnitComponentPlugin.h
index b3cbf9a3b1e43d262370fc3b6082d07612a9c7cc..18616020e0683a70e6fcb0f95c7e7a09939db357 100644
--- a/source/RobotAPI/libraries/RobotAPIComponentPlugins/RobotUnitComponentPlugin.h
+++ b/source/RobotAPI/libraries/RobotAPIComponentPlugins/RobotUnitComponentPlugin.h
@@ -2,6 +2,7 @@
 
 #include <ArmarXCore/core/Component.h>
 #include <RobotAPI/interface/units/RobotUnit/RobotUnitInterface.h>
+#include <RobotAPI/libraries/RobotUnitDataStreamingReceiver/RobotUnitDataStreamingReceiver.h>
 
 
 namespace armarx
@@ -17,6 +18,7 @@ namespace armarx
             void preOnInitComponent() override;
 
             void preOnConnectComponent() override;
+            void postOnDisconnectComponent() override;
 
             void postCreatePropertyDefinitions(PropertyDefinitionsPtr& properties) override;
 
@@ -24,12 +26,46 @@ namespace armarx
 
             void setRobotUnitName(const std::string& name);
             const std::string& getRobotUnitName() const;
+
+            void deactivate();
+
+            //controllers
+        public:
+            template<class PrxT>
+            PrxT createNJointController(const std::string& className,
+                                        const std::string& instanceName,
+                                        const NJointControllerConfigPtr& config,
+                                        bool doManageController = true)
+            {
+                return PrxT::checkedCast(createNJointController(className, instanceName, config, doManageController));
+            }
+            template<class PrxT>
+            void createNJointController(PrxT& prx,
+                                        const std::string& className,
+                                        const std::string& instanceName,
+                                        const NJointControllerConfigPtr& config,
+                                        bool doManageController = true)
+            {
+                prx = PrxT::checkedCast(createNJointController(className, instanceName, config, doManageController));
+            }
+            NJointControllerInterfacePrx createNJointController(const std::string& className,
+                    const std::string& instanceName,
+                    const NJointControllerConfigPtr& config,
+                    bool doManageController = true);
+            void manageController(const NJointControllerInterfacePrx& ctrl);
+            void manageController(const std::string& ctrl);
+
+            //datastreaming
+        public:
+            RobotUnitDataStreamingReceiverPtr startDataSatreming(const RobotUnitDataStreaming::Config& cfg);
+
         private:
             static constexpr const char* PROPERTY_NAME = "RobotUnitName";
             RobotUnitInterfacePrx _robotUnit;
             std::string           _robotUnitName;
+            bool                  _deactivated = false;
+            std::set<std::string> _ctrls;
         };
-
     }
 }
 
diff --git a/source/RobotAPI/libraries/RobotStatechartHelpers/ObstacleAvoidingPlatformUnitHelper.cpp b/source/RobotAPI/libraries/RobotStatechartHelpers/ObstacleAvoidingPlatformUnitHelper.cpp
index 27525c42d19079f8fbd3db620f03ad1710f09897..03ed255120ccf8a5084ea824f7d8e2d790c1c485 100644
--- a/source/RobotAPI/libraries/RobotStatechartHelpers/ObstacleAvoidingPlatformUnitHelper.cpp
+++ b/source/RobotAPI/libraries/RobotStatechartHelpers/ObstacleAvoidingPlatformUnitHelper.cpp
@@ -89,3 +89,10 @@ const
     return target_dist < m_pos_reached_threshold and
            std::fabs(target_angular_dist) < m_ori_reached_threshold;
 }
+
+
+void
+armarx::ObstacleAvoidingPlatformUnitHelper::setMaxVelocities(float max_vel, float max_angular_vel)
+{
+    m_platform_unit->setMaxVelocities(max_vel, max_angular_vel);
+}
diff --git a/source/RobotAPI/libraries/RobotStatechartHelpers/ObstacleAvoidingPlatformUnitHelper.h b/source/RobotAPI/libraries/RobotStatechartHelpers/ObstacleAvoidingPlatformUnitHelper.h
index 96bd461e7f6194de38283839eaaff0d5ec135967..12d7100f997eeb818f6cf0aff989e42a92059df5 100644
--- a/source/RobotAPI/libraries/RobotStatechartHelpers/ObstacleAvoidingPlatformUnitHelper.h
+++ b/source/RobotAPI/libraries/RobotStatechartHelpers/ObstacleAvoidingPlatformUnitHelper.h
@@ -61,6 +61,9 @@ namespace armarx
         isFinalTargetReached()
         const;
 
+        void
+        setMaxVelocities(float max_vel, float max_angular_vel);
+
     private:
 
         struct target
diff --git a/source/RobotAPI/libraries/RobotUnitDataStreamingReceiver/RobotUnitDataStreamingReceiver.cpp b/source/RobotAPI/libraries/RobotUnitDataStreamingReceiver/RobotUnitDataStreamingReceiver.cpp
index 2846da675f26f263aa244715205b490d78d4803b..10a524cb71f64e12add7d65870139b1c44707ea5 100644
--- a/source/RobotAPI/libraries/RobotUnitDataStreamingReceiver/RobotUnitDataStreamingReceiver.cpp
+++ b/source/RobotAPI/libraries/RobotUnitDataStreamingReceiver/RobotUnitDataStreamingReceiver.cpp
@@ -37,21 +37,37 @@ namespace armarx::detail::RobotUnitDataStreamingReceiver
         {
             return "RobotUnitDataStreamingReceiver";
         }
+        ~Receiver()
+        {
+            std::lock_guard g{_data_mutex};
+        }
         void onInitComponent() override {}
         void onConnectComponent() override {}
         void onExitComponent() override {}
 
-        void update(const RobotUnitDataStreaming::TimeStepSeq& data, const Ice::Current&) override
+        void update_async(
+            const RobotUnitDataStreaming::AMD_Receiver_updatePtr& ptr,
+            const RobotUnitDataStreaming::TimeStepSeq& data,
+            Ice::Long msgSequenceNbr,
+            const Ice::Current&) override
         {
+            ptr->ice_response();
+            if (_discard_data)
+            {
+                return;
+            }
+            static_assert(sizeof(std::uint64_t) == sizeof(msgSequenceNbr));
+            const auto seq = static_cast<std::uint64_t>(msgSequenceNbr);
             std::lock_guard g{_data_mutex};
             ARMARX_INFO << deactivateSpam()
                         << "received " << data.size() << " timesteps";
-            _data.emplace_back(data);
+            _data[seq] = data;
         }
 
-        std::mutex                                       _data_mutex;
-        std::deque<RobotUnitDataStreaming::TimeStepSeq>  _data;
-        Ice::Identity                                    _identity;
+        std::atomic_bool                                              _discard_data = false;
+        std::mutex                                                    _data_mutex;
+        std::map<std::uint64_t, RobotUnitDataStreaming::TimeStepSeq>  _data;
+        Ice::Identity                                                 _identity;
     };
 }
 
@@ -82,12 +98,26 @@ namespace armarx
     {
         if (_proxy)
         {
+            _receiver->_discard_data = true;
             if (!_description.entries.empty())
             {
-                _ru->stopDataStreaming(_proxy);
+                try
+                {
+                    _ru->stopDataStreaming(_proxy);
+                }
+                catch (...)
+                {
+                    ARMARX_WARNING << "did not stop streaming since the network call failed";
+                }
             }
+            auto icemanager = _obj->getArmarXManager()->getIceManager();
             auto adapter = _obj->getArmarXManager()->getAdapter();
             adapter->remove(_receiver->_identity);
+
+            while (icemanager->isObjectReachable(_receiver->_identity.name))
+            {
+                ARMARX_INFO << deactivateSpam() << "waiting until receiver is removed from ice";
+            }
         }
         _proxy    = nullptr;
         _receiver = nullptr;
@@ -96,14 +126,47 @@ namespace armarx
     std::deque<RobotUnitDataStreaming::TimeStep>& RobotUnitDataStreamingReceiver::getDataBuffer()
     {
         ARMARX_CHECK_NOT_NULL(_receiver);
-        std::deque<RobotUnitDataStreaming::TimeStepSeq> data;
+        std::map<std::uint64_t, RobotUnitDataStreaming::TimeStepSeq>  data;
         {
             std::lock_guard g{_receiver->_data_mutex};
             std::swap(data, _receiver->_data);
         }
-        for (auto& chunk : data)
+        _tmp_data_buffer.merge(data);
+        if (!data.empty())
         {
-            for (auto& step : chunk)
+            ARMARX_ERROR << "Double message sequence IDs! This should not happen!\nIDs:\n"
+                         << ARMARX_STREAM_PRINTER
+            {
+                for (const auto& [key, _] : data)
+                {
+                    out << "    " << key << "\n";
+                }
+            };
+        }
+
+        auto it = _tmp_data_buffer.begin();
+        for (std::size_t idx = 0; it != _tmp_data_buffer.end(); ++it, ++idx)
+        {
+            if (_last_iteration_id == -1)
+            {
+                _tmp_data_buffer_seq_id = it->first - 1;
+            }
+            if (_tmp_data_buffer_seq_id + 1 != it->first)
+            {
+                if (_tmp_data_buffer.size() > 10 && idx < _tmp_data_buffer.size() - 10)
+                {
+                    //there is a lot more data (10 updates) in the buffer!
+                    //-> some message calls went missing!
+                    ARMARX_ERROR << "some update messages went missing!";
+                }
+                else
+                {
+                    //maybe one or two frames are missing (due to async calls) -> wait
+                    break;
+                }
+            }
+            _tmp_data_buffer_seq_id = it->first;
+            for (auto& step : it->second)
             {
                 if (
                     _last_iteration_id != -1 &&
@@ -117,6 +180,7 @@ namespace armarx
                 _data_buffer.emplace_back(std::move(step));
             }
         }
+        _tmp_data_buffer.erase(_tmp_data_buffer.begin(), it);
         return _data_buffer;
     }
 
@@ -124,4 +188,16 @@ namespace armarx
     {
         return _description;
     }
+
+    std::string RobotUnitDataStreamingReceiver::getDataDescriptionString() const
+    {
+        std::stringstream str;
+        const auto& entr = getDataDescription().entries;
+        str << "Received data (" << entr.size() << " entries):\n";
+        for (const auto& [k, v] : entr)
+        {
+            str << "    " << k << ": type " << v.type << " index " << v.index << "\n";
+        }
+        return str.str();
+    }
 }
diff --git a/source/RobotAPI/libraries/RobotUnitDataStreamingReceiver/RobotUnitDataStreamingReceiver.h b/source/RobotAPI/libraries/RobotUnitDataStreamingReceiver/RobotUnitDataStreamingReceiver.h
index 6f52239991ae99fd1e82272f322d8455311e714b..60a03b5c98109b657adddcd48c55731c84cb2f63 100644
--- a/source/RobotAPI/libraries/RobotUnitDataStreamingReceiver/RobotUnitDataStreamingReceiver.h
+++ b/source/RobotAPI/libraries/RobotUnitDataStreamingReceiver/RobotUnitDataStreamingReceiver.h
@@ -23,6 +23,7 @@
 #pragma once
 
 #include <mutex>
+#include <type_traits>
 
 #include <ArmarXCore/core/ManagedIceObject.h>
 
@@ -53,6 +54,26 @@ namespace armarx
         using timestep_t = RobotUnitDataStreaming::TimeStep;
         using entry_t    = RobotUnitDataStreaming::DataEntry;
 
+        template<class T>
+        struct DataEntryReader
+        {
+            DataEntryReader()                                  = default;
+            DataEntryReader(DataEntryReader&&)                 = default;
+            DataEntryReader(const DataEntryReader&)            = default;
+            DataEntryReader& operator=(DataEntryReader&&)      = default;
+            DataEntryReader& operator=(const DataEntryReader&) = default;
+
+            DataEntryReader(const RobotUnitDataStreaming::DataEntry& k);
+
+            DataEntryReader& operator=(const RobotUnitDataStreaming::DataEntry& k);
+
+            void set(const RobotUnitDataStreaming::DataEntry& k);
+            T get(const RobotUnitDataStreaming::TimeStep& t) const;
+            T operator()(const RobotUnitDataStreaming::TimeStep& t) const;
+        private:
+            RobotUnitDataStreaming::DataEntry _key;
+        };
+
         RobotUnitDataStreamingReceiver(
             const ManagedIceObjectPtr& obj,
             const RobotUnitInterfacePrx& ru,
@@ -61,39 +82,198 @@ namespace armarx
 
         std::deque<timestep_t>& getDataBuffer();
         const RobotUnitDataStreaming::DataStreamingDescription& getDataDescription() const;
+        std::string getDataDescriptionString() const;
+
+        template<class T>
+        DataEntryReader<T> getDataEntryReader(const std::string& name) const;
+
+        template<class T>
+        void getDataEntryReader(DataEntryReader<T>& e, const std::string& name) const;
+        //statics
+        static void VisitEntry(auto&& f, const timestep_t& st, const entry_t& e);
+        template<class T>
+        static T GetAs(const timestep_t& st, const entry_t& e);
+
+        template<class T>
+        static RobotUnitDataStreaming::DataEntryType ExpectedDataEntryType();
+        static void VisitEntries(auto&& f, const timestep_t& st, const auto& cont);
+    private:
+        ManagedIceObjectPtr                                           _obj;
+        RobotUnitInterfacePrx                                         _ru;
+        detail::RobotUnitDataStreamingReceiver::ReceiverPtr           _receiver;
+        RobotUnitDataStreaming::ReceiverPrx                           _proxy;
+        RobotUnitDataStreaming::DataStreamingDescription              _description;
+        std::map<std::uint64_t, RobotUnitDataStreaming::TimeStepSeq>  _tmp_data_buffer;
+        std::uint64_t                                                 _tmp_data_buffer_seq_id = 0;
+        std::deque<RobotUnitDataStreaming::TimeStep>                  _data_buffer;
+        long                                                          _last_iteration_id = -1;
+
+    };
+}
+//impl
+namespace armarx
+{
+    template<class T> inline
+    RobotUnitDataStreamingReceiver::DataEntryReader<T>::DataEntryReader(const RobotUnitDataStreaming::DataEntry& k)
+    {
+        set(k);
+    }
+
+    template<class T> inline
+    void
+    RobotUnitDataStreamingReceiver::DataEntryReader<T>::set(const RobotUnitDataStreaming::DataEntry& k)
+    {
+        ARMARX_CHECK_EQUAL(RobotUnitDataStreamingReceiver::ExpectedDataEntryType<T>(),
+                           k.type) << "the key references a value of the wrong type!";
+        _key = k;
+    }
 
-        static void visitEntry(auto&& f, const timestep_t& st, const entry_t& e)
+    template<class T> inline
+    RobotUnitDataStreamingReceiver::DataEntryReader<T>&
+    RobotUnitDataStreamingReceiver::DataEntryReader<T>::operator=(const RobotUnitDataStreaming::DataEntry& k)
+    {
+        set(k);
+        return *this;
+    }
+
+    template<class T> inline
+    T
+    RobotUnitDataStreamingReceiver::DataEntryReader<T>::get(const RobotUnitDataStreaming::TimeStep& t) const
+    {
+        return RobotUnitDataStreamingReceiver::GetAs<T>(t, _key);
+    }
+
+    template<class T> inline
+    T
+    RobotUnitDataStreamingReceiver::DataEntryReader<T>::operator()(const RobotUnitDataStreaming::TimeStep& t) const
+    {
+        return get(t);
+    }
+
+    template<class T> inline
+    void
+    RobotUnitDataStreamingReceiver::getDataEntryReader(DataEntryReader<T>& e, const std::string& name) const
+    {
+        e = _description.entries.at(name);
+    }
+    template<class T> inline
+    RobotUnitDataStreamingReceiver::DataEntryReader<T>
+    RobotUnitDataStreamingReceiver::getDataEntryReader(const std::string& name) const
+    {
+        DataEntryReader<T> r;
+        getDataEntryReader(r);
+        return r;
+    }
+
+    inline void
+    RobotUnitDataStreamingReceiver::VisitEntry(auto&& f, const timestep_t& st, const entry_t& e)
+    {
+        using enum_t = RobotUnitDataStreaming::DataEntryType;
+    // *INDENT-OFF*
+    switch (e.type)
+    {
+        case enum_t::NodeTypeBool  : f(st.bools  .at(e.index)); break;
+        case enum_t::NodeTypeByte  : f(st.bytes  .at(e.index)); break;
+        case enum_t::NodeTypeShort : f(st.shorts .at(e.index)); break;
+        case enum_t::NodeTypeInt   : f(st.ints   .at(e.index)); break;
+        case enum_t::NodeTypeLong  : f(st.longs  .at(e.index)); break;
+        case enum_t::NodeTypeFloat : f(st.floats .at(e.index)); break;
+        case enum_t::NodeTypeDouble: f(st.doubles.at(e.index)); break;
+    };
+    // *INDENT-ON*
+    }
+
+    template<class T> inline
+    T
+    RobotUnitDataStreamingReceiver::GetAs(const timestep_t& st, const entry_t& e)
+    {
+        using enum_t = RobotUnitDataStreaming::DataEntryType;
+        if constexpr(std::is_same_v<bool, T>)
+        {
+            ARMARX_CHECK_EQUAL(e.type, enum_t::NodeTypeBool);
+            return st.bools  .at(e.index);
+        }
+        else if constexpr(std::is_same_v<Ice::Byte, T>)
         {
-            using enum_t = RobotUnitDataStreaming::DataEntryType;
-            // *INDENT-OFF*
-            switch (e.type)
-            {
-                case enum_t::NodeTypeBool  : f(st.bools  .at(e.index)); break;
-                case enum_t::NodeTypeByte  : f(st.bytes  .at(e.index)); break;
-                case enum_t::NodeTypeShort : f(st.shorts .at(e.index)); break;
-                case enum_t::NodeTypeInt   : f(st.ints   .at(e.index)); break;
-                case enum_t::NodeTypeLong  : f(st.longs  .at(e.index)); break;
-                case enum_t::NodeTypeFloat : f(st.floats .at(e.index)); break;
-                case enum_t::NodeTypeDouble: f(st.doubles.at(e.index)); break;
-            };
-            // *INDENT-ON*
+            ARMARX_CHECK_EQUAL(e.type, enum_t::NodeTypeByte);
+            return st.bytes  .at(e.index);
         }
+        else if constexpr(std::is_same_v<Ice::Short, T>)
+        {
+            ARMARX_CHECK_EQUAL(e.type, enum_t::NodeTypeShort);
+            return st.shorts .at(e.index);
+        }
+        else if constexpr(std::is_same_v<Ice::Int, T>)
+        {
+            ARMARX_CHECK_EQUAL(e.type, enum_t::NodeTypeInt);
+            return st.ints   .at(e.index);
+        }
+        else if constexpr(std::is_same_v<Ice::Long, T>)
+        {
+            ARMARX_CHECK_EQUAL(e.type, enum_t::NodeTypeLong);
+            return st.longs  .at(e.index);
+        }
+        else if constexpr(std::is_same_v<Ice::Float, T>)
+        {
+            ARMARX_CHECK_EQUAL(e.type, enum_t::NodeTypeFloat);
+            return st.floats .at(e.index);
+        }
+        else if constexpr(std::is_same_v<Ice::Double, T>)
+        {
+            ARMARX_CHECK_EQUAL(e.type, enum_t::NodeTypeDouble);
+            return st.doubles.at(e.index);
+        }
+        else
+        {
+            static_assert(!std::is_same_v<T, T>, "Type not supported!");
+        }
+    }
 
-        static void visitEntries(auto&& f, const timestep_t& st, const auto& cont)
+    template<class T> inline
+    RobotUnitDataStreaming::DataEntryType
+    RobotUnitDataStreamingReceiver::ExpectedDataEntryType()
+    {
+        using enum_t = RobotUnitDataStreaming::DataEntryType;
+        if constexpr(std::is_same_v<bool, T>)
+        {
+            return enum_t::NodeTypeBool;
+        }
+        else if constexpr(std::is_same_v<Ice::Byte, T>)
+        {
+            return enum_t::NodeTypeByte;
+        }
+        else if constexpr(std::is_same_v<Ice::Short, T>)
+        {
+            return enum_t::NodeTypeShort;
+        }
+        else if constexpr(std::is_same_v<Ice::Int, T>)
+        {
+            return enum_t::NodeTypeInt;
+        }
+        else if constexpr(std::is_same_v<Ice::Long, T>)
+        {
+            return enum_t::NodeTypeLong;
+        }
+        else if constexpr(std::is_same_v<Ice::Float, T>)
+        {
+            return enum_t::NodeTypeFloat;
+        }
+        else if constexpr(std::is_same_v<Ice::Double, T>)
+        {
+            return enum_t::NodeTypeDouble;
+        }
+        else
         {
-            for (const entry_t& e : cont)
-            {
-                visitEntry(f, st, e);
-            }
+            static_assert(!std::is_same_v<T, T>, "Type not supported!");
         }
+    }
 
-    private:
-        ManagedIceObjectPtr                                 _obj;
-        RobotUnitInterfacePrx                               _ru;
-        detail::RobotUnitDataStreamingReceiver::ReceiverPtr _receiver;
-        RobotUnitDataStreaming::ReceiverPrx                 _proxy;
-        RobotUnitDataStreaming::DataStreamingDescription    _description;
-        std::deque<RobotUnitDataStreaming::TimeStep>        _data_buffer;
-        long                                                _last_iteration_id = -1;
-    };
+    inline void
+    RobotUnitDataStreamingReceiver::VisitEntries(auto&& f, const timestep_t& st, const auto& cont)
+    {
+        for (const entry_t& e : cont)
+        {
+            VisitEntry(f, st, e);
+        }
+    }
 }
diff --git a/source/RobotAPI/libraries/armem/CMakeLists.txt b/source/RobotAPI/libraries/armem/CMakeLists.txt
index 644c655fab44881d28429b7fdd266b1d41e9a8e8..5e85729b15a7afbf8855a6eca1059062635df405 100644
--- a/source/RobotAPI/libraries/armem/CMakeLists.txt
+++ b/source/RobotAPI/libraries/armem/CMakeLists.txt
@@ -28,7 +28,9 @@ set(LIB_FILES
     core/ice_conversions.cpp
     core/Memory.cpp
     core/ProviderSegment.cpp
+
     core/detail/MemoryItem.cpp
+    core/detail/MaxHistorySize.cpp
 
     core/error/ArMemError.cpp
 
@@ -88,6 +90,7 @@ set(LIB_HEADERS
     core/ProviderSegment.h
 
     core/detail/EntityContainer.h
+    core/detail/MaxHistorySize.h
     core/detail/MemoryContainer.h
     core/detail/MemoryItem.h
     core/detail/TypedEntityContainer.h
diff --git a/source/RobotAPI/libraries/armem/client/Query.cpp b/source/RobotAPI/libraries/armem/client/Query.cpp
index 87f8c7dfc678fbb065e526f7f6255e9c847ef50a..33a6b0a94db270cbf007e063436cdda47a041023 100644
--- a/source/RobotAPI/libraries/armem/client/Query.cpp
+++ b/source/RobotAPI/libraries/armem/client/Query.cpp
@@ -12,7 +12,7 @@ namespace armarx::armem::client
 
     armem::query::data::Input QueryInput::toIce() const
     {
-        return armem::toIce<query::data::Input>(*this);
+        return armem::toIce<armem::query::data::Input>(*this);
     }
 
     QueryResult QueryResult::fromIce(const armem::query::data::Result& ice)
@@ -22,7 +22,7 @@ namespace armarx::armem::client
 
     armem::query::data::Result QueryResult::toIce() const
     {
-        return armem::toIce<query::data::Result>(*this);
+        return armem::toIce<armem::query::data::Result>(*this);
     }
 }
 
diff --git a/source/RobotAPI/libraries/armem/client/Writer.cpp b/source/RobotAPI/libraries/armem/client/Writer.cpp
index 015d0773aded333bc6f528f744c20989717f052e..6286921f85ecdbbd123ea0e388353ff842d79d34 100644
--- a/source/RobotAPI/libraries/armem/client/Writer.cpp
+++ b/source/RobotAPI/libraries/armem/client/Writer.cpp
@@ -111,36 +111,18 @@ namespace armarx::armem::client
         return result.results.at(0);
     }
 
-    armarx::armem::MemoryID
-    Writer::commit(const armem::MemoryID& entityID, const armarx::aron::datanavigator::AronDictDataNavigatorPtr& instance)
+    EntityUpdateResult Writer::commit(
+        const MemoryID& entityID,
+        const std::vector<aron::datanavigator::AronDictDataNavigatorPtr>& instancesData,
+        Time timeCreated)
     {
-        std::vector<armarx::aron::datanavigator::AronDictDataNavigatorPtr> data({instance});
-        return commit(entityID, data)[0];
-    }
-
-    std::vector<armarx::armem::MemoryID>
-    Writer::commit(const armem::MemoryID& entityID, const std::vector<armarx::aron::datanavigator::AronDictDataNavigatorPtr>& data)
-    {
-        armem::Commit c;
-        armem::EntityUpdate& update = c.updates.emplace_back();
-
+        EntityUpdate update;
         update.entityID = entityID;
-        update.timeCreated = armem::Time::now();
-        update.instancesData = data;
-
-        armem::CommitResult commitResult = commit(c);
-
-        std::vector<armarx::armem::MemoryID> ret;
-        for (const auto& res : commitResult.results)
-        {
-            ARMARX_INFO << res;
-            ret.push_back(res.snapshotID);
-        }
-
-        return ret;
+        update.instancesData = instancesData;
+        update.timeCreated = timeCreated;
+        return commit(update);
     }
 
-
     void
     Writer::setWritingMemory(server::WritingMemoryInterfacePrx memory)
     {
diff --git a/source/RobotAPI/libraries/armem/client/Writer.h b/source/RobotAPI/libraries/armem/client/Writer.h
index 6f8fbe8769c15665b28959e2aaab21085214abd7..990a0f1c312eaf10fad24cf4cfc3012bb5138d67 100644
--- a/source/RobotAPI/libraries/armem/client/Writer.h
+++ b/source/RobotAPI/libraries/armem/client/Writer.h
@@ -9,7 +9,17 @@ namespace armarx::armem::client
 {
 
     /**
-     * @brief Helps sending data to a memory.
+     * @brief Helps a memory client sending data to a memory.
+     *
+     * You can check whether the writer is ready using the bool operator:
+     * @code
+     * client::Writer writer(writingMemoryProxy);
+     * ...
+     * if (writer)
+     * {
+     *     writer.commit(...);
+     * }
+     * @endcode
      */
     class Writer
     {
@@ -27,16 +37,18 @@ namespace armarx::armem::client
         data::AddSegmentResult addSegment(const data::AddSegmentInput& input);
         data::AddSegmentsResult addSegments(const data::AddSegmentsInput& input);
 
+
         /**
          * @brief Writes a `Commit` to the memory.
          */
         CommitResult commit(const Commit& commit);
+        /// Commit a single entity update.
         EntityUpdateResult commit(const EntityUpdate& update);
-
-        armem::MemoryID commit(const armem::MemoryID& entityID, const armarx::aron::datanavigator::AronDictDataNavigatorPtr& instance);
-        std::vector<armarx::armem::MemoryID> commit(const armem::MemoryID& entityID, const std::vector<armarx::aron::datanavigator::AronDictDataNavigatorPtr>& data);
-
-
+        /// Commit a single entity update.
+        EntityUpdateResult commit(
+            const MemoryID& entityID,
+            const std::vector<aron::datanavigator::AronDictDataNavigatorPtr>& instancesData,
+            Time timeCreated);
 
         void setWritingMemory(server::WritingMemoryInterfacePrx memory);
 
diff --git a/source/RobotAPI/libraries/armem/core/CoreSegment.cpp b/source/RobotAPI/libraries/armem/core/CoreSegment.cpp
index 16e3b4291608c5970c074f7ea89e4d59c0e44dba..34f73cbdf4f7845a8fc2ad0ab14bc7d9ffcb8775 100644
--- a/source/RobotAPI/libraries/armem/core/CoreSegment.cpp
+++ b/source/RobotAPI/libraries/armem/core/CoreSegment.cpp
@@ -126,11 +126,22 @@ namespace armarx::armem
             throw armem::error::ContainerEntryAlreadyExists(
                 providerSegment.getLevelName(), providerSegment.name(), getLevelName(), this->name());
         }
+
         auto it = providerSegments.emplace(providerSegment.name(), std::move(providerSegment)).first;
         it->second.id().setCoreSegmentID(id());
+        it->second.setMaxHistorySize(maxHistorySize);
         return it->second;
     }
 
+    void CoreSegment::setMaxHistorySize(long maxSize)
+    {
+        MaxHistorySize::setMaxHistorySize(maxSize);
+        for (auto& [name, seg] : providerSegments)
+        {
+            seg.setMaxHistorySize(maxSize);
+        }
+    }
+
     std::string CoreSegment::getLevelName() const
     {
         return "core segment";
diff --git a/source/RobotAPI/libraries/armem/core/CoreSegment.h b/source/RobotAPI/libraries/armem/core/CoreSegment.h
index 68bf7dc4ebf1d9a22d74728b6f4b4b2470dbe218..aed697fb00d5aaf4c3d1f8446be5b289fae97cb8 100644
--- a/source/RobotAPI/libraries/armem/core/CoreSegment.h
+++ b/source/RobotAPI/libraries/armem/core/CoreSegment.h
@@ -5,6 +5,7 @@
 
 #include "ProviderSegment.h"
 #include "detail/TypedEntityContainer.h"
+#include "detail/MaxHistorySize.h"
 
 
 namespace armarx::armem
@@ -13,7 +14,9 @@ namespace armarx::armem
     /**
      * @brief Data of a core segment containing multiple provider segments.
      */
-    class CoreSegment : public detail::TypedEntityContainer<ProviderSegment, CoreSegment>
+    class CoreSegment :
+        public detail::TypedEntityContainer<ProviderSegment, CoreSegment>
+        , public detail::MaxHistorySize
     {
         using Base = detail::TypedEntityContainer<ProviderSegment, CoreSegment>;
 
@@ -59,6 +62,14 @@ namespace armarx::armem
         ProviderSegment& addProviderSegment(ProviderSegment&& providerSegment);
 
 
+        /**
+         * @brief Sets the maximum history size of entities in this segment.
+         * This affects all current entities as well as new ones.
+         * @see Entity::setMaxHistorySize()
+         */
+        void setMaxHistorySize(long maxSize) override;
+
+
         bool equalsDeep(const CoreSegment& other) const;
 
 
diff --git a/source/RobotAPI/libraries/armem/core/Entity.h b/source/RobotAPI/libraries/armem/core/Entity.h
index 51d55aa4951af17e671417ab95c21bbbb3690e7b..b81ffe76199f7a978d822a4d91cc421b48537682 100644
--- a/source/RobotAPI/libraries/armem/core/Entity.h
+++ b/source/RobotAPI/libraries/armem/core/Entity.h
@@ -169,8 +169,6 @@ namespace armarx::armem
         // ToDo: Add max age;
         // ToDo in future: keep/remove predicate
 
-
-
         // MemoryItem interface
     public:
         std::string getKeyString() const override
diff --git a/source/RobotAPI/libraries/armem/core/MemoryID.cpp b/source/RobotAPI/libraries/armem/core/MemoryID.cpp
index 73d92995e3a24d15bd3593ea8f0ec1314cefe2e2..664319410949b11c7563512a6ccc22dc0c2dd3e1 100644
--- a/source/RobotAPI/libraries/armem/core/MemoryID.cpp
+++ b/source/RobotAPI/libraries/armem/core/MemoryID.cpp
@@ -70,18 +70,37 @@ namespace armarx::armem
         return simox::alg::join(items, delimeter, false, false);
     }
 
-    std::string MemoryID::getLastNameSet() const
+    std::string MemoryID::getLeafItem() const
     {
         std::vector<std::string> items = getAllItems();
-        std::string latest = "";
-        for (const std::string& name : items)
+        for (auto it = items.rbegin(); it != items.rend(); ++it)
         {
-            if (!name.empty())
+            if (!it->empty())
             {
-                latest = name;
+                return *it;
             }
         }
-        return latest;
+        return "";
+    }
+
+    bool MemoryID::hasGap() const
+    {
+        bool emptyFound = false;
+        for (const std::string& name : getAllItems())
+        {
+            if (name.empty())
+            {
+                emptyFound = true;
+            }
+            else
+            {
+                if (emptyFound)
+                {
+                    return true;
+                }
+            }
+        }
+        return false;
     }
 
 
@@ -277,6 +296,16 @@ namespace armarx::armem
         return int(parseInteger(string, "instance index"));
     }
 
+    bool MemoryID::operator==(const MemoryID& other) const
+    {
+        return memoryName == other.memoryName
+               and coreSegmentName == other.coreSegmentName
+               and providerSegmentName == other.providerSegmentName
+               and entityName == other.entityName
+               and timestamp == other.timestamp
+               and instanceIndex == other.instanceIndex;
+    }
+
     long long MemoryID::parseInteger(const std::string& string, const std::string& semanticName)
     {
         try
diff --git a/source/RobotAPI/libraries/armem/core/MemoryID.h b/source/RobotAPI/libraries/armem/core/MemoryID.h
index d92197c96bf08a0dfcabf22e4effe7f54d697762..1fc22f7288b51970f298a9309cbe33b087d48f5f 100644
--- a/source/RobotAPI/libraries/armem/core/MemoryID.h
+++ b/source/RobotAPI/libraries/armem/core/MemoryID.h
@@ -41,9 +41,14 @@ namespace armarx::armem
         std::string str(const std::string& delimeter) const;
         static MemoryID fromString(const std::string& string);
 
+        std::string timestampStr() const;
+        std::string instanceIndexStr() const;
 
-        std::vector<std::string> getItems() const;
+
+        /// Get all levels as string.
         std::vector<std::string> getAllItems() const;
+        /// Get the levels from root to first not defined level (excluding).
+        std::vector<std::string> getItems() const;
 
 
         bool hasMemoryName() const
@@ -107,26 +112,26 @@ namespace armarx::armem
         MemoryID withTimestamp(Time time) const;
         MemoryID withInstanceIndex(int index) const;
 
-        std::string getLastNameSet() const;
 
-        std::string timestampStr() const;
-        std::string instanceIndexStr() const;
+        /// Indicate whether this ID has a gap such as in 'Memory//MyProvider' (no core segment name).
+        bool hasGap() const;
+        /// Get the lowest defined level (or empty string if there is none).
+        std::string getLeafItem() const;
+
 
         static Time timestampFromStr(const std::string& timestamp);
         static int instanceIndexFromStr(const std::string& index);
 
-        friend std::ostream& operator<<(std::ostream& os, const MemoryID id);
 
-        bool operator== (const MemoryID& other) const
+        bool operator ==(const MemoryID& other) const;
+        inline bool operator !=(const MemoryID& other) const
         {
-            return memoryName == other.memoryName
-                   and coreSegmentName == other.coreSegmentName
-                   and providerSegmentName == other.providerSegmentName
-                   and entityName == other.entityName
-                   and timestamp == other.timestamp
-                   and instanceIndex == other.instanceIndex;
+            return !(*this == other);
         }
 
+        friend std::ostream& operator<<(std::ostream& os, const MemoryID id);
+
+
     private:
 
         static long long parseInteger(const std::string& string, const std::string& semanticName);
diff --git a/source/RobotAPI/libraries/armem/core/ProviderSegment.cpp b/source/RobotAPI/libraries/armem/core/ProviderSegment.cpp
index 28010d765fd024f0b83442082d9daf636e7274e0..fb0ca8cc82a3cfcbf3f89251c87b2d79a7f4e357 100644
--- a/source/RobotAPI/libraries/armem/core/ProviderSegment.cpp
+++ b/source/RobotAPI/libraries/armem/core/ProviderSegment.cpp
@@ -154,7 +154,7 @@ namespace armarx::armem
 
     void ProviderSegment::setMaxHistorySize(long maxSize)
     {
-        this->maxHistorySize = maxSize;
+        MaxHistorySize::setMaxHistorySize(maxSize);
         for (auto& [name, entity] : entities)
         {
             entity.setMaxHistorySize(maxSize);
diff --git a/source/RobotAPI/libraries/armem/core/ProviderSegment.h b/source/RobotAPI/libraries/armem/core/ProviderSegment.h
index ecfa53be218d27cb9978009196aec93f68f475c7..384ee1b416c2dac48ae1dcccdc9fa3e984ff6700 100644
--- a/source/RobotAPI/libraries/armem/core/ProviderSegment.h
+++ b/source/RobotAPI/libraries/armem/core/ProviderSegment.h
@@ -5,6 +5,7 @@
 
 #include "Entity.h"
 #include "detail/TypedEntityContainer.h"
+#include "detail/MaxHistorySize.h"
 
 
 namespace armarx::armem
@@ -13,7 +14,10 @@ namespace armarx::armem
     /**
      * @brief Data of a provider segment containing multiple entities.
      */
-    class ProviderSegment : public detail::TypedEntityContainer<Entity, ProviderSegment>
+    class ProviderSegment :
+        public detail::TypedEntityContainer<Entity, ProviderSegment>
+        , public detail::MaxHistorySize
+
     {
         using Base = detail::TypedEntityContainer<Entity, ProviderSegment>;
 
@@ -66,7 +70,7 @@ namespace armarx::armem
          * This affects all current entities as well as new ones.
          * @see Entity::setMaxHistorySize()
          */
-        void setMaxHistorySize(long maxSize);
+        void setMaxHistorySize(long maxSize) override;
 
 
         bool equalsDeep(const ProviderSegment& other) const;
@@ -88,12 +92,6 @@ namespace armarx::armem
         /// The entities.
         std::map<std::string, Entity> entities;
 
-        /**
-         * @brief Maximum size of entity histories.
-         * @see Entity::maxHstorySize
-         */
-        long maxHistorySize = -1;
-
     };
 
 }
diff --git a/source/RobotAPI/libraries/armem/core/detail/MaxHistorySize.cpp b/source/RobotAPI/libraries/armem/core/detail/MaxHistorySize.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..cdd34e3be26351bab89ad6b712026769057f8b0e
--- /dev/null
+++ b/source/RobotAPI/libraries/armem/core/detail/MaxHistorySize.cpp
@@ -0,0 +1,19 @@
+#include "MaxHistorySize.h"
+
+
+namespace armarx::armem::detail
+{
+    MaxHistorySize::~MaxHistorySize()
+    {
+    }
+
+    void MaxHistorySize::setMaxHistorySize(long maxSize)
+    {
+        this->maxHistorySize = maxSize;
+    }
+
+    long MaxHistorySize::getMaxHistorySize() const
+    {
+        return maxHistorySize;
+    }
+}
diff --git a/source/RobotAPI/libraries/armem/core/detail/MaxHistorySize.h b/source/RobotAPI/libraries/armem/core/detail/MaxHistorySize.h
new file mode 100644
index 0000000000000000000000000000000000000000..d96e732964103c93987708e2b1d5dbaf9377640a
--- /dev/null
+++ b/source/RobotAPI/libraries/armem/core/detail/MaxHistorySize.h
@@ -0,0 +1,31 @@
+#pragma once
+
+
+
+namespace armarx::armem::detail
+{
+    class MaxHistorySize
+    {
+    public:
+
+        virtual ~MaxHistorySize();
+
+        /**
+         * @brief Sets the maximum history size of entities in this segment.
+         * This affects all current entities as well as new ones.
+         * @see Entity::setMaxHistorySize()
+         */
+        virtual void setMaxHistorySize(long maxSize);
+        virtual long getMaxHistorySize() const;
+
+
+    protected:
+
+        /**
+         * @brief Maximum size of entity histories.
+         * @see Entity::maxHstorySize
+         */
+        long maxHistorySize = -1;
+
+    };
+}
diff --git a/source/RobotAPI/libraries/armem/core/io/DiskReader/DiskReader.cpp b/source/RobotAPI/libraries/armem/core/io/DiskReader/DiskReader.cpp
index 491ea69873af11f55d8df97f428e562b9aafcc54..92f7d29a2363141f1018935140ba011e2865cdc9 100644
--- a/source/RobotAPI/libraries/armem/core/io/DiskReader/DiskReader.cpp
+++ b/source/RobotAPI/libraries/armem/core/io/DiskReader/DiskReader.cpp
@@ -155,7 +155,7 @@ namespace armarx::armem::io
 
     aron::typenavigator::AronObjectTypeNavigatorPtr DiskReader::readSingleTypeInformationFromDisk(const MemoryID& id) const
     {
-        std::filesystem::path p = rootPath / id.str() / (id.getLastNameSet() + getTypeSuffix());
+        std::filesystem::path p = rootPath / id.str() / (id.getLeafItem() + getTypeSuffix());
         return readSingleTypeInformationFromDisk(p);
     }
 
diff --git a/source/RobotAPI/libraries/armem/core/io/DiskWriter/DiskWriter.cpp b/source/RobotAPI/libraries/armem/core/io/DiskWriter/DiskWriter.cpp
index d0a5d9d3fc002b759c385c61037eef0291436fc2..f996440e9f20d3892398033d9631999694ba1215 100644
--- a/source/RobotAPI/libraries/armem/core/io/DiskWriter/DiskWriter.cpp
+++ b/source/RobotAPI/libraries/armem/core/io/DiskWriter/DiskWriter.cpp
@@ -308,5 +308,4 @@ namespace armarx::armem::io
         historyTimestampsError.insert(historyTimestampsError.end(), o.historyTimestampsError.begin(), o.historyTimestampsError.end());
         entityInstancesError.insert(entityInstancesError.end(), o.entityInstancesError.begin(), o.entityInstancesError.end());
     }
-
 }
diff --git a/source/RobotAPI/libraries/armem/mns/ClientPlugin.cpp b/source/RobotAPI/libraries/armem/mns/ClientPlugin.cpp
index 3ecd25a856c018b75a007af78f57d41401fdc432..f7bba9445c73a7c13a3374969d631530145d9c14 100644
--- a/source/RobotAPI/libraries/armem/mns/ClientPlugin.cpp
+++ b/source/RobotAPI/libraries/armem/mns/ClientPlugin.cpp
@@ -19,20 +19,19 @@ namespace armarx::armem::mns::plugins
         {
             properties->defineOptionalProperty<std::string>(
                 makePropertyName(PROPERTY_MNS_NAME_NAME),
-                PROPERTY_MNS_NAME_DEFAULT,
+                parent<ClientPluginUserBase>().memoryNameSystemName,
                 "Name of the Memory Name System (MNS) component.");
         }
         if (!properties->hasDefinition(makePropertyName(PROPERTY_MNS_ENABLED_NAME)))
         {
             properties->defineOptionalProperty<bool>(
                 makePropertyName(PROPERTY_MNS_ENABLED_NAME),
-                PROPERTY_MNS_ENABLED_DEFAULT,
+                parent<ClientPluginUserBase>().memoryNameSystemEnabled,
                 "Whether to use (and depend on) the Memory Name System (MNS)."
                 "\nSet to false to use this memory as a stand-alone.");
         }
     }
 
-
     void ClientPlugin::preOnInitComponent()
     {
         if (isMemoryNameSystemEnabled())
@@ -49,19 +48,18 @@ namespace armarx::armem::mns::plugins
         }
     }
 
-
     bool ClientPlugin::isMemoryNameSystemEnabled()
     {
         return parentDerives<Component>() ?
                parent<Component>().getProperty<bool>(makePropertyName(PROPERTY_MNS_ENABLED_NAME)) :
-               PROPERTY_MNS_ENABLED_DEFAULT;
+               parent<ClientPluginUserBase>().memoryNameSystemEnabled;
     }
 
     std::string ClientPlugin::getMemoryNameSystemName()
     {
         return parentDerives<Component>() ?
                parent<Component>().getProperty<std::string>(makePropertyName(PROPERTY_MNS_NAME_NAME)) :
-               std::string{PROPERTY_MNS_NAME_DEFAULT};
+               std::string{parent<ClientPluginUserBase>().memoryNameSystemName};
     }
 
     mns::MemoryNameSystemInterfacePrx ClientPlugin::getMemoryNameSystem()
@@ -71,9 +69,38 @@ namespace armarx::armem::mns::plugins
                : nullptr;
     }
 
+    ClientPluginUserBase::~ClientPluginUserBase()
+    {
+    }
+
+    armem::data::WaitForMemoryResult ClientPluginUserBase::useMemory(const MemoryID& id)
+    {
+        return useMemory(id.memoryName);
+    }
+
+    armem::data::WaitForMemoryResult ClientPluginUserBase::useMemory(const std::string& memoryName)
+    {
+        armem::data::WaitForMemoryInput input;
+        input.name = memoryName;
+
+        armem::data::WaitForMemoryResult result = memoryNameSystem->waitForMemory(input);
+        if (result.success)
+        {
+            if (Component* comp = dynamic_cast<Component*>(this))
+            {
+                // Add dependency.
+                comp->usingProxy(result.proxy->ice_getIdentity().name);
+            }
+        }
+        return result;
+    }
 
     armem::data::WaitForMemoryResult ClientPluginUserBase::waitForMemory(const std::string& memoryName)
     {
+        if (!memoryNameSystem)
+        {
+            return {};
+        }
         armem::data::WaitForMemoryInput input;
         input.name = memoryName;
         return memoryNameSystem->waitForMemory(input);
@@ -81,6 +108,10 @@ namespace armarx::armem::mns::plugins
 
     armem::data::ResolveMemoryNameResult ClientPluginUserBase::resolveMemoryName(const std::string& memoryName)
     {
+        if (!memoryNameSystem)
+        {
+            return {};
+        }
         armem::data::ResolveMemoryNameInput input;
         input.name = memoryName;
         return memoryNameSystem->resolveMemoryName(input);
diff --git a/source/RobotAPI/libraries/armem/mns/ClientPlugin.h b/source/RobotAPI/libraries/armem/mns/ClientPlugin.h
index 074ec2ef023bc9286276dfe07229f822ea3f5b88..b941d214cf4fb3530d0e074cdc4e4b8e6e1e60b3 100644
--- a/source/RobotAPI/libraries/armem/mns/ClientPlugin.h
+++ b/source/RobotAPI/libraries/armem/mns/ClientPlugin.h
@@ -3,6 +3,7 @@
 #include <ArmarXCore/core/Component.h>
 
 #include <RobotAPI/interface/armem/mns/MemoryNameSystemInterface.h>
+#include <RobotAPI/libraries/armem/core/MemoryID.h>
 
 
 namespace armarx::armem::mns
@@ -44,12 +45,9 @@ namespace armarx::armem::mns::plugins
          */
         mns::MemoryNameSystemInterfacePrx getMemoryNameSystem();
 
-
-    private:
+    public:
         static constexpr const char* PROPERTY_MNS_ENABLED_NAME = "mns.MemoryNameSystemEnabled";
-        static constexpr const bool PROPERTY_MNS_ENABLED_DEFAULT = true;
         static constexpr const char* PROPERTY_MNS_NAME_NAME = "mns.MemoryNameSystemName";
-        static constexpr const char* PROPERTY_MNS_NAME_DEFAULT = "ArMemMemoryNameSystem";
     };
 
 
@@ -60,13 +58,25 @@ namespace armarx::armem::mns::plugins
     class ClientPluginUserBase
     {
     protected:
+
+        virtual ~ClientPluginUserBase();
+
+
         armem::data::WaitForMemoryResult waitForMemory(const std::string& memoryName);
         armem::data::ResolveMemoryNameResult resolveMemoryName(const std::string& memoryName);
         bool isMemoryAvailable(const std::string& memoryName);
 
+        armem::data::WaitForMemoryResult useMemory(const MemoryID& id);
+        armem::data::WaitForMemoryResult useMemory(const std::string& memoryName);
+
+
     public:
+
         /// Only set when enabled.
         mns::MemoryNameSystemInterfacePrx memoryNameSystem = nullptr;
 
+        bool memoryNameSystemEnabled = true;
+        std::string memoryNameSystemName = "ArMemMemoryNameSystem";
+
     };
 }
diff --git a/source/RobotAPI/libraries/armem/server/MemoryRemoteGui.cpp b/source/RobotAPI/libraries/armem/server/MemoryRemoteGui.cpp
index e6c51d554b185570c0de0b3e658a363bc0abac1b..3c5e7b6ecb4172b075d6cca7b4a59b0d543c3283 100644
--- a/source/RobotAPI/libraries/armem/server/MemoryRemoteGui.cpp
+++ b/source/RobotAPI/libraries/armem/server/MemoryRemoteGui.cpp
@@ -3,7 +3,7 @@
 #include <ArmarXCore/core/exceptions/local/ExpressionException.h>
 
 #include <RobotAPI/libraries/aron/aroncore/navigators/datanavigator/AronAllDataNavigators.h>
-#include <RobotAPI/libraries/aron/aroncore/navigators/visitors/AronDataVisitor.h>
+#include <RobotAPI/libraries/aron/aroncore/navigators/visitors/DataVisitor.h>
 
 #include <SimoxUtility/meta/type_name.h>
 
diff --git a/source/RobotAPI/libraries/armem/server/RemoteGuiAronDataVisitor.cpp b/source/RobotAPI/libraries/armem/server/RemoteGuiAronDataVisitor.cpp
index 6f6369a4f23909b38362f823128a29284c4f5946..d2253746e591bcd18caabf997df25f9f0746fe5f 100644
--- a/source/RobotAPI/libraries/armem/server/RemoteGuiAronDataVisitor.cpp
+++ b/source/RobotAPI/libraries/armem/server/RemoteGuiAronDataVisitor.cpp
@@ -41,12 +41,12 @@ namespace armarx::armem::server
         return true;
     }
 
-    void RemoteGuiAronDataVisitor::streamValueText(AronStringDataNavigator& n, std::stringstream& ss)
+    void RemoteGuiAronDataVisitor::streamValueText(StringDataNavigator& n, std::stringstream& ss)
     {
         ss << "'" << n.getValue() << "'";
     }
 
-    void RemoteGuiAronDataVisitor::streamValueText(AronNDArrayDataNavigator& n, std::stringstream& ss)
+    void RemoteGuiAronDataVisitor::streamValueText(NDArrayDataNavigator& n, std::stringstream& ss)
     {
         ss << "shape (" << simox::alg::join(simox::alg::multi_to_string(n.getDimensions()), ", ") << ")";
     }
diff --git a/source/RobotAPI/libraries/armem/server/RemoteGuiAronDataVisitor.h b/source/RobotAPI/libraries/armem/server/RemoteGuiAronDataVisitor.h
index 945cd1de6a220d90735b24e09bbbabbf33490836..ee2c40570db1cca8a4e371e3d4bfd5f7347cf18f 100644
--- a/source/RobotAPI/libraries/armem/server/RemoteGuiAronDataVisitor.h
+++ b/source/RobotAPI/libraries/armem/server/RemoteGuiAronDataVisitor.h
@@ -5,13 +5,13 @@
 
 #include <ArmarXGui/libraries/RemoteGui/Client/Widgets.h>
 
-#include <RobotAPI/libraries/aron/aroncore/navigators/visitors/AronDataVisitor.h>
+#include <RobotAPI/libraries/aron/aroncore/navigators/visitors/DataVisitor.h>
 
 
 namespace armarx::armem::server
 {
 
-    struct RemoteGuiAronDataVisitor : public aron::visitor::AronDataVisitor
+    struct RemoteGuiAronDataVisitor : public aron::visitor::DataVisitor
     {
         using GroupBox = armarx::RemoteGui::Client::GroupBox;
         using GridLayout = armarx::RemoteGui::Client::GridLayout;
@@ -34,20 +34,20 @@ namespace armarx::armem::server
         virtual ~RemoteGuiAronDataVisitor() override;
 
 
-        bool visitEnter(const std::string& key, AronDictDataNavigator& n) override
+        bool visitEnter(const std::string& key, DictDataNavigator& n) override
         {
             return visitEnter(key, "dict", n.childrenSize());
         }
-        bool visitExit(AronDictDataNavigator&) override
+        bool visitExit(DictDataNavigator&) override
         {
             return visitExit();
         }
 
-        bool visitEnter(const std::string& key, AronListDataNavigator& n) override
+        bool visitEnter(const std::string& key, ListDataNavigator& n) override
         {
             return visitEnter(key, "list", n.childrenSize());
         }
-        bool visitExit(AronListDataNavigator&) override
+        bool visitExit(ListDataNavigator&) override
         {
             return visitExit();
         }
@@ -57,42 +57,42 @@ namespace armarx::armem::server
         bool visitExit();
 
         // Do not hide base overloads.
-        using AronDataVisitor::visitEnter;
-        using AronDataVisitor::visitExit;
+        using DataVisitor::visitEnter;
+        using DataVisitor::visitExit;
 
 
-        bool visit(const std::string& key, AronBoolDataNavigator& b) override
+        bool visit(const std::string& key, BoolDataNavigator& b) override
         {
             this->addValueLabel(key, b, "bool");
             return true;
         }
-        bool visit(const std::string& key, AronDoubleDataNavigator& d) override
+        bool visit(const std::string& key, DoubleDataNavigator& d) override
         {
             this->addValueLabel(key, d, "double");
             return true;
         }
-        bool visit(const std::string& key, AronFloatDataNavigator& f) override
+        bool visit(const std::string& key, FloatDataNavigator& f) override
         {
             this->addValueLabel(key, f, "float");
             return true;
         }
-        bool visit(const std::string& key, AronIntDataNavigator& i) override
+        bool visit(const std::string& key, IntDataNavigator& i) override
         {
             this->addValueLabel(key, i, "int");
             return true;
         }
-        bool visit(const std::string& key, AronLongDataNavigator& l) override
+        bool visit(const std::string& key, LongDataNavigator& l) override
         {
             this->addValueLabel(key, l, "long");
             return true;
         }
-        bool visit(const std::string& key, AronStringDataNavigator& string) override
+        bool visit(const std::string& key, StringDataNavigator& string) override
         {
             this->addValueLabel(key, string, "string");
             return true;
         }
 
-        bool visit(const std::string& key, AronNDArrayDataNavigator& array) override
+        bool visit(const std::string& key, NDArrayDataNavigator& array) override
         {
             this->addValueLabel(key, array, "ND Array");
             return true;
@@ -127,8 +127,8 @@ namespace armarx::armem::server
         {
             ss << n.getValue();
         }
-        void streamValueText(AronStringDataNavigator& n, std::stringstream& ss);
-        void streamValueText(AronNDArrayDataNavigator& n, std::stringstream& ss);
+        void streamValueText(StringDataNavigator& n, std::stringstream& ss);
+        void streamValueText(NDArrayDataNavigator& n, std::stringstream& ss);
 
         void checkGroupsNotEmpty() const;
 
diff --git a/source/RobotAPI/libraries/armem_gui/CMakeLists.txt b/source/RobotAPI/libraries/armem_gui/CMakeLists.txt
index 677ac70bc947279f8632d60d5d9ef792b2eb1a07..b0f974d9effc324e80a108d1889f291122d4b61f 100644
--- a/source/RobotAPI/libraries/armem_gui/CMakeLists.txt
+++ b/source/RobotAPI/libraries/armem_gui/CMakeLists.txt
@@ -12,9 +12,12 @@ set(LIBRARIES
 set(SOURCES
     InstanceTreeWidget.cpp
     MemoryTreeWidget.cpp
-    QTreeWidgetAronDataVisitor.cpp
     gui_utils.cpp
 
+    instance/InstanceTreeDataVisitorBase.cpp
+    instance/InstanceTreeDataVisitor.cpp
+    instance/InstanceTreeTypedDataVisitor.cpp
+
     query_widgets/QueryWidget.cpp
     query_widgets/SnapshotForm.cpp
     query_widgets/SnapshotSelectorWidget.cpp
@@ -23,9 +26,12 @@ set(HEADERS
     InstanceTreeWidget.h
     MemoryTreeWidget.h
     TreeWidgetBuilder.h
-    QTreeWidgetAronDataVisitor.h
     gui_utils.h
 
+    instance/InstanceTreeDataVisitorBase.h
+    instance/InstanceTreeDataVisitor.h
+    instance/InstanceTreeTypedDataVisitor.h
+
     query_widgets/QueryWidget.h
     query_widgets/SnapshotForm.h
     query_widgets/SnapshotSelectorWidget.h
diff --git a/source/RobotAPI/libraries/armem_gui/InstanceTreeWidget.cpp b/source/RobotAPI/libraries/armem_gui/InstanceTreeWidget.cpp
index d63f84fe55ddafddfc054bb94d287d392c21fc3f..f8c5ed61a3ee104c5463d7f17ef53064474fea0a 100644
--- a/source/RobotAPI/libraries/armem_gui/InstanceTreeWidget.cpp
+++ b/source/RobotAPI/libraries/armem_gui/InstanceTreeWidget.cpp
@@ -8,7 +8,9 @@
 #include <ArmarXCore/core/exceptions/local/ExpressionException.h>
 
 #include <RobotAPI/libraries/aron/aroncore/navigators/typenavigator/AronObjectTypeNavigator.h>
-#include <RobotAPI/libraries/armem_gui/QTreeWidgetAronDataVisitor.h>
+#include <RobotAPI/libraries/armem_gui/gui_utils.h>
+#include <RobotAPI/libraries/armem_gui/instance/InstanceTreeDataVisitor.h>
+#include <RobotAPI/libraries/armem_gui/instance/InstanceTreeTypedDataVisitor.h>
 
 
 namespace armarx::armem::gui
@@ -24,22 +26,63 @@ namespace armarx::armem::gui
         clear();
         QStringList columns;
         columns.insert(int(Columns::KEY), "Key");
-        columns.insert(int(Columns::TYPE), "Type");
         columns.insert(int(Columns::VALUE), "Value");
+        columns.insert(int(Columns::TYPE), "Type");
         setColumnCount(columns.size());
         setHeaderLabels(columns);
 
         // header()->setMinimumSectionSize(25);
-        // header()->resizeSection(int(Columns::KEY), 250);
+        header()->resizeSection(int(Columns::KEY), 250);
+        header()->resizeSection(int(Columns::VALUE), 250);
         // header()->setTextElideMode(Qt::TextElideMode::ElideRight);
+
+        itemInstanceID = new QTreeWidgetItem({"Instance ID"});
+        itemInstanceID->addChild(new QTreeWidgetItem({"Memory Name"}));
+        itemInstanceID->addChild(new QTreeWidgetItem({"Core Segment Name"}));
+        itemInstanceID->addChild(new QTreeWidgetItem({"Provider Segment Name"}));
+        itemInstanceID->addChild(new QTreeWidgetItem({"Entity Name"}));
+        itemInstanceID->addChild(new QTreeWidgetItem({"Timestamp"}));
+        itemInstanceID->addChild(new QTreeWidgetItem({"Instance Index"}));
+
+        itemMetadata = new QTreeWidgetItem({"Metadata"});
+        itemMetadata->addChild(new QTreeWidgetItem({"Confidence"}));
+        itemMetadata->addChild(new QTreeWidgetItem({"Time Created"}));
+        itemMetadata->addChild(new QTreeWidgetItem({"Time Sent"}));
+        itemMetadata->addChild(new QTreeWidgetItem({"Time Arrived"}));
+
+        itemData = new QTreeWidgetItem({"Data"});
+
+        QList<QTreeWidgetItem*> items = {itemInstanceID, itemMetadata, itemData};
+        addTopLevelItems(items);
+        for (auto* item : items)
+        {
+            item->setExpanded(true);
+        }
     }
 
+    void InstanceTreeWidget::setStatusLabel(QLabel* statusLabel)
+    {
+        this->statusLabel = statusLabel;
+    }
+
+    void InstanceTreeWidget::setUseTypeInfo(bool enable)
+    {
+        this->useTypeInfo = enable;
+        update();
+    }
+
+
     void InstanceTreeWidget::update(const MemoryID& id, const Memory& memory)
     {
-        const armem::EntityInstance* instance;
+        aron::typenavigator::AronObjectTypeNavigatorPtr aronType = nullptr;
+        const armem::EntityInstance* instance = nullptr;
         try
         {
             instance = &memory.getEntityInstance(id);
+            if (useTypeInfo)
+            {
+                aronType = memory.getCoreSegment(id.coreSegmentName).getProviderSegment(id.providerSegmentName).aronType();
+            }
         }
         catch (const armem::error::ArMemError& e)
         {
@@ -51,35 +94,80 @@ namespace armarx::armem::gui
         };
         if (instance)
         {
-            update(*instance);
+            update(*instance, aronType);
         }
     }
 
-    void InstanceTreeWidget::update(const EntityInstance& instance)
+
+    void InstanceTreeWidget::update(const EntityInstance& instance, aron::typenavigator::AronObjectTypeNavigatorPtr aronType)
     {
-        QTreeWidgetItem* item = new QTreeWidgetItem();
-        item->setText(0, QString::fromStdString(instance.id().str()));
+        currentInstance = instance;
+        currentAronType = aronType;
+        update();
+    }
 
-        if (!instance.data())
+    void InstanceTreeWidget::update()
+    {
+        if (currentInstance)
         {
-            item->setText(0, "(No data.)");
+            updateInstanceID(currentInstance->id());
+            updateData(currentInstance->data(), currentAronType);
+            updateMetaData(currentInstance->metadata());
+
+            emit updated();
         }
-        else
+    }
+
+
+    void InstanceTreeWidget::updateInstanceID(const MemoryID& id)
+    {
+        const std::vector<std::string> items = id.getAllItems();
+        ARMARX_CHECK_EQUAL(itemInstanceID->childCount(), static_cast<int>(items.size()));
+        int i = 0;
+        for (const std::string& item : items)
         {
-            QTreeWidgetAronDataVisitor visitor(item);
-            visitor.applyTo(*instance.data());
+            itemInstanceID->child(i++)->setText(int(Columns::VALUE), QString::fromStdString(item));
         }
+    }
 
-        clear();
-        addTopLevelItem(item);
-
-        item->setExpanded(true);
-        emit updated();
+    void InstanceTreeWidget::updateData(const aron::datanavigator::AronDictDataNavigatorPtr& data, aron::typenavigator::AronObjectTypeNavigatorPtr aronType)
+    {
+        armarx::gui::clearItem(itemData);
+        if (!data)
+        {
+            QTreeWidgetItem* item = new QTreeWidgetItem({"(No data.)"});
+            itemData->addChild(item);
+        }
+        else if (useTypeInfo && aronType)
+        {
+            InstanceTreeTypedDataVisitor visitor(itemData);
+            visitor.setColumns(int(Columns::KEY), int(Columns::VALUE), int(Columns::TYPE));
+            visitor.applyTo(*aronType, *data);
+        }
+        else
+        {
+            InstanceTreeDataVisitor visitor(itemData);
+            visitor.setColumns(int(Columns::KEY), int(Columns::VALUE), int(Columns::TYPE));
+            visitor.applyTo(*data);
+        }
+        itemData->setExpanded(true);
     }
 
-    void InstanceTreeWidget::setStatusLabel(QLabel* statusLabel)
+    void InstanceTreeWidget::updateMetaData(const EntityInstanceMetadata& metadata)
     {
-        this->statusLabel = statusLabel;
+        std::vector<std::string> items =
+        {
+            std::to_string(metadata.confidence),
+            armem::toDateTimeMilliSeconds(metadata.timeCreated),
+            armem::toDateTimeMilliSeconds(metadata.timeSent),
+            armem::toDateTimeMilliSeconds(metadata.timeArrived)
+        };
+        ARMARX_CHECK_EQUAL(itemMetadata->childCount(), items.size());
+        int i = 0;
+        for (const std::string& item : items)
+        {
+            itemMetadata->child(i++)->setText(int(Columns::VALUE), QString::fromStdString(item));
+        }
     }
 
 }
diff --git a/source/RobotAPI/libraries/armem_gui/InstanceTreeWidget.h b/source/RobotAPI/libraries/armem_gui/InstanceTreeWidget.h
index 4c3c2fa300d4364ea8b968babf9a83ce64e714e8..9bf076d65c3868b52775eb31f02ca4e01e1ca284 100644
--- a/source/RobotAPI/libraries/armem_gui/InstanceTreeWidget.h
+++ b/source/RobotAPI/libraries/armem_gui/InstanceTreeWidget.h
@@ -1,9 +1,14 @@
 #pragma once
 
+#include <optional>
+
 #include <QTreeWidget>
 
+#include <RobotAPI/libraries/aron/aroncore/navigators/typenavigator/AronObjectTypeNavigator.h>
+
 #include <RobotAPI/libraries/armem/core/Memory.h>
 
+
 class QLabel;
 
 
@@ -17,10 +22,12 @@ namespace armarx::armem::gui
 
         InstanceTreeWidget();
 
-        void update(const MemoryID& id, const Memory& memory);
-        void update(const EntityInstance& instance);
-
         void setStatusLabel(QLabel* statusLabel);
+        void setUseTypeInfo(bool enable);
+
+        void update(const MemoryID& id, const Memory& memory);
+        void update(const EntityInstance& instance, aron::typenavigator::AronObjectTypeNavigatorPtr aronType = nullptr);
+        void update();
 
 
     signals:
@@ -35,15 +42,28 @@ namespace armarx::armem::gui
     private:
 
         void initWidget();
+        void updateInstanceID(const MemoryID& id);
+        void updateData(const aron::datanavigator::AronDictDataNavigatorPtr& data, aron::typenavigator::AronObjectTypeNavigatorPtr aronType = nullptr);
+        void updateMetaData(const EntityInstanceMetadata& metadata);
+
+
+    private:
 
         QLabel* statusLabel = nullptr;
+        bool useTypeInfo = true;
+
+        QTreeWidgetItem* itemInstanceID;
+        QTreeWidgetItem* itemMetadata;
+        QTreeWidgetItem* itemData;
 
+        std::optional<EntityInstance> currentInstance;
+        aron::typenavigator::AronObjectTypeNavigatorPtr currentAronType = nullptr;
 
         enum class Columns
         {
             KEY = 0,
-            TYPE = 1,
-            VALUE = 2,
+            VALUE = 1,
+            TYPE = 2,
         };
     };
 
diff --git a/source/RobotAPI/libraries/armem_gui/MemoryTreeWidget.cpp b/source/RobotAPI/libraries/armem_gui/MemoryTreeWidget.cpp
index cbea351b288a5f766326dbe6857752d5d6aa093d..f17ff107046cbe7bc304bada3368c05bae7e406a 100644
--- a/source/RobotAPI/libraries/armem_gui/MemoryTreeWidget.cpp
+++ b/source/RobotAPI/libraries/armem_gui/MemoryTreeWidget.cpp
@@ -7,7 +7,6 @@
 #include <ArmarXCore/core/exceptions/local/ExpressionException.h>
 
 #include <RobotAPI/libraries/aron/aroncore/navigators/typenavigator/AronObjectTypeNavigator.h>
-#include <RobotAPI/libraries/armem_gui/QTreeWidgetAronDataVisitor.h>
 
 
 namespace armarx::armem::gui
@@ -37,7 +36,14 @@ namespace armarx::armem::gui
         header()->setTextElideMode(Qt::TextElideMode::ElideRight);
 
 
-        connect(this, &QTreeWidget::currentItemChanged, this, &MemoryTreeWidget::handleSelection);
+        connect(this, &QTreeWidget::currentItemChanged, this, &This::handleSelection);
+
+        connect(this, &This::memorySelected, this, &This::itemSelected);
+        connect(this, &This::coreSegmentSelected, this, &This::itemSelected);
+        connect(this, &This::providerSegmentSelected, this, &This::itemSelected);
+        connect(this, &This::entitySelected, this, &This::itemSelected);
+        connect(this, &This::snapshotSelected, this, &This::itemSelected);
+        connect(this, &This::instanceSelected, this, &This::itemSelected);
     }
 
     void MemoryTreeWidget::initBuilders()
@@ -116,7 +122,6 @@ namespace armarx::armem::gui
         instanceBuilder.setMakeItemFn([this](const EntityInstance & instance)
         {
             QTreeWidgetItem* item = makeItem("", instance);
-            item->setData(int(Columns::ID), Qt::UserRole, QString::fromStdString(instance.id().str()));
             return item;
         });
         instanceBuilder.setCompareFn([](const EntityInstance & lhs, QTreeWidgetItem * rhsItem)
@@ -145,19 +150,46 @@ namespace armarx::armem::gui
         emit updated();
     }
 
+    std::optional<MemoryID> MemoryTreeWidget::selectedID() const
+    {
+        return _selectedID;
+    }
+
     void MemoryTreeWidget::handleSelection()
     {
         QTreeWidgetItem* item = this->currentItem();
-        if (!item
-            || item->data(int(Columns::LEVEL), Qt::UserRole).toString().toStdString() != EntityInstance().getLevelName())
+        if (!item)
         {
             return;
         }
 
-        QString itemData = item->data(int(Columns::ID), Qt::UserRole).toString();
-        MemoryID instanceID(itemData.toStdString());
+        const std::string levelName = item->data(int(Columns::LEVEL), Qt::UserRole).toString().toStdString();
+        _selectedID = MemoryID(item->data(int(Columns::ID), Qt::UserRole).toString().toStdString());
 
-        emit instanceSelected(instanceID);
+        if (levelName == Memory().getLevelName())
+        {
+            emit memorySelected(*_selectedID);
+        }
+        else if (levelName == CoreSegment().getLevelName())
+        {
+            emit coreSegmentSelected(*_selectedID);
+        }
+        else if (levelName == ProviderSegment().getLevelName())
+        {
+            emit providerSegmentSelected(*_selectedID);
+        }
+        else if (levelName == Entity().getLevelName())
+        {
+            emit entitySelected(*_selectedID);
+        }
+        else if (levelName == EntitySnapshot().getLevelName())
+        {
+            emit snapshotSelected(*_selectedID);
+        }
+        else if (levelName == EntityInstance().getLevelName())
+        {
+            emit instanceSelected(*_selectedID);
+        }
     }
 
 
@@ -199,18 +231,7 @@ namespace armarx::armem::gui
 
     void MemoryTreeWidget::updateChildren(const armem::EntityInstance& data, QTreeWidgetItem* dataItem)
     {
-        if (instanceIntrospection)
-        {
-            if (data.data())
-            {
-                QTreeWidgetAronDataVisitor visitor(dataItem);
-                visitor.applyTo(*data.data());
-            }
-            else
-            {
-                dataItem->addChild(new QTreeWidgetItem(QStringList{"(No introspection available.)"}));
-            }
-        }
+        (void) data, (void) dataItem;
     }
 
     QTreeWidgetItem* MemoryTreeWidget::makeItem(const std::string& key, const armem::detail::MemoryItem& memoryItem)
@@ -225,6 +246,7 @@ namespace armarx::armem::gui
 
         QTreeWidgetItem* item = new QTreeWidgetItem(columns);
         item->setData(int(Columns::LEVEL), Qt::UserRole, QString::fromStdString(memoryItem.getLevelName()));
+        item->setData(int(Columns::ID), Qt::UserRole, QString::fromStdString(memoryItem.id().str()));
         item->setTextAlignment(int(Columns::SIZE), Qt::AlignRight);
         return item;
     }
@@ -250,7 +272,17 @@ namespace armarx::armem::gui
         std::string typeName;
         if (container.aronType())
         {
-            typeName = container.aronType()->getName();
+            typeName = container.aronType()->getObjectName();
+
+            std::string del = "::";
+            size_t find = typeName.rfind(del);
+            if (find != typeName.npos)
+            {
+                find += del.size();  // include del
+                std::stringstream ss;
+                ss << typeName.substr(find) << " (" << typeName.substr(0, find) << ")";
+                typeName = ss.str();
+            }
         }
         else
         {
diff --git a/source/RobotAPI/libraries/armem_gui/MemoryTreeWidget.h b/source/RobotAPI/libraries/armem_gui/MemoryTreeWidget.h
index 0aff62014b444997d67d1ce67517f95952cda734..4310f3e30cbf79b7b257d3a060c30e0b135a028c 100644
--- a/source/RobotAPI/libraries/armem_gui/MemoryTreeWidget.h
+++ b/source/RobotAPI/libraries/armem_gui/MemoryTreeWidget.h
@@ -17,6 +17,8 @@ namespace armarx::armem::gui
     class MemoryTreeWidget : public QTreeWidget
     {
         Q_OBJECT
+        using This = MemoryTreeWidget;
+
     public:
 
         MemoryTreeWidget();
@@ -24,10 +26,20 @@ namespace armarx::armem::gui
         void update(const armem::Memory& memory);
         void update(const std::map<std::string, const armem::Memory*>& memories);
 
+        std::optional<MemoryID> selectedID() const;
+
 
     signals:
 
         void updated();
+
+        void itemSelected(const MemoryID& id);
+
+        void memorySelected(const MemoryID& id);
+        void coreSegmentSelected(const MemoryID& id);
+        void providerSegmentSelected(const MemoryID& id);
+        void entitySelected(const MemoryID& id);
+        void snapshotSelected(const MemoryID& id);
         void instanceSelected(const MemoryID& id);
 
 
@@ -63,8 +75,6 @@ namespace armarx::armem::gui
 
     private:
 
-        bool instanceIntrospection = false;
-
         MapTreeWidgetBuilder<std::string, const Memory*> memoryBuilder;
         MapTreeWidgetBuilder<std::string, CoreSegment> coreSegmentBuilder;
         MapTreeWidgetBuilder<std::string, ProviderSegment> provSegmentBuilder;
@@ -72,6 +82,7 @@ namespace armarx::armem::gui
         MapTreeWidgetBuilder<armem::Time, EntitySnapshot> snapshotBuilder;
         TreeWidgetBuilder<std::vector<EntityInstance>> instanceBuilder;
 
+        std::optional<MemoryID> _selectedID;
 
         enum class Columns
         {
diff --git a/source/RobotAPI/libraries/armem_gui/QTreeWidgetAronDataVisitor.cpp b/source/RobotAPI/libraries/armem_gui/QTreeWidgetAronDataVisitor.cpp
deleted file mode 100644
index c3d169ff240ed50fd45fcbd5c9456fafb974ba68..0000000000000000000000000000000000000000
--- a/source/RobotAPI/libraries/armem_gui/QTreeWidgetAronDataVisitor.cpp
+++ /dev/null
@@ -1,69 +0,0 @@
-#include "QTreeWidgetAronDataVisitor.h"
-
-#include <ArmarXCore/core/exceptions/local/ExpressionException.h>
-
-
-namespace armarx::armem::gui
-{
-
-    QTreeWidgetAronDataVisitor::QTreeWidgetAronDataVisitor()
-    {
-    }
-
-    QTreeWidgetAronDataVisitor::QTreeWidgetAronDataVisitor(QTreeWidgetItem* root)
-    {
-        rootItems.push(root);
-    }
-
-    QTreeWidgetAronDataVisitor::~QTreeWidgetAronDataVisitor()
-    {}
-
-    bool QTreeWidgetAronDataVisitor::_visitEnter(const std::string& key, const std::string& type, size_t numChildren)
-    {
-        QTreeWidgetItem* item = nullptr;
-        if (rootItems.size() > 0)
-        {
-            item = rootItems.top();
-            rootItems.pop();
-        }
-        else
-        {
-            QStringList cols;
-            cols.insert(0, QString::fromStdString(key));
-            cols.insert(1, QString::fromStdString(type));
-            cols.insert(2, QString::number(numChildren) + " items");
-            item = new QTreeWidgetItem(cols);
-        }
-        items.push(item);
-        return true;
-    }
-
-    bool QTreeWidgetAronDataVisitor::_visitExit()
-    {
-        ARMARX_CHECK_POSITIVE(items.size());
-        QTreeWidgetItem* item = items.top();
-        items.pop();
-        item->setExpanded(true);
-        if (items.size() > 0)
-        {
-            items.top()->addChild(item);
-        }
-        else
-        {
-            rootItems.push(item);
-        }
-        return true;
-    }
-
-    void QTreeWidgetAronDataVisitor::streamValueText(AronStringDataNavigator& n, std::stringstream& ss)
-    {
-        ss << "'" << n.getValue() << "'";
-    }
-
-    void QTreeWidgetAronDataVisitor::streamValueText(AronNDArrayDataNavigator& n, std::stringstream& ss)
-    {
-        ss << "shape (" << simox::alg::join(simox::alg::multi_to_string(n.getDimensions()), ", ") << ")";
-    }
-
-
-}
diff --git a/source/RobotAPI/libraries/armem_gui/QTreeWidgetAronDataVisitor.h b/source/RobotAPI/libraries/armem_gui/QTreeWidgetAronDataVisitor.h
deleted file mode 100644
index 5d6c7667e636745aa57d1076563eda1c19f01685..0000000000000000000000000000000000000000
--- a/source/RobotAPI/libraries/armem_gui/QTreeWidgetAronDataVisitor.h
+++ /dev/null
@@ -1,124 +0,0 @@
-#pragma once
-
-#include <sstream>
-#include <stack>
-
-#include <QTreeWidget>
-#include <QLabel>
-
-#include <RobotAPI/libraries/aron/aroncore/navigators/visitors/AronDataVisitor.h>
-
-
-namespace armarx::armem::gui
-{
-
-
-
-    struct QTreeWidgetAronDataVisitor : public aron::visitor::AronDataVisitor
-    {
-        std::stack<QTreeWidgetItem*> rootItems;
-        std::stack<QTreeWidgetItem*> items;
-
-
-        QTreeWidgetAronDataVisitor();
-        QTreeWidgetAronDataVisitor(QTreeWidgetItem* root);
-        virtual ~QTreeWidgetAronDataVisitor() override;
-
-
-        bool visitEnter(const std::string& key, AronDictDataNavigator& n) override
-        {
-            return _visitEnter(key, "Dict", n.childrenSize());
-        }
-        bool visitExit(AronDictDataNavigator&) override
-        {
-            return _visitExit();
-        }
-
-        bool visitEnter(const std::string& key, AronListDataNavigator& n) override
-        {
-            return _visitEnter(key, "List", n.childrenSize());
-        }
-        bool visitExit(AronListDataNavigator&) override
-        {
-            return _visitExit();
-        }
-
-        // Same for Dict and List
-        bool _visitEnter(const std::string& key, const std::string& type, size_t numChildren);
-        bool _visitExit();
-
-
-        bool visit(const std::string& key, AronBoolDataNavigator& b) override
-        {
-            this->addValueRow(key, b, "Bool");
-            return true;
-        }
-        bool visit(const std::string& key, AronDoubleDataNavigator& d) override
-        {
-            this->addValueRow(key, d, "Double");
-            return true;
-        }
-        bool visit(const std::string& key, AronFloatDataNavigator& f) override
-        {
-            this->addValueRow(key, f, "Float");
-            return true;
-        }
-        bool visit(const std::string& key, AronIntDataNavigator& i) override
-        {
-            this->addValueRow(key, i, "Int");
-            return true;
-        }
-        bool visit(const std::string& key, AronLongDataNavigator& l) override
-        {
-            this->addValueRow(key, l, "Long");
-            return true;
-        }
-        bool visit(const std::string& key, AronStringDataNavigator& string) override
-        {
-            this->addValueRow(key, string, "String");
-            return true;
-        }
-
-        bool visit(const std::string& key, AronNDArrayDataNavigator& array) override
-        {
-            this->addValueRow(key, array, "ND Array");
-            return true;
-        }
-
-
-    private:
-
-        template <class Navigator>
-        void addValueRow(const std::string& key, Navigator& n, const std::string& typeName)
-        {
-            if (items.size() > 0)
-            {
-                items.top()->addChild(new QTreeWidgetItem(this->makeValueRowStrings(key, n, typeName)));
-            }
-        }
-
-        template <class Navigator>
-        QStringList makeValueRowStrings(const std::string& key, Navigator& n, const std::string& typeName)
-        {
-            std::stringstream value;
-            streamValueText(n, value);
-            return
-            {
-                QString::fromStdString(key),
-                QString::fromStdString(typeName),
-                QString::fromStdString(value.str()),
-            };
-        }
-
-        template <class Navigator>
-        void streamValueText(Navigator& n, std::stringstream& ss)
-        {
-            ss << n.getValue();
-        }
-        void streamValueText(AronStringDataNavigator& n, std::stringstream& ss);
-        void streamValueText(AronNDArrayDataNavigator& n, std::stringstream& ss);
-
-    };
-
-
-}
diff --git a/source/RobotAPI/libraries/armem_gui/gui_utils.cpp b/source/RobotAPI/libraries/armem_gui/gui_utils.cpp
index b914d624236852e05796d009d3077892eed48d43..1bbfe2dc065129bdc65d35dd09b27856b2a70742 100644
--- a/source/RobotAPI/libraries/armem_gui/gui_utils.cpp
+++ b/source/RobotAPI/libraries/armem_gui/gui_utils.cpp
@@ -3,6 +3,7 @@
 #include <QLayout>
 #include <QLayoutItem>
 #include <QWidget>
+#include <QTreeWidgetItem>
 
 
 namespace armarx
@@ -28,5 +29,12 @@ namespace armarx
         }
     }
 
-
+    void gui::clearItem(QTreeWidgetItem* item)
+    {
+        while (item->childCount() > 0)
+        {
+            delete item->takeChild(0);
+        }
+    }
 }
+
diff --git a/source/RobotAPI/libraries/armem_gui/gui_utils.h b/source/RobotAPI/libraries/armem_gui/gui_utils.h
index eabcffb765798175b93a1376305f01e868d6ecf4..23824173121dda4dce002e4185a94601fa739beb 100644
--- a/source/RobotAPI/libraries/armem_gui/gui_utils.h
+++ b/source/RobotAPI/libraries/armem_gui/gui_utils.h
@@ -2,6 +2,7 @@
 
 
 class QLayout;
+class QTreeWidgetItem;
 
 
 namespace armarx::gui
@@ -15,4 +16,13 @@ namespace armarx::gui
      */
     void clearLayout(QLayout* layout);
 
+    /**
+     * @brief Clear a tree widget item
+     *
+     * Take and delete all children of `item`.
+     *
+     * @param item The tree widget item.
+     */
+    void clearItem(QTreeWidgetItem* item);
+
 }
diff --git a/source/RobotAPI/libraries/armem_gui/instance/InstanceTreeDataVisitor.cpp b/source/RobotAPI/libraries/armem_gui/instance/InstanceTreeDataVisitor.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d92450283599807b2b4d35531bccc113c0906f54
--- /dev/null
+++ b/source/RobotAPI/libraries/armem_gui/instance/InstanceTreeDataVisitor.cpp
@@ -0,0 +1,9 @@
+#include "InstanceTreeDataVisitor.h"
+
+#include <ArmarXCore/core/exceptions/local/ExpressionException.h>
+
+
+namespace armarx::armem::gui
+{
+
+}
diff --git a/source/RobotAPI/libraries/armem_gui/instance/InstanceTreeDataVisitor.h b/source/RobotAPI/libraries/armem_gui/instance/InstanceTreeDataVisitor.h
new file mode 100644
index 0000000000000000000000000000000000000000..2ceb790caf10591bb0260a52f83445f4458fa84f
--- /dev/null
+++ b/source/RobotAPI/libraries/armem_gui/instance/InstanceTreeDataVisitor.h
@@ -0,0 +1,78 @@
+#pragma once
+
+#include <sstream>
+#include <stack>
+
+#include <QTreeWidget>
+#include <QLabel>
+
+#include <RobotAPI/libraries/aron/aroncore/navigators/visitors/DataVisitor.h>
+
+#include "InstanceTreeDataVisitorBase.h"
+
+
+namespace armarx::armem::gui
+{
+
+    class InstanceTreeDataVisitor :
+        public aron::visitor::DataVisitor,
+        public InstanceTreeDataVisitorBase
+    {
+    public:
+
+        using InstanceTreeDataVisitorBase::InstanceTreeDataVisitorBase;
+
+
+        bool visitEnter(const std::string& key, DictDataNavigator& n) override
+        {
+            return _visitEnter(key, "Dict", n.childrenSize());
+        }
+        bool visitExit(DictDataNavigator&) override
+        {
+            return _visitExit();
+        }
+
+        bool visitEnter(const std::string& key, ListDataNavigator& n) override
+        {
+            return _visitEnter(key, "List", n.childrenSize());
+        }
+        bool visitExit(ListDataNavigator&) override
+        {
+            return _visitExit();
+        }
+
+
+        bool visit(const std::string& key, BoolDataNavigator& b) override
+        {
+            return this->addValueRow(key, b, "Bool");
+        }
+        bool visit(const std::string& key, DoubleDataNavigator& d) override
+        {
+            return this->addValueRow(key, d, "Double");
+        }
+        bool visit(const std::string& key, FloatDataNavigator& f) override
+        {
+            return this->addValueRow(key, f, "Float");
+        }
+        bool visit(const std::string& key, IntDataNavigator& i) override
+        {
+            return this->addValueRow(key, i, "Int");
+        }
+        bool visit(const std::string& key, LongDataNavigator& l) override
+        {
+            return this->addValueRow(key, l, "Long");
+        }
+        bool visit(const std::string& key, StringDataNavigator& string) override
+        {
+            return this->addValueRow(key, string, "String");
+        }
+
+        bool visit(const std::string& key, NDArrayDataNavigator& array) override
+        {
+            return this->addValueRow(key, array, "ND Array");
+        }
+
+    };
+
+
+}
diff --git a/source/RobotAPI/libraries/armem_gui/instance/InstanceTreeDataVisitorBase.cpp b/source/RobotAPI/libraries/armem_gui/instance/InstanceTreeDataVisitorBase.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..7784106311912e98e924745632a9fdfcc18c1cf8
--- /dev/null
+++ b/source/RobotAPI/libraries/armem_gui/instance/InstanceTreeDataVisitorBase.cpp
@@ -0,0 +1,75 @@
+#include "InstanceTreeDataVisitorBase.h"
+
+#include <ArmarXCore/core/exceptions/local/ExpressionException.h>
+
+
+namespace armarx::armem::gui
+{
+
+    InstanceTreeDataVisitorBase::InstanceTreeDataVisitorBase()
+    {
+    }
+
+    InstanceTreeDataVisitorBase::InstanceTreeDataVisitorBase(QTreeWidgetItem* root)
+    {
+        rootItems.push(root);
+    }
+
+    InstanceTreeDataVisitorBase::~InstanceTreeDataVisitorBase()
+    {}
+
+    void InstanceTreeDataVisitorBase::setColumns(int key, int value, int type)
+    {
+        this->columnKey = key;
+        this->columnType = type;
+        this->columnValue = value;
+    }
+
+    bool InstanceTreeDataVisitorBase::_visitEnter(const std::string& key, const std::string& type, size_t numChildren)
+    {
+        QTreeWidgetItem* item = nullptr;
+        if (rootItems.size() > 0)
+        {
+            item = rootItems.top();
+            rootItems.pop();
+        }
+        else
+        {
+            QStringList cols;
+            cols.insert(columnKey, QString::fromStdString(key));
+            cols.insert(columnValue, QString::number(numChildren) + " items");
+            cols.insert(columnType, QString::fromStdString(type));
+            item = new QTreeWidgetItem(cols);
+        }
+        items.push(item);
+        return true;
+    }
+
+    bool InstanceTreeDataVisitorBase::_visitExit()
+    {
+        ARMARX_CHECK_POSITIVE(items.size());
+        QTreeWidgetItem* item = items.top();
+        items.pop();
+        item->setExpanded(true);
+        if (items.size() > 0)
+        {
+            items.top()->addChild(item);
+        }
+        else
+        {
+            rootItems.push(item);
+        }
+        return true;
+    }
+
+    void InstanceTreeDataVisitorBase::streamValueText(aron::visitor::DataVisitor::StringDataNavigator& n, std::stringstream& ss)
+    {
+        ss << "'" << n.getValue() << "'";
+    }
+
+    void InstanceTreeDataVisitorBase::streamValueText(aron::visitor::DataVisitor::NDArrayDataNavigator& n, std::stringstream& ss)
+    {
+        ss << "shape (" << simox::alg::join(simox::alg::multi_to_string(n.getDimensions()), ", ") << ")";
+    }
+
+}
diff --git a/source/RobotAPI/libraries/armem_gui/instance/InstanceTreeDataVisitorBase.h b/source/RobotAPI/libraries/armem_gui/instance/InstanceTreeDataVisitorBase.h
new file mode 100644
index 0000000000000000000000000000000000000000..fd45d515e2bb4e71a165dd173a3d63fd8980d763
--- /dev/null
+++ b/source/RobotAPI/libraries/armem_gui/instance/InstanceTreeDataVisitorBase.h
@@ -0,0 +1,75 @@
+#pragma once
+
+#include <sstream>
+#include <stack>
+
+#include <QTreeWidget>
+#include <QLabel>
+
+#include <RobotAPI/libraries/aron/aroncore/navigators/visitors/DataVisitor.h>
+
+
+namespace armarx::armem::gui
+{
+
+    class InstanceTreeDataVisitorBase
+    {
+    public:
+
+        InstanceTreeDataVisitorBase();
+        InstanceTreeDataVisitorBase(QTreeWidgetItem* root);
+        virtual ~InstanceTreeDataVisitorBase();
+
+        void setColumns(int key, int value, int type);
+
+
+    protected:
+
+        // Same for Dict and List
+        bool _visitEnter(const std::string& key, const std::string& type, size_t numChildren);
+        bool _visitExit();
+
+
+        template <class Navigator>
+        bool addValueRow(const std::string& key, Navigator& n, const std::string& typeName)
+        {
+            if (items.size() > 0)
+            {
+                items.top()->addChild(new QTreeWidgetItem(this->makeValueRowStrings(key, n, typeName)));
+            }
+            return true;
+        }
+
+        template <class Navigator>
+        QStringList makeValueRowStrings(const std::string& key, Navigator& n, const std::string& typeName)
+        {
+            std::stringstream value;
+            streamValueText(n, value);
+            QStringList cols;
+            cols.insert(columnKey, QString::fromStdString(key));
+            cols.insert(columnValue, QString::fromStdString(value.str()));
+            cols.insert(columnType, QString::fromStdString(typeName));
+            return cols;
+        }
+
+        template <class Navigator>
+        void streamValueText(Navigator& n, std::stringstream& ss)
+        {
+            ss << n.getValue();
+        }
+        void streamValueText(aron::visitor::DataVisitor::StringDataNavigator& n, std::stringstream& ss);
+        void streamValueText(aron::visitor::DataVisitor::NDArrayDataNavigator& n, std::stringstream& ss);
+
+
+    public:
+
+        std::stack<QTreeWidgetItem*> rootItems;
+        std::stack<QTreeWidgetItem*> items;
+
+        int columnKey = 0;
+        int columnValue = 1;
+        int columnType = 2;
+
+    };
+
+}
diff --git a/source/RobotAPI/libraries/armem_gui/instance/InstanceTreeTypedDataVisitor.cpp b/source/RobotAPI/libraries/armem_gui/instance/InstanceTreeTypedDataVisitor.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d7f8169b940499ac297bcd6e27e16d4c2f411333
--- /dev/null
+++ b/source/RobotAPI/libraries/armem_gui/instance/InstanceTreeTypedDataVisitor.cpp
@@ -0,0 +1,10 @@
+#include "InstanceTreeTypedDataVisitor.h"
+
+#include <ArmarXCore/core/exceptions/local/ExpressionException.h>
+
+
+namespace armarx::armem::gui
+{
+
+
+}
diff --git a/source/RobotAPI/libraries/armem_gui/instance/InstanceTreeTypedDataVisitor.h b/source/RobotAPI/libraries/armem_gui/instance/InstanceTreeTypedDataVisitor.h
new file mode 100644
index 0000000000000000000000000000000000000000..e55b3eb5eaa359817526a943558daa20af6645b3
--- /dev/null
+++ b/source/RobotAPI/libraries/armem_gui/instance/InstanceTreeTypedDataVisitor.h
@@ -0,0 +1,107 @@
+#pragma once
+
+#include <sstream>
+#include <stack>
+
+#include <QTreeWidget>
+#include <QLabel>
+
+#include <RobotAPI/libraries/aron/aroncore/navigators/visitors/TypedDataVisitor.h>
+#include "InstanceTreeDataVisitorBase.h"
+
+
+namespace armarx::armem::gui
+{
+
+    class InstanceTreeTypedDataVisitor :
+        public aron::visitor::TypedDataVisitor,
+        public InstanceTreeDataVisitorBase
+    {
+    public:
+
+        using InstanceTreeDataVisitorBase::InstanceTreeDataVisitorBase;
+
+
+        bool visitEnter(DictTypeNavigator& type, const std::string& key, DictDataNavigator& data) override
+        {
+            return _visitEnter(key, type.getName(), data.childrenSize());
+        }
+        bool visitExit(DictTypeNavigator&, DictDataNavigator&) override
+        {
+            return _visitExit();
+        }
+
+        bool visitEnter(ObjectTypeNavigator& type, const std::string& key, DictDataNavigator& data) override
+        {
+            return _visitEnter(key, type.getName(), data.childrenSize());
+        }
+        bool visitExit(ObjectTypeNavigator&, DictDataNavigator&) override
+        {
+            return _visitExit();
+        }
+
+        bool visitEnter(ListTypeNavigator& type, const std::string& key, ListDataNavigator& data) override
+        {
+            return _visitEnter(key, type.getName(), data.childrenSize());
+        }
+        bool visitExit(ListTypeNavigator&, ListDataNavigator&) override
+        {
+            return _visitExit();
+        }
+
+        bool visitEnter(TupleTypeNavigator& type, const std::string& key, ListDataNavigator& data) override
+        {
+            return _visitEnter(key, type.getName(), data.childrenSize());
+        }
+        bool visitExit(TupleTypeNavigator&, ListDataNavigator&) override
+        {
+            return _visitExit();
+        }
+
+
+        bool visit(BoolTypeNavigator& type, const std::string& key, BoolDataNavigator& data) override
+        {
+            return this->addValueRow(key, data, type.getName());
+        }
+        bool visit(DoubleTypeNavigator& type, const std::string& key, DoubleDataNavigator& data) override
+        {
+            return this->addValueRow(key, data, type.getName());
+        }
+        bool visit(FloatTypeNavigator& type, const std::string& key, FloatDataNavigator& data) override
+        {
+            return this->addValueRow(key, data, type.getName());
+        }
+        bool visit(IntTypeNavigator& type, const std::string& key, IntDataNavigator& data) override
+        {
+            return this->addValueRow(key, data, type.getName());
+        }
+        bool visit(LongTypeNavigator& type, const std::string& key, LongDataNavigator& data) override
+        {
+            return this->addValueRow(key, data, type.getName());
+        }
+        bool visit(StringTypeNavigator& type, const std::string& key, StringDataNavigator& data) override
+        {
+            return this->addValueRow(key, data, type.getName());
+        }
+
+
+        bool visit(EigenMatrixTypeNavigator& type, const std::string& key, NDArrayDataNavigator& data) override
+        {
+            return this->addValueRow(key, data, type.getName());
+        }
+        bool visit(IVTCByteImageTypeNavigator& type, const std::string& key, NDArrayDataNavigator& data) override
+        {
+            return this->addValueRow(key, data, type.getName());
+        }
+        bool visit(OpenCVMatTypeNavigator& type, const std::string& key, NDArrayDataNavigator& data) override
+        {
+            return this->addValueRow(key, data, type.getName());
+        }
+        bool visit(PCLPointCloudTypeNavigator& type, const std::string& key, NDArrayDataNavigator& data) override
+        {
+            return this->addValueRow(key, data, type.getName());
+        }
+
+    };
+
+}
diff --git a/source/RobotAPI/libraries/aron/aroncore/CMakeLists.txt b/source/RobotAPI/libraries/aron/aroncore/CMakeLists.txt
index ca62febd315774ce184005fdc018a5f1187329f0..fb75e9b7c50bbdd4d6769d3a371a3c47b24a7e9a 100644
--- a/source/RobotAPI/libraries/aron/aroncore/CMakeLists.txt
+++ b/source/RobotAPI/libraries/aron/aroncore/CMakeLists.txt
@@ -47,7 +47,8 @@ set(LIB_FILES
     navigators/typenavigator/AronPrimitiveTypeNavigator.cpp
     navigators/typenavigator/AronTypeNavigatorFactory.cpp
 
-    navigators/visitors/AronDataVisitor.cpp
+    navigators/visitors/DataVisitor.cpp
+    navigators/visitors/TypedDataVisitor.cpp
 
     io/AronDataIO/classWriters/NavigatorWriter/AronDataNavigatorWriter.cpp
     io/AronDataIO/classWriters/NlohmannJSONWriter/AronDataNlohmannJSONWriter.cpp
@@ -122,7 +123,8 @@ set(LIB_HEADERS
     navigators/typenavigator/AronPrimitiveTypeNavigator.h
     navigators/typenavigator/AronTypeNavigatorFactory.h
 
-    navigators/visitors/AronDataVisitor.h
+    navigators/visitors/DataVisitor.h
+    navigators/visitors/TypedDataVisitor.h
 
     io/AronReaderWriter.h
     io/AronReaderWriterToken.h
diff --git a/source/RobotAPI/libraries/aron/aroncore/codegenerator/typeReaders/xmlReader/AronTypeXMLReaderFactory.cpp b/source/RobotAPI/libraries/aron/aroncore/codegenerator/typeReaders/xmlReader/AronTypeXMLReaderFactory.cpp
index 385f92212cce8e30735cdd3139addb674726d2e8..f2ac4d541a8dcf34d052bc9e8604f943abe87fbe 100644
--- a/source/RobotAPI/libraries/aron/aroncore/codegenerator/typeReaders/xmlReader/AronTypeXMLReaderFactory.cpp
+++ b/source/RobotAPI/libraries/aron/aroncore/codegenerator/typeReaders/xmlReader/AronTypeXMLReaderFactory.cpp
@@ -44,25 +44,24 @@ namespace armarx
                 std::stack<AronGenerateTypeInfoPtr> AronTypeXMLReaderFactory::TheObjectWeAreGoingToGenerateNowStack = {};
                 std::map<std::string, AronGenerateTypeInfoPtr> AronTypeXMLReaderFactory::AllKnownGeneratedPublicObjects = {};
 
-                const std::map<std::string, AronTypeXMLReaderFactoryPtr> AronTypeXMLReaderFactory::Factories =
+
+                typenavigator::AronTypeNavigatorPtr AronTypeXMLReaderFactory::create(const RapidXmlReaderNode& node, const AronPath& path) const
                 {
 #define RUN_ARON_MACRO(upperType, lowerType, capsType) \
-    {AronTypeXMLReaderData::ARON_GENERATE_##capsType##_TAG, AronTypeXMLReaderFactoryPtr(new Aron##upperType##TypeXMLReaderFactory())}, \
-
-                    HANDLE_CONTAINER_TYPES
-                    HANDLE_COMPLEX_TYPES
-                    HANDLE_PRIMITIVE_TYPES
+    {AronTypeXMLReaderData::ARON_GENERATE_##capsType##_TAG, AronTypeXMLReaderFactoryPtr(new Aron##upperType##TypeXMLReaderFactory())},
+                    static const std::map<std::string, AronTypeXMLReaderFactoryPtr> Factories =
+                    {
+                        HANDLE_CONTAINER_TYPES
+                        HANDLE_COMPLEX_TYPES
+                        HANDLE_PRIMITIVE_TYPES
+                    };
 #undef RUN_ARON_MACRO
-                };
 
-                typenavigator::AronTypeNavigatorPtr AronTypeXMLReaderFactory::create(const RapidXmlReaderNode& node, const AronPath& path) const
-                {
                     const std::string tag = simox::alg::to_lower(node.name());
                     if (tag == "")
                     {
                         throw exception::AronException("AronTypeXMLReaderFactory", "create", "An node is empty. Cannot find facory for empty nodes.");
                     }
-
                     auto factory_iterator = Factories.find(tag);
                     if (factory_iterator != Factories.end())
                     {
diff --git a/source/RobotAPI/libraries/aron/aroncore/codegenerator/typeReaders/xmlReader/AronTypeXMLReaderFactory.h b/source/RobotAPI/libraries/aron/aroncore/codegenerator/typeReaders/xmlReader/AronTypeXMLReaderFactory.h
index df781306e704a3cdef7e1a41e50bf3d6763d1f42..8347da4c914e1058b3c8be10f9b80417b31966a9 100644
--- a/source/RobotAPI/libraries/aron/aroncore/codegenerator/typeReaders/xmlReader/AronTypeXMLReaderFactory.h
+++ b/source/RobotAPI/libraries/aron/aroncore/codegenerator/typeReaders/xmlReader/AronTypeXMLReaderFactory.h
@@ -68,9 +68,6 @@ namespace armarx
                 protected:
                     static std::stack<AronGenerateTypeInfoPtr> TheObjectWeAreGoingToGenerateNowStack;
                     static std::map<std::string, AronGenerateTypeInfoPtr> AllKnownGeneratedPublicObjects;
-
-                private:
-                    static const std::map<std::string, AronTypeXMLReaderFactoryPtr> Factories;
                 };
 
 #define RUN_ARON_MACRO(upperType, lowerType, capsType) \
diff --git a/source/RobotAPI/libraries/aron/aroncore/navigators/typenavigator/AronDictTypeNavigator.cpp b/source/RobotAPI/libraries/aron/aroncore/navigators/typenavigator/AronDictTypeNavigator.cpp
index 997d1bf8cf73dda37bce8938d202e621188c659b..6cb665fd736af4fb3b6aa6e28541d4f796ed11fe 100644
--- a/source/RobotAPI/libraries/aron/aroncore/navigators/typenavigator/AronDictTypeNavigator.cpp
+++ b/source/RobotAPI/libraries/aron/aroncore/navigators/typenavigator/AronDictTypeNavigator.cpp
@@ -46,6 +46,8 @@ namespace armarx
                 type(o)
             {
                 CheckAronPtrForNull("AronDictTypeNavigator", "AronDictTypeNavigator", getPath(), o);
+
+                acceptedTypeNavigator = FromAronType(o->acceptedType);
             }
 
             void AronDictTypeNavigator::setAcceptedType(const AronTypeNavigatorPtr& a)
diff --git a/source/RobotAPI/libraries/aron/aroncore/navigators/typenavigator/AronListTypeNavigator.cpp b/source/RobotAPI/libraries/aron/aroncore/navigators/typenavigator/AronListTypeNavigator.cpp
index d77033eccc99b96ea2c57db99f36179c2a7b9b75..98f6f7364a94546b21afebad5c3fc86c04189af0 100644
--- a/source/RobotAPI/libraries/aron/aroncore/navigators/typenavigator/AronListTypeNavigator.cpp
+++ b/source/RobotAPI/libraries/aron/aroncore/navigators/typenavigator/AronListTypeNavigator.cpp
@@ -44,6 +44,8 @@ namespace armarx
                 type(o)
             {
                 CheckAronPtrForNull("AronListTypeNavigator", "AronListTypeNavigator", getPath(), o);
+
+                acceptedTypeNavigator = FromAronType(o->acceptedType);
             }
 
             // static methods
diff --git a/source/RobotAPI/libraries/aron/aroncore/navigators/typenavigator/AronObjectTypeNavigator.cpp b/source/RobotAPI/libraries/aron/aroncore/navigators/typenavigator/AronObjectTypeNavigator.cpp
index 63b13137ed73427745069b8032f8f03488a8ccff..9d483dd69ab02a49a1a8ea95bfe93a6010ee6807 100644
--- a/source/RobotAPI/libraries/aron/aroncore/navigators/typenavigator/AronObjectTypeNavigator.cpp
+++ b/source/RobotAPI/libraries/aron/aroncore/navigators/typenavigator/AronObjectTypeNavigator.cpp
@@ -46,6 +46,11 @@ namespace armarx
                 type(o)
             {
                 CheckAronPtrForNull("AronObjectTypeNavigator", "AronObjectTypeNavigator", getPath(), o);
+
+                for(const auto& [key, t] : o->elementTypes)
+                {
+                    acceptedTypeNavigators[key] = FromAronType(t);
+                }
             }
 
             // static methods
diff --git a/source/RobotAPI/libraries/aron/aroncore/navigators/typenavigator/AronTupleTypeNavigator.cpp b/source/RobotAPI/libraries/aron/aroncore/navigators/typenavigator/AronTupleTypeNavigator.cpp
index a58ea955e6b80287c79934bd6a73486c67f99a4a..9f9d44403a7159ecc4746e027cee37ac1cd9cb6c 100644
--- a/source/RobotAPI/libraries/aron/aroncore/navigators/typenavigator/AronTupleTypeNavigator.cpp
+++ b/source/RobotAPI/libraries/aron/aroncore/navigators/typenavigator/AronTupleTypeNavigator.cpp
@@ -45,6 +45,11 @@ namespace armarx
                 type(o)
             {
                 CheckAronPtrForNull("AronTupleTypeNavigator", "AronTupleTypeNavigator", getPath(), o);
+
+                for (const auto& t : type->elementTypes)
+                {
+                    acceptedTypeNavigators.push_back(FromAronType(t));
+                }
             }
 
             type::AronTupleTypePtr AronTupleTypeNavigator::toAronTupleTypePtr() const
diff --git a/source/RobotAPI/libraries/aron/aroncore/navigators/visitors/AronDataVisitor.cpp b/source/RobotAPI/libraries/aron/aroncore/navigators/visitors/DataVisitor.cpp
similarity index 62%
rename from source/RobotAPI/libraries/aron/aroncore/navigators/visitors/AronDataVisitor.cpp
rename to source/RobotAPI/libraries/aron/aroncore/navigators/visitors/DataVisitor.cpp
index 42f8912de06188a929790d310069f16bb62cc8eb..4715af4f46adba0d69ee0f1b7212930a21d3c866 100644
--- a/source/RobotAPI/libraries/aron/aroncore/navigators/visitors/AronDataVisitor.cpp
+++ b/source/RobotAPI/libraries/aron/aroncore/navigators/visitors/DataVisitor.cpp
@@ -1,4 +1,4 @@
-#include "AronDataVisitor.h"
+#include "DataVisitor.h"
 
 #include <SimoxUtility/meta/type_name.h>
 
@@ -9,27 +9,27 @@ namespace armarx::aron::visitor
 {
 
 
-    AronDataVisitor::AronDataVisitor()
+    DataVisitor::DataVisitor()
     {
     }
 
-    AronDataVisitor::~AronDataVisitor()
+    DataVisitor::~DataVisitor()
     {
     }
 
 
-    bool AronDataVisitor::applyTo(data::AronDataPtr& data)
+    bool DataVisitor::applyTo(data::AronDataPtr& data)
     {
         ARMARX_CHECK_NOT_NULL(data);
-        return applyTo(*AronDataNavigator::FromAronData(data));
+        return applyTo(*DataNavigator::FromAronData(data));
     }
 
-    bool AronDataVisitor::applyTo(AronDataVisitor::AronDataNavigator& navigator)
+    bool DataVisitor::applyTo(DataVisitor::DataNavigator& navigator)
     {
         return this->applyTo("", navigator);
     }
 
-    bool AronDataVisitor::applyTo(const std::string& key, AronDataNavigator& navigator)
+    bool DataVisitor::applyTo(const std::string& key, DataNavigator& navigator)
     {
         auto handleCollection = [this, key](auto & n)
         {
@@ -48,11 +48,11 @@ namespace armarx::aron::visitor
             return true;
         };
 
-        if (auto n = dynamic_cast<AronDictDataNavigator*>(&navigator))
+        if (auto n = dynamic_cast<DictDataNavigator*>(&navigator))
         {
             return handleCollection(*n);
         }
-        else if (auto n = dynamic_cast<AronListDataNavigator*>(&navigator))
+        else if (auto n = dynamic_cast<ListDataNavigator*>(&navigator))
         {
             return handleCollection(*n);
         }
@@ -60,38 +60,38 @@ namespace armarx::aron::visitor
         ARMARX_CHECK_EQUAL(navigator.childrenSize(), 0)
                 << simox::meta::get_type_name(navigator);
 
-        if (auto n = dynamic_cast<AronBoolDataNavigator*>(&navigator))
+        if (auto n = dynamic_cast<BoolDataNavigator*>(&navigator))
         {
             return visit(key, *n);
         }
-        else if (auto n = dynamic_cast<AronDoubleDataNavigator*>(&navigator))
+        else if (auto n = dynamic_cast<DoubleDataNavigator*>(&navigator))
         {
             return visit(key, *n);
         }
-        else if (auto n = dynamic_cast<AronFloatDataNavigator*>(&navigator))
+        else if (auto n = dynamic_cast<FloatDataNavigator*>(&navigator))
         {
             return visit(key, *n);
         }
-        else if (auto n = dynamic_cast<AronIntDataNavigator*>(&navigator))
+        else if (auto n = dynamic_cast<IntDataNavigator*>(&navigator))
         {
             return visit(key, *n);
         }
-        else if (auto n = dynamic_cast<AronLongDataNavigator*>(&navigator))
+        else if (auto n = dynamic_cast<LongDataNavigator*>(&navigator))
         {
             return visit(key, *n);
         }
-        else if (auto n = dynamic_cast<AronNDArrayDataNavigator*>(&navigator))
+        else if (auto n = dynamic_cast<NDArrayDataNavigator*>(&navigator))
         {
             return visit(key, *n);
         }
-        else if (auto n = dynamic_cast<AronStringDataNavigator*>(&navigator))
+        else if (auto n = dynamic_cast<StringDataNavigator*>(&navigator))
         {
             return visit(key, *n);
         }
         ARMARX_CHECK(false) << "Unhandled AronDataNavigatorType '" << simox::meta::get_type_name(navigator) << "'.";
     }
 
-    bool AronDataVisitor::applyToChildren(AronDataVisitor::AronDictDataNavigator& navigator)
+    bool DataVisitor::applyToChildren(DictDataNavigator& navigator)
     {
         for (const std::string& key : navigator.getAllKeys())
         {
@@ -107,7 +107,7 @@ namespace armarx::aron::visitor
         return true;
     }
 
-    bool AronDataVisitor::applyToChildren(AronDataVisitor::AronListDataNavigator& navigator)
+    bool DataVisitor::applyToChildren(ListDataNavigator& navigator)
     {
         size_t i = 0;
         for (auto& child : navigator.getChildren())
diff --git a/source/RobotAPI/libraries/aron/aroncore/navigators/visitors/AronDataVisitor.h b/source/RobotAPI/libraries/aron/aroncore/navigators/visitors/DataVisitor.h
similarity index 54%
rename from source/RobotAPI/libraries/aron/aroncore/navigators/visitors/AronDataVisitor.h
rename to source/RobotAPI/libraries/aron/aroncore/navigators/visitors/DataVisitor.h
index ec5527e2e51ad23a040768943e000746ec651c9f..a3c37ac2d02fb5274bd65b0b42a39b1d6ee4b397 100644
--- a/source/RobotAPI/libraries/aron/aroncore/navigators/visitors/AronDataVisitor.h
+++ b/source/RobotAPI/libraries/aron/aroncore/navigators/visitors/DataVisitor.h
@@ -1,8 +1,8 @@
 #pragma once
 
-#include <optional>
+#include <string>
 
-#include "../datanavigator/AronAllDataNavigators.h"
+#include <RobotAPI/libraries/aron/aroncore/navigators/datanavigator/AronAllDataNavigators.h>
 
 
 namespace armarx::aron::visitor
@@ -34,148 +34,148 @@ namespace armarx::aron::visitor
      * @see  `aron::datanavigator::AronDataNavigator`
      * @see `std::stack` To manage data with stack semantics.
      */
-    class AronDataVisitor
+    class DataVisitor
     {
     public:
 
         // Define types to ease writing code in this and derived classes.
 
-        using AronDataNavigator = datanavigator::AronDataNavigator;
+        using DataNavigator = datanavigator::AronDataNavigator;
 
-        using AronDictDataNavigator = datanavigator::AronDictDataNavigator;
-        using AronListDataNavigator = datanavigator::AronListDataNavigator;
+        using DictDataNavigator = datanavigator::AronDictDataNavigator;
+        using ListDataNavigator = datanavigator::AronListDataNavigator;
 
-        using AronBoolDataNavigator = datanavigator::AronBoolDataNavigator;
-        using AronDoubleDataNavigator = datanavigator::AronDoubleDataNavigator;
-        using AronFloatDataNavigator = datanavigator::AronFloatDataNavigator;
-        using AronIntDataNavigator = datanavigator::AronIntDataNavigator;
-        using AronLongDataNavigator = datanavigator::AronLongDataNavigator;
-        using AronNDArrayDataNavigator = datanavigator::AronNDArrayDataNavigator;
-        using AronStringDataNavigator = datanavigator::AronStringDataNavigator;
+        using BoolDataNavigator = datanavigator::AronBoolDataNavigator;
+        using DoubleDataNavigator = datanavigator::AronDoubleDataNavigator;
+        using FloatDataNavigator = datanavigator::AronFloatDataNavigator;
+        using IntDataNavigator = datanavigator::AronIntDataNavigator;
+        using LongDataNavigator = datanavigator::AronLongDataNavigator;
+        using NDArrayDataNavigator = datanavigator::AronNDArrayDataNavigator;
+        using StringDataNavigator = datanavigator::AronStringDataNavigator;
 
 
     public:
 
-        AronDataVisitor();
-        virtual ~AronDataVisitor();
+        DataVisitor();
+        virtual ~DataVisitor();
 
 
         bool applyTo(data::AronDataPtr& aronData);
-        bool applyTo(AronDataNavigator& navigator);
-        bool applyTo(const std::string& key, AronDataNavigator& navigator);
+        bool applyTo(DataNavigator& navigator);
+        bool applyTo(const std::string& key, DataNavigator& navigator);
 
 
 
-        virtual bool visitEnter(AronDictDataNavigator& dict)
+        virtual bool visitEnter(DictDataNavigator& dict)
         {
             (void) dict;
             return true;
         }
-        virtual bool visitExit(AronDictDataNavigator& dict)
+        virtual bool visitExit(DictDataNavigator& dict)
         {
             (void) dict;
             return true;
         }
-        virtual bool visitEnter(AronListDataNavigator& list)
+        virtual bool visitEnter(ListDataNavigator& list)
         {
             (void) list;
             return true;
         }
-        virtual bool visitExit(AronListDataNavigator& list)
+        virtual bool visitExit(ListDataNavigator& list)
         {
             (void) list;
             return true;
         }
 
-        virtual bool visit(AronBoolDataNavigator& b)
+        virtual bool visit(BoolDataNavigator& b)
         {
             (void) b;
             return true;
         }
-        virtual bool visit(AronDoubleDataNavigator& d)
+        virtual bool visit(DoubleDataNavigator& d)
         {
             (void) d;
             return true;
         }
-        virtual bool visit(AronFloatDataNavigator& f)
+        virtual bool visit(FloatDataNavigator& f)
         {
             (void) f;
             return true;
         }
-        virtual bool visit(AronIntDataNavigator& i)
+        virtual bool visit(IntDataNavigator& i)
         {
             (void) i;
             return true;
         }
-        virtual bool visit(AronLongDataNavigator& l)
+        virtual bool visit(LongDataNavigator& l)
         {
             (void) l;
             return true;
         }
-        virtual bool visit(AronNDArrayDataNavigator& array)
+        virtual bool visit(NDArrayDataNavigator& array)
         {
             (void) array;
             return true;
         }
-        virtual bool visit(AronStringDataNavigator& string)
+        virtual bool visit(StringDataNavigator& string)
         {
             (void) string;
             return true;
         }
 
 
-        virtual bool visitEnter(const std::string& key, AronDictDataNavigator& dict)
+        virtual bool visitEnter(const std::string& key, DictDataNavigator& dict)
         {
             (void) key;
             return visitEnter(dict);
         }
-        virtual bool visitExit(const std::string& key, AronDictDataNavigator& dict)
+        virtual bool visitExit(const std::string& key, DictDataNavigator& dict)
         {
             (void) key;
             return visitExit(dict);
         }
-        virtual bool visitEnter(const std::string& key, AronListDataNavigator& list)
+        virtual bool visitEnter(const std::string& key, ListDataNavigator& list)
         {
             (void) key;
             return visitEnter(list);
         }
-        virtual bool visitExit(const std::string& key, AronListDataNavigator& list)
+        virtual bool visitExit(const std::string& key, ListDataNavigator& list)
         {
             (void) key;
             return visitExit(list);
         }
 
-        virtual bool visit(const std::string& key, AronBoolDataNavigator& b)
+        virtual bool visit(const std::string& key, BoolDataNavigator& b)
         {
             (void) key;
             return visit(b);
         }
-        virtual bool visit(const std::string& key, AronDoubleDataNavigator& d)
+        virtual bool visit(const std::string& key, DoubleDataNavigator& d)
         {
             (void) key;
             return visit(d);
         }
-        virtual bool visit(const std::string& key, AronFloatDataNavigator& f)
+        virtual bool visit(const std::string& key, FloatDataNavigator& f)
         {
             (void) key;
             return visit(f);
         }
-        virtual bool visit(const std::string& key, AronIntDataNavigator& i)
+        virtual bool visit(const std::string& key, IntDataNavigator& i)
         {
             (void) key;
             return visit(i);
         }
-        virtual bool visit(const std::string& key, AronLongDataNavigator& l)
+        virtual bool visit(const std::string& key, LongDataNavigator& l)
         {
             (void) key;
             return visit(l);
         }
-        virtual bool visit(const std::string& key, AronNDArrayDataNavigator& array)
+        virtual bool visit(const std::string& key, NDArrayDataNavigator& array)
         {
             (void) key;
             return visit(array);
         }
-        virtual bool visit(const std::string& key, AronStringDataNavigator& string)
+        virtual bool visit(const std::string& key, StringDataNavigator& string)
         {
             (void) key;
             return visit(string);
@@ -184,8 +184,8 @@ namespace armarx::aron::visitor
 
     private:
 
-        bool applyToChildren(AronDictDataNavigator& navigator);
-        bool applyToChildren(AronListDataNavigator& navigator);
+        bool applyToChildren(DictDataNavigator& navigator);
+        bool applyToChildren(ListDataNavigator& navigator);
 
     };
 
@@ -203,58 +203,58 @@ namespace armarx::aron::visitor
 struct MyDerivedAronDataVisitor : public armarx::aron::visitor::AronDataVisitor
 {
 
-    bool visitEnter(AronDictDataNavigator& dict) override
+    bool visitEnter(DictDataNavigator& dict) override
     {
         (void) dict;
         return true;
     }
-    bool visitExit(AronDictDataNavigator& dict) override
+    bool visitExit(DictDataNavigator& dict) override
     {
         (void) dict;
         return true;
     }
-    bool visitEnter(AronListDataNavigator& list) override
+    bool visitEnter(ListDataNavigator& list) override
     {
         (void) list;
         return true;
     }
-    bool visitExit(AronListDataNavigator& list) override
+    bool visitExit(ListDataNavigator& list) override
     {
         (void) list;
         return true;
     }
 
-    bool visit(AronBoolDataNavigator& b) override
+    bool visit(BoolDataNavigator& b) override
     {
         (void) b;
         return true;
     }
-    bool visit(AronDoubleDataNavigator& d) override
+    bool visit(DoubleDataNavigator& d) override
     {
         (void) d;
         return true;
     }
-    bool visit(AronFloatDataNavigator& f) override
+    bool visit(FloatDataNavigator& f) override
     {
         (void) f;
         return true;
     }
-    bool visit(AronIntDataNavigator& i) override
+    bool visit(IntDataNavigator& i) override
     {
         (void) i;
         return true;
     }
-    bool visit(AronLongDataNavigator& l) override
+    bool visit(LongDataNavigator& l) override
     {
         (void) l;
         return true;
     }
-    bool visit(AronNDArrayDataNavigator& array) override
+    bool visit(NDArrayDataNavigator& array) override
     {
         (void) array;
         return true;
     }
-    bool visit(AronStringDataNavigator& string) override
+    bool visit(StringDataNavigator& string) override
     {
         (void) string;
         return true;
diff --git a/source/RobotAPI/libraries/aron/aroncore/navigators/visitors/TypedDataVisitor.cpp b/source/RobotAPI/libraries/aron/aroncore/navigators/visitors/TypedDataVisitor.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..7936152be03cd09575812d80a48e3fd5eb18a24c
--- /dev/null
+++ b/source/RobotAPI/libraries/aron/aroncore/navigators/visitors/TypedDataVisitor.cpp
@@ -0,0 +1,182 @@
+#include "TypedDataVisitor.h"
+
+#include <SimoxUtility/meta/type_name.h>
+
+#include <ArmarXCore/core/exceptions/local/ExpressionException.h>
+
+
+namespace armarx::aron::visitor
+{
+
+
+    TypedDataVisitor::TypedDataVisitor()
+    {
+    }
+
+    TypedDataVisitor::~TypedDataVisitor()
+    {
+    }
+
+    bool TypedDataVisitor::applyTo(TypeNavigator& type, DataNavigator& data)
+    {
+        return this->applyTo("", type, data);
+    }
+
+    template <class DataT, class TypeT>
+    bool TypedDataVisitor::applyToCollection(TypeT& type, const std::string& key, DataNavigator& data)
+    {
+        DataT& dataCast = dynamic_cast<DataT&>(data);
+        if (!visitEnter(type, key, dataCast))
+        {
+            return false;
+        }
+        if (!applyToChildren(type, dataCast))
+        {
+            return false;
+        }
+        if (!visitExit(type, key, dataCast))
+        {
+            return false;
+        }
+        return true;
+    }
+
+    bool TypedDataVisitor::applyTo(const std::string& key, TypeNavigator& type, DataNavigator& data)
+    {
+        if (auto t = dynamic_cast<ObjectTypeNavigator*>(&type))
+        {
+            return applyToCollection<DictDataNavigator>(*t, key, data);
+        }
+        else if (auto t = dynamic_cast<DictTypeNavigator*>(&type))
+        {
+            return applyToCollection<DictDataNavigator>(*t, key, data);
+        }
+        else if (auto t = dynamic_cast<ListTypeNavigator*>(&type))
+        {
+            return applyToCollection<ListDataNavigator>(*t, key, data);
+        }
+        else if (auto t = dynamic_cast<TupleTypeNavigator*>(&type))
+        {
+            return applyToCollection<ListDataNavigator>(*t, key, data);
+        }
+
+        ARMARX_CHECK_EQUAL(type.childrenSize(), 0) << simox::meta::get_type_name(type);
+        ARMARX_CHECK_EQUAL(data.childrenSize(), 0) << simox::meta::get_type_name(data);
+
+        if (auto t = dynamic_cast<BoolTypeNavigator*>(&type))
+        {
+            return visit(*t, key, dynamic_cast<BoolDataNavigator&>(data));
+        }
+        else if (auto t = dynamic_cast<DoubleTypeNavigator*>(&type))
+        {
+            return visit(*t, key, dynamic_cast<DoubleDataNavigator&>(data));
+        }
+        else if (auto t = dynamic_cast<FloatTypeNavigator*>(&type))
+        {
+            return visit(*t, key, dynamic_cast<FloatDataNavigator&>(data));
+        }
+        else if (auto t = dynamic_cast<IntTypeNavigator*>(&type))
+        {
+            return visit(*t, key, dynamic_cast<IntDataNavigator&>(data));
+        }
+        else if (auto t = dynamic_cast<LongTypeNavigator*>(&type))
+        {
+            return visit(*t, key, dynamic_cast<LongDataNavigator&>(data));
+        }
+        else if (auto t = dynamic_cast<StringTypeNavigator*>(&type))
+        {
+            return visit(*t, key, dynamic_cast<StringDataNavigator&>(data));
+        }
+
+        if (auto t = dynamic_cast<EigenMatrixTypeNavigator*>(&type))
+        {
+            return visit(*t, key, dynamic_cast<NDArrayDataNavigator&>(data));
+        }
+        else if (auto t = dynamic_cast<IVTCByteImageTypeNavigator*>(&type))
+        {
+            return visit(*t, key, dynamic_cast<NDArrayDataNavigator&>(data));
+        }
+        else if (auto t = dynamic_cast<OpenCVMatTypeNavigator*>(&type))
+        {
+            return visit(*t, key, dynamic_cast<NDArrayDataNavigator&>(data));
+        }
+        else if (auto t = dynamic_cast<PCLPointCloudTypeNavigator*>(&type))
+        {
+            return visit(*t, key, dynamic_cast<NDArrayDataNavigator&>(data));
+        }
+
+        ARMARX_CHECK(false) << "Unhandled AronTypeNavigatorType '" << simox::meta::get_type_name(type) << "'."
+                            << "\n(Data: '" << simox::meta::get_type_name(data) << "')";
+    }
+
+    bool TypedDataVisitor::applyToChildren(ObjectTypeNavigator& type, DictDataNavigator& data)
+    {
+        for (const std::string& key : type.getAllKeys())
+        {
+            TypeNavigator::PointerType childType = type.getAcceptedType(key);
+            DataNavigator::PointerType childData = data.getElement(key);
+            if (childType && childData)
+            {
+                if (!applyTo(key, *childType, *childData))
+                {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    bool TypedDataVisitor::applyToChildren(DictTypeNavigator& type, DictDataNavigator& data)
+    {
+        TypeNavigator::PointerType childType = type.getAcceptedType();
+        for (const std::string& key : data.getAllKeys())
+        {
+            DataNavigator::PointerType childData = data.getElement(key);
+            if (childType && childData)
+            {
+                if (!applyTo(key, *childType, *childData))
+                {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    bool TypedDataVisitor::applyToChildren(ListTypeNavigator& type, ListDataNavigator& data)
+    {
+        TypeNavigator::PointerType childType = type.getAcceptedType();
+        size_t i = 0;
+        for (const DataNavigator::PointerType& childData : data.getElements())
+        {
+            if (childType && childData)
+            {
+                if (!applyTo(std::to_string(i), *childType, *childData))
+                {
+                    return false;
+                }
+            }
+            ++i;
+        }
+        return true;
+    }
+
+    bool TypedDataVisitor::applyToChildren(TupleTypeNavigator& type, ListDataNavigator& data)
+    {
+        unsigned int i = 0;
+        for (const TypeNavigator::PointerType& childType : type.getAcceptedTypes())
+        {
+            DataNavigator::PointerType childData = data.getElement(i);
+            if (childType && childData)
+            {
+                if (!applyTo(std::to_string(i), *childType, *childData))
+                {
+                    return false;
+                }
+            }
+            ++i;
+        }
+        return true;
+    }
+
+}
diff --git a/source/RobotAPI/libraries/aron/aroncore/navigators/visitors/TypedDataVisitor.h b/source/RobotAPI/libraries/aron/aroncore/navigators/visitors/TypedDataVisitor.h
new file mode 100644
index 0000000000000000000000000000000000000000..ac67b9fbde35432be646b824eccd34c89de7feac
--- /dev/null
+++ b/source/RobotAPI/libraries/aron/aroncore/navigators/visitors/TypedDataVisitor.h
@@ -0,0 +1,397 @@
+#pragma once
+
+#include <RobotAPI/libraries/aron/aroncore/navigators/datanavigator/AronAllDataNavigators.h>
+#include <RobotAPI/libraries/aron/aroncore/navigators/typenavigator/AronAllTypeNavigators.h>
+
+
+namespace armarx::aron::visitor
+{
+
+    /**
+     * @brief A visitor traversing an `aron::Type::AronTypePtr` using
+     * `aron::Typenavigator::AronTypeNavigator`s, taking care of type checking,
+     * casting and hierarchical traversal.
+     *
+     * To use it, create a class deriving from `AronTypeVisitor` and
+     * override the overloads of `visitEnter()`, `visitExit()` and `visit()`
+     * for the types you would like to handle (see blow for a copy-and-paste
+     * example).
+     * Then, instantiate your derived visitor and call `applyTo()`, passing
+     * the `AronTypePtr` or the root `AronTypeNavigator`.
+     *
+     * For dicts and lists, you will get a `visitEnter()`/`visitExit()` pair.
+     * For types without children (e.g. primitive types), you get a single
+     * `visit()` call.
+     *
+     * Each visit function should return true to continue traversal or
+     * false to stop it. All default implementations return true.
+     *
+     * To the the location of the passed navigator in the original `AronType`,
+     * use `navigator.getPath()`.
+     *
+     * @see  `aron::Type::AronTypePtr`
+     * @see  `aron::Typenavigator::AronTypeNavigator`
+     * @see `std::stack` To manage Type with stack semantics.
+     */
+    class TypedDataVisitor
+    {
+    public:
+
+        // Define types to ease writing code in this and derived classes.
+
+        // Data - possible data representations
+        using DataNavigator = datanavigator::AronDataNavigator;
+
+        using DictDataNavigator = datanavigator::AronDictDataNavigator;
+        using ListDataNavigator = datanavigator::AronListDataNavigator;
+
+        using BoolDataNavigator = datanavigator::AronBoolDataNavigator;
+        using DoubleDataNavigator = datanavigator::AronDoubleDataNavigator;
+        using FloatDataNavigator = datanavigator::AronFloatDataNavigator;
+        using IntDataNavigator = datanavigator::AronIntDataNavigator;
+        using LongDataNavigator = datanavigator::AronLongDataNavigator;
+        using StringDataNavigator = datanavigator::AronStringDataNavigator;
+
+        using NDArrayDataNavigator = datanavigator::AronNDArrayDataNavigator;
+
+
+        // Type
+        using TypeNavigator = typenavigator::AronTypeNavigator;
+
+        // Dict-valued
+        using DictTypeNavigator = typenavigator::AronDictTypeNavigator;
+        using ObjectTypeNavigator = typenavigator::AronObjectTypeNavigator;
+
+        // List-valued
+        using ListTypeNavigator = typenavigator::AronListTypeNavigator;
+        using TupleTypeNavigator = typenavigator::AronTupleTypeNavigator;
+
+        // Primitive-valued
+        using BoolTypeNavigator = typenavigator::AronBoolTypeNavigator;
+        using DoubleTypeNavigator = typenavigator::AronDoubleTypeNavigator;
+        using FloatTypeNavigator = typenavigator::AronFloatTypeNavigator;
+        using IntTypeNavigator = typenavigator::AronIntTypeNavigator;
+        using LongTypeNavigator = typenavigator::AronLongTypeNavigator;
+        using StringTypeNavigator = typenavigator::AronStringTypeNavigator;
+
+        // Array-valued
+        using EigenMatrixTypeNavigator = typenavigator::AronEigenMatrixTypeNavigator;
+        using IVTCByteImageTypeNavigator = typenavigator::AronIVTCByteImageTypeNavigator;
+        using OpenCVMatTypeNavigator = typenavigator::AronOpenCVMatTypeNavigator;
+        using PCLPointCloudTypeNavigator = typenavigator::AronPCLPointCloudTypeNavigator;
+
+
+    public:
+
+        TypedDataVisitor();
+        virtual ~TypedDataVisitor();
+
+
+        bool applyTo(TypeNavigator& type, DataNavigator& data);
+        bool applyTo(const std::string& key, TypeNavigator& type, DataNavigator& data);
+
+
+        virtual bool visitEnter(DictTypeNavigator& type, DictDataNavigator& data)
+        {
+            (void) type, (void) data;
+            return true;
+        }
+        virtual bool visitExit(DictTypeNavigator& type, DictDataNavigator& data)
+        {
+            (void) type, (void) data;
+            return true;
+        }
+
+        virtual bool visitEnter(ObjectTypeNavigator& type, DictDataNavigator& data)
+        {
+            (void) type, (void) data;
+            return true;
+        }
+        virtual bool visitExit(ObjectTypeNavigator& type, DictDataNavigator& data)
+        {
+            (void) type, (void) data;
+            return true;
+        }
+
+        virtual bool visitEnter(ListTypeNavigator& type, ListDataNavigator& data)
+        {
+            (void) type, (void) data;
+            return true;
+        }
+        virtual bool visitExit(ListTypeNavigator& type, ListDataNavigator& data)
+        {
+            (void) type, (void) data;
+            return true;
+        }
+
+        virtual bool visitEnter(TupleTypeNavigator& type, ListDataNavigator& data)
+        {
+            (void) type, (void) data;
+            return true;
+        }
+        virtual bool visitExit(TupleTypeNavigator& type, ListDataNavigator& data)
+        {
+            (void) type, (void) data;
+            return true;
+        }
+
+
+        virtual bool visit(BoolTypeNavigator& type, BoolDataNavigator& data)
+        {
+            (void) type, (void) data;
+            return true;
+        }
+        virtual bool visit(DoubleTypeNavigator& type, DoubleDataNavigator& data)
+        {
+            (void) type, (void) data;
+            return true;
+        }
+        virtual bool visit(FloatTypeNavigator& type, FloatDataNavigator& data)
+        {
+            (void) type, (void) data;
+            return true;
+        }
+        virtual bool visit(IntTypeNavigator& type, IntDataNavigator& data)
+        {
+            (void) type, (void) data;
+            return true;
+        }
+        virtual bool visit(LongTypeNavigator& type, LongDataNavigator& data)
+        {
+            (void) type, (void) data;
+            return true;
+        }
+        virtual bool visit(StringTypeNavigator& type, StringDataNavigator& data)
+        {
+            (void) type, (void) data;
+            return true;
+        }
+
+
+        virtual bool visit(EigenMatrixTypeNavigator& type, NDArrayDataNavigator& data)
+        {
+            (void) type, (void) type, (void) data;
+            return true;
+        }
+        virtual bool visit(IVTCByteImageTypeNavigator& type, NDArrayDataNavigator& data)
+        {
+            (void) type, (void) type, (void) data;
+            return true;
+        }
+        virtual bool visit(OpenCVMatTypeNavigator& type, NDArrayDataNavigator& data)
+        {
+            (void) type, (void) type, (void) data;
+            return true;
+        }
+        virtual bool visit(PCLPointCloudTypeNavigator& type, NDArrayDataNavigator& data)
+        {
+            (void) type, (void) type, (void) data;
+            return true;
+        }
+
+
+
+        virtual bool visitEnter(DictTypeNavigator& type, const std::string& key, DictDataNavigator& data)
+        {
+            (void) key;
+            visitEnter(type, data);
+            return true;
+        }
+        virtual bool visitExit(DictTypeNavigator& type, const std::string& key, DictDataNavigator& data)
+        {
+            (void) key;
+            visitExit(type, data);
+            return true;
+        }
+
+        virtual bool visitEnter(ObjectTypeNavigator& type, const std::string& key, DictDataNavigator& data)
+        {
+            (void) key;
+            visitEnter(type, data);
+            return true;
+        }
+        virtual bool visitExit(ObjectTypeNavigator& type, const std::string& key, DictDataNavigator& data)
+        {
+            (void) key;
+            visitExit(type, data);
+            return true;
+        }
+
+        virtual bool visitEnter(ListTypeNavigator& type, const std::string& key, ListDataNavigator& data)
+        {
+            (void) key;
+            visitEnter(type, data);
+            return true;
+        }
+        virtual bool visitExit(ListTypeNavigator& type, const std::string& key, ListDataNavigator& data)
+        {
+            (void) key;
+            visitExit(type, data);
+            return true;
+        }
+
+        virtual bool visitEnter(TupleTypeNavigator& type, const std::string& key, ListDataNavigator& data)
+        {
+            (void) key;
+            visitEnter(type, data);
+            return true;
+        }
+        virtual bool visitExit(TupleTypeNavigator& type, const std::string& key, ListDataNavigator& data)
+        {
+            (void) key;
+            visitExit(type, data);
+            return true;
+        }
+
+
+        virtual bool visit(BoolTypeNavigator& type, const std::string& key, BoolDataNavigator& data)
+        {
+            (void) key;
+            visit(type, data);
+            return true;
+        }
+        virtual bool visit(DoubleTypeNavigator& type, const std::string& key, DoubleDataNavigator& data)
+        {
+            (void) key;
+            visit(type, data);
+            return true;
+        }
+        virtual bool visit(FloatTypeNavigator& type, const std::string& key, FloatDataNavigator& data)
+        {
+            (void) key;
+            visit(type, data);
+            return true;
+        }
+        virtual bool visit(IntTypeNavigator& type, const std::string& key, IntDataNavigator& data)
+        {
+            (void) key;
+            visit(type, data);
+            return true;
+        }
+        virtual bool visit(LongTypeNavigator& type, const std::string& key, LongDataNavigator& data)
+        {
+            (void) key;
+            visit(type, data);
+            return true;
+        }
+        virtual bool visit(StringTypeNavigator& type, const std::string& key, StringDataNavigator& data)
+        {
+            (void) key;
+            visit(type, data);
+            return true;
+        }
+
+
+        virtual bool visit(EigenMatrixTypeNavigator& type, const std::string& key, NDArrayDataNavigator& data)
+        {
+            (void) type, (void) key;
+            visit(type, data);
+            return true;
+        }
+        virtual bool visit(IVTCByteImageTypeNavigator& type, const std::string& key, NDArrayDataNavigator& data)
+        {
+            (void) type, (void) key;
+            visit(type, data);
+            return true;
+        }
+        virtual bool visit(OpenCVMatTypeNavigator& type, const std::string& key, NDArrayDataNavigator& data)
+        {
+            (void) type, (void) key;
+            visit(type, data);
+            return true;
+        }
+        virtual bool visit(PCLPointCloudTypeNavigator& type, const std::string& key, NDArrayDataNavigator& data)
+        {
+            (void) type, (void) key;
+            visit(type, data);
+            return true;
+        }
+
+
+
+    private:
+
+        template <class DataT, class TypeT>
+        bool applyToCollection(TypeT& type, const std::string& key, DataNavigator& data);
+
+        bool applyToChildren(ObjectTypeNavigator& type, DictDataNavigator& data);
+        bool applyToChildren(DictTypeNavigator& type, DictDataNavigator& data);
+        bool applyToChildren(ListTypeNavigator& type, ListDataNavigator& data);
+        bool applyToChildren(TupleTypeNavigator& type, ListDataNavigator& data);
+
+    };
+
+}
+
+
+/* Copy-and-paste example below.
+ * Remove functions you don't need.
+ * Add `const std::string& key, ` to parameter list if you need an items's key
+ * in the parent container.
+ */
+
+#if 0
+
+struct MyDerivedAronTypeVisitor : public armarx::aron::visitor::AronTypeVisitor
+{
+
+    bool visitEnter(DictTypeNavigator& dict) override
+    {
+        (void) dict;
+        return true;
+    }
+    bool visitExit(DictTypeNavigator& dict) override
+    {
+        (void) dict;
+        return true;
+    }
+    bool visitEnter(ListTypeNavigator& list) override
+    {
+        (void) list;
+        return true;
+    }
+    bool visitExit(ListTypeNavigator& list) override
+    {
+        (void) list;
+        return true;
+    }
+
+    bool visit(BoolTypeNavigator& b) override
+    {
+        (void) b;
+        return true;
+    }
+    bool visit(DoubleTypeNavigator& d) override
+    {
+        (void) d;
+        return true;
+    }
+    bool visit(FloatTypeNavigator& f) override
+    {
+        (void) f;
+        return true;
+    }
+    bool visit(IntTypeNavigator& i) override
+    {
+        (void) i;
+        return true;
+    }
+    bool visit(LongTypeNavigator& l) override
+    {
+        (void) l;
+        return true;
+    }
+    bool visit(NDArrayTypeNavigator& array) override
+    {
+        (void) array;
+        return true;
+    }
+    bool visit(StringTypeNavigator& string) override
+    {
+        (void) string;
+        return true;
+    }
+
+};
+
+#endif
diff --git a/source/RobotAPI/libraries/core/remoterobot/RobotStateObserver.cpp b/source/RobotAPI/libraries/core/remoterobot/RobotStateObserver.cpp
index 08fbb612d15a9734c86d1043aee74088a330171a..9f2dc660d9945879bf66c7d5d37e9d15a0865926 100644
--- a/source/RobotAPI/libraries/core/remoterobot/RobotStateObserver.cpp
+++ b/source/RobotAPI/libraries/core/remoterobot/RobotStateObserver.cpp
@@ -168,9 +168,15 @@ void RobotStateObserver::udpatePoseDatafields(const FramedPoseBaseMap& poseMap)
     }
 }
 
-DatafieldRefBasePtr RobotStateObserver::getPoseDatafield(const std::string& nodeName, const Ice::Current&) const
+void RobotStateObserver::getPoseDatafield_async(
+    const AMD_RobotStateObserverInterface_getPoseDatafieldPtr& amd,
+    const std::string& nodeName,
+    const Ice::Current&) const
 {
-    return getDatafieldRefByName(TCP_POSE_CHANNEL, nodeName);
+    addWorkerJob("RobotStateObserver::getPoseDatafield", [this, amd, nodeName]
+    {
+        return getDatafieldRefByName(TCP_POSE_CHANNEL, nodeName);
+    });
 }
 
 void RobotStateObserver::updateNodeVelocities(const NameValueMap& jointVel, long timestampMicroSeconds)
diff --git a/source/RobotAPI/libraries/core/remoterobot/RobotStateObserver.h b/source/RobotAPI/libraries/core/remoterobot/RobotStateObserver.h
index e3acfd611dc6487744decc1c4d3183e33f74c383..8f0899834450db1b5674bdebf0bfa2443ab4de8e 100644
--- a/source/RobotAPI/libraries/core/remoterobot/RobotStateObserver.h
+++ b/source/RobotAPI/libraries/core/remoterobot/RobotStateObserver.h
@@ -99,7 +99,10 @@ namespace armarx
 
         // RobotStateObserverInterface interface
     public:
-        DatafieldRefBasePtr getPoseDatafield(const std::string& nodeName, const Ice::Current&) const override;
+        void getPoseDatafield_async(
+            const AMD_RobotStateObserverInterface_getPoseDatafieldPtr& amd,
+            const std::string& nodeName,
+            const Ice::Current&) const override;
     };
 
     using RobotStateObserverPtr = IceInternal::Handle<RobotStateObserver>;