diff --git a/source/RobotAPI/components/units/HandUnit.h b/source/RobotAPI/components/units/HandUnit.h
index 3816605266f1bc44dce40a752bfe94b14af8177b..0241caff84c93709619c0bcabae2736d443e5c1b 100644
--- a/source/RobotAPI/components/units/HandUnit.h
+++ b/source/RobotAPI/components/units/HandUnit.h
@@ -172,7 +172,7 @@ namespace armarx
 
         // HandUnitInterface interface
     public:
-        std::string getHandName(const Ice::Current&) override;
+        std::string getHandName(const Ice::Current& = Ice::emptyCurrent) override;
         void setJointForces(const NameValueMap& targetJointForces, const Ice::Current&) override;
         void sendJointCommands(const NameCommandMap& targetJointCommands, const Ice::Current&) override;
     };
diff --git a/source/RobotAPI/libraries/ArmarXObjects/ObjectFinder.cpp b/source/RobotAPI/libraries/ArmarXObjects/ObjectFinder.cpp
index 4b61a29ecf41a7af19336ccdc81d30c7dc32189a..f5516353eecf459e4d2cde12db3737b396908972 100644
--- a/source/RobotAPI/libraries/ArmarXObjects/ObjectFinder.cpp
+++ b/source/RobotAPI/libraries/ArmarXObjects/ObjectFinder.cpp
@@ -104,6 +104,7 @@ namespace armarx
     {
         return findObject(id.dataset(), id.className());
     }
+
     std::optional<ObjectInfo> ObjectFinder::findObject(const objpose::ObjectPose& obj) const
     {
         return findObject(obj.objectID);
diff --git a/source/RobotAPI/libraries/ArmarXObjects/ObjectInfo.cpp b/source/RobotAPI/libraries/ArmarXObjects/ObjectInfo.cpp
index 00c5efd4a4b52bd95743e2427f661108a80891f7..6d20564f660aee832698ca9d1eda297b56de9f3c 100644
--- a/source/RobotAPI/libraries/ArmarXObjects/ObjectInfo.cpp
+++ b/source/RobotAPI/libraries/ArmarXObjects/ObjectInfo.cpp
@@ -91,6 +91,36 @@ namespace armarx
         return file(".xml");
     }
 
+    PackageFileLocation ObjectInfo::urdf() const
+    {
+        return file(".urdf");
+    }
+
+    PackageFileLocation ObjectInfo::sdf() const
+    {
+        return file(".sdf");
+    }
+
+    std::optional<PackageFileLocation> ObjectInfo::getModel() const
+    {
+        if (fs::is_regular_file(simoxXML().absolutePath))
+        {
+            return simoxXML();
+        }
+        else if (fs::is_regular_file(urdf().absolutePath))
+        {
+            return urdf();
+        }
+        else if (fs::is_regular_file(sdf().absolutePath))
+        {
+            return sdf();
+        }
+        else
+        {
+            return std::nullopt;
+        }
+    }
+
     PackageFileLocation ObjectInfo::articulatedSimoxXML() const
     {
         return file(".xml", "_articulated", true);
@@ -101,6 +131,11 @@ namespace armarx
         return file(".urdf", "_articulated", true);
     }
 
