diff --git a/source/RobotAPI/components/armem/server/ObjectMemory/ObjectMemory.cpp b/source/RobotAPI/components/armem/server/ObjectMemory/ObjectMemory.cpp
index 76d042a9ecd96b1d6f03814efe6cfb8d609eb0d5..da5440d7da1443c59b3414d48988505f6a298d8f 100644
--- a/source/RobotAPI/components/armem/server/ObjectMemory/ObjectMemory.cpp
+++ b/source/RobotAPI/components/armem/server/ObjectMemory/ObjectMemory.cpp
@@ -143,8 +143,8 @@ namespace armarx::armem::server::obj
         // TODO: the instance segment should check the provided object poses and instantiate the needed robots by itself.
         ARMARX_CHECK_NOT_NULL(virtualRobotReaderPlugin);
         
-        VirtualRobot::RobotPtr robot = virtualRobotReaderPlugin->get().getSynchronizedRobot(
-                    robotName, VirtualRobot::RobotIO::RobotDescription::eStructure, true);
+        VirtualRobot::RobotPtr robot = virtualRobotReaderPlugin->get().getRobot(
+                    robotName, Clock::Now(), VirtualRobot::RobotIO::RobotDescription::eStructure);
         ARMARX_CHECK_NOT_NULL(robot);
 
         getProxyFromProperty(kinematicUnitObserver, "cmp.KinematicUnitObserverName", false, "", false);
diff --git a/source/RobotAPI/components/units/PlatformUnit.cpp b/source/RobotAPI/components/units/PlatformUnit.cpp
index b60e943849edd0720eb9b523ee6518e0fced18df..4cbf370ff4803d16e103684877a9b0353d6d0526 100644
--- a/source/RobotAPI/components/units/PlatformUnit.cpp
+++ b/source/RobotAPI/components/units/PlatformUnit.cpp
@@ -38,6 +38,7 @@ namespace armarx
 
         def->topic(odometryPrx);
         def->topic(globalPosePrx);
+        def->topic(listenerPrx, listenerChannelName, "");
 
         def->component(robotStateComponent);
 
@@ -58,8 +59,6 @@ namespace armarx
 
     void PlatformUnit::onConnectComponent()
     {
-        listenerPrx = getTopic<PlatformUnitListenerPrx>(listenerChannelName);
-
         this->onStartPlatformUnit();
     }
 
diff --git a/source/RobotAPI/components/units/PlatformUnit.h b/source/RobotAPI/components/units/PlatformUnit.h
index 097de6689522498722a1ec499b83cbeb12c5fa25..1b0b9499a4f50e6ec0b64631aaf9f85c9fa5bca5 100644
--- a/source/RobotAPI/components/units/PlatformUnit.h
+++ b/source/RobotAPI/components/units/PlatformUnit.h
@@ -133,4 +133,3 @@ namespace armarx
 
     PlatformPose toPlatformPose(const TransformStamped& transformStamped);
 }
