diff --git a/source/RobotAPI/components/ArViz/Coin/VisualizationArrowCircle.h b/source/RobotAPI/components/ArViz/Coin/VisualizationArrowCircle.h
index 87fd71f938e32f0324c8dd3f3c9fadfd60892235..179864cc951672758ad36351829e97105d9452e9 100644
--- a/source/RobotAPI/components/ArViz/Coin/VisualizationArrowCircle.h
+++ b/source/RobotAPI/components/ArViz/Coin/VisualizationArrowCircle.h
@@ -3,13 +3,15 @@
 #include "ElementVisualizer.h"
 
 #include <RobotAPI/interface/ArViz/Elements.h>
+
 #include <Inventor/nodes/SoCone.h>
+#include <Inventor/nodes/SoCoordinate3.h>
 #include <Inventor/nodes/SoCylinder.h>
+#include <Inventor/nodes/SoIndexedFaceSet.h>
+#include <Inventor/nodes/SoShapeHints.h>
 #include <Inventor/nodes/SoSphere.h>
 #include <Inventor/nodes/SoTranslation.h>
 
-#include <VirtualRobot/Visualization/CoinVisualization/CoinVisualizationFactory.h>
-#include <VirtualRobot/Visualization/CoinVisualization/CoinVisualizationNode.h>
 
 namespace armarx::viz::coin
 {
@@ -17,50 +19,172 @@ namespace armarx::viz::coin
     {
         using ElementType = data::ElementArrowCircle;
 
-        bool update(ElementType const& element)
+        SoCoordinate3* coords;
+        SoIndexedFaceSet* torusFaceSet;
+        SoSeparator* torus;
+        SoSeparator* coneSep;
+        SoTransform* coneTransform;
+        SoTransform* coneSignRotation;
+        SoCone* cone;
+
+        std::vector<SbVec3f> vertexPositions;
+        std::vector<int32_t> faces;
+        std::vector<int32_t> matInx;
+
+        static const int RINGS = 32;
+        static const int SIDES = 8;
+
+        VisualizationArrowCircle()
         {
-            int rings = 32;
+            SoMaterialBinding* torusBinding = new SoMaterialBinding;
+            torusBinding->value = SoMaterialBinding::PER_VERTEX_INDEXED;
+
+            coords = new SoCoordinate3;
 
+            SoShapeHints* torusHints = new SoShapeHints;
+            // Disable back culling and enable two-sided lighting
+            torusHints->vertexOrdering = SoShapeHints::VertexOrdering::COUNTERCLOCKWISE;
+            torusHints->shapeType = SoShapeHints::ShapeType::UNKNOWN_SHAPE_TYPE;
+
+            torusFaceSet = new SoIndexedFaceSet();
+            torus = new SoSeparator;
+
+            torus->addChild(torusBinding);
+            torus->addChild(coords);
+            torus->addChild(torusHints);
+            torus->addChild(torusFaceSet);
+
+            coneSep = new SoSeparator();
+            coneTransform = new SoTransform;
+
+            node->addChild(torus);
+            node->addChild(coneSep);
+
+            coneSignRotation = new SoTransform;
+            cone = new SoCone;
+
+            coneSep->addChild(coneTransform);
+            coneSep->addChild(coneSignRotation);
+            coneSep->addChild(cone);
+
+            int numVerticesPerRow = SIDES + 1;
+            int numVerticesPerColumn = RINGS + 1;
+            vertexPositions.resize(numVerticesPerRow * numVerticesPerColumn);
+
+            int numFaces = RINGS * SIDES * 2;
+            faces.resize(numFaces * 4);
+            matInx.resize(numFaces * 4);
+        }
+
+        bool update(ElementType const& element)
+        {
             float completion = std::min<float>(1.0f, std::max(-1.0f, element.completion));
             int sign = completion >= 0 ? 1 : -1;
-            float torusCompletion = completion - 1.0f / rings * sign;
+            float torusCompletion = completion - 1.0f / RINGS * sign;
             if (torusCompletion * sign < 0)
             {
                 torusCompletion = 0;
             }
-            auto color = element.color;
-            const float conv = 1.0f / 255.0f;
-            float r = color.r * conv;
-            float g = color.g * conv;
-            float b = color.b * conv;
-            float a = color.a * conv;
 
-            auto torusNode = VirtualRobot::CoinVisualizationFactory().createTorus(
-                                 element.radius, element.width, torusCompletion,
-                                 r, g, b, 1.0f - a,
-                                 8, rings);
-            SoNode* torus = dynamic_cast<VirtualRobot::CoinVisualizationNode&>(*torusNode).getCoinVisualization();
+            const float TWO_PI = 2.0f * (float)M_PI;
 
+            {
+                // Create a torus mesh (for the completion circle
+                float radius = element.radius;
+                float tubeRadius = element.width;
+                float completion = torusCompletion;
 
-            float angle0 = (float)(rings - 2) / rings * 2 * M_PI * completion;
-            float x0 = element.radius * cos(angle0);
-            float y0 = element.radius * sin(angle0);
-            float angle1 = (float)(rings - 1) / rings * 2 * M_PI * completion;
+                int numVerticesPerRow = SIDES + 1;
+                int numVerticesPerColumn = RINGS + 1;
 
-            SoSeparator* subSep = new SoSeparator();
-            SoTransform* tr = new SoTransform;
-            tr->translation.setValue(x0, y0, 0);
 
-            tr->rotation.setValue(SbVec3f(0, 0, 1), angle1);
-            subSep->addChild(tr);
+                float theta = 0.0f;
+                float phi = 0.0f;
+                float verticalAngularStride = TWO_PI / RINGS;
+                float horizontalAngularStride = TWO_PI / SIDES;
 
-            subSep->addChild(VirtualRobot::CoinVisualizationFactory::CreateArrow(
-                                 Eigen::Vector3f::UnitY()*sign, 0, element.width,
-                                 VirtualRobot::VisualizationFactory::Color(r, g, b, 1.0f - a)));
+                int numVertices = numVerticesPerColumn * numVerticesPerRow;
+                for (int verticalIt = 0; verticalIt < numVerticesPerColumn; verticalIt++)
+                {
+                    theta = verticalAngularStride * verticalIt * completion;
 
-            node->removeAllChildren();
-            node->addChild(torus);
-            node->addChild(subSep);
+                    for (int horizontalIt = 0; horizontalIt < numVerticesPerRow; horizontalIt++)
+                    {
+                        phi = horizontalAngularStride * horizontalIt;
+
+                        // position
+                        float x = std::cos(theta) * (radius + tubeRadius * std::cos(phi));
+                        float y = std::sin(theta) * (radius + tubeRadius * std::cos(phi));
+                        float z = tubeRadius * std::sin(phi);
+
+                        int vertexIndex = verticalIt * numVerticesPerRow + horizontalIt;
+                        vertexPositions[vertexIndex].setValue(x, y, z);
+                    }
+                }
+                coords->point.setValuesPointer(numVertices, vertexPositions.data());
+
+                for (int verticalIt = 0; verticalIt < RINGS; verticalIt++)
+                {
+                    for (int horizontalIt = 0; horizontalIt < SIDES; horizontalIt++)
+                    {
+                        int faceIndex = (verticalIt * SIDES + horizontalIt) * 2;
+
+                        short lt = (short)(horizontalIt + verticalIt * (numVerticesPerRow));
+                        short rt = (short)((horizontalIt + 1) + verticalIt * (numVerticesPerRow));
+
+                        short lb = (short)(horizontalIt + (verticalIt + 1) * (numVerticesPerRow));
+                        short rb = (short)((horizontalIt + 1) + (verticalIt + 1) * (numVerticesPerRow));
+
+
+                        faces[faceIndex * 4 + 0] = lt;
+                        faces[faceIndex * 4 + 1] = rt;
+                        faces[faceIndex * 4 + 2] = lb;
+                        faces[faceIndex * 4 + 3] = SO_END_FACE_INDEX;
+
+                        matInx[faceIndex * 4 + 0] = 0;
+                        matInx[faceIndex * 4 + 1] = 0;
+                        matInx[faceIndex * 4 + 2] = 0;
+                        matInx[faceIndex * 4 + 3] = SO_END_FACE_INDEX;
+
+                        faceIndex += 1;
+
+                        faces[faceIndex * 4 + 0] = rt;
+                        faces[faceIndex * 4 + 1] = rb;
+                        faces[faceIndex * 4 + 2] = lb;
+                        faces[faceIndex * 4 + 3] = SO_END_FACE_INDEX;
+
+                        matInx[faceIndex * 4 + 0] = 0;
+                        matInx[faceIndex * 4 + 1] = 0;
+                        matInx[faceIndex * 4 + 2] = 0;
+                        matInx[faceIndex * 4 + 3] = SO_END_FACE_INDEX;
+                    }
+                }
+
+                torusFaceSet->coordIndex.setValuesPointer(faces.size(), faces.data());
+                torusFaceSet->materialIndex.setValuesPointer(matInx.size(), matInx.data());
+            }
+
+            {
+                // Create a cone to make the arrow for the completion circle
+                float angle0 = (RINGS - 1.0f) / RINGS * TWO_PI * completion;
+                float x0 = element.radius * std::cos(angle0);
+                float y0 = element.radius * std::sin(angle0);
+                float angle1 = (RINGS - 0.5f) / RINGS * TWO_PI * completion;
+
+                coneTransform->translation.setValue(x0, y0, 0);
+
+                coneTransform->rotation.setValue(SbVec3f(0, 0, 1), angle1);
+
+                float coneHeight = element.width * 6.0f;
+                float coneBottomRadius = element.width * 2.5f;
+
+                SbVec3f axis(0.0f, 0.0f, 1.0f);
+                float angle = sign > 0.0f ? 0.0f : (float)M_PI;
+                coneSignRotation->rotation.setValue(axis, angle);
+
+                cone->bottomRadius.setValue(coneBottomRadius);
+                cone->height.setValue(coneHeight);
+            }
 
             return true;
         }
diff --git a/source/RobotAPI/components/ArViz/Coin/VisualizationMesh.h b/source/RobotAPI/components/ArViz/Coin/VisualizationMesh.h
index 785b27019532891f0f53ec97b10c3835c97c3cdf..120bb629a6ddb6008ebeb7780e31d4954441be4e 100644
--- a/source/RobotAPI/components/ArViz/Coin/VisualizationMesh.h
+++ b/source/RobotAPI/components/ArViz/Coin/VisualizationMesh.h
@@ -46,8 +46,7 @@ namespace armarx::viz::coin
             {
                 colorSize = 1;
             }
-            matAmb.resize(colorSize);
-            matDif.resize(colorSize);
+            matColor.resize(colorSize);
             transp.resize(colorSize);
 
             const float conv = 1.0f / 255.0f;
@@ -58,8 +57,7 @@ namespace armarx::viz::coin
                 float g = color.g * conv;
                 float b = color.b * conv;
                 float a = color.a * conv;
-                matAmb[0].setValue(r, g, b);
-                matDif[0].setValue(r, g, b);
+                matColor[0].setValue(r, g, b);
                 transp[0] = 1.0f - a;
             }
             else
@@ -71,15 +69,14 @@ namespace armarx::viz::coin
                     float g = color.g * conv;
                     float b = color.b * conv;
                     float a = color.a * conv;
-                    matAmb[i].setValue(r, g, b);
-                    matDif[i].setValue(r, g, b);
+                    matColor[i].setValue(r, g, b);
                     transp[i] = 1.0f - a;
                 }
             }
 
             // Define colors for the faces
-            materials->diffuseColor.setValuesPointer(colorSize, matDif.data());
-            materials->ambientColor.setValuesPointer(colorSize, matAmb.data());
+            materials->diffuseColor.setValuesPointer(colorSize, matColor.data());
+            materials->ambientColor.setValuesPointer(colorSize, matColor.data());
             materials->transparency.setValuesPointer(colorSize, transp.data());
 
             // define vertex array
@@ -123,8 +120,7 @@ namespace armarx::viz::coin
         SoCoordinate3* coords;
         SoIndexedFaceSet* faceSet;
 
-        std::vector<SbColor> matAmb;
-        std::vector<SbColor> matDif;
+        std::vector<SbColor> matColor;
         std::vector<float> transp;
         std::vector<SbVec3f> vertexPositions;
         std::vector<int32_t> faces;
diff --git a/source/RobotAPI/components/ArViz/Coin/Visualizer.cpp b/source/RobotAPI/components/ArViz/Coin/Visualizer.cpp
index ff525ff98eda9eb834dfabb2f6bdfcd42ddb019b..89c8340b7fd524b9d3df06bb4332e7e591701011 100644
--- a/source/RobotAPI/components/ArViz/Coin/Visualizer.cpp
+++ b/source/RobotAPI/components/ArViz/Coin/Visualizer.cpp
@@ -426,14 +426,14 @@ namespace armarx::viz
         }
     }
 