+    PackageFileLocation ObjectInfo::articulatedSdf() const
+    {
+        return file(".sdf", "_articulated");
+    }
+
     std::optional<PackageFileLocation> ObjectInfo::getArticulatedModel() const
     {
         if (fs::is_regular_file(articulatedSimoxXML().absolutePath))
@@ -111,6 +146,10 @@ namespace armarx
         {
             return articulatedUrdf();
         }
+        else if (fs::is_regular_file(articulatedSdf().absolutePath))
+        {
+            return articulatedSdf();
+        }
         else
         {
             return std::nullopt;
diff --git a/source/RobotAPI/libraries/ArmarXObjects/ObjectInfo.h b/source/RobotAPI/libraries/ArmarXObjects/ObjectInfo.h
index abc1d9dd7ba13e05a578a873427f81668274f136..ccbd4eb1be32116d8fc7ced05d8148f027fefccf 100644
--- a/source/RobotAPI/libraries/ArmarXObjects/ObjectInfo.h
+++ b/source/RobotAPI/libraries/ArmarXObjects/ObjectInfo.h
@@ -80,10 +80,15 @@ namespace armarx
 
 
         PackageFileLocation simoxXML() const;
+        PackageFileLocation urdf() const;
+        PackageFileLocation sdf() const;
+        /// Return the Simox XML, URDF or SDF, if one exists.
+        std::optional<PackageFileLocation> getModel() const;
 
         PackageFileLocation articulatedSimoxXML() const;
         PackageFileLocation articulatedUrdf() const;
-        /// Return the articulated Simox XML or URDF, if one exists.
+        PackageFileLocation articulatedSdf() const;
+        /// Return the articulated Simox XML, URDF or SDF, if one exists.
         std::optional<PackageFileLocation> getArticulatedModel() const;
 
 
diff --git a/source/RobotAPI/libraries/ArmarXObjects/json_conversions.cpp b/source/RobotAPI/libraries/ArmarXObjects/json_conversions.cpp
index cf42e169e67f0f18aef427c65fd24a73160983bf..446b625e4e91359fadd8dd43b4dacdc460a9d513 100644
--- a/source/RobotAPI/libraries/ArmarXObjects/json_conversions.cpp
+++ b/source/RobotAPI/libraries/ArmarXObjects/json_conversions.cpp
@@ -83,7 +83,7 @@ void armarx::objects::to_json(simox::json::json& j, const SceneObject& rhs)
     j["instanceName"] = rhs.instanceName;
     j["collection"] = rhs.collection;
     j["position"] = rhs.position;
-    j["orientation"] = rhs.orientation;
+    j["orientation"] = rhs.orientation.normalized();
     if (rhs.isStatic.has_value())
     {
         j["isStatic"] = rhs.isStatic.value();
@@ -106,6 +106,7 @@ void armarx::objects::from_json(const simox::json::json& j, SceneObject& rhs)
     j.at("collection").get_to(rhs.collection);
     j.at("position").get_to(rhs.position);
     j.at("orientation").get_to(rhs.orientation);
+    rhs.orientation.normalize();
 
     if (j.count("isStatic"))
     {
diff --git a/source/RobotAPI/libraries/armem_laser_scans/client/common/Reader.cpp b/source/RobotAPI/libraries/armem_laser_scans/client/common/Reader.cpp
index ec17f944c60747160a3306032fa89c13899d6b86..e7ceabba97898778af1c13d9ad9c805357f79ac2 100644
--- a/source/RobotAPI/libraries/armem_laser_scans/client/common/Reader.cpp
+++ b/source/RobotAPI/libraries/armem_laser_scans/client/common/Reader.cpp
@@ -6,11 +6,10 @@
 #include <map>
 #include <optional>
 #include <ostream>
+#include <type_traits>
 #include <utility>
 #include <vector>
 
-#include <type_traits>
-
 // ICE
 #include <IceUtil/Handle.h>
 #include <IceUtil/Time.h>
@@ -34,15 +33,13 @@
 #include <RobotAPI/libraries/aron/core/data/variant/complex/NDArray.h>
 
 // RobotAPI Armem
-#include <RobotAPI/libraries/armem/core/error.h>
-#include <RobotAPI/libraries/armem/core/wm/memory_definitions.h>
-#include <RobotAPI/libraries/armem/util/util.h>
-
 #include <RobotAPI/libraries/armem/client/Query.h>
 #include <RobotAPI/libraries/armem/client/Reader.h>
 #include <RobotAPI/libraries/armem/client/query/Builder.h>
 #include <RobotAPI/libraries/armem/client/query/selectors.h>
-
+#include <RobotAPI/libraries/armem/core/error.h>
+#include <RobotAPI/libraries/armem/core/wm/memory_definitions.h>
+#include <RobotAPI/libraries/armem/util/util.h>
 #include <RobotAPI/libraries/armem_laser_scans/aron/LaserScan.aron.generated.h>
 #include <RobotAPI/libraries/armem_laser_scans/aron_conversions.h>
 #include <RobotAPI/libraries/armem_laser_scans/types.h>
@@ -62,21 +59,22 @@ namespace armarx::armem::laser_scans::client
     Reader::registerPropertyDefinitions(armarx::PropertyDefinitionsPtr& def)
     {
         ARMARX_DEBUG << "TransformReader: registerPropertyDefinitions";
-        registerPropertyDefinitions(def);
 
         const std::string prefix = propertyPrefix;
-
     }
 
-    void Reader::connect()
+    void
+    Reader::connect()
     {
         // Wait for the memory to become available and add it as dependency.
-        ARMARX_IMPORTANT << "MappingDataReader: Waiting for memory '"
-                         << constants::memoryName << "' ...";
+        ARMARX_IMPORTANT << "MappingDataReader: Waiting for memory '" << constants::memoryName
+                         << "' ...";
         try
         {
-            memoryReader = memoryNameSystem.useReader(MemoryID().withMemoryName(constants::memoryName));
-            ARMARX_IMPORTANT << "MappingDataReader: Connected to memory '" << constants::memoryName << "'";
+            memoryReader =
+                memoryNameSystem.useReader(MemoryID().withMemoryName(constants::memoryName));
+            ARMARX_IMPORTANT << "MappingDataReader: Connected to memory '" << constants::memoryName
+                             << "'";
         }
         catch (const armem::error::CouldNotResolveMemoryServer& e)
         {
@@ -91,27 +89,43 @@ namespace armarx::armem::laser_scans::client
         armarx::armem::client::query::Builder qb;
 
         ARMARX_VERBOSE << "Query for agent: " << query.agent
-                    << " memory name: " << constants::memoryName;
+                       << " memory name: " << constants::memoryName;
 
         if (query.sensorList.empty()) // all sensors
         {
             // clang-format off
-            qb
+            auto& snapshots = qb
             .coreSegments().withName(constants::memoryName)
             .providerSegments().withName(query.agent)
             .entities().all()
-            .snapshots().timeRange(query.timeRange.min, query.timeRange.max);
+            .snapshots();
             // clang-format on
+            if (query.timeRange.has_value())
+            {
+                snapshots.timeRange(query.timeRange->min, query.timeRange->max);
+            }
+            else
+            {
+                snapshots.latest();
+            }
         }
         else
         {
             // clang-format off
-            qb
+            auto& snapshots = qb
             .coreSegments().withName(constants::memoryName)
             .providerSegments().withName(query.agent)
             .entities().withNames(query.sensorList)
-            .snapshots().timeRange(query.timeRange.min, query.timeRange.max);
+            .snapshots();
             // clang-format on
+            if (query.timeRange.has_value())
+            {
+                snapshots.timeRange(query.timeRange->min, query.timeRange->max);
+            }
+            else
+            {
+                snapshots.latest();
+            }
         }
 
         return qb;
@@ -126,16 +140,14 @@ namespace armarx::armem::laser_scans::client
             ARMARX_WARNING << "No entities!";
         }
 
-        const auto convert =
-            [](const auto& aronLaserScanStamped,
-               const wm::EntityInstance & ei) -> LaserScanStamped
+        const auto convert = [](const auto& aronLaserScanStamped,
+                                const wm::EntityInstance& ei) -> LaserScanStamped
         {
             LaserScanStamped laserScanStamped;
             fromAron(aronLaserScanStamped, laserScanStamped);
 
             const auto ndArrayNavigator =
-            aron::data::NDArray::DynamicCast(
-                ei.data()->getElement("scan"));
+                aron::data::NDArray::DynamicCast(ei.data()->getElement("scan"));
 
             ARMARX_CHECK_NOT_NULL(ndArrayNavigator);
 
@@ -145,47 +157,48 @@ namespace armarx::armem::laser_scans::client
         };
 
         // loop over all entities and their snapshots
-        providerSegment.forEachEntity([&outV, &convert](const wm::Entity & entity)
-        {
-            // If we don't need this warning, we could directly iterate over the snapshots.
-            if (entity.empty())
+        providerSegment.forEachEntity(
+            [&outV, &convert](const wm::Entity& entity)
             {
-                ARMARX_WARNING << "Empty history for " << entity.id();
-            }
-            ARMARX_DEBUG << "History size: " << entity.size();
-
-            entity.forEachInstance([&outV, &convert](const wm::EntityInstance & entityInstance)
-            {
-                if (const auto o = tryCast<arondto::LaserScanStamped>(entityInstance))
+                // If we don't need this warning, we could directly iterate over the snapshots.
+                if (entity.empty())
                 {
-                    outV.push_back(convert(*o, entityInstance));
+                    ARMARX_WARNING << "Empty history for " << entity.id();
                 }
+                ARMARX_DEBUG << "History size: " << entity.size();
+
+                entity.forEachInstance(
+                    [&outV, &convert](const wm::EntityInstance& entityInstance)
+                    {
+                        if (const auto o = tryCast<arondto::LaserScanStamped>(entityInstance))
+                        {
+                            outV.push_back(convert(*o, entityInstance));
+                        }
+                        return true;
+                    });
                 return true;
             });
-            return true;
-        });
 
         return outV;
     }
 
-    Reader::Result Reader::queryData(const Query& query) const
+    Reader::Result
+    Reader::queryData(const Query& query) const
     {
         const auto qb = buildQuery(query);
 
         ARMARX_DEBUG << "[MappingDataReader] query ... ";
 
-        const armem::client::QueryResult qResult =
-            memoryReader.query(qb.buildQueryInput());
+        const armem::client::QueryResult qResult = memoryReader.query(qb.buildQueryInput());
 
         ARMARX_DEBUG << "[MappingDataReader] result: " << qResult;
 
         if (not qResult.success)
         {
-            ARMARX_WARNING << "Failed to query data from memory: "
-                           << qResult.errorMessage;
-            return {.laserScans   = {},
-                    .sensors      = {},
-                    .status       = Result::Status::Error,
+            ARMARX_WARNING << "Failed to query data from memory: " << qResult.errorMessage;
+            return {.laserScans = {},
+                    .sensors = {},
+                    .status = Result::Status::Error,
                     .errorMessage = qResult.errorMessage};
         }
 
@@ -195,16 +208,17 @@ namespace armarx::armem::laser_scans::client
 
         const auto laserScans = asLaserScans(providerSegment);
         std::vector<std::string> sensors;
-        providerSegment.forEachEntity([&sensors](const wm::Entity & entity)
-        {
-            sensors.push_back(entity.name());
-            return true;
-        });
+        providerSegment.forEachEntity(
+            [&sensors](const wm::Entity& entity)
+            {
+                sensors.push_back(entity.name());
+                return true;
+            });
 
-        return {.laserScans   = laserScans,
-                .sensors      = sensors,
-                .status       = Result::Status::Success,
+        return {.laserScans = laserScans,
+                .sensors = sensors,
+                .status = Result::Status::Success,
                 .errorMessage = ""};
     }
 
-} // namespace armarx::armem::vision::laser_scans::client
+} // namespace armarx::armem::laser_scans::client
diff --git a/source/RobotAPI/libraries/armem_laser_scans/client/common/Reader.h b/source/RobotAPI/libraries/armem_laser_scans/client/common/Reader.h
index 70703521336f8ac0b1fdf9649df4a3777d95f431..55beab204b12a7f72432ef2e38789f1856058934 100644
--- a/source/RobotAPI/libraries/armem_laser_scans/client/common/Reader.h
+++ b/source/RobotAPI/libraries/armem_laser_scans/client/common/Reader.h
@@ -72,7 +72,8 @@ namespace armarx::armem::laser_scans::client
         {
             std::string agent;
 
-            TimeRange timeRange;
+            // if not provided, only latest is queried
+            std::optional<TimeRange> timeRange;
 
             // if empty, all sensors will be queried
             std::vector<std::string> sensorList;
diff --git a/source/RobotAPI/libraries/armem_laser_scans/server/Visu.cpp b/source/RobotAPI/libraries/armem_laser_scans/server/Visu.cpp
index 2387e7319e2646857d9c821647f32d136ffdd969..551e4792c2eba3b5e19d2ebf468f2d090a53af41 100644
--- a/source/RobotAPI/libraries/armem_laser_scans/server/Visu.cpp
+++ b/source/RobotAPI/libraries/armem_laser_scans/server/Visu.cpp
@@ -301,8 +301,7 @@ namespace armarx::armem::server::laser_scans
         if (robots.count(name) == 0)
         {
             ARMARX_CHECK_NOT_NULL(virtualRobotReader);
-            const auto robot = virtualRobotReader->getRobot(
-                name, timestamp, VirtualRobot::RobotIO::RobotDescription::eStructure);
+            const auto robot = virtualRobotReader->getRobot(name);
 
             if (robot)
             {
@@ -324,7 +323,7 @@ namespace armarx::armem::server::laser_scans
             }
             else
             {
-                ARMARX_VERBOSE << "Faield to synchronize robot `" << name << "`";
+                ARMARX_INFO << deactivateSpam(10) << "Failed to synchronize robot `" << name << "`";
             }
         }
         return entry.first;
diff --git a/source/RobotAPI/libraries/armem_objects/aron/ObjectClass.xml b/source/RobotAPI/libraries/armem_objects/aron/ObjectClass.xml
index a90821817037a2deb733474743f33221048ab24b..e2d695429d3c4193ad97df106821f5bb912a0028 100644
--- a/source/RobotAPI/libraries/armem_objects/aron/ObjectClass.xml
+++ b/source/RobotAPI/libraries/armem_objects/aron/ObjectClass.xml
@@ -27,6 +27,22 @@ Core segment type of Object/Class.
                 <armarx::arondto::PackagePath />
             </ObjectChild>
 
+            <ObjectChild key="urdfPath">
+                <armarx::arondto::PackagePath />
+            </ObjectChild>
+
+            <ObjectChild key="articulatedUrdfPath">
+                <armarx::arondto::PackagePath />
+            </ObjectChild>
+
+            <ObjectChild key="sdfPath">
+                <armarx::arondto::PackagePath />
+            </ObjectChild>
+
+            <ObjectChild key="articulatedSdfPath">
+                <armarx::arondto::PackagePath />
+            </ObjectChild>
+
             <ObjectChild key="meshWrlPath">
                 <armarx::arondto::PackagePath />
             </ObjectChild>
diff --git a/source/RobotAPI/libraries/armem_objects/server/class/Segment.cpp b/source/RobotAPI/libraries/armem_objects/server/class/Segment.cpp
index a95e98d011e52c7f6251a2119b66b971b9d5a045..4dcf3262724cd6a9626a967f9582d4514a478d89 100644
--- a/source/RobotAPI/libraries/armem_objects/server/class/Segment.cpp
+++ b/source/RobotAPI/libraries/armem_objects/server/class/Segment.cpp
@@ -191,7 +191,11 @@ namespace armarx::armem::server::obj::clazz
             }
         };
         setPathIfExists(data.simoxXmlPath, info.simoxXML());
+        setPathIfExists(data.urdfPath, info.urdf());
+        setPathIfExists(data.sdfPath, info.sdf());
         setPathIfExists(data.articulatedSimoxXmlPath, info.articulatedSimoxXML());
+        setPathIfExists(data.articulatedUrdfPath, info.articulatedUrdf());
+        setPathIfExists(data.articulatedSdfPath, info.articulatedSdf());
         setPathIfExists(data.meshObjPath, info.wavefrontObj());
         setPathIfExists(data.meshWrlPath, info.meshWrl());
 
diff --git a/source/RobotAPI/libraries/armem_objects/server/instance/Segment.cpp b/source/RobotAPI/libraries/armem_objects/server/instance/Segment.cpp
index 0fd61b04c6305584e714cf38eb26c2370db2afc9..3b22bf1d1368a51be9e3ea71da20b8a343f3079b 100644
--- a/source/RobotAPI/libraries/armem_objects/server/instance/Segment.cpp
+++ b/source/RobotAPI/libraries/armem_objects/server/instance/Segment.cpp
@@ -1311,10 +1311,9 @@ namespace armarx::armem::server::obj::instance
         {
             // Try to fetch the robot.
             ARMARX_CHECK_NOT_NULL(reader);
-            bool warnings = false;
             VirtualRobot::RobotPtr robot = reader->getRobot(
                         robotName, Clock::Now(),
-                        VirtualRobot::RobotIO::RobotDescription::eStructure, warnings);
+                        VirtualRobot::RobotIO::RobotDescription::eStructure);
 
             if (robot)
             {
diff --git a/source/RobotAPI/libraries/armem_robot/types.h b/source/RobotAPI/libraries/armem_robot/types.h
index 345564d4b859af306acecdc82d00096c4a559351..6f29809973ed4ae1d0a70e9c0830ac0ab0003037 100644
--- a/source/RobotAPI/libraries/armem_robot/types.h
+++ b/source/RobotAPI/libraries/armem_robot/types.h
@@ -40,6 +40,9 @@ namespace armarx::armem::robot
         Eigen::Vector3f torque;
     };
 
+    using ToFArray = Eigen::MatrixXf;
+
+
     struct RobotState
     {
         using JointMap = std::map<std::string, float>;
diff --git a/source/RobotAPI/libraries/armem_robot_state/aron/Proprioception.xml b/source/RobotAPI/libraries/armem_robot_state/aron/Proprioception.xml
index c7ac7670d399329bb6674dad3243a048153534f8..e84ccf38297fee314fc3d4372386d8ca26e0e8d9 100644
--- a/source/RobotAPI/libraries/armem_robot_state/aron/Proprioception.xml
+++ b/source/RobotAPI/libraries/armem_robot_state/aron/Proprioception.xml
@@ -235,6 +235,13 @@
 
         </Object>
 
+        <Object name="armarx::armem::prop::arondto::ToF">
+            
+            <ObjectChild key="array">
+                <Matrix rows="-1" cols="-1" type="float32" />
+            </ObjectChild>
+
+        </Object>
         
         
         <Object name="armarx::armem::arondto::Proprioception">
@@ -257,6 +264,12 @@
                 </Dict>
             </ObjectChild>
 
+            <!-- TODO move to separate segment  -->
+            <ObjectChild key="tof">
+                <Dict>
+                    <armarx::armem::prop::arondto::ToF/>
+                </Dict>
+            </ObjectChild>
 
             <ObjectChild key="extraFloats">
                 <Dict>
diff --git a/source/RobotAPI/libraries/armem_robot_state/aron_conversions.cpp b/source/RobotAPI/libraries/armem_robot_state/aron_conversions.cpp
index 1c18fe5b78799b1b2f9555a33a8997e7edb60d28..b079cec2e38c92510dac533980c070ef9acf0f09 100644
--- a/source/RobotAPI/libraries/armem_robot_state/aron_conversions.cpp
+++ b/source/RobotAPI/libraries/armem_robot_state/aron_conversions.cpp
@@ -97,4 +97,14 @@ namespace armarx::armem
         aron::toAron(dto.torque, bo.torque);
     }
 
+
+    void fromAron(const armarx::armem::prop::arondto::ToF& dto, robot::ToFArray& bo){
+        bo = dto.array;
+    }
+
+    void toAron(armarx::armem::prop::arondto::ToF& dto, const robot::ToFArray& bo){
+        dto.array = bo;
+    }
+
+
 } // namespace armarx::armem
diff --git a/source/RobotAPI/libraries/armem_robot_state/aron_conversions.h b/source/RobotAPI/libraries/armem_robot_state/aron_conversions.h
index 75c339c7fc4aad7f24b5b52befdf2e7f1451b345..1912e6c69092982ae5a5677615bfa6658a46c9a9 100644
--- a/source/RobotAPI/libraries/armem_robot_state/aron_conversions.h
+++ b/source/RobotAPI/libraries/armem_robot_state/aron_conversions.h
@@ -38,6 +38,7 @@ namespace armarx::armem
     {
         struct Platform;
         struct ForceTorque;
+        struct ToF;
     }
 
     namespace arondto
@@ -66,4 +67,8 @@ namespace armarx::armem
     void toAron(armarx::armem::prop::arondto::ForceTorque& dto, const robot::ForceTorque& bo);
 
 
+    void fromAron(const armarx::armem::prop::arondto::ToF& dto, robot::ToFArray& bo);
+    void toAron(armarx::armem::prop::arondto::ToF& dto, const robot::ToFArray& bo);
+
+
 }  // namespace armarx::armem
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 611fa0e0d3f5bb931f5d64a60c70735d698c623f..d5f4844b574d3c6522f1d4461b7d9372c9f029c0 100644
--- a/source/RobotAPI/libraries/armem_robot_state/client/common/RobotReader.cpp
+++ b/source/RobotAPI/libraries/armem_robot_state/client/common/RobotReader.cpp
@@ -121,7 +121,7 @@ namespace armarx::armem::robot_state
                 const auto elapsedTime = armem::Time::Now() - tsStartFunctionInvokation;
                 if (elapsedTime > syncTimeout)
                 {
-                    ARMARX_WARNING << "Could not synchronize object " << obj.description.name;
+                    ARMARX_VERBOSE << "Could not synchronize object " << obj.description.name;
                     return false;
                 }
 
@@ -137,9 +137,7 @@ namespace armarx::armem::robot_state
     std::optional<robot::RobotDescription>
     RobotReader::queryDescription(
             const std::string& name,
-            const armem::Time& timestamp,
-            bool warnings
-            )
+            const armem::Time& timestamp)
     {
 
         const auto sanitizedTimestamp = timestamp.isValid() ? timestamp : Clock::Now();
@@ -159,11 +157,8 @@ namespace armarx::armem::robot_state
 
         if (not memoryReader)
         {
-            if (warnings)
-            {
-                ARMARX_WARNING << "Memory reader is null. Did you forget to call "
-                                  "RobotReader::connect() in onConnectComponent()?";
-            }
+            ARMARX_WARNING << "Memory reader is null. Did you forget to call "
+                                "RobotReader::connect() in onConnectComponent()?";
             return std::nullopt;
         }
 
@@ -182,10 +177,7 @@ namespace armarx::armem::robot_state
         }
         catch (...)
         {
-            if (warnings)
-            {
-                ARMARX_WARNING << "query description failure" << GetHandledExceptionString();
-            }
+            ARMARX_VERBOSE << "Query description failure" << GetHandledExceptionString();
         }
 
         return std::nullopt;
@@ -198,14 +190,14 @@ namespace armarx::armem::robot_state
         const auto jointMap = queryJointState(description, timestamp);
         if (not jointMap)
         {
-            ARMARX_WARNING << "Failed to query joint state for robot '" << description.name << "'.";
+            ARMARX_VERBOSE << "Failed to query joint state for robot '" << description.name << "'.";
             return std::nullopt;
         }
 
         const auto globalPose = queryGlobalPose(description, timestamp);
         if (not globalPose)
         {
-            ARMARX_WARNING << "Failed to query global pose for robot " << description.name;
+            ARMARX_VERBOSE << "Failed to query global pose for robot " << description.name;
             return std::nullopt;
         }
 
@@ -235,7 +227,7 @@ namespace armarx::armem::robot_state
         }
         catch (...)
         {
-            ARMARX_WARNING << GetHandledExceptionString();
+            ARMARX_VERBOSE << GetHandledExceptionString();
             return std::nullopt;
         }
     }