-
diff --git a/source/RobotAPI/components/units/RobotUnit/CMakeLists.txt b/source/RobotAPI/components/units/RobotUnit/CMakeLists.txt
index bcbf667a05a4bf246cc074c2f253ed2f08f56810..afb8f6a0c352085ffc08e72e7f0c74f1f419680f 100755
--- a/source/RobotAPI/components/units/RobotUnit/CMakeLists.txt
+++ b/source/RobotAPI/components/units/RobotUnit/CMakeLists.txt
@@ -34,6 +34,7 @@ set(LIB_FILES
     Units/InertialMeasurementSubUnit.cpp
     Units/KinematicSubUnit.cpp
     Units/PlatformSubUnit.cpp
+    Units/LocalizationSubUnit.cpp
     Units/TrajectoryControllerSubUnit.cpp
     Units/TCPControllerSubUnit.cpp
 
@@ -57,6 +58,9 @@ set(LIB_FILES
 
     Devices/SensorDevice.cpp
     Devices/ControlDevice.cpp
+
+    Devices/GlobalRobotPoseSensorDevice.cpp
+
 )
 set(LIB_HEADERS
     util.h
@@ -105,6 +109,7 @@ set(LIB_HEADERS
     Units/InertialMeasurementSubUnit.h
     Units/KinematicSubUnit.h
     Units/PlatformSubUnit.h
+    Units/LocalizationSubUnit.h
     Units/TrajectoryControllerSubUnit.h
     Units/TCPControllerSubUnit.h
 
@@ -133,6 +138,7 @@ set(LIB_HEADERS
     Devices/ControlDevice.h
 
     Devices/RTThreadTimingsSensorDevice.h
+    Devices/GlobalRobotPoseSensorDevice.h
 )
 ###########################################################################
 #since the robot unit is a complex class, it is split into several modules.
diff --git a/source/RobotAPI/components/units/RobotUnit/Devices/GlobalRobotPoseSensorDevice.cpp b/source/RobotAPI/components/units/RobotUnit/Devices/GlobalRobotPoseSensorDevice.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..57f7cf102806a02d1bf502eaf5920e6b43dfff3f
--- /dev/null
+++ b/source/RobotAPI/components/units/RobotUnit/Devices/GlobalRobotPoseSensorDevice.cpp
@@ -0,0 +1,158 @@
+#include "GlobalRobotPoseSensorDevice.h"
+#include "ArmarXCore/core/logging/Logging.h"
+
+#include <SimoxUtility/math/convert/pos_rpy_to_mat4f.h>
+
+namespace armarx
+{
+    SensorValueBase::SensorValueInfo<SensorValueGlobalPoseCorrection>
+    SensorValueGlobalPoseCorrection::GetClassMemberInfo()
+    {
+        SensorValueInfo<SensorValueGlobalPoseCorrection> svi;
+        svi.addMemberVariable(&SensorValueGlobalPoseCorrection::global_T_odom, "global_T_odom")
+            .setVariantReportFrame("", GlobalFrame);
+        return svi;
+    }
+
+
+    bool
+    SensorValueGlobalPoseCorrection::isAvailable() const
+    {
+        return not global_T_odom.isIdentity();
+    }
+
+    SensorValueBase::SensorValueInfo<SensorValueGlobalRobotPose>
+    SensorValueGlobalRobotPose::GetClassMemberInfo()
+    {
+        SensorValueInfo<SensorValueGlobalRobotPose> svi;
+        svi.addMemberVariable(&SensorValueGlobalRobotPose::global_T_root, "global_T_root")
+            .setVariantReportFrame("", GlobalFrame);
+        return svi;
+    }
+
+
+    bool
+    SensorValueGlobalRobotPose::isAvailable() const
+    {
+        return not global_T_root.isIdentity();
+    }
+
+
+    std::string
+    GlobalRobotPoseCorrectionSensorDevice::DeviceName()
+    {
+        return "GlobalRobotPoseCorrectionSensorDevice";
+    }
+
+
+    GlobalRobotPoseCorrectionSensorDevice::GlobalRobotPoseCorrectionSensorDevice() :
+        DeviceBase(DeviceName()), SensorDevice(DeviceName())
+    {
+        transformationBuffer.reinitAllBuffers(SensorValueType::Transformation::Identity());
+    }
+
+
+    const SensorValueBase*
+    GlobalRobotPoseCorrectionSensorDevice::getSensorValue() const
+    {
+        return &sensor;
+    }
+
+
+    std::string
+    GlobalRobotPoseCorrectionSensorDevice::getReportingFrame() const
+    {
+        return GlobalFrame;
+    }
+
+
+    void
+    GlobalRobotPoseCorrectionSensorDevice::rtReadSensorValues(
+        const IceUtil::Time& sensorValuesTimestamp,
+        const IceUtil::Time& timeSinceLastIteration)
+    {
+        sensor.global_T_odom = transformationBuffer.getUpToDateReadBuffer();
+    }
+
+
+    void
+    GlobalRobotPoseCorrectionSensorDevice::updateGlobalPositionCorrection(
+        const SensorValueType::Transformation& global_T_odom)
+    {
+        transformationBuffer.getWriteBuffer() = global_T_odom;
+        transformationBuffer.commitWrite();
+    }
+
+
+    std::string
+    GlobalRobotPoseSensorDevice::DeviceName()
+    {
+        return "GlobalRobotPoseSensorDevice";
+    }
+
+
+    GlobalRobotPoseSensorDevice::GlobalRobotPoseSensorDevice() :
+        DeviceBase(DeviceName()), SensorDevice(DeviceName())
+    {
+    }
+
+
+    const SensorValueBase*
+    GlobalRobotPoseSensorDevice::getSensorValue() const
+    {
+        return &sensor;
+    }
+
+
+    std::string
+    GlobalRobotPoseSensorDevice::getReportingFrame() const
+    {
+        return GlobalFrame;
+    }
+
+
+    void
+    GlobalRobotPoseSensorDevice::rtReadSensorValues(const IceUtil::Time& sensorValuesTimestamp,
+                                                    const IceUtil::Time& timeSinceLastIteration)
+    {
+    }
+
+
+    std::string
+    GlobalRobotLocalizationSensorDevice::DeviceName()
+    {
+        return "GlobalRobotLocalizationSensorDevice";
+    }
+
+
+    GlobalRobotLocalizationSensorDevice::GlobalRobotLocalizationSensorDevice() :
+        DeviceBase(DeviceName()), SensorDevice(DeviceName())
+    {
+    }
+
+
+    void
+    GlobalRobotLocalizationSensorDevice::rtReadSensorValues(
+        const IceUtil::Time& sensorValuesTimestamp,
+        const IceUtil::Time& timeSinceLastIteration)
+    {
+
+        if (sensorGlobalPositionCorrection == nullptr or sensorRelativePosition == nullptr)
+        {
+            ARMARX_ERROR << "one of the sensors is not available";
+            return;
+        }
+
+        const auto global_T_relative = sensorGlobalPositionCorrection->global_T_odom;
+        const auto relative_T_robot =
+            simox::math::pos_rpy_to_mat4f(sensorRelativePosition->relativePositionX,
+                                          sensorRelativePosition->relativePositionY,
+                                          0,
+                                          0,
+                                          0,
+                                          sensorRelativePosition->relativePositionRotation);
+        const auto global_T_robot = global_T_relative * relative_T_robot;
+
+        sensor.global_T_root = global_T_robot;
+    }
+} // namespace armarx
diff --git a/source/RobotAPI/components/units/RobotUnit/Devices/GlobalRobotPoseSensorDevice.h b/source/RobotAPI/components/units/RobotUnit/Devices/GlobalRobotPoseSensorDevice.h
new file mode 100644
index 0000000000000000000000000000000000000000..c3cd19f4a3777a6903ceca8b4a1e8660f25b617b
--- /dev/null
+++ b/source/RobotAPI/components/units/RobotUnit/Devices/GlobalRobotPoseSensorDevice.h
@@ -0,0 +1,120 @@
+
+#pragma once
+
+#include <Eigen/Core>
+
+#include "ArmarXCore/core/logging/Logging.h"
+#include "ArmarXCore/util/CPPUtility/TripleBuffer.h"
+
+#include "RobotAPI/components/units/RobotUnit/SensorValues/SensorValueHolonomicPlatform.h"
+#include <RobotAPI/components/units/RobotUnit/Devices/SensorDevice.h>
+#include <RobotAPI/components/units/RobotUnit/SensorValues/SensorValueBase.h>
+#include <RobotAPI/libraries/core/FramedPose.h>
+
+namespace armarx
+{
+
+    /**
+    * @brief The pose correction to obtain the robot's global pose.
+    *
+    * In conjunction with the SensorValueHolonomicPlatformRelativePosition
+    * information, the global robot pose can be obtained which
+    * - provides the robot's initial localization within the map
+    * - compensates odometry drift over time.
+    *
+    */
+    class SensorValueGlobalPoseCorrection : virtual public SensorValueBase
+    {
+    public:
+        using Transformation = Eigen::Matrix4f;
+        Transformation global_T_odom = Transformation::Identity();
+
+        // TODO add timestamp
+
+        static SensorValueInfo<SensorValueGlobalPoseCorrection> GetClassMemberInfo();
+
+        bool isAvailable() const;
+
+        DETAIL_SensorValueBase_DEFAULT_METHOD_IMPLEMENTATION
+    };
+
+
+    class SensorValueGlobalRobotPose : virtual public SensorValueBase
+    {
+    public:
+        using Transformation = Eigen::Matrix4f;
+        Transformation global_T_root = Transformation::Identity();
+
+        static SensorValueInfo<SensorValueGlobalRobotPose> GetClassMemberInfo();
+
+        bool isAvailable() const;
+
+        DETAIL_SensorValueBase_DEFAULT_METHOD_IMPLEMENTATION
+    };
+
+    TYPEDEF_PTRS_SHARED(GlobalRobotPoseCorrectionSensorDevice);
+    class GlobalRobotPoseCorrectionSensorDevice : virtual public SensorDevice
+    {
+    public:
+        using SensorValueType = SensorValueGlobalPoseCorrection;
+
+        static std::string DeviceName();
+
+        GlobalRobotPoseCorrectionSensorDevice();
+
+        const SensorValueBase* getSensorValue() const override;
+
+        std::string getReportingFrame() const override;
+
+        void rtReadSensorValues(const IceUtil::Time& sensorValuesTimestamp,
+                                const IceUtil::Time& timeSinceLastIteration) override;
+
+        void updateGlobalPositionCorrection(const SensorValueType::Transformation& global_T_odom);
+
+    private:
+        SensorValueType sensor;
+
+        TripleBuffer<SensorValueType::Transformation> transformationBuffer;
+    };
+
+
+    TYPEDEF_PTRS_SHARED(GlobalRobotPoseSensorDevice);
+    class GlobalRobotPoseSensorDevice : virtual public SensorDevice
+    {
+    public:
+        using SensorValueType = SensorValueGlobalRobotPose;
+
+        static std::string DeviceName();
+
+        GlobalRobotPoseSensorDevice();
+
+        const SensorValueBase* getSensorValue() const override;
+
+        std::string getReportingFrame() const override;
+
+        void rtReadSensorValues(const IceUtil::Time& sensorValuesTimestamp,
+                                const IceUtil::Time& timeSinceLastIteration) override;
+
+    protected:
+        SensorValueType sensor;
+    };
+
+
+    TYPEDEF_PTRS_SHARED(GlobalRobotPoseSensorDevice);
+    class GlobalRobotLocalizationSensorDevice : virtual public GlobalRobotPoseSensorDevice
+    {
+    public:
+        static std::string DeviceName();
+
+        GlobalRobotLocalizationSensorDevice();
+
+        void rtReadSensorValues(const IceUtil::Time& sensorValuesTimestamp,
+                                const IceUtil::Time& timeSinceLastIteration) override;
+
+        const SensorValueGlobalPoseCorrection* sensorGlobalPositionCorrection;
+        const SensorValueHolonomicPlatformRelativePosition* sensorRelativePosition;
+
+    };
+
+
+} // namespace armarx
diff --git a/source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointHolonomicPlatformGlobalPositionController.cpp b/source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointHolonomicPlatformGlobalPositionController.cpp
index 013af71634177b541922df2733ad495098b435eb..074efbc511936171b36d34acd0adbac87a1dde8a 100755
--- a/source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointHolonomicPlatformGlobalPositionController.cpp
+++ b/source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointHolonomicPlatformGlobalPositionController.cpp
@@ -22,9 +22,13 @@
  *             GNU General Public License
  */
 #include "NJointHolonomicPlatformGlobalPositionController.h"
+#include "ArmarXCore/core/logging/Logging.h"
+#include "RobotAPI/components/units/RobotUnit/util/ControlThreadOutputBuffer.h"
 
 #include <RobotAPI/components/units/RobotUnit/NJointControllers/NJointControllerRegistry.h>
 
+#include <SimoxUtility/math/convert/mat3f_to_rpy.h>
+#include <SimoxUtility/math/convert/mat4f_to_rpy.h>
 #include <SimoxUtility/math/periodic/periodic_clamp.h>
 #include <cmath>
 
@@ -42,8 +46,8 @@ namespace armarx
         opid(cfg->p_rot, cfg->i_rot, cfg->d_rot, cfg->maxRotationVelocity, cfg->maxRotationAcceleration, true)
 
     {
-        const SensorValueBase* sv = useSensorValue(cfg->platformName);
-        this->sv = sv->asA<SensorValueHolonomicPlatform>();
+        const SensorValueBase* sv = useSensorValue(GlobalRobotLocalizationSensorDevice::DeviceName());
+        this->sv = sv->asA<GlobalRobotLocalizationSensorDevice::SensorValueType>();
         target = useControlTarget(cfg->platformName, ControlModes::HolonomicPlatformVelocity)->asA<ControlTargetHolonomicPlatformVelocity>();
 
 
@@ -55,45 +59,64 @@ namespace armarx
 
     void NJointHolonomicPlatformGlobalPositionController::rtRun(const IceUtil::Time& currentTime, const IceUtil::Time& timeSinceLastIteration)
     {
-        currentPosition << sv->relativePositionX, sv->relativePositionY;
-        currentOrientation = sv->relativePositionRotation;
+        const auto global_T_robot = sv->global_T_root;
 
+        const Eigen::Vector3f rpy = simox::math::mat4f_to_rpy(global_T_robot);
+        const float global_orientation = rpy.z();
+        const Eigen::Vector2f global_P_robot = global_T_robot.block<2,1>(0,3);
 
         if (rtGetControlStruct().newTargetSet)
         {
             pid.reset();
             opid.reset();
 
-        getWriterControlStruct().newTargetSet = false;
-        writeControlStruct();
+            getWriterControlStruct().newTargetSet = false;
+            writeControlStruct();
 	
-            isAborted = false;
+            isTargetSet = true;
         }
-        if (isAborted)
+
+
+        // if ((sv->lastUpdate + IceUtil::Time::seconds(2)) < currentTime)
+        // {
+        //     ARMARX_RT_LOGF_WARNING  << deactivateSpam(0.5) << "Waiting for global pos";
+
+        //     target->velocityX = 0;
+        //     target->velocityY = 0;
+
+        //     target->velocityRotation = 0;
+        //     isAborted = true;
+
+        //     return;
+        // }
+
+        if (not isTargetSet)
         {
+            target->velocityX = 0;
+            target->velocityY = 0;
+            target->velocityRotation = 0;
+
             return;
         }
-        else if ((rtGetControlStruct().lastUpdate + IceUtil::Time::seconds(2)) < currentTime)
-        {
-            // ARMARX_RT_LOGF_WARNING  << deactivateSpam(0.5) << "Waiting for global pos";
 
+        if(not sv->isAvailable())
+        {
+            // ARMARX_RT_LOGF_INFO << deactivateSpam(1) << "global pose not available";
             target->velocityX = 0;
             target->velocityY = 0;
-
             target->velocityRotation = 0;
-            isAborted = true;
 
             return;
         }
 
-        const float measuredOrientation = rtGetControlStruct().globalOrientation;
+        const float measuredOrientation = global_orientation;
 
-        pid.update(timeSinceLastIteration.toSecondsDouble(), rtGetControlStruct().globalPosition, rtGetControlStruct().target);
+        pid.update(timeSinceLastIteration.toSecondsDouble(), global_P_robot, rtGetControlStruct().target);
         opid.update(timeSinceLastIteration.toSecondsDouble(), static_cast<double>(measuredOrientation), rtGetControlStruct().targetOrientation);
 
         const Eigen::Rotation2Df global_R_local(-measuredOrientation);
+        const Eigen::Vector2f velocities = global_R_local * pid.getControlValue();
 
-        Eigen::Vector2f velocities = global_R_local * pid.getControlValue();
         target->velocityX = velocities.x();
         target->velocityY = velocities.y();
         target->velocityRotation = static_cast<float>(opid.getControlValue());
@@ -101,6 +124,9 @@ namespace armarx
 
     void NJointHolonomicPlatformGlobalPositionController::rtPreActivateController()
     {
+        target->velocityX = 0;
+        target->velocityY = 0;
+        target->velocityRotation = 0;
     }
 
     void NJointHolonomicPlatformGlobalPositionController::setTarget(float x, float y, float yaw, float translationAccuracy, float rotationAccuracy)
@@ -111,28 +137,12 @@ namespace armarx
 
         getWriterControlStruct().target << x, y;
         getWriterControlStruct().targetOrientation = simox::math::periodic_clamp(yaw, -M_PIf32, M_PIf32);
+
         getWriterControlStruct().translationAccuracy = translationAccuracy;
         getWriterControlStruct().rotationAccuracy = rotationAccuracy;
+        
         getWriterControlStruct().newTargetSet = true;
         writeControlStruct();
     }
 
-
-    void NJointHolonomicPlatformGlobalPositionController::setGlobalPos(const PlatformPose& currentPose)
-    {
-        // ..todo: check if norm is too large
-
-        getWriterControlStruct().globalPosition << currentPose.x, currentPose.y;
-        getWriterControlStruct().globalOrientation = simox::math::periodic_clamp(currentPose.rotationAroundZ, -M_PIf32, M_PIf32);
-
-        getWriterControlStruct().startPosition = currentPosition;
-        getWriterControlStruct().startOrientation = currentOrientation;
-
-        getWriterControlStruct().lastUpdate = IceUtil::Time::microSeconds(currentPose.timestampInMicroSeconds);
-        writeControlStruct();
-
-
-    }
-
 } // namespace armarx
-
diff --git a/source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointHolonomicPlatformGlobalPositionController.h b/source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointHolonomicPlatformGlobalPositionController.h
index a343e404f97f759d232669b2a1ed72c5b49bd861..37a0de6feb1720dc702b1b5e5dd356b36e974399 100755
--- a/source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointHolonomicPlatformGlobalPositionController.h
+++ b/source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointHolonomicPlatformGlobalPositionController.h
@@ -34,6 +34,7 @@
 #include "../SensorValues/SensorValueHolonomicPlatform.h"
 
 #include "../ControlTargets/ControlTarget1DoFActuator.h"
+#include "RobotAPI/components/units/RobotUnit/Devices/GlobalRobotPoseSensorDevice.h"
 #include <RobotAPI/libraries/core/PIDController.h>
 
 #include <RobotAPI/components/units/RobotUnit/ControlTargets/ControlTargetHolonomicPlatformVelocity.h>
@@ -71,11 +72,11 @@ namespace armarx
         float rotationAccuracy = 0.0f;
         bool newTargetSet = false;
 
-        Eigen::Vector2f startPosition;
-        float startOrientation;
+        // Eigen::Vector2f startPosition;
+        // float startOrientation;
 
-        Eigen::Vector2f globalPosition;
-        float globalOrientation;
+        // Eigen::Vector2f globalPosition;
+        // float globalOrientation;
 
         IceUtil::Time lastUpdate = IceUtil::Time::seconds(0);
     };
@@ -108,21 +109,14 @@ namespace armarx
 
         void setTarget(float x, float y, float yaw, float translationAccuracy, float rotationAccuracy);
 
-        void setGlobalPos(const PlatformPose& currentPose);
-
-
     protected:
-        const SensorValueHolonomicPlatform* sv;
+        const GlobalRobotLocalizationSensorDevice::SensorValueType* sv;
         MultiDimPIDController pid;
         PIDController  opid;
 
         ControlTargetHolonomicPlatformVelocity* target;
 
-        Eigen::Vector2f currentPosition;
-        float currentOrientation;
-        bool isAborted = false;
+        bool isTargetSet = false;
 
     };
 } // namespace armarx
-
-
diff --git a/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleControlThread.cpp b/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleControlThread.cpp
index a3269b4d0e11cb792f639e4c477218dcb58183e8..5d7d7d01ece91cb274e2f4e6a6f0619c06f4a65e 100644
--- a/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleControlThread.cpp
+++ b/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleControlThread.cpp
@@ -22,12 +22,15 @@
 
 #include "RobotUnitModuleControlThread.h"
 
+#include <SimoxUtility/math/convert/pos_rpy_to_mat4f.h>
 #include <VirtualRobot/XML/RobotIO.h>
 
 #include <ArmarXCore/core/time/TimeUtil.h>
 #include <ArmarXCore/core/util/OnScopeExit.h>
 #include <ArmarXCore/observers/filters/rtfilters/AverageFilter.h>
 #include <ArmarXCore/observers/filters/rtfilters/ButterworthFilter.h>
+#include <RobotAPI/components/units/RobotUnit/SensorValues/SensorValueHolonomicPlatform.h>
+#include <RobotAPI/components/units/RobotUnit/Devices/GlobalRobotPoseSensorDevice.h>
 #include <RobotAPI/components/units/RobotUnit/util/DynamicsHelper.h>
 #include <RobotAPI/components/units/RobotUnit/NJointControllers/NJointControllerBase.h>
 #include <RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleControlThreadDataBuffer.h>
@@ -1083,12 +1086,16 @@ namespace armarx::RobotUnitModule
     {
         if (njctrl->rtGetRobot())
         {
+            // update joints / nodes
             auto& from = rtRobotNodes;
             auto& to = njctrl->rtGetRobotNodes();
             for (std::size_t i = 0; i < from.size(); ++i)
             {
                 to.at(i)->copyPoseFrom(from.at(i));
             }
+
+            // update global root pose
+            njctrl->rtGetRobot()->setGlobalPose(rtRobot->getGlobalPose(), false);
         }
     }
 
@@ -1169,6 +1176,25 @@ namespace armarx::RobotUnitModule
         return str.str();
     }
 
+    void
+    ControlThread::rtUpdateRobotGlobalPose()
+    {
+        const ConstSensorDevicePtr globalPoseSensorDevice = _module<Devices>().getSensorDevice(GlobalRobotPoseSensorDevice::DeviceName());
+        if(not globalPoseSensorDevice)
+        {
+            return;
+        }
+
+        const auto *const sensorValue = globalPoseSensorDevice->getSensorValue()->asA<SensorValueGlobalRobotPose>();
+        if(sensorValue == nullptr)
+        {
+            return;
+        }
+
+        const auto global_T_robot = sensorValue->global_T_root;
+        rtSetRobotGlobalPose(global_T_robot, false);
+    }
+
     void
     ControlThread::rtSetRobotGlobalPose(const Eigen::Matrix4f& gp, bool updateRobot)
     {
diff --git a/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleControlThread.h b/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleControlThread.h
index 0dcf52aa47c01ddcd9cacd970373cf5e3423edf1..9b14a13ba370166793e188c8c8577fcc5ea19516 100644
--- a/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleControlThread.h
+++ b/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleControlThread.h
@@ -274,6 +274,7 @@ namespace armarx::RobotUnitModule
          */
         void rtSetEmergencyStopState(EmergencyStopState state);
 
+        void rtUpdateRobotGlobalPose();
         void rtSetRobotGlobalPose(const Eigen::Matrix4f& gp, bool updateRobot = true);
 
         /// Activate a joint controller from the rt loop (only works in switch mode RTThread)
@@ -390,4 +391,3 @@ namespace armarx::RobotUnitModule
         friend class ControlThreadAttorneyForRobotUnitEmergencyStopMaster;
     };
 }