-    void CoinVisualizer::exportToVRML(const std::string& s)
+    void CoinVisualizer::exportToVRML(const std::string& exportFilePath)
     {
 
 
         SoOutput* so = new SoOutput();
-        if (!so->openFile(s.c_str()))
+        if (!so->openFile(exportFilePath.c_str()))
         {
-            ARMARX_ERROR << "Could not open file " << s << " for writing." << std::endl;
+            ARMARX_ERROR << "Could not open file " << exportFilePath << " for writing." << std::endl;
             return;
         }
 
diff --git a/source/RobotAPI/components/ArViz/Coin/Visualizer.h b/source/RobotAPI/components/ArViz/Coin/Visualizer.h
index e2d9a4634d5f1747174c125292a33233699dceda..01d7072ca3a59dc6b69fb6b5c0adf3e6f25b4ead 100644
--- a/source/RobotAPI/components/ArViz/Coin/Visualizer.h
+++ b/source/RobotAPI/components/ArViz/Coin/Visualizer.h
@@ -129,7 +129,7 @@ namespace armarx::viz
 
         void update();
 
-        void exportToVRML(const std::string& s);
+        void exportToVRML(std::string const& exportFilePath);
 
         template <typename ElementVisuT>
         void registerVisualizerFor()
diff --git a/source/RobotAPI/components/RobotState/RobotStateComponent.cpp b/source/RobotAPI/components/RobotState/RobotStateComponent.cpp
index 735aae1176215b9940b73afe01d5dcece4cfb363..6016f68207af9112ab5835774e786593a404e336 100644
--- a/source/RobotAPI/components/RobotState/RobotStateComponent.cpp
+++ b/source/RobotAPI/components/RobotState/RobotStateComponent.cpp
@@ -24,8 +24,6 @@
 
 #include "RobotStateComponent.h"
 
-#include <thread>
-
 #include <Ice/ObjectAdapter.h>
 
 #include <VirtualRobot/RobotNodeSet.h>
@@ -33,7 +31,6 @@
 #include <VirtualRobot/Nodes/RobotNode.h>
 #include <VirtualRobot/XML/RobotIO.h>
 
-#include <ArmarXCore/core/util/OnScopeExit.h>
 #include <ArmarXCore/core/ArmarXManager.h>
 #include <ArmarXCore/core/ArmarXObjectScheduler.h>
 #include <ArmarXCore/core/application/Application.h>
@@ -48,553 +45,23 @@ using namespace Eigen;
 using namespace Ice;
 using namespace VirtualRobot;
 
-namespace armarx::detail
+
+namespace armarx
 {
-    class RobotStateComponentWorker
+    RobotStateComponent::~RobotStateComponent()
     {
-    public:
-        struct Job
-        {
-            enum class JobType
-            {
-                none,
-                getSynchronizedRobot,
-                getRobotSnapshot,
-                getRobotSnapshotAtTimestamp,
-                getJointConfigAtTimestamp,
-                getRobotStateAtTimestamp,
-
-                reportGlobalRobotPose,
-                reportPlatformPose,
-                reportJointAngles,
-                reportJointVelocities,
-                simulatorWasReset
-            };
-            AMD_RobotStateComponentInterface_getSynchronizedRobotPtr getSynchronizedRobot;
-            AMD_RobotStateComponentInterface_getRobotSnapshotPtr getRobotSnapshot;
-            AMD_RobotStateComponentInterface_getRobotSnapshotAtTimestampPtr getRobotSnapshotAtTimestamp;
-            AMD_RobotStateComponentInterface_getJointConfigAtTimestampPtr getJointConfigAtTimestamp;
-            AMD_RobotStateComponentInterface_getRobotStateAtTimestampPtr getRobotStateAtTimestamp;
-
-            JobType type = JobType::none;
-            PoseStamped currentPose;
-            std::string robotName;
-            Eigen::Matrix4f pose;
-            long timestamp;
-            double time;
-            NameValueMap perJointValues;
-            bool aValueChanged;
-        };
-        template <class ValueT>
-        struct Timestamped
-        {
-            IceUtil::Time timestamp;
-            ValueT value;
-        };
-
-        VirtualRobot::RobotPtr synchronized;
-
-        std::thread      worker;
-        std::atomic_bool stopWrk{false};
-
-        std::map<IceUtil::Time, NameValueMap> jointHistory;
-        std::map<IceUtil::Time, FramedPosePtr> poseHistory;
-
-        size_t jointHistoryLength;
-        size_t poseHistoryLength;
-        RobotStateObserverPtr robotStateObs;
-        SharedRobotInterfacePrx synchronizedPrx;
-        SharedRobotServantPtr sharedRobotServant;
-        RobotStateListenerInterfacePrx robotStateListenerPrx;
-        RobotStateComponentInterfacePrx parent;
-        Ice::ObjectAdapterPtr objectAdapter;
-
-        std::mutex      jobsMutex;
-        std::deque<Job> jobs;
-
-    public:
-        RobotStateComponentWorker()
-        {
-            try
-            {
-                if (synchronizedPrx)
-                {
-                    synchronizedPrx->unref();
-                }
-            }
-            catch (...)
-            {}
-        }
-        ~RobotStateComponentWorker()
-        {
-            stopWorker();
-        }
-
-        void startWorker()
-        {
-            stopWrk = false;
-            ARMARX_CHECK_EXPRESSION(!worker.joinable());
-            ARMARX_INFO << "starting worker";
-            worker = std::thread{[&]{work();}};
-        }
-        void stopWorker()
-        {
-            stopWrk = true;
-            if (worker.joinable())
-            {
-                ARMARX_INFO << "stopping worker";
-                worker.join();
-            }
-        }
-
-        void addJob(Job j)
-        {
-            std::lock_guard g{jobsMutex};
-            jobs.emplace_back(std::move(j));
-            ARMARX_DEBUG <<::deactivateSpam(1) << "adding job -> queue size: " << jobs.size();
-        }
-    private:
-        void work()
-        {
-            ARMARX_INFO << "started worker";
-            ARMARX_ON_SCOPE_EXIT
-            {
-                ARMARX_INFO << "stopped worker";
-            };
-            while (!stopWrk)
-            {
-                std::deque<Job> jobs;
-                {
-                    std::lock_guard g{jobsMutex};
-                    std::swap(jobs, this->jobs);
-                }
-                if (jobs.empty())
-                {
-                    std::this_thread::sleep_for(std::chrono::milliseconds{2});
-                    ARMARX_DEBUG_S << ::deactivateSpam(1) << "no jobs";
-                    continue;
-                }
-                using clock_t = std::chrono::high_resolution_clock;
-                const auto start = clock_t::now();
-                for (auto& j : jobs)
-                {
-                    run(j);
-                }
-                const auto msecs = std::chrono::duration_cast<std::chrono::nanoseconds>(clock_t::now() - start).count() * 1e-6;
-                ARMARX_DEBUG_S << ::deactivateSpam(1) << jobs.size() << " jobs took " << msecs << " ms";
-            }
-        }
-
-        void run(Job& j)
-        {
-            switch (j.type)
-            {
-                case Job::JobType::getSynchronizedRobot:
-                    getSynchronizedRobot(j);
-                    break;
-                case Job::JobType::getRobotSnapshot:
-                    getRobotSnapshot(j);
-                    break;
-                case Job::JobType::getRobotSnapshotAtTimestamp:
-                    getRobotSnapshotAtTimestamp(j);
-                    break;
-                case Job::JobType::getJointConfigAtTimestamp:
-                    getJointConfigAtTimestamp(j);
-                    break;
-                case Job::JobType::getRobotStateAtTimestamp:
-                    getRobotStateAtTimestamp(j);
-                    break;
-                case Job::JobType::reportGlobalRobotPose:
-                    reportGlobalRobotPose(j);
-                    break;
-                case Job::JobType::reportPlatformPose:
-                    reportPlatformPose(j);
-                    break;
-                case Job::JobType::reportJointAngles:
-                    reportJointAngles(j);
-                    break;
-                case Job::JobType::reportJointVelocities:
-                    reportJointVelocities(j);
-                    break;
-                case Job::JobType::simulatorWasReset:
-                    simulatorWasReset(j);
-                    break;
-                default:
-                    ARMARX_FATAL << "job type not set!";
-                    std::terminate();
-            }
-        }
-
-        void getSynchronizedRobot(Job& j)
-        {
-            if (!synchronizedPrx)
-            {
-                j.getSynchronizedRobot->ice_exception(
-                    NotInitializedException("Shared Robot is NULL", "getSynchronizedRobot"));
-                return;
-            }
-            j.getSynchronizedRobot->ice_response(synchronizedPrx);
-        }
-        void getRobotSnapshot(Job& j)
-        {
-            if (!synchronized)
-            {
-                j.getRobotSnapshot->ice_exception(NotInitializedException("Shared Robot is NULL", "getRobotSnapshot"));
-                return;
-            }
-
-            auto clone = synchronized->clone(synchronized->getName());
-
-            SharedRobotServantPtr p = new SharedRobotServant(clone, RobotStateComponentInterfacePrx::uncheckedCast(parent), nullptr);
-            p->setTimestamp(IceUtil::Time::microSecondsDouble(sharedRobotServant->getTimestamp()->timestamp));
-            auto result = objectAdapter->addWithUUID(p);
-            // virtal robot clone is buggy -> set global pose here
-            p->setGlobalPose(new Pose(synchronized->getGlobalPose()));
-            j.getRobotSnapshot->ice_response(SharedRobotInterfacePrx::uncheckedCast(result));
-        }
-        void getRobotSnapshotAtTimestamp(Job& j)
-        {
-            const IceUtil::Time time = IceUtil::Time::microSecondsDouble(j.time);
-
-            if (!synchronized)
-            {
-                j.getRobotSnapshotAtTimestamp->ice_exception(
-                    NotInitializedException("Shared Robot is NULL", "getRobotSnapshot"));
-                return;
-            }
-
-            VirtualRobot::RobotPtr clone = synchronized->clone(synchronized->getName());
-            auto config = interpolate(time);
-            if (!config)
-            {
-                ARMARX_WARNING << "Could not find or interpolate a robot state for time " << time.toDateTime();
-                j.getRobotSnapshotAtTimestamp->ice_response(nullptr);
-                return;
-            }
-
-            clone->setJointValues(config->jointMap);
-            SharedRobotServantPtr p = new SharedRobotServant(clone, RobotStateComponentInterfacePrx::uncheckedCast(parent), nullptr);
-            p->setTimestamp(time);
-            auto result = objectAdapter->addWithUUID(p);
-            // Virtal robot clone is buggy -> set global pose here.
-            p->setGlobalPose(config->globalPose);
-
-            j.getRobotSnapshotAtTimestamp->ice_response(SharedRobotInterfacePrx::uncheckedCast(result));
-        }
-        void getJointConfigAtTimestamp(Job& j)
-        {
-            auto jointAngles = interpolateJoints(IceUtil::Time::microSecondsDouble(j.time));
-            j.getJointConfigAtTimestamp->ice_response(jointAngles ? jointAngles->value : NameValueMap());
-        }
-        void getRobotStateAtTimestamp(Job& j)
-        {
-            auto config = interpolate(IceUtil::Time::microSecondsDouble(j.time));
-            j.getRobotStateAtTimestamp->ice_response(config ? *config : RobotStateConfig());
-        }
-        void reportPlatformPose(Job& j)
-        {
-            const Eigen::Matrix4f globalPose = j.currentPose.pose;
-
-            IceUtil::Time time = IceUtil::Time::microSeconds(j.currentPose.header.timestampInMicroSeconds);
-            insertPose(time, globalPose);
-
-            if (sharedRobotServant)
-            {
-                sharedRobotServant->setTimestamp(time);
-            }
-        }
-        void reportGlobalRobotPose(Job& j)
-        {
-            if (synchronized)
-            {
-                std::string localRobotName = synchronized->getName();
-                ARMARX_DEBUG << "Comparing " << localRobotName
-                             << " and " << j.robotName << ".";
-                if (localRobotName == j.robotName)
-                {
-                    const IceUtil::Time time = IceUtil::Time::microSeconds(j.timestamp);
-
-                    insertPose(time, j.pose);
-                    synchronized->setGlobalPose(j.pose);
-
-                    if (sharedRobotServant)
-                    {
-                        sharedRobotServant->setTimestamp(time);
-                    }
-                }
-            }
-            else
-            {
-                throw NotInitializedException("Robot Ptr is NULL", "reportGlobalRobotPose");
-            }
-        }
-        void reportJointAngles(Job& j)
-        {
-            if (j.timestamp <= 0)
-            {
-                j.timestamp = IceUtil::Time::now().toMicroSeconds();
-            }
-
-            IceUtil::Time time = IceUtil::Time::microSeconds(j.timestamp);
-
-            ARMARX_DEBUG << deactivateSpam(1) << "Got new jointangles: " << j.perJointValues
-                         << " from timestamp " << time.toDateTime()
-                         << " a value changed: " << j.aValueChanged;
-
-            if (j.aValueChanged)
-            {
-                {
-                    WriteLockPtr lock = synchronized->getWriteLock();
-
-                    synchronized->setJointValues(j.perJointValues);
-                }
-
-                if (robotStateObs)
-                {
-                    robotStateObs->updatePoses();
-                }
-            }
-            if (sharedRobotServant)
-            {
-                sharedRobotServant->setTimestamp(time);
-            }
-
-            {
-                jointHistory.emplace_hint(jointHistory.end(), time, j.perJointValues);
-
-                if (jointHistory.size() > jointHistoryLength)
-                {
-                    jointHistory.erase(jointHistory.begin());
-                }
-            }
-
-            robotStateListenerPrx->reportJointValues(j.perJointValues, j.timestamp, j.aValueChanged);
-        }
-        void reportJointVelocities(Job& j)
-        {
-            if (robotStateObs)
-            {
-                robotStateObs->updateNodeVelocities(j.perJointValues, j.timestamp);
-            }
-        }
-        void simulatorWasReset(Job& j)
-        {
-            poseHistory.clear();
-            jointHistory.clear();
-        }
-
-    private:
-        void
-        insertPose(IceUtil::Time timestamp, const Matrix4f& globalPose)
-        {
-            IceUtil::Time duration;
-            {
-                IceUtil::Time start = IceUtil::Time::now();
-                duration = IceUtil::Time::now() - start;
-
-                poseHistory.emplace_hint(poseHistory.end(),
-                                         timestamp, new FramedPose(globalPose, GlobalFrame, ""));
-
-                if (poseHistory.size() > poseHistoryLength)
-                {
-                    poseHistory.erase(poseHistory.begin());
-                }
-            }
-
-            if (robotStateObs)
-            {
-                robotStateObs->updatePoses();
-            }
-        }
-        std::optional<RobotStateConfig>
-        interpolate(IceUtil::Time time) const
-        {
-            auto joints = interpolateJoints(time);
-            auto globalPose = interpolatePose(time);
-
-            if (joints && globalPose)
-            {
-                RobotStateConfig config;
-                // Use time stamp from interpolation.
-                // config.timestamp = time.toMicroSeconds();
-                config.timestamp = std::min(joints->timestamp, globalPose->timestamp).toMicroSeconds();
-                config.jointMap = joints->value;
-                config.globalPose = globalPose->value;
-                return config;
-            }
-            else
-            {
-                return std::nullopt;
-            }
-        }
-        auto
-        interpolateJoints(IceUtil::Time time) const -> std::optional<Timestamped<NameValueMap>>
-        {
-            if (jointHistory.empty())
-            {
-                ARMARX_WARNING << deactivateSpam(1) << "Joint history of robot state component is empty!";
-                return std::nullopt;
-            }
-
-            const IceUtil::Time newestTimeInHistory = jointHistory.rbegin()->first;
-            if (time > newestTimeInHistory)
-            {
-                IceUtil::Time maxOffset = IceUtil::Time::seconds(2);
-                if (time <= newestTimeInHistory + maxOffset)
-                {
-                    ARMARX_INFO << deactivateSpam(5)
-                                << "Requested joint timestamp is newer than newest available timestamp!"
-                                << "\n- requested timestamp: \t" << time.toDateTime()
-                                << "\n- newest timestamp:    \t" << newestTimeInHistory.toDateTime()
-                                << "\n- difference:          \t" << (time - newestTimeInHistory).toMicroSeconds() << " us";
-                }
-                else
-                {
-                    ARMARX_WARNING << deactivateSpam(1) << "Requested joint timestamp is substantially newer (>"
-                                   << maxOffset.toSecondsDouble() << " sec) than newest available timestamp!"
-                                   << "\n- requested timestamp: \t" << time.toDateTime()
-                                   << "\n- newest timestamp:    \t" << newestTimeInHistory.toDateTime();
-                    return std::nullopt;
-                }
-
-                return Timestamped<NameValueMap> {jointHistory.rbegin()->first, jointHistory.rbegin()->second};
-            }
-
-            // Get the oldest entry whose time >= time.
-            auto nextIt = jointHistory.lower_bound(time);
-            if (nextIt == jointHistory.end())
-            {
-                ARMARX_WARNING << deactivateSpam(1)
-                               << "Could not find or interpolate a robot joint angles for time " << time.toDateTime()
-                               << "\n- oldest available value: " << jointHistory.begin()->first.toDateTime()
-                               << "\n- newest available value: " << newestTimeInHistory.toDateTime();
-                return std::nullopt;
-            }
-
-            if (nextIt == jointHistory.begin())
-            {
-                // Next was oldest entry.
-                return Timestamped<NameValueMap> {nextIt->first, nextIt->second};
-            }
-
-            const NameValueMap& next = nextIt->second;
-            auto prevIt = std::prev(nextIt);
-
-
-            // Interpolate.
-
-            IceUtil::Time prevTime = prevIt->first;
-            IceUtil::Time nextTime = nextIt->first;
-
-            float t = static_cast<float>((time - prevTime).toSecondsDouble()
-                                         / (nextTime - prevTime).toSecondsDouble());
-
-            NameValueMap jointAngles;
-            auto prevJointIt = prevIt->second.begin();
-            for (const auto& [name, nextAngle] : next)
-            {
-                float value = (1 - t) * prevJointIt->second + t * nextAngle;
-                prevJointIt++;
-
-                jointAngles.emplace(name, value);
-            }
-
-            return Timestamped<NameValueMap> {time, std::move(jointAngles)};
-        }
-        auto
-        interpolatePose(IceUtil::Time time) const -> std::optional<Timestamped<FramedPosePtr>>
+        try
         {
-            if (poseHistory.empty())
-            {
-                ARMARX_INFO << deactivateSpam(10)
-                            << "Pose history is empty. This can happen if there is no platform unit.";
-
-                ReadLockPtr readLock = synchronized->getReadLock();
-
-                FramedPosePtr pose = new FramedPose(synchronized->getGlobalPose(), armarx::GlobalFrame, "");
-                return Timestamped<FramedPosePtr> {IceUtil::Time::seconds(0), pose};
-            }
-
-
-            const IceUtil::Time newestTimeInHistory = poseHistory.rbegin()->first;
-            if (time > newestTimeInHistory)
+            if (_synchronizedPrx)
             {
-                IceUtil::Time maxOffset = IceUtil::Time::seconds(2);
-                if (time <= newestTimeInHistory + maxOffset)
-                {
-                    ARMARX_INFO << deactivateSpam(5)
-                                << "Requested pose timestamp is newer than newest available timestamp!"
-                                << "\n- requested timestamp: \t" << time.toDateTime()
-                                << "\n- newest timestamp:    \t" << newestTimeInHistory.toDateTime()
-                                << "\n- difference:          \t" << (time - newestTimeInHistory).toMicroSeconds() << " us";
-                }
-                else
-                {
-                    ARMARX_WARNING << deactivateSpam(1) << "Requested pose timestamp is substantially newer (>"
-                                   << maxOffset.toSecondsDouble() << " sec) than newest available timestamp!"
-                                   << "\n- requested timestamp: \t" << time.toDateTime()
-                                   << "\n- newest timestamp:    \t" << newestTimeInHistory.toDateTime();
-                    return std::nullopt;
-                }
-                return Timestamped<FramedPosePtr> {poseHistory.rbegin()->first, poseHistory.rbegin()->second};
-            }
-
-
-            auto nextIt = poseHistory.lower_bound(time);
-            if (nextIt == poseHistory.end())
-            {
-                ARMARX_WARNING << deactivateSpam(1)
-                               << "Could not find or interpolate platform pose for time " << time.toDateTime()
-                               << "\n- oldest available value: " << jointHistory.begin()->first.toDateTime()
-                               << "\n- newest available value: " << newestTimeInHistory.toDateTime();
-                return std::nullopt;
+                _synchronizedPrx->unref();
             }
-
-
-            if (nextIt == poseHistory.begin())
-            {
-                // Next was oldest entry.
-                return Timestamped<FramedPosePtr> {nextIt->first, nextIt->second};
-            }
-
-            auto prevIt = std::prev(nextIt);
-            ARMARX_CHECK_EXPRESSION(prevIt->second);
-
-            const FramedPosePtr& next = nextIt->second;
-            const FramedPosePtr& prev = prevIt->second;
-
-
-            // Interpolate.
-
-            IceUtil::Time prevTime = prevIt->first;
-            IceUtil::Time nextTime = nextIt->first;
-
-            float t = static_cast<float>((time - prevTime).toSecondsDouble()
-                                         / (nextTime - prevTime).toSecondsDouble());
-
-            Eigen::Matrix4f globalPoseNext = next->toEigen();
-            Eigen::Matrix4f globalPosePrev = prev->toEigen();
-
-
-            Eigen::Matrix4f globalPose;
-
-            math::Helpers::Position(globalPose) =
-                (1 - t) * math::Helpers::Position(globalPosePrev) + t * math::Helpers::Position(globalPoseNext);
-
-            Eigen::Quaternionf rotNext(math::Helpers::Orientation(globalPoseNext));
-            Eigen::Quaternionf rotPrev(math::Helpers::Orientation(globalPosePrev));
-            Eigen::Quaternionf rotNew = rotPrev.slerp(t, rotNext);
-
-            math::Helpers::Orientation(globalPose) = rotNew.toRotationMatrix();
-
-            return Timestamped<FramedPosePtr> {time, new FramedPose(globalPose, armarx::GlobalFrame, "")};
         }
-    };
-}
+        catch (...)
+        {}
+    }
 
 
-namespace armarx
-{
     RobotStatePropertyDefinitions::RobotStatePropertyDefinitions(std::string prefix) :
         ComponentPropertyDefinitions(prefix)
     {
@@ -610,11 +77,6 @@ namespace armarx
     }
 
 
-    RobotStateComponent::RobotStateComponent()
-    {
-        _worker = std::make_unique<detail::RobotStateComponentWorker>();
-    }
-
     std::string RobotStateComponent::getDefaultName() const
     {
         return "RobotStateComponent";
@@ -623,9 +85,15 @@ namespace armarx
 
     void RobotStateComponent::onInitComponent()
     {
-        ARMARX_CHECK_NOT_NULL(_worker);
         robotStateTopicName = getProperty<std::string>("RobotStateReportingTopic").getValue();
         offeringTopic(getProperty<std::string>("RobotStateReportingTopic"));
+        const std::size_t historyLength = static_cast<std::size_t>(getProperty<int>("HistoryLength").getValue());
+
+        jointHistory.clear();
+        jointHistoryLength = historyLength;
+
+        poseHistory.clear();
+        poseHistoryLength = historyLength;
 
         relativeRobotFile = getProperty<std::string>("RobotFileName").getValue();
 
@@ -634,34 +102,21 @@ namespace armarx
             throw UserException("Could not find robot file " + robotFile);
         }
 
-        //setup worker
-        {
-            const std::size_t historyLength = static_cast<std::size_t>(getProperty<int>("HistoryLength").getValue());
-            _worker->jointHistoryLength = historyLength;
-            _worker->poseHistoryLength = historyLength;
-            _worker->objectAdapter         = getObjectAdapter();
-            _worker->synchronized = VirtualRobot::RobotIO::loadRobot(robotFile, VirtualRobot::RobotIO::eStructure);
-            _worker->synchronized->setName(getProperty<std::string>("AgentName").getValue());
-        }
-
-        robotName = _worker->synchronized->getName();
+        this->_synchronized = VirtualRobot::RobotIO::loadRobot(robotFile, VirtualRobot::RobotIO::eStructure);
+        _synchronized->setName(getProperty<std::string>("AgentName").getValue());
 
         robotModelScaling = getProperty<float>("RobotModelScaling").getValue();
         ARMARX_INFO << "scale factor: " << robotModelScaling;
         if (robotModelScaling != 1.0f)
         {
             ARMARX_INFO << "Scaling robot model with scale factor " << robotModelScaling;
-            _worker->synchronized =
-                _worker->synchronized->clone(_worker->synchronized->getName(),
-                                             _worker->synchronized->getCollisionChecker(),
-                                             robotModelScaling);
+            _synchronized = _synchronized->clone(_synchronized->getName(), _synchronized->getCollisionChecker(), robotModelScaling);
         }
 
-        if (_worker->synchronized)
+        if (this->_synchronized)
         {
-            ARMARX_VERBOSE << "Loaded robot from file " << robotFile << ". Robot name: "
-                           << _worker->synchronized->getName();
-            _worker->synchronized->setPropagatingJointValuesEnabled(false);
+            ARMARX_VERBOSE << "Loaded robot from file " << robotFile << ". Robot name: " << this->_synchronized->getName();
+            this->_synchronized->setPropagatingJointValuesEnabled(false);
         }
         else
         {
@@ -676,7 +131,7 @@ namespace armarx
             throw UserException("RobotNodeSet not defined");
         }
 
-        VirtualRobot::RobotNodeSetPtr rns =  _worker->synchronized->getRobotNodeSet(robotNodeSetName);
+        VirtualRobot::RobotNodeSetPtr rns =  this->_synchronized->getRobotNodeSet(robotNodeSetName);
 
         if (!rns)
         {
@@ -735,89 +190,96 @@ namespace armarx
 
     void RobotStateComponent::onConnectComponent()
     {
-        {
-            getProxy(_worker->parent, -1);
-            _worker->robotStateListenerPrx = getTopic<RobotStateListenerInterfacePrx>(getProperty<std::string>("RobotStateReportingTopic"));
-
-            _worker->sharedRobotServant    = new SharedRobotServant(_worker->synchronized,
-                    RobotStateComponentInterfacePrx::uncheckedCast(getProxy()),
-                    _worker->robotStateListenerPrx);
-            _worker->sharedRobotServant->ref();
-            _worker->sharedRobotServant->setRobotStateComponent(RobotStateComponentInterfacePrx::uncheckedCast(getProxy()));
-            _worker->synchronizedPrx       = SharedRobotInterfacePrx::uncheckedCast(getObjectAdapter()->addWithUUID(_worker->sharedRobotServant));
+        robotStateListenerPrx = getTopic<RobotStateListenerInterfacePrx>(getProperty<std::string>("RobotStateReportingTopic"));
+        _sharedRobotServant =  new SharedRobotServant(this->_synchronized, RobotStateComponentInterfacePrx::uncheckedCast(getProxy()), robotStateListenerPrx);
+        _sharedRobotServant->ref();
 
-            if (_worker->robotStateObs)
-            {
-                _worker->robotStateObs->setRobot(_worker->synchronized);
-            }
-
-            _worker->startWorker();
-        }
+        _sharedRobotServant->setRobotStateComponent(RobotStateComponentInterfacePrx::uncheckedCast(getProxy()));
+        this->_synchronizedPrx = SharedRobotInterfacePrx::uncheckedCast(getObjectAdapter()->addWithUUID(_sharedRobotServant));
         ARMARX_INFO << "Started RobotStateComponent" << flush;
+        if (robotStateObs)
+        {
+            robotStateObs->setRobot(_synchronized);
+        }
     }
+
     void RobotStateComponent::onDisconnectComponent()
     {
-        _worker->stopWorker();
     }
 
-    void RobotStateComponent::getSynchronizedRobot_async(
-        const AMD_RobotStateComponentInterface_getSynchronizedRobotPtr& amd,
-        const Ice::Current&) const
+
+    SharedRobotInterfacePrx RobotStateComponent::getSynchronizedRobot(const Current&) const
     {
-        detail::RobotStateComponentWorker::Job j;
-        j.type = detail::RobotStateComponentWorker::Job::JobType::getSynchronizedRobot;
-        j.getSynchronizedRobot = amd;
-        _worker->addJob(std::move(j));
+        if (!this->_synchronizedPrx)
+        {
+            throw NotInitializedException("Shared Robot is NULL", "getSynchronizedRobot");
+        }
+
+        return this->_synchronizedPrx;
     }
 
-    void RobotStateComponent::getRobotSnapshot_async(
-        const AMD_RobotStateComponentInterface_getRobotSnapshotPtr& amd,
-        const std::string& deprecated,
-        const Ice::Current&)
+
+    SharedRobotInterfacePrx RobotStateComponent::getRobotSnapshot(const std::string& deprecated, const Current&)
     {
         (void) deprecated;
-        detail::RobotStateComponentWorker::Job j;
-        j.type = detail::RobotStateComponentWorker::Job::JobType::getRobotSnapshot;
-        j.getRobotSnapshot = amd;
-        _worker->addJob(std::move(j));
+
+        if (!_synchronized)
+        {
+            throw NotInitializedException("Shared Robot is NULL", "getRobotSnapshot");
+        }
+
+        auto clone = this->_synchronized->clone(_synchronized->getName());
+
+        SharedRobotServantPtr p = new SharedRobotServant(clone, RobotStateComponentInterfacePrx::uncheckedCast(getProxy()), nullptr);
+        p->setTimestamp(IceUtil::Time::microSecondsDouble(_sharedRobotServant->getTimestamp()->timestamp));
+        auto result = getObjectAdapter()->addWithUUID(p);
+        // virtal robot clone is buggy -> set global pose here
+        p->setGlobalPose(new Pose(_synchronized->getGlobalPose()));
+        return SharedRobotInterfacePrx::uncheckedCast(result);
     }
 
-    void RobotStateComponent::getRobotSnapshotAtTimestamp_async(
-        const AMD_RobotStateComponentInterface_getRobotSnapshotAtTimestampPtr& amd,
-        double time,
-        const Ice::Current&)
+    SharedRobotInterfacePrx RobotStateComponent::getRobotSnapshotAtTimestamp(double _time, const Current&)
     {
-        detail::RobotStateComponentWorker::Job j;
-        j.type = detail::RobotStateComponentWorker::Job::JobType::getRobotSnapshotAtTimestamp;
-        j.time = time;
-        j.getRobotSnapshotAtTimestamp = amd;
-        _worker->addJob(std::move(j));
+        const IceUtil::Time time = IceUtil::Time::microSecondsDouble(_time);
+
+        if (!_synchronized)
+        {
+            throw NotInitializedException("Shared Robot is NULL", "getRobotSnapshot");
+        }
+
+        VirtualRobot::RobotPtr clone = this->_synchronized->clone(_synchronized->getName());
+        auto config = interpolate(time);
+        if (!config)
+        {
+            ARMARX_WARNING << "Could not find or interpolate a robot state for time " << time.toDateTime();
+            return nullptr;
+        }
+
+        clone->setJointValues(config->jointMap);
+        SharedRobotServantPtr p = new SharedRobotServant(clone, RobotStateComponentInterfacePrx::uncheckedCast(getProxy()), nullptr);
+        p->setTimestamp(time);
+        auto result = getObjectAdapter()->addWithUUID(p);
+        // Virtal robot clone is buggy -> set global pose here.
+        p->setGlobalPose(config->globalPose);
+
+        return SharedRobotInterfacePrx::uncheckedCast(result);
     }
 
-    void RobotStateComponent::getJointConfigAtTimestamp_async(
-        const AMD_RobotStateComponentInterface_getJointConfigAtTimestampPtr& amd,
-        double time,
-        const Ice::Current&) const
+
+    NameValueMap RobotStateComponent::getJointConfigAtTimestamp(double timestamp, const Current&) const
     {
-        detail::RobotStateComponentWorker::Job j;
-        j.type = detail::RobotStateComponentWorker::Job::JobType::getJointConfigAtTimestamp;
-        j.time = time;
-        j.getJointConfigAtTimestamp = amd;
-        _worker->addJob(std::move(j));
+        auto jointAngles = interpolateJoints(IceUtil::Time::microSecondsDouble(timestamp));
+        return jointAngles ? jointAngles->value : NameValueMap();
     }
 
-    void RobotStateComponent::getRobotStateAtTimestamp_async(
-        const AMD_RobotStateComponentInterface_getRobotStateAtTimestampPtr& amd,
-        double time,
-        const Ice::Current&) const
+
+    RobotStateConfig RobotStateComponent::getRobotStateAtTimestamp(double timestamp, const Current&) const
     {
-        detail::RobotStateComponentWorker::Job j;
-        j.type = detail::RobotStateComponentWorker::Job::JobType::getRobotStateAtTimestamp;
-        j.time = time;
-        j.getRobotStateAtTimestamp = amd;
-        _worker->addJob(std::move(j));
+        auto config = interpolate(IceUtil::Time::microSecondsDouble(timestamp));
+        return config ? *config : RobotStateConfig();
     }
 
+
     std::string RobotStateComponent::getRobotFilename(const Ice::Current&) const
     {
         return relativeRobotFile;
@@ -833,17 +295,53 @@ namespace armarx
         return robotInfo;
     }
 
+
     void RobotStateComponent::reportJointAngles(
         const NameValueMap& jointAngles, Ice::Long timestamp, bool aValueChanged, const Current&)
     {
-        detail::RobotStateComponentWorker::Job j;
-        j.type = detail::RobotStateComponentWorker::Job::JobType::reportJointAngles;
-        j.perJointValues = jointAngles;
-        j.timestamp = timestamp;
-        j.aValueChanged = aValueChanged;
-        _worker->addJob(std::move(j));
+        if (timestamp <= 0)
+        {
+            timestamp = IceUtil::Time::now().toMicroSeconds();
+        }
+
+        IceUtil::Time time = IceUtil::Time::microSeconds(timestamp);
+
+        ARMARX_DEBUG << deactivateSpam(1) << "Got new jointangles: " << jointAngles
+                     << " from timestamp " << time.toDateTime()
+                     << " a value changed: " << aValueChanged;
+
+        if (aValueChanged)
+        {
+            {
+                WriteLockPtr lock = _synchronized->getWriteLock();
+
+                _synchronized->setJointValues(jointAngles);
+            }
+
+            if (robotStateObs)
+            {
+                robotStateObs->updatePoses();
+            }
+        }
+        if (_sharedRobotServant)
+        {
+            _sharedRobotServant->setTimestamp(time);
+        }
+
+        {
+            std::unique_lock lock(jointHistoryMutex);
+            jointHistory.emplace_hint(jointHistory.end(), time, jointAngles);
+
+            if (jointHistory.size() > jointHistoryLength)
+            {
+                jointHistory.erase(jointHistory.begin());
+            }
+        }
+
+        robotStateListenerPrx->reportJointValues(jointAngles, timestamp, aValueChanged);
     }
 
+
     void
     RobotStateComponent::reportGlobalRobotPose(
         const std::string& robotName,
@@ -851,21 +349,47 @@ namespace armarx
         const long timestamp,
         const Ice::Current&)
     {
-        detail::RobotStateComponentWorker::Job j;
-        j.type = detail::RobotStateComponentWorker::Job::JobType::reportGlobalRobotPose;
-        j.robotName = robotName;
-        j.pose = pose;
-        j.timestamp = timestamp;
-        _worker->addJob(std::move(j));
+        if (_synchronized)
+        {
+            std::string localRobotName = _synchronized->getName();
+            ARMARX_DEBUG << "Comparing " << localRobotName << " and " << robotName << ".";
+            if (localRobotName == robotName)
+            {
+                const IceUtil::Time time = IceUtil::Time::microSeconds(timestamp);
+
+                insertPose(time, pose);
+                _synchronized->setGlobalPose(pose);
+
+                if (_sharedRobotServant)
+                {
+                    _sharedRobotServant->setTimestamp(time);
+                }
+            }
+        }
+        else
+        {
+            throw NotInitializedException("Robot Ptr is NULL", "reportGlobalRobotPose");
+        }
     }
 
 
     void RobotStateComponent::reportPlatformPose(const PoseStamped& platformPose, const Current&)
+
+    void RobotStateComponent::reportPlatformPose(const PlatformPose& currentPose, const Current&)
     {
-        detail::RobotStateComponentWorker::Job j;
-        j.type = detail::RobotStateComponentWorker::Job::JobType::reportPlatformPose;
-        j.currentPose = platformPose;
-        _worker->addJob(std::move(j));
+        const float z = 0;
+        const Eigen::Vector3f position(currentPose.x, currentPose.y, z);
+        const Eigen::Matrix3f orientation =
+            Eigen::AngleAxisf(currentPose.rotationAroundZ, Eigen::Vector3f::UnitZ()).toRotationMatrix();
+        const Eigen::Matrix4f globalPose = math::Helpers::Pose(position, orientation);
+
+        IceUtil::Time time = IceUtil::Time::microSeconds(currentPose.timestampInMicroSeconds);
+        insertPose(time, globalPose);
+
+        if (_sharedRobotServant)
+        {
+            _sharedRobotServant->setTimestamp(time);
+        }
     }
 
 
@@ -876,8 +400,8 @@ namespace armarx
 
     void RobotStateComponent::setRobotStateObserver(RobotStateObserverPtr observer)
     {
-        ARMARX_CHECK_EXPRESSION(_worker);
-        _worker->robotStateObs = observer;
+        // Unused.
+        (void) newPlatformPositionX, (void) newPlatformPositionY, (void) newPlatformRotation;
     }
 
 
@@ -912,22 +436,57 @@ namespace armarx
         return result;
     }
 
+    void RobotStateComponent::reportControlModeChanged(const NameControlModeMap& jointModes, Ice::Long timestamp, bool aValueChanged, const Current&)
+    {
+        // Unused.
+        (void) jointModes, (void) timestamp, (void) aValueChanged;
+    }
     void RobotStateComponent::reportJointVelocities(const NameValueMap& jointVelocities, Ice::Long timestamp, bool aValueChanged, const Current&)
     {
         // Unused.
-        detail::RobotStateComponentWorker::Job j;
-        j.type = detail::RobotStateComponentWorker::Job::JobType::reportJointVelocities;
-        j.perJointValues = jointVelocities;
-        j.timestamp = timestamp;
-        j.aValueChanged = aValueChanged;
-        _worker->addJob(std::move(j));
+        (void) aValueChanged;
+        if (robotStateObs)
+        {
+            robotStateObs->updateNodeVelocities(jointVelocities, timestamp);
+        }
+    }
+    void RobotStateComponent::reportJointTorques(const NameValueMap& jointTorques, Ice::Long timestamp, bool aValueChanged, const Current&)
+    {
+        // Unused.
+        (void) jointTorques, (void) timestamp, (void) aValueChanged;
+    }
+
+    void RobotStateComponent::reportJointAccelerations(const NameValueMap& jointAccelerations, Ice::Long timestamp, bool aValueChanged, const Current&)
+    {
+        // Unused.
+        (void) jointAccelerations, (void) timestamp, (void) aValueChanged;
+    }
+    void RobotStateComponent::reportJointCurrents(const NameValueMap& jointCurrents, Ice::Long timestamp, bool aValueChanged, const Current&)
+    {
+        // Unused.
+        (void) jointCurrents, (void) timestamp, (void) aValueChanged;
+    }
+    void RobotStateComponent::reportJointMotorTemperatures(const NameValueMap& jointMotorTemperatures, Ice::Long timestamp, bool aValueChanged, const Current&)
+    {
+        // Unused.
+        (void) jointMotorTemperatures, (void) timestamp, (void) aValueChanged;
+    }
+    void RobotStateComponent::reportJointStatuses(const NameStatusMap& jointStatuses, Ice::Long timestamp, bool aValueChanged, const Current&)
+    {
+        // Unused.
+        (void) jointStatuses, (void) timestamp, (void) aValueChanged;
     }
 
     void RobotStateComponent::simulatorWasReset(const Current&)
     {
-        detail::RobotStateComponentWorker::Job j;
-        j.type = detail::RobotStateComponentWorker::Job::JobType::simulatorWasReset;
-        _worker->addJob(std::move(j));
+        {
+            std::lock_guard lock(poseHistoryMutex);
+            poseHistory.clear();
+        }
+        {
+            std::lock_guard lock(jointHistoryMutex);
+            jointHistory.clear();
+        }
     }
 
     PropertyDefinitionsPtr RobotStateComponent::createPropertyDefinitions()
@@ -936,16 +495,22 @@ namespace armarx
                                           getConfigIdentifier()));
     }
 