@@ -268,7 +260,7 @@ namespace armarx::armem::robot_state
 
             if (not qResult.success) /* c++20 [[unlikely]] */
             {
-                ARMARX_WARNING << qResult.errorMessage;
+                ARMARX_VERBOSE << qResult.errorMessage;
                 return std::nullopt;
             }
 
@@ -276,7 +268,7 @@ namespace armarx::armem::robot_state
         }
         catch (...)
         {
-            ARMARX_WARNING << deactivateSpam(1) << "Failed to query joint state. Reason: "
+            ARMARX_VERBOSE << deactivateSpam(1) << "Failed to query joint state. Reason: "
                            << GetHandledExceptionString();
             return std::nullopt;
         }
@@ -306,7 +298,7 @@ namespace armarx::armem::robot_state
 
         if (not qResult.success) /* c++20 [[unlikely]] */
         {
-            ARMARX_WARNING << qResult.errorMessage;
+            ARMARX_VERBOSE << qResult.errorMessage;
             return {};
         }
 
@@ -339,7 +331,7 @@ namespace armarx::armem::robot_state
 
         if (not qResult.success) /* c++20 [[unlikely]] */
         {
-            ARMARX_WARNING << qResult.errorMessage;
+            ARMARX_VERBOSE << qResult.errorMessage;
             return std::nullopt;
         }
 