-
diff --git a/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleDevices.cpp b/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleDevices.cpp
index fb8b38fc28ad83a8ba07ac395049796ac797d956..cbc9e50f06bc09a60635f6b6dd37e225f798377f 100644
--- a/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleDevices.cpp
+++ b/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleDevices.cpp
@@ -26,6 +26,7 @@
 
 #include <ArmarXCore/core/util/StringHelpers.h>
 #include <ArmarXCore/core/util/algorithm.h>
+#include "RobotAPI/components/units/RobotUnit/Devices/GlobalRobotPoseSensorDevice.h"
 
 namespace armarx::RobotUnitModule
 {
@@ -448,6 +449,11 @@ namespace armarx::RobotUnitModule
         {
             addSensorDevice(createRTThreadTimingSensorDevice());
         }
+
+        // this device will be used by the PlatformUnit to make the robot's global pose
+        // available to e.g. the NJointControllers.
+        addSensorDevice(std::make_shared<GlobalRobotPoseCorrectionSensorDevice>());
+        addSensorDevice(std::make_shared<GlobalRobotLocalizationSensorDevice>());
     }
 
     void Devices::_postFinishDeviceInitialization()
diff --git a/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleLogging.cpp b/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleLogging.cpp
index c1b9e88ca02c778cb61328ead80e9922e4161cf5..92f65d1941cd1c88dde3ace948d0c37a85d4ab60 100644
--- a/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleLogging.cpp
+++ b/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleLogging.cpp
@@ -77,6 +77,7 @@ namespace armarx::RobotUnitModule::details
         DurationsEntry msg;
     };
 } // namespace armarx::RobotUnitModule::details
+
 namespace armarx::RobotUnitModule
 {
     void
@@ -672,7 +673,8 @@ namespace armarx::RobotUnitModule
     {
 
         ARMARX_TRACE;
-        //header
+
+        // Header.
         {
             durations.header.start();
             ARMARX_TRACE;
@@ -702,428 +704,434 @@ namespace armarx::RobotUnitModule
             }
             durations.header.stop();
         }
-        //process devices
-        {//sens
-         {ARMARX_TRACE;
-        durations.sens.start();
-        //sensors
-        for (std::size_t idxDev = 0; idxDev < data.sensors.size(); ++idxDev)
+
+        // Process devices.
         {
-            const SensorValueBase* val = data.sensors.at(idxDev);
-            //dimensions of sensor value (e.g. vel, tor, f_x, f_y, ...)
-            for (std::size_t idxField = 0; idxField < val->getNumberOfDataFields(); ++idxField)
+            // Sensors.
             {
-                if (!rtLoggingEntries.empty())
+                ARMARX_TRACE;
+                durations.sens.start();
+                //sensors
+                for (std::size_t idxDev = 0; idxDev < data.sensors.size(); ++idxDev)
                 {
-                    durations.sens_csv.start();
-                    const auto str = val->getDataFieldAs<std::string>(idxField);
-                    for (auto& [_, entry] : rtLoggingEntries)
+                    const SensorValueBase* val = data.sensors.at(idxDev);
+                    //dimensions of sensor value (e.g. vel, tor, f_x, f_y, ...)
+                    for (std::size_t idxField = 0; idxField < val->getNumberOfDataFields(); ++idxField)
                     {
-                        if (entry->loggedSensorDeviceValues.at(idxDev).at(idxField))
+                        if (!rtLoggingEntries.empty())
                         {
-                            entry->stream << ";" << str;
+                            durations.sens_csv.start();
+                            const auto str = val->getDataFieldAs<std::string>(idxField);
+                            for (auto& [_, entry] : rtLoggingEntries)
+                            {
+                                if (entry->loggedSensorDeviceValues.at(idxDev).at(idxField))
+                                {
+                                    entry->stream << ";" << str;
+                                }
+                            }
+                            durations.sens_csv.stop();
+                        }
+                        if (!rtDataStreamingEntry.empty())
+                        {
+                            durations.sens_stream.start();
+                            for (auto& [_, data] : rtDataStreamingEntry)
+                            {
+                                durations.sens_stream_elem.start();
+                                data.processSens(*val, idxDev, idxField);
+                                durations.sens_stream_elem.stop();
+                            }
+                            durations.sens_stream.stop();
                         }
                     }
-                    durations.sens_csv.stop();
-                }
-                if (!rtDataStreamingEntry.empty())
-                {
-                    durations.sens_stream.start();
-                    for (auto& [_, data] : rtDataStreamingEntry)
-                    {
-                        durations.sens_stream_elem.start();
-                        data.processSens(*val, idxDev, idxField);
-                        durations.sens_stream_elem.stop();
-                    }
-                    durations.sens_stream.stop();
                 }
+                durations.sens.stop();
             }
-        }
-        durations.sens.stop();
-    }
-    //ctrl
-    {
-        durations.ctrl.start();
-        ARMARX_TRACE;
-        //joint controllers
-        for (std::size_t idxDev = 0; idxDev < data.control.size(); ++idxDev)
-        {
-            const auto& vals = data.control.at(idxDev);
-            //control value (e.g. v_platform)
-            for (std::size_t idxVal = 0; idxVal < vals.size(); ++idxVal)
+
+            // Controller.
             {
-                const ControlTargetBase* val = vals.at(idxVal);
-                //dimensions of control value (e.g. v_platform_x, v_platform_y, v_platform_rotate)
-                for (std::size_t idxField = 0; idxField < val->getNumberOfDataFields(); ++idxField)
+                durations.ctrl.start();
+                ARMARX_TRACE;
+                //joint controllers
+                for (std::size_t idxDev = 0; idxDev < data.control.size(); ++idxDev)
                 {
-                    if (!rtLoggingEntries.empty())
+                    const auto& vals = data.control.at(idxDev);
+                    //control value (e.g. v_platform)
+                    for (std::size_t idxVal = 0; idxVal < vals.size(); ++idxVal)
                     {
-                        durations.ctrl_csv.start();
-                        std::string str;
-                        val->getDataFieldAs(idxField, str); // expensive function
-                        for (auto& [_, entry] : rtLoggingEntries)
+                        const ControlTargetBase* val = vals.at(idxVal);
+                        //dimensions of control value (e.g. v_platform_x, v_platform_y, v_platform_rotate)
+                        for (std::size_t idxField = 0; idxField < val->getNumberOfDataFields(); ++idxField)
                         {
-                            if (entry->loggedControlDeviceValues.at(idxDev).at(idxVal).at(idxField))
+                            if (!rtLoggingEntries.empty())
                             {
-                                entry->stream << ";" << str;
+                                durations.ctrl_csv.start();
+                                std::string str;
+                                val->getDataFieldAs(idxField, str); // expensive function
+                                for (auto& [_, entry] : rtLoggingEntries)
+                                {
+                                    if (entry->loggedControlDeviceValues.at(idxDev).at(idxVal).at(idxField))
+                                    {
+                                        entry->stream << ";" << str;
+                                    }
+                                }
+                                durations.ctrl_csv.stop();
+                            }
+                            if (!rtDataStreamingEntry.empty())
+                            {
+                                durations.ctrl_stream.start();
+                                for (auto& [_, data] : rtDataStreamingEntry)
+                                {
+                                    durations.ctrl_stream_elem.start();
+                                    data.processCtrl(*val, idxDev, idxVal, idxField);
+                                    durations.ctrl_stream_elem.stop();
+                                }
+                                durations.ctrl_stream.stop();
                             }
                         }
-                        durations.ctrl_csv.stop();
                     }
-                    if (!rtDataStreamingEntry.empty())
+                }
+
+                durations.ctrl.stop();
+            }
+        }
+
+        //finish processing
+        {
+            //store data to backlog
+            {
+                durations.backlog.start();
+                ARMARX_TRACE;
+                if (data.writeTimestamp + rtLoggingBacklogRetentionTime >= now)
+                {
+                    backlog.emplace_back(data, true); //true for minimal copy
+                }
+                durations.backlog.stop();
+            }
+            //print + reset messages
+            {
+                durations.msg.start();
+                ARMARX_TRACE;
+                for (const ::armarx::detail::RtMessageLogEntryBase* ptr : data.messages.getEntries())
+                {
+                    if (!ptr)
                     {
-                        durations.ctrl_stream.start();
-                        for (auto& [_, data] : rtDataStreamingEntry)
-                        {
-                            durations.ctrl_stream_elem.start();
-                            data.processCtrl(*val, idxDev, idxVal, idxField);
-                            durations.ctrl_stream_elem.stop();
-                        }
-                        durations.ctrl_stream.stop();
+                        break;
                     }
+                    ptr->print(controlThreadId);
                 }
+                durations.msg.stop();
             }
         }
-        durations.ctrl.stop();
     }
-} // namespace armarx::RobotUnitModule
-//finish processing
-{
-    //store data to backlog
+
+    bool
+    Logging::MatchName(const std::string& pattern, const std::string& name)
     {
-        durations.backlog.start();
         ARMARX_TRACE;
-        if (data.writeTimestamp + rtLoggingBacklogRetentionTime >= now)
+        if (pattern.empty())
         {
-            backlog.emplace_back(data, true); //true for minimal copy
+            return false;
         }
-        durations.backlog.stop();
-    }
-    //print + reset messages
-    {
-        durations.msg.start();
-        ARMARX_TRACE;
-        for (const ::armarx::detail::RtMessageLogEntryBase* ptr : data.messages.getEntries())
+        static const std::regex pattern_regex{R"(^\^?[- ._*a-zA-Z0-9]+\$?$)"};
+        if (!std::regex_match(pattern, pattern_regex))
         {
-            if (!ptr)
-            {
-                break;
-            }
-            ptr->print(controlThreadId);
+            throw InvalidArgumentException{"Pattern '" + pattern + "' is invalid"};
         }
-        durations.msg.stop();
+        static const std::regex reg_dot{"[.]"};
+        static const std::regex reg_star{"[*]"};
+        const std::string rpl1 = std::regex_replace(pattern, reg_dot, "\\.");
+        const std::string rpl2 = std::regex_replace(rpl1, reg_star, ".*");
+        const std::regex key_regex{rpl2};
+        return std::regex_search(name, key_regex);
     }
-}
-}
 
-bool
-Logging::MatchName(const std::string& pattern, const std::string& name)
-{
-    ARMARX_TRACE;
-    if (pattern.empty())
-    {
-        return false;
-    }
-    static const std::regex pattern_regex{R"(^\^?[- ._*a-zA-Z0-9]+\$?$)"};
-    if (!std::regex_match(pattern, pattern_regex))
+    void
+    Logging::_postOnInitRobotUnit()
     {
-        throw InvalidArgumentException{"Pattern '" + pattern + "' is invalid"};
-    }
-    static const std::regex reg_dot{"[.]"};
-    static const std::regex reg_star{"[*]"};
-    const std::string rpl1 = std::regex_replace(pattern, reg_dot, "\\.");
-    const std::string rpl2 = std::regex_replace(rpl1, reg_star, ".*");
-    const std::regex key_regex{rpl2};
-    return std::regex_search(name, key_regex);
-}
-
-void
-Logging::_postOnInitRobotUnit()
-{
-    ARMARX_TRACE;
-    throwIfInControlThread(BOOST_CURRENT_FUNCTION);
-    rtLoggingTimestepMs = getProperty<std::size_t>("RTLogging_PeriodMs");
-    ARMARX_CHECK_LESS(0, rtLoggingTimestepMs) << "The property RTLoggingPeriodMs must not be 0";
+        ARMARX_TRACE;
+        throwIfInControlThread(BOOST_CURRENT_FUNCTION);
+        rtLoggingTimestepMs = getProperty<std::size_t>("RTLogging_PeriodMs");
+        ARMARX_CHECK_LESS(0, rtLoggingTimestepMs) << "The property RTLoggingPeriodMs must not be 0";
 
-    messageBufferSize = getProperty<std::size_t>("RTLogging_MessageBufferSize");
-    messageBufferMaxSize = getProperty<std::size_t>("RTLogging_MaxMessageBufferSize");
-    ARMARX_CHECK_LESS_EQUAL(messageBufferSize, messageBufferMaxSize);
+        messageBufferSize = getProperty<std::size_t>("RTLogging_MessageBufferSize");
+        messageBufferMaxSize = getProperty<std::size_t>("RTLogging_MaxMessageBufferSize");
+        ARMARX_CHECK_LESS_EQUAL(messageBufferSize, messageBufferMaxSize);
 
-    messageBufferNumberEntries = getProperty<std::size_t>("RTLogging_MessageNumber");
-    messageBufferMaxNumberEntries = getProperty<std::size_t>("RTLogging_MaxMessageNumber");
-    ARMARX_CHECK_LESS_EQUAL(messageBufferNumberEntries, messageBufferMaxNumberEntries);
+        messageBufferNumberEntries = getProperty<std::size_t>("RTLogging_MessageNumber");
+        messageBufferMaxNumberEntries = getProperty<std::size_t>("RTLogging_MaxMessageNumber");
+        ARMARX_CHECK_LESS_EQUAL(messageBufferNumberEntries, messageBufferMaxNumberEntries);
 
-    rtLoggingBacklogRetentionTime =
-        IceUtil::Time::milliSeconds(getProperty<std::size_t>("RTLogging_KeepIterationsForMs"));
+        rtLoggingBacklogRetentionTime =
+            IceUtil::Time::milliSeconds(getProperty<std::size_t>("RTLogging_KeepIterationsForMs"));
 
-    ARMARX_CHECK_GREATER(getControlThreadTargetPeriod().toMicroSeconds(), 0);
-}
+        ARMARX_CHECK_GREATER(getControlThreadTargetPeriod().toMicroSeconds(), 0);
+    }
 