+    void RobotStateComponent::setRobotStateObserver(RobotStateObserverPtr observer)
+    {
+        robotStateObs = observer;
+    }
+
     std::string RobotStateComponent::getRobotName(const Current&) const
     {
-        if (!robotName.empty())
+        if (_synchronized)
         {
-            return robotName;
+            return _synchronized->getName();  // _synchronizedPrx->getName();
         }
         else
         {
             throw NotInitializedException("Robot Ptr is NULL", "getName");
         }
+
     }
 
     std::string RobotStateComponent::getRobotNodeSetName(const Current&) const
@@ -961,4 +526,217 @@ namespace armarx
     {
         return robotStateTopicName;
     }
+
+
+    void RobotStateComponent::insertPose(IceUtil::Time timestamp, const Matrix4f& globalPose)
+    {
+        IceUtil::Time duration;
+        {
+            IceUtil::Time start = IceUtil::Time::now();
+            std::unique_lock lock(poseHistoryMutex);
+            duration = IceUtil::Time::now() - start;
+
+            poseHistory.emplace_hint(poseHistory.end(),
+                                     timestamp, new FramedPose(globalPose, GlobalFrame, ""));
+
+            if (poseHistory.size() > poseHistoryLength)
+            {
+                poseHistory.erase(poseHistory.begin());
+            }
+        }
+
+        if (robotStateObs)
+        {
+            robotStateObs->updatePoses();
+        }
+    }
+
+    std::optional<RobotStateConfig> RobotStateComponent::interpolate(IceUtil::Time time) const
+    {
+        auto joints = interpolateJoints(time);
+        auto globalPose = interpolatePose(time);
+
+        if (joints && globalPose)
+        {
+            RobotStateConfig config;
+            // Use time stamp from interpolation.
+            // config.timestamp = time.toMicroSeconds();
+            config.timestamp = std::min(joints->timestamp, globalPose->timestamp).toMicroSeconds();
+            config.jointMap = joints->value;
+            config.globalPose = globalPose->value;
+            return config;
+        }
+        else
+        {
+            return std::nullopt;
+        }
+    }
+
+    auto RobotStateComponent::interpolateJoints(IceUtil::Time time) const -> std::optional<Timestamped<NameValueMap>>
+    {
+        std::shared_lock lock(jointHistoryMutex);
+        if (jointHistory.empty())
+        {
+            ARMARX_WARNING << deactivateSpam(1) << "Joint history of robot state component is empty!";
+            return std::nullopt;
+        }
+
+        const IceUtil::Time newestTimeInHistory = jointHistory.rbegin()->first;
+        if (time > newestTimeInHistory)
+        {
+            IceUtil::Time maxOffset = IceUtil::Time::seconds(2);
+            if (time <= newestTimeInHistory + maxOffset)
+            {
+                ARMARX_INFO << deactivateSpam(5)
+                            << "Requested joint timestamp is newer than newest available timestamp!"
+                            << "\n- requested timestamp: \t" << time.toDateTime()
+                            << "\n- newest timestamp:    \t" << newestTimeInHistory.toDateTime()
+                            << "\n- difference:          \t" << (time - newestTimeInHistory).toMicroSeconds() << " us";
+            }
+            else
+            {
+                ARMARX_WARNING << deactivateSpam(1) << "Requested joint timestamp is substantially newer (>"
+                               << maxOffset.toSecondsDouble() << " sec) than newest available timestamp!"
+                               << "\n- requested timestamp: \t" << time.toDateTime()
+                               << "\n- newest timestamp:    \t" << newestTimeInHistory.toDateTime();
+                return std::nullopt;
+            }
+
+            return Timestamped<NameValueMap> {jointHistory.rbegin()->first, jointHistory.rbegin()->second};
+        }
+
+        // Get the oldest entry whose time >= time.
+        auto nextIt = jointHistory.lower_bound(time);
+        if (nextIt == jointHistory.end())
+        {
+            ARMARX_WARNING << deactivateSpam(1)
+                           << "Could not find or interpolate a robot joint angles for time " << time.toDateTime()
+                           << "\n- oldest available value: " << jointHistory.begin()->first.toDateTime()
+                           << "\n- newest available value: " << newestTimeInHistory.toDateTime();
+            return std::nullopt;
+        }
+
+        if (nextIt == jointHistory.begin())
+        {
+            // Next was oldest entry.
+            return Timestamped<NameValueMap> {nextIt->first, nextIt->second};
+        }
+
+        const NameValueMap& next = nextIt->second;
+        auto prevIt = std::prev(nextIt);
+
+
+        // Interpolate.
+
+        IceUtil::Time prevTime = prevIt->first;
+        IceUtil::Time nextTime = nextIt->first;
+
+        float t = static_cast<float>((time - prevTime).toSecondsDouble()
+                                     / (nextTime - prevTime).toSecondsDouble());
+
+        NameValueMap jointAngles;
+        auto prevJointIt = prevIt->second.begin();
+        for (const auto& [name, nextAngle] : next)
+        {
+            float value = (1 - t) * prevJointIt->second + t * nextAngle;
+            prevJointIt++;
+
+            jointAngles.emplace(name, value);
+        }
+
+        return Timestamped<NameValueMap> {time, std::move(jointAngles)};
+    }
+
+    auto RobotStateComponent::interpolatePose(IceUtil::Time time) const -> std::optional<Timestamped<FramedPosePtr>>
+    {
+        std::shared_lock lock(poseHistoryMutex);
+
+        if (poseHistory.empty())
+        {
+            ARMARX_INFO << deactivateSpam(10)
+                        << "Pose history is empty. This can happen if there is no platform unit.";
+
+            ReadLockPtr readLock = _synchronized->getReadLock();
+
+            FramedPosePtr pose = new FramedPose(_synchronized->getGlobalPose(), armarx::GlobalFrame, "");
+            return Timestamped<FramedPosePtr> {IceUtil::Time::seconds(0), pose};
+        }
+
+
+        const IceUtil::Time newestTimeInHistory = poseHistory.rbegin()->first;
+        if (time > newestTimeInHistory)
+        {
+            IceUtil::Time maxOffset = IceUtil::Time::seconds(2);
+            if (time <= newestTimeInHistory + maxOffset)
+            {
+                ARMARX_INFO << deactivateSpam(5)
+                            << "Requested pose timestamp is newer than newest available timestamp!"
+                            << "\n- requested timestamp: \t" << time.toDateTime()
+                            << "\n- newest timestamp:    \t" << newestTimeInHistory.toDateTime()
+                            << "\n- difference:          \t" << (time - newestTimeInHistory).toMicroSeconds() << " us";
+            }
+            else
+            {
+                ARMARX_WARNING << deactivateSpam(1) << "Requested pose timestamp is substantially newer (>"
+                               << maxOffset.toSecondsDouble() << " sec) than newest available timestamp!"
+                               << "\n- requested timestamp: \t" << time.toDateTime()
+                               << "\n- newest timestamp:    \t" << newestTimeInHistory.toDateTime();
+                return std::nullopt;
+            }
+            return Timestamped<FramedPosePtr> {poseHistory.rbegin()->first, poseHistory.rbegin()->second};
+        }
+
+
+        auto nextIt = poseHistory.lower_bound(time);
+        if (nextIt == poseHistory.end())
+        {
+            ARMARX_WARNING << deactivateSpam(1)
+                           << "Could not find or interpolate platform pose for time " << time.toDateTime()
+                           << "\n- oldest available value: " << jointHistory.begin()->first.toDateTime()
+                           << "\n- newest available value: " << newestTimeInHistory.toDateTime();
+            return std::nullopt;
+        }
+
+
+        if (nextIt == poseHistory.begin())
+        {
+            // Next was oldest entry.
+            return Timestamped<FramedPosePtr> {nextIt->first, nextIt->second};
+        }
+
+        auto prevIt = std::prev(nextIt);
+        ARMARX_CHECK_EXPRESSION(prevIt->second);
+
+        const FramedPosePtr& next = nextIt->second;
+        const FramedPosePtr& prev = prevIt->second;
+
+
+        // Interpolate.
+
+        IceUtil::Time prevTime = prevIt->first;
+        IceUtil::Time nextTime = nextIt->first;
+
+        float t = static_cast<float>((time - prevTime).toSecondsDouble()
+                                     / (nextTime - prevTime).toSecondsDouble());
+
+        Eigen::Matrix4f globalPoseNext = next->toEigen();
+        Eigen::Matrix4f globalPosePrev = prev->toEigen();
+
+
+        Eigen::Matrix4f globalPose;
+
+        math::Helpers::Position(globalPose) =
+            (1 - t) * math::Helpers::Position(globalPosePrev) + t * math::Helpers::Position(globalPoseNext);
+
+        Eigen::Quaternionf rotNext(math::Helpers::Orientation(globalPoseNext));
+        Eigen::Quaternionf rotPrev(math::Helpers::Orientation(globalPosePrev));
+        Eigen::Quaternionf rotNew = rotPrev.slerp(t, rotNext);
+
+        math::Helpers::Orientation(globalPose) = rotNew.toRotationMatrix();
+
+        return Timestamped<FramedPosePtr> {time, new FramedPose(globalPose, armarx::GlobalFrame, "")};
+    }
+
+
+
 }