@@ -362,7 +354,7 @@ namespace armarx::armem::robot_state
         }
         catch (...)
         {
-            ARMARX_WARNING << deactivateSpam(1) << "Failed to query global pose. Reason: "
+            ARMARX_VERBOSE << deactivateSpam(1) << "Failed to query global pose. Reason: "
                            << GetHandledExceptionString();
             return std::nullopt;
         }
@@ -381,7 +373,7 @@ namespace armarx::armem::robot_state
 
         if (providerSegment.empty())
         {
-            ARMARX_WARNING << "No entity found";
+            ARMARX_VERBOSE << "No entity found";
             return std::nullopt;
         }
 
@@ -394,9 +386,10 @@ namespace armarx::armem::robot_state
                 instance = &i;
                 return false; // break
             });
-        if (!instance)
+
+        if (instance == nullptr)
         {
-            ARMARX_WARNING << "No entity snapshots found";
+            ARMARX_VERBOSE << "No entity snapshots found";
             return std::nullopt;
         }
 
@@ -436,6 +429,11 @@ namespace armarx::armem::robot_state
         coreSegment.forEachEntity(
             [&jointMap](const wm::Entity& entity)
             {
+                if(not entity.getLatestSnapshot().hasInstance(0))
+                {
+                    return;
+                }
+
                 const auto& entityInstance = entity.getLatestSnapshot().getInstance(0);
 
                 const auto proprioception =
@@ -525,7 +523,7 @@ namespace armarx::armem::robot_state
 
         if (not qResult.success) /* c++20 [[unlikely]] */
         {
-            ARMARX_WARNING << qResult.errorMessage;
+            ARMARX_VERBOSE << qResult.errorMessage;
             return std::nullopt;
         }
 
@@ -558,7 +556,7 @@ namespace armarx::armem::robot_state
 
         if (not qResult.success) /* c++20 [[unlikely]] */
         {
-            ARMARX_WARNING << qResult.errorMessage;
+            ARMARX_VERBOSE << qResult.errorMessage;
             return std::nullopt;
         }
 
@@ -566,6 +564,37 @@ namespace armarx::armem::robot_state
     }
 
 
+
+    std::optional<std::map<RobotReader::Hand, robot::ToFArray>> RobotReader::queryToF(const robot::RobotDescription& description,
+                         const armem::Time& timestamp) const
+    {
+                // Query all entities from provider.
+        armem::client::query::Builder qb;
+
+        ARMARX_DEBUG << "Querying ToF data for robot: " << description;
+
+        // clang-format off
+        qb
+        .coreSegments().withName(constants::proprioceptionCoreSegment)
+        .providerSegments().withName(description.name) // agent
+        .entities().all() // TODO
+        .snapshots().beforeOrAtTime(timestamp);
+        // clang-format on
+
+        const armem::client::QueryResult qResult = memoryReader.query(qb.buildQueryInput());
+
+        ARMARX_DEBUG << "Lookup result in reader: " << qResult;
+
+        if (not qResult.success) /* c++20 [[unlikely]] */
+        {
+            ARMARX_VERBOSE << qResult.errorMessage;
+            return std::nullopt;
+        }
+
+        return getToF(qResult.memory, description.name);
+    }
+
+
     std::optional<robot::PlatformState>
     RobotReader::getRobotPlatformState(const armarx::armem::wm::Memory& memory,
                                        const std::string& name) const
@@ -580,6 +609,11 @@ namespace armarx::armem::robot_state
         coreSegment.forEachEntity(
             [&platformState](const wm::Entity& entity)
             {
+                if(not entity.getLatestSnapshot().hasInstance(0))
+                {
+                    return;
+                }
+
                 const auto& entityInstance = entity.getLatestSnapshot().getInstance(0);
 
                 const auto proprioception =
@@ -623,6 +657,11 @@ namespace armarx::armem::robot_state
         coreSegment.forEachEntity(
             [&forceTorques](const wm::Entity& entity)
             {
+                if(not entity.getLatestSnapshot().hasInstance(0))
+                {
+                    return;
+                }
+
                 const auto& entityInstance = entity.getLatestSnapshot().getInstance(0);
 
                 const auto proprioception =
@@ -675,6 +714,48 @@ namespace armarx::armem::robot_state
         return forceTorques;
     }
 
+    std::map<RobotReader::Hand, robot::ToFArray>
+    RobotReader::getToF(const armarx::armem::wm::Memory& memory,
+                                const std::string& name) const
+    {
+        std::map<RobotReader::Hand, robot::ToFArray> tofs;
+
+        // clang-format off
+        const armem::wm::CoreSegment& coreSegment = memory
+                .getCoreSegment(constants::proprioceptionCoreSegment);
+        // clang-format on
+
+        coreSegment.forEachEntity(
+            [&tofs](const wm::Entity& entity)
+            {
+                ARMARX_DEBUG << "Processing ToF element";
+
+                if(not entity.getLatestSnapshot().hasInstance(0))
+                {
+                    return;
+                }
+                const auto& entityInstance = entity.getLatestSnapshot().getInstance(0);
+
+                const auto proprioception =
+                    tryCast<::armarx::armem::arondto::Proprioception>(entityInstance);
+                ARMARX_CHECK(proprioception.has_value());
+
+
+                for (const auto& [handName, dtoFt] : proprioception->tof)
+                {
+                    ARMARX_DEBUG << "Processing ToF element for hand `" << handName << "`";
+
+                    robot::ToFArray tof;
+                    fromAron(dtoFt, tof);
+
+                    const auto hand = fromHandName(handName);
+                    tofs.emplace(hand, tof);
+                }
+            });
+
+        return tofs;
+    }
+
 
     std::optional<robot::RobotDescription>
     RobotReader::getRobotDescription(const armarx::armem::wm::Memory& memory,
@@ -691,7 +772,7 @@ namespace armarx::armem::robot_state
                                         { instance = &i; });
         if (instance == nullptr)
         {
-            ARMARX_WARNING << "No entity snapshots found in provider segment `" << name << "`";
+            ARMARX_VERBOSE << "No entity snapshots found in provider segment `" << name << "`";
             return std::nullopt;
         }
 
diff --git a/source/RobotAPI/libraries/armem_robot_state/client/common/RobotReader.h b/source/RobotAPI/libraries/armem_robot_state/client/common/RobotReader.h
index bb63c714180325961c434d61e4a8e31b78a84045..da57e74afa0fedc79570a31a064ef0661a0cd8f3 100644
--- a/source/RobotAPI/libraries/armem_robot_state/client/common/RobotReader.h
+++ b/source/RobotAPI/libraries/armem_robot_state/client/common/RobotReader.h
@@ -50,7 +50,7 @@ namespace armarx::armem::robot_state
 
         void registerPropertyDefinitions(::armarx::PropertyDefinitionsPtr& def);
 
-        bool synchronize(robot::Robot& obj, const armem::Time& timestamp) override;
+        [[nodiscard]] bool synchronize(robot::Robot& obj, const armem::Time& timestamp) override;
 
         std::optional<robot::Robot> get(const std::string& name,
                                         const armem::Time& timestamp) override;
@@ -58,8 +58,7 @@ namespace armarx::armem::robot_state
                          const armem::Time& timestamp) override;
 
         std::optional<robot::RobotDescription> queryDescription(const std::string& name,
-                                                                const armem::Time& timestamp,
-                                                                bool warnings = true);
+                                                                const armem::Time& timestamp);
 
         std::optional<robot::RobotState> queryState(const robot::RobotDescription& description,
                                                     const armem::Time& timestamp);
@@ -100,6 +99,10 @@ namespace armarx::armem::robot_state
                           const armem::Time& start,
                           const armem::Time& end) const;
 
+
+        std::optional<std::map<Hand, robot::ToFArray>> queryToF(const robot::RobotDescription& description,
+                         const armem::Time& timestamp) const;
+
         /**
          * @brief retrieve the robot's pose in the odometry frame. 
          *
@@ -142,6 +145,9 @@ namespace armarx::armem::robot_state
         std::map<RobotReader::Hand, std::map<armem::Time, robot::ForceTorque>>
         getForceTorques(const armarx::armem::wm::Memory& memory, const std::string& name) const;
 
+        std::map<RobotReader::Hand, robot::ToFArray>
+        getToF(const armarx::armem::wm::Memory& memory, const std::string& name) const;
+
         struct Properties
         {
         } properties;
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 8c1f8dfb0ad4f6f833d27191588fc8d766998235..4f03377e988f5a573e966a146bc335ed6494c2a7 100644
--- a/source/RobotAPI/libraries/armem_robot_state/client/common/VirtualRobotReader.cpp
+++ b/source/RobotAPI/libraries/armem_robot_state/client/common/VirtualRobotReader.cpp
@@ -47,7 +47,7 @@ namespace armarx::armem::robot_state
         const auto robotState = queryState(robotDescription, timestamp);
         if (not robotState)
         {
-            ARMARX_WARNING << "Querying robot state failed for robot `" << robot.getName() << "` "
+            ARMARX_VERBOSE << "Querying robot state failed for robot `" << robot.getName() << "` "
                            << "(type `"<< robot.getType() << "`)!";
             return false;
         }
@@ -61,19 +61,16 @@ namespace armarx::armem::robot_state
     VirtualRobot::RobotPtr
     VirtualRobotReader::getRobot(const std::string& name,
                                  const armem::Time& timestamp,
-                                 const VirtualRobot::RobotIO::RobotDescription& loadMode,
-                                 bool warnings)
+                                 const VirtualRobot::RobotIO::RobotDescription& loadMode)
     {
         ARMARX_INFO << deactivateSpam(60)
                     << "Querying robot description for robot '" << name << "'";
-        const auto description = queryDescription(name, timestamp, warnings);
+        const auto description = queryDescription(name, timestamp);
 
         if (not description)
         {
-            if (warnings)
-            {
-                ARMARX_WARNING << "The description of robot `" << name << "` is not a available!";
-            }
+            ARMARX_VERBOSE << "The description of robot `" << name << "` is not a available!";
+
             return nullptr;
         }
 
@@ -134,7 +131,7 @@ namespace armarx::armem::robot_state
             Clock::WaitFor(sleepAfterFailure);
         }
 
-        ARMARX_WARNING << "Failed to get synchronized robot `" << name << "`";
+        ARMARX_VERBOSE << "Failed to get synchronized robot `" << name << "`";
         return nullptr;
     }
 
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 d19e0483fdfa04f00579ba85b1e830f58feee241..19a184e8c4cee71e2a7866206f2ae55cd51f0d27 100644
--- a/source/RobotAPI/libraries/armem_robot_state/client/common/VirtualRobotReader.h
+++ b/source/RobotAPI/libraries/armem_robot_state/client/common/VirtualRobotReader.h
@@ -53,8 +53,7 @@ namespace armarx::armem::robot_state
         getRobot(const std::string& name,
                  const armem::Time& timestamp = armem::Time::Invalid(),
                  const VirtualRobot::RobotIO::RobotDescription& loadMode =
-                     VirtualRobot::RobotIO::RobotDescription::eStructure,
-                 bool warnings = true);
+                     VirtualRobot::RobotIO::RobotDescription::eStructure);
 
         [[nodiscard]] VirtualRobot::RobotPtr
         getSynchronizedRobot(const std::string& name,
diff --git a/source/RobotAPI/libraries/armem_robot_state/server/CMakeLists.txt b/source/RobotAPI/libraries/armem_robot_state/server/CMakeLists.txt
index 169d59f1a86d6a1bea1b9e54033409d23fb3cd7f..887cc2eec912ffc8bedcff94d5b19495d8fc12c1 100644
--- a/source/RobotAPI/libraries/armem_robot_state/server/CMakeLists.txt
+++ b/source/RobotAPI/libraries/armem_robot_state/server/CMakeLists.txt
@@ -44,6 +44,7 @@ armarx_add_library(
         proprioception/RobotUnitReader.h
 
         proprioception/converters/Armar6Converter.h
+        proprioception/converters/ArmarDEConverter.h
         proprioception/converters/ConverterTools.h
         proprioception/converters/ConverterRegistry.h
         proprioception/converters/ConverterInterface.h
@@ -63,6 +64,7 @@ armarx_add_library(
         proprioception/RobotUnitReader.cpp
 
         proprioception/converters/Armar6Converter.cpp
+        proprioception/converters/ArmarDEConverter.cpp
         proprioception/converters/ConverterTools.cpp
         proprioception/converters/ConverterRegistry.cpp
         proprioception/converters/ConverterInterface.cpp
diff --git a/source/RobotAPI/libraries/armem_robot_state/server/proprioception/converters/ArmarDEConverter.cpp b/source/RobotAPI/libraries/armem_robot_state/server/proprioception/converters/ArmarDEConverter.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a4ac7a8c3a2daf23f80cbb5d88c3290915190129
--- /dev/null
+++ b/source/RobotAPI/libraries/armem_robot_state/server/proprioception/converters/ArmarDEConverter.cpp
@@ -0,0 +1,296 @@
+#include "ArmarDEConverter.h"
+#include <cmath>
+#include <string>
+
+#include <SimoxUtility/algorithm/get_map_keys_values.h>
+#include <SimoxUtility/algorithm/advanced.h>
+#include "ArmarXCore/core/exceptions/local/ExpressionException.h"
+
+#include <RobotAPI/libraries/RobotUnitDataStreamingReceiver/RobotUnitDataStreamingReceiver.h>
+#include <RobotAPI/libraries/aron/core/data/variant/container/Dict.h>
+
+#include <RobotAPI/libraries/armem_robot_state/server/proprioception/aron_conversions.h>
+
+#include "ConverterTools.h"
+
+
+namespace armarx::armem::server::robot_state::proprioception
+{
+
+    ArmarDEConverter::ArmarDEConverter() :
+        tools(std::make_unique<ConverterTools>())
+    {
+    }
+
+
+    ArmarDEConverter::~ArmarDEConverter()
+    {
+    }
+
+
+    aron::data::DictPtr
+    ArmarDEConverter::convert(
+        const RobotUnitDataStreaming::TimeStep& data,
+        const RobotUnitDataStreaming::DataStreamingDescription& description)
+    {
+        arondto::Proprioception dto;
+        dto.iterationID = data.iterationId;
+
+        for (const auto& [dataEntryName, dataEntry] : description.entries)
+        {
+            process(dto, dataEntryName, {data, dataEntry});
+        }
+
+        // resize to square 
+        for(auto& [_, tof] : dto.tof)
+        {
+            const int sr = std::sqrt(tof.array.size());
+            const bool isSquare = (sr * sr == tof.array.size());
+
+            if(tof.array.size() > 0 and isSquare)
+            {
+                tof.array.resize(sr, sr);
+            }
+        }
+        
+
+        return dto.toAron();
+    }
+
+
+    void ArmarDEConverter::process(
+        arondto::Proprioception& dto,
+        const std::string& entryName,
+        const ConverterValue& value)
+    {
+        const std::vector<std::string> split = simox::alg::split(entryName, ".", false, false);
+        ARMARX_CHECK_GREATER_EQUAL(split.size(), 3);
+        const std::set<size_t> acceptedSizes{3, 4, 5};
+        ARMARX_CHECK_GREATER(acceptedSizes.count(split.size()), 0)
+                << "Data entry name could not be parsed (exected 3 or 4 or 5 components between '.'): "
+                << "\n- split: '" << split << "'";
+
+        const std::string& category = split.at(0);
+        const std::string& name = split.at(1);
+        const std::string& field = split.at(2);
+        ARMARX_CHECK_EQUAL(category, "sens") << category << " | " << entryName;
+
+        if (name == "Platform")
+        {
+            // Platform
+            processPlatformEntry(dto.platform, field, value);
+        }
+        else if (simox::alg::starts_with(name, "FT"))
+        {
+            // Force Torque
+            processForceTorqueEntry(dto.forceTorque, split, value);
+        }
+        else if (simox::alg::contains(field, "tofDepth"))
+        {
+            // ARMARX_DEBUG << "Processing ToF sensor data";
+            processToFEntry(dto.tof, split, value);
+        }
+        else
+        {
+            // Joint
+            bool processed = processJointEntry(dto.joints, split, value);
+            if (not processed)
+            {
+                // Fallback: Put in extra.
+                const std::vector<std::string> comps{simox::alg::advanced(split.begin(), 1), split.end()};
+                const std::string key = simox::alg::join(comps, ".");
+
+                switch (value.entry.type)
+                {
+                    case RobotUnitDataStreaming::NodeTypeFloat:
+                        dto.extraFloats[key] = getValueAs<float>(value);
+                        break;
+                    case RobotUnitDataStreaming::NodeTypeLong:
+                        dto.extraLongs[key] = getValueAs<long>(value);
+                        break;
+                    default:
+                        ARMARX_DEBUG << "Cannot handle extra field '" << key << "' of type "
+                                     << RobotUnitDataStreaming::DataEntryNames.to_name(value.entry.type);
+                        break;
+                }
+            }
+        }
+    }
+
+
+
+    void ArmarDEConverter::processPlatformEntry(
+        prop::arondto::Platform& dto,
+        const std::string& fieldName,
+        const ConverterValue& value)
+    {
+        if (findByPrefix(fieldName, tools->platformIgnored))
+        {
+            return;
+        }
+        else if (auto getter = findByPrefix(fieldName, tools->platformPoseGetters))
+        {
+            if (Eigen::Vector3f* dst = getter(dto))
+            {
+                if (auto setter = findBySuffix(fieldName, tools->vector3fSetters))
+                {
+                    setter(*dst, getValueAs<float>(value));
+                }
+            }
+        }
+        else
+        {
+            // No setter for this field. Put in extra.
+            dto.extra[fieldName] = getValueAs<float>(value);
+        }
+    }
+
+
+    void ArmarDEConverter::processForceTorqueEntry(
+        std::map<std::string, prop::arondto::ForceTorque>& fts,
+        const std::vector<std::string>& split,
+        const ConverterValue& value)
+    {
+        const std::string& name = split.at(1);
+        std::vector<std::string> splitName = simox::alg::split(name, " ", false, false);
+        ARMARX_CHECK_EQUAL(splitName.size(), 2);
+        ARMARX_CHECK_EQUAL(splitName.at(0), "FT");
+
+        auto it = tools->sidePrefixMap.find(splitName.at(1));
+        ARMARX_CHECK(it != tools->sidePrefixMap.end()) << splitName.at(1);
+
+        const std::string& side = it->second;
+        processForceTorqueEntry(fts[side], split, value);
+    }
+
+    void ArmarDEConverter::processToFEntry(
+            std::map<std::string, prop::arondto::ToF>& tofs,
+            const std::vector<std::string>& split,
+            const ConverterValue& value)
+    {
+        // split e.g. "sens.LeftHand.tofDepth.element_15" (split at dot)
+        
+        ARMARX_CHECK_EQUAL(split.size(), 4);
+        ARMARX_CHECK_EQUAL(split.at(2), "tofDepth");
+
+        const std::string& name = split.at(1);
+
+        // element 0 sens
+        // element 1 is either LeftHand or RightHand
+
+        const std::map<std::string, std::string> sidePrefixMap
+        {
+            {"LeftHand", "Left"},
+            {"RightHand", "Right"}
+        };
+
+        auto it = sidePrefixMap.find(name);
+        ARMARX_CHECK(it != sidePrefixMap.end()) << name;
+
+        const std::string& side = it->second;
+        processToFEntry(tofs[side], split, value);
+    }
+    
+    void ArmarDEConverter::processToFEntry(prop::arondto::ToF& tof,
+                const std::vector<std::string>& split,
+                const ConverterValue& value)
+    {
+        // split, e.g., element_12
+        const std::vector<std::string> elements = simox::alg::split(split.back(), "_");
+        ARMARX_CHECK_EQUAL(elements.size(), 2);
+
+        const int idx = std::stoi(elements.at(1));
+
+        if(tof.array.size() < (idx +1))
+        {
+            tof.array.resize(idx+1, 1);
+        }
+
+        tof.array(idx) = getValueAs<float>(value);
+    }
+
+
+    void ArmarDEConverter::processForceTorqueEntry(
+        prop::arondto::ForceTorque& dto,
+        const std::vector<std::string>& split,
+        const ConverterValue& value)
+    {
+        const std::string& fieldName = split.at(2);
+        if (auto getter = findByPrefix(fieldName, tools->ftGetters))
+        {
+            if (Eigen::Vector3f* dst = getter(dto))
+            {
+                if (auto setter = findBySuffix(fieldName, tools->vector3fSetters))
+                {
+                    setter(*dst, getValueAs<float>(value));
+                }
+            }
+        }
+        else
+        {
+            // No setter for this field. Put in extra.
+            std::string key = split.size() == 4
+                              ? (fieldName + "." + split.at(3))
+                              : fieldName;
+
+            switch (value.entry.type)
+            {
+                case RobotUnitDataStreaming::NodeTypeFloat:
+                    dto.extra[key] = getValueAs<float>(value);
+                    break;
+                case RobotUnitDataStreaming::NodeTypeInt:
+                    dto.extra[key] = getValueAs<int>(value);
+                    break;
+                case RobotUnitDataStreaming::NodeTypeLong:
+                    dto.extra[key] = getValueAs<long>(value);
+                    break;
+                default:
+                    ARMARX_DEBUG << "Cannot handle extra field '" << key << "' of type "
+                                    << RobotUnitDataStreaming::DataEntryNames.to_name(value.entry.type);
+                    break;
+            }
+        }
+    }
+
+
+    bool ArmarDEConverter::processJointEntry(
+        prop::arondto::Joints& dto,
+        const std::vector<std::string>& split,
+        const ConverterValue& value)
+    {
+        const std::string& jointName = split.at(1);
+        const std::string& fieldName = split.at(2);
+        if (false)
+        {
+            // Only in simulation.
+            if (auto getter = findByPrefix(fieldName, tools->jointGetters))
+            {
+                if (std::map<std::string, float>* map = getter(dto))
+                {
+                    (*map)[jointName] = getValueAs<float>(value);
+                }
+            }
+        }
+
+        const std::string tempSuffix = "Temperature";
+        if (simox::alg::ends_with(split.at(2), tempSuffix))
+        {
+            // Handle "dieTemperature" etc
+            const std::string name = split.at(2).substr(0, split.at(2).size() - tempSuffix.size());
+            dto.temperature[split.at(1)][name] = getValueAs<float>(value);
+            return true;
+        }
+        else if (auto it = tools->jointSetters.find(fieldName); it != tools->jointSetters.end())
+        {
+            const ConverterTools::JointSetter& setter = it->second;
+            setter(dto, split, value);
+            return true;
+        }
+        else
+        {
+            // ARMARX_DEBUG << "Ignoring unhandled field: '" << simox::alg::join(split, ".") << "'";
+            return false;
+        }
+    }
+
+}
diff --git a/source/RobotAPI/libraries/armem_robot_state/server/proprioception/converters/ArmarDEConverter.h b/source/RobotAPI/libraries/armem_robot_state/server/proprioception/converters/ArmarDEConverter.h
new file mode 100644
index 0000000000000000000000000000000000000000..6f5c287159d10fa252ae2f21215e1328c52cf6e8
--- /dev/null
+++ b/source/RobotAPI/libraries/armem_robot_state/server/proprioception/converters/ArmarDEConverter.h
@@ -0,0 +1,78 @@
+#pragma once
+
+#include <map>
+#include <string>
+
+#include <Eigen/Core>
+
+#include <RobotAPI/libraries/armem_robot_state/aron/Proprioception.aron.generated.h>
+
+#include "ConverterInterface.h"
+
+
+
+namespace armarx::armem::server::robot_state::proprioception
+{
+    struct ConverterValue;
+    class ConverterTools;
+
+
+    class ArmarDEConverter : public ConverterInterface
+    {
+    public:
+
+        ArmarDEConverter();
+        virtual ~ArmarDEConverter() override;
+
+
+        aron::data::DictPtr
+        convert(
+            const RobotUnitDataStreaming::TimeStep& data,
+            const RobotUnitDataStreaming::DataStreamingDescription& description) override;
+
+
+    protected:
+
+        void process(arondto::Proprioception& dto, const std::string& entryName, const ConverterValue& value);
+
+
+
+    private:
+
+        void processPlatformEntry(
+            prop::arondto::Platform& dto,
+            const std::string& fieldName,
+            const ConverterValue& value);
+
+        void processForceTorqueEntry(
+            std::map<std::string, prop::arondto::ForceTorque>& fts,
+            const std::vector<std::string>& split,
+            const ConverterValue& value);
+
+        void processForceTorqueEntry(
+            prop::arondto::ForceTorque& ft,
+            const std::vector<std::string>& split,
+            const ConverterValue& value);
+
+        void processToFEntry(
+            std::map<std::string, prop::arondto::ToF>& fts,
+            const std::vector<std::string>& split,
+            const ConverterValue& value);
+
+        void processToFEntry(
+            prop::arondto::ToF& tof,
+            const std::vector<std::string>& split,
+            const ConverterValue& value);
+
+        bool processJointEntry(
+            prop::arondto::Joints& dto,
+            const std::vector<std::string>& split,
+            const ConverterValue& value);
+
+
+    private:
+
+        std::unique_ptr<ConverterTools> tools;
+
+    };
+}
diff --git a/source/RobotAPI/libraries/armem_robot_state/server/proprioception/converters/ConverterRegistry.cpp b/source/RobotAPI/libraries/armem_robot_state/server/proprioception/converters/ConverterRegistry.cpp
index 0c6baa3b770e2136543be7885b1e856a7e93bb78..48ea1537572cdc50488190da9c6c69a7cbb024ae 100644
--- a/source/RobotAPI/libraries/armem_robot_state/server/proprioception/converters/ConverterRegistry.cpp
+++ b/source/RobotAPI/libraries/armem_robot_state/server/proprioception/converters/ConverterRegistry.cpp
@@ -1,6 +1,7 @@
 #include "ConverterRegistry.h"
 
 #include "Armar6Converter.h"
+#include "ArmarDEConverter.h"
 
 #include <SimoxUtility/algorithm/get_map_keys_values.h>
 
@@ -11,7 +12,7 @@ namespace armarx::armem::server::robot_state::proprioception
     ConverterRegistry::ConverterRegistry()
     {
         add<Armar6Converter>("Armar6");
-        add<Armar6Converter>("ArmarDE");
+        add<ArmarDEConverter>("ArmarDE");
         add<Armar6Converter>("Armar7");
     }