-void
-Logging::_postFinishDeviceInitialization()
-{
-    ARMARX_TRACE;
-    throwIfInControlThread(BOOST_CURRENT_FUNCTION);
-    //init buffer
+    void
+    Logging::_postFinishDeviceInitialization()
     {
         ARMARX_TRACE;
-        std::size_t ctrlThreadPeriodUs =
-            static_cast<std::size_t>(getControlThreadTargetPeriod().toMicroSeconds());
-        std::size_t logThreadPeriodUs = rtLoggingTimestepMs * 1000;
-        std::size_t nBuffers = (logThreadPeriodUs / ctrlThreadPeriodUs + 1) * 100;
+        throwIfInControlThread(BOOST_CURRENT_FUNCTION);
+        //init buffer
+        {
+            ARMARX_TRACE;
+            std::size_t ctrlThreadPeriodUs =
+                static_cast<std::size_t>(getControlThreadTargetPeriod().toMicroSeconds());
+            std::size_t logThreadPeriodUs = rtLoggingTimestepMs * 1000;
+            std::size_t nBuffers = (logThreadPeriodUs / ctrlThreadPeriodUs + 1) * 100;
 
-        const auto bufferSize =
-            _module<ControlThreadDataBuffer>().getControlThreadOutputBuffer().initialize(
-                nBuffers,
-                _module<Devices>().getControlDevices(),
-                _module<Devices>().getSensorDevices(),
-                messageBufferSize,
-                messageBufferNumberEntries,
-                messageBufferMaxSize,
-                messageBufferMaxNumberEntries);
-        ARMARX_INFO << "RTLogging activated! using " << nBuffers << "buffers "
-                    << "(buffersize = " << bufferSize << " bytes)";
-    }
-    //init logging names + field types
-    {
-        ARMARX_TRACE;
-        const auto makeValueMetaData = [&](auto* val, const std::string& namePre)
+            const auto bufferSize =
+                _module<ControlThreadDataBuffer>().getControlThreadOutputBuffer().initialize(
+                    nBuffers,
+                    _module<Devices>().getControlDevices(),
+                    _module<Devices>().getSensorDevices(),
+                    messageBufferSize,
+                    messageBufferNumberEntries,
+                    messageBufferMaxSize,
+                    messageBufferMaxNumberEntries);
+            ARMARX_INFO << "RTLogging activated. Using " << nBuffers << " buffers "
+                        << "(buffersize = " << bufferSize << " bytes)";
+        }
+        //init logging names + field types
         {
-            ValueMetaData data;
-            const auto names = val->getDataFieldNames();
-            data.fields.resize(names.size());
+            ARMARX_TRACE;
+            const auto makeValueMetaData = [&](auto* val, const std::string& namePre)
+            {
+                ValueMetaData data;
+                const auto names = val->getDataFieldNames();
+                data.fields.resize(names.size());
 
-            for (std::size_t fieldIdx = 0; fieldIdx < names.size(); ++fieldIdx)
+                for (std::size_t fieldIdx = 0; fieldIdx < names.size(); ++fieldIdx)
+                {
+                    std::string const& fieldName = names[fieldIdx];
+                    data.fields.at(fieldIdx).name = namePre + '.' + fieldName;
+                    data.fields.at(fieldIdx).type = &(val->getDataFieldType(fieldIdx));
+                }
+                return data;
+            };
+
+            //sensorDevices
+            controlDeviceValueMetaData.reserve(_module<Devices>().getControlDevices().size());
+            for (const auto& cd : _module<Devices>().getControlDevices().values())
             {
-                std::string const& fieldName = names[fieldIdx];
-                data.fields.at(fieldIdx).name = namePre + '.' + fieldName;
-                data.fields.at(fieldIdx).type = &(val->getDataFieldType(fieldIdx));
+                ARMARX_TRACE;
+                controlDeviceValueMetaData.emplace_back();
+                auto& dataForDev = controlDeviceValueMetaData.back();
+                dataForDev.reserve(cd->getJointControllers().size());
+                for (auto jointC : cd->getJointControllers())
+                {
+                    dataForDev.emplace_back(makeValueMetaData(jointC->getControlTarget(),
+                                                              "ctrl." + cd->getDeviceName() + "." +
+                                                                  jointC->getControlMode()));
+                }
             }
-            return data;
-        };
-
-        //sensorDevices
-        controlDeviceValueMetaData.reserve(_module<Devices>().getControlDevices().size());
-        for (const auto& cd : _module<Devices>().getControlDevices().values())
-        {
-            ARMARX_TRACE;
-            controlDeviceValueMetaData.emplace_back();
-            auto& dataForDev = controlDeviceValueMetaData.back();
-            dataForDev.reserve(cd->getJointControllers().size());
-            for (auto jointC : cd->getJointControllers())
+            //sensorDevices
+            sensorDeviceValueMetaData.reserve(_module<Devices>().getSensorDevices().size());
+            for (const auto& sd : _module<Devices>().getSensorDevices().values())
             {
-                dataForDev.emplace_back(makeValueMetaData(jointC->getControlTarget(),
-                                                          "ctrl." + cd->getDeviceName() + "." +
-                                                              jointC->getControlMode()));
+                ARMARX_TRACE;
+                sensorDeviceValueMetaData.emplace_back(
+                    makeValueMetaData(sd->getSensorValue(), "sens." + sd->getDeviceName()));
             }
         }
-        //sensorDevices
-        sensorDeviceValueMetaData.reserve(_module<Devices>().getSensorDevices().size());
-        for (const auto& sd : _module<Devices>().getSensorDevices().values())
+        //start logging thread is done in rtinit
+        //maybe add the default log
         {
             ARMARX_TRACE;
-            sensorDeviceValueMetaData.emplace_back(
-                makeValueMetaData(sd->getSensorValue(), "sens." + sd->getDeviceName()));
+            const auto loggingpath = getProperty<std::string>("RTLogging_DefaultLog").getValue();
+            if (!loggingpath.empty())
+            {
+                defaultLogHandle = startRtLogging(loggingpath, getLoggingNames());
+            }
         }
     }
-    //start logging thread is done in rtinit
-    //maybe add the default log
+
+    void
+    Logging::DataStreamingEntry::clearResult()
     {
         ARMARX_TRACE;
-        const auto loggingpath = getProperty<std::string>("RTLogging_DefaultLog").getValue();
-        if (!loggingpath.empty())
+        for (auto& e : result)
         {
-            defaultLogHandle = startRtLogging(loggingpath, getLoggingNames());
+            entryBuffer.emplace_back(std::move(e));
         }
+        result.clear();
     }
-}
 
-void
-Logging::DataStreamingEntry::clearResult()
-{
-    ARMARX_TRACE;
-    for (auto& e : result)
+    RobotUnitDataStreaming::TimeStep
+    Logging::DataStreamingEntry::allocateResultElement() const
     {
-        entryBuffer.emplace_back(std::move(e));
+        ARMARX_TRACE;
+        RobotUnitDataStreaming::TimeStep data;
+        data.bools.resize(numBools);
+        data.bytes.resize(numBytes);
+        data.shorts.resize(numShorts);
+        data.ints.resize(numInts);
+        data.longs.resize(numLongs);
+        data.floats.resize(numFloats);
+        data.doubles.resize(numDoubles);
+        return data;
     }
-    result.clear();
-}
 
-RobotUnitDataStreaming::TimeStep
-Logging::DataStreamingEntry::allocateResultElement() const
-{
-    ARMARX_TRACE;
-    RobotUnitDataStreaming::TimeStep data;
-    data.bools.resize(numBools);
-    data.bytes.resize(numBytes);
-    data.shorts.resize(numShorts);
-    data.ints.resize(numInts);
-    data.longs.resize(numLongs);
-    data.floats.resize(numFloats);
-    data.doubles.resize(numDoubles);
-    return data;
-}
-
-RobotUnitDataStreaming::TimeStep
-Logging::DataStreamingEntry::getResultElement()
-{
-    ARMARX_TRACE;
-    if (entryBuffer.empty())
+    RobotUnitDataStreaming::TimeStep
+    Logging::DataStreamingEntry::getResultElement()
     {
-        return allocateResultElement();
+        ARMARX_TRACE;
+        if (entryBuffer.empty())
+        {
+            return allocateResultElement();
+        }
+        auto e = std::move(entryBuffer.back());
+        entryBuffer.pop_back();
+        return e;
     }
-    auto e = std::move(entryBuffer.back());
-    entryBuffer.pop_back();
-    return e;
-}
 
-void
-Logging::DataStreamingEntry::processHeader(const ControlThreadOutputBuffer::Entry& e)
-{
-    ARMARX_TRACE;
-    if (stopStreaming)
+    void
+    Logging::DataStreamingEntry::processHeader(const ControlThreadOutputBuffer::Entry& e)
     {
-        return;
-    }
-    result.emplace_back(getResultElement());
+        ARMARX_TRACE;
+        if (stopStreaming)
+        {
+            return;
+        }
+        result.emplace_back(getResultElement());
 
-    auto& data = result.back();
-    data.iterationId = e.iteration;
-    data.timestampUSec = e.sensorValuesTimestamp.toMicroSeconds();
-    data.timesSinceLastIterationUSec = e.timeSinceLastIteration.toMicroSeconds();
-}
+        auto& data = result.back();
+        data.iterationId = e.iteration;
+        data.timestampUSec = e.sensorValuesTimestamp.toMicroSeconds();
+        data.timesSinceLastIterationUSec = e.timeSinceLastIteration.toMicroSeconds();
+    }
 
-void
-WriteTo(const auto& dentr,
-        const Logging::DataStreamingEntry::OutVal& out,
-        const auto& val,
-        std::size_t fidx,
-        auto& data)
-{
-    ARMARX_TRACE;
-    using enum_t = Logging::DataStreamingEntry::ValueT;
-    try
+    void
+    WriteTo(const auto& dentr,
+            const Logging::DataStreamingEntry::OutVal& out,
+            const auto& val,
+            std::size_t fidx,
+            auto& data)
     {
         ARMARX_TRACE;
-        switch (out.value)
+        using enum_t = Logging::DataStreamingEntry::ValueT;
+        try
         {
-            case enum_t::Bool:
-                bool b;
-                val.getDataFieldAs(fidx, b);
-                data.bools.at(out.idx) = b;
-                return;
-            case enum_t::Byte:
-                val.getDataFieldAs(fidx, data.bytes.at(out.idx));
-                return;
-            case enum_t::Short:
-                val.getDataFieldAs(fidx, data.shorts.at(out.idx));
-                return;
-            case enum_t::Int:
-                val.getDataFieldAs(fidx, data.ints.at(out.idx));
-                return;
-            case enum_t::Long:
-                val.getDataFieldAs(fidx, data.longs.at(out.idx));
-                return;
-            case enum_t::Float:
-                val.getDataFieldAs(fidx, data.floats.at(out.idx));
-                return;
-            case enum_t::Double:
-                val.getDataFieldAs(fidx, data.doubles.at(out.idx));
-                return;
-            case enum_t::Skipped:
-                return;
+            ARMARX_TRACE;
+            switch (out.value)
+            {
+                case enum_t::Bool:
+                    bool b;
+                    val.getDataFieldAs(fidx, b);
+                    data.bools.at(out.idx) = b;
+                    return;
+                case enum_t::Byte:
+                    val.getDataFieldAs(fidx, data.bytes.at(out.idx));
+                    return;
+                case enum_t::Short:
+                    val.getDataFieldAs(fidx, data.shorts.at(out.idx));
+                    return;
+                case enum_t::Int:
+                    val.getDataFieldAs(fidx, data.ints.at(out.idx));
+                    return;
+                case enum_t::Long:
+                    val.getDataFieldAs(fidx, data.longs.at(out.idx));
+                    return;
+                case enum_t::Float:
+                    val.getDataFieldAs(fidx, data.floats.at(out.idx));
+                    return;
+                case enum_t::Double:
+                    val.getDataFieldAs(fidx, data.doubles.at(out.idx));
+                    return;
+                case enum_t::Skipped:
+                    return;
+            }
+        }
+        catch (...)
+        {
+            ARMARX_ERROR << GetHandledExceptionString() << "\ntype " << static_cast<int>(out.value)
+                         << "\n"
+                         << VAROUT(data.bools.size()) << " " << VAROUT(dentr.numBools) << "\n"
+                         << VAROUT(data.bytes.size()) << " " << VAROUT(dentr.numBytes) << "\n"
+                         << VAROUT(data.shorts.size()) << " " << VAROUT(dentr.numShorts) << "\n"
+                         << VAROUT(data.ints.size()) << " " << VAROUT(dentr.numInts) << "\n"
+                         << VAROUT(data.longs.size()) << " " << VAROUT(dentr.numLongs) << "\n"
+                         << VAROUT(data.floats.size()) << " " << VAROUT(dentr.numFloats) << "\n"
+                         << VAROUT(data.doubles.size()) << " " << VAROUT(dentr.numDoubles);
+            throw;
         }
     }
-    catch (...)
-    {
-        ARMARX_ERROR << GetHandledExceptionString() << "\ntype " << static_cast<int>(out.value)
-                     << "\n"
-                     << VAROUT(data.bools.size()) << " " << VAROUT(dentr.numBools) << "\n"
-                     << VAROUT(data.bytes.size()) << " " << VAROUT(dentr.numBytes) << "\n"
-                     << VAROUT(data.shorts.size()) << " " << VAROUT(dentr.numShorts) << "\n"
-                     << VAROUT(data.ints.size()) << " " << VAROUT(dentr.numInts) << "\n"
-                     << VAROUT(data.longs.size()) << " " << VAROUT(dentr.numLongs) << "\n"
-                     << VAROUT(data.floats.size()) << " " << VAROUT(dentr.numFloats) << "\n"
-                     << VAROUT(data.doubles.size()) << " " << VAROUT(dentr.numDoubles);
-        throw;
-    }
-}
 