diff --git a/source/RobotAPI/components/RobotState/RobotStateComponent.h b/source/RobotAPI/components/RobotState/RobotStateComponent.h
index f36f95e2fd954e40bf53cb6abf7dfbffe5cae896..aba4d1e828a5b55b9165fb6681ca291f4d2bb5fb 100644
--- a/source/RobotAPI/components/RobotState/RobotStateComponent.h
+++ b/source/RobotAPI/components/RobotState/RobotStateComponent.h
@@ -41,10 +41,6 @@
 #include <shared_mutex>
 #include <mutex>
 
-namespace armarx::detail
-{
-    using RobotStateComponentWorkerPtr = std::unique_ptr<class RobotStateComponentWorker>;
-}
 
 namespace armarx
 {
@@ -86,7 +82,6 @@ namespace armarx
         virtual public RobotStateComponentInterface
     {
     public:
-        RobotStateComponent();
 
         std::string getDefaultName() const override;
 
@@ -94,8 +89,7 @@ namespace armarx
         // RobotStateComponentInterface interface
 
         /// \return SharedRobotInterface proxy to the internal synchronized robot.
-        void getSynchronizedRobot_async(const AMD_RobotStateComponentInterface_getSynchronizedRobotPtr& amd,
-                                        const Ice::Current& = Ice::emptyCurrent) const override;
+        SharedRobotInterfacePrx getSynchronizedRobot(const Ice::Current&) const override;
 
         /**
          * Creates a snapshot of the robot state at this moment in time.
@@ -103,18 +97,11 @@ namespace armarx
          * \return Clone of the internal synchronized robot fixed to the configuration from the time of calling this function.
          */
         // [[deprecated]]
-        void getRobotSnapshot_async(const AMD_RobotStateComponentInterface_getRobotSnapshotPtr& amd,
-                                    const std::string& deprecated,
-                                    const Ice::Current& = Ice::emptyCurrent) override;
-        void getRobotSnapshotAtTimestamp_async(const AMD_RobotStateComponentInterface_getRobotSnapshotAtTimestampPtr& amd,
-                                               double time,
-                                               const Ice::Current& = Ice::emptyCurrent) override;
-        void getJointConfigAtTimestamp_async(const AMD_RobotStateComponentInterface_getJointConfigAtTimestampPtr& amd,
-                                             double time,
-                                             const Ice::Current& = Ice::emptyCurrent) const override;
-        void getRobotStateAtTimestamp_async(const AMD_RobotStateComponentInterface_getRobotStateAtTimestampPtr& amd,
-                                            double time,
-                                            const Ice::Current& = Ice::emptyCurrent) const override;
+        SharedRobotInterfacePrx getRobotSnapshot(const std::string& deprecated, const Ice::Current&) override;
+
+        SharedRobotInterfacePrx getRobotSnapshotAtTimestamp(double time, const Ice::Current& current) override;
+        NameValueMap getJointConfigAtTimestamp(double timestamp, const Ice::Current&) const override;
+        RobotStateConfig getRobotStateAtTimestamp(double timestamp, const Ice::Current&) const override;
 
         /// \return the robot xml filename as specified in the configuration
         std::string getRobotFilename(const Ice::Current&) const override;
@@ -148,8 +135,11 @@ namespace armarx
         /// Does nothing.
         void reportPlatformOdometryPose(const PoseStamped& odometryPose, const Ice::Current&) override;
 
-        //called from application
+
+        // Own interface.
         void setRobotStateObserver(RobotStateObserverPtr observer);
+
+
     protected:
 
         // Component interface.
@@ -164,6 +154,9 @@ namespace armarx
         void onConnectComponent() override;
         void onDisconnectComponent() override;
 
+        /// Calls unref() on RobotStateComponent::_synchronizedPrx.
+        ~RobotStateComponent() override;
+
         /// Create an instance of RobotStatePropertyDefinitions.
         PropertyDefinitionsPtr createPropertyDefinitions() override;
 
@@ -171,40 +164,77 @@ namespace armarx
         // Inherited from KinematicUnitInterface
 
         /// Does nothing.
-        void reportControlModeChanged(const NameControlModeMap&, Ice::Long, bool, const Ice::Current&) override {}
+        void reportControlModeChanged(const NameControlModeMap& jointModes, Ice::Long timestamp, bool aValueChanged, const Ice::Current& c = Ice::emptyCurrent) override;
         /// Stores the reported joint angles in the joint history and publishes the new joint angles.
         void reportJointAngles(const NameValueMap& jointAngles, Ice::Long timestamp,  bool aValueChanged, const Ice::Current& c = Ice::emptyCurrent) override;
         /// Sends the joint velocities to the robot state observer.
         void reportJointVelocities(const NameValueMap& jointVelocities, Ice::Long timestamp,  bool aValueChanged, const Ice::Current& c = Ice::emptyCurrent) override;
         /// Does nothing.
-        void reportJointTorques(const NameValueMap&, Ice::Long,  bool, const Ice::Current&)           override {}
+        void reportJointTorques(const NameValueMap& jointTorques, Ice::Long timestamp,  bool aValueChanged, const Ice::Current& c = Ice::emptyCurrent) override;
         /// Does nothing.
-        void reportJointAccelerations(const NameValueMap&, Ice::Long, bool, const Ice::Current&)      override {}
+        void reportJointAccelerations(const NameValueMap& jointAccelerations, Ice::Long timestamp, bool aValueChanged, const Ice::Current& c) override;
         /// Does nothing.
-        void reportJointCurrents(const NameValueMap&, Ice::Long,  bool, const Ice::Current&)          override {}
+        void reportJointCurrents(const NameValueMap& jointCurrents, Ice::Long timestamp,  bool aValueChanged, const Ice::Current& c = Ice::emptyCurrent) override;
         /// Does nothing.
-        void reportJointMotorTemperatures(const NameValueMap&, Ice::Long,  bool, const Ice::Current&) override {}
+        void reportJointMotorTemperatures(const NameValueMap& jointMotorTemperatures, Ice::Long timestamp,  bool aValueChanged, const Ice::Current& c = Ice::emptyCurrent) override;
         /// Does nothing.
-        void reportJointStatuses(const NameStatusMap&, Ice::Long,  bool, const Ice::Current&)         override {}
+        void reportJointStatuses(const NameStatusMap& jointStatuses, Ice::Long timestamp,  bool aValueChanged, const Ice::Current& c = Ice::emptyCurrent) override;
 
         void simulatorWasReset(const Ice::Current& = Ice::emptyCurrent) override;
     private:
 
         void readRobotInfo(const std::string& robotFile);
         RobotInfoNodePtr readRobotInfo(const RapidXmlReaderNode& infoNode);
+
+        void insertPose(IceUtil::Time timestamp, const Eigen::Matrix4f& globalPose);
+
+
+        template <class ValueT>
+        struct Timestamped
+        {
+            IceUtil::Time timestamp;
+            ValueT value;
+        };
+
+        /// Interpolate the robot state from histories and store it in `config`.
+        std::optional<RobotStateConfig> interpolate(IceUtil::Time time) const;
+        /// Interpolate the joint angles from history and store it in `jointAngles`.
+        std::optional<Timestamped<NameValueMap>> interpolateJoints(IceUtil::Time time) const;
+        /// Interpolate the robot pose from history and store it in `pose`.
+        std::optional<Timestamped<FramedPosePtr>> interpolatePose(IceUtil::Time time) const;
+
+
     private:
 
+        /// Local robot model.
+        VirtualRobot::RobotPtr _synchronized;
+        /// Local shared robot.
+        SharedRobotServantPtr _sharedRobotServant;
+        /// Ice proxy to `_sharedRobotServant`.
+        SharedRobotInterfacePrx _synchronizedPrx;
+
+        RobotStateListenerInterfacePrx robotStateListenerPrx;
+        RobotStateObserverPtr robotStateObs;
+
         std::string robotStateTopicName;
         std::string robotFile;
         std::string relativeRobotFile;
-        std::string robotName;
+
+        mutable std::shared_mutex jointHistoryMutex;
+        std::map<IceUtil::Time, NameValueMap> jointHistory;
+        size_t jointHistoryLength;
+
+        mutable std::shared_mutex poseHistoryMutex;
+        std::map<IceUtil::Time, FramedPosePtr> poseHistory;
+        size_t poseHistoryLength;
+
         std::string robotNodeSetName;
 
         float robotModelScaling;
 
         RobotInfoNodePtr robotInfo;
 
-        detail::RobotStateComponentWorkerPtr _worker;
     };
+
 }
 