-void
-Logging::DataStreamingEntry::processCtrl(const ControlTargetBase& val,
-                                         std::size_t didx,
-                                         std::size_t vidx,
-                                         std::size_t fidx)
-{
-    ARMARX_TRACE;
-    if (stopStreaming)
+    void
+    Logging::DataStreamingEntry::processCtrl(const ControlTargetBase& val,
+                                             std::size_t didx,
+                                             std::size_t vidx,
+                                             std::size_t fidx)
     {
-        return;
+        ARMARX_TRACE;
+        if (stopStreaming)
+        {
+            return;
+        }
+        auto& data = result.back();
+        const OutVal& o = ctrlDevs.at(didx).at(vidx).at(fidx);
+        WriteTo(*this, o, val, fidx, data);
     }
-    auto& data = result.back();
-    const OutVal& o = ctrlDevs.at(didx).at(vidx).at(fidx);
-    WriteTo(*this, o, val, fidx, data);
-}
 
-void
-Logging::DataStreamingEntry::processSens(const SensorValueBase& val,
-                                         std::size_t didx,
-                                         std::size_t fidx)
-{
-    ARMARX_TRACE;
-    if (stopStreaming)
+    void
+    Logging::DataStreamingEntry::processSens(const SensorValueBase& val,
+                                             std::size_t didx,
+                                             std::size_t fidx)
     {
-        return;
+        ARMARX_TRACE;
+        if (stopStreaming)
+        {
+            return;
+        }
+        auto& data = result.back();
+        const OutVal& o = sensDevs.at(didx).at(fidx);
+        WriteTo(*this, o, val, fidx, data);
     }
-    auto& data = result.back();
-    const OutVal& o = sensDevs.at(didx).at(fidx);
-    WriteTo(*this, o, val, fidx, data);
-}
-
-void
-Logging::DataStreamingEntry::send(const RobotUnitDataStreaming::ReceiverPrx& r, std::uint64_t msgId)
-{
-    ARMARX_TRACE;
-    const auto start_send = IceUtil::Time::now();
-    updateCalls.emplace_back(r->begin_update(result, static_cast<Ice::Long>(msgId)));
-    const auto start_clear = IceUtil::Time::now();
-    clearResult();
-    const auto end = IceUtil::Time::now();
-    ARMARX_DEBUG_S << "Logging::DataStreamingEntry::send"
-                   << "\n    update " << (start_clear - start_send).toMilliSecondsDouble() << "ms ("
-                   << result.size() << " timesteps)"
-                   << "\n    clear  " << (end - start_clear).toMilliSecondsDouble() << "ms";
 
-    //now execute all ready callbacks
-    std::size_t i = 0;
-    for (; i < updateCalls.size(); ++i)
+    void
+    Logging::DataStreamingEntry::send(const RobotUnitDataStreaming::ReceiverPrx& r, std::uint64_t msgId)
     {
-        try
+        ARMARX_TRACE;
+        const auto start_send = IceUtil::Time::now();
+        updateCalls.emplace_back(r->begin_update(result, static_cast<Ice::Long>(msgId)));
+        const auto start_clear = IceUtil::Time::now();
+        clearResult();
+        const auto end = IceUtil::Time::now();
+        ARMARX_DEBUG_S << "Logging::DataStreamingEntry::send"
+                       << "\n    update " << (start_clear - start_send).toMilliSecondsDouble() << "ms ("
+                       << result.size() << " timesteps)"
+                       << "\n    clear  " << (end - start_clear).toMilliSecondsDouble() << "ms";
+
+        //now execute all ready callbacks
+        std::size_t i = 0;
+        for (; i < updateCalls.size(); ++i)
         {
-            if (!updateCalls.at(i)->isCompleted())
+            try
             {
-                break;
+                if (!updateCalls.at(i)->isCompleted())
+                {
+                    break;
+                }
+                r->end_update(updateCalls.at(i));
+                connectionFailures = 0;
             }
-            r->end_update(updateCalls.at(i));
-            connectionFailures = 0;
-        }
-        catch (...)
-        {
-            ARMARX_TRACE;
-            ++connectionFailures;
-            if (connectionFailures > rtStreamMaxClientErrors)
+            catch (...)
             {
-                stopStreaming = true;
-                ARMARX_WARNING_S << "DataStreaming Receiver was not reachable for "
-                                 << connectionFailures << " iterations! Removing receiver";
-                updateCalls.clear();
-                break;
+                ARMARX_TRACE;
+                ++connectionFailures;
+                if (connectionFailures > rtStreamMaxClientErrors)
+                {
+                    stopStreaming = true;
+                    ARMARX_WARNING_S << "DataStreaming Receiver was not reachable for "
+                                     << connectionFailures << " iterations! Removing receiver";
+                    updateCalls.clear();
+                    break;
+                }
             }
         }
+        if (!updateCalls.empty())
+        {
+            updateCalls.erase(updateCalls.begin(), updateCalls.begin() + i);
+        }
     }
-    if (!updateCalls.empty())
-    {
-        updateCalls.erase(updateCalls.begin(), updateCalls.begin() + i);
-    }
-}
 }
diff --git a/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleLogging.h b/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleLogging.h
index ce63e07571da1dfd17d42b99e0c446a72aa83532..732b3a193d6da5831634a1c6caa0206e9c391140 100644
--- a/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleLogging.h
+++ b/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleLogging.h
@@ -73,8 +73,8 @@ namespace armarx::RobotUnitModule
 
             defineOptionalProperty<std::size_t>(
                 "RTLogging_KeepIterationsForMs", 60 * 1000,
-                "All logging data (SensorValues, ControlTargets, Messages) is keept for this duration "
-                "and can be dunped in case of an error.");
+                "All logging data (SensorValues, ControlTargets, Messages) is kept for this duration "
+                "and can be dumped in case of an error.");
 
             defineOptionalProperty<std::size_t>(
                 "RTLogging_StreamingDataMaxClientConnectionFailures", 10,
diff --git a/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleUnits.cpp b/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleUnits.cpp
index d562fa2dc3bb421eb09640c119db2f6f73c45018..80efce08aeaefed56bf599ceb928c7e1615e36a0 100644
--- a/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleUnits.cpp
+++ b/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleUnits.cpp
@@ -23,6 +23,10 @@
 #include <ArmarXCore/core/IceManager.h>
 #include <ArmarXCore/core/IceGridAdmin.h>
 
+#include "RobotAPI/components/units/RobotUnit/SensorValues/SensorValueHolonomicPlatform.h"
+#include "RobotAPI/components/units/RobotUnit/Units/LocalizationSubUnit.h"
+#include <RobotAPI/components/units/RobotUnit/Devices/GlobalRobotPoseSensorDevice.h>
+
 #include "RobotUnitModuleUnits.h"
 
 #include "../Units/ForceTorqueSubUnit.h"
@@ -152,6 +156,11 @@ namespace armarx::RobotUnitModule
             ARMARX_INFO << "initializing default units";
             initializeKinematicUnit();
             ARMARX_DEBUG << "KinematicUnit initialized";
+
+            ARMARX_DEBUG << "initializing LocalizationUnit";
+            initializeLocalizationUnit();
+            ARMARX_DEBUG << "LocalizationUnit initialized";
+
             initializePlatformUnit();
             ARMARX_DEBUG << "PlatformUnit initialized";
             initializeForceTorqueUnit();
@@ -162,6 +171,7 @@ namespace armarx::RobotUnitModule
             ARMARX_DEBUG << "TrajectoryControllerUnit initialized";
             initializeTcpControllerUnit();
             ARMARX_DEBUG << "TcpControllerUnit initialized";
+            
         }
         ARMARX_INFO << "initializing default units...done! " << (TimeUtil::GetTime(true) - beg).toMicroSeconds() << " us";
     }
@@ -394,8 +404,7 @@ namespace armarx::RobotUnitModule
         unit->pt = ctrl;
         unit->relativePosCtrl = ctrlRelativePosition;
 
-        unit->platformSensorIndex = _module<Devices>().getSensorDevices().index(_module<RobotData>().getRobotPlatformName());
-
+        // unit->platformSensorIndex = _module<Devices>().getSensorDevices().index(_module<RobotData>().getRobotPlatformName());
 
         NJointHolonomicPlatformGlobalPositionControllerConfigPtr configGlobalPositionCtrlCfg = new NJointHolonomicPlatformGlobalPositionControllerConfig;
         configGlobalPositionCtrlCfg->platformName = _module<RobotData>().getRobotPlatformName();
@@ -415,6 +424,56 @@ namespace armarx::RobotUnitModule
         addUnit(std::move(unit));
     }
 
+    void Units::initializeLocalizationUnit()
+    {
+        ARMARX_DEBUG << "initializeLocalizationUnit";
+
+        throwIfInControlThread(BOOST_CURRENT_FUNCTION);
+        using UnitT = LocalizationSubUnit;
+        using IfaceT = LocalizationUnitInterface;
+
+        auto guard = getGuard();
+        throwIfStateIsNot(RobotUnitState::InitializingUnits, __FUNCTION__);
+        //check if unit is already added
+        if (getUnit(IfaceT::ice_staticId()))
+        {
+            return;
+        }
+
+        ARMARX_DEBUG << "Getting device SensorValueHolonomicPlatformRelativePosition";
+        const SensorDevicePtr& sensorDeviceRelativePosition = _module<Devices>().getSensorDevices().at(_module<RobotData>().getRobotPlatformName());
+        ARMARX_CHECK_EXPRESSION(sensorDeviceRelativePosition->getSensorValue()->asA<SensorValueHolonomicPlatformRelativePosition>());
+
+        // const SensorDevicePtr& sensorDevicePoseCorrection = _module<Devices>().getSensorDevices().at(GlobalRobotPoseCorrectionSensorDevice::DeviceName());
+        // ARMARX_CHECK_EXPRESSION(sensorDeviceRelativePosition->getSensorValue()->asA<SensorValueGlobalPoseCorrection>());
+
+
+        //add it
+        const std::string configName = "LocalizationUnit";
+        const std::string confPre = getConfigDomain() + "." + configName + ".";
+        Ice::PropertiesPtr properties = getIceProperties()->clone();
+        //properties->setProperty(confPre + "MinimumLoggingLevel", getProperty<std::string>("MinimumLoggingLevel").getValue());
+        //fill properties
+        // properties->setProperty(confPre + "PlatformName", _module<RobotData>().getRobotPlatformInstanceName());
+        ARMARX_DEBUG << "creating unit " << configName << " using these properties: " << properties->getPropertiesForPrefix("");
+        IceInternal::Handle<UnitT> unit = Component::create<UnitT>(properties, configName, getConfigDomain());
+        //config
+
+        ARMARX_DEBUG << "Setting device GlobalRobotPoseCorrectionSensorDevice";
+        unit->globalPositionCorrectionSensorDevice = dynamic_cast<decltype(unit->globalPositionCorrectionSensorDevice)>(
+            _module<Devices>().getSensorDevices().at(GlobalRobotPoseCorrectionSensorDevice::DeviceName()).get());
+
+
+        const SensorDevicePtr& sensorDeviceGlobalRobotLocalization = _module<Devices>().getSensorDevices().at(GlobalRobotLocalizationSensorDevice::DeviceName());
+        ARMARX_CHECK_EXPRESSION(sensorDeviceGlobalRobotLocalization->getSensorValue()->asA<GlobalRobotLocalizationSensorDevice::SensorValueType>());
+
+        dynamic_cast<GlobalRobotLocalizationSensorDevice&>(*sensorDeviceGlobalRobotLocalization).sensorRelativePosition = sensorDeviceRelativePosition->getSensorValue()->asA<SensorValueHolonomicPlatformRelativePosition>();
+        dynamic_cast<GlobalRobotLocalizationSensorDevice&>(*sensorDeviceGlobalRobotLocalization).sensorGlobalPositionCorrection = unit->globalPositionCorrectionSensorDevice->getSensorValue()->asA<SensorValueGlobalPoseCorrection>();
+
+        //add
+        addUnit(unit);
+    }
+
     void Units::initializeForceTorqueUnit()
     {
         throwIfInControlThread(BOOST_CURRENT_FUNCTION);
diff --git a/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleUnits.h b/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleUnits.h
index d2f4ee59c173c06007479a14539f2025bc3ea793..ecb6e49b5e3ebd44fb358e976b7ffdfe68d56a82 100644
--- a/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleUnits.h
+++ b/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleUnits.h
@@ -251,6 +251,8 @@ namespace armarx::RobotUnitModule
         virtual void initializeTrajectoryControllerUnit();
         /// @brief Initializes the TcpControllerUnit
         virtual void initializeTcpControllerUnit();
+        /// @brief Initializes the TcpControllerUnit
+        virtual void initializeLocalizationUnit();
         /// @brief Create the \ref KinematicUnit (this function should be called in \ref initializeKinematicUnit)
         ManagedIceObjectPtr createKinematicSubUnit(const Ice::PropertiesPtr& properties,
                 const std::string& positionControlMode = ControlModes::Position1DoF,
diff --git a/source/RobotAPI/components/units/RobotUnit/SensorValues/SensorValueHolonomicPlatform.h b/source/RobotAPI/components/units/RobotUnit/SensorValues/SensorValueHolonomicPlatform.h
index 51b775a8ff44717716e6c3a83e47aaeb938199de..b7318e72fe1ae0cc7811389a0eccaa95f80a5ef5 100644
--- a/source/RobotAPI/components/units/RobotUnit/SensorValues/SensorValueHolonomicPlatform.h
+++ b/source/RobotAPI/components/units/RobotUnit/SensorValues/SensorValueHolonomicPlatform.h
@@ -67,13 +67,20 @@ namespace armarx
         }
     };
 