diff --git a/source/RobotAPI/gui-plugins/ArMemMemoryViewer/ArMemMemoryViewerWidgetController.cpp b/source/RobotAPI/gui-plugins/ArMemMemoryViewer/ArMemMemoryViewerWidgetController.cpp
index 6dd944d27b72db26da41223bdd35b05766331748..2636ee8ade97c82c97a40a93d4741bddfa466569 100644
--- a/source/RobotAPI/gui-plugins/ArMemMemoryViewer/ArMemMemoryViewerWidgetController.cpp
+++ b/source/RobotAPI/gui-plugins/ArMemMemoryViewer/ArMemMemoryViewerWidgetController.cpp
@@ -271,7 +271,12 @@ namespace armarx
             const armem::EntitySnapshot* snapshot = nullptr;
             if (!id.hasTimestamp())
             {
-                snapshot = &memoryData->getEntity(id).getLatestSnapshot();
+                const armem::Entity& entity = memoryData->getEntity(id);
+                if (entity.empty())
+                {
+                    return;
+                }
+                snapshot = &entity.getLatestSnapshot();
                 id.timestamp = snapshot->time();
             }
             if (!id.hasInstanceIndex())
diff --git a/source/RobotAPI/gui-plugins/CartesianImpedanceController/CartesianImpedanceControllerWidget.ui b/source/RobotAPI/gui-plugins/CartesianImpedanceController/CartesianImpedanceControllerWidget.ui
index a90f9ebec033fe01b2ea927b00283106bc10c872..890f754e5a2e26d8c22226868c5bcbbc98ee5a98 100644
--- a/source/RobotAPI/gui-plugins/CartesianImpedanceController/CartesianImpedanceControllerWidget.ui
+++ b/source/RobotAPI/gui-plugins/CartesianImpedanceController/CartesianImpedanceControllerWidget.ui
@@ -54,7 +54,7 @@
                  <string>Left</string>
                 </property>
                 <property name="checked">
-                 <bool>true</bool>
+                 <bool>false</bool>
                 </property>
                </widget>
               </item>
@@ -63,6 +63,9 @@
                 <property name="text">
                  <string>Right</string>
                 </property>
+                <property name="checked">
+                 <bool>true</bool>
+                </property>
                </widget>
               </item>
               <item>
@@ -211,64 +214,111 @@
            <widget class="QWidget" name="widgetTarget" native="true">
             <layout class="QGridLayout" name="gridLayout_2">
              <item row="1" column="1">
-              <widget class="QDoubleSpinBox" name="doubleSpinBoxTargRX"/>
+              <widget class="QDoubleSpinBox" name="doubleSpinBoxTargRX">
+               <property name="minimum">
+                <double>-100.000000000000000</double>
+               </property>
+               <property name="maximum">
+                <double>100.000000000000000</double>
+               </property>
+               <property name="singleStep">
+                <double>0.010000000000000</double>
+               </property>
+              </widget>
              </item>
              <item row="1" column="3">
-              <widget class="QDoubleSpinBox" name="doubleSpinBoxTargRZ"/>
+              <widget class="QDoubleSpinBox" name="doubleSpinBoxTargRZ">
+               <property name="minimum">
+                <double>-100.000000000000000</double>
+               </property>
+               <property name="maximum">
+                <double>100.000000000000000</double>
+               </property>
+               <property name="singleStep">
+                <double>0.010000000000000</double>
+               </property>
+              </widget>
              </item>
              <item row="1" column="2">
-              <widget class="QDoubleSpinBox" name="doubleSpinBoxTargRY"/>
+              <widget class="QDoubleSpinBox" name="doubleSpinBoxTargRY">
+               <property name="minimum">
+                <double>-100.000000000000000</double>
+               </property>
+               <property name="maximum">
+                <double>100.000000000000000</double>
+               </property>
+               <property name="singleStep">
+                <double>0.010000000000000</double>
+               </property>
+              </widget>
              </item>
              <item row="0" column="3">
               <widget class="QDoubleSpinBox" name="doubleSpinBoxTargTZ"/>
              </item>
              <item row="2" column="0" colspan="4">
               <layout class="QGridLayout" name="gridLayout_3">
-               <item row="0" column="1">
-                <widget class="QPushButton" name="pushButtonTargSet">
+               <item row="1" column="0">
+                <widget class="QPushButton" name="pushButtonTargGet">
                  <property name="text">
-                  <string>Set Pose</string>
+                  <string>Set to current</string>
                  </property>
                 </widget>
                </item>
-               <item row="0" column="2">
-                <widget class="QPushButton" name="pushButtonTargAdd">
+               <item row="3" column="2">
+                <widget class="QRadioButton" name="radioButtonVisuAdd">
                  <property name="text">
                   <string>Add Pose</string>
                  </property>
+                 <property name="checked">
+                  <bool>false</bool>
+                 </property>
                 </widget>
                </item>
-               <item row="1" column="0">
+               <item row="3" column="0">
                 <widget class="QLabel" name="label_2">
                  <property name="text">
                   <string>Visu</string>
                  </property>
                 </widget>
                </item>
-               <item row="0" column="0">
-                <widget class="QPushButton" name="pushButtonTargGet">
+               <item row="3" column="1">
+                <widget class="QRadioButton" name="radioButtonVisuSet">
                  <property name="text">
-                  <string>Set to current</string>
+                  <string>Set Pose</string>
+                 </property>
+                 <property name="checked">
+                  <bool>true</bool>
                  </property>
                 </widget>
                </item>
-               <item row="1" column="2">
-                <widget class="QRadioButton" name="radioButtonVisuAdd">
+               <item row="1" column="1">
+                <widget class="QPushButton" name="pushButtonTargSet">
                  <property name="text">
-                  <string>Add Pose</string>
+                  <string>Set Pose</string>
                  </property>
-                 <property name="checked">
+                </widget>
+               </item>
+               <item row="1" column="2">
+                <widget class="QPushButton" name="pushButtonTargAdd">
+                 <property name="enabled">
                   <bool>false</bool>
                  </property>
+                 <property name="text">
+                  <string>Add Pose</string>
+                 </property>
                 </widget>
                </item>
-               <item row="1" column="1">
-                <widget class="QRadioButton" name="radioButtonVisuSet">
+               <item row="2" column="2">
+                <widget class="QCheckBox" name="checkBoxEnableAddPose">
                  <property name="text">
-                  <string>Set Pose</string>
+                  <string>enable add pose</string>
                  </property>
-                 <property name="checked">
-                  <bool>true</bool>
+                </widget>
+               </item>
+               <item row="2" column="1">
+                <widget class="QCheckBox" name="checkBoxAutoUpdatePose">
+                 <property name="text">
+                  <string>Auto set pose</string>
                  </property>
                 </widget>
                </item>
@@ -394,8 +444,8 @@
      <y>121</y>
     </hint>
     <hint type="destinationlabel">
-     <x>195</x>
-     <y>149</y>
+     <x>207</x>
+     <y>139</y>
     </hint>
    </hints>
   </connection>
@@ -439,7 +489,7 @@
    <hints>
     <hint type="sourcelabel">
      <x>590</x>
-     <y>43</y>
+     <y>41</y>
     </hint>
     <hint type="destinationlabel">
      <x>281</x>
@@ -479,5 +529,21 @@
     </hint>
    </hints>
   </connection>
+  <connection>
+   <sender>checkBoxEnableAddPose</sender>
+   <signal>clicked(bool)</signal>
+   <receiver>pushButtonTargAdd</receiver>
+   <slot>setEnabled(bool)</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>449</x>
+     <y>281</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>461</x>
+     <y>259</y>
+    </hint>
+   </hints>
+  </connection>
  </connections>
 </ui>
diff --git a/source/RobotAPI/gui-plugins/CartesianImpedanceController/CartesianImpedanceControllerWidgetController.cpp b/source/RobotAPI/gui-plugins/CartesianImpedanceController/CartesianImpedanceControllerWidgetController.cpp
index 502caf22f0a3dfa746df260967fd459f681de7a7..6b34ac81d1d2bd48e8f6bdaae2cbf2bd2b711b26 100644
--- a/source/RobotAPI/gui-plugins/CartesianImpedanceController/CartesianImpedanceControllerWidgetController.cpp
+++ b/source/RobotAPI/gui-plugins/CartesianImpedanceController/CartesianImpedanceControllerWidgetController.cpp
@@ -114,12 +114,18 @@ namespace armarx
         {
             synchronizeLocalClone(_robot);
         }
+        if (_ui.checkBoxAutoUpdatePose->isChecked())
+        {
+            ARMARX_TRACE;
+            on_pushButtonTargSet_clicked();
+        }
         const bool lockY = _ui.checkBoxLockY->isChecked();
         const bool lockZ = _ui.checkBoxLockZ->isChecked();
         bool anyTracking = lockY || lockZ;
         _ui.widgetTarget->setEnabled(!anyTracking);
         if (_rns && (lockY || lockZ))
         {
+            ARMARX_TRACE;
             Eigen::Matrix4f pose = _rns->getTCP()->getPoseInRootFrame();
             if (lockY)
             {
@@ -154,9 +160,12 @@ namespace armarx
     {
         ARMARX_TRACE;
         std::lock_guard g{_allMutex};
-        if (_visuHandRobotFile.empty() || !_robot)
+        if (_visuHandRobotFile.empty() || !_robot || !arviz.topic())
         {
-            arviz.commitLayerContaining("hand");
+            if (arviz.topic())
+            {
+                arviz.commitLayerContaining("hand");
+            }
             return;
         }
 
diff --git a/source/RobotAPI/interface/core/RobotState.ice b/source/RobotAPI/interface/core/RobotState.ice
index 1beb3e37d11fd1fe1f4478e8c657766048928b28..332959df89b7c0c4fe55ce2442f240d29e45213e 100644
--- a/source/RobotAPI/interface/core/RobotState.ice
+++ b/source/RobotAPI/interface/core/RobotState.ice
@@ -198,28 +198,28 @@ module armarx
         /**
          * @return proxy to the shared robot which constantly updates all joint values
          */
-        ["cpp:const", "amd"]
+        ["cpp:const"]
         idempotent
         SharedRobotInterface* getSynchronizedRobot() throws NotInitializedException;
 
         /**
          * @return proxy to a copy of the shared robot with non updating joint values
          */
-        ["amd"] SharedRobotInterface* getRobotSnapshot(string deprecated) throws NotInitializedException;
+        SharedRobotInterface* getRobotSnapshot(string deprecated) throws NotInitializedException;
 
         /**
           * Create robot snapshot proxy from past timestamp. The time that can be gone back depends on the robotstatecomponent configuration.
           * @return Snapshot
           *
           * */
-        ["amd"] SharedRobotInterface* getRobotSnapshotAtTimestamp(double time) throws NotInitializedException;
+        SharedRobotInterface* getRobotSnapshotAtTimestamp(double time) throws NotInitializedException;
 
         /**
           * Return the joint values from past timestamp. The time that can be gone back depends on the robotstatecomponent configuration.
           * @return Jointname-jointvalue map
           *
           * */
-        ["cpp:const", "amd"]
+        ["cpp:const"]
         idempotent
         NameValueMap getJointConfigAtTimestamp(double time) throws NotInitializedException;
 
@@ -228,7 +228,7 @@ module armarx
           * @return Robot configuration containing jointvalue map and globalpose
           *
           * */
-        ["cpp:const", "amd"] 
+        ["cpp:const"]
         idempotent
         RobotStateConfig getRobotStateAtTimestamp(double time) throws NotInitializedException;
 
diff --git a/source/RobotAPI/interface/units/RobotUnit/NJointTaskSpaceDMPController.ice b/source/RobotAPI/interface/units/RobotUnit/NJointTaskSpaceDMPController.ice
index f9ef01e542e65c421fb5a80e82a8f4d23815c81d..2f039d60c1343421a5a22bc576eec0ea7b3fc456 100644
--- a/source/RobotAPI/interface/units/RobotUnit/NJointTaskSpaceDMPController.ice
+++ b/source/RobotAPI/interface/units/RobotUnit/NJointTaskSpaceDMPController.ice
@@ -516,6 +516,7 @@ module armarx
         bool isManipulability = false;
         Ice::DoubleSeq kmani;
         Ice::DoubleSeq positionManipulability;
+        Ice::DoubleSeq maniWeight;
 
     };
 
diff --git a/source/RobotAPI/libraries/RobotAPINJointControllerWidgets/CartesianImpedanceControllerConfigWidget.cpp b/source/RobotAPI/libraries/RobotAPINJointControllerWidgets/CartesianImpedanceControllerConfigWidget.cpp
index 91318db432c554018bced9906a407c1e7738d9f5..800eccc800ea2ad6b8e6e2bb796c95eac73f4d91 100644
--- a/source/RobotAPI/libraries/RobotAPINJointControllerWidgets/CartesianImpedanceControllerConfigWidget.cpp
+++ b/source/RobotAPI/libraries/RobotAPINJointControllerWidgets/CartesianImpedanceControllerConfigWidget.cpp
@@ -28,26 +28,26 @@ namespace armarx
         kxyz.addWidget(ui.doubleSpinBoxKTX);
         kxyz.addWidget(ui.doubleSpinBoxKTY);
         kxyz.addWidget(ui.doubleSpinBoxKTZ);
-        kxyz.setMinMax(0, 1000);
-        kxyz.set(500);
+        kxyz.setMinMax(0, 5000);
+        kxyz.set(1000);
 
         krpy.addWidget(ui.doubleSpinBoxKRX);
         krpy.addWidget(ui.doubleSpinBoxKRY);
         krpy.addWidget(ui.doubleSpinBoxKRZ);
-        krpy.setMinMax(0, 1000);
-        krpy.set(1);
+        krpy.setMinMax(0, 5000);
+        krpy.set(500);
 
         dxyz.addWidget(ui.doubleSpinBoxDTX);
         dxyz.addWidget(ui.doubleSpinBoxDTY);
         dxyz.addWidget(ui.doubleSpinBoxDTZ);
-        dxyz.setMinMax(0, 1000);
-        dxyz.set(0);
+        dxyz.setMinMax(0, 5000);
+        dxyz.set(250);
 
         drpy.addWidget(ui.doubleSpinBoxDRX);
         drpy.addWidget(ui.doubleSpinBoxDRY);
         drpy.addWidget(ui.doubleSpinBoxDRZ);
-        drpy.setMinMax(0, 1000);
-        drpy.set(0);
+        drpy.setMinMax(0, 5000);
+        drpy.set(100);
 
         using T = CartesianImpedanceControllerConfigWidget;
         connect(ui.pushButtonNullspaceUpdateJoints, &QPushButton::clicked, this, &T::on_pushButtonNullspaceUpdateJoints_clicked);
@@ -218,7 +218,7 @@ namespace armarx
                 lay->addWidget(b, i, 2);
                 b->setMinimum(0);
                 b->setMaximum(1000);
-                b->setValue(1);
+                b->setValue(2);
             }
             {
                 auto b = new QDoubleSpinBox;
@@ -226,12 +226,12 @@ namespace armarx
                 lay->addWidget(b, i, 3);
                 b->setMinimum(0);
                 b->setMaximum(1000);
-                b->setValue(0);
+                b->setValue(1);
             }
             ++i;
         }
-        jointKnull.set(5);
-        jointDnull.set(0);
+        jointKnull.set(2);
+        jointDnull.set(1);
 
         on_pushButtonNullspaceUpdateJoints_clicked();
     }
diff --git a/source/RobotAPI/libraries/RobotAPINJointControllerWidgets/CartesianImpedanceControllerConfigWidget.ui b/source/RobotAPI/libraries/RobotAPINJointControllerWidgets/CartesianImpedanceControllerConfigWidget.ui
index 3d3e53610438552d803aaf65c999c698c313c2fe..669892bd956030629ddc31abc71804c4c8e31140 100644
--- a/source/RobotAPI/libraries/RobotAPINJointControllerWidgets/CartesianImpedanceControllerConfigWidget.ui
+++ b/source/RobotAPI/libraries/RobotAPINJointControllerWidgets/CartesianImpedanceControllerConfigWidget.ui
@@ -30,23 +30,45 @@
     <widget class="QWidget" name="widget" native="true">
      <layout class="QGridLayout" name="gridLayout_3">
       <item row="2" column="1">
-       <widget class="QDoubleSpinBox" name="doubleSpinBoxKRX"/>
+       <widget class="QDoubleSpinBox" name="doubleSpinBoxKRX">
+        <property name="toolTip">
+         <string>200 - 800 (use 500)</string>
+        </property>
+       </widget>
       </item>
       <item row="4" column="3">
-       <widget class="QDoubleSpinBox" name="doubleSpinBoxDRZ"/>
+       <widget class="QDoubleSpinBox" name="doubleSpinBoxDRZ">
+        <property name="toolTip">
+         <string>50 - 500</string>
+        </property>
+       </widget>
       </item>
       <item row="2" column="0">
        <widget class="QLabel" name="label_5">
+        <property name="toolTip">
+         <string>200 - 800 (use 500)</string>
+        </property>
         <property name="text">
          <string>K RPY</string>
         </property>
        </widget>
       </item>
       <item row="5" column="1" colspan="3">
-       <widget class="QDoubleSpinBox" name="doubleSpinBoxTorqueLim"/>
+       <widget class="QDoubleSpinBox" name="doubleSpinBoxTorqueLim">
+        <property name="maximum">
+         <double>1000.000000000000000</double>
+        </property>
+        <property name="value">
+         <double>20.000000000000000</double>
+        </property>
+       </widget>
       </item>
       <item row="1" column="1">
-       <widget class="QDoubleSpinBox" name="doubleSpinBoxKTX"/>
+       <widget class="QDoubleSpinBox" name="doubleSpinBoxKTX">
+        <property name="toolTip">
+         <string>500 - 2000 (use 1000)</string>
+        </property>
+       </widget>
       </item>
       <item row="1" column="0">
        <widget class="QLabel" name="label_3">
@@ -56,13 +78,20 @@
           <verstretch>0</verstretch>
          </sizepolicy>
         </property>
+        <property name="toolTip">
+         <string>500 - 2000 (use 1000)</string>
+        </property>
         <property name="text">
          <string>K XYZ</string>
         </property>
        </widget>
       </item>
       <item row="2" column="2">
-       <widget class="QDoubleSpinBox" name="doubleSpinBoxKRY"/>
+       <widget class="QDoubleSpinBox" name="doubleSpinBoxKRY">
+        <property name="toolTip">
+         <string>200 - 800 (use 500)</string>
+        </property>
+       </widget>
       </item>
       <item row="5" column="0">
        <widget class="QLabel" name="label_6">
@@ -72,16 +101,32 @@
        </widget>
       </item>
       <item row="1" column="2">
-       <widget class="QDoubleSpinBox" name="doubleSpinBoxKTY"/>
+       <widget class="QDoubleSpinBox" name="doubleSpinBoxKTY">
+        <property name="toolTip">
+         <string>500 - 2000 (use 1000)</string>
+        </property>
+       </widget>
       </item>
       <item row="4" column="2">
-       <widget class="QDoubleSpinBox" name="doubleSpinBoxDRY"/>
+       <widget class="QDoubleSpinBox" name="doubleSpinBoxDRY">
+        <property name="toolTip">
+         <string>50 - 500</string>
+        </property>
+       </widget>
       </item>
       <item row="4" column="1">
-       <widget class="QDoubleSpinBox" name="doubleSpinBoxDRX"/>
+       <widget class="QDoubleSpinBox" name="doubleSpinBoxDRX">
+        <property name="toolTip">
+         <string>50 - 500</string>
+        </property>
+       </widget>
       </item>
       <item row="3" column="1">
-       <widget class="QDoubleSpinBox" name="doubleSpinBoxDTX"/>
+       <widget class="QDoubleSpinBox" name="doubleSpinBoxDTX">
+        <property name="toolTip">
+         <string>100 - 500</string>
+        </property>
+       </widget>
       </item>
       <item row="0" column="0" colspan="4">
        <widget class="QGroupBox" name="groupBox_3">
@@ -122,6 +167,9 @@
               </item>
               <item row="0" column="3">
                <widget class="QLabel" name="label_10">
+                <property name="toolTip">
+                 <string>0.5 - 1</string>
+                </property>
                 <property name="text">
                  <string>Dnull</string>
                 </property>
@@ -129,6 +177,9 @@
               </item>
               <item row="0" column="2">
                <widget class="QLabel" name="label_12">
+                <property name="toolTip">
+                 <string>1 - 10</string>
+                </property>
                 <property name="text">
                  <string>Knull</string>
                 </property>
@@ -157,30 +208,52 @@
        </widget>
       </item>
       <item row="3" column="3">
-       <widget class="QDoubleSpinBox" name="doubleSpinBoxDTZ"/>
+       <widget class="QDoubleSpinBox" name="doubleSpinBoxDTZ">
+        <property name="toolTip">
+         <string>100 - 500</string>
+        </property>
+       </widget>
       </item>
       <item row="4" column="0">
        <widget class="QLabel" name="label_2">
+        <property name="toolTip">
+         <string>50 - 500</string>
+        </property>
         <property name="text">
          <string>D RPY</string>
         </property>
        </widget>
       </item>
       <item row="3" column="2">
-       <widget class="QDoubleSpinBox" name="doubleSpinBoxDTY"/>
+       <widget class="QDoubleSpinBox" name="doubleSpinBoxDTY">
+        <property name="toolTip">
+         <string>100 - 500</string>
+        </property>
+       </widget>
       </item>
       <item row="3" column="0">
        <widget class="QLabel" name="label_4">
+        <property name="toolTip">
+         <string>100 - 500</string>
+        </property>
         <property name="text">
          <string>D XYZ</string>
         </property>
        </widget>
       </item>
       <item row="2" column="3">
-       <widget class="QDoubleSpinBox" name="doubleSpinBoxKRZ"/>
+       <widget class="QDoubleSpinBox" name="doubleSpinBoxKRZ">
+        <property name="toolTip">
+         <string>200 - 800 (use 500)</string>
+        </property>
+       </widget>
       </item>
       <item row="1" column="3">
-       <widget class="QDoubleSpinBox" name="doubleSpinBoxKTZ"/>
+       <widget class="QDoubleSpinBox" name="doubleSpinBoxKTZ">
+        <property name="toolTip">
+         <string>500 - 2000 (use 1000)</string>
+        </property>
+       </widget>
       </item>
       <item row="6" column="0" colspan="4">
        <widget class="QPushButton" name="pushButtonSettingsSend">
diff --git a/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointPeriodicTSDMPCompliantController.cpp b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointPeriodicTSDMPCompliantController.cpp
index ccd553f342786bc813a913b80e9b95b0feb4cf46..79a090adbae49e70b400ca3cd358b0599a11c9f1 100644
--- a/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointPeriodicTSDMPCompliantController.cpp
+++ b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointPeriodicTSDMPCompliantController.cpp
@@ -130,7 +130,22 @@ namespace armarx
 
 
         isManipulability = cfg->isManipulability;
-        auto manipulability = std::make_shared<VirtualRobot::SingleRobotNodeSetManipulability>(rns, rns->getTCP(), VirtualRobot::AbstractManipulability::Mode::Position, VirtualRobot::AbstractManipulability::Type::Velocity, rns->getRobot()->getRootNode());
+
+
+        ARMARX_CHECK_EQUAL(cfg->maniWeight.size(), rns->getNodeNames().size());
+        Eigen::VectorXd maniWeightVec;
+        maniWeightVec.setOnes(rns->getNodeNames().size());
+        for (size_t i = 0; i < cfg->maniWeight.size(); ++i)
+        {
+            maniWeightVec(i) = cfg->maniWeight[i];
+        }
+
+        Eigen::MatrixXd maniWeightMat = maniWeightVec.asDiagonal();
+        VirtualRobot::SingleRobotNodeSetManipulabilityPtr manipulability(
+            new VirtualRobot::SingleRobotNodeSetManipulability(rns, rns->getTCP(),
+                    VirtualRobot::AbstractManipulability::Mode::Position,
+                    VirtualRobot::AbstractManipulability::Type::Velocity,
+                    rns->getRobot()->getRootNode(), maniWeightMat));
         manipulabilityTracker.reset(new VirtualRobot::SingleChainManipulabilityTracking(manipulability));
 
         ARMARX_CHECK_EQUAL(cfg->positionManipulability.size(), 9);
@@ -469,7 +484,12 @@ namespace armarx
         //            targetPose.block<3, 3>(0, 0) = rotVel * targetPose.block<3, 3>(0, 0);
 
         // inverse dynamic controller
-        jacobi.block<3, 8>(0, 0) = 0.001 * jacobi.block<3, 8>(0, 0); // convert mm to m
+
+        for (size_t ki = 0; ki < 3; ++ki)
+        {
+            jacobi.row(ki) = 0.001 * jacobi.row(ki); // convert mm to m
+
+        }
 
 
 
@@ -516,7 +536,7 @@ namespace armarx
         float manidist = 0;
         if (isManipulability)
         {
-            nullspaceTorque = manipulabilityTracker->calculateVelocity(targetManipulability, kmani);
+            nullspaceTorque = manipulabilityTracker->calculateVelocity(targetManipulability, kmani, true);
             manidist = manipulabilityTracker->computeDistance(targetManipulability);
         }
         else
diff --git a/source/RobotAPI/libraries/armem/core/MemoryID.cpp b/source/RobotAPI/libraries/armem/core/MemoryID.cpp
index 664319410949b11c7563512a6ccc22dc0c2dd3e1..61dd4836ca9f16ffd6b36342facbd2f610c75ff3 100644
--- a/source/RobotAPI/libraries/armem/core/MemoryID.cpp
+++ b/source/RobotAPI/libraries/armem/core/MemoryID.cpp
@@ -1,20 +1,45 @@
 #include "MemoryID.h"
 
-#include <SimoxUtility/algorithm/string.h>
-
 #include "error/ArMemError.h"
 