+    /**
+     * @brief The robot's position relative to its initial pose when starting the robot unit based on odometry information. 
+     * 
+     * Note: The relative position undergoes a significant drift over time.
+     */
     class SensorValueHolonomicPlatformRelativePosition : virtual public SensorValueBase
     {
     public:
         DETAIL_SensorValueBase_DEFAULT_METHOD_IMPLEMENTATION
+
         float relativePositionX = 0;
         float relativePositionY = 0;
         float relativePositionRotation = 0;
+
         static SensorValueInfo<SensorValueHolonomicPlatformRelativePosition> GetClassMemberInfo()
         {
             SensorValueInfo<SensorValueHolonomicPlatformRelativePosition> svi;
@@ -84,22 +91,28 @@ namespace armarx
         }
     };
 
-    class SensorValueHolonomicPlatformAbsolutePosition : virtual public SensorValueBase
-    {
-    public:
-        DETAIL_SensorValueBase_DEFAULT_METHOD_IMPLEMENTATION
-        float absolutePositionX;
-        float absolutePositionY;
-        float absolutePositionRotation;
-        static SensorValueInfo<SensorValueHolonomicPlatformAbsolutePosition> GetClassMemberInfo()
-        {
-            SensorValueInfo<SensorValueHolonomicPlatformAbsolutePosition> svi;
-            svi.addMemberVariable(&SensorValueHolonomicPlatformAbsolutePosition::absolutePositionX, "absolutePositionX");
-            svi.addMemberVariable(&SensorValueHolonomicPlatformAbsolutePosition::absolutePositionY, "absolutePositionY");
-            svi.addMemberVariable(&SensorValueHolonomicPlatformAbsolutePosition::absolutePositionRotation, "absolutePositionRotation");
-            return svi;
-        }
-    };
+
+    // The following class is deprecated: if the absolute position is provided, it will become inconsistent with the relative position.     
+    // Therefore, SensorValueHolonomicPlatformRelativePosition + SensorValueHolonomicPlatformGlobalPositionCorrection should be used instead.
+
+    // class SensorValueHolonomicPlatformAbsolutePosition : virtual public SensorValueBase
+    // {
+    // public:
+    //     DETAIL_SensorValueBase_DEFAULT_METHOD_IMPLEMENTATION
+    //     float absolutePositionX;
+    //     float absolutePositionY;
+    //     float absolutePositionRotation;
+    //     static SensorValueInfo<SensorValueHolonomicPlatformAbsolutePosition> GetClassMemberInfo()
+    //     {
+    //         SensorValueInfo<SensorValueHolonomicPlatformAbsolutePosition> svi;
+    //         svi.addMemberVariable(&SensorValueHolonomicPlatformAbsolutePosition::absolutePositionX, "absolutePositionX");
+    //         svi.addMemberVariable(&SensorValueHolonomicPlatformAbsolutePosition::absolutePositionY, "absolutePositionY");
+    //         svi.addMemberVariable(&SensorValueHolonomicPlatformAbsolutePosition::absolutePositionRotation, "absolutePositionRotation");
+    //         return svi;
+    //     }
+    // };
+
+    
 
     class SensorValueHolonomicPlatform :
         virtual public SensorValueHolonomicPlatformVelocity,
@@ -126,16 +139,19 @@ namespace armarx
         }
     };
 
-    class SensorValueHolonomicPlatformWithAbsolutePosition : virtual public SensorValueHolonomicPlatform, virtual public SensorValueHolonomicPlatformAbsolutePosition
-    {
-    public:
-        DETAIL_SensorValueBase_DEFAULT_METHOD_IMPLEMENTATION
-        static SensorValueInfo<SensorValueHolonomicPlatformWithAbsolutePosition> GetClassMemberInfo()
-        {
-            SensorValueInfo<SensorValueHolonomicPlatformWithAbsolutePosition> svi;
-            svi.addBaseClass<SensorValueHolonomicPlatform>();
-            svi.addBaseClass<SensorValueHolonomicPlatformAbsolutePosition>();
-            return svi;
-        }
-    };
+    // The following class is deprecated: if the absolute position is provided, it will become inconsistent with the relative position. 
+    // Therefore, SensorValueHolonomicPlatformRelativePosition + SensorValueHolonomicPlatformGlobalPositionCorrection should be used instead.
+
+    // class SensorValueHolonomicPlatformWithAbsolutePosition : virtual public SensorValueHolonomicPlatform, virtual public SensorValueHolonomicPlatformAbsolutePosition
+    // {
+    // public:
+    //     DETAIL_SensorValueBase_DEFAULT_METHOD_IMPLEMENTATION
+    //     static SensorValueInfo<SensorValueHolonomicPlatformWithAbsolutePosition> GetClassMemberInfo()
+    //     {
+    //         SensorValueInfo<SensorValueHolonomicPlatformWithAbsolutePosition> svi;
+    //         svi.addBaseClass<SensorValueHolonomicPlatform>();
+    //         svi.addBaseClass<SensorValueHolonomicPlatformAbsolutePosition>();
+    //         return svi;
+    //     }
+    // };
 }
diff --git a/source/RobotAPI/components/units/RobotUnit/Units/LocalizationSubUnit.cpp b/source/RobotAPI/components/units/RobotUnit/Units/LocalizationSubUnit.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..12c3faf13ffb311a36994002f8f05ef7122dc206
--- /dev/null
+++ b/source/RobotAPI/components/units/RobotUnit/Units/LocalizationSubUnit.cpp
@@ -0,0 +1,56 @@
+/*
+ * This file is part of ArmarX.
+ *
+ * ArmarX is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * ArmarX is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @package    RobotAPI::ArmarXObjects::LocalizationSubUnit
+ * @author     Raphael ( raphael dot grimm at kit dot edu )
+ * @date       2017
+ * @copyright  http://www.gnu.org/licenses/gpl-2.0.txt
+ *             GNU General Public License
+ */
+#include "LocalizationSubUnit.h"
+
+#include <Eigen/Core>
+#include <Eigen/Geometry>
+
+#include <SimoxUtility/math/convert/mat4f_to_rpy.h>
+
+#include <RobotAPI/components/units/RobotUnit/Devices/GlobalRobotPoseSensorDevice.h>
+#include <RobotAPI/interface/core/GeometryBase.h>
+#include <RobotAPI/interface/core/PoseBase.h>
+#include <RobotAPI/libraries/core/FramedPose.h>
+
+
+namespace armarx
+{
+    LocalizationSubUnit::~LocalizationSubUnit() = default;
+
+
+    void LocalizationSubUnit::update(const armarx::SensorAndControl& sc, const JointAndNJointControllers&)
+    {
+        if (!getProxy())
+        {
+            //this unit is not initialized yet
+            ARMARX_IMPORTANT << deactivateSpam(1) << "not initialized yet - skipping this update";
+            return;
+        }
+    }
+
+
+    void LocalizationSubUnit::reportGlobalRobotPoseCorrection(const TransformStamped& global_T_odom, const Ice::Current&)
+    {
+        ARMARX_CHECK_EXPRESSION(globalPositionCorrectionSensorDevice);
+        globalPositionCorrectionSensorDevice->updateGlobalPositionCorrection(global_T_odom.transform);
+    }
+}
diff --git a/source/RobotAPI/components/units/RobotUnit/Units/LocalizationSubUnit.h b/source/RobotAPI/components/units/RobotUnit/Units/LocalizationSubUnit.h
new file mode 100644
index 0000000000000000000000000000000000000000..f628ecc3164f02134d1a4c8c2e9b5915295e5762
--- /dev/null
+++ b/source/RobotAPI/components/units/RobotUnit/Units/LocalizationSubUnit.h
@@ -0,0 +1,89 @@
+/*
+ * This file is part of ArmarX.
+ *
+ * ArmarX is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * ArmarX is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @package    RobotAPI::ArmarXObjects::GlobalPoseSubUnit
+ * @author     Raphael ( raphael dot grimm at kit dot edu )
+ * @date       2017
+ * @copyright  http://www.gnu.org/licenses/gpl-2.0.txt
+ *             GNU General Public License
+ */
+
+#pragma once
+
+#include <mutex>
+
+#include <Eigen/Core>
+
+#include <VirtualRobot/MathTools.h>
+
+#include <RobotAPI/components/units/SensorActorUnit.h>
+#include <RobotAPI/libraries/core/Pose.h>
+#include <RobotAPI/interface/core/RobotState.h>
+#include <RobotAPI/interface/units/LocalizationUnitInterface.h>
+
+#include "RobotUnitSubUnit.h"
+
+namespace armarx
+{
+
+    class LocalizationUnit :
+        virtual public LocalizationUnitInterface,
+        virtual public SensorActorUnit
+    {
+    public:
+        // inherited from Component
+        std::string getDefaultName() const override
+        {
+            return "LocalizationUnit";
+        }
+
+        void onInitComponent() override {}
+        void onConnectComponent() override {}
+    };
+
+
+
+    class GlobalRobotPoseCorrectionSensorDevice;
+
+    TYPEDEF_PTRS_HANDLE(LocalizationSubUnit);
+    class LocalizationSubUnit:
+        virtual public RobotUnitSubUnit,
+        virtual public LocalizationUnit,
+        virtual public LocalizationSubUnitInterface
+    {
+    public:
+        LocalizationSubUnit() = default;
+        ~LocalizationSubUnit() override;
+
+        void update(const SensorAndControl& sc, const JointAndNJointControllers& c) override;
+
+        void reportGlobalRobotPoseCorrection(const TransformStamped& global_T_odom, const Ice::Current& = Ice::emptyCurrent) override;
+
+        /**
+         * This device partially holds the information about the robot's global pose.
+         * It is the transformation from the `global` to the `odometry` frame which can be 
+         * obtained by SLAM. In conjunction with the relative pose (pose within the `odometry` frame),
+         * the global pose can be obtained.
+         */
+        GlobalRobotPoseCorrectionSensorDevice* globalPositionCorrectionSensorDevice;
+
+    private:
+
+        std::string agentName;
+        std::string robotRootFrame;
+
+
+    };
+}
diff --git a/source/RobotAPI/components/units/RobotUnit/Units/PlatformSubUnit.cpp b/source/RobotAPI/components/units/RobotUnit/Units/PlatformSubUnit.cpp
index 49e49a65f436d35425e2babce87e0940f0857ce4..83635aac61c22444388dfb4646b4b32f1029f918 100755
--- a/source/RobotAPI/components/units/RobotUnit/Units/PlatformSubUnit.cpp
+++ b/source/RobotAPI/components/units/RobotUnit/Units/PlatformSubUnit.cpp
@@ -24,10 +24,13 @@
 #include <Eigen/Core>
 #include <Eigen/Geometry>
 
+#include <SimoxUtility/math/convert/mat4f_to_rpy.h>
+
 #include <RobotAPI/interface/core/GeometryBase.h>
 #include <RobotAPI/interface/core/PoseBase.h>
 #include <RobotAPI/libraries/core/FramedPose.h>
-#include <SimoxUtility/math/convert/mat4f_to_rpy.h>
+#include <RobotAPI/components/units/RobotUnit/Devices/GlobalRobotPoseSensorDevice.h>
+
 
 namespace armarx
 {
@@ -72,47 +75,51 @@ namespace armarx
         globalPoseHeader.agent = agentName;
         globalPoseHeader.timestampInMicroSeconds = timestamp;
 
+
         //pos
         {
             ARMARX_CHECK_EXPRESSION(sensorValue->isA<SensorValueHolonomicPlatformRelativePosition>());
             const SensorValueHolonomicPlatformRelativePosition* s = sensorValue->asA<SensorValueHolonomicPlatformRelativePosition>();
-            relX = s->relativePositionX;
-            relY = s->relativePositionY;
-            relR = s->relativePositionRotation;
 
+            const auto odom_T_robot = VirtualRobot::MathTools::posrpy2eigen4f(s->relativePositionX, s->relativePositionY, 0, 0, 0, s->relativePositionRotation);
 
             // @@@ CHECK BELOW:
-            if (s->isA<SensorValueHolonomicPlatformAbsolutePosition>())
-            {
-                const SensorValueHolonomicPlatformAbsolutePosition* sabs = s->asA<SensorValueHolonomicPlatformAbsolutePosition>();
-                abs = positionCorrection * VirtualRobot::MathTools::posrpy2eigen4f(sabs->absolutePositionX, sabs->absolutePositionY, 0, 0, 0, sabs->absolutePositionRotation);
+            // if (s->isA<SensorValueHolonomicPlatformAbsolutePosition>())
+            // {
+            //     const SensorValueHolonomicPlatformAbsolutePosition* sabs = s->asA<SensorValueHolonomicPlatformAbsolutePosition>();
+            //     abs = positionCorrection * VirtualRobot::MathTools::posrpy2eigen4f(sabs->absolutePositionX, sabs->absolutePositionY, 0, 0, 0, sabs->absolutePositionRotation);
 
-                TransformStamped currentPose;
-                currentPose.header = globalPoseHeader;
-                currentPose.transform = abs;
+            //     TransformStamped currentPose;
+            //     currentPose.header = globalPoseHeader;
+            //     currentPose.transform = abs;
 
-                globalPosePrx->reportGlobalRobotPose(currentPose);
+            //     globalPosePrx->reportGlobalRobotPose(currentPose);
 
-                // legacy interfaces
-                PlatformPose platformPose = toPlatformPose(currentPose);
-                listenerPrx->reportPlatformPose(platformPose);
-                globalPosCtrl->setGlobalPos(platformPose);
-            }
-            else
-            {
-                abs = positionCorrection * VirtualRobot::MathTools::posrpy2eigen4f(relX, relY, 0, 0, 0, relR);
-            }
+            //     // legacy interfaces
+            //     PlatformPose platformPose = toPlatformPose(currentPose);
+            //     listenerPrx->reportPlatformPose(platformPose);
+            //     globalPosCtrl->setGlobalPos(platformPose);
+            // }
+            // else
+            // {
+            //    global_T_robot = global_T_odom * odom_T_robot;
+            // }
+
+            // const auto global_T_robot = global_T_odom * odom_T_robot;
 
-            TransformStamped odomPose;
-            odomPose.header = odomPoseHeader;
-            odomPose.transform = VirtualRobot::MathTools::posrpy2eigen4f(relX, relY, 0, 0, 0, relR);
 
+            const TransformStamped odomPose
+            {
+                .header = odomPoseHeader,
+                .transform = odom_T_robot
+            };
             odometryPrx->reportOdometryPose(odomPose);
 
             // legacy interface
             const auto odomLegacyPose = toPlatformPose(odomPose);
             listenerPrx->reportPlatformOdometryPose(odomLegacyPose.x, odomLegacyPose.y, odomLegacyPose.rotationAroundZ);
         }
+        
         //vel
         {
             ARMARX_CHECK_EXPRESSION(sensorValue->isA<SensorValueHolonomicPlatformVelocity>());
@@ -127,7 +134,7 @@ namespace armarx
 
             // legacy interface
             const auto& vel = odomVelocity.twist;
-            listenerPrx->reportPlatformVelocity(vel.linear.x(), vel.linear.y(), vel.angular.z());
+            // listenerPrx->reportPlatformVelocity(vel.linear.x(), vel.linear.y(), vel.angular.z());
         }
     }
 
@@ -175,59 +182,23 @@ namespace armarx
         maxVAng = std::abs(mxVAng);
     }
 
-    void armarx::PlatformSubUnit::setGlobalPose(armarx::PoseBasePtr globalPose, const Ice::Current&)
-    {
-        std::lock_guard<std::mutex> guard {dataMutex};
-        PosePtr p = PosePtr::dynamicCast(globalPose);
-        positionCorrection = p->toEigen() * abs.inverse();
-    }
+    // void armarx::PlatformSubUnit::setGlobalPose(armarx::PoseBasePtr globalPose, const Ice::Current&)
+    // {
+    //     std::lock_guard<std::mutex> guard {dataMutex};
+    //     PosePtr p = PosePtr::dynamicCast(globalPose);
+    //     global_T_odom = p->toEigen() * global_T_robot.inverse();
+    // }
 
-    armarx::PoseBasePtr armarx::PlatformSubUnit::getGlobalPose(const Ice::Current&)
-    {
-        std::lock_guard<std::mutex> guard {dataMutex};
-        return new Pose {abs};
-    }
+    // armarx::PoseBasePtr armarx::PlatformSubUnit::getGlobalPose(const Ice::Current&)
+    // {
+    //     std::lock_guard<std::mutex> guard {dataMutex};
+    //     return new Pose {global_T_robot};
+    // }
 
     void armarx::PlatformSubUnit::stopPlatform(const Ice::Current& c)
     {
         move(0, 0, 0);
     }
 
-    Eigen::Matrix4f armarx::PlatformSubUnit::getRelativePose() const
-    {
-        Eigen::Matrix4f rp = VirtualRobot::MathTools::rpy2eigen4f(0, 0, relR);
-        rp(0, 3) = relX;
-        rp(1, 3) = relY;
-        return rp;
-    }
-
-    void armarx::PlatformSubUnit::reportGlobalRobotPose(const TransformStamped& currentPose, const Ice::Current&)
-    {
-        globalPosCtrl->setGlobalPos(toPlatformPose(currentPose));
-    }
-
-
-
-    // legacy stuff
-
-
-    void armarx::PlatformSubUnit::reportPlatformPose(PlatformPose const& currentPose, const Ice::Current& c)
-    {
-        globalPosCtrl->setGlobalPos(currentPose);
-    }
-
-    void armarx::PlatformSubUnit::reportNewTargetPose(Ice::Float newPlatformPositionX, Ice::Float newPlatformPositionY, Ice::Float newPlatformRotation, const Ice::Current& c)
-    {
-
-    }
-
-    void armarx::PlatformSubUnit::reportPlatformVelocity(Ice::Float currentPlatformVelocityX, Ice::Float currentPlatformVelocityY, Ice::Float currentPlatformVelocityRotation, const Ice::Current& c)
-    {
-
-    }
-
-    void armarx::PlatformSubUnit::reportPlatformOdometryPose(Ice::Float, Ice::Float, Ice::Float, const Ice::Current&)
-    {
-    }
 