+#include <SimoxUtility/algorithm/advanced.h>
+#include <SimoxUtility/algorithm/string/string_tools.h>
+
+#include <boost/algorithm/string.hpp>
+
+#include <forward_list>
+
 
 namespace armarx::armem
 {
 
+    const std::string MemoryID::delimiter = "/";
+
+
     MemoryID::MemoryID()
     {
     }
 
     MemoryID::MemoryID(const std::string& string)
     {
-        std::vector<std::string> items = simox::alg::split(string, "/", false, false);
+        std::forward_list<std::string> items;
+        boost::split(items, string, boost::is_any_of(delimiter));
+
+        // Handle escaped /'s
+        for (auto it = items.begin(); it != items.end(); ++it)
+        {
+            while (it->size() > 0 && it->back() == '\\')
+            {
+                // The / causing the split was escaped. Merge the items together.
+                auto next = simox::alg::advanced(it, 1);
+                if (next != items.end())
+                {
+                    // "it\" + "next" => "it/next"
+                    *it = it->substr(0, it->size() - 1) + delimiter + *next;
+                    items.erase_after(it); // Invalidates `next`, but not `it`.
+                }
+            }
+        }
 
         auto it = items.begin();
         if (it == items.end())
@@ -55,19 +80,19 @@ namespace armarx::armem
     }
 
 
-    std::string MemoryID::str() const
+    std::string MemoryID::str(bool escapeDelimiters) const
     {
-        return str("/");
+        return str(delimiter, escapeDelimiters);
     }
 
-    std::string MemoryID::str(const std::string& delimeter) const
+    std::string MemoryID::str(const std::string& delimiter, bool escapeDelimiter) const
     {
-        std::vector<std::string> items = getAllItems();
+        std::vector<std::string> items = getAllItems(escapeDelimiter);
         while (items.size() > 0 && items.back().empty())
         {
             items.pop_back();
         }
-        return simox::alg::join(items, delimeter, false, false);
+        return simox::alg::join(items, delimiter, false, false);
     }
 
     std::string MemoryID::getLeafItem() const
@@ -86,52 +111,55 @@ namespace armarx::armem
     bool MemoryID::hasGap() const
     {
         bool emptyFound = false;
-        for (const std::string& name : getAllItems())
+        for (const std::string& item : getAllItems())
         {
-            if (name.empty())
+            if (item.empty())
             {
                 emptyFound = true;
             }
-            else
+            else if (emptyFound)
             {
-                if (emptyFound)
-                {
-                    return true;
-                }
+                // Found a non-empty item after an empty item.
+                return true;
             }
         }
         return false;
     }
 
+    bool MemoryID::isWellDefined() const
+    {
+        return !hasGap();
+    }
+
 
     MemoryID MemoryID::fromString(const std::string& string)
     {
         return MemoryID(string);
     }
 
-    std::vector<std::string> MemoryID::getItems() const
+    std::vector<std::string> MemoryID::getItems(bool escapeDelimiters) const
     {
         std::vector<std::string> items;
 
-        items.push_back(memoryName);
+        items.push_back(escape(memoryName, escapeDelimiters));
 
         if (!hasCoreSegmentName())
         {
             return items;
         }
-        items.push_back(coreSegmentName);
+        items.push_back(escape(coreSegmentName, escapeDelimiters));
 
         if (!hasProviderSegmentName())
         {
             return items;
         }
-        items.push_back(providerSegmentName);
+        items.push_back(escape(providerSegmentName, escapeDelimiters));
 
         if (!hasEntityName())
         {
             return items;
         }
-        items.push_back(entityName);
+        items.push_back(escape(entityName, escapeDelimiters));
 
         if (!hasTimestamp())
         {
@@ -148,11 +176,12 @@ namespace armarx::armem
         return items;
     }
 
-    std::vector<std::string> MemoryID::getAllItems() const
+    std::vector<std::string> MemoryID::getAllItems(bool escapeDelimiters) const
     {
         return
         {
-            memoryName, coreSegmentName, providerSegmentName, entityName,
+            escape(memoryName, escapeDelimiters), escape(coreSegmentName, escapeDelimiters),
+            escape(providerSegmentName, escapeDelimiters), escape(entityName, escapeDelimiters),
             timestampStr(), instanceIndexStr()
         };
     }
@@ -276,6 +305,7 @@ namespace armarx::armem
         return id;
     }
 
+
     std::string MemoryID::timestampStr() const
     {
         return hasTimestamp() ? std::to_string(timestamp.toMicroSeconds()) : "";
@@ -306,8 +336,46 @@ namespace armarx::armem
                and instanceIndex == other.instanceIndex;
     }
 
+    bool MemoryID::operator<(const MemoryID& rhs) const
+    {
+        int c = memoryName.compare(rhs.memoryName);
+        if (c != 0)
+        {
+            return c < 0;
+        }
+        // Equal memory name
+        c = coreSegmentName.compare(rhs.coreSegmentName);
+        if (c != 0)
+        {
+            return c < 0;
+        }
+        // Equal core segment ID
+        c = providerSegmentName.compare(rhs.providerSegmentName);
+        if (c != 0)
+        {
+            return c < 0;
+        }
+        // Equal provider segment ID
+        c = entityName.compare(rhs.entityName);
+        if (c != 0)
+        {
+            return c < 0;
+        }
+        // Equal entity ID
+        if (timestamp != rhs.timestamp)
+        {
+            return timestamp < rhs.timestamp;
+        }
+        // Equal entity snapshot ID
+        return instanceIndex < rhs.instanceIndex;
+    }
+
     long long MemoryID::parseInteger(const std::string& string, const std::string& semanticName)
     {
+        if (string.empty())
+        {
+            return -1;
+        }
         try
         {
             return std::stoll(string);
@@ -322,15 +390,44 @@ namespace armarx::armem
         }
     }
 
+    std::string MemoryID::escapeDelimiter(const std::string& name)
+    {
+        return simox::alg::replace_all(name, delimiter, "\\" + delimiter);
+    }
+
+    std::string MemoryID::escape(const std::string& name, bool escapeDelimiters)
+    {
+        if (escapeDelimiters)
+        {
+            return escapeDelimiter(name);
+        }
+        else
+        {
+            return name;
+        }
+    }
+
     std::ostream& operator<<(std::ostream& os, const MemoryID id)
     {
         return os << "'" << id.str() << "'";
     }
 
 
-    bool
-    contains(const MemoryID& general, const MemoryID& specific)
+    bool contains(const MemoryID& general, const MemoryID& specific)
     {
+        if (!general.isWellDefined())
+        {
+            std::stringstream ss;
+            ss << "ID `general` is not well-defined, which is required for `" << __FUNCTION__ << "()`.";
+            throw error::InvalidMemoryID(general, ss.str());
+        }
+        if (!specific.isWellDefined())
+        {
+            std::stringstream ss;
+            ss << "ID `specific` is not well-defined, which is required for `" << __FUNCTION__ << "()`.";
+            throw error::InvalidMemoryID(specific, ss.str());
+        }
+
         if (general.memoryName.empty())
         {
             return true;
diff --git a/source/RobotAPI/libraries/armem/core/MemoryID.h b/source/RobotAPI/libraries/armem/core/MemoryID.h
index 1fc22f7288b51970f298a9309cbe33b087d48f5f..09415ec4abd73185f77050c89683b326f3c3e9d0 100644
--- a/source/RobotAPI/libraries/armem/core/MemoryID.h
+++ b/source/RobotAPI/libraries/armem/core/MemoryID.h
@@ -12,11 +12,37 @@ namespace armarx::armem
     /**
      * @brief A memory ID.
      *
-     * Structure:
-     * `MemoryName/CoreSegmentName/ProviderSegmentName/EntityName/Timestamp/InstanceIndex`
+     * A memory ID is an index into the hierarchical memory structure.
+     * It specifies the keys for the different levels, starting from the
+     * memory name and ending at the instance index.
      *
-     * Example:
-     * `VisionMemory/RGBImages/PrimesenseRGB/image/1245321323/0`
+     * A memory ID need not be complete, e.g. it may specify only the memory
+     * and core segment names (thus representing a core segment ID).
+     * A memory ID that fully identifies a level starting from the memory is
+     * called well-defined.
+     * @see `isWellDefined()`
+     *
+     * Memory IDs can be encoded in strings using a delimiter:
+     * - Structure: "MemoryName/CoreSegmentName/ProviderSegmentName/EntityName/Timestamp/InstanceIndex"
+     * - Example:   "Vision/RGBImages/Primesense/image/1245321323/0"
+     * @see `str()`
+     *
+     * If an ID does not specify the lower levels, these parts can be omitted.
+     * Thus, an entity ID could look like:
+     * - Structure: "MemoryName/CoreSegmentName/ProviderSegmentName/EntityName"
+     * - Example:   "Vision/RGBImages/Primesense/image"
+     *
+     * If a name contains a "/", it will be escaped:
+     * - Example:   "Vision/RGBImages/Primesense/my\/entity\/with\/slashes"
+     *
+     * Memory IDs may be not well-defined. This can occur e.g. when preparing
+     * an entity instance ID which is still pending the timestamp.
+     * It could look like (note the missing timestamp):
+     * - Example:   "Vision/RGBImages/Primesense/image//0"
+     *
+     * These IDs are still valid and can be handled (encoded as string etc.).
+     * However, some operations may not be well-defined for non-well-defined IDs
+     * (such as `contains()`).
      */
     class MemoryID
     {
@@ -30,26 +56,37 @@ namespace armarx::armem
         int instanceIndex = -1;
 
 
-
     public:
 
+        /// Construct a default (empty) memory ID.
         MemoryID();
+        /// (Re-)Construct a memory ID from a string representation as returned by `str()`.
         explicit MemoryID(const std::string& string);
 
 
-        std::string str() const;
-        std::string str(const std::string& delimeter) const;
-        static MemoryID fromString(const std::string& string);
-
-        std::string timestampStr() const;
-        std::string instanceIndexStr() 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;
-
+        /**
+         * @brief Indicate whether this ID is well-defined.
+         *
+         * A well-defined ID has no specified level after a non-specified level (i.e., no gaps).
+         *
+         * Well-defined examples:
+         * - "" (empty, but well-defined)
+         * - "Memory" (a memory ID)
+         * - "Memory/Core" (a core segment ID)
+         * - "Memory/Core/Provider" (a provider segment ID)
+         *
+         * Non-well-defined examples:
+         * - "Memory//Provider" (no core segment name)
+         * - "/Core" (no memory name)
+         * - "Mem/Core/Prov/entity//0" (no timestamp)
+         * - "///entity//0" (no memory, core segment and provider segment names)
+         *
+         * @return True if `*this` is a well-defined memory ID.
+         */
+        bool isWellDefined() const;
+
+
+        // Checks whether a specific level is specified.
 
         bool hasMemoryName() const
         {
@@ -113,15 +150,49 @@ namespace armarx::armem
         MemoryID withInstanceIndex(int index) const;
 
 
+        // String conversion
+
+        /**
+         * @brief Get a string representation of this memory ID.
+         *
+         * Items are separated by a delimiter. If `escapeDelimiter` is true,
+         * delimiters occuring inside names are escaped with backward slashes.
+         * This allows to reconstruct the memory ID from the result of `str()`
+         * in these cases.
+         *
+         * @param escapeDelimiter If true, escape delimiters inside names
+         * @return A string representation of this MemoryID.
+         */
+        std::string str(bool escapeDelimiters = true) const;
+
+        /// Get the timestamp as string.
+        std::string timestampStr() const;
+        /// Get the instance index as string.
+        std::string instanceIndexStr() const;
+
+        /// Alias for constructor from string.
+        static MemoryID fromString(const std::string& string);
+        /// Reconstruct a timestamp from a string as returned by `timestampStr()`.
+        static Time timestampFromStr(const std::string& timestamp);
+        /// Reconstruct an instance index from a string as returned by `instanceIndexStr()`.
+        static int instanceIndexFromStr(const std::string& index);
+
+
+        /// Get all levels as strings.
+        std::vector<std::string> getAllItems(bool escapeDelimiters = false) const;
+        /// Get the levels from root to first not defined level (excluding).
+        std::vector<std::string> getItems(bool escapeDelimiters = false) const;
+
+
+        // Other utility.
+
         /// 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);
-
+        // Operators
 
         bool operator ==(const MemoryID& other) const;
         inline bool operator !=(const MemoryID& other) const
@@ -129,18 +200,59 @@ namespace armarx::armem
             return !(*this == other);
         }
 
+        bool operator< (const MemoryID& rhs) const;
+        inline bool operator> (const MemoryID& rhs) const
+        {
+            return rhs < (*this);
+        }
+        inline bool operator<=(const MemoryID& rhs) const
+        {
+            return !operator> (rhs);
+        }
+        inline bool operator>=(const MemoryID& rhs) const
+        {
+            return !operator< (rhs);
+        }
+
         friend std::ostream& operator<<(std::ostream& os, const MemoryID id);
 
 
     private:
 
         static long long parseInteger(const std::string& string, const std::string& semanticName);
+        static std::string escapeDelimiter(const std::string& name);
+        static std::string escape(const std::string& name, bool escapeDelimiters);
+
+        static const std::string delimiter;
+
+
+        // Do not allow specifying the delimiter from outside.
+        std::string str(const std::string& delimiter, bool escapeDelimiter) const;
 
     };
 
 
-    bool
-    contains(const MemoryID& general, const MemoryID& specific);
+    /**
+     * @brief Indicates whether `general` is "less specific" than, or equal to, `specific`,
+     * i.e. `general` "contains" `specific`.
+     *
+     * A memory ID A is said to be less specific than B, if B the same values as A
+     * for all levels specified in A, but potentially also specifies the lower levels.
+     *
+     * Examples:
+     * - "" contains ""
+     * - "m" contains "m" and "m/c", but not "n" and "n/c"
+     * - "m/c" contains "m/c" and "m/c/p", but not "m/d" and "m/c/q"
+     *
+     * If a memory ID has a gap (`@see MemoryID::hasGap()`), such as "m//p",
+     * the levels after the gap are ignored.
+     * - "m//p" contains "m", "m/c" and "m/c/p".
+     *
+     * @param general The less specific memory ID
+     * @param specific The more specific memory ID
+     * @return True if `general` is less specific than `specific`.
+     */
+    bool contains(const MemoryID& general, const MemoryID& specific);
 
 }
 
diff --git a/source/RobotAPI/libraries/armem/server/query_proc/EntityQueryProcessor.cpp b/source/RobotAPI/libraries/armem/server/query_proc/EntityQueryProcessor.cpp
index d325f4b9e522ae376bcd598ce8c67c64a2dfdcff..c062c089e31f8cf5c1314e4e4fcd7608ee5f2a48 100644
--- a/source/RobotAPI/libraries/armem/server/query_proc/EntityQueryProcessor.cpp
+++ b/source/RobotAPI/libraries/armem/server/query_proc/EntityQueryProcessor.cpp
@@ -74,6 +74,11 @@ namespace armarx::armem::query_proc
 
     void EntityQueryProcessor::process(Entity& result, const armem::query::data::entity::IndexRange& query, const Entity& entity) const
     {
+        if (entity.empty())
+        {
+            return;
+        }
+
         size_t first = negativeIndexSemantics(query.first, entity.history.size());
         size_t last = negativeIndexSemantics(query.last, entity.history.size());
 
@@ -103,6 +108,8 @@ namespace armarx::armem::query_proc
     void EntityQueryProcessor::process(Entity& result, const Time& min, const Time& max, const Entity& entity,
                                        const armem::query::data::EntityQuery& query) const
     {
+        (void) query;
+
         // Returns an iterator pointing to the first element that is not less than (i.e. greater or equal to) key.
         auto begin = min.toMicroSeconds() > 0 ? entity.history.lower_bound(min) : entity.history.begin();
         // Returns an iterator pointing to the first element that is *greater than* key.
@@ -121,14 +128,14 @@ namespace armarx::armem::query_proc
 
     size_t EntityQueryProcessor::negativeIndexSemantics(long index, size_t size)
     {
-        size_t max = size > 0 ? size - 1 : 0;
+        const size_t max = size > 0 ? size - 1 : 0;
         if (index >= 0)
         {
             return std::clamp<size_t>(static_cast<size_t>(index), 0, max);
         }
         else
         {
-            return std::clamp<size_t>(size - static_cast<size_t>(- index), 0, max);
+            return static_cast<size_t>(std::clamp<long>(static_cast<long>(size) + index, 0, static_cast<long>(max)));
         }
     }
 
diff --git a/source/RobotAPI/libraries/armem/test/ArMemMemoryIDTest.cpp b/source/RobotAPI/libraries/armem/test/ArMemMemoryIDTest.cpp
index d811c053ba4c57864030eaa8b0d5a7485a6df58c..1f94d9adb9a2d023a3813c0e09edf8b41367ace1 100644
--- a/source/RobotAPI/libraries/armem/test/ArMemMemoryIDTest.cpp
+++ b/source/RobotAPI/libraries/armem/test/ArMemMemoryIDTest.cpp
@@ -26,6 +26,7 @@
 
 #include <RobotAPI/Test.h>
 #include "../core/MemoryID.h"
+#include "../core/error.h"
 
 #include <iostream>
 
@@ -33,22 +34,106 @@
 namespace armem = armarx::armem;
 
 
-BOOST_AUTO_TEST_CASE(test_memoryid_contains)
+BOOST_AUTO_TEST_CASE(test_MemoryID_contains)
 {
     armem::MemoryID general, specific;
 
-    BOOST_CHECK(armem::contains(general, specific));
+    // Both empty.
+    BOOST_TEST_CONTEXT(VAROUT(general) << " | " << VAROUT(specific))
+    {
+        BOOST_CHECK(armem::contains(general, specific));
+    }
 
+    // Diverging.
     general.memoryName = "a";
     specific.memoryName = "b";
 
-    BOOST_CHECK(not armem::contains(general, specific));
+    BOOST_TEST_CONTEXT(VAROUT(general) << " | " << VAROUT(specific))
+    {
+        BOOST_CHECK(not armem::contains(general, specific));
+        BOOST_CHECK(not armem::contains(specific, general));
+    }
 
+    // Identical.
     specific.memoryName = "a";
 
-    BOOST_CHECK(armem::contains(general, specific));
+    BOOST_TEST_CONTEXT(VAROUT(general) << " | " << VAROUT(specific))
+    {
+        BOOST_CHECK(armem::contains(general, specific));
+        BOOST_CHECK(armem::contains(specific, general));
+    }
 
-    specific.providerSegmentName = "aa";
+    // general contains specific
+    specific.coreSegmentName = "c";
+
+    BOOST_TEST_CONTEXT(VAROUT(general) << " | " << VAROUT(specific))
+    {
+        BOOST_CHECK(armem::contains(general, specific));
+        BOOST_CHECK(not armem::contains(specific, general));
+    }
+
+    // general contains specific
+    specific.providerSegmentName = "d";
+
+    BOOST_TEST_CONTEXT(VAROUT(general) << " | " << VAROUT(specific))
+    {
+        BOOST_CHECK(armem::contains(general, specific));
+        BOOST_CHECK(not armem::contains(specific, general));
+    }
+
+    // Not well-defined ID - throw an exception.
+    specific.coreSegmentName.clear();
+
+    BOOST_TEST_CONTEXT(VAROUT(general) << " | " << VAROUT(specific))
+    {
+        BOOST_CHECK_THROW(armem::contains(general, specific), armem::error::InvalidMemoryID);
+        BOOST_CHECK_THROW(armem::contains(specific, general), armem::error::InvalidMemoryID);
+    }
+}
+
+
+
+BOOST_AUTO_TEST_CASE(test_MemoryID_from_to_string)
+{
+    armem::MemoryID idIn {"Memory/Core/Prov/entity/2810381/2"};
+
+    BOOST_CHECK_EQUAL(idIn.memoryName, "Memory");
+    BOOST_CHECK_EQUAL(idIn.coreSegmentName, "Core");
+    BOOST_CHECK_EQUAL(idIn.providerSegmentName, "Prov");
+    BOOST_CHECK_EQUAL(idIn.entityName, "entity");
+    BOOST_CHECK_EQUAL(idIn.timestamp, IceUtil::Time::microSeconds(2810381));
+    BOOST_CHECK_EQUAL(idIn.instanceIndex, 2);
+
+
+    BOOST_TEST_CONTEXT(VAROUT(idIn.str()))
+    {
+        armem::MemoryID idOut(idIn.str());
+        BOOST_CHECK_EQUAL(idOut, idIn);
+    }
+
+    idIn.entityName = "KIT/Amicelli/0";  // Like an ObjectID
+    BOOST_CHECK_EQUAL(idIn.entityName, "KIT/Amicelli/0");
+
+    BOOST_TEST_CONTEXT(VAROUT(idIn.str()))
+    {
+        armem::MemoryID idOut(idIn.str());
+        BOOST_CHECK_EQUAL(idOut.entityName, "KIT/Amicelli/0");
+        BOOST_CHECK_EQUAL(idOut, idIn);
+    }
+
+    idIn = armem::MemoryID {"InThe\\/Mid/AtTheEnd\\//\\/AtTheStart/YCB\\/sugar\\/-1//2"};
+    BOOST_CHECK_EQUAL(idIn.memoryName, "InThe/Mid");
+    BOOST_CHECK_EQUAL(idIn.coreSegmentName, "AtTheEnd/");
+    BOOST_CHECK_EQUAL(idIn.providerSegmentName, "/AtTheStart");
+    BOOST_CHECK_EQUAL(idIn.entityName, "YCB/sugar/-1");
+    BOOST_CHECK_EQUAL(idIn.timestamp, IceUtil::Time::microSeconds(-1));
+    BOOST_CHECK_EQUAL(idIn.instanceIndex, 2);
+
+    BOOST_TEST_CONTEXT(VAROUT(idIn.str()))
+    {
+        armem::MemoryID idOut(idIn.str());
+        BOOST_CHECK_EQUAL(idOut, idIn);
+    }
 
-    BOOST_CHECK(armem::contains(general, specific));
 }
+
diff --git a/source/RobotAPI/libraries/armem/test/ArMemQueryTest.cpp b/source/RobotAPI/libraries/armem/test/ArMemQueryTest.cpp
index f36411237759df97bf1ff0beb81d60cfec95f59a..b35fb39452fd014e7d9a7bec6353ca181b5a14e2 100644
--- a/source/RobotAPI/libraries/armem/test/ArMemQueryTest.cpp
+++ b/source/RobotAPI/libraries/armem/test/ArMemQueryTest.cpp
@@ -119,10 +119,10 @@ BOOST_AUTO_TEST_CASE(test_entity_Single_latest)
     addResults(query::entity::Single());
     BOOST_REQUIRE_GT(results.size(), 0);
 
-    for (const auto& result : results)
+    for (const armem::Entity& result : results)
     {
         BOOST_CHECK_EQUAL(result.name(), entity.name());
-        BOOST_CHECK_EQUAL(result.history.size(), 1);
+        BOOST_CHECK_EQUAL(result.size(), 1);
         BOOST_CHECK_EQUAL(result.history.begin()->second.time(), entity.getLatestSnapshot().time());
         BOOST_CHECK_NE(&result.history.begin()->second, &entity.history.rbegin()->second);
     }
@@ -134,10 +134,10 @@ BOOST_AUTO_TEST_CASE(test_entity_Single_existing)
     addResults(query::entity::Single { 3000 });
     BOOST_REQUIRE_GT(results.size(), 0);
 
-    for (const auto& result : results)
+    for (const armem::Entity& result : results)
     {
         BOOST_CHECK_EQUAL(result.name(), entity.name());
-        BOOST_CHECK_EQUAL(result.history.size(), 1);
+        BOOST_CHECK_EQUAL(result.size(), 1);
         BOOST_CHECK_EQUAL(result.history.begin()->second.time(), armem::Time::microSeconds(3000));
     }
 }
@@ -148,10 +148,10 @@ BOOST_AUTO_TEST_CASE(test_entity_Single_non_existing)
     addResults(query::entity::Single { 3500 });
     BOOST_REQUIRE_GT(results.size(), 0);
 
-    for (const auto& result : results)
+    for (const armem::Entity& result : results)
     {
         BOOST_CHECK_EQUAL(result.name(), entity.name());
-        BOOST_CHECK_EQUAL(result.history.size(), 0);
+        BOOST_CHECK_EQUAL(result.size(), 0);
     }
 }
 
@@ -161,10 +161,10 @@ BOOST_AUTO_TEST_CASE(test_entity_All)
     addResults(query::entity::All());
     BOOST_REQUIRE_GT(results.size(), 0);
 
-    for (const auto& result : results)
+    for (const armem::Entity& result : results)
     {
         BOOST_CHECK_EQUAL(result.name(), entity.name());
-        BOOST_CHECK_EQUAL(result.history.size(), entity.history.size());
+        BOOST_CHECK_EQUAL(result.size(), entity.size());
         auto jt = entity.history.begin();
         for (auto it = result.history.begin(); it != result.history.end(); ++it, ++jt)
         {
@@ -182,11 +182,11 @@ BOOST_AUTO_TEST_CASE(test_entity_TimeRange_slice)
     addResults(query::entity::TimeRange{ 1500, 3500 });
     BOOST_REQUIRE_GT(results.size(), 0);
 
-    for (const auto& result : results)
+    for (const armem::Entity& result : results)
     {
         BOOST_CHECK_EQUAL(result.name(), entity.name());
 
-        BOOST_CHECK_EQUAL(result.history.size(), 2);
+        BOOST_CHECK_EQUAL(result.size(), 2);
 
         std::vector<armem::Time> times = simox::alg::get_keys(result.history);
         std::vector<armem::Time> expected
@@ -203,11 +203,11 @@ BOOST_AUTO_TEST_CASE(test_entity_TimeRange_exact)
     addResults(query::entity::TimeRange{ 2000, 4000 });
     BOOST_REQUIRE_GT(results.size(), 0);
 
-    for (const auto& result : results)
+    for (const armem::Entity& result : results)
     {
         BOOST_CHECK_EQUAL(result.name(), entity.name());
 
-        BOOST_CHECK_EQUAL(result.history.size(), 3);
+        BOOST_CHECK_EQUAL(result.size(), 3);
 
         std::vector<armem::Time> times = simox::alg::get_keys(result.history);
         std::vector<armem::Time> expected
@@ -224,11 +224,11 @@ BOOST_AUTO_TEST_CASE(test_entity_TimeRange_all)
     addResults(query::entity::TimeRange{ -1, -1 });
     BOOST_REQUIRE_GT(results.size(), 0);
 
-    for (const auto& result : results)
+    for (const armem::Entity& result : results)
     {
         BOOST_CHECK_EQUAL(result.name(), entity.name());
 
-        BOOST_CHECK_EQUAL(result.history.size(), entity.history.size());
+        BOOST_CHECK_EQUAL(result.size(), entity.size());
 
         std::vector<armem::Time> times = simox::alg::get_keys(result.history);
         std::vector<armem::Time> expected = simox::alg::get_keys(entity.history);
@@ -243,11 +243,11 @@ BOOST_AUTO_TEST_CASE(test_entity_TimeRange_empty)
     addResults(query::entity::TimeRange{ 6000, 1000 });
     BOOST_REQUIRE_GT(results.size(), 0);
 
-    for (const auto& result : results)
+    for (const armem::Entity& result : results)
     {
         BOOST_CHECK_EQUAL(result.name(), entity.name());
 
-        BOOST_CHECK_EQUAL(result.history.size(), 0);
+        BOOST_CHECK_EQUAL(result.size(), 0);
     }
 }
 
@@ -257,11 +257,11 @@ BOOST_AUTO_TEST_CASE(test_entity_TimeRange_from_start)
     addResults(query::entity::TimeRange{ -1, 2500 });
     BOOST_REQUIRE_GT(results.size(), 0);
 
-    for (const auto& result : results)
+    for (const armem::Entity& result : results)
     {
         BOOST_CHECK_EQUAL(result.name(), entity.name());
 
-        BOOST_CHECK_EQUAL(result.history.size(), 2);
+        BOOST_CHECK_EQUAL(result.size(), 2);
 
         std::vector<armem::Time> times = simox::alg::get_keys(result.history);
         std::vector<armem::Time> expected
@@ -278,11 +278,11 @@ BOOST_AUTO_TEST_CASE(test_entity_TimeRange_to_end)
     addResults(query::entity::TimeRange{ 2500, -1 });
     BOOST_REQUIRE_GT(results.size(), 0);
 
-    for (const auto& result : results)
+    for (const armem::Entity& result : results)
     {
         BOOST_CHECK_EQUAL(result.name(), entity.name());
 
-        BOOST_CHECK_EQUAL(result.history.size(), 3);
+        BOOST_CHECK_EQUAL(result.size(), 3);
 
         std::vector<armem::Time> times = simox::alg::get_keys(result.history);
         std::vector<armem::Time> expected
@@ -314,10 +314,15 @@ BOOST_AUTO_TEST_CASE(test_negative_index_semantics)
     BOOST_CHECK_EQUAL(EntityQueryProcessor::negativeIndexSemantics(-1, 1), 0);
     BOOST_CHECK_EQUAL(EntityQueryProcessor::negativeIndexSemantics(-5, 1), 0);
 
+    BOOST_CHECK_EQUAL(EntityQueryProcessor::negativeIndexSemantics(-1, 2), 1);
+    BOOST_CHECK_EQUAL(EntityQueryProcessor::negativeIndexSemantics(-5, 2), 0);
+
     BOOST_CHECK_EQUAL(EntityQueryProcessor::negativeIndexSemantics(-1, 5), 4);
     BOOST_CHECK_EQUAL(EntityQueryProcessor::negativeIndexSemantics(-5, 5), 0);
     BOOST_CHECK_EQUAL(EntityQueryProcessor::negativeIndexSemantics(-5, 6), 1);
     BOOST_CHECK_EQUAL(EntityQueryProcessor::negativeIndexSemantics(-5, 10), 5);
+    BOOST_CHECK_EQUAL(EntityQueryProcessor::negativeIndexSemantics(-10, 10), 0);
+    BOOST_CHECK_EQUAL(EntityQueryProcessor::negativeIndexSemantics(-20, 10), 0);
 }
 
 
@@ -327,11 +332,11 @@ BOOST_AUTO_TEST_CASE(test_entity_IndexRange_all_default)
     addResults(query::entity::IndexRange(0, -1));
     BOOST_REQUIRE_GT(results.size(), 0);
 
-    for (const auto& result : results)
+    for (const armem::Entity& result : results)
     {
         BOOST_CHECK_EQUAL(result.name(), entity.name());
 
-        BOOST_CHECK_EQUAL(result.history.size(), entity.history.size());
+        BOOST_CHECK_EQUAL(result.size(), entity.size());
 
         std::vector<armem::Time> times = simox::alg::get_keys(result.history);
         std::vector<armem::Time> expected = simox::alg::get_keys(entity.history);
@@ -350,11 +355,11 @@ BOOST_AUTO_TEST_CASE(test_entity_IndexRange_slice)
     addResults(query::entity::IndexRange{ -4, -2 });
     BOOST_REQUIRE_GT(results.size(), 0);
 
-    for (const auto& result : results)
+    for (const armem::Entity& result : results)
     {
         BOOST_CHECK_EQUAL(result.name(), entity.name());
 
-        BOOST_CHECK_EQUAL(result.history.size(), 3);
+        BOOST_CHECK_EQUAL(result.size(), 3);
 
         std::vector<armem::Time> times = simox::alg::get_keys(result.history);
         std::vector<armem::Time> expected
@@ -366,7 +371,7 @@ BOOST_AUTO_TEST_CASE(test_entity_IndexRange_slice)
 }
 
 
-BOOST_AUTO_TEST_CASE(test_entity_IndexRange_empty)
+BOOST_AUTO_TEST_CASE(test_entity_IndexRange_empty_range)
 {
     BOOST_REQUIRE_EQUAL(entity.size(), 5);
     addResults(query::entity::IndexRange{  1,  0 });
@@ -378,16 +383,34 @@ BOOST_AUTO_TEST_CASE(test_entity_IndexRange_empty)
 
     BOOST_REQUIRE_GT(results.size(), 0);
 
-    for (const auto& result : results)
+    for (const armem::Entity& result : results)
     {
         BOOST_CHECK_EQUAL(result.name(), entity.name());
 
-        BOOST_CHECK_EQUAL(result.history.size(), 0);
+        BOOST_CHECK_EQUAL(result.size(), 0);
     }
 }
 
 
+BOOST_AUTO_TEST_CASE(test_entity_IndexRange_empty_entity)
+{
+    entity.clear();
+    BOOST_REQUIRE_EQUAL(entity.size(), 0);
+    addResults(query::entity::IndexRange{  0,  0 });
+    addResults(query::entity::IndexRange{  0, 10 });
+    addResults(query::entity::IndexRange{-10, -1 });
+    addResults(query::entity::IndexRange{  2,  5 });
+    addResults(query::entity::IndexRange{  3, -3 });
+    addResults(query::entity::IndexRange{ -1, 10 });
+
+    BOOST_REQUIRE_GT(results.size(), 0);
 
+    for (const armem::Entity& result : results)
+    {
+        BOOST_CHECK_EQUAL(result.name(), entity.name());
+        BOOST_CHECK_EQUAL(result.size(), 0);
+    }
+}
 
 
 BOOST_AUTO_TEST_SUITE_END()