-}
\ No newline at end of file
+}
diff --git a/source/RobotAPI/components/units/RobotUnit/Units/PlatformSubUnit.h b/source/RobotAPI/components/units/RobotUnit/Units/PlatformSubUnit.h
index 21ab6338ee505a526222b52b3dfea085404a91af..24f8ac9db2bd10eb6c9e8e7e2f36ac75931a69e0 100755
--- a/source/RobotAPI/components/units/RobotUnit/Units/PlatformSubUnit.h
+++ b/source/RobotAPI/components/units/RobotUnit/Units/PlatformSubUnit.h
@@ -40,6 +40,8 @@
 
 namespace armarx
 {
+    class GlobalRobotPoseCorrectionSensorDevice;
+
     TYPEDEF_PTRS_HANDLE(PlatformSubUnit);
     class PlatformSubUnit:
         virtual public RobotUnitSubUnit,
@@ -53,20 +55,8 @@ namespace armarx
         void move(Ice::Float vx, Ice::Float vy, Ice::Float vr,  const Ice::Current& = Ice::emptyCurrent) override;
         void moveTo(Ice::Float rx, Ice::Float ry, Ice::Float rr, Ice::Float lac, Ice::Float rac,  const Ice::Current& = Ice::emptyCurrent) override;
         void moveRelative(Ice::Float rx, Ice::Float ry, Ice::Float rr, Ice::Float lac, Ice::Float rac,  const Ice::Current& = Ice::emptyCurrent) override;
-
         void setMaxVelocities(Ice::Float mxVLin, Ice::Float mxVAng,  const Ice::Current& = Ice::emptyCurrent) override;
 
-        virtual void setGlobalPose(PoseBasePtr globalPose,  const Ice::Current& = Ice::emptyCurrent) /*override*/;
-        virtual PoseBasePtr getGlobalPose(const Ice::Current& = Ice::emptyCurrent) /*override*/;
-
-        void reportGlobalRobotPose(const TransformStamped& currentPose, const Ice::Current& = Ice::emptyCurrent) override;
-
-
-        void reportPlatformPose(PlatformPose const& currentPose, const Ice::Current& c = ::Ice::Current()) override ;
-        void reportNewTargetPose(Ice::Float newPlatformPositionX, Ice::Float newPlatformPositionY, Ice::Float newPlatformRotation, const Ice::Current& c = ::Ice::Current()) override;
-        void reportPlatformVelocity(Ice::Float currentPlatformVelocityX, Ice::Float currentPlatformVelocityY, Ice::Float currentPlatformVelocityRotation, const Ice::Current& c = ::Ice::Current()) override;
-        void reportPlatformOdometryPose(::Ice::Float, ::Ice::Float, ::Ice::Float, const ::Ice::Current& = ::Ice::Current()) override;
-
 
         // PlatformUnit interface
         void onInitPlatformUnit()  override
@@ -84,24 +74,16 @@ namespace armarx
         NJointHolonomicPlatformUnitVelocityPassThroughControllerPtr pt;
         NJointHolonomicPlatformRelativePositionControllerPtr relativePosCtrl;
         NJointHolonomicPlatformGlobalPositionControllerPtr globalPosCtrl;
+
         std::size_t platformSensorIndex;
+
     protected:
-        Eigen::Matrix4f getRelativePose() const;
 
         mutable std::mutex dataMutex;
 
         Ice::Float maxVLin = std::numeric_limits<Ice::Float>::infinity();
         Ice::Float maxVAng = std::numeric_limits<Ice::Float>::infinity();
 
-        float relX = 0;
-        float relY = 0;
-        float relR = 0;
-
-        Eigen::Matrix4f abs;
-
-        // TODO(fabian.reister): likely remove or adapt
-        Eigen::Matrix4f positionCorrection = Eigen::Matrix4f::Identity();
-
 
     private:
 
diff --git a/source/RobotAPI/components/units/RobotUnit/util/ControlThreadOutputBuffer.cpp b/source/RobotAPI/components/units/RobotUnit/util/ControlThreadOutputBuffer.cpp
index 2dd62115bcf3ff0895cb3ecaa04fb2d2614d2294..8e5aa6c3238a3149180217c31bfff947adc27bff 100644
--- a/source/RobotAPI/components/units/RobotUnit/util/ControlThreadOutputBuffer.cpp
+++ b/source/RobotAPI/components/units/RobotUnit/util/ControlThreadOutputBuffer.cpp
@@ -100,7 +100,7 @@ namespace armarx
         )
         {
             ARMARX_TRACE;
-            auto& entry = entries.at(toBounds(onePastLoggingReadPosition));
+            detail::ControlThreadOutputBufferEntry& entry = entries.at(toBounds(onePastLoggingReadPosition));
             consumer(entry, offset, num);
             entry.messages.reset(messageBufferSize, messageBufferEntries, entry.iteration);
 
diff --git a/source/RobotAPI/interface/CMakeLists.txt b/source/RobotAPI/interface/CMakeLists.txt
index 41a52f9f8a0a2d981583ae1a5c4e85a07f0ff750..bc9e81e3ed47da9b47fdf570caf549ee1fce7e65 100644
--- a/source/RobotAPI/interface/CMakeLists.txt
+++ b/source/RobotAPI/interface/CMakeLists.txt
@@ -51,6 +51,7 @@ set(SLICE_FILES
     units/HeadIKUnit.ice
     units/KinematicUnitInterface.ice
     units/PlatformUnitInterface.ice
+    units/LocalizationUnitInterface.ice
     units/RobotPoseUnitInterface.ice
     units/TCPControlUnit.ice
     units/TCPMoverUnitInterface.ice
@@ -162,4 +163,3 @@ set(SLICE_FILES_ADDITIONAL_SOURCES
 armarx_interfaces_generate_library(RobotAPI "${ROBOTAPI_INTERFACE_DEPEND}")
 
 target_link_libraries(RobotAPIInterfaces PUBLIC ArmarXCore)
-
diff --git a/source/RobotAPI/interface/core/RobotLocalization.ice b/source/RobotAPI/interface/core/RobotLocalization.ice
index 6e5b38a32d000f219f8a868dfa8d869945637249..1d65d3a1102b1197713cf0d0d40834cfbd64b0e8 100644
--- a/source/RobotAPI/interface/core/RobotLocalization.ice
+++ b/source/RobotAPI/interface/core/RobotLocalization.ice
@@ -29,18 +29,26 @@
 #include <RobotAPI/interface/core/PoseBase.ice>
 
 module armarx{
-    interface GlobalRobotPoseProvider extends armem::server::MemoryInterface {
+    interface GlobalRobotPoseProvider extends armem::server::MemoryInterface 
+    {
         // timestamp in microseconds
         PoseBase getGlobalRobotPose(long timestamp, string robotName);
     }
 
-    interface GlobalRobotPoseLocalizationListener{
+    interface GlobalRobotPoseLocalizationListener
+    {
         void reportGlobalRobotPose(TransformStamped currentPose);
     }
+
+    interface GlobalRobotPoseLocalizationCorrectionListener
+    {
+        void reportGlobalRobotPoseCorrection(TransformStamped global_T_odom);
+    }
     
-    interface OdometryListener{
+    interface OdometryListener
+    {
         void reportOdometryVelocity(TwistStamped platformVelocity);
         void reportOdometryPose(TransformStamped odometryPose);
     }
 
-} // module armarx
\ No newline at end of file
+} // module armarx
diff --git a/source/RobotAPI/interface/units/LocalizationUnitInterface.ice b/source/RobotAPI/interface/units/LocalizationUnitInterface.ice
new file mode 100644
index 0000000000000000000000000000000000000000..8799ee4f0e75822c2c6d59dfb77212213ec1f7bf
--- /dev/null
+++ b/source/RobotAPI/interface/units/LocalizationUnitInterface.ice
@@ -0,0 +1,53 @@
+/*
+ * This file is part of ArmarX.
+ *
+ * Copyright (C) 2012-2016, High Performance Humanoid Technologies (H2T), Karlsruhe Institute of Technology (KIT), all rights reserved.
+ *
+ * ArmarX is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * ArmarX is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @package    ArmarX::Core
+ * @author     Manfred Kroehnert (manfred dot kroehnert at kit dot edu)
+ * @copyright  2013 Manfred Kroehnert
+ * @license    http://www.gnu.org/licenses/gpl-2.0.txt
+ *             GNU General Public License
+ */
+
+#pragma once
+
+#include <RobotAPI/interface/units/UnitInterface.ice>
+
+#include <ArmarXCore/interface/core/UserException.ice>
+#include <ArmarXCore/interface/core/BasicTypes.ice>
+#include <RobotAPI/interface/core/RobotLocalization.ice>
+
+#include <RobotAPI/interface/core/GeometryBase.ice>
+
+module armarx
+{	
+	
+    interface LocalizationUnitInterface extends SensorActorUnitInterface
+    {
+        void reportGlobalRobotPoseCorrection(TransformStamped global_T_odom);
+    };
+
+    interface LocalizationUnitListener
+    {
+       
+    };
+
+    interface LocalizationSubUnitInterface extends LocalizationUnitInterface
+    {
+
+    };
+
+};
diff --git a/source/RobotAPI/interface/units/PlatformUnitInterface.ice b/source/RobotAPI/interface/units/PlatformUnitInterface.ice
index 148e807f9514e1ea69db397c337a7030235f5702..f7f62d13d0b490fd50284582096e0308fff90223 100644
--- a/source/RobotAPI/interface/units/PlatformUnitInterface.ice
+++ b/source/RobotAPI/interface/units/PlatformUnitInterface.ice
@@ -117,10 +117,9 @@ module armarx
         void reportPlatformOdometryPose(float x, float y, float angle);
     };
 
-    interface PlatformSubUnitInterface extends PlatformUnitInterface, GlobalRobotPoseLocalizationListener, PlatformUnitListener
+    interface PlatformSubUnitInterface extends PlatformUnitInterface
     {
 
     };
 
 };
-
diff --git a/source/RobotAPI/libraries/ArmarXObjects/ObjectPoseClient.cpp b/source/RobotAPI/libraries/ArmarXObjects/ObjectPoseClient.cpp
index 13de0bb80cccb9d9e7a63819907d3b7d81688fbd..a85ae2c2c5531450d3f9c0440e31d8c1695884ba 100644
--- a/source/RobotAPI/libraries/ArmarXObjects/ObjectPoseClient.cpp
+++ b/source/RobotAPI/libraries/ArmarXObjects/ObjectPoseClient.cpp
@@ -36,7 +36,7 @@ namespace armarx::objpose
 
 
     ObjectPoseSeq
-    ObjectPoseClient::fetchObjectPoses()
+    ObjectPoseClient::fetchObjectPoses() const
     {
         if (not objectPoseStorage)
         {
@@ -48,7 +48,7 @@ namespace armarx::objpose
 
 
     ObjectPoseMap
-    ObjectPoseClient::fetchObjectPosesAsMap()
+    ObjectPoseClient::fetchObjectPosesAsMap() const
     {
         ObjectPoseMap map;
         for (auto& pose : fetchObjectPoses())
@@ -60,7 +60,7 @@ namespace armarx::objpose
 
     
     std::optional<ObjectPose>
-    ObjectPoseClient::fetchObjectPose(const ObjectID& objectID)
+    ObjectPoseClient::fetchObjectPose(const ObjectID& objectID) const
     {
         const auto *object = findObjectPoseByID(fetchObjectPoses(), objectID);
 
@@ -74,7 +74,7 @@ namespace armarx::objpose
     
 
     ObjectPoseSeq
-    ObjectPoseClient::fetchObjectPosesFromProvider(const std::string& providerName)
+    ObjectPoseClient::fetchObjectPosesFromProvider(const std::string& providerName) const
     {
         if (!objectPoseStorage)
         {
diff --git a/source/RobotAPI/libraries/ArmarXObjects/ObjectPoseClient.h b/source/RobotAPI/libraries/ArmarXObjects/ObjectPoseClient.h
index a5b5fd18d7686e0cc46cd7e0154588ca3b13b40f..8a1cb31f23f30b37724177aaff7ba30e77ec5604 100644
--- a/source/RobotAPI/libraries/ArmarXObjects/ObjectPoseClient.h
+++ b/source/RobotAPI/libraries/ArmarXObjects/ObjectPoseClient.h
@@ -57,14 +57,14 @@ namespace armarx::objpose
          * @return The known object poses.
          */
         ObjectPoseSeq
-        fetchObjectPoses();
+        fetchObjectPoses() const;
 
         /**
          * @brief Fetch all known object poses.
          * @return The known object poses, with object ID as key.
          */
         ObjectPoseMap
-        fetchObjectPosesAsMap();
+        fetchObjectPosesAsMap() const;
 
         /**
          * @brief Fetch the pose of a single object.
@@ -76,7 +76,7 @@ namespace armarx::objpose
          * @return The object's pose, if known.
          */
         std::optional<ObjectPose>
-        fetchObjectPose(const ObjectID& objectID);
+        fetchObjectPose(const ObjectID& objectID) const;
 
         /**
          * @brief Fetch object poses from a specific provider.
@@ -84,7 +84,7 @@ namespace armarx::objpose
          * @return The object poses from that provider.
          */
         ObjectPoseSeq
-        fetchObjectPosesFromProvider(const std::string& providerName);
+        fetchObjectPosesFromProvider(const std::string& providerName) const;
 
 
         /**
diff --git a/source/RobotAPI/libraries/armem_objects/server/instance/Segment.cpp b/source/RobotAPI/libraries/armem_objects/server/instance/Segment.cpp
index 6ba35fd2042b04540721c95c1b48d566ad9d3d5a..46fe311e31ce6a9f80650d2178a2a425f08e17c5 100644
--- a/source/RobotAPI/libraries/armem_objects/server/instance/Segment.cpp
+++ b/source/RobotAPI/libraries/armem_objects/server/instance/Segment.cpp
@@ -153,7 +153,7 @@ namespace armarx::armem::server::obj::instance
         stats.numUpdated = 0;
 
         // timestamp used to reduce the rpc calls for robot sync 
-        Time robotSyncTimestamp = -1;
+        Time robotSyncTimestamp = Time::Invalid();
 
         for (const objpose::data::ProvidedObjectPose& provided : providedPoses)
         {
diff --git a/source/RobotAPI/libraries/armem_robot_state/client/common/RobotReader.cpp b/source/RobotAPI/libraries/armem_robot_state/client/common/RobotReader.cpp
index f32527a0a5b541d3ecc33015e3a3a7a482109439..6e3cd9af2259531d336dda34e206013b46334206 100644
--- a/source/RobotAPI/libraries/armem_robot_state/client/common/RobotReader.cpp
+++ b/source/RobotAPI/libraries/armem_robot_state/client/common/RobotReader.cpp
@@ -137,15 +137,18 @@ namespace armarx::armem::robot_state
     std::optional<robot::RobotDescription>
     RobotReader::queryDescription(const std::string& name, const armem::Time& timestamp)
     {
+
+        const auto sanitizedTimestamp = timestamp.isValid() ? timestamp : Clock::Now();
+
         // Query all entities from provider.
         armem::client::query::Builder qb;
 
         // clang-format off
         qb
-        .coreSegments().all() // withName(properties.descriptionCoreSegment)
-        .providerSegments().all() // .withName(name)
+        .coreSegments().withName(constants::descriptionCoreSegment)
+        .providerSegments().withName(name)
         .entities().all()
-        .snapshots().beforeOrAtTime(timestamp);
+        .snapshots().beforeOrAtTime(sanitizedTimestamp);
         // clang-format on
 
         ARMARX_DEBUG << "Lookup query in reader";
@@ -670,7 +673,7 @@ namespace armarx::armem::robot_state
         // clang-format off
         const armem::wm::ProviderSegment& providerSegment = memory
                 .getCoreSegment(constants::descriptionCoreSegment)
-                .getProviderSegment(name); // TODO(fabian.reister): all
+                .getProviderSegment(name);
         // clang-format on
 
         const armem::wm::EntityInstance* instance = nullptr;
@@ -678,7 +681,7 @@ namespace armarx::armem::robot_state
                                         { instance = &i; });
         if (instance == nullptr)
         {
-            ARMARX_WARNING << "No entity snapshots found";
+            ARMARX_WARNING << "No entity snapshots found in provider segment `" << name << "`";
             return std::nullopt;
         }
 
diff --git a/source/RobotAPI/libraries/armem_robot_state/client/common/VirtualRobotReader.cpp b/source/RobotAPI/libraries/armem_robot_state/client/common/VirtualRobotReader.cpp
index 0eb7e2dde3c4e9e56342325c1069f499230186ee..4aa5969dd34e247c2abcce2500f9c15c33353098 100644
--- a/source/RobotAPI/libraries/armem_robot_state/client/common/VirtualRobotReader.cpp
+++ b/source/RobotAPI/libraries/armem_robot_state/client/common/VirtualRobotReader.cpp
@@ -78,16 +78,10 @@ namespace armarx::armem::robot_state
                     << xmlFilename << "'";
 
         auto robot = VirtualRobot::RobotIO::loadRobot(xmlFilename, loadMode);
+        ARMARX_CHECK_NOT_NULL(robot) << "Could not load robot from file `" << xmlFilename << "`";
+        
         robot->setName(name);
 
-        const bool success = synchronizeRobot(*robot, timestamp);
-
-        if (not success)
-        {
-            ARMARX_WARNING << "Could not synchronize robot `" << name << "` with the memory!";
-            return nullptr;
-        }
-
         return robot;
     }
 
diff --git a/source/RobotAPI/libraries/armem_robot_state/client/common/VirtualRobotReader.h b/source/RobotAPI/libraries/armem_robot_state/client/common/VirtualRobotReader.h
index ea1d87b62fd2ad54b536b607d4ba316ae16e3777..19a184e8c4cee71e2a7866206f2ae55cd51f0d27 100644
--- a/source/RobotAPI/libraries/armem_robot_state/client/common/VirtualRobotReader.h
+++ b/source/RobotAPI/libraries/armem_robot_state/client/common/VirtualRobotReader.h
@@ -51,7 +51,7 @@ namespace armarx::armem::robot_state
 
         [[nodiscard]] VirtualRobot::RobotPtr
         getRobot(const std::string& name,
-                 const armem::Time& timestamp,
+                 const armem::Time& timestamp = armem::Time::Invalid(),
                  const VirtualRobot::RobotIO::RobotDescription& loadMode =
                      VirtualRobot::RobotIO::RobotDescription::eStructure);
 
diff --git a/source/RobotAPI/libraries/armem_robot_state/common/localization/TransformHelper.cpp b/source/RobotAPI/libraries/armem_robot_state/common/localization/TransformHelper.cpp
index 9c194be892458bdac83ce2291cc0eff9cd40dbe9..5ba3398f4ea1e8a00b4249fe411c213dda659c93 100644
--- a/source/RobotAPI/libraries/armem_robot_state/common/localization/TransformHelper.cpp
+++ b/source/RobotAPI/libraries/armem_robot_state/common/localization/TransformHelper.cpp
@@ -151,9 +151,9 @@ namespace armarx::armem::common::robot_state::localization
             tfLookup[frames.front()] = frames.back();
         }
 
-        std::string currentFrame = GlobalFrame;
+        std::string currentFrame = query.header.parentFrame;
         chain.push_back(currentFrame);
-        while(tfLookup.count(currentFrame) > 0 and currentFrame != ::armarx::armem::robot_state::constants::robotRootNodeName)
+        while(tfLookup.count(currentFrame) > 0 and currentFrame != query.header.frame)
         {
             currentFrame = tfLookup.at(currentFrame);
             chain.push_back(currentFrame);
@@ -161,7 +161,7 @@ namespace armarx::armem::common::robot_state::localization
        
         ARMARX_VERBOSE << VAROUT(chain);
 
-        if (chain.empty() or chain.back() != ::armarx::armem::robot_state::constants::robotRootNodeName)
+        if (chain.empty() or chain.back() != query.header.frame)
         {
             ARMARX_WARNING << deactivateSpam(60) << "Cannot create tf lookup chain '" << query.header.parentFrame
                            << " -> " << query.header.frame << "' for robot `" + query.header.agent + "`.";