diff --git a/.gitlab/CODEOWNERS b/.gitlab/CODEOWNERS
index af86e2ce7810f25704e7afbbbb3072e53e36b487..2a5d5735c0809d89c455cfced4ecd1ca96bc961d 100644
--- a/.gitlab/CODEOWNERS
+++ b/.gitlab/CODEOWNERS
@@ -1,17 +1,17 @@
 # ARON
 
-/source/RobotAPI/libraries/aron/ @fratty @dreher
+/source/RobotAPI/libraries/aron/ @peller @dreher
 
-/source/RobotAPI/interface/aron/ @fratty @dreher
-/source/RobotAPI/interface/aron.ice @fratty @dreher
+/source/RobotAPI/interface/aron/ @peller @dreher
+/source/RobotAPI/interface/aron.ice @peller @dreher
 
 
 # ArMem
-/source/RobotAPI/components/armem/ @fratty @RainerKartmann @dreher
+/source/RobotAPI/components/armem/ @peller @kartmann @dreher
 
-/source/RobotAPI/libraries/armem/ @fratty @RainerKartmann @dreher
-/source/RobotAPI/libraries/armem_robot_localization/ @FabianReister
-/source/RobotAPI/libraries/armem_robot_mapping/ @FabianReister
+/source/RobotAPI/libraries/armem/ @peller @kartmann @dreher
+/source/RobotAPI/libraries/armem_robot_localization/ @reister
+/source/RobotAPI/libraries/armem_robot_mapping/ @reister
 
 /source/RobotAPI/interface/armem/ @fratty @RainerKartmann @dreher
 /source/RobotAPI/interface/armem.ice @fratty @RainerKartmann @dreher
diff --git a/scenarios/ArMemExample/config/ExampleMemory.cfg b/scenarios/ArMemExample/config/ExampleMemory.cfg
index 7989108bc28741f5c638fe53de5608ecaf8c7612..251382f2af086afccf73924421ea31a2aad01017 100644
--- a/scenarios/ArMemExample/config/ExampleMemory.cfg
+++ b/scenarios/ArMemExample/config/ExampleMemory.cfg
@@ -143,21 +143,12 @@ ArmarX.ArMemExampleMemory.tpc.pub.MemoryListener = MemoryUpdates
 # ArmarX.ExampleMemory.mem.MemoryName = Example
 
 
-# ArmarX.ExampleMemory.mem.ltm..buffer.storeFreq:  Frequency to store the buffer to the LTM in Hz.
+# ArmarX.ExampleMemory.mem.ltm.configuration:  
 #  Attributes:
-#  - Default:            10
+#  - Default:            {}
 #  - Case sensitivity:   yes
 #  - Required:           no
-# ArmarX.ExampleMemory.mem.ltm..buffer.storeFreq = 10
-
-
-# ArmarX.ExampleMemory.mem.ltm.depthImageExtractor.Enabled:  
-#  Attributes:
-#  - Default:            true
-#  - Case sensitivity:   yes
-#  - Required:           no
-#  - Possible values: {0, 1, false, no, true, yes}
-# ArmarX.ExampleMemory.mem.ltm.depthImageExtractor.Enabled = true
+# ArmarX.ExampleMemory.mem.ltm.configuration = {}
 
 
 # ArmarX.ExampleMemory.mem.ltm.enabled:  
@@ -169,100 +160,6 @@ ArmarX.ArMemExampleMemory.tpc.pub.MemoryListener = MemoryUpdates
 # ArmarX.ExampleMemory.mem.ltm.enabled = false
 
 
-# ArmarX.ExampleMemory.mem.ltm.exrConverter.Enabled:  
-#  Attributes:
-#  - Default:            true
-#  - Case sensitivity:   yes
-#  - Required:           no
-#  - Possible values: {0, 1, false, no, true, yes}
-# ArmarX.ExampleMemory.mem.ltm.exrConverter.Enabled = true
-
-
-# ArmarX.ExampleMemory.mem.ltm.imageExtractor.Enabled:  
-#  Attributes:
-#  - Default:            true
-#  - Case sensitivity:   yes
-#  - Required:           no
-#  - Possible values: {0, 1, false, no, true, yes}
-# ArmarX.ExampleMemory.mem.ltm.imageExtractor.Enabled = true
-
-
-# ArmarX.ExampleMemory.mem.ltm.memFreqFilter.Enabled:  
-#  Attributes:
-#  - Default:            false
-#  - Case sensitivity:   yes
-#  - Required:           no
-#  - Possible values: {0, 1, false, no, true, yes}
-# ArmarX.ExampleMemory.mem.ltm.memFreqFilter.Enabled = false
-
-
-# ArmarX.ExampleMemory.mem.ltm.memFreqFilter.WaitingTime:  Waiting time in MS after each LTM update.
-#  Attributes:
-#  - Default:            -1
-#  - Case sensitivity:   yes
-#  - Required:           no
-# ArmarX.ExampleMemory.mem.ltm.memFreqFilter.WaitingTime = -1
-
-
-# ArmarX.ExampleMemory.mem.ltm.pngConverter.Enabled:  
-#  Attributes:
-#  - Default:            true
-#  - Case sensitivity:   yes
-#  - Required:           no
-#  - Possible values: {0, 1, false, no, true, yes}
-# ArmarX.ExampleMemory.mem.ltm.pngConverter.Enabled = true
-
-
-# ArmarX.ExampleMemory.mem.ltm.sizeToCompressDataInMegaBytes:  The size in MB to compress away the current export. Exports are numbered (lower number means newer).
-#  Attributes:
-#  - Default:            1024
-#  - Case sensitivity:   yes
-#  - Required:           no
-# ArmarX.ExampleMemory.mem.ltm.sizeToCompressDataInMegaBytes = 1024
-
-
-# ArmarX.ExampleMemory.mem.ltm.snapEqFilter.Enabled:  
-#  Attributes:
-#  - Default:            false
-#  - Case sensitivity:   yes
-#  - Required:           no
-#  - Possible values: {0, 1, false, no, true, yes}
-# ArmarX.ExampleMemory.mem.ltm.snapEqFilter.Enabled = false
-
-
-# ArmarX.ExampleMemory.mem.ltm.snapEqFilter.MaxWaitingTime:  Max Waiting time in MS after each Entity update.
-#  Attributes:
-#  - Default:            -1
-#  - Case sensitivity:   yes
-#  - Required:           no
-# ArmarX.ExampleMemory.mem.ltm.snapEqFilter.MaxWaitingTime = -1
-
-
-# ArmarX.ExampleMemory.mem.ltm.snapFreqFilter.Enabled:  
-#  Attributes:
-#  - Default:            false
-#  - Case sensitivity:   yes
-#  - Required:           no
-#  - Possible values: {0, 1, false, no, true, yes}
-# ArmarX.ExampleMemory.mem.ltm.snapFreqFilter.Enabled = false
-
-
-# ArmarX.ExampleMemory.mem.ltm.snapFreqFilter.WaitingTime:  Waiting time in MS after each Entity update.
-#  Attributes:
-#  - Default:            -1
-#  - Case sensitivity:   yes
-#  - Required:           no
-# ArmarX.ExampleMemory.mem.ltm.snapFreqFilter.WaitingTime = -1
-
-
-# ArmarX.ExampleMemory.mem.ltm.storagepath:  The path to the memory storage (the memory will be stored in a seperate subfolder).
-#  Attributes:
-#  - Default:            Default value not mapped.
-#  - Case sensitivity:   yes
-#  - Required:           no
-# ArmarX.ExampleMemory.mem.ltm.storagepath = Default value not mapped.
-
-
 # ArmarX.ExampleMemory.mns.MemoryNameSystemEnabled:  Whether to use (and depend on) the Memory Name System (MNS).
 # Set to false to use this memory as a stand-alone.
 #  Attributes:
diff --git a/scenarios/SkillProviderTest/config/SkillsMemory.cfg b/scenarios/SkillProviderTest/config/SkillsMemory.cfg
index 711047a4029175550111268cf857a613c2dd48b2..8b2bf04855a21e5a8ca955da89ba3a309460241e 100644
--- a/scenarios/SkillProviderTest/config/SkillsMemory.cfg
+++ b/scenarios/SkillProviderTest/config/SkillsMemory.cfg
@@ -167,21 +167,12 @@
 # ArmarX.SkillMemory.mem.MemoryName = Skill
 
 
-# ArmarX.SkillMemory.mem.ltm..buffer.storeFreq:  Frequency to store the buffer to the LTM in Hz.
+# ArmarX.SkillMemory.mem.ltm.configuration:  
 #  Attributes:
-#  - Default:            10
+#  - Default:            {}
 #  - Case sensitivity:   yes
 #  - Required:           no
-# ArmarX.SkillMemory.mem.ltm..buffer.storeFreq = 10
-
-
-# ArmarX.SkillMemory.mem.ltm.depthImageExtractor.Enabled:  
-#  Attributes:
-#  - Default:            true
-#  - Case sensitivity:   yes
-#  - Required:           no
-#  - Possible values: {0, 1, false, no, true, yes}
-# ArmarX.SkillMemory.mem.ltm.depthImageExtractor.Enabled = true
+# ArmarX.SkillMemory.mem.ltm.configuration = {}
 
 
 # ArmarX.SkillMemory.mem.ltm.enabled:  
@@ -193,100 +184,6 @@
 # ArmarX.SkillMemory.mem.ltm.enabled = false
 
 
-# ArmarX.SkillMemory.mem.ltm.exrConverter.Enabled:  
-#  Attributes:
-#  - Default:            true
-#  - Case sensitivity:   yes
-#  - Required:           no
-#  - Possible values: {0, 1, false, no, true, yes}
-# ArmarX.SkillMemory.mem.ltm.exrConverter.Enabled = true
-
-
-# ArmarX.SkillMemory.mem.ltm.imageExtractor.Enabled:  
-#  Attributes:
-#  - Default:            true
-#  - Case sensitivity:   yes
-#  - Required:           no
-#  - Possible values: {0, 1, false, no, true, yes}
-# ArmarX.SkillMemory.mem.ltm.imageExtractor.Enabled = true
-
-
-# ArmarX.SkillMemory.mem.ltm.memFreqFilter.Enabled:  
-#  Attributes:
-#  - Default:            false
-#  - Case sensitivity:   yes
-#  - Required:           no
-#  - Possible values: {0, 1, false, no, true, yes}
-# ArmarX.SkillMemory.mem.ltm.memFreqFilter.Enabled = false
-
-
-# ArmarX.SkillMemory.mem.ltm.memFreqFilter.WaitingTime:  Waiting time in MS after each LTM update.
-#  Attributes:
-#  - Default:            -1
-#  - Case sensitivity:   yes
-#  - Required:           no
-# ArmarX.SkillMemory.mem.ltm.memFreqFilter.WaitingTime = -1
-
-
-# ArmarX.SkillMemory.mem.ltm.pngConverter.Enabled:  
-#  Attributes:
-#  - Default:            true
-#  - Case sensitivity:   yes
-#  - Required:           no
-#  - Possible values: {0, 1, false, no, true, yes}
-# ArmarX.SkillMemory.mem.ltm.pngConverter.Enabled = true
-
-
-# ArmarX.SkillMemory.mem.ltm.sizeToCompressDataInMegaBytes:  The size in MB to compress away the current export. Exports are numbered (lower number means newer).
-#  Attributes:
-#  - Default:            1024
-#  - Case sensitivity:   yes
-#  - Required:           no
-# ArmarX.SkillMemory.mem.ltm.sizeToCompressDataInMegaBytes = 1024
-
-
-# ArmarX.SkillMemory.mem.ltm.snapEqFilter.Enabled:  
-#  Attributes:
-#  - Default:            false
-#  - Case sensitivity:   yes
-#  - Required:           no
-#  - Possible values: {0, 1, false, no, true, yes}
-# ArmarX.SkillMemory.mem.ltm.snapEqFilter.Enabled = false
-
-
-# ArmarX.SkillMemory.mem.ltm.snapEqFilter.MaxWaitingTime:  Max Waiting time in MS after each Entity update.
-#  Attributes:
-#  - Default:            -1
-#  - Case sensitivity:   yes
-#  - Required:           no
-# ArmarX.SkillMemory.mem.ltm.snapEqFilter.MaxWaitingTime = -1
-
-
-# ArmarX.SkillMemory.mem.ltm.snapFreqFilter.Enabled:  
-#  Attributes:
-#  - Default:            false
-#  - Case sensitivity:   yes
-#  - Required:           no
-#  - Possible values: {0, 1, false, no, true, yes}
-# ArmarX.SkillMemory.mem.ltm.snapFreqFilter.Enabled = false
-
-
-# ArmarX.SkillMemory.mem.ltm.snapFreqFilter.WaitingTime:  Waiting time in MS after each Entity update.
-#  Attributes:
-#  - Default:            -1
-#  - Case sensitivity:   yes
-#  - Required:           no
-# ArmarX.SkillMemory.mem.ltm.snapFreqFilter.WaitingTime = -1
-
-
-# ArmarX.SkillMemory.mem.ltm.storagepath:  The path to the memory storage (the memory will be stored in a seperate subfolder).
-#  Attributes:
-#  - Default:            Default value not mapped.
-#  - Case sensitivity:   yes
-#  - Required:           no
-# ArmarX.SkillMemory.mem.ltm.storagepath = Default value not mapped.
-
-
 # ArmarX.SkillMemory.mns.MemoryNameSystemEnabled:  Whether to use (and depend on) the Memory Name System (MNS).
 # Set to false to use this memory as a stand-alone.
 #  Attributes:
diff --git a/source/RobotAPI/components/ArViz/Client/Elements.cpp b/source/RobotAPI/components/ArViz/Client/Elements.cpp
index f479f4ef5456fc7a88d0f3a0fa87d2e77e9aab66..d97fea3b03d55ddb82a379628197a5f04ffc3d74 100644
--- a/source/RobotAPI/components/ArViz/Client/Elements.cpp
+++ b/source/RobotAPI/components/ArViz/Client/Elements.cpp
@@ -107,9 +107,9 @@ namespace armarx::viz
         float angle = std::acos(naturalDir.dot(dir));
         if (cross.squaredNorm() < 1.0e-12f)
         {
-            // Directions are almost colinear ==> Do no rotation
+            // Directions are almost colinear ==> Angle is either 0 or 180 deg
             cross = Eigen::Vector3f::UnitX();
-            angle = 0.0f;
+            // Keep angle
         }
         Eigen::Vector3f axis = cross.normalized();
         Eigen::Quaternionf ori(Eigen::AngleAxisf(angle, axis));
diff --git a/source/RobotAPI/components/ArViz/Example/ArVizExample.cpp b/source/RobotAPI/components/ArViz/Example/ArVizExample.cpp
index 2c93faf7fa4a464909bd6dea214c74022571474f..e52609fa085feac2dc4ef8fc93f68127aef8b040 100644
--- a/source/RobotAPI/components/ArViz/Example/ArVizExample.cpp
+++ b/source/RobotAPI/components/ArViz/Example/ArVizExample.cpp
@@ -275,13 +275,18 @@ namespace armarx
 
     void fillExampleLayer(viz::Layer& layer, double timeInSeconds)
     {
+        for (int i = 0; i < 6; ++i)
         {
-            Eigen::Vector3f pos = Eigen::Vector3f::Zero();
-            pos.z() = +300.0f;
+            Eigen::Vector3f pos = Eigen::Vector3f(-200.0, 200.0, 300);
+            pos.x() +=  -300 * i;
+
+            Eigen::Vector3f normal = Eigen::Vector3f::Zero();
+            normal(i / 2) = (i % 2 == 0 ? 1.0 : -1.0);
 
-            viz::ArrowCircle circle = viz::ArrowCircle("circle")
+            viz::ArrowCircle circle = viz::ArrowCircle("circle " + std::to_string(i))
                                       .position(pos)
                                       .radius(100.0f)
+                                      .normal(normal)
                                       .width(10.0f)
                                       .color(viz::Color::fromRGBA(255, 0, 255));
 
diff --git a/source/RobotAPI/components/armem/server/RobotStateMemory/RobotStateMemory.cpp b/source/RobotAPI/components/armem/server/RobotStateMemory/RobotStateMemory.cpp
index eab8bf5e6dd721395647519d3e04fecc62ffbb7f..f77e01607b0036a2f9525b88dc919f0f1882608b 100644
--- a/source/RobotAPI/components/armem/server/RobotStateMemory/RobotStateMemory.cpp
+++ b/source/RobotAPI/components/armem/server/RobotStateMemory/RobotStateMemory.cpp
@@ -47,6 +47,7 @@ namespace armarx::armem::server::robot_state
     RobotStateMemory::RobotStateMemory() :
         descriptionSegment(iceAdapter()),
         proprioceptionSegment(iceAdapter()),
+        exteroceptionSegment(iceAdapter()),
         localizationSegment(iceAdapter()),
         commonVisu(descriptionSegment, proprioceptionSegment, localizationSegment)
     {
@@ -86,6 +87,7 @@ namespace armarx::armem::server::robot_state
         setMemoryName(armem::robot_state::memoryID.memoryName);
 
         descriptionSegment.defineProperties(defs, prefix + "desc.");
+        exteroceptionSegment.defineProperties(defs, prefix + "ext.");
         proprioceptionSegment.defineProperties(defs, prefix + "prop.");
         localizationSegment.defineProperties(defs, prefix + "loc.");
         commonVisu.defineProperties(defs, prefix + "visu.");
@@ -104,6 +106,7 @@ namespace armarx::armem::server::robot_state
     {
         descriptionSegment.init();
         proprioceptionSegment.init();
+        exteroceptionSegment.init();
         localizationSegment.init();
         commonVisu.init();
 
diff --git a/source/RobotAPI/components/armem/server/RobotStateMemory/RobotStateMemory.h b/source/RobotAPI/components/armem/server/RobotStateMemory/RobotStateMemory.h
index 09280c4691a479a3bbd612131565775669bf21d1..70513a0cf56ff0cd6d82603cc3266fb405e5af3d 100644
--- a/source/RobotAPI/components/armem/server/RobotStateMemory/RobotStateMemory.h
+++ b/source/RobotAPI/components/armem/server/RobotStateMemory/RobotStateMemory.h
@@ -27,26 +27,25 @@
 
 #include <ArmarXCore/core/Component.h>
 
+#include <RobotAPI/interface/core/RobotLocalization.h>
 #include <RobotAPI/libraries/RobotAPIComponentPlugins/ArVizComponentPlugin.h>
 #include <RobotAPI/libraries/RobotUnitDataStreamingReceiver/RobotUnitDataStreamingReceiver.h>
 #include <RobotAPI/libraries/armem/server/plugins/ReadWritePluginUser.h>
-
+#include <RobotAPI/libraries/armem_robot_state/server/common/Visu.h>
 #include <RobotAPI/libraries/armem_robot_state/server/description/Segment.h>
 #include <RobotAPI/libraries/armem_robot_state/server/localization/Segment.h>
-#include <RobotAPI/libraries/armem_robot_state/server/common/Visu.h>
-#include <RobotAPI/libraries/armem_robot_state/server/proprioception/Segment.h>
 #include <RobotAPI/libraries/armem_robot_state/server/proprioception/RobotStateWriter.h>
 #include <RobotAPI/libraries/armem_robot_state/server/proprioception/RobotUnitData.h>
 #include <RobotAPI/libraries/armem_robot_state/server/proprioception/RobotUnitReader.h>
-
-#include <RobotAPI/interface/core/RobotLocalization.h>
+#include <RobotAPI/libraries/armem_robot_state/server/proprioception/Segment.h>
+#include <RobotAPI/libraries/armem_robot_state/server/exteroception/Segment.h>
 
 
 namespace armarx::plugins
 {
     class DebugObserverComponentPlugin;
     class RobotUnitComponentPlugin;
-}
+} // namespace armarx::plugins
 namespace armarx::armem::server::robot_state
 {
 
@@ -68,7 +67,6 @@ namespace armarx::armem::server::robot_state
         virtual public armarx::GlobalRobotPoseProvider
     {
     public:
-
         RobotStateMemory();
         virtual ~RobotStateMemory() override;
 
@@ -77,11 +75,12 @@ namespace armarx::armem::server::robot_state
 
 
         // GlobalRobotPoseProvider interface
-        armarx::PoseBasePtr getGlobalRobotPose(Ice::Long timestamp, const std::string& robotName, const ::Ice::Current&) override;
+        armarx::PoseBasePtr getGlobalRobotPose(Ice::Long timestamp,
+                                               const std::string& robotName,
+                                               const ::Ice::Current&) override;
 
 
     protected:
-
         armarx::PropertyDefinitionsPtr createPropertyDefinitions() override;
 
         void onInitComponent() override;
@@ -91,13 +90,11 @@ namespace armarx::armem::server::robot_state
 
 
     private:
-
         void startRobotUnitStream();
         void stopRobotUnitStream();
 
 
     private:
-
         armarx::plugins::DebugObserverComponentPlugin* debugObserver = nullptr;
 
 
@@ -109,6 +106,9 @@ namespace armarx::armem::server::robot_state
         proprioception::Segment proprioceptionSegment;
         armem::data::MemoryID robotUnitProviderID;
 
+        // - exteroception
+        exteroception::Segment exteroceptionSegment;
+
         // - localization
         localization::Segment localizationSegment;
 
@@ -129,11 +129,12 @@ namespace armarx::armem::server::robot_state
             proprioception::RobotStateWriter writer;
 
             // queue
-            TripleBuffer<std::vector<proprioception::RobotUnitData>> dataBuffer;
+            using Queue = armarx::armem::server::robot_state::proprioception::Queue;
+            Queue dataBuffer;
 
             bool waitForRobotUnit = false;
         };
         RobotUnit robotUnit;
     };
 
-}  // namespace armarx::armem::server::robot_state
+} // namespace armarx::armem::server::robot_state
diff --git a/source/RobotAPI/components/skills/SkillProviderExample/SkillProviderExample.cpp b/source/RobotAPI/components/skills/SkillProviderExample/SkillProviderExample.cpp
index bc50155edc0d42a775c63ade67e35f38e34fd8c5..985ef8171792570e6dad35d7a0abb09d78492006 100644
--- a/source/RobotAPI/components/skills/SkillProviderExample/SkillProviderExample.cpp
+++ b/source/RobotAPI/components/skills/SkillProviderExample/SkillProviderExample.cpp
@@ -20,6 +20,8 @@ namespace armarx::skills::provider
         default_params.some_float = 5;
         default_params.some_int = 42;
         default_params.some_text = "YOLO";
+        default_params.some_list_of_matrices.push_back(Eigen::Matrix3f::Zero());
+        //default_params.some_matrix = Eigen::Matrix3f::Zero();
 
         return SkillDescription{
             "HelloWorld",
diff --git a/source/RobotAPI/components/skills/SkillProviderExample/aron/HelloWorldAcceptedType.xml b/source/RobotAPI/components/skills/SkillProviderExample/aron/HelloWorldAcceptedType.xml
index 553a93ad0898ddc40d112e097af9c95ca801da55..a2423c560b8548c265af0ae14602b8771fe46218 100644
--- a/source/RobotAPI/components/skills/SkillProviderExample/aron/HelloWorldAcceptedType.xml
+++ b/source/RobotAPI/components/skills/SkillProviderExample/aron/HelloWorldAcceptedType.xml
@@ -1,6 +1,17 @@
 <?xml version="1.0" encoding="UTF-8" ?>
 <AronTypeDefinition>
     <GenerateTypes>
+        <IntEnum name="HelloWorldInteEnum">
+            <EnumValue key="INT_ENUM_VALUE_0" value="0" />
+            <EnumValue key="INT_ENUM_VALUE_1" value="1" />
+            <EnumValue key="INT_ENUM_VALUE_2" value="2" />
+            <EnumValue key="INT_ENUM_VALUE_3" value="3" />
+            <EnumValue key="INT_ENUM_VALUE_4" value="4" />
+            <EnumValue key="INT_ENUM_VALUE_5" value="5" />
+            <EnumValue key="INT_ENUM_VALUE_6" value="6" />
+            <EnumValue key="INT_ENUM_VALUE_7" value="7" />
+            <EnumValue key="INT_ENUM_VALUE_8" value="8" />
+        </IntEnum>
         <Object name='armarx::skills::Example::HelloWorldAcceptedType'>
             <ObjectChild key='some_int'>
                 <Int />
@@ -11,6 +22,23 @@
             <ObjectChild key='some_text'>
                 <String />
             </ObjectChild>
+
+            <ObjectChild key='some_list_of_matrices'>
+                <List>
+                    <Matrix rows="3" cols="3" type="float32" />
+                </List>
+            </ObjectChild>
+
+            <ObjectChild key='some_dict_of_matrices'>
+                <Dict>
+                    <Matrix rows="3" cols="3" type="float32" />
+                </Dict>
+            </ObjectChild>
+
+            <ObjectChild key='some_matrix'>
+                <Matrix rows="3" cols="3" type="float32" />
+            </ObjectChild>
+
         </Object>
     </GenerateTypes>
 
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/gui-plugins/SkillManagerPlugin/CMakeLists.txt b/source/RobotAPI/gui-plugins/SkillManagerPlugin/CMakeLists.txt
index 89a90ab482f9916ff11ad149faa1a3fc1b7d483c..b40d5a2fcf9c480a71f0576d049ad0a311813815 100644
--- a/source/RobotAPI/gui-plugins/SkillManagerPlugin/CMakeLists.txt
+++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/CMakeLists.txt
@@ -9,15 +9,22 @@ set(SOURCES
     aronTreeWidget/visitors/AronTreeWidgetConverter.cpp
     aronTreeWidget/visitors/AronTreeWidgetSetter.cpp
     aronTreeWidget/visitors/AronTreeWidgetModalCreator.cpp
+    aronTreeWidget/visitors/AronTreeWidgetContextMenu.cpp
     aronTreeWidget/Data.cpp
+    aronTreeWidget/widgets/CustomWidget.cpp
+    aronTreeWidget/widgets/EditMatrixWidget.cpp
+    aronTreeWidget/widgets/IntEnumWidget.cpp
+    aronTreeWidget/ListDictHelper.cpp
+    aronTreeWidget/widgets/QuaternionWidget.cpp
     aronTreeWidget/AronTreeWidgetItem.cpp
     aronTreeWidget/AronTreeWidgetController.cpp
-    aronTreeWidget/modal/AronTreeWidgetModal.cpp
-    aronTreeWidget/modal/int_long/AronTreeWidgetIntInputModalController.cpp
-    aronTreeWidget/modal/float_double/AronTreeWidgetFloatInputModalController.cpp
-    aronTreeWidget/modal/bool/AronTreeWidgetBoolInputModalController.cpp
     aronTreeWidget/modal/text/AronTreeWidgetTextInputModalController.cpp
     aronTreeWidget/modal/dict/AronTreeWidgetDictInputModalController.cpp
+    aronTreeWidget/modal/float_double/AronTreeWidgetFloatInputModalController.cpp
+    aronTreeWidget/modal/int_long/AronTreeWidgetIntInputModalController.cpp
+    aronTreeWidget/modal/bool/AronTreeWidgetBoolInputModalController.cpp
+    aronTreeWidget/modal/AronTreeWidgetModal.cpp
+    ColorPalettes.cpp
     SkillManagerMonitorWidgetController.cpp
 )
 
@@ -26,25 +33,29 @@ set(HEADERS
     aronTreeWidget/visitors/AronTreeWidgetConverter.h
     aronTreeWidget/visitors/AronTreeWidgetSetter.h
     aronTreeWidget/visitors/AronTreeWidgetModalCreator.h
+    aronTreeWidget/visitors/AronTreeWidgetContextMenu.h
     aronTreeWidget/Data.h
+    aronTreeWidget/widgets/NDArrayHelper.h
+    aronTreeWidget/widgets/EditMatrixWidget.h
+    aronTreeWidget/widgets/CustomWidget.h
+    aronTreeWidget/widgets/IntEnumWidget.h
+    aronTreeWidget/ListDictHelper.h
+    aronTreeWidget/widgets/QuaternionWidget.h
     aronTreeWidget/AronTreeWidgetItem.h
     aronTreeWidget/AronTreeWidgetController.h
     aronTreeWidget/modal/AronTreeWidgetModal.h
-    aronTreeWidget/modal/int_long/AronTreeWidgetIntInputModalController.h
-    aronTreeWidget/modal/float_double/AronTreeWidgetFloatInputModalController.h
-    aronTreeWidget/modal/bool/AronTreeWidgetBoolInputModalController.h
     aronTreeWidget/modal/text/AronTreeWidgetTextInputModalController.h
     aronTreeWidget/modal/dict/AronTreeWidgetDictInputModalController.h
+    aronTreeWidget/modal/float_double/AronTreeWidgetFloatInputModalController.h
+    aronTreeWidget/modal/int_long/AronTreeWidgetIntInputModalController.h
+    aronTreeWidget/modal/bool/AronTreeWidgetBoolInputModalController.h
+    ColorPalettes.h
     SkillManagerMonitorWidgetController.h
 )
 
 set(GUI_UIS
     SkillManagerMonitorWidget.ui
-    aronTreeWidget/modal/int_long/AronTreeWidgetIntInputModal.ui
-    aronTreeWidget/modal/float_double/AronTreeWidgetFloatInputModal.ui
-    aronTreeWidget/modal/bool/AronTreeWidgetBoolInputModal.ui
     aronTreeWidget/modal/text/AronTreeWidgetTextInputModal.ui
-    aronTreeWidget/modal/dict/AronTreeWidgetDictInputModal.ui
 )
 
 # Add more libraries you depend on here, e.g. ${QT_LIBRARIES}.
diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/ColorPalettes.cpp b/source/RobotAPI/gui-plugins/SkillManagerPlugin/ColorPalettes.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..05cd7a5cc08224561af8df64cf6be2347adb3e37
--- /dev/null
+++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/ColorPalettes.cpp
@@ -0,0 +1,32 @@
+#include "ColorPalettes.h"
+
+namespace armarx::gui_color_palette
+{
+    QPalette
+    getErrorPalette()
+    {
+        QPalette errorPalette;
+        errorPalette.setColor(QPalette::Base, Qt::red);
+        return errorPalette;
+    }
+    QPalette
+    getNormalPalette()
+    {
+
+        QPalette normalPalette;
+
+        normalPalette.setColor(QPalette::Base, Qt::white);
+        return normalPalette;
+    }
+
+    QPalette
+    getIndirectErrorPalette()
+    {
+        QPalette indirectErr;
+        static QColor orange = QColor::fromRgb(255, 165, 0);
+        // orange color
+        indirectErr.setColor(QPalette::Base, orange);
+        return indirectErr;
+    }
+
+} // namespace armarx::gui_color_palette
diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/ColorPalettes.h b/source/RobotAPI/gui-plugins/SkillManagerPlugin/ColorPalettes.h
new file mode 100644
index 0000000000000000000000000000000000000000..ea2c247a9428559de4be7bdb8fc1497c14b1ea00
--- /dev/null
+++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/ColorPalettes.h
@@ -0,0 +1,11 @@
+#pragma once
+#include <QPalette>
+
+namespace armarx::gui_color_palette
+{
+    QPalette getNormalPalette();
+
+    QPalette getErrorPalette();
+
+    QPalette getIndirectErrorPalette();
+} // namespace armarx::gui_color_palette
diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidget.ui b/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidget.ui
index 3aa3984c65aad167af2b49e94ab34130c880c998..1e80202efb18b2aca77e8ba45b87827e362ae233 100644
--- a/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidget.ui
+++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidget.ui
@@ -6,145 +6,187 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>1015</width>
-    <height>498</height>
+    <width>1060</width>
+    <height>657</height>
    </rect>
   </property>
+  <property name="sizePolicy">
+   <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+    <horstretch>0</horstretch>
+    <verstretch>0</verstretch>
+   </sizepolicy>
+  </property>
   <property name="windowTitle">
    <string>SkillManagerMonitorWidget</string>
   </property>
-  <layout class="QVBoxLayout" name="verticalLayout">
-   <item>
-    <widget class="QGroupBox" name="groupBoxActiveSkills">
+  <layout class="QGridLayout" name="gridLayout_3">
+   <item row="0" column="0">
+    <widget class="QSplitter" name="splitter_2">
      <property name="sizePolicy">
       <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
        <horstretch>0</horstretch>
        <verstretch>0</verstretch>
       </sizepolicy>
      </property>
-     <property name="title">
-      <string>Active Skills</string>
-     </property>
-     <layout class="QGridLayout" name="gridLayout_3">
-      <item row="0" column="0">
-       <widget class="QListWidget" name="listWidgetActiveSkills">
-        <property name="sizePolicy">
-         <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
-          <horstretch>0</horstretch>
-          <verstretch>0</verstretch>
-         </sizepolicy>
-        </property>
-       </widget>
-      </item>
-     </layout>
-    </widget>
-   </item>
-   <item>
-    <widget class="QSplitter" name="splitter">
      <property name="orientation">
-      <enum>Qt::Horizontal</enum>
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="childrenCollapsible">
+      <bool>false</bool>
      </property>
-     <widget class="QGroupBox" name="groupBoxSkills">
+     <widget class="QGroupBox" name="groupBoxActiveSkills">
+      <property name="sizePolicy">
+       <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+        <horstretch>0</horstretch>
+        <verstretch>0</verstretch>
+       </sizepolicy>
+      </property>
       <property name="title">
-       <string>Manager</string>
+       <string>Active Skills</string>
       </property>
-      <layout class="QGridLayout" name="gridLayout">
-       <item row="2" column="0">
-        <widget class="QLabel" name="label">
-         <property name="text">
-          <string>Update Frequency:</string>
+      <layout class="QGridLayout" name="gridLayout_4">
+       <item row="0" column="0">
+        <widget class="QListWidget" name="listWidgetActiveSkills">
+         <property name="sizePolicy">
+          <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+           <horstretch>0</horstretch>
+           <verstretch>0</verstretch>
+          </sizepolicy>
          </property>
         </widget>
        </item>
-       <item row="3" column="0" colspan="3">
-        <widget class="QTreeWidget" name="treeWidgetSkills">
-         <column>
+      </layout>
+     </widget>
+     <widget class="QSplitter" name="splitter">
+      <property name="sizePolicy">
+       <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+        <horstretch>0</horstretch>
+        <verstretch>0</verstretch>
+       </sizepolicy>
+      </property>
+      <property name="orientation">
+       <enum>Qt::Horizontal</enum>
+      </property>
+      <widget class="QGroupBox" name="groupBoxSkills">
+       <property name="sizePolicy">
+        <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
+         <horstretch>0</horstretch>
+         <verstretch>0</verstretch>
+        </sizepolicy>
+       </property>
+       <property name="title">
+        <string>Manager</string>
+       </property>
+       <layout class="QGridLayout" name="gridLayout">
+        <item row="2" column="0">
+         <widget class="QLabel" name="label">
           <property name="text">
-           <string>Skill</string>
+           <string>Update Frequency:</string>
           </property>
-         </column>
-         <column>
-          <property name="text">
-           <string>HasType</string>
+         </widget>
+        </item>
+        <item row="3" column="0" colspan="3">
+         <widget class="QTreeWidget" name="treeWidgetSkills">
+          <column>
+           <property name="text">
+            <string>Skill</string>
+           </property>
+          </column>
+          <column>
+           <property name="text">
+            <string>HasType</string>
+           </property>
+          </column>
+          <column>
+           <property name="text">
+            <string>State</string>
+           </property>
+          </column>
+         </widget>
+        </item>
+        <item row="2" column="1">
+         <widget class="QDoubleSpinBox" name="doubleSpinBoxUpdateFreq"/>
+        </item>
+       </layout>
+      </widget>
+      <widget class="QGroupBox" name="groupBoxSkillDetails">
+       <property name="sizePolicy">
+        <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
+         <horstretch>0</horstretch>
+         <verstretch>0</verstretch>
+        </sizepolicy>
+       </property>
+       <property name="title">
+        <string>Skill Details</string>
+       </property>
+       <layout class="QGridLayout" name="gridLayout_2">
+        <item row="1" column="0" colspan="4">
+         <widget class="QTreeWidget" name="treeWidgetSkillDetails">
+          <property name="contextMenuPolicy">
+           <enum>Qt::CustomContextMenu</enum>
+          </property>
+          <property name="editTriggers">
+           <set>QAbstractItemView::DoubleClicked|QAbstractItemView::EditKeyPressed</set>
           </property>
-         </column>
-         <column>
+          <column>
+           <property name="text">
+            <string>Key</string>
+           </property>
+          </column>
+          <column>
+           <property name="text">
+            <string>Value</string>
+           </property>
+          </column>
+          <column>
+           <property name="text">
+            <string>Type</string>
+           </property>
+          </column>
+          <column>
+           <property name="text">
+            <string>defaultValue</string>
+           </property>
+          </column>
+         </widget>
+        </item>
+        <item row="6" column="3">
+         <widget class="QPushButton" name="pushButtonExecuteSkill">
           <property name="text">
-           <string>State</string>
+           <string>Request Execution</string>
           </property>
-         </column>
-        </widget>
-       </item>
-       <item row="2" column="1">
-        <widget class="QDoubleSpinBox" name="doubleSpinBoxUpdateFreq"/>
-       </item>
-      </layout>
-     </widget>
-     <widget class="QGroupBox" name="groupBoxSkillDetails">
-      <property name="title">
-       <string>Skill Details</string>
-      </property>
-      <layout class="QGridLayout" name="gridLayout_2">
-       <item row="1" column="0" colspan="4">
-        <widget class="QTreeWidget" name="treeWidgetSkillDetails">
-         <column>
+         </widget>
+        </item>
+        <item row="0" column="0">
+         <widget class="QPushButton" name="pushButtonPaste">
           <property name="text">
-           <string>Key</string>
+           <string>Set from clipboard</string>
           </property>
-         </column>
-         <column>
+         </widget>
+        </item>
+        <item row="6" column="0">
+         <widget class="QPushButton" name="pushButtonStopSkill">
           <property name="text">
-           <string>Value</string>
+           <string>Stop current skill</string>
           </property>
-         </column>
-         <column>
+         </widget>
+        </item>
+        <item row="0" column="3">
+         <widget class="QPushButton" name="pushButtonReset">
           <property name="text">
-           <string>Type</string>
+           <string>Reset args</string>
           </property>
-         </column>
-         <column>
+         </widget>
+        </item>
+        <item row="0" column="1">
+         <widget class="QPushButton" name="pushButtonCopy">
           <property name="text">
-           <string>defaultValue</string>
+           <string>Copy args to clipboard</string>
           </property>
-         </column>
-        </widget>
-       </item>
-       <item row="6" column="3">
-        <widget class="QPushButton" name="pushButtonExecuteSkill">
-         <property name="text">
-          <string>Request Execution</string>
-         </property>
-        </widget>
-       </item>
-       <item row="0" column="0">
-        <widget class="QPushButton" name="pushButtonPaste">
-         <property name="text">
-          <string>Set from clipboard</string>
-         </property>
-        </widget>
-       </item>
-       <item row="6" column="0">
-        <widget class="QPushButton" name="pushButtonStopSkill">
-         <property name="text">
-          <string>Stop current skill</string>
-         </property>
-        </widget>
-       </item>
-       <item row="0" column="3">
-        <widget class="QPushButton" name="pushButtonReset">
-         <property name="text">
-          <string>Reset args</string>
-         </property>
-        </widget>
-       </item>
-       <item row="0" column="1">
-        <widget class="QPushButton" name="pushButtonCopy">
-         <property name="text">
-          <string>Copy args to clipboard</string>
-         </property>
-        </widget>
-       </item>
-      </layout>
+         </widget>
+        </item>
+       </layout>
+      </widget>
      </widget>
     </widget>
    </item>
diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.cpp b/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.cpp
index 27a954593ad99d252410ffec11d086689c1d9e07..edc9eebb6d619dd09de033ac2959b4858d263246 100644
--- a/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.cpp
+++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.cpp
@@ -20,52 +20,57 @@
  *             GNU General Public License
  */
 
+#include "SkillManagerMonitorWidgetController.h"
+
 #include <string>
 
-#include "SkillManagerMonitorWidgetController.h"
+#include <RobotAPI/libraries/skills/provider/Skill.h>
 
-#include "aronTreeWidget/visitors/AronTreeWidgetCreator.h"
 #include "aronTreeWidget/visitors/AronTreeWidgetConverter.h"
+#include "aronTreeWidget/visitors/AronTreeWidgetCreator.h"
 #include "aronTreeWidget/visitors/AronTreeWidgetModalCreator.h"
 
-#include <RobotAPI/libraries/skills/provider/Skill.h>
-
 // modals
 #include "aronTreeWidget/modal/text/AronTreeWidgetTextInputModalController.h"
 
 // debug
-#include <RobotAPI/libraries/aron/converter/json/NLohmannJSONConverter.h>
-
-#include <QDoubleSpinBox>
 #include <QClipboard>
+#include <QDoubleSpinBox>
+
+#include <RobotAPI/libraries/aron/converter/json/NLohmannJSONConverter.h>
 
 #include "aronTreeWidget/Data.h"
 
 //config
 namespace armarx
 {
-    QPointer<QDialog> SkillManagerMonitorWidgetController::getConfigDialog(QWidget* parent)
+    QPointer<QDialog>
+    SkillManagerMonitorWidgetController::getConfigDialog(QWidget* parent)
     {
         if (!dialog)
         {
             dialog = new SimpleConfigDialog(parent);
-            dialog->addProxyFinder<skills::manager::dti::SkillManagerInterfacePrx>("SkillManager", "", "Skill*");
+            dialog->addProxyFinder<skills::manager::dti::SkillManagerInterfacePrx>(
+                "SkillManager", "", "Skill*");
         }
         return qobject_cast<SimpleConfigDialog*>(dialog);
     }
-    void SkillManagerMonitorWidgetController::configured()
+    void
+    SkillManagerMonitorWidgetController::configured()
     {
         observerName = dialog->getProxyName("SkillManager");
     }
-    void SkillManagerMonitorWidgetController::loadSettings(QSettings* settings)
+    void
+    SkillManagerMonitorWidgetController::loadSettings(QSettings* settings)
     {
         observerName = settings->value("SkillManager", "SkillManager").toString().toStdString();
     }
-    void SkillManagerMonitorWidgetController::saveSettings(QSettings* settings)
+    void
+    SkillManagerMonitorWidgetController::saveSettings(QSettings* settings)
     {
         settings->setValue("SkillManager", QString::fromStdString(observerName));
     }
-}
+} // namespace armarx
 
 // Others
 namespace armarx
@@ -81,29 +86,40 @@ namespace armarx
         widget.doubleSpinBoxUpdateFreq->setSuffix(" Hz");
 
         refreshSkillsResultTimer = new QTimer(this);
-        refreshSkillsResultTimer->setInterval(1000 / 5);  // Keep this stable.
+        refreshSkillsResultTimer->setInterval(1000 / 5); // Keep this stable.
         refreshSkillsResultTimer->start();
 
-        connect(widget.doubleSpinBoxUpdateFreq, &QDoubleSpinBox::editingFinished,
-                this, &SkillManagerMonitorWidgetController::updateTimerFrequency);
-        connect(refreshSkillsResultTimer, &QTimer::timeout,
-                this, &SkillManagerMonitorWidgetController::refreshSkills);
-
-        connect(widget.pushButtonCopy, &QPushButton::clicked,
-                this, &SkillManagerMonitorWidgetController::copyCurrentConfig);
-        connect(widget.pushButtonPaste, &QPushButton::clicked,
-                this, &SkillManagerMonitorWidgetController::pasteCurrentConfig);
-
-        connect(widget.pushButtonExecuteSkill, &QPushButton::clicked,
-                this, &SkillManagerMonitorWidgetController::executeSkill);
-        connect(widget.pushButtonStopSkill, &QPushButton::clicked,
-                this, &SkillManagerMonitorWidgetController::stopSkill);
-
-        connect(widget.treeWidgetSkills, &QTreeWidget::currentItemChanged,
-                this, &SkillManagerMonitorWidgetController::skillSelectionChanged);
-
-        connect(widget.treeWidgetSkillDetails, &QTreeWidget::itemDoubleClicked,
-                this, &SkillManagerMonitorWidgetController::onTreeWidgetItemDoubleClicked);
+        connect(widget.doubleSpinBoxUpdateFreq,
+                &QDoubleSpinBox::editingFinished,
+                this,
+                &SkillManagerMonitorWidgetController::updateTimerFrequency);
+        connect(refreshSkillsResultTimer,
+                &QTimer::timeout,
+                this,
+                &SkillManagerMonitorWidgetController::refreshSkills);
+
+        connect(widget.pushButtonCopy,
+                &QPushButton::clicked,
+                this,
+                &SkillManagerMonitorWidgetController::copyCurrentConfig);
+        connect(widget.pushButtonPaste,
+                &QPushButton::clicked,
+                this,
+                &SkillManagerMonitorWidgetController::pasteCurrentConfig);
+
+        connect(widget.pushButtonExecuteSkill,
+                &QPushButton::clicked,
+                this,
+                &SkillManagerMonitorWidgetController::executeSkill);
+        connect(widget.pushButtonStopSkill,
+                &QPushButton::clicked,
+                this,
+                &SkillManagerMonitorWidgetController::stopSkill);
+
+        connect(widget.treeWidgetSkills,
+                &QTreeWidget::currentItemChanged,
+                this,
+                &SkillManagerMonitorWidgetController::skillSelectionChanged);
     }
 
     SkillManagerMonitorWidgetController::~SkillManagerMonitorWidgetController()
@@ -111,25 +127,38 @@ namespace armarx
 
     }
 
-    void SkillManagerMonitorWidgetController::onInitComponent()
+    void 
+    SkillManagerMonitorWidgetController::reconnectToSkillManager()
+    {
+        if (connected)
+        {
+            getProxy(manager, observerName, 1000);
+        }
+    }
+
+    void 
+    SkillManagerMonitorWidgetController::onInitComponent()
     {
         usingProxy(observerName);
     }
 
 
-    void SkillManagerMonitorWidgetController::onConnectComponent()
+    void
+    SkillManagerMonitorWidgetController::onConnectComponent()
     {
-        getProxy(manager, observerName);
         widget.groupBoxSkills->setTitle(QString::fromStdString(observerName));
-        widget.treeWidgetSkillDetails->setEditTriggers(QAbstractItemView::EditTrigger::NoEditTriggers);
+        widget.treeWidgetSkillDetails->setEditTriggers(
+            QAbstractItemView::EditTrigger::NoEditTriggers);
         widget.treeWidgetSkillDetails->setColumnHidden(3, true);
 
         connected = true;
     }
 
-    void SkillManagerMonitorWidgetController::onDisconnectComponent()
+    void
+    SkillManagerMonitorWidgetController::onDisconnectComponent()
     {
         connected = false;
+        manager = nullptr;
 
         // reset all
         skills.clear();
@@ -140,25 +169,30 @@ namespace armarx
         selectedSkill.skillName = "";
     }
 
-    void SkillManagerMonitorWidgetController::updateTimerFrequency()
+    void
+    SkillManagerMonitorWidgetController::updateTimerFrequency()
     {
         int f = static_cast<int>(std::round(1000 / widget.doubleSpinBoxUpdateFreq->value()));
         refreshSkillsResultTimer->setInterval(f);
     }
 
-    void SkillManagerMonitorWidgetController::refreshSkills()
+    void
+    SkillManagerMonitorWidgetController::refreshSkills()
     {
-        static std::map<skills::provider::dto::Execution::Status, std::string> ExecutionStatus2String = {
-            {skills::provider::dto::Execution::Status::Aborted, "Aborted"},
-            {skills::provider::dto::Execution::Status::Failed, "Failed"},
-            {skills::provider::dto::Execution::Status::Idle, "Not yet started"},
-            {skills::provider::dto::Execution::Status::Running, "Running"},
-            {skills::provider::dto::Execution::Status::Scheduled, "Scheduled"},
-            {skills::provider::dto::Execution::Status::Succeeded, "Succeeded"}
-        };
-
-        if (!connected)
+        static std::map<skills::provider::dto::Execution::Status, std::string>
+            ExecutionStatus2String = {
+                {skills::provider::dto::Execution::Status::Aborted, "Aborted"},
+                {skills::provider::dto::Execution::Status::Failed, "Failed"},
+                {skills::provider::dto::Execution::Status::Idle, "Not yet started"},
+                {skills::provider::dto::Execution::Status::Running, "Running"},
+                {skills::provider::dto::Execution::Status::Scheduled, "Scheduled"},
+                {skills::provider::dto::Execution::Status::Succeeded, "Succeeded"}};
+
+        if (!manager)
+        {
+            reconnectToSkillManager();
             return;
+        }
 
         /* CHECK OWN SKILLS LIST */
         // remove non-existing ones
@@ -196,7 +230,9 @@ namespace armarx
         while (i < widget.treeWidgetSkills->topLevelItemCount())
         {
             QTreeWidgetItem* item = widget.treeWidgetSkills->topLevelItem(i);
-            if (std::find(removedProviders.begin(), removedProviders.end(), item->text(0).toStdString()) != removedProviders.end())
+            if (std::find(removedProviders.begin(),
+                          removedProviders.end(),
+                          item->text(0).toStdString()) != removedProviders.end())
             {
                 delete widget.treeWidgetSkills->takeTopLevelItem(i);
             }
@@ -209,7 +245,8 @@ namespace armarx
         // add new providers
         for (const auto& [providerName, providerSkills] : skills)
         {
-            if (auto it = std::find(newProviders.begin(), newProviders.end(), providerName); it != newProviders.end())
+            if (auto it = std::find(newProviders.begin(), newProviders.end(), providerName);
+                it != newProviders.end())
             {
                 auto item = new QTreeWidgetItem(widget.treeWidgetSkills);
                 item->setText(0, QString::fromStdString(providerName));
@@ -225,7 +262,7 @@ namespace armarx
         // update status and active skills window
         std::map<skills::SkillID, std::string> activeSkillsAndPrefixes;
         auto managerStatuses = manager->getSkillExecutionStatuses();
-        for (int i = 0;  i < widget.treeWidgetSkills->topLevelItemCount(); ++i)
+        for (int i = 0; i < widget.treeWidgetSkills->topLevelItemCount(); ++i)
         {
             try
             {
@@ -240,11 +277,15 @@ namespace armarx
                     skills::SkillID currentSkillId(providerName, skillItem->text(0).toStdString());
 
                     auto statusForSkill = allStatusesForProvider.at(currentSkillId.skillName);
-                    skillItem->setText(2, QString::fromStdString(ExecutionStatus2String.at(statusForSkill.header.status)));
+                    skillItem->setText(2,
+                                       QString::fromStdString(ExecutionStatus2String.at(
+                                           statusForSkill.header.status)));
 
-                    if (not statusForSkill.header.executorName.empty()) // it means that the skill was called by someone
+                    if (not statusForSkill.header.executorName
+                                .empty()) // it means that the skill was called by someone
                     {
-                        activeSkillsAndPrefixes.insert({currentSkillId, statusForSkill.header.executorName});
+                        activeSkillsAndPrefixes.insert(
+                            {currentSkillId, statusForSkill.header.executorName});
                     }
                 }
             }
@@ -261,7 +302,8 @@ namespace armarx
         {
             auto prefixedStr = id.toString(prefix);
             bool longest = true;
-            for (const auto& [id2, prefix2] : activeSkillsAndPrefixes) // check if there is a deeper skill currently executing
+            for (const auto& [id2, prefix2] :
+                 activeSkillsAndPrefixes) // check if there is a deeper skill currently executing
             {
                 auto prefixedStr2 = id.toString(prefix2);
                 if (prefixedStr == prefixedStr2)
@@ -278,12 +320,14 @@ namespace armarx
 
             if (longest)
             {
-                widget.listWidgetActiveSkills->addItem(QString::fromStdString(id.toString() + ": " + id.toString(prefix)));
+                widget.listWidgetActiveSkills->addItem(
+                    QString::fromStdString(id.toString() + ": " + id.toString(prefix)));
             }
         }
     }
 
-    void SkillManagerMonitorWidgetController::executeSkill()
+    void
+    SkillManagerMonitorWidgetController::executeSkill()
     {
         if (selectedSkill.providerName.empty() or selectedSkill.skillName.empty())
         {
@@ -307,12 +351,14 @@ namespace armarx
         exInfo.skillId = {selectedSkill.providerName, selectedSkill.skillName};
         exInfo.params = aron::data::Dict::ToAronDictDTO(data);
 
-        ARMARX_IMPORTANT << "Executing skill from GUI: " << selectedSkill.providerName << "/" << selectedSkill.skillName << ". The data was: " << data;
+        ARMARX_IMPORTANT << "Executing skill from GUI: " << selectedSkill.providerName << "/"
+                         << selectedSkill.skillName << ". The data was: " << data;
         // Note that we execute the skill in a seperate thread so that the GUI thread does not freeze.
         manager->begin_executeSkill(exInfo);
     }
 
-    void SkillManagerMonitorWidgetController::stopSkill()
+    void
+    SkillManagerMonitorWidgetController::stopSkill()
     {
         if (selectedSkill.providerName.empty() or selectedSkill.skillName.empty())
         {
@@ -325,11 +371,14 @@ namespace armarx
             return;
         }
 
-        ARMARX_INFO << "Stopping skill from GUI: " << selectedSkill.providerName << "/" << selectedSkill.skillName;
+        ARMARX_INFO << "Stopping skill from GUI: " << selectedSkill.providerName << "/"
+                    << selectedSkill.skillName;
         manager->abortSkill(selectedSkill.providerName, selectedSkill.skillName);
     }
 
-    void SkillManagerMonitorWidgetController::skillSelectionChanged(QTreeWidgetItem* current, QTreeWidgetItem*)
+    void
+    SkillManagerMonitorWidgetController::skillSelectionChanged(QTreeWidgetItem* current,
+                                                               QTreeWidgetItem*)
     {
         widget.groupBoxSkillDetails->setEnabled(false);
 
@@ -352,10 +401,12 @@ namespace armarx
         newSelectedSkill.skillName = current->text(0).toStdString();
 
         // setup groupBox
-        widget.groupBoxSkillDetails->setTitle(QString::fromStdString(newSelectedSkill.providerName + "/" + newSelectedSkill.skillName));
+        widget.groupBoxSkillDetails->setTitle(QString::fromStdString(
+            newSelectedSkill.providerName + "/" + newSelectedSkill.skillName));
         widget.groupBoxSkillDetails->setEnabled(true);
 
-        if (newSelectedSkill.providerName == selectedSkill.providerName and newSelectedSkill.skillName == selectedSkill.skillName)
+        if (newSelectedSkill.providerName == selectedSkill.providerName and
+            newSelectedSkill.skillName == selectedSkill.skillName)
         {
             return;
         }
@@ -370,37 +421,46 @@ namespace armarx
         auto skillDesc = skills.at(selectedSkill.providerName).at(selectedSkill.skillName);
 
         {
-            auto it = new QTreeWidgetItem(widget.treeWidgetSkillDetails,
-                                          {QString::fromStdString("Name"), QString::fromStdString(skillDesc.skillName)});
+            auto it = new QTreeWidgetItem(
+                widget.treeWidgetSkillDetails,
+                {QString::fromStdString("Name"), QString::fromStdString(skillDesc.skillName)});
             widget.treeWidgetSkillDetails->addTopLevelItem(it);
         }
 
         {
-            auto it = new QTreeWidgetItem(widget.treeWidgetSkillDetails,
-                                          {QString::fromStdString("Robot"), QString::fromStdString(simox::alg::join(skillDesc.robots, ", "))});
+            auto it = new QTreeWidgetItem(
+                widget.treeWidgetSkillDetails,
+                {QString::fromStdString("Robot"),
+                 QString::fromStdString(simox::alg::join(skillDesc.robots, ", "))});
             widget.treeWidgetSkillDetails->addTopLevelItem(it);
         }
 
         {
             auto it = new QTreeWidgetItem(widget.treeWidgetSkillDetails,
-                                          {QString::fromStdString("Description"), QString::fromStdString(skillDesc.description)});
+                                          {QString::fromStdString("Description"),
+                                           QString::fromStdString(skillDesc.description)});
             widget.treeWidgetSkillDetails->addTopLevelItem(it);
         }
 
         {
-            auto it = new QTreeWidgetItem(widget.treeWidgetSkillDetails,
-                                          {QString::fromStdString("Timeout"), QString::fromStdString(std::to_string(skillDesc.timeoutMs)) + " ms"});
+            auto it = new QTreeWidgetItem(
+                widget.treeWidgetSkillDetails,
+                {QString::fromStdString("Timeout"),
+                 QString::fromStdString(std::to_string(skillDesc.timeoutMs)) + " ms"});
             widget.treeWidgetSkillDetails->addTopLevelItem(it);
         }
 
-        skillsArgumentsTreeWidgetItem = new QTreeWidgetItem(widget.treeWidgetSkillDetails, {QString::fromStdString("Arguments")});
+        skillsArgumentsTreeWidgetItem = new QTreeWidgetItem(widget.treeWidgetSkillDetails,
+                                                            {QString::fromStdString("Arguments")});
         auto aron_args = aron::type::Object::FromAronObjectDTO(skillDesc.acceptedType);
         auto default_args = aron::data::Dict::FromAronDictDTO(skillDesc.defaultParams);
 
-        aronTreeWidgetController = std::make_shared<AronTreeWidgetController>(widget.treeWidgetSkillDetails, skillsArgumentsTreeWidgetItem, aron_args, default_args);
+        aronTreeWidgetController = std::make_shared<AronTreeWidgetController>(
+            widget.treeWidgetSkillDetails, skillsArgumentsTreeWidgetItem, aron_args, default_args);
     }
 
-    aron::data::DictPtr SkillManagerMonitorWidgetController::getConfigAsAron() const
+    aron::data::DictPtr
+    SkillManagerMonitorWidgetController::getConfigAsAron() const
     {
         // create argument aron (if there is an accepted type set)
         if (aronTreeWidgetController)
@@ -410,7 +470,8 @@ namespace armarx
         return nullptr;
     }
 
-    void SkillManagerMonitorWidgetController::copyCurrentConfig()
+    void
+    SkillManagerMonitorWidgetController::copyCurrentConfig()
     {
         auto data = getConfigAsAron();
         if (!data)
@@ -423,7 +484,8 @@ namespace armarx
         clipboard->setText(QString::fromStdString(json.dump(2)));
     }
 
-    void SkillManagerMonitorWidgetController::pasteCurrentConfig()
+    void
+    SkillManagerMonitorWidgetController::pasteCurrentConfig()
     {
         QClipboard* clipboard = QApplication::clipboard();
         std::string s = clipboard->text().toStdString();
@@ -438,34 +500,10 @@ namespace armarx
         aronTreeWidgetController->setFromAron(data);
     }
 
-    void SkillManagerMonitorWidgetController::resetCurrentConfig()
+    void
+    SkillManagerMonitorWidgetController::resetCurrentConfig()
     {
         // TODO
     }
 
-    void SkillManagerMonitorWidgetController::onTreeWidgetItemDoubleClicked(QTreeWidgetItem* item, int column)
-    {
-        if (!item)
-        {
-            return;
-        }
-
-        if (column == 1)
-        {
-            if (item->flags() & Qt::ItemIsEditable) // we use the flag to indicate whether the item is editable or not
-            {
-                // we assume its aron item
-                AronTreeWidgetItem* aItem = AronTreeWidgetItem::DynamicCastAndCheck(item);
-                std::string name = aItem->text(aron_tree_widget::constantes::TREE_WIDGET_ITEM_NAME).toStdString();
-                std::string type = aItem->text(aron_tree_widget::constantes::TREE_WIDGET_ITEM_TYPE).toStdString();
-
-                // why visitor?!?!?
-                AronTreeWidgetModalCreatorVisitor v(name, aItem, widget.treeWidgetSkillDetails);
-                aron::type::visit(v, aItem->aronType);
-                auto modal = v.createdModal;
-                modal->exec();
-            }
-        }
-    }
-}
-
+} // namespace armarx
diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.h b/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.h
index 64256f2d6530d766726df37ec5fc60c9429d3e70..d9a9379bdfdea0ee56c9c5f3e601ef68a5ce75b5 100644
--- a/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.h
+++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.h
@@ -22,25 +22,24 @@
 #pragma once
 
 #include <stack>
-#include <vector>
 #include <thread>
+#include <vector>
+
+#include <QTimer>
+
 #include <ArmarXCore/core/system/ImportExportComponent.h>
 
-#include <ArmarXGui/libraries/ArmarXGuiBase/ArmarXGuiPlugin.h>
 #include <ArmarXGui/libraries/ArmarXGuiBase/ArmarXComponentWidgetController.h>
+#include <ArmarXGui/libraries/ArmarXGuiBase/ArmarXGuiPlugin.h>
 #include <ArmarXGui/libraries/SimpleConfigDialog/SimpleConfigDialog.h>
 
-#include <RobotAPI/interface/skills/SkillMemoryInterface.h>
-
 #include <RobotAPI/gui-plugins/SkillManagerPlugin/ui_SkillManagerMonitorWidget.h>
-
-#include "aronTreeWidget/AronTreeWidgetController.h"
-
-#include <RobotAPI/libraries/aron/core/type/variant/All.h>
+#include <RobotAPI/interface/skills/SkillMemoryInterface.h>
 #include <RobotAPI/libraries/aron/core/data/variant/All.h>
+#include <RobotAPI/libraries/aron/core/type/variant/All.h>
 #include <RobotAPI/libraries/aron/core/type/visitor/variant/VariantVisitor.h>
 
-#include <QTimer>
+#include "aronTreeWidget/AronTreeWidgetController.h"
 
 namespace armarx
 {
@@ -71,6 +70,8 @@ namespace armarx
             return "Skills.Manager";
         }
 
+        void reconnectToSkillManager();
+
         void onInitComponent() override;
         void onConnectComponent() override;
         void onDisconnectComponent() override;
@@ -88,7 +89,6 @@ namespace armarx
         void pasteCurrentConfig();
         void resetCurrentConfig();
 
-        void onTreeWidgetItemDoubleClicked(QTreeWidgetItem * item, int column);
 
     private:
         aron::data::DictPtr getConfigAsAron() const;
@@ -120,11 +120,13 @@ namespace armarx
         AronTreeWidgetControllerPtr aronTreeWidgetController = nullptr;
 
         // others
-        std::atomic_bool connected = false;
         QTimer* refreshSkillsResultTimer;
 
         // skillExecutions
         std::vector<std::thread> executions;
+
+        // connected flag
+        std::atomic_bool connected = false;
     };
 }
 
diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/TODO b/source/RobotAPI/gui-plugins/SkillManagerPlugin/TODO
new file mode 100644
index 0000000000000000000000000000000000000000..d25aead078c039b5724f9a6f05abe669ed1caf50
--- /dev/null
+++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/TODO
@@ -0,0 +1,3 @@
+- keep set values around to not loose precision of values that have not been manipulated (in AronTreeWidgetItem, as well as Matrix and Quaternion) 
+- get rid of any todos present
+
diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/AronTreeWidgetController.cpp b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/AronTreeWidgetController.cpp
index 0ef63ff506ebb1f624f7380e61309f02c522b915..52110b494a2bfc38a361d8354eb18efccc760617 100644
--- a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/AronTreeWidgetController.cpp
+++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/AronTreeWidgetController.cpp
@@ -1,43 +1,62 @@
 #include "AronTreeWidgetController.h"
 
+#include <RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetModalCreator.h>
+
+#include "visitors/AronTreeWidgetContextMenu.h"
 #include "visitors/AronTreeWidgetConverter.h"
 #include "visitors/AronTreeWidgetSetter.h"
 
+
 namespace armarx
 {
-    AronTreeWidgetController::AronTreeWidgetController(QTreeWidget* tree, QTreeWidgetItem* parent, const aron::type::ObjectPtr& type, const aron::data::DictPtr& data):
-        parent(parent),
-        tree(tree),
-        type(type)
+    AronTreeWidgetController::AronTreeWidgetController(QTreeWidget* tree,
+                                                       QTreeWidgetItem* parent,
+                                                       const aron::type::ObjectPtr& type,
+                                                       const aron::data::DictPtr& data) :
+        parent(parent), tree(tree), type(type)
     {
-        if (type) // if there is a type set, we create a tree widget from the typp
+        connect(tree,
+                SIGNAL(customContextMenuRequested(const QPoint&)),
+                this,
+                SLOT(ShowContextMenu(const QPoint&)));
+        connect(tree,
+                &QTreeWidget::itemDoubleClicked,
+                this,
+                &AronTreeWidgetController::onTreeWidgetItemDoubleClicked);
+
+        if (type) // if there is a type set, we create a tree widget from the type
         {
-            AronTreeWidgetCreatorVisitor v;
+            AronTreeWidgetCreatorVisitor v(parent);
+            v.setTopLevelWidget(tree);
             aron::type::visit(v, type);
 
-            if (v.createdQWidgetItem)
-            {
-                parent->addChild(v.createdQWidgetItem);
-            }
-
             if (data) // check if there is a default argument set. Prefill the GUI with it
             {
                 setFromAron(data);
             }
         }
-        else if(data) // there is no type but a default configuration. Prefill the GUI with the default arguments
+        // there is no type but a default configuration. Prefill the GUI with the default arguments
+        else if (data)
         {
+            // TODO: There is no visitor for that (yet)...
             // create type from data, ...
         }
         else
         {
             new QTreeWidgetItem(parent, {QString::fromStdString("No args")});
         }
+
+        // connect change handling after args init
+        connect(tree,
+                &QTreeWidget::itemChanged,
+                this,
+                &AronTreeWidgetController::onTreeWidgetItemChanged);
     }
 
-    aron::data::DictPtr AronTreeWidgetController::convertToAron() const
+    aron::data::DictPtr
+    AronTreeWidgetController::convertToAron() const
     {
-        if (parent)
+        if (parent && type)
         {
             AronTreeWidgetConverterVisitor v(parent, 0);
             aron::type::visit(v, type);
@@ -48,7 +67,8 @@ namespace armarx
         return nullptr;
     }
 
-    void AronTreeWidgetController::setFromAron(const aron::data::DictPtr& data)
+    void
+    AronTreeWidgetController::setFromAron(const aron::data::DictPtr& data)
     {
         if (parent)
         {
@@ -56,4 +76,87 @@ namespace armarx
             aron::data::visit(v, data);
         }
     }
-}
+    void
+    AronTreeWidgetController::ShowContextMenu(const QPoint& pos)
+    {
+        tree->blockSignals(true);
+
+        auto idx = tree->indexAt(pos);
+        AronTreeWidgetItem* clickedItem = AronTreeWidgetItem::DynamicCast(tree->itemAt(pos));
+        if (clickedItem)
+        {
+            AronTreeWidgetContextMenuVisitor visitor(clickedItem, pos, tree, idx.row());
+
+            aron::type::visit(visitor, clickedItem->aronType);
+            visitor.showMenuAndExecute();
+        }
+
+        tree->blockSignals(false);
+    }
+    void
+    AronTreeWidgetController::onTreeWidgetItemDoubleClicked(QTreeWidgetItem* item, int column)
+    {
+        if (!item)
+        {
+            return;
+        }
+        tree->blockSignals(true);
+
+        auto* aronItem = AronTreeWidgetItem::DynamicCast(item);
+        if (column == 1 && aronItem)
+        {
+
+
+            std::string name =
+                aronItem->text(aron_tree_widget::constantes::TREE_WIDGET_ITEM_NAME).toStdString();
+            // depending on aron type, create extra gui element.
+            AronTreeWidgetModalCreatorVisitor v(name, aronItem, tree);
+            aron::type::visit(v, aronItem->aronType);
+            auto modal = v.createdModal;
+
+            // if no modal is created, we instead use the edit field directly
+            if (modal)
+            {
+                modal->exec();
+            }
+            else if (aronItem->col1Editable)
+            {
+                item->treeWidget()->editItem(item, column);
+            }
+        }
+        else if (column == 0 && aronItem && aronItem->col0Editable)
+        {
+            item->treeWidget()->editItem(item, column);
+        }
+
+        tree->blockSignals(false);
+    }
+
+    void
+    AronTreeWidgetController::onTreeWidgetItemChanged(QTreeWidgetItem* item, int column)
+    {
+        tree->blockSignals(true);
+
+        auto* aronElem = AronTreeWidgetItem::DynamicCast(item);
+        if (aronElem)
+        {
+            aronElem->onUserChange(column);
+        }
+        // start conversion for entire tree -- this also sets the highlighting
+        if (parent->childCount() == 1)
+        {
+            auto* aronTreeRoot = AronTreeWidgetItem::DynamicCast(parent->child(0));
+            aronTreeRoot->resetError();
+            if (aronTreeRoot)
+            {
+                AronTreeWidgetConverterVisitor v(parent, 0);
+                aron::type::visit(v, type);
+                aronTreeRoot->setValueErrorState(v.hasDirectError(), v.onlyChildFailedConversion());
+            }
+        }
+        // else perhaps the GUI was stopped or died.
+
+        tree->blockSignals(false);
+    }
+
+} // namespace armarx
diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/AronTreeWidgetController.h b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/AronTreeWidgetController.h
index c70b0277b41684a7144319a3c9d07fcf7dd31668..c3c2c9c2c913fba11fdd4dfc362e98297c4338f4 100644
--- a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/AronTreeWidgetController.h
+++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/AronTreeWidgetController.h
@@ -1,24 +1,30 @@
 #pragma once
 
 #include <stack>
-#include <ArmarXCore/core/system/ImportExportComponent.h>
 
-#include "Data.h"
+#include <QTreeWidget>
+
+#include <ArmarXCore/core/system/ImportExportComponent.h>
 
-#include <ArmarXGui/libraries/ArmarXGuiBase/ArmarXGuiPlugin.h>
 #include <ArmarXGui/libraries/ArmarXGuiBase/ArmarXComponentWidgetController.h>
+#include <ArmarXGui/libraries/ArmarXGuiBase/ArmarXGuiPlugin.h>
 
-#include <QTreeWidget>
-#include "visitors/AronTreeWidgetCreator.h"
 #include "AronTreeWidgetItem.h"
+#include "Data.h"
+#include "visitors/AronTreeWidgetCreator.h"
 
 namespace armarx
 {
-    class AronTreeWidgetController
+    // Main controller for any AronTreeWidget GUI. It attaches itself to the parent and needs the active widget.
+    // It's responsible to handle all signals for non-widget fields and click events.
+    class AronTreeWidgetController : public QObject
     {
-
+        Q_OBJECT
     public:
-        AronTreeWidgetController(QTreeWidget* tree, QTreeWidgetItem* parent, const aron::type::ObjectPtr& type, const aron::data::DictPtr& data = nullptr);
+        AronTreeWidgetController(QTreeWidget* tree,
+                                 QTreeWidgetItem* parent,
+                                 const aron::type::ObjectPtr& type,
+                                 const aron::data::DictPtr& data = nullptr);
 
         aron::data::DictPtr convertToAron() const;
         void setFromAron(const aron::data::DictPtr&);
@@ -28,7 +34,19 @@ namespace armarx
         QTreeWidget* tree;
 
         aron::type::ObjectPtr type;
+
+    private slots:
+        // allows most primitive fields to be directly editable in the tree
+        // only String will open up a new widget
+        void onTreeWidgetItemDoubleClicked(QTreeWidgetItem* item, int column);
+        // check the new user input. Maybe undo if the field must not be edited.
+        // Also highlight if the input cannot be parsed. (Or the errors are now fixed)
+        void onTreeWidgetItemChanged(QTreeWidgetItem* item, int column);
+
+    public slots:
+        // hook for items to show a context menu (add  / delete element)
+        void ShowContextMenu(const QPoint&);
     };
 
     using AronTreeWidgetControllerPtr = std::shared_ptr<AronTreeWidgetController>;
-}
+} // namespace armarx
diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/AronTreeWidgetItem.cpp b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/AronTreeWidgetItem.cpp
index e53161bb8b2ee4aee0c34ac2fc82c3214894f0cd..29d895f7b0f9666ebf42acd2bf3046ac90d7f1db 100644
--- a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/AronTreeWidgetItem.cpp
+++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/AronTreeWidgetItem.cpp
@@ -1,21 +1,24 @@
 #include "AronTreeWidgetItem.h"
 
+#include <QAction>
+#include <QMenu>
+
 #include <RobotAPI/libraries/aron/core/type/variant/All.h>
 
+#include "../ColorPalettes.h"
+#include "visitors/AronTreeWidgetConverter.h"
+#include "widgets/CustomWidget.h"
+
 namespace armarx
 {
-    AronTreeWidgetItem* AronTreeWidgetItem::DynamicCast(QTreeWidgetItem* i)
+    AronTreeWidgetItem*
+    AronTreeWidgetItem::DynamicCast(QTreeWidgetItem* i)
     {
         return dynamic_cast<AronTreeWidgetItem*>(i);
     }
 
-    AronTreeWidgetItem* AronTreeWidgetItem::copy()
-    {
-        AronTreeWidgetItem* ret = new AronTreeWidgetItem(*this);
-        return ret;
-    }
-
-    AronTreeWidgetItem* AronTreeWidgetItem::DynamicCastAndCheck(QTreeWidgetItem* i)
+    AronTreeWidgetItem*
+    AronTreeWidgetItem::DynamicCastAndCheck(QTreeWidgetItem* i)
     {
         if (!i)
         {
@@ -25,4 +28,174 @@ namespace armarx
         ARMARX_CHECK_NOT_NULL(c);
         return c;
     }
-}
+
+    bool
+    AronTreeWidgetItem::isValueErrorneous()
+    {
+        return itemValueError;
+    }
+
+    void
+    AronTreeWidgetItem::setValueErrorState(bool isErrorSource, bool isTransitiveError)
+    {
+        itemValueError |= isErrorSource;
+        transitiveValueError |= isTransitiveError;
+
+
+        if (CustomWidget::DynamicCast(treeWidget()->itemWidget(this, 1)))
+        {
+            // The widgets handle errors themselves
+            return;
+        }
+        auto palette = gui_color_palette::getNormalPalette();
+        if (itemValueError)
+        {
+            palette = gui_color_palette::getErrorPalette();
+        }
+        else if (transitiveValueError)
+        {
+            palette = gui_color_palette::getIndirectErrorPalette();
+        }
+
+        QTreeWidgetItem::setBackground(1, QBrush(palette.color(QPalette::Base)));
+    }
+
+    void
+    AronTreeWidgetItem::setKeyErrorState(bool hasError)
+    {
+        ARMARX_CHECK(col0Editable); //only editable keys should call this function!
+        auto palette =
+            hasError ? gui_color_palette::getErrorPalette() : gui_color_palette::getNormalPalette();
+
+        keyValueError = hasError;
+
+        QTreeWidgetItem::setBackground(1, QBrush(palette.color(QPalette::Base)));
+    }
+
+    void
+    AronTreeWidgetItem::resetError()
+    {
+        keyValueError = false;
+        itemValueError = false;
+        transitiveValueError = false;
+        // also reset children
+        for (int i = 0; i < childCount(); ++i)
+        {
+            auto* arChild = AronTreeWidgetItem::DynamicCastAndCheck(QTreeWidgetItem::child(i));
+            arChild->resetError();
+        }
+    }
+
+
+    void
+    AronTreeWidgetItem::checkKeyValidityOfChildren()
+    {
+        ARMARX_CHECK(aronType->getDescriptor() == aron::type::Descriptor::DICT);
+        // return if check failed
+        if (aronType->getDescriptor() != aron::type::Descriptor::DICT)
+        {
+            return;
+        }
+        // iterate through children; memorize keys
+        std::map<QString, std::vector<int>> found_keys;
+        auto numChildren = childCount();
+        for (int i = 0; i < numChildren; ++i)
+        {
+            auto* casted = AronTreeWidgetItem::DynamicCastAndCheck(child(i));
+            if (!casted)
+            {
+                // soft error here, we already report it above. - Definetly programming error
+                continue;
+            }
+            auto& vec = found_keys[casted->text(0)];
+            vec.push_back(i);
+        }
+        // highlight keys that conflict
+        // memorize children that are not ok
+        std::set<int> errorneous_indices;
+        for (auto [key, vals] : found_keys)
+        {
+            if (vals.size() > 1)
+            {
+                for (int i : vals)
+                {
+                    auto* casted = AronTreeWidgetItem::DynamicCastAndCheck(child(i));
+                    if (!casted)
+                    {
+                        // soft error here, we already report it above. - Definetly programming error
+                        continue;
+                    }
+                    casted->setKeyErrorState(true);
+                    errorneous_indices.emplace(i);
+                }
+            }
+        }
+        // clear potential error state of other elements
+        for (int i = 0; i < numChildren; ++i)
+        {
+            if (errorneous_indices.find(i) != errorneous_indices.end())
+            {
+                continue;
+            }
+            auto* casted = AronTreeWidgetItem::DynamicCastAndCheck(child(i));
+            if (!casted)
+            {
+                // soft error here, we already report it above. - Definetly programming error
+                continue;
+            }
+            casted->setKeyErrorState(false);
+        }
+    }
+
+    void
+    AronTreeWidgetItem::onUserChange(int changedColumn)
+    {
+        QTreeWidgetItem* qParent = QTreeWidgetItem::parent();
+        ARMARX_CHECK(qParent);
+        AronTreeWidgetItem* aronParent = DynamicCast(qParent);
+        if (changedColumn == 0)
+        {
+            if (col0Editable)
+            {
+                // Topmost should always be an Object and col0 is not editable in the child then...
+                // -> aronParent should never be nullptr
+                ARMARX_CHECK(aronParent);
+                // check if the element is child of a dict. If so, validate uniqueness of keys
+                if (aronParent->aronType->getDescriptor() == aron::type::Descriptor::DICT)
+                {
+                    aronParent->checkKeyValidityOfChildren();
+                }
+            }
+            else
+            {
+                // maybe while editing keys, we try to edit a key that should not change by tabbing.
+                // Catch that here and undo the edit
+                preventIllegalKeyChange();
+            }
+        }
+    }
+
+    void
+    AronTreeWidgetItem::preventIllegalKeyChange()
+    {
+        if (!col0Editable)
+        {
+            setText(0, unchangeableKey);
+        }
+    }
+
+    AronTreeWidgetItem::AronTreeWidgetItem(bool editKey,
+                                           bool editVal,
+                                           QString key,
+                                           aron::type::VariantPtr type) :
+        aronType(type), col0Editable(editKey), col1Editable(editVal)
+    {
+        this->setText(0, key);
+        // add hook to check for edited keys for children of dictionaries
+        if (!editKey)
+        {
+            unchangeableKey = std::move(key);
+        }
+    }
+
+} // namespace armarx
diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/AronTreeWidgetItem.h b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/AronTreeWidgetItem.h
index 3d6d0c2a329c5a4376fb24a406dadf706d6b898b..9106cb3192526f15355445deb0c6f1654921c17a 100644
--- a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/AronTreeWidgetItem.h
+++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/AronTreeWidgetItem.h
@@ -1,39 +1,65 @@
 #pragma once
 
-#include <stack>
-#include <ArmarXCore/core/system/ImportExportComponent.h>
+#include <QTreeWidget>
 
-#include "Data.h"
+#include <ArmarXCore/core/system/ImportExportComponent.h>
 
-#include <ArmarXGui/libraries/ArmarXGuiBase/ArmarXGuiPlugin.h>
 #include <ArmarXGui/libraries/ArmarXGuiBase/ArmarXComponentWidgetController.h>
+#include <ArmarXGui/libraries/ArmarXGuiBase/ArmarXGuiPlugin.h>
 
 #include <RobotAPI/libraries/aron/core/type/variant/Variant.h>
 
-#include <QTreeWidget>
+#include "Data.h"
 
 namespace armarx
 {
+    // Internal derived QtTreeWidgetItem class. Contains additional information to compare its data agains aron types.
+    // It contains 3 columns: Key ; Value ; Type
+    // The key can only be edited if the parent object is a dict
     class AronTreeWidgetItem : public QObject, public QTreeWidgetItem
     {
         Q_OBJECT
     public:
-        AronTreeWidgetItem(const AronTreeWidgetItem& other) :
-            QObject(),
-            QTreeWidgetItem(other)
-        {
-            aronType = other.aronType;
-        }
+        AronTreeWidgetItem(bool editKey, bool editVal, QString key, aron::type::VariantPtr type);
 
         using QTreeWidgetItem::QTreeWidgetItem;
 
-        AronTreeWidgetItem* copy(); // differs from clone!!!!
-
         static AronTreeWidgetItem* DynamicCast(QTreeWidgetItem*);
-
         static AronTreeWidgetItem* DynamicCastAndCheck(QTreeWidgetItem*);
 
         aron::type::VariantPtr aronType;
+        // if editing the first column should be allowed
+        const bool col0Editable = false;
+        // if editing the second column should be allowed
+        const bool col1Editable = false;
+
+        bool isValueErrorneous();
+        // marks the gui in a specific color. Also stores if there is currently an error.
+        // the only way to reset the color back to normal is with resetError() (error is sticky)
+        void setValueErrorState(bool isErrorSource, bool isTransitiveError);
+        void setKeyErrorState(bool hasError);
+        // reset error storage that influences coloring for this and all children
+        void resetError();
+
+        // Checks if the children of a dict are unique
+        // should not be called on other types! (does nothing then)
+        void checkKeyValidityOfChildren();
+
+        // main logic on changes. Gets called from the onTreeWidgetItemChanged() slot in AronTreeWidgetController.
+        // (This class cannot directly consume this signal, at least I did not find a nice way...)
+        void onUserChange(int changedColumn);
+
+    private:
+        // because the editable keyword counts for all columns, it is possible to TAB into uneditable keys.
+        // We do not want those to change, so just change them back once they finished editing.
+        void preventIllegalKeyChange();
 
+        bool itemValueError = false;
+        bool transitiveValueError = false;
+        bool keyValueError = false;
+        // hacky storage of previous key value for items that usually should not be editable.
+        // Problem: Dict-keys are editable, one can tab from that to any other value field and edit it.
+        // Fix: Once the change is commited, the AronTreeWidgetController notices the change and checks if it was allowed.
+        QString unchangeableKey = "";
     };
-}
+} // namespace armarx
diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/ListDictHelper.cpp b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/ListDictHelper.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..9866e8bc9f8c35a00e6411331461511e4c031e9f
--- /dev/null
+++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/ListDictHelper.cpp
@@ -0,0 +1,28 @@
+#include "ListDictHelper.h"
+
+namespace armarx::misc
+{
+    QString
+    generateNumElementsText(int num)
+    {
+        QString numElemsText = "<";
+        if (num == 0)
+        {
+            numElemsText.append("no");
+        }
+        else
+        {
+            numElemsText.append(QString::number(num));
+        }
+        if (num > 1 || num == 0)
+        {
+            numElemsText.append(" elements>");
+        }
+        else
+        {
+            numElemsText.append(" element>");
+        }
+        return numElemsText;
+    }
+
+} // namespace armarx::misc
diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/ListDictHelper.h b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/ListDictHelper.h
new file mode 100644
index 0000000000000000000000000000000000000000..c5d991ad2861aef5c32fc82c033c9090070f13b5
--- /dev/null
+++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/ListDictHelper.h
@@ -0,0 +1,8 @@
+#include <QString>
+
+
+namespace armarx::misc
+{
+    // helper that generates a string on how many items are available
+    QString generateNumElementsText(int num);
+} // namespace armarx::misc
diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/modal/dict/AronTreeWidgetDictInputModalController.cpp b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/modal/dict/AronTreeWidgetDictInputModalController.cpp
index f7d83d98b6cde491cad878822b69b50adb34d355..71a88e54fcf49d77ea5de6804ef06a11e90e6ae8 100644
--- a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/modal/dict/AronTreeWidgetDictInputModalController.cpp
+++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/modal/dict/AronTreeWidgetDictInputModalController.cpp
@@ -1,6 +1,7 @@
 #include "AronTreeWidgetDictInputModalController.h"
 
 #include <RobotAPI/libraries/aron/core/type/variant/All.h>
+
 #include "../../visitors/AronTreeWidgetCreator.h"
 
 namespace armarx
@@ -29,7 +30,7 @@ namespace armarx
     {
         for (const auto& added : addedItems)
         {
-            item->addChild(added->copy());
+            //item->addChild(added->copy());
         }
 
         AronTreeWidgetModal::submit();
@@ -59,12 +60,14 @@ namespace armarx
             auto d = aron::type::Dict::DynamicCastAndCheck(t);
             auto ac = d->getAcceptedType();
 
-            AronTreeWidgetCreatorVisitor v;
+            AronTreeWidgetCreatorVisitor v(nullptr);
+            v.setTopLevelWidget(widget.treeWidgetDict);
             aron::type::visit(v, ac);
 
             if (v.createdQWidgetItem)
             {
-                v.createdQWidgetItem->setText(aron_tree_widget::constantes::TREE_WIDGET_ITEM_NAME, s);
+                v.createdQWidgetItem->setText(aron_tree_widget::constantes::TREE_WIDGET_ITEM_NAME,
+                                              s);
                 addedItems.push_back(v.createdQWidgetItem);
                 widget.treeWidgetDict->addTopLevelItem(v.createdQWidgetItem);
             }
diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetContextMenu.cpp b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetContextMenu.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..98e271cd81c8180af051e094169f63b58176b0e8
--- /dev/null
+++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetContextMenu.cpp
@@ -0,0 +1,243 @@
+#include "AronTreeWidgetContextMenu.h"
+
+#include <QMenu>
+#include <QPoint>
+#include <QTreeWidget>
+#include <QTreeWidgetItem>
+
+#include "../AronTreeWidgetItem.h"
+#include "../ListDictHelper.h"
+#include "AronTreeWidgetCreator.h"
+
+namespace armarx
+{
+    AronTreeWidgetContextMenuVisitor::AronTreeWidgetContextMenuVisitor(
+        AronTreeWidgetItem* i,
+        const QPoint& pos,
+        QTreeWidget* contextMenuParent,
+        int x) :
+        parentItem(i), contextMenuParent(contextMenuParent), pos(pos), index(x)
+    {
+    }
+
+    void
+    AronTreeWidgetContextMenuVisitor::addDeleteAction()
+    {
+        auto* castedParent = AronTreeWidgetItem::DynamicCast(parentItem->QTreeWidgetItem::parent());
+        if (!castedParent)
+        {
+            // must be top level element
+            return;
+        }
+        auto aronType = castedParent->aronType->getDescriptor();
+        if (aron::type::Descriptor::DICT == aronType || aron::type::Descriptor::LIST == aronType)
+        {
+            QMenu contextMenu("Context menu", contextMenuParent);
+            actions.emplace_back("remove element", contextMenuParent);
+            action_callbacks.push_back([this]() mutable { this->executeDelete(); });
+        }
+    }
+
+    void
+    AronTreeWidgetContextMenuVisitor::executeDelete()
+    {
+        auto* containerPtr = parentItem->QTreeWidgetItem::parent();
+        containerPtr->removeChild(parentItem);
+        auto* castedContainer = AronTreeWidgetItem::DynamicCast(containerPtr);
+
+        // if the parent item is a List, we need to redo the numbers
+        if (castedContainer &&
+            castedContainer->aronType->getDescriptor() == aron::type::Descriptor::LIST)
+        {
+            // start renumbering from the removed child onwards
+            for (int i = index; i < castedContainer->childCount(); ++i)
+            {
+                std::string numberString = std::to_string(i);
+                castedContainer->child(i)->setText(0, numberString.c_str());
+            }
+            // This displays the number of children also when the list is collapsed
+            QString numElemsText = misc::generateNumElementsText(castedContainer->childCount());
+            containerPtr->setText(1, numElemsText);
+            // set italic
+            auto currFont = castedContainer->font(1);
+            currFont.setItalic(true);
+            castedContainer->setFont(1, currFont);
+        }
+    }
+
+
+    void
+    AronTreeWidgetContextMenuVisitor::visitAronVariant(const aron::type::ObjectPtr&)
+    {
+        addDeleteAction();
+    }
+
+    // lol
+    void
+    armarx::AronTreeWidgetContextMenuVisitor::addAddAction()
+    {
+        actions.emplace_back("Add element", contextMenuParent);
+        action_callbacks.push_back([this]() mutable { this->executeAddElement(); });
+    }
+
+    void
+    AronTreeWidgetContextMenuVisitor::executeAddElement()
+    {
+        AronTreeWidgetCreatorVisitor creator(parentItem);
+        aron::type::visit(creator, parentItem->aronType->getChildren()[0]);
+
+        if (!creator.createdQWidgetItem)
+        {
+            throw std::runtime_error("Creation of TreeElementChild failed unexpectedly");
+        }
+        // if it is a list, we update the number of children at the top
+        auto* castedContainer = AronTreeWidgetItem::DynamicCast(parentItem);
+
+        // if the parent item is a List, we need to redo the numbers
+        if (castedContainer &&
+            castedContainer->aronType->getDescriptor() == aron::type::Descriptor::LIST)
+        {
+            // This displays the number of children also when the list is collapsed
+            auto numElemsText = misc::generateNumElementsText(castedContainer->childCount());
+            castedContainer->setText(1, numElemsText);
+            // set italic
+            auto currFont = castedContainer->font(1);
+            currFont.setItalic(true);
+            castedContainer->setFont(1, currFont);
+        }
+    }
+
+    void
+    AronTreeWidgetContextMenuVisitor::visitAronVariant(const aron::type::DictPtr&)
+    {
+        addAddAction();
+        addDeleteAction();
+    }
+
+    void
+    AronTreeWidgetContextMenuVisitor::visitAronVariant(const aron::type::PairPtr&)
+    {
+        addDeleteAction();
+    }
+
+    void
+    AronTreeWidgetContextMenuVisitor::visitAronVariant(const aron::type::TuplePtr&)
+    {
+        addDeleteAction();
+    }
+
+    void
+    AronTreeWidgetContextMenuVisitor::visitAronVariant(const aron::type::ListPtr&)
+    {
+        addAddAction();
+        addDeleteAction();
+    }
+
+    void
+    AronTreeWidgetContextMenuVisitor::visitAronVariant(const aron::type::NDArrayPtr&)
+    {
+        addDeleteAction();
+    }
+
+    void
+    AronTreeWidgetContextMenuVisitor::visitAronVariant(const aron::type::MatrixPtr&)
+    {
+        addDeleteAction();
+    }
+
+    void
+    AronTreeWidgetContextMenuVisitor::visitAronVariant(const aron::type::QuaternionPtr&)
+    {
+        addDeleteAction();
+    }
+
+    void
+    AronTreeWidgetContextMenuVisitor::visitAronVariant(const aron::type::ImagePtr&)
+    {
+        addDeleteAction();
+    }
+
+    void
+    AronTreeWidgetContextMenuVisitor::visitAronVariant(const aron::type::PointCloudPtr&)
+    {
+        addDeleteAction();
+    }
+
+    void
+    AronTreeWidgetContextMenuVisitor::visitAronVariant(const aron::type::IntEnumPtr&)
+    {
+        addDeleteAction();
+    }
+
+    void
+    AronTreeWidgetContextMenuVisitor::visitAronVariant(const aron::type::IntPtr&)
+    {
+        addDeleteAction();
+    }
+
+    void
+    AronTreeWidgetContextMenuVisitor::visitAronVariant(const aron::type::LongPtr&)
+    {
+        addDeleteAction();
+    }
+
+    void
+    AronTreeWidgetContextMenuVisitor::visitAronVariant(const aron::type::FloatPtr&)
+    {
+        addDeleteAction();
+    }
+
+    void
+    AronTreeWidgetContextMenuVisitor::visitAronVariant(const aron::type::DoublePtr&)
+    {
+        addDeleteAction();
+    }
+
+    void
+    AronTreeWidgetContextMenuVisitor::visitAronVariant(const aron::type::BoolPtr&)
+    {
+        addDeleteAction();
+    }
+
+    void
+    AronTreeWidgetContextMenuVisitor::visitAronVariant(const aron::type::StringPtr&)
+    {
+        addDeleteAction();
+    }
+
+    void
+    AronTreeWidgetContextMenuVisitor::visitUnknown(Input&)
+    {
+        ARMARX_WARNING << "Tried to open Context menu on unknown aron type";
+    }
+
+    void
+    AronTreeWidgetContextMenuVisitor::showMenuAndExecute()
+    {
+        QMenu menu("Context Menu", contextMenuParent);
+        for (auto& el : actions)
+        {
+            menu.addAction(&el);
+        }
+        auto* chosenAction = menu.exec(contextMenuParent->mapToGlobal(pos));
+
+        if (!chosenAction)
+        {
+            return;
+        }
+
+        // not elegant, but is a small loop anyway
+        auto it = actions.begin();
+        size_t count = 0;
+        while (it != actions.end())
+        {
+            if (chosenAction == &*it)
+            {
+                action_callbacks[count]();
+                break;
+            }
+            ++it;
+            ++count;
+        }
+    }
+} // namespace armarx
diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetContextMenu.h b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetContextMenu.h
new file mode 100644
index 0000000000000000000000000000000000000000..510f68292b91bf9934dcecd4300d698e64d516b3
--- /dev/null
+++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetContextMenu.h
@@ -0,0 +1,67 @@
+#pragma once
+
+
+#include <QAction>
+
+#include <RobotAPI/libraries/aron/core/data/variant/All.h>
+#include <RobotAPI/libraries/aron/core/type/variant/All.h>
+#include <RobotAPI/libraries/aron/core/type/visitor/variant/VariantVisitor.h>
+
+class QTreeWidget;
+class QPoint;
+
+namespace armarx
+{
+
+    class AronTreeWidgetItem;
+
+    // Visitor on aron types. It creates a  context menu dependent on the type of the AronTreeWidgetItem.
+    // Its only used for Lists and Dicts.
+    class AronTreeWidgetContextMenuVisitor : public armarx::aron::type::ConstVariantVisitor
+    {
+
+        AronTreeWidgetItem* parentItem;
+        QTreeWidget* contextMenuParent;
+        const QPoint& pos;
+        int index;
+
+    public:
+        AronTreeWidgetContextMenuVisitor() = delete;
+        AronTreeWidgetContextMenuVisitor(AronTreeWidgetItem* i,
+                                         const QPoint& pos,
+                                         QTreeWidget* contextMenuParent,
+                                         int x);
+
+        void visitAronVariant(const aron::type::ObjectPtr&) final;
+        void visitAronVariant(const aron::type::DictPtr&) final;
+        void visitAronVariant(const aron::type::PairPtr&) final;
+        void visitAronVariant(const aron::type::TuplePtr&) final;
+        void visitAronVariant(const aron::type::ListPtr&) final;
+        void visitAronVariant(const aron::type::NDArrayPtr&) final;
+        void visitAronVariant(const aron::type::MatrixPtr&) final;
+        void visitAronVariant(const aron::type::QuaternionPtr&) final;
+        void visitAronVariant(const aron::type::ImagePtr&) final;
+        void visitAronVariant(const aron::type::PointCloudPtr&) final;
+        void visitAronVariant(const aron::type::IntEnumPtr&) final;
+        void visitAronVariant(const aron::type::IntPtr&) final;
+        void visitAronVariant(const aron::type::LongPtr&) final;
+        void visitAronVariant(const aron::type::FloatPtr&) final;
+        void visitAronVariant(const aron::type::DoublePtr&) final;
+        void visitAronVariant(const aron::type::BoolPtr&) final;
+        void visitAronVariant(const aron::type::StringPtr&) final;
+        void visitUnknown(Input&) final;
+
+        void showMenuAndExecute();
+
+    private:
+        std::list<QAction> actions;
+        std::vector<std::function<void()>> action_callbacks;
+
+        // Creates a remove option if the element is a direct child of a list or dict
+        void addDeleteAction();
+        void executeDelete();
+
+        void addAddAction();
+        void executeAddElement();
+    };
+} // namespace armarx
diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetConverter.cpp b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetConverter.cpp
index fbdc653abc5fa7cab715fc8abc7aa200de0243c1..c0a8088db7b5ad4e4e1db955b42e9316164038b3 100644
--- a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetConverter.cpp
+++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetConverter.cpp
@@ -26,16 +26,68 @@
 #include "AronTreeWidgetConverter.h"
 
 // armarx
+#include <SimoxUtility/algorithm/string.h>
+
 #include <ArmarXCore/core/logging/Logging.h>
 
+#include "RobotAPI/libraries/aron/core/data/variant/All.h"
+
 // qt
 #include <QTreeWidgetItem>
 
+#include "../widgets/EditMatrixWidget.h"
+#include "../widgets/IntEnumWidget.h"
+#include "../widgets/QuaternionWidget.h"
+
+
 namespace armarx
 {
+    bool
+    AronTreeWidgetConverterVisitor::isConversionSuccessful()
+    {
+        return !isDirectError && !hasTransitiveError;
+    }
+
+    bool
+    AronTreeWidgetConverterVisitor::onlyChildFailedConversion()
+    {
+        return hasTransitiveError;
+    }
+
+    bool
+    AronTreeWidgetConverterVisitor::hasDirectError() const
+    {
+        return isDirectError;
+    }
+
+    void
+    AronTreeWidgetConverterVisitor::handleErrors(AronTreeWidgetConverterVisitor childV,
+                                                 bool ownFault)
+    {
+        ARMARX_TRACE;
+        isDirectError |= ownFault;
+        hasTransitiveError |= childV.isDirectError || childV.hasTransitiveError;
+
+        auto* aronItem = AronTreeWidgetItem::DynamicCast(parentItem->child(index));
+        ARMARX_CHECK(aronItem);
+        aronItem->setValueErrorState(isDirectError, hasTransitiveError);
+    }
+
+    void
+    AronTreeWidgetConverterVisitor::handleErrors(bool ownFault)
+    {
+        ARMARX_TRACE;
+        isDirectError = ownFault;
+        auto* aronItem = AronTreeWidgetItem::DynamicCast(parentItem->child(index));
+        ARMARX_CHECK(aronItem);
+        aronItem->setValueErrorState(isDirectError, false);
+    }
+
+
     void
     AronTreeWidgetConverterVisitor::visitAronVariant(const aron::type::ObjectPtr& i)
     {
+        ARMARX_TRACE;
         auto createdAronDict = std::make_shared<aron::data::Dict>(i->getPath());
         createdAron = createdAronDict;
         QTreeWidgetItem* el = parentItem->child(index);
@@ -43,16 +95,22 @@ namespace armarx
         unsigned int x = 0;
         for (const auto& [key, value] : i->getMemberTypes())
         {
+            ARMARX_TRACE;
             AronTreeWidgetConverterVisitor v(el, x++);
             aron::type::visit(v, value);
 
-            createdAronDict->addElement(key, v.createdAron);
+            handleErrors(v);
+            if (v.isConversionSuccessful())
+            {
+                createdAronDict->addElement(key, v.createdAron);
+            }
         }
     }
 
     void
     AronTreeWidgetConverterVisitor::visitAronVariant(const aron::type::DictPtr& i)
     {
+        ARMARX_TRACE;
         auto createdAronDict = std::make_shared<aron::data::Dict>(i->getPath());
         createdAron = createdAronDict;
         QTreeWidgetItem* el = parentItem->child(index);
@@ -62,71 +120,206 @@ namespace armarx
             auto it = el->child(x);
             AronTreeWidgetConverterVisitor v(el, x);
             aron::type::visit(v, i->getAcceptedType());
-
-            if (v.createdAron)
+            auto key = it->text(0).toStdString();
+            // TODO: handle key errors more elegantly / separately, fine for now
+            handleErrors(v, createdAronDict->hasElement(key));
+            if (v.createdAron && v.isConversionSuccessful() && !createdAronDict->hasElement(key))
             {
-                createdAronDict->addElement(it->text(0).toStdString(), v.createdAron);
+                createdAronDict->addElement(key, v.createdAron);
             }
         }
     }
 
     void
-    AronTreeWidgetConverterVisitor::visitAronVariant(const aron::type::PairPtr& i)
+    AronTreeWidgetConverterVisitor::visitAronVariant(const aron::type::ListPtr& i)
     {
-        // TODO
+        ARMARX_TRACE;
+        auto createdAronList = std::make_shared<aron::data::List>(i->getPath());
+        createdAron = createdAronList;
+        auto* elem = parentItem->child(index);
+        auto childrenTypes = i->getChildren();
+        ARMARX_CHECK(childrenTypes.size() == 1);
+        for (int j = 0; j < elem->childCount(); ++j)
+        {
+            AronTreeWidgetConverterVisitor convVisitor(elem, j);
+            aron::type::visit(convVisitor, childrenTypes[0]);
+            handleErrors(convVisitor);
+
+            if (convVisitor.createdAron && convVisitor.isConversionSuccessful())
+            {
+                createdAronList->addElement(convVisitor.createdAron);
+            }
+        }
     }
 
+
     void
-    AronTreeWidgetConverterVisitor::visitAronVariant(const aron::type::TuplePtr& i)
+    AronTreeWidgetConverterVisitor::visitAronVariant(const aron::type::PairPtr& i)
     {
-        // TODO
+        ARMARX_TRACE;
+        auto createdAronPair = std::make_shared<aron::data::List>(i->getPath());
+        createdAron = createdAronPair;
+        auto* elem = parentItem->child(index);
+
+        for (int j = 0; j < 2; ++j)
+        {
+            AronTreeWidgetConverterVisitor convVisitor(elem, j);
+            handleErrors(convVisitor);
+            if (convVisitor.createdAron && convVisitor.isConversionSuccessful())
+            {
+                createdAronPair->addElement(convVisitor.createdAron);
+            }
+        }
     }
 
     void
-    AronTreeWidgetConverterVisitor::visitAronVariant(const aron::type::ListPtr& i)
+    AronTreeWidgetConverterVisitor::visitAronVariant(const aron::type::TuplePtr& i)
     {
-        // TODO
+        ARMARX_TRACE;
+        auto createdAronList = std::make_shared<aron::data::List>(i->getPath());
+        createdAron = createdAronList;
+        QTreeWidgetItem* el = parentItem->child(index);
+
+        for (int x = 0; x < el->childCount(); ++x)
+        {
+            auto* it = el->child(x);
+            AronTreeWidgetConverterVisitor v(it, x);
+            aron::type::visit(v, i->getAcceptedType(x));
+            handleErrors(v);
+
+            if (v.createdAron)
+            {
+                createdAronList->addElement(v.createdAron);
+            }
+        }
     }
 
     void
     AronTreeWidgetConverterVisitor::visitAronVariant(const aron::type::NDArrayPtr& i)
     {
-        // TODO
+        ARMARX_TRACE;
+        ARMARX_ERROR << "Currently do not support supplying raw NDArrays!";
     }
 
     void
     AronTreeWidgetConverterVisitor::visitAronVariant(const aron::type::MatrixPtr& i)
     {
-        // TODO
+        ARMARX_TRACE;
+        auto createdMatrix = std::make_shared<aron::data::NDArray>(i->getPath());
+        int dataSize = 0;
+        switch (i->getElementType())
+        {
+            case armarx::aron::type::matrix::INT16:
+                dataSize = 2;
+                break;
+            case armarx::aron::type::matrix::INT32:
+            case armarx::aron::type::matrix::FLOAT32:
+                dataSize = 4;
+                break;
+            case armarx::aron::type::matrix::FLOAT64:
+            case armarx::aron::type::matrix::INT64:
+                dataSize = 8;
+                break;
+        };
+        createdMatrix->setShape({i->getRows(), i->getCols(), dataSize});
+        createdMatrix->setType(i->getFullName());
+        int totalByteSize = i->getRows() * i->getCols() * dataSize;
+        createdAron = createdMatrix;
+
+        auto* currElem = parentItem->child(index);
+        auto* rootWidget = currElem->treeWidget();
+        ARMARX_CHECK(rootWidget);
+        auto* widget = rootWidget->itemWidget(currElem, 1);
+        auto* matrixWidget = EditMatrixWidget::DynamicCastAndCheck(widget);
+
+        handleErrors(matrixWidget->hasParseErrors());
+        if (matrixWidget->hasParseErrors())
+        {
+            return;
+        }
+        // write to aron data
+        std::vector<unsigned char> elems;
+        elems.reserve(totalByteSize);
+        // CAUTION: Raw data has column based storage
+        for (size_t col = 0; col < (size_t)i->getCols(); ++col)
+        {
+            for (size_t row = 0; row < (size_t)i->getRows(); ++row)
+            {
+                // gets us directly the byte wise format
+                auto parsed = matrixWidget->parseElement(row, col);
+                // append vector to vector
+                elems.insert(elems.end(), parsed.begin(), parsed.end());
+            }
+        }
+        createdMatrix->setData(totalByteSize, elems.data());
     }
 
     void
     AronTreeWidgetConverterVisitor::visitAronVariant(const aron::type::QuaternionPtr& i)
     {
-        // TODO
+        ARMARX_TRACE;
+        auto createdQuat = std::make_shared<aron::data::NDArray>(i->getPath());
+        createdAron = createdQuat;
+        int dataSize = i->getElementType() == aron::type::quaternion::ElementType::FLOAT32 ? 4 : 8;
+        createdQuat->setShape({1, 4, dataSize});
+        createdQuat->setType(i->getFullName());
+        auto* currTreeElem = parentItem->child(index);
+        auto* itemWidget = currTreeElem->treeWidget()->itemWidget(currTreeElem, 1);
+        auto* quatWidget = QuaternionWidget::DynamicCastAndCheck(itemWidget);
+
+        // error handling
+        handleErrors(quatWidget->hasParseErrors());
+        if (quatWidget->hasParseErrors())
+        {
+            return;
+        }
+
+        // write to aron data
+        auto serialized = quatWidget->parseAllToNDArray();
+        if ((int)serialized.size() != dataSize * 4)
+        {
+            ARMARX_ERROR
+                << "serialized quaternions did not return byte sequence of correct length!";
+        }
+        createdQuat->setData(serialized.size(), serialized.data());
     }
 
     void
     AronTreeWidgetConverterVisitor::visitAronVariant(const aron::type::ImagePtr& i)
     {
+        ARMARX_TRACE;
         // TODO
     }
 
     void
     AronTreeWidgetConverterVisitor::visitAronVariant(const aron::type::PointCloudPtr& i)
     {
+        ARMARX_TRACE;
         // TODO
     }
 
     void
     AronTreeWidgetConverterVisitor::visitAronVariant(const aron::type::IntEnumPtr& i)
     {
-        // TODO
+        ARMARX_TRACE;
+        QTreeWidgetItem* el = parentItem->child(index);
+        auto* genericWidget = el->treeWidget()->itemWidget(el, 1);
+        auto* intEnumWidget = IntEnumWidget::DynamicCastAndCheck(genericWidget);
+        if (!intEnumWidget)
+        {
+            // already reporting error; continue here
+            return;
+        }
+        bool success;
+        std::tie(success, createdAron) = intEnumWidget->parseToAron();
+
+        handleErrors(!success);
     }
 
     void
     AronTreeWidgetConverterVisitor::visitAronVariant(const aron::type::IntPtr& i)
     {
+        ARMARX_TRACE;
         auto createdAronInt = std::make_shared<aron::data::Int>(i->getPath());
         createdAron = createdAronInt;
         QTreeWidgetItem* el = parentItem->child(index);
@@ -137,14 +330,25 @@ namespace armarx
             createdAronInt->setValue(0);
             return;
         }
-
-        int val = std::stoi(str);
-        createdAronInt->setValue(val);
+        try
+        {
+            int val = simox::alg::to_<int>(str);
+            createdAronInt->setValue(val);
+        }
+        catch (const simox::error::SimoxError& err)
+        {
+            handleErrors();
+            ARMARX_VERBOSE << "Conversion from String to Int failed. Error:\"" << err.what()
+                           << "\"";
+            return;
+        }
+        handleErrors(false);
     }
 
     void
     AronTreeWidgetConverterVisitor::visitAronVariant(const aron::type::LongPtr& i)
     {
+        ARMARX_TRACE;
         auto createdAronLong = std::make_shared<aron::data::Long>(i->getPath());
         createdAron = createdAronLong;
         QTreeWidgetItem* el = parentItem->child(index);
@@ -152,15 +356,27 @@ namespace armarx
         std::string str = el->text(1).toStdString();
         if (str.empty())
         {
+            //TODO: similar behaviour for rest?
             str = el->text(3).toStdString();
         }
-
-        createdAronLong->fromString(str);
+        try
+        {
+            createdAronLong->setValue(simox::alg::to_<long>(str));
+        }
+        catch (const simox::error::SimoxError& err)
+        {
+            handleErrors();
+            ARMARX_VERBOSE << "Conversion from String to Long failed. Error:\"" << err.what()
+                           << "\"";
+            return;
+        }
+        handleErrors(false);
     }
 
     void
     AronTreeWidgetConverterVisitor::visitAronVariant(const aron::type::FloatPtr& i)
     {
+        ARMARX_TRACE;
         auto createdAronFloat = std::make_shared<aron::data::Float>(i->getPath());
         createdAron = createdAronFloat;
         QTreeWidgetItem* el = parentItem->child(index);
@@ -170,13 +386,24 @@ namespace armarx
         {
             str = el->text(3).toStdString();
         }
-
-        createdAronFloat->fromString(str);
+        try
+        {
+            createdAronFloat->setValue(simox::alg::to_<float>(str));
+        }
+        catch (const simox::error::SimoxError& err)
+        {
+            handleErrors();
+            ARMARX_VERBOSE << "Conversion from String to Float failed. Error:\"" << err.what()
+                           << "\"";
+            return;
+        }
+        handleErrors(false);
     }
 
     void
     AronTreeWidgetConverterVisitor::visitAronVariant(const aron::type::DoublePtr& i)
     {
+        ARMARX_TRACE;
         auto createdAronDouble = std::make_shared<aron::data::Double>(i->getPath());
         createdAron = createdAronDouble;
         QTreeWidgetItem* el = parentItem->child(index);
@@ -186,13 +413,24 @@ namespace armarx
         {
             str = el->text(3).toStdString();
         }
-
-        createdAronDouble->fromString(str);
+        try
+        {
+            createdAronDouble->setValue(simox::alg::to_<double>(str));
+        }
+        catch (const simox::error::SimoxError& err)
+        {
+            handleErrors();
+            ARMARX_VERBOSE << "Conversion from String to Double failed. Error:\"" << err.what()
+                           << "\"";
+            return;
+        }
+        handleErrors(false);
     }
 
     void
     AronTreeWidgetConverterVisitor::visitAronVariant(const aron::type::BoolPtr& i)
     {
+        ARMARX_TRACE;
         auto createdAronBool = std::make_shared<aron::data::Bool>(i->getPath());
         createdAron = createdAronBool;
         QTreeWidgetItem* el = parentItem->child(index);
@@ -202,24 +440,36 @@ namespace armarx
         {
             str = el->text(3).toStdString();
         }
-
-        createdAronBool->fromString(str);
+        try
+        {
+            createdAronBool->setValue(simox::alg::to_<bool>(str));
+        }
+        catch (const simox::error::SimoxError& err)
+        {
+            handleErrors();
+            ARMARX_VERBOSE << "Conversion from String to Bool failed. Error:\"" << err.what()
+                           << "\"";
+            return;
+        }
+        handleErrors(false);
     }
 
     void
     AronTreeWidgetConverterVisitor::visitAronVariant(const aron::type::StringPtr& i)
     {
+        ARMARX_TRACE;
         auto createdAronString = std::make_shared<aron::data::String>(i->getPath());
         createdAron = createdAronString;
         QTreeWidgetItem* el = parentItem->child(index);
 
         std::string str = el->text(1).toStdString();
-        createdAronString->fromString(str);
+        createdAronString->setValue(str);
     }
 
-    void AronTreeWidgetConverterVisitor::visitUnknown(Input&)
+    void
+    AronTreeWidgetConverterVisitor::visitUnknown(Input&)
     {
-        ARMARX_WARNING_S << "Received an unknown type when trying to convert a skill argument type to an aron data object.";
+        ARMARX_WARNING_S << "Received an unknown type when trying to convert a skill argument type "
+                            "to an aron data object.";
     }
-}
-
+} // namespace armarx
diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetConverter.h b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetConverter.h
index eb056cdc2a65f14ef4d884124d6cb14ac2e9ed7e..c127ac5e49276e878221dc39a5db8a7b821ccec7 100644
--- a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetConverter.h
+++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetConverter.h
@@ -21,8 +21,8 @@
  */
 #pragma once
 
-#include <RobotAPI/libraries/aron/core/type/variant/All.h>
 #include <RobotAPI/libraries/aron/core/data/variant/All.h>
+#include <RobotAPI/libraries/aron/core/type/variant/All.h>
 #include <RobotAPI/libraries/aron/core/type/visitor/variant/VariantVisitor.h>
 
 // forward declarations of qt
@@ -32,8 +32,7 @@ class QTreeWidgetItem;
 namespace armarx
 {
     // Conversion from TreeView to aron data
-    class AronTreeWidgetConverterVisitor :
-            public armarx::aron::type::ConstVariantVisitor
+    class AronTreeWidgetConverterVisitor : public armarx::aron::type::ConstVariantVisitor
     {
     public:
         QTreeWidgetItem* parentItem;
@@ -41,10 +40,27 @@ namespace armarx
         aron::data::VariantPtr createdAron = nullptr;
 
         AronTreeWidgetConverterVisitor() = delete;
-        AronTreeWidgetConverterVisitor(QTreeWidgetItem* i, int x) :
-            parentItem(i), index(x)
-        {}
+        AronTreeWidgetConverterVisitor(QTreeWidgetItem* i, int x) : parentItem(i), index(x)
+        {
+        }
+        // if the conversion was successful after calling visit()
+        bool isConversionSuccessful();
+        // returns true if this type itself was sucessfully parsed, but some contained object failed.
+        // also false if there is no error
+        bool onlyChildFailedConversion();
+
+        bool hasDirectError() const;
+
+    private:
+        bool isDirectError = false;
+        bool hasTransitiveError = false;
+        // adds all errors from other visitor to our own error collection -> collecting errors
+        // with ownFault, we also add this node to the collection
+        void handleErrors(AronTreeWidgetConverterVisitor childV, bool ownFault = false);
+        // we are the cause...
+        void handleErrors(bool ownFault = true);
 
+    public:
         void visitAronVariant(const aron::type::ObjectPtr&) final;
         void visitAronVariant(const aron::type::DictPtr&) final;
         void visitAronVariant(const aron::type::PairPtr&) final;
@@ -64,6 +80,4 @@ namespace armarx
         void visitAronVariant(const aron::type::StringPtr&) final;
         void visitUnknown(Input&) final;
     };
-}
-
-
+} // namespace armarx
diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetCreator.cpp b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetCreator.cpp
index ee43334bb26862322610746269fee97a16d0cccd..84cb58585e3b4e7f3a058db66f3b5f3a40f54aea 100644
--- a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetCreator.cpp
+++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetCreator.cpp
@@ -22,28 +22,98 @@
 
 #include <string>
 
+#include "../widgets/EditMatrixWidget.h"
+#include "../widgets/IntEnumWidget.h"
+#include "../widgets/QuaternionWidget.h"
+
 // base class
 #include "AronTreeWidgetCreator.h"
 
 // data
+#include <QComboBox>
+
 #include "../AronTreeWidgetItem.h"
 #include "../Data.h"
+#include "../ListDictHelper.h"
+#include "AronTreeWidgetContextMenu.h"
 
 namespace armarx
 {
+
+    AronTreeWidgetCreatorVisitor::AronTreeWidgetCreatorVisitor(QTreeWidgetItem* parentInstance) :
+        parentOfCreatedObj(parentInstance)
+    {
+        // The parent of the root aron Tree Widget will not be aron type.
+        // there an explicit setTopLevelWidget() is required.
+        auto* aronParent = AronTreeWidgetItem::DynamicCast(parentInstance);
+        if (aronParent)
+        {
+            toplevelWidget = aronParent->treeWidget();
+        }
+    }
+
+    std::string
+    AronTreeWidgetCreatorVisitor::generateUniqueKeyFromSet(std::set<std::string>&& usedKeys)
+    {
+        size_t num = 0;
+        while (true)
+        {
+            std::string proposedName = this->defaultMapKeyName + std::to_string(num);
+            auto it = usedKeys.find(proposedName);
+            if (it == usedKeys.end())
+            {
+                break;
+            }
+            ++num;
+        }
+        return this->defaultMapKeyName + std::to_string(num);
+    }
+
     void
-    AronTreeWidgetCreatorVisitor::createSimpleTreeViewWidget(Input& i, const std::string& defaul)
+    AronTreeWidgetCreatorVisitor::insertNewTreeViewWidget(Input& i, const std::string& defaul)
     {
         ARMARX_CHECK_NOT_NULL(i);
 
         auto key = i->getPath().getLastElement();
-        createdQWidgetItem = new AronTreeWidgetItem();
-        createdQWidgetItem->aronType = i;
-        createdQWidgetItem->setText(0, QString::fromStdString(key));
+        bool isDictChild = false;
+        // edit key, to be a unique string, if the parent is a dict
+        auto* aronParent = AronTreeWidgetItem::DynamicCast(parentOfCreatedObj);
+        if (aronParent && aronParent->aronType->getDescriptor() == aron::type::Descriptor::DICT)
+        {
+            isDictChild = true;
+            std::set<std::string> usedKeys;
+            for (int i = 0; i < parentOfCreatedObj->childCount(); ++i)
+            {
+                auto* sibling = AronTreeWidgetItem::DynamicCast(parentOfCreatedObj->child(i));
+                if (sibling)
+                {
+                    usedKeys.insert(sibling->text(0).toStdString());
+                }
+            }
+            key = generateUniqueKeyFromSet(std::move(usedKeys));
+        }
+        // if it's a list -> choose the right number
+        else if (aronParent &&
+                 aronParent->aronType->getDescriptor() == aron::type::Descriptor::LIST)
+        {
+            key = std::to_string(parentOfCreatedObj->childCount());
+        }
+
+        createdQWidgetItem =
+            new AronTreeWidgetItem(isDictChild, editableValue, QString::fromStdString(key), i);
         createdQWidgetItem->setText(1, QString::fromStdString(defaul));
         createdQWidgetItem->setText(2, QString::fromStdString(i->getShortName()));
-        createdQWidgetItem->setText(3, QString::fromStdString(aron_tree_widget::constantes::ITEM_EMPTY_MESSAGE) /*QString::fromStdString(i->getDefaultFromString())*/);
-        createdQWidgetItem->setFlags(createdQWidgetItem->flags() | Qt::ItemIsEditable);
+        createdQWidgetItem->setText(
+            3,
+            QString::fromStdString(
+                aron_tree_widget::constantes::
+                    ITEM_EMPTY_MESSAGE) /*QString::fromStdString(i->getDefaultFromString())*/);
+
+        if (editableValue || isDictChild)
+        {
+            createdQWidgetItem->setFlags(createdQWidgetItem->flags() | Qt::ItemIsEditable);
+        }
+        parentOfCreatedObj->addChild(createdQWidgetItem);
     }
 
     void
@@ -57,73 +127,203 @@ namespace armarx
             key = i->getPath().getLastElement();
         }
 
-        createdQWidgetItem = new AronTreeWidgetItem();
-        createdQWidgetItem->setText(0, QString::fromStdString(key));
+        createdQWidgetItem =
+            new AronTreeWidgetItem(editableValue, false, QString::fromStdString(key), i);
+        parentOfCreatedObj->addChild(createdQWidgetItem);
 
         for (const auto& [key, value] : i->getMemberTypes())
         {
-            AronTreeWidgetCreatorVisitor v;
+            AronTreeWidgetCreatorVisitor v(createdQWidgetItem);
             aron::type::visit(v, value);
 
-            if (v.createdQWidgetItem)
-            {
-                createdQWidgetItem->addChild(v.createdQWidgetItem);
-            }
+            assert(v.createdQWidgetItem);
         }
     }
 
     void
     AronTreeWidgetCreatorVisitor::visitAronVariant(const aron::type::DictPtr& i)
-    { createSimpleTreeViewWidget(i, ""); }
+    {
+        ARMARX_CHECK_NOT_NULL(i);
+
+        insertNewTreeViewWidget(i, "");
+        // The DictType has only one member, its key-type. This also must be present
+        ARMARX_CHECK_EQUAL(i->getChildren().size(), 1);
+    }
     void
-    AronTreeWidgetCreatorVisitor::visitAronVariant(const aron::type::PairPtr& i)
-    { createSimpleTreeViewWidget(i, ""); }
+    AronTreeWidgetCreatorVisitor::visitAronVariant(const aron::type::PairPtr& pair)
+    {
+        // create default, uneditable tree widget item.
+        insertNewTreeViewWidget(pair, "");
+        // attach two children
+        ARMARX_CHECK(pair->getChildren().size() == 2);
+        for (size_t i = 0; i < 2; ++i)
+        {
+            AronTreeWidgetCreatorVisitor v(createdQWidgetItem);
+            aron::type::visit(v, pair->getChildren()[i]);
+            if (v.createdQWidgetItem)
+            {
+                std::string descr = "p[" + std::to_string(i) + "]";
+                v.createdQWidgetItem->setText(0, descr.c_str());
+            }
+        }
+    }
     void
-    AronTreeWidgetCreatorVisitor::visitAronVariant(const aron::type::TuplePtr& i)
-    { createSimpleTreeViewWidget(i, ""); }
+    AronTreeWidgetCreatorVisitor::visitAronVariant(const aron::type::TuplePtr& tuple)
+    {
+        // CAUTION; UNTESTED
+        // create default, uneditable tree widget item.
+        insertNewTreeViewWidget(tuple, "");
+        // attach all children
+        for (size_t i = 0; i < tuple->getChildren().size(); ++i)
+        {
+            AronTreeWidgetCreatorVisitor v(createdQWidgetItem);
+            aron::type::visit(v, tuple->getChildren()[i]);
+            if (v.createdQWidgetItem)
+            {
+                std::string descr = "tup[" + std::to_string(i) + "]";
+                v.createdQWidgetItem->setText(0, descr.c_str());
+            }
+        }
+    }
     void
     AronTreeWidgetCreatorVisitor::visitAronVariant(const aron::type::ListPtr& i)
-    { createSimpleTreeViewWidget(i, ""); }
+    {
+        insertNewTreeViewWidget(i, "");
+        auto txt = misc::generateNumElementsText(0);
+        createdQWidgetItem->setText(1, txt);
+    }
     void
     AronTreeWidgetCreatorVisitor::visitAronVariant(const aron::type::NDArrayPtr& i)
-    { createSimpleTreeViewWidget(i, ""); }
+    {
+        insertNewTreeViewWidget(i, "");
+    }
+
     void
     AronTreeWidgetCreatorVisitor::visitAronVariant(const aron::type::MatrixPtr& i)
-    { createSimpleTreeViewWidget(i, ""); }
+    {
+        editableValue = false;
+        insertNewTreeViewWidget(i, "");
+        // special code to print the type of base type used
+        QString type = "";
+        switch (i->getElementType())
+        {
+            case armarx::aron::type::matrix::INT16:
+                type = "<int16>";
+                break;
+            case armarx::aron::type::matrix::INT32:
+                type = "<int32>";
+                break;
+            case armarx::aron::type::matrix::INT64:
+                type = "<int64>";
+                break;
+            case armarx::aron::type::matrix::FLOAT32:
+                type = "<float>";
+                break;
+            case armarx::aron::type::matrix::FLOAT64:
+                type = "<double>";
+                break;
+        }
+        type = createdQWidgetItem->text(2) + type;
+        createdQWidgetItem->setText(2, type);
+
+        // Widget fiddling source: https://blog.manash.io/quick-qt-6-how-to-add-qpushbutton-or-widgets-to-a-qtreewidget-as-qtreewidgetitem-2ae9f54c0e5f
+        // overlay custom widget in column 1
+        auto* toplevelWidget = createdQWidgetItem->treeWidget();
+        EditMatrixWidget* matWidget = new EditMatrixWidget(
+            i->getRows(), i->getCols(), i->getElementType(), createdQWidgetItem);
+        toplevelWidget->setItemWidget(createdQWidgetItem, 1, matWidget);
+    }
     void
     AronTreeWidgetCreatorVisitor::visitAronVariant(const aron::type::QuaternionPtr& i)
-    { createSimpleTreeViewWidget(i, ""); }
+    {
+        editableValue = false;
+        insertNewTreeViewWidget(i, "");
+        // special code to print the type of base type used
+        QString type = "";
+        switch (i->getElementType())
+        {
+            case armarx::aron::type::quaternion::FLOAT32:
+                type = "<float>";
+                break;
+            case armarx::aron::type::quaternion::FLOAT64:
+                type = "<double>";
+                break;
+        }
+        type = createdQWidgetItem->text(2) + type;
+        createdQWidgetItem->setText(2, type);
+
+        auto* toplevelWidget = createdQWidgetItem->treeWidget();
+        QuaternionWidget* quatWidget =
+            new QuaternionWidget(i->getElementType(), createdQWidgetItem);
+        toplevelWidget->setItemWidget(createdQWidgetItem, 1, quatWidget);
+    }
     void
     AronTreeWidgetCreatorVisitor::visitAronVariant(const aron::type::ImagePtr& i)
-    { createSimpleTreeViewWidget(i, ""); }
+    {
+        insertNewTreeViewWidget(i, "");
+    }
     void
     AronTreeWidgetCreatorVisitor::visitAronVariant(const aron::type::PointCloudPtr& i)
-    { createSimpleTreeViewWidget(i, ""); }
+    {
+        insertNewTreeViewWidget(i, "");
+    }
     void
     AronTreeWidgetCreatorVisitor::visitAronVariant(const aron::type::IntEnumPtr& i)
-    { createSimpleTreeViewWidget(i, ""); }
+    {
+        editableValue = false;
+        ARMARX_CHECK_NOT_NULL(i);
+        ARMARX_CHECK_GREATER(i->getAcceptedValueNames().size(), 0);
+
+        insertNewTreeViewWidget(i, "");
+        IntEnumWidget* widget = new IntEnumWidget(i, createdQWidgetItem);
+        createdQWidgetItem->treeWidget()->setItemWidget(createdQWidgetItem, 1, widget);
+    }
     void
     AronTreeWidgetCreatorVisitor::visitAronVariant(const aron::type::IntPtr& i)
-    { createSimpleTreeViewWidget(i, "0"); }
+    {
+        editableValue = true;
+        insertNewTreeViewWidget(i, "0");
+    }
     void
     AronTreeWidgetCreatorVisitor::visitAronVariant(const aron::type::LongPtr& i)
-    { createSimpleTreeViewWidget(i, "0"); }
+    {
+        editableValue = true;
+        insertNewTreeViewWidget(i, "0");
+    }
     void
     AronTreeWidgetCreatorVisitor::visitAronVariant(const aron::type::FloatPtr& i)
-    { createSimpleTreeViewWidget(i, "0.0"); }
+    {
+        editableValue = true;
+        insertNewTreeViewWidget(i, "0.0");
+    }
     void
     AronTreeWidgetCreatorVisitor::visitAronVariant(const aron::type::DoublePtr& i)
-    { createSimpleTreeViewWidget(i, "0.0"); }
+    {
+        editableValue = true;
+        insertNewTreeViewWidget(i, "0.0");
+    }
     void
     AronTreeWidgetCreatorVisitor::visitAronVariant(const aron::type::BoolPtr& i)
-    { createSimpleTreeViewWidget(i, "false"); }
+    {
+        editableValue = true;
+        insertNewTreeViewWidget(i, "false");
+    }
     void
     AronTreeWidgetCreatorVisitor::visitAronVariant(const aron::type::StringPtr& i)
-    { createSimpleTreeViewWidget(i, ""); }
+    {
+        insertNewTreeViewWidget(i, "");
+    }
 
-    void AronTreeWidgetCreatorVisitor::visitUnknown(Input&)
+    void
+    AronTreeWidgetCreatorVisitor::visitUnknown(Input&)
     {
-        ARMARX_WARNING_S << "Received an unknown type when trying to create a tree view widget for a skill argument type.";
+        ARMARX_WARNING_S << "Received an unknown type when trying to create a tree view widget for "
+                            "a skill argument type.";
     }
-}
 
+    void
+    AronTreeWidgetCreatorVisitor::setTopLevelWidget(QTreeWidget* widget)
+    {
+        toplevelWidget = widget;
+    }
+} // namespace armarx
diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetCreator.h b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetCreator.h
index 63dde7ef0be04d8d790c5f8434ae1b82faeb107a..b3d2ffb54cca6bf7fe8aac2395d733f3ba458817 100644
--- a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetCreator.h
+++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetCreator.h
@@ -21,8 +21,10 @@
  */
 #pragma once
 
-#include <RobotAPI/libraries/aron/core/type/variant/All.h>
+#include <QTreeWidgetItem>
+
 #include <RobotAPI/libraries/aron/core/data/variant/All.h>
+#include <RobotAPI/libraries/aron/core/type/variant/All.h>
 #include <RobotAPI/libraries/aron/core/type/visitor/variant/VariantVisitor.h>
 
 namespace armarx
@@ -30,15 +32,20 @@ namespace armarx
     class AronTreeWidgetItem;
 
     // Convert aron type to tree widgets
-    class AronTreeWidgetCreatorVisitor :
-            public armarx::aron::type::ConstVariantVisitor
+    class AronTreeWidgetCreatorVisitor : public armarx::aron::type::ConstVariantVisitor
     {
     public:
-        AronTreeWidgetItem* createdQWidgetItem;
+        AronTreeWidgetItem* createdQWidgetItem = nullptr;
+
+        AronTreeWidgetCreatorVisitor() = delete;
 
-        AronTreeWidgetCreatorVisitor() = default;
+        // Takes the parent tree element and attaches the newly crated object during visit() to it.
+        // This allows us to also use information of the parent object during creation (like if this child is a dict entry or part of a list)
+        // IMPORTANT: For the root element, manually set the topLevelWidget after this constructor
+        AronTreeWidgetCreatorVisitor(QTreeWidgetItem* parentInstance);
+
+        void insertNewTreeViewWidget(Input& i, const std::string&);
 
-        void createSimpleTreeViewWidget(Input& i, const std::string&);
 
         void visitAronVariant(const aron::type::ObjectPtr&) final;
         void visitAronVariant(const aron::type::DictPtr& i) final;
@@ -58,7 +65,17 @@ namespace armarx
         void visitAronVariant(const aron::type::BoolPtr& i) final;
         void visitAronVariant(const aron::type::StringPtr& i) final;
         void visitUnknown(Input&) final;
-    };
-}
 
+        // setter for the widget attachment point. Only needs to be manually set for the root element.
+        void setTopLevelWidget(QTreeWidget* widget);
 
+    private:
+        void handleEditable();
+        std::string generateUniqueKeyFromSet(std::set<std::string>&& usedKeys);
+        QTreeWidgetItem* parentOfCreatedObj = nullptr;
+        QTreeWidget* toplevelWidget = nullptr;
+        const std::string defaultMapKeyName = "key_";
+        // controls, if values (column 1) can be edited directly
+        bool editableValue = false;
+    };
+} // namespace armarx
diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetModalCreator.cpp b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetModalCreator.cpp
index 7ff248bd58499028bcf43a158f83f67c1259b43c..fc58634bb9bc02834d4e72663e3c16ffe36d6de6 100644
--- a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetModalCreator.cpp
+++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetModalCreator.cpp
@@ -28,7 +28,7 @@
 
 // modals
 #include "../modal/text/AronTreeWidgetTextInputModalController.h"
-#include "../modal/dict/AronTreeWidgetDictInputModalController.h"
+//#include "../modal/dict/AronTreeWidgetDictInputModalController.h"
 
 // qt
 #include <QTreeWidget>
@@ -37,84 +37,6 @@
 namespace armarx
 {
 
-    void AronTreeWidgetModalCreatorVisitor::visitAronVariant(const aron::type::ObjectPtr& i)
-    {
-        // should not happen, right?
-    }
-
-    void
-    AronTreeWidgetModalCreatorVisitor::visitAronVariant(const aron::type::DictPtr& i)
-    {
-        createdModal = std::make_shared<AronTreeWidgetDictInputModalController>(label, item, parent);
-    }
-
-    void
-    AronTreeWidgetModalCreatorVisitor::visitAronVariant(const aron::type::PairPtr& i)
-    {
-    }
-
-    void
-    AronTreeWidgetModalCreatorVisitor::visitAronVariant(const aron::type::TuplePtr& i)
-    { }
-
-    void
-    AronTreeWidgetModalCreatorVisitor::visitAronVariant(const aron::type::ListPtr& i)
-    { }
-
-    void
-    AronTreeWidgetModalCreatorVisitor::visitAronVariant(const aron::type::NDArrayPtr& i)
-    { }
-
-    void
-    AronTreeWidgetModalCreatorVisitor::visitAronVariant(const aron::type::MatrixPtr& i)
-    { }
-
-    void
-    AronTreeWidgetModalCreatorVisitor::visitAronVariant(const aron::type::QuaternionPtr& i)
-    { }
-
-    void
-    AronTreeWidgetModalCreatorVisitor::visitAronVariant(const aron::type::ImagePtr& i)
-    { }
-
-    void
-    AronTreeWidgetModalCreatorVisitor::visitAronVariant(const aron::type::PointCloudPtr& i)
-    { }
-
-    void
-    AronTreeWidgetModalCreatorVisitor::visitAronVariant(const aron::type::IntEnumPtr& i)
-    { }
-
-    void
-    AronTreeWidgetModalCreatorVisitor::visitAronVariant(const aron::type::IntPtr& i)
-    {
-        createdModal = std::make_shared<AronTreeWidgetTextInputModalController>(label, item, parent);
-    }
-
-    void
-    AronTreeWidgetModalCreatorVisitor::visitAronVariant(const aron::type::LongPtr& i)
-    {
-        createdModal = std::make_shared<AronTreeWidgetTextInputModalController>(label, item, parent);
-    }
-
-    void
-    AronTreeWidgetModalCreatorVisitor::visitAronVariant(const aron::type::FloatPtr& i)
-    {
-        createdModal = std::make_shared<AronTreeWidgetTextInputModalController>(label, item, parent);
-    }
-
-    void
-    AronTreeWidgetModalCreatorVisitor::visitAronVariant(const aron::type::DoublePtr& i)
-    {
-        createdModal = std::make_shared<AronTreeWidgetTextInputModalController>(label, item, parent);
-    }
-
-    void
-    AronTreeWidgetModalCreatorVisitor::visitAronVariant(const aron::type::BoolPtr& i)
-    {
-        createdModal = std::make_shared<AronTreeWidgetTextInputModalController>(label, item, parent);
-    }
-
     void
     AronTreeWidgetModalCreatorVisitor::visitAronVariant(const aron::type::StringPtr& i)
     {
diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetModalCreator.h b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetModalCreator.h
index e22930a1080977d0feb6475c72a3b6c848d5d8e5..f4c8f0223a039c6b9be926d6bddf360bce32f629 100644
--- a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetModalCreator.h
+++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetModalCreator.h
@@ -29,15 +29,17 @@
 
 namespace armarx
 {
-    // Convert aron type to tree widget
+    // Convert aron type to tree widget.
+    // (Widgets are only created for string types to enter longer texts.
+    // However, the visitor implementation allows modals for differnt types. Might be useful in the future..)
     class AronTreeWidgetModalCreatorVisitor :
             public armarx::aron::type::ConstVariantVisitor
     {
     public:
-        std::string label;
-        AronTreeWidgetItem* item;
-        QTreeWidget* parent;
-        AronTreeWidgetModalControllerPtr createdModal;
+        std::string label = "";
+        AronTreeWidgetItem* item = nullptr;
+        QTreeWidget* parent = nullptr;
+        AronTreeWidgetModalControllerPtr createdModal = nullptr;
 
         AronTreeWidgetModalCreatorVisitor() = delete;
         AronTreeWidgetModalCreatorVisitor(const std::string& label, AronTreeWidgetItem* item, QTreeWidget* parent) :
@@ -46,22 +48,6 @@ namespace armarx
             parent(parent)
         {}
 
-        void visitAronVariant(const aron::type::ObjectPtr&) final;
-        void visitAronVariant(const aron::type::DictPtr& i) final;
-        void visitAronVariant(const aron::type::PairPtr& i) final;
-        void visitAronVariant(const aron::type::TuplePtr& i) final;
-        void visitAronVariant(const aron::type::ListPtr& i) final;
-        void visitAronVariant(const aron::type::NDArrayPtr& i) final;
-        void visitAronVariant(const aron::type::MatrixPtr& i) final;
-        void visitAronVariant(const aron::type::QuaternionPtr& i) final;
-        void visitAronVariant(const aron::type::ImagePtr& i) final;
-        void visitAronVariant(const aron::type::PointCloudPtr& i) final;
-        void visitAronVariant(const aron::type::IntEnumPtr& i) final;
-        void visitAronVariant(const aron::type::IntPtr& i) final;
-        void visitAronVariant(const aron::type::LongPtr& i) final;
-        void visitAronVariant(const aron::type::FloatPtr& i) final;
-        void visitAronVariant(const aron::type::DoublePtr& i) final;
-        void visitAronVariant(const aron::type::BoolPtr& i) final;
         void visitAronVariant(const aron::type::StringPtr& i) final;
         void visitUnknown(Input&) final;
     };
diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetSetter.cpp b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetSetter.cpp
index 87d99fe162344661a0511f49563c5d601342fe11..cf719f8a2d1360d574fb8ebcac867378c3fd6f1b 100644
--- a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetSetter.cpp
+++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetSetter.cpp
@@ -20,34 +20,106 @@
  *             GNU General Public License
  */
 
+#include "AronTreeWidgetSetter.h"
+
 #include <string>
 
-#include "AronTreeWidgetSetter.h"
+#include "../ListDictHelper.h"
+#include "../widgets/EditMatrixWidget.h"
+#include "../widgets/IntEnumWidget.h"
+#include "../widgets/QuaternionWidget.h"
+#include "AronTreeWidgetContextMenu.h"
+#include "AronTreeWidgetCreator.h"
+
+
+template <typename T>
+std::string
+usString(T number, size_t precision = 3)
+{
+    std::stringstream ss;
+    const char* locale = "C";
+    ss.imbue(std::locale(locale));
+
+    ss << std::fixed << std::setprecision(precision) << number;
+    return ss.str();
+}
+
 
 //visitors
 namespace armarx
 {
-    bool AronTreeWidgetSetterVisitor::checkTreeWidgetItemForSimilarName(const std::string& name) const
+    bool
+    AronTreeWidgetSetterVisitor::checkTreeWidgetItemForSimilarName(const std::string& name) const
     {
         QTreeWidgetItem* el = parentItem->child(index);
+
+        // do not check attribute name, if the element is part of a list or map
+        auto* castedThis = AronTreeWidgetItem::DynamicCast(el->parent());
+        if (castedThis)
+        {
+            auto descr = castedThis->aronType->getDescriptor();
+            if (descr == aron::type::Descriptor::LIST || descr == aron::type::Descriptor::DICT)
+            {
+                return true;
+            }
+        }
         std::string n = el->text(0).toStdString();
         if (name != n)
         {
-            ARMARX_WARNING_S << "Could not set a tree widget value for the element with key '" << name << "' because it is different from the expected name '" << n << "'.";
+            ARMARX_WARNING_S << "Could not set a tree widget value for the element with key '"
+                             << name << "' because it is different from the expected name '" << n
+                             << "'.";
             return false;
         }
         return true;
     }
 
-    void AronTreeWidgetSetterVisitor::visitAronVariant(const aron::data::DictPtr& i)
+    void
+    AronTreeWidgetSetterVisitor::adjustNumberOfChildren(AronTreeWidgetItem* parent,
+                                                        size_t numChildren)
+    {
+        if (((size_t)parent->childCount()) < numChildren)
+        {
+            // The type to create must be the only child of the current aron type
+            ARMARX_CHECK_EQUAL(parent->aronType->childrenSize(), 1);
+            size_t childrenToAdd = numChildren - parent->childCount();
+            for (size_t j = 0; j < childrenToAdd; ++j)
+            {
+                AronTreeWidgetCreatorVisitor childCreator(parent);
+                aron::type::visit(childCreator, parent->aronType->getChildren()[0]);
+                ARMARX_CHECK_NOT_NULL(childCreator.createdQWidgetItem);
+            }
+        }
+        else if ((size_t)parent->childCount() > numChildren)
+        {
+            size_t numChilds = (size_t)parent->childCount() - numChildren;
+            // pop the last child
+            for (size_t j = 0; j < numChilds; ++j)
+            {
+                parent->removeChild(parent->child(parent->childCount() - 1));
+            }
+        }
+    }
+
+
+    void
+    AronTreeWidgetSetterVisitor::visitAronVariant(const aron::data::DictPtr& i)
     {
-        if (i->getPath().size() == 0 || checkTreeWidgetItemForSimilarName(i->getPath().getLastElement())) // either it is the root or it has a name
+        // either it is the root or it has a name
+        if (i->getPath().size() == 0 ||
+            checkTreeWidgetItemForSimilarName(i->getPath().getLastElement()))
         {
             QTreeWidgetItem* el = parentItem->child(index);
+            auto* aronTreeWidget = AronTreeWidgetItem::DynamicCastAndCheck(el);
+            // allocate enough child items
+            adjustNumberOfChildren(aronTreeWidget, i->childrenSize());
 
+            // write child values
             unsigned int x = 0;
             for (const auto& [key, value] : i->getElements())
             {
+                el->child(x)->setText(0, {key.c_str()});
+
                 AronTreeWidgetSetterVisitor v(el, x++);
                 aron::data::visit(v, value);
             }
@@ -55,72 +127,224 @@ namespace armarx
         }
     }
 
-    void AronTreeWidgetSetterVisitor::visitAronVariant(const aron::data::ListPtr& i)
+    void
+    AronTreeWidgetSetterVisitor::visitAronVariant(const aron::data::ListPtr& i)
     {
         if (checkTreeWidgetItemForSimilarName(i->getPath().getLastElement()))
         {
             QTreeWidgetItem* el = parentItem->child(index);
+            auto* aronTreeWidget = AronTreeWidgetItem::DynamicCastAndCheck(el);
+            adjustNumberOfChildren(aronTreeWidget, i->childrenSize());
 
             unsigned int x = 0;
             for (const auto& value : i->getElements())
             {
-                AronTreeWidgetSetterVisitor v(el, x++);
+                AronTreeWidgetSetterVisitor v(el, x);
                 aron::data::visit(v, value);
+                auto* currChild = el->child(x);
+                std::string listNum = usString(x);
+                currChild->setText(0, listNum.c_str());
+
+                ++x;
+            }
+            // This displays the number of children also when the list is collapsed
+            QString numElemsText = misc::generateNumElementsText(i->getElements().size());
+            aronTreeWidget->setText(1, numElemsText);
+            // set italic
+            auto currFont = aronTreeWidget->font(1);
+            currFont.setItalic(true);
+            aronTreeWidget->setFont(1, currFont);
+        }
+    }
+
+
+    void
+    visitMatrix(EditMatrixWidget* matrixWidget,
+                const std::shared_ptr<armarx::aron::type::Matrix>& matrixType,
+                const aron::data::NDArrayPtr& arr)
+    {
+        auto elemType = matrixType->getElementType();
+        auto* rawData = arr->getData();
+        // string can convert any item
+        auto toString = [elemType, rawData](size_t elementNr) -> std::string
+        {
+            switch (elemType)
+            {
+                case aron::type::matrix::ElementType::FLOAT32:
+                {
+                    static_assert(sizeof(float) == 4);
+                    float* interpreted = reinterpret_cast<float*>(rawData);
+                    float laundered = std::launder(interpreted)[elementNr];
+                    return usString<float>(laundered);
+                }
+                case aron::type::matrix::ElementType::FLOAT64:
+                {
+                    static_assert(sizeof(double) == 8);
+                    double* interpreted = reinterpret_cast<double*>(rawData);
+                    float laundered = std::launder(interpreted)[elementNr];
+                    return usString<double>(laundered);
+                }
+                case aron::type::matrix::ElementType::INT16:
+                {
+                    int16_t* interpreted = reinterpret_cast<int16_t*>(rawData);
+                    int16_t laudered = std::launder(interpreted)[elementNr];
+                    return usString<int16_t>(laudered);
+                }
+                case aron::type::matrix::ElementType::INT32:
+                {
+                    int32_t* interpreted = reinterpret_cast<int32_t*>(rawData);
+                    int32_t laudered = std::launder(interpreted)[elementNr];
+                    return usString<int32_t>(laudered);
+                }
+                case aron::type::matrix::ElementType::INT64:
+                {
+                    int64_t* interpreted = reinterpret_cast<int64_t*>(rawData);
+                    int64_t laudered = std::launder(interpreted)[elementNr];
+                    return usString<int64_t>(laudered);
+                }
+            }
+            return "Error!";
+        };
+
+
+        for (size_t row = 0; (int)row < matrixType->getRows(); ++row)
+        {
+            for (size_t col = 0; (int)col < matrixType->getCols(); ++col)
+            {
+                matrixWidget->setText(row, col, toString(col * matrixType->getRows() + row));
+            }
+        }
+    }
+    void
+    visitQuaternion(QuaternionWidget* quatWidget,
+                    std::shared_ptr<armarx::aron::type::Quaternion>& quatType,
+                    const aron::data::NDArrayPtr& arr)
+    {
+        auto elemType = quatType->getElementType();
+        auto rawData = arr->getData();
+        auto shape = arr->getShape();
+        // string can convert any item
+        auto toString = [elemType, rawData](size_t elementNr) -> std::string
+        {
+            switch (elemType)
+            {
+                case aron::type::quaternion::ElementType::FLOAT32:
+                {
+                    static_assert(sizeof(float) == 4);
+                    float* interpreted = reinterpret_cast<float*>(rawData);
+                    float laundered = std::launder(interpreted)[elementNr];
+                    return usString<float>(laundered);
+                }
+                case aron::type::quaternion::ElementType::FLOAT64:
+                {
+                    static_assert(sizeof(double) == 8);
+                    double* interpreted = reinterpret_cast<double*>(rawData);
+
+                    float laundered = std::launder(interpreted)[elementNr];
+                    return usString<double>(laundered);
+                }
             }
+            return "Error!";
+        };
+        for (size_t i = 0; i < 4; ++i)
+        {
+            quatWidget->setText((QuaternionWidget::QuaternionComponents)i, toString(i));
         }
     }
 
-    void AronTreeWidgetSetterVisitor::visitAronVariant(const aron::data::NDArrayPtr& i)
+    void
+    AronTreeWidgetSetterVisitor::visitAronVariant(const aron::data::NDArrayPtr& arr)
     {
+        // Matrices are handled as NDArray. Raw ndarrays cannot be created currently
+        auto* castedEl = AronTreeWidgetItem::DynamicCast(parentItem->child(index));
+        ARMARX_CHECK(castedEl);
+
+        auto matrixCast = aron::type::Matrix::DynamicCast(castedEl->aronType);
+        auto quaternionCast = aron::type::Quaternion::DynamicCast(castedEl->aronType);
+
+        auto* rootWidget = castedEl->treeWidget();
+        ARMARX_CHECK(rootWidget);
+        auto* matrixWidget = EditMatrixWidget::DynamicCast(rootWidget->itemWidget(castedEl, 1));
+        auto* quaternionWidget = QuaternionWidget::DynamicCast(rootWidget->itemWidget(castedEl, 1));
 
+        if (matrixCast && matrixWidget)
+        {
+            visitMatrix(matrixWidget, matrixCast, arr);
+        }
+        else if (quaternionCast && quaternionWidget)
+        {
+            visitQuaternion(quaternionWidget, quaternionCast, arr);
+        }
+        else
+        {
+            ARMARX_ERROR
+                << "we do not support raw NDArrays. Ask Fabian Peller for more information.";
+        }
     }
 
-    void AronTreeWidgetSetterVisitor::visitAronVariant(const aron::data::IntPtr& i)
+    void
+    AronTreeWidgetSetterVisitor::visitAronVariant(const aron::data::IntPtr& i)
     {
         if (checkTreeWidgetItemForSimilarName(i->getPath().getLastElement()))
         {
             QTreeWidgetItem* el = parentItem->child(index);
-            el->setText(1, QString::fromStdString(std::to_string(i->getValue())));
+            auto* enumWidget = IntEnumWidget::DynamicCast(el->treeWidget()->itemWidget(el, 1));
+            auto newText = QString::fromStdString(usString<int>(i->getValue()));
+            if (enumWidget)
+            {
+                // Its an IntEnum! -> Ask the custom widget
+                enumWidget->setText(newText);
+            }
+            else
+            {
+                // Its just an int. -> do the QTreeWidgetItem call
+                el->setText(1, newText);
+            }
         }
     }
 
-    void AronTreeWidgetSetterVisitor::visitAronVariant(const aron::data::LongPtr& i)
+    void
+    AronTreeWidgetSetterVisitor::visitAronVariant(const aron::data::LongPtr& i)
     {
         if (checkTreeWidgetItemForSimilarName(i->getPath().getLastElement()))
         {
             QTreeWidgetItem* el = parentItem->child(index);
-            el->setText(1, QString::fromStdString(std::to_string(i->getValue())));
+            el->setText(1, QString::fromStdString(usString<long>(i->getValue())));
         }
     }
 
-    void AronTreeWidgetSetterVisitor::visitAronVariant(const aron::data::FloatPtr& i)
+    void
+    AronTreeWidgetSetterVisitor::visitAronVariant(const aron::data::FloatPtr& i)
     {
         if (checkTreeWidgetItemForSimilarName(i->getPath().getLastElement()))
         {
             QTreeWidgetItem* el = parentItem->child(index);
-            el->setText(1, QString::fromStdString(std::to_string(i->getValue())));
+            el->setText(1, QString::fromStdString(usString<float>(i->getValue())));
         }
     }
 
-    void AronTreeWidgetSetterVisitor::visitAronVariant(const aron::data::DoublePtr& i)
+    void
+    AronTreeWidgetSetterVisitor::visitAronVariant(const aron::data::DoublePtr& i)
     {
         if (checkTreeWidgetItemForSimilarName(i->getPath().getLastElement()))
         {
             QTreeWidgetItem* el = parentItem->child(index);
-            el->setText(1, QString::fromStdString(std::to_string(i->getValue())));
+            el->setText(1, QString::fromStdString(usString<double>(i->getValue())));
         }
     }
 
-    void AronTreeWidgetSetterVisitor::visitAronVariant(const aron::data::BoolPtr& i)
+    void
+    AronTreeWidgetSetterVisitor::visitAronVariant(const aron::data::BoolPtr& i)
     {
         if (checkTreeWidgetItemForSimilarName(i->getPath().getLastElement()))
         {
             QTreeWidgetItem* el = parentItem->child(index);
-            el->setText(1, QString::fromStdString(std::to_string(i->getValue())));
+            el->setText(1, QString::fromStdString(usString<bool>(i->getValue())));
         }
     }
 
-    void AronTreeWidgetSetterVisitor::visitAronVariant(const aron::data::StringPtr& i)
+    void
+    AronTreeWidgetSetterVisitor::visitAronVariant(const aron::data::StringPtr& i)
     {
         if (checkTreeWidgetItemForSimilarName(i->getPath().getLastElement()))
         {
@@ -129,9 +353,10 @@ namespace armarx
         }
     }
 
-    void AronTreeWidgetSetterVisitor::visitUnknown(Input&)
+    void
+    AronTreeWidgetSetterVisitor::visitUnknown(Input&)
     {
-        ARMARX_WARNING_S << "Received an unknown type when trying to set a skill argument type from an aron data object.";
+        ARMARX_WARNING_S << "Received an unknown type when trying to set a skill argument type "
+                            "from an aron data object.";
     }
-}
-
+} // namespace armarx
diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetSetter.h b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetSetter.h
index 336be31e20d4ff44496a8a2f8424d7dd3c1419f1..5090c12e82d28498efe8e1e63015e659f1e1abce 100644
--- a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetSetter.h
+++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetSetter.h
@@ -23,17 +23,18 @@
 
 #include <stack>
 
-#include "../AronTreeWidgetItem.h"
-
-#include <RobotAPI/libraries/aron/core/type/variant/All.h>
 #include <RobotAPI/libraries/aron/core/data/variant/All.h>
 #include <RobotAPI/libraries/aron/core/data/visitor/variant/VariantVisitor.h>
+#include <RobotAPI/libraries/aron/core/type/variant/All.h>
+
+#include "../AronTreeWidgetItem.h"
 
 namespace armarx
 {
-    // Conversion from TreeView to aron data
-    class AronTreeWidgetSetterVisitor :
-            public armarx::aron::data::ConstVariantVisitor
+    // Conversion from aron data to Tree View data
+    // This should be used to programatically change data to be displayed in the GUI.
+    // This code will not be called, if changes are made on the GUI side.
+    class AronTreeWidgetSetterVisitor : public armarx::aron::data::ConstVariantVisitor
     {
     public:
         QTreeWidgetItem* parentItem;
@@ -41,9 +42,9 @@ namespace armarx
         AronTreeWidgetItem* qWidgetItem;
 
         AronTreeWidgetSetterVisitor() = delete;
-        AronTreeWidgetSetterVisitor(QTreeWidgetItem* i, int x) :
-            parentItem(i), index(x)
-        {}
+        AronTreeWidgetSetterVisitor(QTreeWidgetItem* i, int x) : parentItem(i), index(x)
+        {
+        }
 
         virtual void visitAronVariant(const aron::data::DictPtr&) final;
         virtual void visitAronVariant(const aron::data::ListPtr&) final;
@@ -58,7 +59,6 @@ namespace armarx
 
     private:
         bool checkTreeWidgetItemForSimilarName(const std::string& name) const;
+        void adjustNumberOfChildren(AronTreeWidgetItem* parent, size_t numChildren);
     };
-}
-
-
+} // namespace armarx
diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/widgets/CustomWidget.cpp b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/widgets/CustomWidget.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..51836fde9dc7a71fa44740c415fbaf03c3df79e7
--- /dev/null
+++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/widgets/CustomWidget.cpp
@@ -0,0 +1,42 @@
+#include "CustomWidget.h"
+
+#include "ArmarXCore/core/exceptions/local/ExpressionException.h"
+
+namespace armarx
+{
+    CustomWidget::CustomWidget(QTreeWidgetItem* overlayingItem) : overlayingItem(overlayingItem)
+    {
+        // connect to general QTreeWidgetItem callback.
+        // This also lets the conversion start for other objects. (Not just this widget)
+        ARMARX_CHECK(connect(this,
+                             SIGNAL(elemChanged(QTreeWidgetItem*, int)),
+                             overlayingItem->treeWidget(),
+                             SIGNAL(itemChanged(QTreeWidgetItem*, int))));
+    }
+
+    CustomWidget*
+    CustomWidget::DynamicCast(QWidget* elem)
+    {
+        return dynamic_cast<CustomWidget*>(elem);
+    }
+
+    CustomWidget*
+    CustomWidget::DynamicCastAndCheck(QWidget* elem)
+    {
+        if (!elem)
+        {
+            return nullptr;
+        }
+        auto* casted = DynamicCast(elem);
+        ARMARX_CHECK_NOT_NULL(casted);
+        return casted;
+    }
+
+    void
+    CustomWidget::setSupressSignals(bool doSupress)
+    {
+        QObject::blockSignals(doSupress);
+    }
+
+
+} // namespace armarx
diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/widgets/CustomWidget.h b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/widgets/CustomWidget.h
new file mode 100644
index 0000000000000000000000000000000000000000..49477ffa148e6a5c38279015a356571e107dadb7
--- /dev/null
+++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/widgets/CustomWidget.h
@@ -0,0 +1,26 @@
+#pragma once
+
+#include <QTreeWidgetItem>
+#include <QWidget>
+
+namespace armarx
+{
+
+    class CustomWidget : public QWidget
+    {
+        Q_OBJECT
+
+    public:
+        CustomWidget(QTreeWidgetItem* overlayingItem);
+        static CustomWidget* DynamicCast(QWidget*);
+        static CustomWidget* DynamicCastAndCheck(QWidget*);
+
+        virtual void setSupressSignals(bool doSupress);
+
+    protected:
+        QTreeWidgetItem* overlayingItem;
+
+    signals:
+        void elemChanged(QTreeWidgetItem* elem, int col);
+    };
+} // namespace armarx
diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/widgets/EditMatrixWidget.cpp b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/widgets/EditMatrixWidget.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..8e01710f03cf9fabe1f9f50b060bc058016099c8
--- /dev/null
+++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/widgets/EditMatrixWidget.cpp
@@ -0,0 +1,250 @@
+#include "EditMatrixWidget.h"
+
+#include <QGridLayout>
+#include <QLabel>
+
+#include "ArmarXCore/core/exceptions/local/ExpressionException.h"
+#include "ArmarXCore/core/logging/Logging.h"
+
+#include "../../ColorPalettes.h"
+#include "../visitors/AronTreeWidgetCreator.h"
+#include "NDArrayHelper.h"
+
+namespace armarx
+{
+    EditMatrixWidget::EditMatrixWidget(long numRows,
+                                       long numCols,
+                                       aron::type::matrix::ElementType elemType,
+                                       QTreeWidgetItem* currentItem) :
+        CustomWidget(currentItem)
+    {
+        realRows = numRows;
+        realCols = numCols;
+        this->elemType = elemType;
+        // init surrounding layout
+        outerVerticalLayout = new QVBoxLayout();
+        innerHorizontalLayout = new QHBoxLayout();
+        outerVerticalLayout->addItem(innerHorizontalLayout);
+
+
+        QGridLayout* innerGrid = new QGridLayout();
+        const long createRows = std::min(numRows, MAX_ROWS_DISPLAY);
+        const long createCols = std::min(numCols, MAX_COLS_DISPLAY);
+
+        for (long i = 0; i < createRows * createCols; ++i)
+        {
+            auto* edit = new QLineEdit();
+            dispElements.push_back(edit);
+            int currRow = i / createCols;
+            int currCol = i % createCols;
+
+            innerGrid->addWidget(edit, currRow, currCol);
+            std::stringstream ss;
+            ss << "(" << currRow << ", " << currCol << ")";
+            std::string text = ss.str();
+
+            edit->setText(text.c_str());
+        }
+        innerHorizontalLayout->addItem(innerGrid);
+
+        // check, if we need to signal to the user, that not all elements are displayed.
+        if (numRows > MAX_ROWS_DISPLAY)
+        {
+            QLabel* fullLabel = new QLabel("...");
+            outerVerticalLayout->addWidget(fullLabel);
+        }
+        if (numCols > MAX_COLS_DISPLAY)
+        {
+            QLabel* fullLabel = new QLabel("...");
+            innerHorizontalLayout->addWidget(fullLabel);
+        }
+        setLayout(outerVerticalLayout);
+
+        // add hidden elements in vector
+        {
+            const auto hiddenCols = numCols - createCols;
+            // the 0th element holds all columns that are
+            // to the right of the displayed cols AND besides the displayed rows!
+            hiddenElems.push_back(std::vector<std::string>(hiddenCols * createRows, ""));
+
+            // add all rows that are hidden
+            for (long i = 0; i < numRows - createRows; ++i)
+            {
+                // add full cols; everything is hidden here
+                hiddenElems.push_back(std::vector<std::string>(numCols, ""));
+            }
+        }
+
+        for (size_t i = 0; i < dispElements.size(); ++i)
+        {
+            ARMARX_CHECK(connect(
+                dispElements[i], SIGNAL(editingFinished()), this, SLOT(matrixElementChanged())));
+        }
+    }
+
+    EditMatrixWidget*
+    EditMatrixWidget::DynamicCast(QWidget* elem)
+    {
+        return dynamic_cast<EditMatrixWidget*>(elem);
+    }
+
+    EditMatrixWidget*
+    EditMatrixWidget::DynamicCastAndCheck(QWidget* elem)
+    {
+        if (!elem)
+        {
+            return nullptr;
+        }
+        auto* casted = DynamicCast(elem);
+        ARMARX_CHECK_NOT_NULL(casted);
+        return casted;
+    }
+
+    void
+    EditMatrixWidget::setText(long row, long col, const std::string& str)
+    {
+        ARMARX_CHECK(row < realRows);
+        ARMARX_CHECK(col < realCols);
+        auto dispCols = getDisplayedCols();
+        auto dispRows = getDisplayedRows();
+        if (row < dispRows && col < dispCols)
+        {
+            dispElements[row * dispCols + col]->setText(str.c_str());
+            dispElements[row * dispCols + col]->setCursorPosition(0);
+        }
+        else if (row < dispRows)
+        {
+            long idx = row * (realCols - dispCols) + col - dispCols;
+            hiddenElems.at(0).at(idx) = str;
+        }
+        else
+        {
+            hiddenElems.at(row - dispRows + 1).at(col) = str;
+        }
+    }
+
+    std::string
+    EditMatrixWidget::getText(long row, long col)
+    {
+        ARMARX_CHECK(row < realRows);
+        ARMARX_CHECK(col < realCols);
+        const auto dispRows = getDisplayedRows();
+        const auto dispCols = getDisplayedCols();
+        if (row < dispRows && col < dispCols)
+        {
+            auto txt = dispElements.at(row * dispCols + col)->text();
+            return txt.toStdString();
+        }
+        else if (row < getDisplayedRows())
+        {
+            // the stuff besides the displayed rows
+            long idx = row * (realCols - dispCols) + col - dispCols;
+            return hiddenElems.at(0).at(idx);
+        }
+        else
+        {
+            // stuff beneath displayed rows
+            return hiddenElems.at(row - dispRows + 1).at(col);
+        }
+    }
+
+    void
+    EditMatrixWidget::highlightUnparsableEntries()
+    {
+        auto dispRows = getDisplayedRows();
+        auto dispCols = getDisplayedCols();
+        for (long row = 0; row < dispRows; ++row)
+        {
+            for (long col = 0; col < dispCols; ++col)
+            {
+                auto parsed = parseElement(row, col);
+                if (parsed.empty())
+                {
+                    dispElements.at(row * dispCols + col)
+                        ->setPalette(gui_color_palette::getErrorPalette());
+                }
+                else
+                {
+                    dispElements.at(row * dispCols + col)
+                        ->setPalette(gui_color_palette::getNormalPalette());
+                }
+            }
+        }
+    }
+
+    bool
+    EditMatrixWidget::hasParseErrors()
+    {
+        // also parse the hidden stuff!
+        for (long row = 0; row < realRows; ++row)
+        {
+            for (long col = 0; col < realCols; ++col)
+            {
+                auto parsed = parseElement(row, col);
+                if (parsed.empty())
+                {
+                    if (row >= getDisplayedRows() || col >= getDisplayedCols())
+                    {
+                        ARMARX_ERROR
+                            << "Programming error! Could not parse content in EditMatrixWidget "
+                               "that was set programatically from inside the SkillManagerPlugin. "
+                               "The error occured in row "
+                            << row << " and col " << col << ".";
+                    }
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    std::vector<unsigned char>
+    EditMatrixWidget::parseElement(long row, long col)
+    {
+        std::string str = getText(row, col);
+        try
+        {
+            switch (elemType)
+            {
+                case armarx::aron::type::matrix::INT16:
+                    return NDArrayHelper::toByteVector<int16_t>(str);
+
+                case armarx::aron::type::matrix::INT32:
+                    return NDArrayHelper::toByteVector<int32_t>(str);
+
+                case armarx::aron::type::matrix::INT64:
+                    return NDArrayHelper::toByteVector<int64_t>(str);
+
+                case armarx::aron::type::matrix::FLOAT32:
+                    return NDArrayHelper::toByteVector<float>(str);
+
+                case armarx::aron::type::matrix::FLOAT64:
+                    return NDArrayHelper::toByteVector<double>(str);
+            }
+        }
+        catch (const simox::error::SimoxError& err)
+        {
+            return {};
+        }
+        return {};
+    }
+
+    long
+    EditMatrixWidget::getDisplayedRows() const
+    {
+        return std::min(realRows, MAX_ROWS_DISPLAY);
+    }
+    long
+    EditMatrixWidget::getDisplayedCols() const
+    {
+        return std::min(realCols, MAX_COLS_DISPLAY);
+    }
+    void
+    EditMatrixWidget::matrixElementChanged()
+    {
+        blockSignals(true);
+        highlightUnparsableEntries();
+        blockSignals(false);
+        emit elemChanged(overlayingItem, 1);
+    }
+} // namespace armarx
diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/widgets/EditMatrixWidget.h b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/widgets/EditMatrixWidget.h
new file mode 100644
index 0000000000000000000000000000000000000000..1fdaaa9630a09ab4a73f83fc05fa065fd0663e4d
--- /dev/null
+++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/widgets/EditMatrixWidget.h
@@ -0,0 +1,81 @@
+#pragma once
+#include <vector>
+
+#include <QHBoxLayout>
+#include <QLineEdit>
+#include <QObject>
+#include <QTreeWidgetItem>
+#include <QVBoxLayout>
+
+#include "RobotAPI/libraries/aron/core/type/variant/ndarray/Matrix.h"
+
+#include "CustomWidget.h"
+
+namespace armarx
+{
+    // Custom Widget used to display Matrices
+    // MAX_ROWS_DISPLAY and MAX_COLS_DISPLAY are the maximal number of elements displayable
+    // everything else will not be displayed. However, there can still be made changes to this data with setText()
+    class EditMatrixWidget : public CustomWidget
+    {
+        Q_OBJECT
+    public:
+        EditMatrixWidget() = delete;
+        EditMatrixWidget(long numRows,
+                         long numCols,
+                         aron::type::matrix::ElementType elemType,
+                         QTreeWidgetItem* currentWidget);
+
+        static EditMatrixWidget* DynamicCast(QWidget*);
+        static EditMatrixWidget* DynamicCastAndCheck(QWidget*);
+
+        // Sets the text on all visible rows and cols.
+        void setText(long row, long col, const std::string& str);
+        std::string getText(long row, long col);
+        void highlightUnparsableEntries();
+        bool hasParseErrors();
+        // returns an empty vector if parsing failed. Else, contains the individual bytes.
+        std::vector<unsigned char> parseElement(long row, long col);
+
+
+    private:
+        // Dimensions of the underlying Type to represent
+        long realRows = 1;
+        long realCols = 1;
+
+        // maximum of rows / cols to display
+        static constexpr long MAX_ROWS_DISPLAY = 5;
+        static constexpr long MAX_COLS_DISPLAY = 5;
+        long getDisplayedRows() const;
+        long getDisplayedCols() const;
+
+        // Want to add dots to show the user that not all is displayed. This needs some wrapping layouts
+        QVBoxLayout* outerVerticalLayout;
+        QHBoxLayout* innerHorizontalLayout;
+
+        // Using row major layout
+        std::vector<QLineEdit*> dispElements;
+        // rows<cols<text>>: stores get and set messages for hidden elements (if there is not enough space for all elements)
+        std::vector<std::vector<std::string>> hiddenElems;
+
+        template <typename T>
+        static std::vector<unsigned char> toByteVector(const std::string& str);
+
+        // TODO: It would be nice to have this code somewhere else, this way, at least the GUI-responses
+        // are restricted to this Widget (signal & slot stuff)
+        aron::type::matrix::ElementType elemType;
+
+    private slots:
+        void matrixElementChanged();
+    };
+
+    template <typename T>
+    std::vector<unsigned char>
+    EditMatrixWidget::toByteVector(const std::string& str)
+    {
+        auto val = simox::alg::to_<T>(str);
+        std::vector<unsigned char> res(sizeof(val), 0);
+        *reinterpret_cast<T*>(res.data()) = val;
+        return res;
+    }
+} // namespace armarx
diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/widgets/IntEnumWidget.cpp b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/widgets/IntEnumWidget.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..bfe1be2bf154768ae5ff49eff04d13caf492d133
--- /dev/null
+++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/widgets/IntEnumWidget.cpp
@@ -0,0 +1,139 @@
+#include "IntEnumWidget.h"
+
+#include <QHBoxLayout>
+
+#include "RobotAPI/libraries/aron/core/type/variant/All.h"
+
+#include "../../ColorPalettes.h"
+#include "../visitors/AronTreeWidgetConverter.h"
+
+namespace armarx
+{
+    IntEnumWidget::IntEnumWidget(const aron::type::IntEnumPtr& enumPtr,
+                                 QTreeWidgetItem* currentItem) :
+        CustomWidget(currentItem), element_type(enumPtr)
+    {
+        auto names = enumPtr->getAcceptedValueNames();
+        auto outerLayout = new QHBoxLayout();
+        outerLayout->setContentsMargins(0, 0, 0, 0);
+        innerWidget = new QComboBox();
+        outerLayout->addWidget(innerWidget);
+
+        for (const auto& n : names)
+        {
+            innerWidget->addItem(n.c_str());
+        }
+        innerWidget->setInsertPolicy(QComboBox::NoInsert);
+        innerWidget->setEditable(true);
+        innerWidget->setCurrentIndex(0);
+
+        setLayout(outerLayout);
+        ARMARX_CHECK(connect(innerWidget,
+                             SIGNAL(currentTextChanged(const QString&)),
+                             this,
+                             SLOT(textChanged(const QString&))));
+    }
+
+    IntEnumWidget*
+    IntEnumWidget::DynamicCast(QWidget* widget)
+    {
+        return dynamic_cast<IntEnumWidget*>(widget);
+    }
+
+    IntEnumWidget*
+    IntEnumWidget::DynamicCastAndCheck(QWidget* elem)
+    {
+        if (!elem)
+        {
+            return nullptr;
+        }
+        auto* casted = DynamicCast(elem);
+        ARMARX_CHECK_NOT_NULL(casted);
+        return casted;
+    }
+
+    bool
+    IntEnumWidget::hasParseErrors()
+    {
+        return parseToAron().first;
+    }
+
+    void
+    IntEnumWidget::setText(const QString& text)
+    {
+        innerWidget->setEditText(text);
+        highlightUnparsableEntries();
+    }
+
+    QString
+    IntEnumWidget::getText()
+    {
+        return innerWidget->currentText();
+    }
+
+    std::pair<bool, aron::data::IntPtr>
+    IntEnumWidget::parseToAron()
+    {
+        auto crAron = std::make_shared<aron::data::Int>(element_type->getPath());
+
+        // first look for strings in value map
+        auto valueMap = element_type->getAcceptedValueMap();
+        std::string toParse = getText().toStdString();
+
+        auto searchRes = valueMap.find(toParse);
+        if (searchRes != valueMap.end())
+        {
+            crAron->setValue(searchRes->second);
+            return {true, crAron};
+        }
+        // maybe its the number directly
+        auto accVals = element_type->getAcceptedValues();
+        int res;
+        try
+        {
+            res = simox::alg::to_<int>(toParse);
+        }
+        catch (const simox::error::SimoxError& err)
+        {
+            ARMARX_VERBOSE << "Failed to parse IntEnum: Could not convert  \'" << toParse
+                           << "\' to an int. It also was not one of the accepted strings.";
+            return {false, nullptr};
+        }
+        if (std::find(accVals.begin(), accVals.end(), res) != accVals.end())
+        {
+
+            crAron->setValue(res);
+        }
+        else
+        {
+            ARMARX_VERBOSE << "Parsed int " << res
+                           << "but this int is not part of the accepted values.";
+            return {false, nullptr};
+        }
+        return {true, crAron};
+    }
+
+    void
+    IntEnumWidget::highlightUnparsableEntries()
+    {
+        auto parsed = parseToAron().first;
+        if (parsed)
+        {
+            innerWidget->setPalette(gui_color_palette::getNormalPalette());
+        }
+        else
+        {
+            innerWidget->setPalette(gui_color_palette::getErrorPalette());
+        }
+    }
+
+    void
+    IntEnumWidget::textChanged(const QString&)
+    {
+        setSupressSignals(true);
+        highlightUnparsableEntries();
+        setSupressSignals(false);
+        // fire change signal
+        emit CustomWidget::elemChanged(overlayingItem, 1);
+    }
+} // namespace armarx
diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/widgets/IntEnumWidget.h b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/widgets/IntEnumWidget.h
new file mode 100644
index 0000000000000000000000000000000000000000..095ea480f00a6962bb0ebf407c4f43a8379a59e3
--- /dev/null
+++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/widgets/IntEnumWidget.h
@@ -0,0 +1,42 @@
+#pragma once
+
+#include <QComboBox>
+
+#include "RobotAPI/libraries/aron/core/data/variant/primitive/Int.h"
+#include "RobotAPI/libraries/aron/core/type/variant/forward_declarations.h"
+
+#include "../AronTreeWidgetItem.h"
+#include "CustomWidget.h"
+
+namespace armarx
+{
+    // Custom wrapper around the QComboBox widget to represent IntEnums
+    // This class handles parsing once the user edited the field and is also responsible
+    // to parse the according aron data from text
+    class IntEnumWidget : public CustomWidget
+    {
+        Q_OBJECT
+    public:
+        IntEnumWidget(const aron::type::IntEnumPtr&, QTreeWidgetItem* currentItem);
+        // needs to be called after the constructor, because qt needs the meta object to be fully constructed at this point
+        void postCtorCall();
+
+        static IntEnumWidget* DynamicCast(QWidget*);
+        static IntEnumWidget* DynamicCastAndCheck(QWidget*);
+
+        bool hasParseErrors();
+        void setText(const QString& text);
+        QString getText();
+        std::pair<bool, aron::data::IntPtr> parseToAron();
+
+    private:
+        const aron::type::IntEnumPtr element_type;
+        QComboBox* innerWidget;
+
+        bool noParseErrors = true;
+
+        void highlightUnparsableEntries();
+    private slots:
+        void textChanged(const QString&);
+    };
+} // namespace armarx
diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/widgets/NDArrayHelper.cpp b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/widgets/NDArrayHelper.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a9599a2dbdfd456e1237542d34006f5d4c4c9bbf
--- /dev/null
+++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/widgets/NDArrayHelper.cpp
@@ -0,0 +1 @@
+#include "NDArrayHelper.h"
diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/widgets/NDArrayHelper.h b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/widgets/NDArrayHelper.h
new file mode 100644
index 0000000000000000000000000000000000000000..ed91b874cc5f91ee24cf95eb6b46013da7b9d590
--- /dev/null
+++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/widgets/NDArrayHelper.h
@@ -0,0 +1,30 @@
+#pragma once
+#include <string>
+#include <vector>
+
+#include <SimoxUtility/algorithm/string.h>
+
+class NDArrayHelper
+{
+public:
+    // Uses the simox utility to parse floatingpoint and fixed precision types
+    // it then writes the result into a byte vector
+    // an empty byte vector encodes a parsing error.
+    template <typename T>
+    std::vector<unsigned char> static toByteVector(const std::string& str)
+    {
+        try
+        {
+            auto val = simox::alg::to_<T>(str);
+            std::vector<unsigned char> res(sizeof(val), 0);
+            T* reinterpPtr = reinterpret_cast<T*>(res.data());
+            T* laundered = std::launder(reinterpPtr);
+            *laundered = val;
+            return res;
+        }
+        catch (const simox::error::SimoxError& err)
+        {
+            return {};
+        }
+    }
+};
diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/widgets/QuaternionWidget.cpp b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/widgets/QuaternionWidget.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b1d6fa3b946a704b180109c2598b663e2ba03bad
--- /dev/null
+++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/widgets/QuaternionWidget.cpp
@@ -0,0 +1,160 @@
+#include "QuaternionWidget.h"
+
+#include <QHBoxLayout>
+#include <QLabel>
+#include <QLineEdit>
+
+#include "../../ColorPalettes.h"
+#include "NDArrayHelper.h"
+namespace armarx
+{
+
+    QuaternionWidget*
+    QuaternionWidget::DynamicCast(QWidget* elem)
+    {
+        return dynamic_cast<QuaternionWidget*>(elem);
+    }
+
+    QuaternionWidget*
+    QuaternionWidget::DynamicCastAndCheck(QWidget* elem)
+    {
+        if (!elem)
+        {
+            return nullptr;
+        }
+        auto* casted = DynamicCast(elem);
+        ARMARX_CHECK_NOT_NULL(casted);
+        return casted;
+    }
+
+    void
+    QuaternionWidget::setText(QuaternionComponents col, const std::string& str)
+    {
+        size_t idx = (size_t)col;
+        xyzw_components.at(idx)->setText(str.c_str());
+        highlightUnparsableEntries();
+    }
+
+    bool
+    QuaternionWidget::hasParseErrors()
+    {
+        return parseErrors;
+    }
+
+    armarx::QuaternionWidget::QuaternionWidget(aron::type::quaternion::ElementType elType,
+                                               QTreeWidgetItem* currentItem) :
+        CustomWidget(currentItem), element_type(elType)
+    {
+        auto outerLayout = new QHBoxLayout();
+        auto labelCol1 = new QVBoxLayout();
+        auto labelCol2 = new QVBoxLayout();
+        auto xzEdit = new QVBoxLayout();
+        auto ywEdit = new QVBoxLayout();
+
+        outerLayout->addLayout(labelCol1);
+        outerLayout->addLayout(xzEdit);
+        outerLayout->addLayout(labelCol2);
+        outerLayout->addLayout(ywEdit);
+
+        xyzw_components.reserve(4);
+        for (size_t i = 0; i < 4; ++i)
+        {
+            xyzw_components.push_back(new QLineEdit());
+        }
+
+        // Tabbing order >> Viewing order. Thats why the indeces are a bit switched
+        labelCol1->addWidget(new QLabel("x"));
+        xzEdit->addWidget(xyzw_components.at(0));
+
+        labelCol2->addWidget(new QLabel("z"));
+        ywEdit->addWidget(xyzw_components.at(2));
+
+        labelCol1->addWidget(new QLabel("y"));
+        xzEdit->addWidget(xyzw_components.at(1));
+
+        labelCol2->addWidget(new QLabel("w"));
+        ywEdit->addWidget(xyzw_components.at(3));
+
+        for (const auto& el : xyzw_components)
+        {
+            ARMARX_CHECK(
+                connect(el, SIGNAL(editingFinished()), this, SLOT(quaternionElementChanged())));
+        }
+
+        setLayout(outerLayout);
+        highlightUnparsableEntries();
+    }
+
+    void
+    QuaternionWidget::highlightUnparsableEntries()
+    {
+        parseErrors = false;
+        for (size_t i = 0; i < 4; ++i)
+        {
+            bool ok = false;
+            switch (element_type)
+            {
+                case armarx::aron::type::quaternion::FLOAT32:
+                {
+                    float flt;
+                    std::tie(ok, flt) = parseQuatVals<float>((QuaternionComponents)i);
+                    break;
+                }
+                case armarx::aron::type::quaternion::FLOAT64:
+                {
+                    double dbl;
+                    std::tie(ok, dbl) = parseQuatVals<double>((QuaternionComponents)i);
+                    break;
+                }
+            }
+            if (ok)
+            {
+                xyzw_components.at(i)->setPalette(gui_color_palette::getNormalPalette());
+            }
+            else
+            {
+                xyzw_components.at(i)->setPalette(gui_color_palette::getErrorPalette());
+                parseErrors = true;
+            }
+        }
+    }
+
+    std::vector<unsigned char>
+    QuaternionWidget::parseAllToNDArray()
+    {
+        std::vector<unsigned char> res;
+        bool success = true;
+        if (element_type == aron::type::quaternion::FLOAT32)
+        {
+            res.reserve(16);
+            for (size_t i = 0; i < 4; ++i)
+            {
+                auto bytevec =
+                    NDArrayHelper::toByteVector<float>(xyzw_components.at(i)->text().toStdString());
+                success &= !bytevec.empty();
+                res.insert(res.end(), bytevec.begin(), bytevec.end());
+            }
+        }
+        else
+        {
+            res.reserve(32);
+            for (size_t i = 0; i < 4; ++i)
+            {
+                auto bytevec = NDArrayHelper::toByteVector<double>(
+                    xyzw_components.at(i)->text().toStdString());
+                success &= !bytevec.empty();
+                res.insert(res.end(), bytevec.begin(), bytevec.end());
+            }
+        }
+        return (success) ? res : std::vector<unsigned char>();
+    }
+
+    void
+    QuaternionWidget::quaternionElementChanged()
+    {
+        CustomWidget::setSupressSignals(true);
+        highlightUnparsableEntries();
+        CustomWidget::setSupressSignals(false);
+        emit CustomWidget::elemChanged(overlayingItem, 1);
+    }
+} // namespace armarx
diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/widgets/QuaternionWidget.h b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/widgets/QuaternionWidget.h
new file mode 100644
index 0000000000000000000000000000000000000000..d55d2bba35e2712d1d161c83ed86b06b300bcf2d
--- /dev/null
+++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/widgets/QuaternionWidget.h
@@ -0,0 +1,68 @@
+#pragma once
+#include <vector>
+
+#include <QLineEdit>
+#include <QObject>
+#include <QVBoxLayout>
+
+#include "RobotAPI/libraries/aron/core/type/variant/ndarray/Matrix.h"
+
+#include "CustomWidget.h"
+
+
+namespace armarx
+{
+    // Custom Widget which represents a Quaternion - This class does not normalize the inputs
+    // It can parse its data to NDArray and also handles user edit signals itself. (And also the highlighting if errors occur)
+    class QuaternionWidget : public CustomWidget
+    {
+        Q_OBJECT
+    public:
+        QuaternionWidget(aron::type::quaternion::ElementType type, QTreeWidgetItem* currentItem);
+
+        static QuaternionWidget* DynamicCast(QWidget*);
+        static QuaternionWidget* DynamicCastAndCheck(QWidget*);
+
+        enum struct QuaternionComponents
+        {
+            X = 0,
+            Y,
+            Z,
+            W
+        };
+        void setText(QuaternionComponents col, const std::string& str);
+        std::string getText(QuaternionComponents col);
+        bool hasParseErrors();
+        std::vector<unsigned char> parseAllToNDArray();
+
+    private:
+        std::vector<QLineEdit*> xyzw_components;
+        aron::type::quaternion::ElementType element_type;
+        bool parseErrors = false;
+
+        void highlightUnparsableEntries();
+        template <typename T>
+        std::pair<bool, T> parseQuatVals(QuaternionComponents comp);
+
+    private slots:
+        void quaternionElementChanged();
+    };
+
+    template <typename T>
+    std::pair<bool, T>
+    QuaternionWidget::parseQuatVals(QuaternionWidget::QuaternionComponents comp)
+    {
+        // size_t data_size = element_type == aron::type::quaternion::ElementType::FLOAT32 ? 4 : 8;
+        try
+        {
+            T val = simox::alg::to_<T>(xyzw_components.at((size_t)comp)->text().toStdString());
+            return {true, val};
+        }
+        catch (const simox::error::SimoxError& err)
+        {
+            return {false, NAN};
+        }
+    }
+
+
+} // namespace armarx
diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/build/.cmake/api/v1/query/cache-v2 b/source/RobotAPI/gui-plugins/SkillManagerPlugin/build/.cmake/api/v1/query/cache-v2
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/build/.cmake/api/v1/query/cmakeFiles-v1 b/source/RobotAPI/gui-plugins/SkillManagerPlugin/build/.cmake/api/v1/query/cmakeFiles-v1
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/build/.cmake/api/v1/query/codemodel-v2 b/source/RobotAPI/gui-plugins/SkillManagerPlugin/build/.cmake/api/v1/query/codemodel-v2
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/build/qtcsettings.cmake b/source/RobotAPI/gui-plugins/SkillManagerPlugin/build/qtcsettings.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..fccf6a67eee120cbb1092f841fda5cca870a5a14
--- /dev/null
+++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/build/qtcsettings.cmake
@@ -0,0 +1,8 @@
+# This file is managed by Qt Creator, do not edit!
+
+set("CMAKE_BUILD_TYPE" "RelWithDebInfo" CACHE "STRING" "" FORCE)
+set("CMAKE_PROJECT_INCLUDE_BEFORE" "/common/homes/students/bodmer/opt/qtcreator/qtcreator/share/qtcreator/package-manager/auto-setup.cmake" CACHE "PATH" "" FORCE)
+set("QT_QMAKE_EXECUTABLE" "/usr/lib/qt5/bin/qmake" CACHE "STRING" "" FORCE)
+set("CMAKE_PREFIX_PATH" "/usr" CACHE "STRING" "" FORCE)
+set("CMAKE_C_COMPILER" "/usr/bin/gcc" CACHE "STRING" "" FORCE)
+set("CMAKE_CXX_COMPILER" "/usr/bin/g++" CACHE "STRING" "" FORCE)
\ No newline at end of file
diff --git a/source/RobotAPI/interface/CMakeLists.txt b/source/RobotAPI/interface/CMakeLists.txt
index 5d9d3c04b278f8032125f98cf82d63aaa8253155..9e290598fee8047f853044e54ea3775b62ab49f7 100644
--- a/source/RobotAPI/interface/CMakeLists.txt
+++ b/source/RobotAPI/interface/CMakeLists.txt
@@ -108,6 +108,7 @@ set(SLICE_FILES
 
     aron.ice
     aron/Aron.ice
+    aron/test/AronConversionTestInterface.ice
 
 
     armem.ice
diff --git a/source/RobotAPI/interface/aron/test/AronConversionTestInterface.ice b/source/RobotAPI/interface/aron/test/AronConversionTestInterface.ice
new file mode 100644
index 0000000000000000000000000000000000000000..924f40c6d8664123c822eb9f7eb338d8d50b52d5
--- /dev/null
+++ b/source/RobotAPI/interface/aron/test/AronConversionTestInterface.ice
@@ -0,0 +1,61 @@
+/*
+ * 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    SpeechX::aron_cpp_to_python_conv_test
+ * author     Rainer Kartmann ( rainer dot kartmann at kit dot edu )
+ * date       2023
+ * copyright  http://www.gnu.org/licenses/gpl-2.0.txt
+ *            GNU General Public License
+ */
+
+
+#pragma once
+
+#include <RobotAPI/interface/aron/Aron.ice>
+
+
+module armarx { module aron {  module test
+{
+
+module dto
+{
+
+    struct TestAronConversionRequest
+    {
+        string aronClassName;
+        ::armarx::aron::data::dto::Dict probe;
+    };
+    struct TestAronConversionResponse
+    {
+        bool success;
+        string errorMessage;
+
+        ::armarx::aron::data::dto::Dict probe;
+    };
+
+};
+
+
+module dti
+{
+
+    interface AronConversionTestInterface
+    {
+        dto::TestAronConversionResponse testAronConversion(dto::TestAronConversionRequest req);
+    };
+
+};
+
+};};};
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 fea3677bd5aa3d0d2b762beb32e2c7ff8d6cc9ea..6d20564f660aee832698ca9d1eda297b56de9f3c 100644
--- a/source/RobotAPI/libraries/ArmarXObjects/ObjectInfo.cpp
+++ b/source/RobotAPI/libraries/ArmarXObjects/ObjectInfo.cpp
@@ -59,12 +59,17 @@ namespace armarx
         return _id.str();
     }
 
-    ObjectInfo::path ObjectInfo::objectDirectory() const
+    ObjectInfo::path ObjectInfo::objectDirectory(const bool fixDataPath) const
     {
+        if(fixDataPath)
+        {
+            return _relObjectsPath / _id.dataset() / _id.className();
+        }
+
         return path(_packageName) / _relObjectsPath / _id.dataset() / _id.className();
     }
 
-    PackageFileLocation ObjectInfo::file(const std::string& _extension, const std::string& suffix) const
+    PackageFileLocation ObjectInfo::file(const std::string& _extension, const std::string& suffix, const bool fixDataPath) const
     {
         std::string extension = _extension;
         if (extension.at(0) != '.')
@@ -75,8 +80,8 @@ namespace armarx
 
         PackageFileLocation loc;
         loc.package = _packageName;
-        loc.relativePath = objectDirectory() / filename;
-        loc.absolutePath = _absPackageDataDir / loc.relativePath;
+        loc.relativePath = objectDirectory(fixDataPath) / filename;
+        loc.absolutePath = _absPackageDataDir / objectDirectory(false) / filename;
         return loc;
     }
 
@@ -86,14 +91,49 @@ 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");
+        return file(".xml", "_articulated", true);
     }
 
     PackageFileLocation ObjectInfo::articulatedUrdf() const
     {
-        return file(".urdf", "_articulated");
+        return file(".urdf", "_articulated", true);
+    }
+
+    PackageFileLocation ObjectInfo::articulatedSdf() const
+    {
+        return file(".sdf", "_articulated");
     }
 
     std::optional<PackageFileLocation> ObjectInfo::getArticulatedModel() const
@@ -106,6 +146,10 @@ namespace armarx
         {
             return articulatedUrdf();
         }
+        else if (fs::is_regular_file(articulatedSdf().absolutePath))
+        {
+            return articulatedSdf();
+        }
         else
         {
             return std::nullopt;
@@ -293,5 +337,3 @@ std::ostream& armarx::operator<<(std::ostream& os, const ObjectInfo& rhs)
 {
     return os << rhs.id();
 }
-
-
diff --git a/source/RobotAPI/libraries/ArmarXObjects/ObjectInfo.h b/source/RobotAPI/libraries/ArmarXObjects/ObjectInfo.h
index 70fd46b47fb7a8a3c992dfe5d6c3d4676915aed7..ccbd4eb1be32116d8fc7ced05d8148f027fefccf 100644
--- a/source/RobotAPI/libraries/ArmarXObjects/ObjectInfo.h
+++ b/source/RobotAPI/libraries/ArmarXObjects/ObjectInfo.h
@@ -76,14 +76,19 @@ namespace armarx
         std::string idStr() const;
 
 
-        PackageFileLocation file(const std::string& extension, const std::string& suffix = "") const;
+        PackageFileLocation file(const std::string& extension, const std::string& suffix = "", bool fixDataPath = false) const;
 
 
         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;
 
 
@@ -131,7 +136,7 @@ namespace armarx
 
     private:
 
-        path objectDirectory() const;
+        path objectDirectory(bool fixDataPath) const;
 
         std::optional<std::vector<std::string>> loadNames(const std::string& jsonKey) 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/CMakeLists.txt b/source/RobotAPI/libraries/CMakeLists.txt
index ecdd9f825e6442376cd19cd0c3a61a2ac590f51b..057440c94c97f8428c191c2d9c7a83edc95cbf51 100644
--- a/source/RobotAPI/libraries/CMakeLists.txt
+++ b/source/RobotAPI/libraries/CMakeLists.txt
@@ -38,3 +38,4 @@ add_subdirectory(skills)
 
 add_subdirectory(RobotUnitDataStreamingReceiver)
 add_subdirectory(GraspingUtility)
+add_subdirectory(obstacle_avoidance)
diff --git a/source/RobotAPI/libraries/GraspingUtility/GraspTrajectory.cpp b/source/RobotAPI/libraries/GraspingUtility/GraspTrajectory.cpp
index ee722453048da777dbad507f6f9b4e54e25a1865..c4b170313f7d9d71d09b055ffd497b9b658af5ac 100644
--- a/source/RobotAPI/libraries/GraspingUtility/GraspTrajectory.cpp
+++ b/source/RobotAPI/libraries/GraspingUtility/GraspTrajectory.cpp
@@ -58,7 +58,8 @@ namespace armarx
     GraspTrajectoryPtr
     GraspTrajectory::ReadFromReader(const RapidXmlReaderPtr& reader)
     {
-        RapidXmlReaderNode root = reader->getRoot("GraspTrajectory");
+        RapidXmlReaderNode root = reader->getRoot();
+
         GraspTrajectoryPtr traj;
         for (const RapidXmlReaderNode& kpNode : root.nodes("Keypoint"))
         {
diff --git a/source/RobotAPI/libraries/armem/client/util/MemoryListener.h b/source/RobotAPI/libraries/armem/client/util/MemoryListener.h
index ceb765e60db13404fbe170900342cff554b3affe..521d9ce6981e9503d90515b0fc10c518eedaae5a 100644
--- a/source/RobotAPI/libraries/armem/client/util/MemoryListener.h
+++ b/source/RobotAPI/libraries/armem/client/util/MemoryListener.h
@@ -63,12 +63,16 @@ namespace armarx::armem::client::util
             };
             subscribe(subscriptionID, cb);
         }
+
         template <class CalleeT>
         void subscribe(const MemoryID& subscriptionID, CalleeT* callee, MemberCallbackUpdatedOnly<CalleeT> callback)
         {
             auto cb = [callee, callback](const MemoryID&, const std::vector<MemoryID>& updatedSnapshotIDs)
             {
-                (callee->*callback)(updatedSnapshotIDs);
+                if(callee)
+                {
+                    (callee->*callback)(updatedSnapshotIDs);
+                }
             };
             subscribe(subscriptionID, cb);
         }
diff --git a/source/RobotAPI/libraries/armem/core/base/MemoryBase.h b/source/RobotAPI/libraries/armem/core/base/MemoryBase.h
index b6497f8ff421feb16b7f7b07ede1f2d3e57c2266..efc18d58c99ee298b71ce2e775a012d7e6050b04 100644
--- a/source/RobotAPI/libraries/armem/core/base/MemoryBase.h
+++ b/source/RobotAPI/libraries/armem/core/base/MemoryBase.h
@@ -261,12 +261,12 @@ namespace armarx::armem::base
          * @param commit The commit.
          * @return The resulting memory IDs.
          */
-        std::vector<UpdateResult> update(const Commit& commit)
+        std::vector<UpdateResult> update(const Commit& commit, const bool addMissingCoreSegmentDuringUpdate = false, const bool checkMemoryName = true)
         {
             std::vector<UpdateResult> results;
             for (const EntityUpdate& update : commit.updates)
             {
-                results.push_back(this->update(update));
+                results.push_back(this->update(update, addMissingCoreSegmentDuringUpdate, checkMemoryName));
             }
             return results;
         }
@@ -276,11 +276,14 @@ namespace armarx::armem::base
          * @param update The update.
          * @return The resulting entity snapshot's ID.
          */
-        UpdateResult update(const EntityUpdate& update)
+        UpdateResult update(const EntityUpdate& update, const bool addMissingCoreSegmentDuringUpdate = false, const bool checkMemoryName = true)
         {
-            this->_checkContainerName(update.entityID.memoryName, this->name());
+            if (checkMemoryName)
+            {
+                this->_checkContainerName(update.entityID.memoryName, this->name());
+            }
 
-            auto [inserted, coreSeg] = _addCoreSegmentIfMissing(update.entityID.coreSegmentName);
+            auto [inserted, coreSeg] = _addCoreSegmentIfMissing(update.entityID.coreSegmentName, addMissingCoreSegmentDuringUpdate);
 
             // Update entry.
             UpdateResult ret(coreSeg->update(update));
@@ -349,14 +352,14 @@ namespace armarx::armem::base
 
     protected:
 
-        std::pair<bool, CoreSegmentT*> _addCoreSegmentIfMissing(const std::string& coreSegmentName)
+        std::pair<bool, CoreSegmentT*> _addCoreSegmentIfMissing(const std::string& coreSegmentName, const bool addMissingCoreSegmentDuringUpdate)
         {
             CoreSegmentT* coreSeg = nullptr;
 
             auto it = this->_container.find(coreSegmentName);
             if (it == this->_container.end())
             {
-                if (_addMissingCoreSegmentDuringUpdate)
+                if (addMissingCoreSegmentDuringUpdate)
                 {
                     // Insert into map.
                     coreSeg = &addCoreSegment(coreSegmentName);
@@ -373,13 +376,5 @@ namespace armarx::armem::base
                 return {false, coreSeg};
             }
         }
-
-
-    public:
-
-        // ToDo: Remove from base structure - this should be specific to the server versions.
-        // If necessary at all.
-        bool _addMissingCoreSegmentDuringUpdate = false;
-
     };
 }
diff --git a/source/RobotAPI/libraries/armem/server/ltm/base/detail/MemoryItem.cpp b/source/RobotAPI/libraries/armem/server/ltm/base/detail/MemoryItem.cpp
index 6f38d6ea21317b44d37045c985f15d5efe2103da..d5318e1f1e6ec9933ddc7e6b50f3894044111917 100644
--- a/source/RobotAPI/libraries/armem/server/ltm/base/detail/MemoryItem.cpp
+++ b/source/RobotAPI/libraries/armem/server/ltm/base/detail/MemoryItem.cpp
@@ -33,4 +33,9 @@ namespace armarx::armem::server::ltm
     {
         return _id.getLeafItem();
     }
+
+    void MemoryItem::setMemoryName(const std::string& memoryName)
+    {
+        _id.memoryName = memoryName;
+    }
 } // namespace armarx::armem::server::ltm
diff --git a/source/RobotAPI/libraries/armem/server/ltm/base/detail/MemoryItem.h b/source/RobotAPI/libraries/armem/server/ltm/base/detail/MemoryItem.h
index 570231509806a4f6a56d55ab4a4a2d7442de8807..b8d17fe471c17e62aa188406648515e5a32f384a 100644
--- a/source/RobotAPI/libraries/armem/server/ltm/base/detail/MemoryItem.h
+++ b/source/RobotAPI/libraries/armem/server/ltm/base/detail/MemoryItem.h
@@ -21,6 +21,7 @@ namespace armarx::armem::server::ltm
         std::string name() const;
 
         virtual void setMemoryID(const MemoryID&);
+        void setMemoryName(const std::string& memoryName);
 
     protected:
         std::shared_ptr<Processors> processors;
diff --git a/source/RobotAPI/libraries/armem/server/ltm/disk/detail/util/filesystem_util.cpp b/source/RobotAPI/libraries/armem/server/ltm/disk/detail/util/filesystem_util.cpp
index 6b6bfdc1be88e30507e2a5d865b94c44abfb090d..1a40e26a04923bccb123b4b07f00ab9be190efa9 100644
--- a/source/RobotAPI/libraries/armem/server/ltm/disk/detail/util/filesystem_util.cpp
+++ b/source/RobotAPI/libraries/armem/server/ltm/disk/detail/util/filesystem_util.cpp
@@ -1,5 +1,7 @@
 #include "filesystem_util.h"
 
+#include <algorithm>
+
 #include <RobotAPI/libraries/armem/core/error/ArMemError.h>
 
 
diff --git a/source/RobotAPI/libraries/armem/server/plugins/Plugin.h b/source/RobotAPI/libraries/armem/server/plugins/Plugin.h
index 02c89e5f323b4376ca4493f6b0f1e8efa22f3b60..aa6afd8171ff50cf43b955ff145a4770cf8f24b7 100644
--- a/source/RobotAPI/libraries/armem/server/plugins/Plugin.h
+++ b/source/RobotAPI/libraries/armem/server/plugins/Plugin.h
@@ -41,7 +41,7 @@ namespace armarx::armem::server::plugins
 
     public:
 
-        /// Set the name of the wm and the ltm (if enabled).
+        /// Set the name of the wm and the ltm
         void setMemoryName(const std::string& memoryName);
 
 
diff --git a/source/RobotAPI/libraries/armem_gui/MemoryViewer.cpp b/source/RobotAPI/libraries/armem_gui/MemoryViewer.cpp
index 622031b7aead835f8d91b9eeac4ac06362d731a1..b9c789398b0d8ce5c6fb17e0c2cb44fb5bc5b531 100644
--- a/source/RobotAPI/libraries/armem_gui/MemoryViewer.cpp
+++ b/source/RobotAPI/libraries/armem_gui/MemoryViewer.cpp
@@ -150,7 +150,7 @@ namespace armarx::armem::gui
         connect(this, &This::connected, this, &This::startPeriodicUpdateTimer);
         connect(updateWidget, &armem::gui::PeriodicUpdateWidget::update, this, &This::startQueries);
 
-        connect(periodicUpdateTimer, &QTimer::timeout, this, &This::updateAvailableMemories);
+        connect(periodicUpdateTimer, &QTimer::timeout, this, &This::updateListOfActiveMemories);
         connect(periodicUpdateTimer, &QTimer::timeout, this, &This::processQueryResults);
 
         connect(memoryGroup->queryWidget(), &armem::gui::QueryWidget::storeInLTM, this, &This::queryAndStoreInLTM);
@@ -267,7 +267,7 @@ namespace armarx::armem::gui
         {
             std::stringstream ss;
             ss << "Memory name '" << memoryName
-               << "' is unknown. Known are: " << simox::alg::get_keys(memoryData);
+               << "' is unknown. Known are: " << simox::alg::join(simox::alg::get_keys(memoryData), ", ");
             statusLabel->setText(QString::fromStdString(ss.str()));
             return nullptr;
         }
@@ -288,7 +288,7 @@ namespace armarx::armem::gui
     {
         TIMING_START(MemoryStore);
 
-        auto enabledMemories = memoryGroup->queryWidget()->enabledMemories();
+        auto enabledMemories = memoryGroup->queryWidget()->getEnabledMemories();
         for (auto& [name, reader] : memoryReaders)
         {
             // skip if memory should not be queried
@@ -321,7 +321,7 @@ namespace armarx::armem::gui
 
         TIMING_START(MemoryStartRecording);
 
-        auto enabledMemories = memoryGroup->queryWidget()->enabledMemories();
+        auto enabledMemories = memoryGroup->queryWidget()->getEnabledMemories();
         for (auto& [name, reader] : memoryReaders)
         {
             // skip if memory should not be queried
@@ -341,7 +341,7 @@ namespace armarx::armem::gui
 
         TIMING_START(MemoryStopRecording);
 
-        auto enabledMemories = memoryGroup->queryWidget()->enabledMemories();
+        auto enabledMemories = memoryGroup->queryWidget()->getEnabledMemories();
         for (auto& [name, reader] : memoryReaders)
         {
             // skip if memory should not be queried
@@ -406,7 +406,8 @@ namespace armarx::armem::gui
         TIMING_START(MemoryExport)
 
         std::string status;
-        diskControl->storeOnDisk(directory, memoryData, &status);
+        std::vector<wm::Memory> memoryDataVec = simox::alg::get_values(memoryData);
+        diskControl->storeOnDisk(directory, memoryDataVec, &status);
 
         statusLabel->setText(QString::fromStdString(status));
         TIMING_END_STREAM(MemoryExport, ARMARX_VERBOSE)
@@ -418,19 +419,29 @@ namespace armarx::armem::gui
     {
 
         std::string status;
-        std::map<std::string, wm::Memory> data =
+        std::map<std::filesystem::path, wm::Memory> data =
             diskControl->loadFromDisk(directory, memoryGroup->queryInput(), &status);
 
-        for (auto& [name, memory] : data)
+        for (auto& [path, memory] : data)
         {
+            std::string name = memory.id().memoryName;
+            auto commit = armem::toCommit(memory);
+
             if (memoryWriters.count(name) > 0)
             {
-                auto commit = armem::toCommit(memory);
                 memoryWriters.at(name).commit(commit);
             }
             else
             {
-                ARMARX_WARNING << "No memory with name " << name << " available for commit.";
+                ARMARX_INFO << "No memory with name '" << name << "' available for commit. Create new virtual memory.";
+
+                // Please note: Here we assume that a memory server with the same name does not exist.
+                // I think this assumption is ok, since nobody should use filepaths as memory name.
+                // Nonetheless, we did not restrict the user to do so...
+                std::string virtualMemoryName = name + " (at " + path.string() + ")";
+                wm::Memory virtualMemory(virtualMemoryName);
+                virtualMemory.update(commit, true, false);
+                memoryData[virtualMemoryName] = virtualMemory;
             }
         }
 
@@ -487,7 +498,7 @@ namespace armarx::armem::gui
 
         // Can't use a structured binding here because you can't capture those in a lambda
         // according to the C++ standard.
-        auto enabledMemories = memoryGroup->queryWidget()->enabledMemories();
+        auto enabledMemories = memoryGroup->queryWidget()->getEnabledMemories();
         for (const auto& pair : memoryReaders)
         {
             // skip if memory should not be queried
@@ -592,7 +603,7 @@ namespace armarx::armem::gui
         }
 
         // Perhaps remove entries
-        auto enabledMemories = memoryGroup->queryWidget()->enabledMemories();
+        auto enabledMemories = memoryGroup->queryWidget()->getEnabledMemories();
         for (auto it = memoryData.begin(); it != memoryData.end();)
         {
             // Drop all entries in memoryData which are not in memoryReaders anymore.
@@ -764,7 +775,7 @@ namespace armarx::armem::gui
 
 
     void
-    MemoryViewer::updateAvailableMemories()
+    MemoryViewer::updateListOfActiveMemories()
     {
         if (is_connected and mns) // mns must be connected and mns must be available
         {
@@ -773,11 +784,13 @@ namespace armarx::armem::gui
                 memoryReaders = mns.getAllReaders(true);
                 memoryWriters = mns.getAllWriters(true);
 
-                std::vector<std::string> convVec;
-                std::transform(memoryReaders.begin(), memoryReaders.end(), std::back_inserter(convVec), [](const auto& p){return p.first;});
+                std::vector<std::string> activeMemoryNames;
+
+                // add all active memories to update list
+                std::transform(memoryReaders.begin(), memoryReaders.end(), std::back_inserter(activeMemoryNames), [](const auto& p){return p.first;});
 
                 TIMING_START(GuiUpdateAvailableMemories);
-                memoryGroup->queryWidget()->update(convVec);
+                memoryGroup->queryWidget()->update(activeMemoryNames);
                 TIMING_END_STREAM(GuiUpdateAvailableMemories, ARMARX_VERBOSE);
             }
             catch (...)
@@ -796,14 +809,16 @@ namespace armarx::armem::gui
     void
     MemoryViewer::updateMemoryTree()
     {
-        std::map<std::string, const armem::wm::Memory*> convMap;
+        std::map<std::string, const armem::wm::Memory*> memoriesToUpdate;
+
+        //auto checkboxStates = memoryGroup->queryWidget()->getAvailableMemoryStates();
         for (auto& [name, data] : memoryData)
         {
-            convMap[name] = &data;
+            memoriesToUpdate[name] = &data;
         }
 
         TIMING_START(GuiUpdateMemoryTree)
-        memoryGroup->tree()->update(convMap);
+        memoryGroup->tree()->update(memoriesToUpdate);
         TIMING_END_STREAM(GuiUpdateMemoryTree, ARMARX_VERBOSE)
 
         if (debugObserver)
diff --git a/source/RobotAPI/libraries/armem_gui/MemoryViewer.h b/source/RobotAPI/libraries/armem_gui/MemoryViewer.h
index 7be0874b265375827d22067e4325edcbf6c4bd12..69fb59d1c2f83b53ebd6587cfd63c148bcab9b7f 100644
--- a/source/RobotAPI/libraries/armem_gui/MemoryViewer.h
+++ b/source/RobotAPI/libraries/armem_gui/MemoryViewer.h
@@ -110,7 +110,7 @@ namespace armarx::armem::gui
         void processQueryResults();
 
         void updateMemoryTree();
-        void updateAvailableMemories();
+        void updateListOfActiveMemories();
 
 
     signals:
diff --git a/source/RobotAPI/libraries/armem_gui/disk/ControlWidget.cpp b/source/RobotAPI/libraries/armem_gui/disk/ControlWidget.cpp
index fe443952ce26bf9546c9238eaf1fa234f13368f6..a490d63436a484cee322d167a02675710c695260 100644
--- a/source/RobotAPI/libraries/armem_gui/disk/ControlWidget.cpp
+++ b/source/RobotAPI/libraries/armem_gui/disk/ControlWidget.cpp
@@ -78,7 +78,7 @@ namespace armarx::armem::gui::disk
     void
     ControlWidget::storeOnDisk(
         QString directory,
-        const std::map<std::string, wm::Memory> memoryData,
+        const std::vector<wm::Memory> memoryData,
         std::string* outStatus)
     {
         std::filesystem::path path(directory.toUtf8().constData());
@@ -92,8 +92,9 @@ namespace armarx::armem::gui::disk
         else
         {
             int numStored = 0;
-            for (const auto& [name, data] : memoryData)
+            for (const auto& data : memoryData)
             {
+                std::string name = data.id().memoryName;
                 if (std::filesystem::is_regular_file(path / name))
                 {
                     status << "Could not export memory '" << name << "' to " << path << ": Cannot overwrite existing file.\n";
@@ -116,7 +117,7 @@ namespace armarx::armem::gui::disk
     }
 
 
-    std::map<std::string, wm::Memory>
+    std::map<std::filesystem::path, wm::Memory>
     ControlWidget::loadFromDisk(
         QString directory,
         const armem::client::QueryInput& _queryInput,
@@ -124,7 +125,7 @@ namespace armarx::armem::gui::disk
     {
         std::filesystem::path path(directory.toUtf8().constData());
 
-        std::map<std::string, wm::Memory> memoryData;
+        std::map<std::filesystem::path, wm::Memory> memoryData;
 
         auto setStatus = [&](const std::string& s){
             if (outStatus)
@@ -161,7 +162,7 @@ namespace armarx::armem::gui::disk
             }
         }
 
-        // TODO: Only add data that matchs query?
+        // TODO: Only add data that matches query?
         // We use LTM as query target for the disk
         // armem::client::QueryInput queryInput = _queryInput;
         // queryInput.addQueryTargetToAll(armem::query::data::QueryTarget::LTM);
@@ -172,8 +173,8 @@ namespace armarx::armem::gui::disk
             if (std::filesystem::is_directory(p))
             {
                 armem::server::ltm::disk::Memory ltm(p.parent_path(), p.filename());
-                armem::wm::Memory memory = ltm.loadAllAndResolve(); // load list of references
-                memoryData[memory.name()] = std::move(memory);
+                armem::wm::Memory memory = ltm.loadAllAndResolve(); // load list of references and load data
+                memoryData[p] = memory;
 
                 numLoaded++;
             }
diff --git a/source/RobotAPI/libraries/armem_gui/disk/ControlWidget.h b/source/RobotAPI/libraries/armem_gui/disk/ControlWidget.h
index b14c9b0a0810acbafba74638e6ebd87989e81165..5eb35b96057f0639a30d94df4dada8ecd38afd9a 100644
--- a/source/RobotAPI/libraries/armem_gui/disk/ControlWidget.h
+++ b/source/RobotAPI/libraries/armem_gui/disk/ControlWidget.h
@@ -5,6 +5,7 @@
 
 #include <QWidget>
 #include <QString>
+#include <filesystem>
 
 
 class QPushButton;
@@ -26,10 +27,10 @@ namespace armarx::armem::gui::disk
         void
         storeOnDisk(
             QString directory,
-            const std::map<std::string, wm::Memory> memoryData,
+            const std::vector<wm::Memory> memoryData,
             std::string* outStatus = nullptr);
 
-        std::map<std::string, wm::Memory>
+        std::map<std::filesystem::path, wm::Memory>
         loadFromDisk(
             QString directory,
             const armem::client::QueryInput& queryInput,
diff --git a/source/RobotAPI/libraries/armem_gui/query_widgets/QueryWidget.cpp b/source/RobotAPI/libraries/armem_gui/query_widgets/QueryWidget.cpp
index 54e5aaec313825ae63bf8f15351339fce9288129..a3ce95672ec49cf3a3cffb426f28a04be4b43ccc 100644
--- a/source/RobotAPI/libraries/armem_gui/query_widgets/QueryWidget.cpp
+++ b/source/RobotAPI/libraries/armem_gui/query_widgets/QueryWidget.cpp
@@ -162,8 +162,35 @@ namespace armarx::armem::gui
         return _dropDisabledCheckBox->isChecked();
     }
 
+    std::map<std::string, QueryWidget::ActiveMemoryState> QueryWidget::getAvailableMemoryStates() const
+    {
+        std::scoped_lock l(enabledMemoriesMutex);
+
+        std::map<std::string, QueryWidget::ActiveMemoryState> states;
+        int maxIndex = _availableMemoriesGroupBox->layout()->count();
+        for (int i = 0; i < maxIndex; ++i)
+        {
+            auto w = _availableMemoriesGroupBox->layout()->itemAt(i)->widget();
+            QCheckBox* box = static_cast<QCheckBox*>(w);
+            std::string memoryName = box->text().toStdString();
+            if (box->isEnabled() && box->isChecked())
+            {
+                states[memoryName] = ActiveMemoryState::FoundAndChecked;
+            }
+            else if (box->isEnabled() && !box->isChecked())
+            {
+                states[memoryName] = ActiveMemoryState::FoundAndNotChecked;
+            }
+            else
+            {
+                states[memoryName] = ActiveMemoryState::NotFound;
+            }
+        }
+        return states;
+    }
+
 
-    std::vector<std::string> QueryWidget::enabledMemories() const
+    std::vector<std::string> QueryWidget::getEnabledMemories() const
     {
         std::scoped_lock l(enabledMemoriesMutex);
 
diff --git a/source/RobotAPI/libraries/armem_gui/query_widgets/QueryWidget.h b/source/RobotAPI/libraries/armem_gui/query_widgets/QueryWidget.h
index d3d534e5b4896d51d5d0a104852c1d6c64af982f..623b78c4126b6a09acd636c93b9d4c9b6f4934cf 100644
--- a/source/RobotAPI/libraries/armem_gui/query_widgets/QueryWidget.h
+++ b/source/RobotAPI/libraries/armem_gui/query_widgets/QueryWidget.h
@@ -22,6 +22,13 @@ namespace armarx::armem::gui
 
     public:
 
+        enum class ActiveMemoryState
+        {
+            FoundAndChecked,
+            FoundAndNotChecked,
+            NotFound
+        };
+
         QueryWidget();
 
         armem::query::DataMode dataMode() const;
@@ -31,7 +38,9 @@ namespace armarx::armem::gui
 
         int queryLinkRecursionDepth() const;
 
-        std::vector<std::string> enabledMemories() const;
+        std::map<std::string, ActiveMemoryState> getAvailableMemoryStates() const;
+
+        std::vector<std::string> getEnabledMemories() const;
 
         void update(const std::vector<std::string>& memoryNames);
 
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/client/articulated_object/ArticulatedObjectReader.cpp b/source/RobotAPI/libraries/armem_objects/client/articulated_object/ArticulatedObjectReader.cpp
index c16ff257603b9fded0a5ea72737b92b40667fdb6..a2b0ddd6b2985997156cfa6c82998de249409e5a 100644
--- a/source/RobotAPI/libraries/armem_objects/client/articulated_object/ArticulatedObjectReader.cpp
+++ b/source/RobotAPI/libraries/armem_objects/client/articulated_object/ArticulatedObjectReader.cpp
@@ -47,7 +47,7 @@ namespace armarx::armem::articulated_object
         ARMARX_DEBUG << "Object " << name << " available";
 
         auto obj = VirtualRobot::RobotIO::loadRobot(
-                    ArmarXDataPath::resolvePath(it->xml.serialize().path),
+                    it->xml.toSystemPath(),
                     VirtualRobot::RobotIO::eStructure);
 
         if (not obj)
diff --git a/source/RobotAPI/libraries/armem_objects/client/articulated_object/ArticulatedObjectWriter.cpp b/source/RobotAPI/libraries/armem_objects/client/articulated_object/ArticulatedObjectWriter.cpp
index 54049d8bbeb899b350dfab4906a125157ea527b9..0b466d404fbc41d5eee48819418dd5b5cae35d1f 100644
--- a/source/RobotAPI/libraries/armem_objects/client/articulated_object/ArticulatedObjectWriter.cpp
+++ b/source/RobotAPI/libraries/armem_objects/client/articulated_object/ArticulatedObjectWriter.cpp
@@ -3,44 +3,53 @@
 #include <Eigen/Core>
 #include <Eigen/Geometry>
 
+#include <VirtualRobot/Robot.h>
+
 #include <ArmarXCore/core/exceptions/local/ExpressionException.h>
 #include <ArmarXCore/core/logging/Logging.h>
 #include <ArmarXCore/core/system/ArmarXDataPath.h>
-
-#include <VirtualRobot/Robot.h>
+#include <ArmarXCore/core/system/cmake/CMakePackageFinder.h>
 
 
 namespace armarx::armem::articulated_object
 {
-    armem::articulated_object::ArticulatedObject convert(
-            const VirtualRobot::Robot& obj,
-            const armem::Time& timestamp)
+    armem::articulated_object::ArticulatedObject
+    convert(const VirtualRobot::Robot& obj, const armem::Time& timestamp)
     {
         ARMARX_DEBUG << "Filename is " << obj.getFilename();
 
-        // TODO(fabian.reister): remove "PriorKnowledgeData" below
+        const std::vector<std::string> packages =
+            armarx::CMakePackageFinder::FindAllArmarXSourcePackages();
+        const std::string package = armarx::ArmarXDataPath::getProject(packages, obj.getFilename());
 
-        return armem::articulated_object::ArticulatedObject
+        // make sure that the relative path is without the 'package/' prefix
+        const std::string fileRelPath = [&obj, &package]() -> std::string
         {
-            .description = {
-                .name = obj.getType(),
-                .xml  = PackagePath(armarx::ArmarXDataPath::getProject(
-                {"PriorKnowledgeData"}, obj.getFilename()),
-                obj.getFilename())
-            },
-            .instance    = obj.getName(),
-            .config      = {
-                .timestamp  = timestamp,
-                .globalPose = Eigen::Affine3f(obj.getRootNode()->getGlobalPose()),
-                .jointMap   = obj.getJointValues()
-            },
-            .timestamp   = timestamp};
+            if (simox::alg::starts_with(obj.getFilename(), package))
+            {
+                // remove "package" + "/"
+                const std::string fixedFilename = obj.getFilename().substr(package.size() + 1, -1);
+                return fixedFilename;
+            }
+
+            return obj.getFilename();
+        }();
+
+        return armem::articulated_object::ArticulatedObject{
+            .description = {.name = obj.getType(),
+                            .xml = PackagePath(armarx::ArmarXDataPath::getProject(
+                                                   {package}, fileRelPath),
+                                               obj.getFilename())},
+            .instance = obj.getName(),
+            .config = {.timestamp = timestamp,
+                       .globalPose = Eigen::Affine3f(obj.getRootNode()->getGlobalPose()),
+                       .jointMap = obj.getJointValues()},
+            .timestamp = timestamp};
     }
 
     bool
-    ArticulatedObjectWriter::storeArticulatedObject(
-            const VirtualRobot::RobotPtr& articulatedObject,
-            const armem::Time& timestamp)
+    ArticulatedObjectWriter::storeArticulatedObject(const VirtualRobot::RobotPtr& articulatedObject,
+                                                    const armem::Time& timestamp)
     {
 
         ARMARX_CHECK_NOT_NULL(articulatedObject);
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 887674e048a41f2a93996a0d6fbdb91e90b7f901..c17ce69020b2b7f2c363219339754919fc805723 100644
--- a/source/RobotAPI/libraries/armem_objects/server/instance/Segment.cpp
+++ b/source/RobotAPI/libraries/armem_objects/server/instance/Segment.cpp
@@ -222,12 +222,21 @@ namespace armarx::armem::server::obj::instance
                 stats.numUpdated++;
 
                 VirtualRobot::RobotPtr robot = robots.get(provided.robotName, provided.providerName);
+
+                if(not robot)
+                {
+                    ARMARX_INFO << deactivateSpam(1) << "Failed to retrieve robot `" << provided.robotName << "`.";
+                }
+
                 // robot may be null!
 
                 // Update the robot to obtain correct local -> global transformation
                 if (robot and robotSyncTimestamp != timestamp)
                 {
-                    ARMARX_CHECK(robots.reader->synchronizeRobot(*robot, timestamp));
+                    ARMARX_CHECK(robots.reader->synchronizeRobot(*robot, timestamp)) 
+                        << "Failed to synchronize robot to timestamp " << timestamp 
+                        << ". This is " << (Clock::Now() - timestamp).toSecondsDouble() << " seconds in the past.";
+                        
                     robotSyncTimestamp = timestamp;
 
 
@@ -1302,14 +1311,13 @@ 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)
             {
-                reader->synchronizeRobot(*robot, Clock::Now());
+                ARMARX_CHECK(reader->synchronizeRobot(*robot, Clock::Now()));
                 // Store robot if valid.
                 loaded.emplace(robotName, robot);
             }
diff --git a/source/RobotAPI/libraries/armem_objects/server/instance/Visu.cpp b/source/RobotAPI/libraries/armem_objects/server/instance/Visu.cpp
index 3a13f6722e5cd2c0f824c630a83367b47af1de72..514096731b83167b902dfe4198deae82725837ed 100644
--- a/source/RobotAPI/libraries/armem_objects/server/instance/Visu.cpp
+++ b/source/RobotAPI/libraries/armem_objects/server/instance/Visu.cpp
@@ -194,7 +194,7 @@ namespace armarx::armem::server::obj::instance
                 {
                     viz::Robot robot(key);
                     robot.pose(pose);
-                    robot.file(model->package, model->relativePath);
+                    robot.file(model->package, model->package + "/" + model->relativePath);
                     robot.joints(objectPose.objectJointValues);
 
                     layer.add(robot);
diff --git a/source/RobotAPI/libraries/armem_robot/types.h b/source/RobotAPI/libraries/armem_robot/types.h
index 345564d4b859af306acecdc82d00096c4a559351..2bc45c144b53e3900e8c7041c54d33ee0d205f56 100644
--- a/source/RobotAPI/libraries/armem_robot/types.h
+++ b/source/RobotAPI/libraries/armem_robot/types.h
@@ -40,6 +40,15 @@ namespace armarx::armem::robot
         Eigen::Vector3f torque;
     };
 
+    using ToFArray = Eigen::MatrixXf;
+
+    struct ToF
+    {
+        ToFArray array;
+        std::string frame;
+    };
+
+
     struct RobotState
     {
         using JointMap = std::map<std::string, float>;
diff --git a/source/RobotAPI/libraries/armem_robot_state/CMakeLists.txt b/source/RobotAPI/libraries/armem_robot_state/CMakeLists.txt
index a9c0ceb1b8cd552915819a052a2ffd73bbfdec29..8dda90015cd030197cd4af43fd2b9d534968fc19 100644
--- a/source/RobotAPI/libraries/armem_robot_state/CMakeLists.txt
+++ b/source/RobotAPI/libraries/armem_robot_state/CMakeLists.txt
@@ -65,6 +65,7 @@ armarx_enable_aron_file_generation_for_target(
     ARON_FILES
         aron/JointState.xml
         aron/Proprioception.xml
+        aron/Exteroception.xml
         aron/TransformHeader.xml
         aron/Transform.xml
 )
diff --git a/source/RobotAPI/libraries/armem_robot_state/aron/Exteroception.xml b/source/RobotAPI/libraries/armem_robot_state/aron/Exteroception.xml
new file mode 100644
index 0000000000000000000000000000000000000000..80f72e06059a39e60e6709a5e7acb28c63ee3395
--- /dev/null
+++ b/source/RobotAPI/libraries/armem_robot_state/aron/Exteroception.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<AronTypeDefinition>
+    <CodeIncludes>
+        <SystemInclude include="Eigen/Core" />
+        <SystemInclude include="Eigen/Geometry" />
+    </CodeIncludes>
+
+    <GenerateTypes>
+
+        <Object name="armarx::armem::exteroception::arondto::ToF">
+            
+            <ObjectChild key="array">
+                <Matrix rows="-1" cols="-1" type="float32" />
+            </ObjectChild>
+
+        </Object>
+        
+        
+        <Object name="armarx::armem::arondto::Exteroception">
+            
+            <ObjectChild key="iterationID">
+                <long />
+            </ObjectChild>
+
+            <ObjectChild key="tof">
+                <Dict>
+                    <armarx::armem::exteroception::arondto::ToF/>
+                </Dict>
+            </ObjectChild>
+
+        </Object>
+
+            
+    </GenerateTypes>
+</AronTypeDefinition>
diff --git a/source/RobotAPI/libraries/armem_robot_state/aron/Proprioception.xml b/source/RobotAPI/libraries/armem_robot_state/aron/Proprioception.xml
index c7ac7670d399329bb6674dad3243a048153534f8..d5472cbde89434e346f116e6b6f461bf4f2ca34e 100644
--- a/source/RobotAPI/libraries/armem_robot_state/aron/Proprioception.xml
+++ b/source/RobotAPI/libraries/armem_robot_state/aron/Proprioception.xml
@@ -234,8 +234,6 @@
             </ObjectChild>
 
         </Object>
-
-        
         
         <Object name="armarx::armem::arondto::Proprioception">
             
@@ -257,7 +255,6 @@
                 </Dict>
             </ObjectChild>
 
-
             <ObjectChild key="extraFloats">
                 <Dict>
                     <Float />
diff --git a/source/RobotAPI/libraries/armem_robot_state/aron_conversions.cpp b/source/RobotAPI/libraries/armem_robot_state/aron_conversions.cpp
index 1c18fe5b78799b1b2f9555a33a8997e7edb60d28..3749c892d5e46e6ce0f7a848a86e8059ed70991c 100644
--- a/source/RobotAPI/libraries/armem_robot_state/aron_conversions.cpp
+++ b/source/RobotAPI/libraries/armem_robot_state/aron_conversions.cpp
@@ -6,6 +6,7 @@
 
 #include <RobotAPI/libraries/armem_robot_state/aron/JointState.aron.generated.h>
 #include <RobotAPI/libraries/armem_robot_state/aron/Proprioception.aron.generated.h>
+#include <RobotAPI/libraries/armem_robot_state/aron/Exteroception.aron.generated.h>
 #include <RobotAPI/libraries/armem_robot_state/aron/Transform.aron.generated.h>
 #include <RobotAPI/libraries/armem_robot_state/types.h>
 #include <RobotAPI/libraries/aron/common/aron_conversions.h>
@@ -97,4 +98,14 @@ namespace armarx::armem
         aron::toAron(dto.torque, bo.torque);
     }
 
+
+    void fromAron(const armarx::armem::exteroception::arondto::ToF& dto, robot::ToFArray& bo){
+        bo = dto.array;
+    }
+
+    void toAron(armarx::armem::exteroception::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..f78efc200ee18205523ddf7ea5c60e8c6949bf9f 100644
--- a/source/RobotAPI/libraries/armem_robot_state/aron_conversions.h
+++ b/source/RobotAPI/libraries/armem_robot_state/aron_conversions.h
@@ -40,6 +40,11 @@ namespace armarx::armem
         struct ForceTorque;
     }
 
+    namespace exteroception::arondto
+    {
+        struct ToF;
+    }
+
     namespace arondto
     {
         struct Transform;
@@ -65,5 +70,8 @@ namespace armarx::armem
     void fromAron(const armarx::armem::prop::arondto::ForceTorque& dto, robot::ForceTorque& bo);
     void toAron(armarx::armem::prop::arondto::ForceTorque& dto, const robot::ForceTorque& bo);
 
+    void fromAron(const armarx::armem::exteroception::arondto::ToF& dto, robot::ToFArray& bo);
+    void toAron(armarx::armem::exteroception::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..eaa2e9ca07b063eaba3a71887eda2d14fa839c16 100644
--- a/source/RobotAPI/libraries/armem_robot_state/client/common/RobotReader.cpp
+++ b/source/RobotAPI/libraries/armem_robot_state/client/common/RobotReader.cpp
@@ -22,6 +22,7 @@
 #include <RobotAPI/libraries/armem_robot/aron_conversions.h>
 #include <RobotAPI/libraries/armem_robot/robot_conversions.h>
 #include <RobotAPI/libraries/armem_robot/types.h>
+#include <RobotAPI/libraries/armem_robot_state/aron/Exteroception.aron.generated.h>
 #include <RobotAPI/libraries/armem_robot_state/aron/JointState.aron.generated.h>
 #include <RobotAPI/libraries/armem_robot_state/aron/Proprioception.aron.generated.h>
 #include <RobotAPI/libraries/armem_robot_state/aron_conversions.h>
@@ -121,7 +122,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;
                 }
 
@@ -135,11 +136,7 @@ namespace armarx::armem::robot_state
     }
 
     std::optional<robot::RobotDescription>
-    RobotReader::queryDescription(
-            const std::string& name,
-            const armem::Time& timestamp,
-            bool warnings
-            )
+    RobotReader::queryDescription(const std::string& name, const armem::Time& timestamp)
     {
 
         const auto sanitizedTimestamp = timestamp.isValid() ? timestamp : Clock::Now();
@@ -159,11 +156,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 +176,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 +189,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 +226,7 @@ namespace armarx::armem::robot_state
         }
         catch (...)
         {
-            ARMARX_WARNING << GetHandledExceptionString();
+            ARMARX_VERBOSE << GetHandledExceptionString();
             return std::nullopt;
         }
     }
@@ -268,7 +259,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 +267,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 +297,7 @@ namespace armarx::armem::robot_state
 
         if (not qResult.success) /* c++20 [[unlikely]] */
         {
-            ARMARX_WARNING << qResult.errorMessage;
+            ARMARX_VERBOSE << qResult.errorMessage;
             return {};
         }
 
@@ -339,7 +330,7 @@ namespace armarx::armem::robot_state
 
         if (not qResult.success) /* c++20 [[unlikely]] */
         {
-            ARMARX_WARNING << qResult.errorMessage;
+            ARMARX_VERBOSE << qResult.errorMessage;
             return std::nullopt;
         }
 
@@ -352,7 +343,8 @@ namespace armarx::armem::robot_state
     {
         try
         {
-            const auto result = transformReader.getGlobalPose(description.name, constants::robotRootNodeName, timestamp);
+            const auto result = transformReader.getGlobalPose(
+                description.name, constants::robotRootNodeName, timestamp);
             if (not result)
             {
                 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::exteroceptionCoreSegment)
+        .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,47 @@ 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::exteroceptionCoreSegment);
+        // 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 exteroception =
+                    tryCast<::armarx::armem::arondto::Exteroception>(entityInstance);
+                ARMARX_CHECK(exteroception.has_value());
+
+
+                for (const auto& [handName, dtoFt] : exteroception->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,11 +771,77 @@ 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;
         }
 
         return robot::convertRobotDescription(*instance);
     }
 
+    std::vector<robot::RobotDescription>
+    RobotReader::getRobotDescriptions(const armarx::armem::wm::Memory& memory) const
+    {
+        const armem::wm::CoreSegment& coreSegment =
+            memory.getCoreSegment(constants::descriptionCoreSegment);
+
+        std::vector<robot::RobotDescription> descriptions;
+
+        coreSegment.forEachInstance(
+            [&descriptions](const wm::EntityInstance& instance)
+            {
+                if (const std::optional<robot::RobotDescription> desc =
+                        robot::convertRobotDescription(instance))
+                {
+                    descriptions.push_back(desc.value());
+                }
+            });
+
+        return descriptions;
+    }
+
+    std::vector<robot::RobotDescription>
+    RobotReader::queryDescriptions(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().withName(constants::descriptionCoreSegment)
+        .providerSegments().all()
+        .entities().all()
+        .snapshots().beforeOrAtTime(sanitizedTimestamp);
+        // clang-format on
+
+        ARMARX_DEBUG << "Lookup query in reader";
+
+        if (not memoryReader)
+        {
+            ARMARX_WARNING << "Memory reader is null. Did you forget to call "
+                              "RobotReader::connect() in onConnectComponent()?";
+            return {};
+        }
+
+        try
+        {
+            const armem::client::QueryResult qResult = memoryReader.query(qb.buildQueryInput());
+
+            ARMARX_DEBUG << "Lookup result in reader: " << qResult;
+
+            if (not qResult.success) /* c++20 [[unlikely]] */
+            {
+                return {};
+            }
+
+            return getRobotDescriptions(qResult.memory);
+        }
+        catch (...)
+        {
+            ARMARX_VERBOSE << "Query description failure" << GetHandledExceptionString();
+        }
+
+        return {};
+    }
 } // namespace armarx::armem::robot_state
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..a9cddc6b2afd5258271f5718b4f1c82d0dd6a995 100644
--- a/source/RobotAPI/libraries/armem_robot_state/client/common/RobotReader.h
+++ b/source/RobotAPI/libraries/armem_robot_state/client/common/RobotReader.h
@@ -23,6 +23,7 @@
 
 #include <mutex>
 #include <optional>
+#include <vector>
 
 #include <RobotAPI/libraries/armem/client/MemoryNameSystem.h>
 #include <RobotAPI/libraries/armem/client/Reader.h>
@@ -50,7 +51,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 +59,9 @@ 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::vector<robot::RobotDescription> queryDescriptions(const armem::Time& timestamp);
 
         std::optional<robot::RobotState> queryState(const robot::RobotDescription& description,
                                                     const armem::Time& timestamp);
@@ -100,6 +102,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. 
          *
@@ -125,6 +131,9 @@ namespace armarx::armem::robot_state
         std::optional<robot::RobotDescription>
         getRobotDescription(const armarx::armem::wm::Memory& memory, const std::string& name) const;
 
+        std::vector<robot::RobotDescription>
+        getRobotDescriptions(const armarx::armem::wm::Memory& memory) const;
+
         std::optional<robot::RobotState::JointMap>
         getRobotJointState(const armarx::armem::wm::Memory& memory, const std::string& name) const;
 
@@ -142,6 +151,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..225e048864e69a7c349b9e53163d41ed1e0eef6b 100644
--- a/source/RobotAPI/libraries/armem_robot_state/client/common/VirtualRobotReader.cpp
+++ b/source/RobotAPI/libraries/armem_robot_state/client/common/VirtualRobotReader.cpp
@@ -38,16 +38,16 @@ namespace armarx::armem::robot_state
     bool
     VirtualRobotReader::synchronizeRobot(VirtualRobot::Robot& robot, const armem::Time& timestamp)
     {
-        const static auto packages = armarx::CMakePackageFinder::FindAllArmarXSourcePackages();
-        const auto package = armarx::ArmarXDataPath::getProject(packages, robot.getFilename());
+        // const static auto packages = armarx::CMakePackageFinder::FindAllArmarXSourcePackages();
+        // const auto package = armarx::ArmarXDataPath::getProject(packages, robot.getFilename());
 
         const robot::RobotDescription robotDescription{
-            .name = robot.getName(), .xml = PackagePath{package, robot.getFilename()}};
+            .name = robot.getName(), .xml = PackagePath{"", ""}};
 
         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..ab30cbc1317d98f802dc24cbe5d844da02b038e9 100644
--- a/source/RobotAPI/libraries/armem_robot_state/client/common/VirtualRobotReader.h
+++ b/source/RobotAPI/libraries/armem_robot_state/client/common/VirtualRobotReader.h
@@ -27,7 +27,6 @@
 
 #include "RobotReader.h"
 
-
 namespace armarx::armem::robot_state
 {
     /**
@@ -47,14 +46,14 @@ namespace armarx::armem::robot_state
         void connect();
         void registerPropertyDefinitions(::armarx::PropertyDefinitionsPtr& def);
 
-        bool synchronizeRobot(VirtualRobot::Robot& robot, const armem::Time& timestamp);
+        [[nodiscard]] bool synchronizeRobot(VirtualRobot::Robot& robot,
+                                            const armem::Time& timestamp);
 
         [[nodiscard]] VirtualRobot::RobotPtr
         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,
@@ -71,14 +70,12 @@ namespace armarx::armem::robot_state
 
 
     private:
-
         [[nodiscard]] VirtualRobot::RobotPtr
         _getSynchronizedRobot(const std::string& name,
                               const armem::Time& timestamp = armem::Time::Invalid(),
                               const VirtualRobot::RobotIO::RobotDescription& loadMode =
-                                 VirtualRobot::RobotIO::RobotDescription::eStructure,
+                                  VirtualRobot::RobotIO::RobotDescription::eStructure,
                               bool blocking = true);
-
     };
 
 } // namespace armarx::armem::robot_state
diff --git a/source/RobotAPI/libraries/armem_robot_state/client/common/constants.h b/source/RobotAPI/libraries/armem_robot_state/client/common/constants.h
index d9efcbcf795b46ddb4e9647919d38c0c617c1234..5d093c195addda7c64c378d919d38f09987cdfc9 100644
--- a/source/RobotAPI/libraries/armem_robot_state/client/common/constants.h
+++ b/source/RobotAPI/libraries/armem_robot_state/client/common/constants.h
@@ -28,6 +28,7 @@ namespace armarx::armem::robot_state::constants
     inline const std::string descriptionCoreSegment = "Description";
     inline const std::string localizationCoreSegment = "Localization";
     inline const std::string proprioceptionCoreSegment = "Proprioception";
+    inline const std::string exteroceptionCoreSegment = "Exteroception";
 
     inline const std::string descriptionEntityName = "description";
 
diff --git a/source/RobotAPI/libraries/armem_robot_state/memory_ids.cpp b/source/RobotAPI/libraries/armem_robot_state/memory_ids.cpp
index 926c2e843e252efdc9c4711bbe2b03a3a7394bba..2f219eff39376ed3ecc44e47b0780fd1328785a0 100644
--- a/source/RobotAPI/libraries/armem_robot_state/memory_ids.cpp
+++ b/source/RobotAPI/libraries/armem_robot_state/memory_ids.cpp
@@ -30,6 +30,7 @@ namespace armarx::armem
 
     const MemoryID robot_state::descriptionSegmentID { memoryID.withCoreSegmentName("Description") };
     const MemoryID robot_state::proprioceptionSegmentID { memoryID.withCoreSegmentName("Proprioception") };
+    const MemoryID robot_state::exteroceptionSegmentID { memoryID.withCoreSegmentName("Exteroception") };
     const MemoryID robot_state::localizationSegmentID { memoryID.withCoreSegmentName("Localization") };
 
 
diff --git a/source/RobotAPI/libraries/armem_robot_state/memory_ids.h b/source/RobotAPI/libraries/armem_robot_state/memory_ids.h
index 1d8008d4db8d7a71da0a8ca47420040060382ca6..f653236b1f62ec8aef905d45a7ee86af079b05b9 100644
--- a/source/RobotAPI/libraries/armem_robot_state/memory_ids.h
+++ b/source/RobotAPI/libraries/armem_robot_state/memory_ids.h
@@ -32,6 +32,7 @@ namespace armarx::armem::robot_state
 
     extern const MemoryID descriptionSegmentID;
     extern const MemoryID proprioceptionSegmentID;
+    extern const MemoryID exteroceptionSegmentID;
     extern const MemoryID localizationSegmentID;
 
 } // namespace armarx::armem::objects
diff --git a/source/RobotAPI/libraries/armem_robot_state/server/CMakeLists.txt b/source/RobotAPI/libraries/armem_robot_state/server/CMakeLists.txt
index 169d59f1a86d6a1bea1b9e54033409d23fb3cd7f..3ad1d50684d89c246e6123a6ef5d2055779eab6f 100644
--- a/source/RobotAPI/libraries/armem_robot_state/server/CMakeLists.txt
+++ b/source/RobotAPI/libraries/armem_robot_state/server/CMakeLists.txt
@@ -43,10 +43,16 @@ armarx_add_library(
         proprioception/RobotUnitData.h
         proprioception/RobotUnitReader.h
 
+        proprioception/converters/ConverterInterface.h
         proprioception/converters/Armar6Converter.h
         proprioception/converters/ConverterTools.h
         proprioception/converters/ConverterRegistry.h
-        proprioception/converters/ConverterInterface.h
+
+        exteroception/converters/ConverterInterface.h
+        exteroception/converters/ConverterTools.h
+        exteroception/converters/ConverterRegistry.h
+        exteroception/converters/ArmarDEConverter.h
+        exteroception/Segment.h
 
         description/Segment.h
 
@@ -67,6 +73,12 @@ armarx_add_library(
         proprioception/converters/ConverterRegistry.cpp
         proprioception/converters/ConverterInterface.cpp
 
+        exteroception/converters/ConverterInterface.cpp
+        exteroception/converters/ConverterTools.cpp
+        exteroception/converters/ConverterRegistry.cpp
+        exteroception/converters/ArmarDEConverter.cpp
+        exteroception/Segment.cpp
+
         description/Segment.cpp
 )
 
diff --git a/source/RobotAPI/libraries/armem_robot_state/server/exteroception/Segment.cpp b/source/RobotAPI/libraries/armem_robot_state/server/exteroception/Segment.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..63f24d0f46a156adc023b3b64b4f27d344b151c6
--- /dev/null
+++ b/source/RobotAPI/libraries/armem_robot_state/server/exteroception/Segment.cpp
@@ -0,0 +1,50 @@
+#include "Segment.h"
+
+#include <filesystem>
+
+#include <SimoxUtility/algorithm/string/string_tools.h>
+
+#include <ArmarXCore/core/application/properties/PluginAll.h>
+#include <ArmarXCore/core/exceptions/local/ExpressionException.h>
+#include <ArmarXCore/core/system/ArmarXDataPath.h>
+#include <ArmarXCore/core/system/cmake/CMakePackageFinder.h>
+#include <ArmarXCore/core/time/TimeUtil.h>
+
+#include <RobotAPI/libraries/armem/client/Writer.h>
+#include <RobotAPI/libraries/armem/client/query/Builder.h>
+#include <RobotAPI/libraries/armem/client/query/query_fns.h>
+#include <RobotAPI/libraries/armem/core/MemoryID.h>
+#include <RobotAPI/libraries/armem/core/aron_conversions.h>
+#include <RobotAPI/libraries/armem/server/MemoryToIceAdapter.h>
+#include <RobotAPI/libraries/armem_robot/aron/Robot.aron.generated.h>
+#include <RobotAPI/libraries/armem_robot/aron_conversions.h>
+#include <RobotAPI/libraries/armem_robot/robot_conversions.h>
+#include <RobotAPI/libraries/armem_robot/types.h>
+#include <RobotAPI/libraries/armem_robot_state/aron/Exteroception.aron.generated.h>
+#include <RobotAPI/libraries/armem_robot_state/memory_ids.h>
+#include <RobotAPI/libraries/aron/common/aron_conversions.h>
+
+
+namespace armarx::armem::server::robot_state::exteroception
+{
+
+    Segment::Segment(armem::server::MemoryToIceAdapter& memoryToIceAdapter) :
+        Base(memoryToIceAdapter,
+             armem::robot_state::exteroceptionSegmentID.coreSegmentName,
+             arondto::Exteroception::ToAronType())
+    {
+    }
+
+    Segment::~Segment() = default;
+
+
+    // void
+    // Segment::onConnect(const RobotUnitInterfacePrx& robotUnitPrx)
+    // {
+    //     robotUnit = robotUnitPrx;
+
+    //     // store the robot description linked to the robot unit in this segment
+    // }
+
+
+} // namespace armarx::armem::server::robot_state::exteroception
diff --git a/source/RobotAPI/libraries/armem_robot_state/server/exteroception/Segment.h b/source/RobotAPI/libraries/armem_robot_state/server/exteroception/Segment.h
new file mode 100644
index 0000000000000000000000000000000000000000..e8471563d640800a44d4516d6eccdd7d7e355ccd
--- /dev/null
+++ b/source/RobotAPI/libraries/armem_robot_state/server/exteroception/Segment.h
@@ -0,0 +1,55 @@
+/*
+ * 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/>.
+ *
+ * @author     Fabian Reister ( fabian dot reister at kit dot edu )
+ * @date       2023
+ * @copyright  http://www.gnu.org/licenses/gpl-2.0.txt
+ *             GNU General Public License
+ */
+
+#pragma once
+
+#include <mutex>
+#include <optional>
+#include <string>
+#include <unordered_map>
+
+#include <RobotAPI/interface/units/RobotUnit/RobotUnitInterface.h>
+#include <RobotAPI/libraries/armem/server/segment/SpecializedCoreSegment.h>
+#include <RobotAPI/libraries/armem/server/segment/SpecializedProviderSegment.h>
+#include <RobotAPI/libraries/armem_robot/aron/RobotDescription.aron.generated.h>
+#include <RobotAPI/libraries/armem_robot_state/server/forward_declarations.h>
+
+
+namespace armarx::armem::server::robot_state::exteroception
+{
+
+    class Segment : public segment::SpecializedCoreSegment
+    {
+        using Base = segment::SpecializedCoreSegment;
+
+    public:
+        Segment(server::MemoryToIceAdapter& iceMemory);
+        ~Segment() override;
+
+
+        // void onConnect(const RobotUnitInterfacePrx& robotUnitPrx);
+
+
+    private:
+        // RobotUnitInterfacePrx robotUnit;
+    };
+
+} // namespace armarx::armem::server::robot_state::exteroception
diff --git a/source/RobotAPI/libraries/armem_robot_state/server/exteroception/converters/ArmarDEConverter.cpp b/source/RobotAPI/libraries/armem_robot_state/server/exteroception/converters/ArmarDEConverter.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d71bb045b32028df15bb37150892175e1ec8ec72
--- /dev/null
+++ b/source/RobotAPI/libraries/armem_robot_state/server/exteroception/converters/ArmarDEConverter.cpp
@@ -0,0 +1,130 @@
+#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/armem_robot_state/aron/Exteroception.aron.generated.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::exteroception
+{
+
+    ArmarDEConverter::ArmarDEConverter() = default;
+    ArmarDEConverter::~ArmarDEConverter() = default;
+
+
+    aron::data::DictPtr
+    ArmarDEConverter::convert(
+        const RobotUnitDataStreaming::TimeStep& data,
+        const RobotUnitDataStreaming::DataStreamingDescription& description)
+    {
+        arondto::Exteroception 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::Exteroception& 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 (simox::alg::contains(field, "tofDepth"))
+        {
+            // ARMARX_DEBUG << "Processing ToF sensor data";
+            processToFEntry(dto.tof, split, value);
+        }
+        
+    }
+
+
+
+
+    void ArmarDEConverter::processToFEntry(
+            std::map<std::string, armarx::armem::exteroception::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(armarx::armem::exteroception::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);
+    }
+
+
+}
diff --git a/source/RobotAPI/libraries/armem_robot_state/server/exteroception/converters/ArmarDEConverter.h b/source/RobotAPI/libraries/armem_robot_state/server/exteroception/converters/ArmarDEConverter.h
new file mode 100644
index 0000000000000000000000000000000000000000..bf6c482a06bfd4be24fca5ad78a320b5b6834042
--- /dev/null
+++ b/source/RobotAPI/libraries/armem_robot_state/server/exteroception/converters/ArmarDEConverter.h
@@ -0,0 +1,51 @@
+#pragma once
+
+#include <map>
+#include <string>
+
+#include <Eigen/Core>
+
+#include <RobotAPI/libraries/armem_robot_state/aron/Exteroception.aron.generated.h>
+
+#include "ConverterInterface.h"
+
+
+namespace armarx::armem::server::robot_state::exteroception
+{
+    struct ConverterValue;
+    // class ConverterTools;
+
+
+    class ArmarDEConverter : public ConverterInterface
+    {
+    public:
+        ArmarDEConverter();
+        ~ArmarDEConverter() override;
+
+
+        aron::data::DictPtr
+        convert(const RobotUnitDataStreaming::TimeStep& data,
+                const RobotUnitDataStreaming::DataStreamingDescription& description) override;
+
+
+    protected:
+        void process(arondto::Exteroception& dtoExteroception,
+                     const std::string& entryName,
+                     const ConverterValue& value);
+
+
+    private:
+        
+
+        void processToFEntry(std::map<std::string, armarx::armem::exteroception::arondto::ToF>& fts,
+                             const std::vector<std::string>& split,
+                             const ConverterValue& value);
+
+        void processToFEntry(armarx::armem::exteroception::arondto::ToF& tof,
+                             const std::vector<std::string>& split,
+                             const ConverterValue& value);
+
+
+        // std::unique_ptr<ConverterTools> tools;
+    };
+} // namespace armarx::armem::server::robot_state::exteroception
diff --git a/source/RobotAPI/libraries/armem_robot_state/server/exteroception/converters/ConverterInterface.cpp b/source/RobotAPI/libraries/armem_robot_state/server/exteroception/converters/ConverterInterface.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..4ba33e6c5f308cd6213c8ccf02018ad63ba9440b
--- /dev/null
+++ b/source/RobotAPI/libraries/armem_robot_state/server/exteroception/converters/ConverterInterface.cpp
@@ -0,0 +1,11 @@
+#include "ConverterInterface.h"
+
+
+namespace armarx::armem::server::robot_state::exteroception
+{
+
+    ConverterInterface::~ConverterInterface()
+    {
+    }
+
+}
diff --git a/source/RobotAPI/libraries/armem_robot_state/server/exteroception/converters/ConverterInterface.h b/source/RobotAPI/libraries/armem_robot_state/server/exteroception/converters/ConverterInterface.h
new file mode 100644
index 0000000000000000000000000000000000000000..5ba0ecc3c8aeaf5c2b3f3c03d9f36ed83269fb5e
--- /dev/null
+++ b/source/RobotAPI/libraries/armem_robot_state/server/exteroception/converters/ConverterInterface.h
@@ -0,0 +1,32 @@
+#pragma once
+
+#include <memory>
+
+#include <RobotAPI/libraries/aron/core/data/variant/container/Dict.h>
+
+namespace armarx::RobotUnitDataStreaming
+{
+    struct TimeStep;
+    struct DataStreamingDescription;
+    struct DataEntry;
+}
+namespace armarx::armem::arondto
+{
+    class Proprioception;
+}
+
+namespace armarx::armem::server::robot_state::exteroception
+{
+    class ConverterInterface
+    {
+    public:
+
+        virtual ~ConverterInterface();
+
+        virtual
+        aron::data::DictPtr convert(
+            const RobotUnitDataStreaming::TimeStep& data,
+            const RobotUnitDataStreaming::DataStreamingDescription& description) = 0;
+
+    };
+}
diff --git a/source/RobotAPI/libraries/armem_robot_state/server/exteroception/converters/ConverterRegistry.cpp b/source/RobotAPI/libraries/armem_robot_state/server/exteroception/converters/ConverterRegistry.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ef7296b669504e0f8d0aff8b4cd3991fe6ec10b3
--- /dev/null
+++ b/source/RobotAPI/libraries/armem_robot_state/server/exteroception/converters/ConverterRegistry.cpp
@@ -0,0 +1,31 @@
+#include "ConverterRegistry.h"
+
+#include "ArmarDEConverter.h"
+
+#include <SimoxUtility/algorithm/get_map_keys_values.h>
+
+
+namespace armarx::armem::server::robot_state::exteroception
+{
+
+    ConverterRegistry::ConverterRegistry()
+    {
+        add<ArmarDEConverter>("ArmarDE");
+        // add<Armar7Converter>("Armar7");
+    }
+
+
+    ConverterInterface*
+    ConverterRegistry::get(const std::string& key) const
+    {
+        auto it = converters.find(key);
+        return it != converters.end() ? it->second.get() : nullptr;
+    }
+
+
+    std::vector<std::string> ConverterRegistry::getKeys() const
+    {
+        return simox::alg::get_keys(converters);
+    }
+
+}
diff --git a/source/RobotAPI/libraries/armem_robot_state/server/exteroception/converters/ConverterRegistry.h b/source/RobotAPI/libraries/armem_robot_state/server/exteroception/converters/ConverterRegistry.h
new file mode 100644
index 0000000000000000000000000000000000000000..1e1cac9a18eb3d901b0ca0f61eccf08395a279b5
--- /dev/null
+++ b/source/RobotAPI/libraries/armem_robot_state/server/exteroception/converters/ConverterRegistry.h
@@ -0,0 +1,36 @@
+#pragma once
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "ConverterInterface.h"
+
+
+namespace armarx::armem::server::robot_state::exteroception
+{
+    class ConverterRegistry
+    {
+    public:
+
+        ConverterRegistry();
+
+
+        template <class ConverterT, class ...Args>
+        void add(const std::string& key, Args... args)
+        {
+            converters[key].reset(new ConverterT(args...));
+        }
+
+
+        ConverterInterface* get(const std::string& key) const;
+        std::vector<std::string> getKeys() const;
+
+
+    private:
+
+        std::map<std::string, std::unique_ptr<ConverterInterface>> converters;
+
+    };
+}
diff --git a/source/RobotAPI/libraries/armem_robot_state/server/exteroception/converters/ConverterTools.cpp b/source/RobotAPI/libraries/armem_robot_state/server/exteroception/converters/ConverterTools.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6086a9aee5f2adb8d997a65302084e0c902d747c
--- /dev/null
+++ b/source/RobotAPI/libraries/armem_robot_state/server/exteroception/converters/ConverterTools.cpp
@@ -0,0 +1,179 @@
+#include "ConverterTools.h"
+
+#include <SimoxUtility/algorithm/get_map_keys_values.h>
+#include <SimoxUtility/algorithm/advanced.h>
+
+#include <RobotAPI/libraries/RobotUnitDataStreamingReceiver/RobotUnitDataStreamingReceiver.h>
+#include <RobotAPI/libraries/aron/core/data/variant/container/Dict.h>
+
+
+namespace armarx::armem::server::robot_state
+{
+
+    std::optional<std::string>
+    exteroception::findByPrefix(const std::string& key, const std::set<std::string>& prefixes)
+    {
+        for (const auto& prefix : prefixes)
+        {
+            if (simox::alg::starts_with(key, prefix))
+            {
+                return prefix;
+            }
+        }
+        return std::nullopt;
+    }
+}
+
+
+namespace armarx::armem::server::robot_state::exteroception
+{
+    ConverterTools::ConverterTools()
+    {
+        {
+            vector3fSetters["X"] = [](Eigen::Vector3f & v, float f)
+            {
+                v.x() = f;
+            };
+            vector3fSetters["Y"] = [](Eigen::Vector3f & v, float f)
+            {
+                v.y() = f;
+            };
+            vector3fSetters["Z"] = [](Eigen::Vector3f & v, float f)
+            {
+                v.z() = f;
+            };
+            vector3fSetters["x"] = vector3fSetters["X"];
+            vector3fSetters["y"] = vector3fSetters["Y"];
+            vector3fSetters["z"] = vector3fSetters["Z"];
+            vector3fSetters["Rotation"] = vector3fSetters["Z"];
+        }
+        {
+            platformPoseGetters["acceleration"] = [](prop::arondto::Platform & p)
+            {
+                return &p.acceleration;
+            };
+            platformPoseGetters["relativePosition"] = [](prop::arondto::Platform & p)
+            {
+                return &p.relativePosition;
+            };
+            platformPoseGetters["velocity"] = [](prop::arondto::Platform & p)
+            {
+                return &p.velocity;
+            };
+            platformIgnored.insert("absolutePosition");
+        }
+        {
+            ftGetters["gravCompF"] = [](prop::arondto::ForceTorque & ft)
+            {
+                return &ft.gravityCompensationForce;
+            };
+            ftGetters["gravCompT"] = [](prop::arondto::ForceTorque & ft)
+            {
+                return &ft.gravityCompensationTorque;
+            };
+            ftGetters["f"] = [](prop::arondto::ForceTorque & ft)
+            {
+                return &ft.force;
+            };
+            ftGetters["t"] = [](prop::arondto::ForceTorque & ft)
+            {
+                return &ft.torque;
+            };
+        }
+        {
+            jointGetters["acceleration"] = [](prop::arondto::Joints & j)
+            {
+                return &j.acceleration;
+            };
+            jointGetters["gravityTorque"] = [](prop::arondto::Joints & j)
+            {
+                return &j.gravityTorque;
+            };
+            jointGetters["inertiaTorque"] = [](prop::arondto::Joints & j)
+            {
+                return &j.inertiaTorque;
+            };
+            jointGetters["inverseDynamicsTorque"] = [](prop::arondto::Joints & j)
+            {
+                return &j.inverseDynamicsTorque;
+            };
+            jointGetters["position"] = [](prop::arondto::Joints & j)
+            {
+                return &j.position;
+            };
+            jointGetters["torque"] = [](prop::arondto::Joints & j)
+            {
+                return &j.torque;
+            };
+            jointGetters["velocity"] = [](prop::arondto::Joints & j)
+            {
+                return &j.velocity;
+            };
+        }
+        {
+
+#define ADD_SCALAR_SETTER(container, name, type) \
+    container [ #name ] = []( \
+                              prop::arondto::Joints & dto, \
+                              const std::vector<std::string>& split, \
+                              const ConverterValue & value) \
+    { \
+        dto. name [split.at(1)] = getValueAs< type >(value); \
+    }
+
+            ADD_SCALAR_SETTER(jointSetters, position, float);
+            ADD_SCALAR_SETTER(jointSetters, velocity, float);
+            ADD_SCALAR_SETTER(jointSetters, acceleration, float);
+
+            ADD_SCALAR_SETTER(jointSetters, relativePosition, float);
+            ADD_SCALAR_SETTER(jointSetters, filteredVelocity, float);
+
+            ADD_SCALAR_SETTER(jointSetters, currentTarget, float);
+            ADD_SCALAR_SETTER(jointSetters, positionTarget, float);
+            ADD_SCALAR_SETTER(jointSetters, velocityTarget, float);
+
+            ADD_SCALAR_SETTER(jointSetters, torque, float);
+            ADD_SCALAR_SETTER(jointSetters, inertiaTorque, float);
+            ADD_SCALAR_SETTER(jointSetters, gravityTorque, float);
+            ADD_SCALAR_SETTER(jointSetters, gravityCompensatedTorque, float);
+            ADD_SCALAR_SETTER(jointSetters, inverseDynamicsTorque, float);
+            ADD_SCALAR_SETTER(jointSetters, torqueTicks, int);
+
+            ADD_SCALAR_SETTER(jointSetters, positionTarget, float);
+            ADD_SCALAR_SETTER(jointSetters, currentTarget, float);
+            ADD_SCALAR_SETTER(jointSetters, positionTarget, float);
+
+            // "temperature" handled below
+            // ADD_SCALAR_SETTER(jointSetters, temperature, float);
+
+            ADD_SCALAR_SETTER(jointSetters, motorCurrent, float);
+            ADD_SCALAR_SETTER(jointSetters, maxTargetCurrent, float);
+
+            ADD_SCALAR_SETTER(jointSetters, sensorBoardUpdateRate, float);
+            ADD_SCALAR_SETTER(jointSetters, I2CUpdateRate, float);
+
+            ADD_SCALAR_SETTER(jointSetters, JointStatusEmergencyStop, bool);
+            ADD_SCALAR_SETTER(jointSetters, JointStatusEnabled, bool);
+            ADD_SCALAR_SETTER(jointSetters, JointStatusError, int);
+            ADD_SCALAR_SETTER(jointSetters, JointStatusOperation, int);
+
+
+#define ADD_VECTOR3_SETTER(container, name, type) \
+    container [ #name ] = [this]( \
+                                  prop::arondto::Joints & dto, \
+                                  const std::vector<std::string>& split, \
+                                  const ConverterValue & value) \
+    { \
+        auto& vec = dto. name [split.at(1)]; \
+        auto& setter = this->vector3fSetters.at(split.at(3)); \
+        setter(vec, getValueAs< type >(value)); \
+    }
+
+            ADD_VECTOR3_SETTER(jointSetters, angularVelocity, float);
+            ADD_VECTOR3_SETTER(jointSetters, linearAcceleration, float);
+
+            // ADD_GETTER(jointVectorGetters, orientation, float);
+        }
+    }
+
+}
diff --git a/source/RobotAPI/libraries/armem_robot_state/server/exteroception/converters/ConverterTools.h b/source/RobotAPI/libraries/armem_robot_state/server/exteroception/converters/ConverterTools.h
new file mode 100644
index 0000000000000000000000000000000000000000..7460ebb133a01387c0f29a472961366877254506
--- /dev/null
+++ b/source/RobotAPI/libraries/armem_robot_state/server/exteroception/converters/ConverterTools.h
@@ -0,0 +1,106 @@
+#pragma once
+
+#include <map>
+#include <set>
+#include <string>
+
+#include <Eigen/Core>
+
+#include <SimoxUtility/algorithm/string/string_tools.h>
+
+#include <RobotAPI/libraries/armem_robot_state/aron/Proprioception.aron.generated.h>
+#include <RobotAPI/libraries/RobotUnitDataStreamingReceiver/RobotUnitDataStreamingReceiver.h>
+
+#include "ConverterInterface.h"
+
+
+namespace armarx::armem::server::robot_state::exteroception
+{
+
+    struct ConverterValue
+    {
+        const RobotUnitDataStreaming::TimeStep& data;
+        const RobotUnitDataStreaming::DataEntry& entry;
+    };
+
+
+    template <class T>
+    T
+    getValueAs(const ConverterValue& value)
+    {
+        return RobotUnitDataStreamingReceiver::GetAs<T>(value.data, value.entry);
+    }
+
+
+    /**
+     * @brief Search
+     * @param key
+     * @param prefixes
+     * @return
+     */
+    std::optional<std::string>
+    findByPrefix(const std::string& key, const std::set<std::string>& prefixes);
+
+
+    template <class ValueT>
+    ValueT
+    findByPrefix(const std::string& key, const std::map<std::string, ValueT>& map)
+    {
+        for (const auto& [prefix, value] : map)
+        {
+            if (simox::alg::starts_with(key, prefix))
+            {
+                return value;
+            }
+        }
+        return nullptr;
+    }
+
+
+    template <class ValueT>
+    ValueT
+    findBySuffix(const std::string& key, const std::map<std::string, ValueT>& map)
+    {
+        for (const auto& [suffix, value] : map)
+        {
+            if (simox::alg::ends_with(key, suffix))
+            {
+                return value;
+            }
+        }
+        return nullptr;
+    }
+
+
+
+    class ConverterTools
+    {
+    public:
+
+        ConverterTools();
+
+
+    public:
+
+        std::map<std::string, std::function<void(Eigen::Vector3f&, float)> > vector3fSetters;
+
+        std::map<std::string, std::function<std::map<std::string, float>*(prop::arondto::Joints&)> > jointGetters;
+        std::map<std::string, std::function<std::map<std::string, Eigen::Vector3f>*(prop::arondto::Joints&)> > jointVectorGetters;
+
+        using JointSetter = std::function<void(prop::arondto::Joints& dto, const std::vector<std::string>& split, const ConverterValue& value)>;
+        std::map<std::string, JointSetter> jointSetters;
+
+        std::map<std::string, std::function<Eigen::Vector3f*(prop::arondto::Platform&)> > platformPoseGetters;
+        std::set<std::string> platformIgnored;
+
+        std::map<std::string, std::function<Eigen::Vector3f*(prop::arondto::ForceTorque&)> > ftGetters;
+
+
+        std::map<std::string, std::string> sidePrefixMap
+        {
+            { "R", "Right" },
+            { "L", "Left" },
+        };
+
+    };
+}
diff --git a/source/RobotAPI/libraries/armem_robot_state/server/proprioception/RobotStateWriter.cpp b/source/RobotAPI/libraries/armem_robot_state/server/proprioception/RobotStateWriter.cpp
index 87df7cb013d99543485fdc8868aa83254bf52ffe..847ec98c82966408545a50bf9d7fa93fc7081d9f 100644
--- a/source/RobotAPI/libraries/armem_robot_state/server/proprioception/RobotStateWriter.cpp
+++ b/source/RobotAPI/libraries/armem_robot_state/server/proprioception/RobotStateWriter.cpp
@@ -29,142 +29,168 @@
 #include <SimoxUtility/math/convert/rpy_to_mat3f.h>
 
 // ArmarX
+#include "ArmarXCore/core/logging/Logging.h"
 #include "ArmarXCore/core/time/Metronome.h"
-#include <ArmarXCore/core/exceptions/local/ExpressionException.h>
-#include <ArmarXCore/core/time/CycleUtil.h>
 #include <ArmarXCore/libraries/ArmarXCoreComponentPlugins/DebugObserverComponentPlugin.h>
 
 #include "RobotAPI/libraries/armem_robot_state/client/common/constants.h"
-#include <RobotAPI/libraries/core/FramedPose.h>
-#include <RobotAPI/libraries/aron/core/data/variant/All.h>
-#include <RobotAPI/libraries/armem/core/Time.h>
-#include <RobotAPI/libraries/armem/core/ice_conversions.h>
 #include <RobotAPI/libraries/armem/server/MemoryToIceAdapter.h>
-#include <RobotAPI/libraries/armem_robot_state/aron/Transform.aron.generated.h>
 #include <RobotAPI/libraries/armem_robot_state/aron/Proprioception.aron.generated.h>
 #include <RobotAPI/libraries/armem_robot_state/server/localization/Segment.h>
+#include <RobotAPI/libraries/aron/core/data/variant/All.h>
+#include <RobotAPI/libraries/core/FramedPose.h>
 
 
 namespace armarx::armem::server::robot_state::proprioception
 {
 
-    void RobotStateWriter::connect(armarx::plugins::DebugObserverComponentPlugin& debugObserver)
+    void
+    RobotStateWriter::connect(armarx::plugins::DebugObserverComponentPlugin& debugObserverPlugin)
     {
         // Thread-local copy of debug observer helper.
         this->debugObserver =
-            DebugObserverHelper(Logging::tag.tagName, debugObserver.getDebugObserver(), true);
+            DebugObserverHelper(Logging::tag.tagName, debugObserverPlugin.getDebugObserver(), true);
     }
 
 
-    static float toDurationMs(
-        std::chrono::high_resolution_clock::time_point start,
-        std::chrono::high_resolution_clock::time_point end)
+    static float
+    toDurationMs(std::chrono::high_resolution_clock::time_point start,
+                 std::chrono::high_resolution_clock::time_point end)
     {
         auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
         return duration.count() / 1000.f;
     }
 
 
-    void RobotStateWriter::run(
-        float pollFrequency,
-        TripleBuffer<std::vector<RobotUnitData>>& dataBuffer,
-        MemoryToIceAdapter& memory,
-        localization::Segment& localizationSegment)
+    void
+    RobotStateWriter::run(float pollFrequency,
+                          Queue& dataBuffer,
+                          MemoryToIceAdapter& memory,
+                          localization::Segment& localizationSegment)
     {
-        Metronome metronome(Frequency::HertzDouble(pollFrequency));
-
         while (task and not task->isStopped())
         {
-            const std::vector<RobotUnitData>& batch = dataBuffer.getUpToDateReadBuffer();
 
-            if (debugObserver)
-            {
-                debugObserver->setDebugObserverDatafield("RobotStateWriter | Queue Size", batch.size());
-            }
+            // if (debugObserver)
+            // {
+            //     debugObserver->setDebugObserverDatafield("RobotStateWriter | Queue Size", dataBuffer.size());
+            // }
 
-            if (not batch.empty())
+            RobotUnitData robotUnitData;
+            if (const auto status = dataBuffer.wait_pull(robotUnitData);
+                status == boost::queue_op_status::success)
             {
                 auto start = std::chrono::high_resolution_clock::now();
                 auto endBuildUpdate = start, endProprioception = start, endLocalization = start;
 
-                Update update = buildUpdate(batch);
+                Update update = buildUpdate(robotUnitData);
                 endBuildUpdate = std::chrono::high_resolution_clock::now();
 
                 // Commits lock the core segments.
 
-                // Proprioception
-                armem::CommitResult result = memory.commitLocking(update.proprioception);
+                // Proprioception + Exteroception
+                armem::CommitResult resultProprioception = memory.commitLocking(update.proprioception);
+
+                ARMARX_DEBUG << deactivateSpam(1) << VAROUT(update.exteroception.updates.size());
+                armem::CommitResult resultExteroception = memory.commitLocking(update.exteroception);
                 endProprioception = std::chrono::high_resolution_clock::now();
 
                 // Localization
                 for (const armem::robot_state::Transform& transform : update.localization)
                 {
-                    localizationSegment.doLocked([&localizationSegment, &transform]()
-                    {
-                        localizationSegment.commitTransform(transform);
-                    });
+                    localizationSegment.doLocked(
+                        [&localizationSegment, &transform]()
+                        { localizationSegment.commitTransform(transform); });
                 }
                 endLocalization = std::chrono::high_resolution_clock::now();
 
-                if (not result.allSuccess())
+                if (not resultProprioception.allSuccess())
+                {
+                    ARMARX_WARNING << "Could not commit data to proprioception segment in memory. Error message: "
+                                   << resultProprioception.allErrorMessages();
+                }
+
+                if (not resultExteroception.allSuccess())
                 {
-                    ARMARX_WARNING << "Could not commit data to memory. Error message: " << result.allErrorMessages();
+                    ARMARX_WARNING << "Could not commit data to exteroception segment in memory. Error message: "
+                                   << resultExteroception.allErrorMessages();
                 }
+
                 if (debugObserver)
                 {
                     auto end = std::chrono::high_resolution_clock::now();
 
-                    debugObserver->setDebugObserverDatafield("RobotStateWriter | t Commit (ms)", toDurationMs(start, end));
-                    debugObserver->setDebugObserverDatafield("RobotStateWriter | t Commit 1. Build Update (ms)", toDurationMs(start, endBuildUpdate));
-                    debugObserver->setDebugObserverDatafield("RobotStateWriter | t Commit 2. Proprioception (ms)", toDurationMs(endBuildUpdate, endProprioception));
-                    debugObserver->setDebugObserverDatafield("RobotStateWriter | t Commit 3. Localization (ms)", toDurationMs(endProprioception, endLocalization));
+                    debugObserver->setDebugObserverDatafield("RobotStateWriter | t Commit (ms)",
+                                                             toDurationMs(start, end));
+                    debugObserver->setDebugObserverDatafield(
+                        "RobotStateWriter | t Commit 1. Build Update (ms)",
+                        toDurationMs(start, endBuildUpdate));
+                    debugObserver->setDebugObserverDatafield(
+                        "RobotStateWriter | t Commit 2. Proprioception (ms)",
+                        toDurationMs(endBuildUpdate, endProprioception));
+                    debugObserver->setDebugObserverDatafield(
+                        "RobotStateWriter | t Commit 3. Localization (ms)",
+                        toDurationMs(endProprioception, endLocalization));
                 }
             }
+            else
+            {
+                ARMARX_WARNING << "Queue pull was not successful. "
+                               << static_cast<std::underlying_type<boost::queue_op_status>::type>(
+                                      status);
+            }
 
             if (debugObserver)
             {
                 debugObserver->sendDebugObserverBatch();
             }
-            metronome.waitForNextTick();
         }
     }
 
 
-    RobotStateWriter::Update RobotStateWriter::buildUpdate(const std::vector<RobotUnitData>& dataQueue)
+    RobotStateWriter::Update
+    RobotStateWriter::buildUpdate(const RobotUnitData& data)
     {
-        ARMARX_CHECK_NOT_EMPTY(dataQueue);
-        ARMARX_DEBUG << "RobotStateWriter: Commit batch of " << dataQueue.size() << " timesteps to memory...";
-
         // Send batch to memory
         Update update;
 
-        for (const RobotUnitData& data: dataQueue)
-        {
-            {
-                armem::EntityUpdate& up = update.proprioception.add();
-                up.entityID = properties.robotUnitProviderID.withEntityName(properties.robotUnitProviderID.providerSegmentName);
-                up.timeCreated = data.timestamp;
-                up.instancesData = { data.proprioception };
-            }
+        if(data.proprioception){
+            armem::EntityUpdate& up = update.proprioception.add();
+            up.entityID = properties.robotUnitProviderID.withEntityName(
+                properties.robotUnitProviderID.providerSegmentName);
+            up.entityID.coreSegmentName =::armarx::armem::robot_state::constants::proprioceptionCoreSegment;
+            up.timeCreated = data.timestamp;
+            up.instancesData = {data.proprioception};
+        }
 
-            // Extract odometry data.
-            const std::string platformKey = "platform";
-            if (data.proprioception->hasElement(platformKey))
-            {
-                ARMARX_DEBUG << "Found odometry data.";
-                auto platformData = aron::data::Dict::DynamicCastAndCheck(data.proprioception->getElement(platformKey));
-                update.localization.emplace_back(getTransform(platformData, data.timestamp));
-            }
-            else
-            {
-                ARMARX_INFO << "No odometry data! "
-                            << "(No element '" << platformKey << "' in proprioception data.)"
-                            << "\nIf you are using a mobile platform this should not have happened."
-                            << "\nThis error is only logged once."
-                            << "\nThese keys exist: " << data.proprioception->getAllKeys()
-                            ;
-                noOdometryDataLogged = true;
-            }
+        // Exteroception
+        if(data.exteroception){
+            armem::EntityUpdate& up = update.exteroception.add();
+            up.entityID = properties.robotUnitProviderID.withEntityName(
+                properties.robotUnitProviderID.providerSegmentName);
+            up.entityID.coreSegmentName = ::armarx::armem::robot_state::constants::exteroceptionCoreSegment;
+            up.timeCreated = data.timestamp;
+            up.instancesData = {data.exteroception};
+        }
+
+        // Extract odometry data.
+        ARMARX_CHECK_NOT_NULL(data.proprioception);
+        const std::string platformKey = "platform";
+        if (data.proprioception->hasElement(platformKey))
+        {
+            ARMARX_DEBUG << "Found odometry data.";
+            auto platformData =
+                aron::data::Dict::DynamicCastAndCheck(data.proprioception->getElement(platformKey));
+            update.localization.emplace_back(getTransform(platformData, data.timestamp));
+        }
+        else
+        {
+            ARMARX_INFO << "No odometry data! "
+                        << "(No element '" << platformKey << "' in proprioception data.)"
+                        << "\nIf you are using a mobile platform this should not have happened."
+                        << "\nThis error is only logged once."
+                        << "\nThese keys exist: " << data.proprioception->getAllKeys();
+            noOdometryDataLogged = true;
         }
 
         return update;
@@ -172,9 +198,8 @@ namespace armarx::armem::server::robot_state::proprioception
 
 
     armem::robot_state::Transform
-    RobotStateWriter::getTransform(
-        const aron::data::DictPtr& platformData,
-        const Time& timestamp) const
+    RobotStateWriter::getTransform(const aron::data::DictPtr& platformData,
+                                   const Time& timestamp) const
     {
         prop::arondto::Platform platform;
         platform.fromAron(platformData);
@@ -182,7 +207,7 @@ namespace armarx::armem::server::robot_state::proprioception
         const Eigen::Vector3f& relPose = platform.relativePosition;
 
         Eigen::Affine3f odometryPose = Eigen::Affine3f::Identity();
-        odometryPose.translation() << relPose.x(), relPose.y(), 0;  // TODO set height
+        odometryPose.translation() << relPose.x(), relPose.y(), 0; // TODO set height
         odometryPose.linear() = simox::math::rpy_to_mat3f(0.f, 0.f, relPose.z());
 
         armem::robot_state::Transform transform;
@@ -195,4 +220,4 @@ namespace armarx::armem::server::robot_state::proprioception
         return transform;
     }
 
-}
+} // namespace armarx::armem::server::robot_state::proprioception
diff --git a/source/RobotAPI/libraries/armem_robot_state/server/proprioception/RobotStateWriter.h b/source/RobotAPI/libraries/armem_robot_state/server/proprioception/RobotStateWriter.h
index d70566ebf5c3aa6808d0e14af9c1af0471ac31c7..78863697a61ecd20c4947188a04965d5990c6f7b 100644
--- a/source/RobotAPI/libraries/armem_robot_state/server/proprioception/RobotStateWriter.h
+++ b/source/RobotAPI/libraries/armem_robot_state/server/proprioception/RobotStateWriter.h
@@ -55,11 +55,14 @@ namespace armarx::armem::server::robot_state::proprioception
     {
     public:
 
-        void connect(armarx::plugins::DebugObserverComponentPlugin& debugObserver);
+        void connect(armarx::plugins::DebugObserverComponentPlugin& debugObserverPlugin);
+
+        using Queue = armarx::armem::server::robot_state::proprioception::Queue;
+
 
         /// Reads data from `dataQueue` and commits to the memory.
         void run(float pollFrequency,
-                 TripleBuffer<std::vector<RobotUnitData>>& dataBuffer,
+                 Queue& dataBuffer,
                  MemoryToIceAdapter& memory,
                  localization::Segment& localizationSegment
                 );
@@ -68,9 +71,10 @@ namespace armarx::armem::server::robot_state::proprioception
         struct Update
         {
             armem::Commit proprioception;
+            armem::Commit exteroception;
             std::vector<armem::robot_state::Transform> localization;
         };
-        Update buildUpdate(const std::vector<RobotUnitData>& dataQueue);
+        Update buildUpdate(const RobotUnitData& dataQueue);
 
 
     private:
diff --git a/source/RobotAPI/libraries/armem_robot_state/server/proprioception/RobotUnitData.h b/source/RobotAPI/libraries/armem_robot_state/server/proprioception/RobotUnitData.h
index c0029b4fbccece40156be49f05ca1efa4215850c..8d904f249029cf9fd5ce010657cb4324f3ba5551 100644
--- a/source/RobotAPI/libraries/armem_robot_state/server/proprioception/RobotUnitData.h
+++ b/source/RobotAPI/libraries/armem_robot_state/server/proprioception/RobotUnitData.h
@@ -2,8 +2,10 @@
 
 #include <memory>
 
-#include <RobotAPI/libraries/aron/core/data/variant/container/Dict.h>
+#include <boost/thread/concurrent_queues/sync_queue.hpp>
+
 #include <RobotAPI/libraries/armem/core/Time.h>
+#include <RobotAPI/libraries/aron/core/data/variant/container/Dict.h>
 
 namespace armarx::armem::server::robot_state::proprioception
 {
@@ -12,6 +14,8 @@ namespace armarx::armem::server::robot_state::proprioception
     {
         Time timestamp;
         aron::data::DictPtr proprioception;
+        aron::data::DictPtr exteroception;
     };
-}
 
+    using Queue = boost::sync_queue<RobotUnitData>;
+} // namespace armarx::armem::server::robot_state::proprioception
diff --git a/source/RobotAPI/libraries/armem_robot_state/server/proprioception/RobotUnitReader.cpp b/source/RobotAPI/libraries/armem_robot_state/server/proprioception/RobotUnitReader.cpp
index 5794287c7231e07f9ffa0db967090f6d415c8f29..53021dc7d88f9362a967f395b1381d07934f271e 100644
--- a/source/RobotAPI/libraries/armem_robot_state/server/proprioception/RobotUnitReader.cpp
+++ b/source/RobotAPI/libraries/armem_robot_state/server/proprioception/RobotUnitReader.cpp
@@ -1,27 +1,15 @@
 #include "RobotUnitReader.h"
 
-#include <RobotAPI/libraries/armem_robot_state/server/proprioception/converters/Armar6Converter.h>
-#include <RobotAPI/libraries/armem_robot_state/server/proprioception/aron_conversions.h>
-#include <RobotAPI/libraries/armem_robot_state/aron/Proprioception.aron.generated.h>
-
-#include <RobotAPI/libraries/aron/core/data/variant/container/Dict.h>
-#include <RobotAPI/libraries/aron/core/data/variant/primitive/Long.h>
-#include <RobotAPI/libraries/aron/core/data/variant/primitive/String.h>
+#include <filesystem>
+#include <istream>
 
-#include <RobotAPI/libraries/RobotUnitDataStreamingReceiver/RobotUnitDataStreamingReceiver.h>
 
 #include "ArmarXCore/core/time/Frequency.h"
 #include "ArmarXCore/core/time/Metronome.h"
-#include "ArmarXCore/core/time/forward_declarations.h"
-#include "ArmarXCore/util/CPPUtility/TripleBuffer.h"
-#include <ArmarXCore/core/time/CycleUtil.h>
 #include <ArmarXCore/libraries/ArmarXCoreComponentPlugins/DebugObserverComponentPlugin.h>
 
-#include <SimoxUtility/algorithm/string/string_tools.h>
-
-#include <istream>
-#include <filesystem>
-#include <fstream>
+#include <RobotAPI/libraries/RobotUnitDataStreamingReceiver/RobotUnitDataStreamingReceiver.h>
+#include <RobotAPI/libraries/aron/core/data/variant/container/Dict.h>
 
 
 namespace armarx::armem::server::robot_state::proprioception
@@ -30,32 +18,39 @@ namespace armarx::armem::server::robot_state::proprioception
     RobotUnitReader::RobotUnitReader() = default;
 
 
-    void RobotUnitReader::connect(
-        armarx::plugins::RobotUnitComponentPlugin& robotUnitPlugin,
-        armarx::plugins::DebugObserverComponentPlugin& debugObserverPlugin,
-        const std::string& robotTypeName)
+    void
+    RobotUnitReader::connect(armarx::plugins::RobotUnitComponentPlugin& robotUnitPlugin,
+                             armarx::plugins::DebugObserverComponentPlugin& debugObserverPlugin,
+                             const std::string& robotTypeName)
     {
         {
-            converter = converterRegistry.get(robotTypeName);
-            ARMARX_CHECK_NOT_NULL(converter)
-                    << "No converter for robot type '" << robotTypeName << "' available. \n"
-                    << "Known are: " << converterRegistry.getKeys();
+            converterProprioception = proprioceptionConverterRegistry.get(robotTypeName);
+            ARMARX_CHECK_NOT_NULL(converterProprioception)
+                << "No converter for robot type '" << robotTypeName << "' available. \n"
+                << "Known are: " << proprioceptionConverterRegistry.getKeys();
 
             config.loggingNames.push_back(properties.sensorPrefix);
             receiver = robotUnitPlugin.startDataStreaming(config);
             description = receiver->getDataDescription();
         }
+
+        {
+            converterExteroception = exteroceptionConverterRegistry.get(robotTypeName);
+            ARMARX_CHECK_NOT_NULL(converterProprioception)
+                << "No converter for robot type '" << robotTypeName << "' available. \n"
+                << "Known are: " << exteroceptionConverterRegistry.getKeys();
+        }
+
         {
             // Thread-local copy of debug observer helper.
-            debugObserver =
-                DebugObserverHelper(Logging::tag.tagName, debugObserverPlugin.getDebugObserver(), true);
+            debugObserver = DebugObserverHelper(
+                Logging::tag.tagName, debugObserverPlugin.getDebugObserver(), true);
         }
     }
 
 
-    void RobotUnitReader::run(
-        float pollFrequency,
-        TripleBuffer<std::vector<RobotUnitData>>& dataBuffer)
+    void
+    RobotUnitReader::run(float pollFrequency, Queue& dataBuffer)
     {
         Metronome metronome(Frequency::HertzDouble(pollFrequency));
 
@@ -63,8 +58,8 @@ namespace armarx::armem::server::robot_state::proprioception
         {
             if (std::optional<RobotUnitData> commit = fetchAndConvertLatestRobotUnitData())
             {
-                dataBuffer.getWriteBuffer().push_back(std::move(commit.value()));
-                dataBuffer.commitWrite();
+                // will lock a mutex
+                dataBuffer.push(std::move(commit.value()));
             }
 
             if (debugObserver)
@@ -77,9 +72,10 @@ namespace armarx::armem::server::robot_state::proprioception
     }
 
 
-    std::optional<RobotUnitData> RobotUnitReader::fetchAndConvertLatestRobotUnitData()
+    std::optional<RobotUnitData>
+    RobotUnitReader::fetchAndConvertLatestRobotUnitData()
     {
-        ARMARX_CHECK_NOT_NULL(converter);
+        ARMARX_CHECK_NOT_NULL(converterProprioception);
 
         const std::optional<RobotUnitDataStreaming::TimeStep> data = fetchLatestData();
         if (not data.has_value())
@@ -91,23 +87,36 @@ namespace armarx::armem::server::robot_state::proprioception
         auto start = std::chrono::high_resolution_clock::now();
 
         RobotUnitData result;
-        result.proprioception = converter->convert(data.value(), description);
+
+        if(converterProprioception != nullptr)
+        {
+            result.proprioception = converterProprioception->convert(data.value(), description);
+        }
+
+        if(converterExteroception != nullptr)
+        {
+            result.exteroception = converterExteroception->convert(data.value(), description);
+        }
+        
         result.timestamp = Time(Duration::MicroSeconds(data->timestampUSec));
 
         auto stop = std::chrono::high_resolution_clock::now();
         auto duration = std::chrono::duration_cast<std::chrono::microseconds>(stop - start);
-        ARMARX_DEBUG << "RobotUnitReader: The total time needed to convert the data to commit: " << duration;
+        ARMARX_DEBUG << "RobotUnitReader: The total time needed to convert the data to commit: "
+                     << duration;
 
         if (debugObserver)
         {
-            debugObserver->setDebugObserverDatafield("RobotUnitReader | t Read+Group [ms]", duration.count() / 1000.f);
+            debugObserver->setDebugObserverDatafield("RobotUnitReader | t Read+Group [ms]",
+                                                     duration.count() / 1000.f);
         }
 
         return result;
     }
 
 
-    std::optional<RobotUnitDataStreaming::TimeStep> RobotUnitReader::fetchLatestData()
+    std::optional<RobotUnitDataStreaming::TimeStep>
+    RobotUnitReader::fetchLatestData()
     {
         std::deque<RobotUnitDataStreaming::TimeStep>& data = receiver->getDataBuffer();
         if (debugObserver)
@@ -127,4 +136,4 @@ namespace armarx::armem::server::robot_state::proprioception
     }
 
 
-}
+} // namespace armarx::armem::server::robot_state::proprioception
diff --git a/source/RobotAPI/libraries/armem_robot_state/server/proprioception/RobotUnitReader.h b/source/RobotAPI/libraries/armem_robot_state/server/proprioception/RobotUnitReader.h
index 5abf7378378828005795d10401a2ee7cc1ea5aa4..88313402f217eb8f46470aafd796465354f6cc68 100644
--- a/source/RobotAPI/libraries/armem_robot_state/server/proprioception/RobotUnitReader.h
+++ b/source/RobotAPI/libraries/armem_robot_state/server/proprioception/RobotUnitReader.h
@@ -1,12 +1,11 @@
 #pragma once
 
-#include <queue>
 #include <map>
 #include <memory>
 #include <optional>
+#include <queue>
 #include <string>
 
-#include "ArmarXCore/util/CPPUtility/TripleBuffer.h"
 #include <ArmarXCore/core/logging/Logging.h>
 #include <ArmarXCore/core/services/tasks/TaskUtil.h>
 #include <ArmarXCore/libraries/DebugObserverHelper/DebugObserverHelper.h>
@@ -15,51 +14,51 @@
 #include <RobotAPI/libraries/RobotAPIComponentPlugins/RobotUnitComponentPlugin.h>
 
 #include "RobotUnitData.h"
-#include "converters/ConverterRegistry.h"
 #include "converters/ConverterInterface.h"
+#include "../exteroception/converters/ConverterInterface.h"
+#include "converters/ConverterRegistry.h"
+#include "../exteroception/converters/ConverterRegistry.h"
 
 
 namespace armarx::plugins
 {
     class RobotUnitComponentPlugin;
     class DebugObserverComponentPlugin;
-}
+} // namespace armarx::plugins
 namespace armarx
 {
     using RobotUnitDataStreamingReceiverPtr = std::shared_ptr<class RobotUnitDataStreamingReceiver>;
 }
 
+
+// TODO move this out of proprioception. it is now for proprioception and exteroception
 namespace armarx::armem::server::robot_state::proprioception
 {
     class RobotUnitReader : public armarx::Logging
     {
     public:
-
         RobotUnitReader();
 
+        using Queue = armarx::armem::server::robot_state::proprioception::Queue;
 
-        void connect(
-            armarx::plugins::RobotUnitComponentPlugin& robotUnitPlugin,
-            armarx::plugins::DebugObserverComponentPlugin& debugObserverPlugin,
-            const std::string& robotTypeName);
 
+        void connect(armarx::plugins::RobotUnitComponentPlugin& robotUnitPlugin,
+                     armarx::plugins::DebugObserverComponentPlugin& debugObserverPlugin,
+                     const std::string& robotTypeName);
 
 
         /// Reads data from `handler` and fills `dataQueue`.
-        void run(float pollFrequency,
-                 TripleBuffer<std::vector<RobotUnitData>>& dataBuffer);
+        void run(float pollFrequency, Queue& dataBuffer);
 
         std::optional<RobotUnitData> fetchAndConvertLatestRobotUnitData();
 
 
     private:
-
         /// Fetch the latest timestep and clear the robot unit buffer.
         std::optional<RobotUnitDataStreaming::TimeStep> fetchLatestData();
 
 
     public:
-
         struct Properties
         {
             std::string sensorPrefix = "sens.*";
@@ -73,11 +72,12 @@ namespace armarx::armem::server::robot_state::proprioception
         RobotUnitDataStreamingReceiverPtr receiver;
         RobotUnitDataStreaming::DataStreamingDescription description;
 
-        ConverterRegistry converterRegistry;
-        ConverterInterface* converter = nullptr;
+        ConverterRegistry proprioceptionConverterRegistry;
+        exteroception::ConverterRegistry exteroceptionConverterRegistry;
+        proprioception::ConverterInterface* converterProprioception = nullptr;
+        exteroception::ConverterInterface* converterExteroception = nullptr;
 
         armarx::SimpleRunningTask<>::pointer_type task = nullptr;
-
     };
 
-}
+} // namespace armarx::armem::server::robot_state::proprioception
diff --git a/source/RobotAPI/libraries/aron/CMakeLists.txt b/source/RobotAPI/libraries/aron/CMakeLists.txt
index ce4f7bc99cb8d923decfdd7fdb79390837e79150..e1ccc8560ff75b018fbc958d0f1febf0512d9590 100644
--- a/source/RobotAPI/libraries/aron/CMakeLists.txt
+++ b/source/RobotAPI/libraries/aron/CMakeLists.txt
@@ -2,3 +2,4 @@ add_subdirectory(core)
 add_subdirectory(converter)
 add_subdirectory(codegeneration)
 add_subdirectory(common)
+add_subdirectory(test)
diff --git a/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/Generator.cpp b/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/Generator.cpp
index 0c9fab0b1fe8e71ae2c9ad3b8fcf2fb32ec03ddc..be87200f51f745b314ef7f3f7c2a67beb18d332a 100644
--- a/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/Generator.cpp
+++ b/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/Generator.cpp
@@ -208,10 +208,13 @@ namespace armarx::aron::codegenerator::cpp
         {
             CppMethodPtr m = CppMethodPtr(new CppMethod("virtual ~" + name + "()"));
             m->setBlock(b);
+
+            m->setEnforceBlockGeneration(true);
             return m;
         }
 
         CppMethodPtr m = CppMethodPtr(new CppMethod("virtual ~" + name + "() = default;"));
+        m->setEnforceBlockGeneration(false);
         return m;
     }
 
@@ -224,6 +227,8 @@ namespace armarx::aron::codegenerator::cpp
         CppMethodPtr m = CppMethodPtr(new CppMethod("virtual void resetSoft() override", doc.str()));
         CppBlockPtr b = this->getResetSoftBlock("");
         m->setBlock(b);
+
+        m->setEnforceBlockGeneration(true);
         return m;
     }
 
@@ -236,6 +241,8 @@ namespace armarx::aron::codegenerator::cpp
         CppMethodPtr m = CppMethodPtr(new CppMethod("virtual void resetHard() override", doc.str()));
         CppBlockPtr b = this->getResetHardBlock("");
         m->setBlock(b);
+
+        m->setEnforceBlockGeneration(true);
         return m;
     }
 
@@ -252,6 +259,8 @@ namespace armarx::aron::codegenerator::cpp
         std::string dummy;
         b->appendBlock(this->getWriteTypeBlock("", "", Path(), dummy));
         m->setBlock(b);
+
+        m->setEnforceBlockGeneration(true);
         return m;
     }
 
@@ -273,6 +282,7 @@ namespace armarx::aron::codegenerator::cpp
         b->addLineAsBlock("throw ::armarx::aron::error::AronException(__PRETTY_FUNCTION__, std::string(\"An error occured during the write method of an aron generated class. The full error log was:\\n\") + " + ARON_VARIABLE_PREFIX + "_e.what());");
 
         m->setBlock(b);
+        m->setEnforceBlockGeneration(true);
         return m;
     }
 
@@ -296,6 +306,8 @@ namespace armarx::aron::codegenerator::cpp
         b->addLine("catch(const std::exception& " + ARON_VARIABLE_PREFIX + "_e)");
         b->addLineAsBlock("throw ::armarx::aron::error::AronException(__PRETTY_FUNCTION__, std::string(\"An error occured during the read method of an aron generated class. The full error log was:\\n\") + " + ARON_VARIABLE_PREFIX + "_e.what());");
         m->setBlock(b);
+
+        m->setEnforceBlockGeneration(true);
         return m;
     }
 
@@ -308,6 +320,8 @@ namespace armarx::aron::codegenerator::cpp
         CppMethodPtr m = CppMethodPtr(new CppMethod(info.returnType + " " + info.methodName + "() const", doc.str()));
         m->addLine(info.writerClassType + " writer;");
         m->addLine("return " + info.enforceConversion + "(this->write(writer))" + info.enforceMemberAccess + ";");
+
+        m->setEnforceBlockGeneration(true);
         return m;
     }
 
@@ -320,6 +334,8 @@ namespace armarx::aron::codegenerator::cpp
         CppMethodPtr m = CppMethodPtr(new CppMethod("void " + info.methodName + "(const " + info.argumentType + "& input)", doc.str()));
         m->addLine(info.readerClassType + " reader;");
         m->addLine("this->read(reader, " + info.enforceConversion + "(input)" + info.enforceMemberAccess + ");");
+
+        m->setEnforceBlockGeneration(true);
         return m;
     }
 
@@ -333,6 +349,8 @@ namespace armarx::aron::codegenerator::cpp
         m->addLine(info.returnType + " t;");
         m->addLine("t.fromAron(input);");
         m->addLine("return t;");
+
+        m->setEnforceBlockGeneration(true);
         return m;
     }
 
@@ -345,6 +363,8 @@ namespace armarx::aron::codegenerator::cpp
         CppMethodPtr m = CppMethodPtr(new CppMethod("static " + info.returnType + " " + info.methodName + "()", doc.str()));
         m->addLine(info.writerClassType + " writer;");
         m->addLine("return " + info.enforceConversion + "(writeType(writer))" + info.enforceMemberAccess + ";");
+
+        m->setEnforceBlockGeneration(true);
         return m;
     }
 
@@ -359,6 +379,8 @@ namespace armarx::aron::codegenerator::cpp
         CppBlockPtr b = this->getEqualsBlock("", "i");
         b->addLine("return true;");
         m->setBlock(b);
+
+        m->setEnforceBlockGeneration(true);
         return m;
     }
 
@@ -588,5 +610,3 @@ namespace armarx::aron::codegenerator::cpp
         return block_if_data;
     }
 }
-
-
diff --git a/source/RobotAPI/libraries/aron/core/aron_conversions.h b/source/RobotAPI/libraries/aron/core/aron_conversions.h
index d0f88cab840be59b86bbeb22d7229afb9f9f0b48..d27d6415877d4c15f9ddf36310e656590f8efd7e 100644
--- a/source/RobotAPI/libraries/aron/core/aron_conversions.h
+++ b/source/RobotAPI/libraries/aron/core/aron_conversions.h
@@ -3,12 +3,29 @@
 #include <map>
 #include <memory>
 #include <optional>
+#include <type_traits>
 #include <vector>
 
 #include "Path.h"
 
 namespace armarx::aron
 {
+
+namespace detail
+{
+
+    // Helper concept to avoid ambiguities
+    template<typename DtoT, typename BoT>
+    concept DtoAndBoAreSame = std::is_same<DtoT, BoT>::value;
+
+    template <class ...>
+    struct is_optional : public std::false_type {};
+
+    template <class ...Ts>
+    struct is_optional<std::optional<Ts...>> : public std::true_type {};
+
+}
+
     /**
      * Framework for converting ARON DTOs (Data Transfer Objects) to C++ BOs
      * (Business Objects) and back.
@@ -51,12 +68,6 @@ namespace armarx::aron
      * }
      * @endcode
      */
-
-    // Helper concept to avoid ambiguities
-    template<typename DtoT, typename BoT>
-    concept DtoAndBoAreSame = std::is_same<DtoT, BoT>::value;
-
-
     // Same type
     template <class T>
     void toAron(T& dto, const T& bo)
@@ -139,6 +150,24 @@ namespace armarx::aron
         }
     }
 
+
+    // One-sided optional
+    template <class DtoT, class BoT>
+    requires (not detail::is_optional<BoT>::value)
+    void toAron(std::optional<DtoT>& dto, const BoT& bo)
+    {
+        dto = DtoT{};
+        toAron(*dto, bo);
+    }
+    template <class DtoT, class BoT>
+    requires (not detail::is_optional<DtoT>::value)
+    void fromAron(DtoT& dto, const std::optional<BoT>& bo)
+    {
+        bo = BoT{};
+        fromAron(dto, *bo);
+    }
+
+
     // Flag-controlled optional
     template <class DtoT, class BoT>
     void toAron(DtoT& dto, bool& dtoValid, const BoT& bo, bool boValid)
@@ -154,6 +183,7 @@ namespace armarx::aron
         }
     }
 
+
     template <class DtoT, class BoT>
     void fromAron(const DtoT& dto, bool dtoValid, BoT& bo, bool& boValid)
     {
@@ -222,7 +252,7 @@ namespace armarx::aron
 
     // std::map
     template <class DtoKeyT, class DtoValueT, class BoKeyT, class BoValueT>
-    requires (!(DtoAndBoAreSame<DtoKeyT, BoKeyT> and DtoAndBoAreSame<DtoValueT, BoValueT>))
+    requires (!(detail::DtoAndBoAreSame<DtoKeyT, BoKeyT> and detail::DtoAndBoAreSame<DtoValueT, BoValueT>))
     void toAron(std::map<DtoKeyT, DtoValueT>& dtoMap,
                 const std::map<BoKeyT, BoValueT>& boMap)
     {
@@ -236,7 +266,7 @@ namespace armarx::aron
         }
     }
     template <class DtoKeyT, class DtoValueT, class BoKeyT, class BoValueT>
-    requires (!(DtoAndBoAreSame<DtoKeyT, BoKeyT> and DtoAndBoAreSame<DtoValueT, BoValueT>))
+    requires (!(detail::DtoAndBoAreSame<DtoKeyT, BoKeyT> and detail::DtoAndBoAreSame<DtoValueT, BoValueT>))
     void fromAron(const std::map<DtoKeyT, DtoValueT>& dtoMap,
                   std::map<BoKeyT, BoValueT>& boMap)
     {
@@ -252,7 +282,7 @@ namespace armarx::aron
 
 
     template <class DtoKeyT, class DtoValueT, class BoKeyT, class BoValueT>
-    requires (!(DtoAndBoAreSame<DtoKeyT, BoKeyT> and DtoAndBoAreSame<DtoValueT, BoValueT>))
+    requires (!(detail::DtoAndBoAreSame<DtoKeyT, BoKeyT> and detail::DtoAndBoAreSame<DtoValueT, BoValueT>))
     std::map<DtoKeyT, DtoValueT> toAron(const std::map<BoKeyT, BoValueT>& boMap)
     {
         std::map<DtoKeyT, DtoValueT> dtoMap;
@@ -343,20 +373,20 @@ namespace armarx
 
     // std::vector
     template <class DtoT, class BoT>
-    requires (!aron::DtoAndBoAreSame<DtoT, BoT>)
+    requires (!aron::detail::DtoAndBoAreSame<DtoT, BoT>)
     void toAron(std::vector<DtoT>& dtos, const std::vector<BoT>& bos)
     {
         armarx::aron::toAron(dtos, bos);
     }
     template <class DtoT, class BoT>
-    requires (!aron::DtoAndBoAreSame<DtoT, BoT>)
+    requires (!aron::detail::DtoAndBoAreSame<DtoT, BoT>)
     void fromAron(const std::vector<DtoT>& dtos, std::vector<BoT>& bos)
     {
         armarx::aron::fromAron(dtos, bos);
     }
 
     template <class DtoT, class BoT>
-    requires (!aron::DtoAndBoAreSame<DtoT, BoT>)
+    requires (!aron::detail::DtoAndBoAreSame<DtoT, BoT>)
     std::vector<DtoT> toAron(const std::vector<BoT>& bos)
     {
         return armarx::aron::toAron<DtoT, BoT>(bos);
@@ -365,13 +395,13 @@ namespace armarx
 
     // std::map
     template <class DtoKeyT, class DtoValueT, class BoKeyT, class BoValueT>
-    requires (!(aron::DtoAndBoAreSame<DtoKeyT, BoKeyT> and aron::DtoAndBoAreSame<DtoValueT, BoValueT>))
+    requires (!(aron::detail::DtoAndBoAreSame<DtoKeyT, BoKeyT> and aron::detail::DtoAndBoAreSame<DtoValueT, BoValueT>))
     void toAron(std::map<DtoKeyT, DtoValueT>& dtoMap, const std::map<BoKeyT, BoValueT>& boMap)
     {
         armarx::aron::toAron(dtoMap, boMap);
     }
     template <class DtoKeyT, class DtoValueT, class BoKeyT, class BoValueT>
-    requires (!(aron::DtoAndBoAreSame<DtoKeyT, BoKeyT> and aron::DtoAndBoAreSame<DtoValueT, BoValueT>))
+    requires (!(aron::detail::DtoAndBoAreSame<DtoKeyT, BoKeyT> and aron::detail::DtoAndBoAreSame<DtoValueT, BoValueT>))
     void fromAron(const std::map<DtoKeyT, DtoValueT>& dtoMap, std::map<BoKeyT, BoValueT>& boMap)
     {
         armarx::aron::fromAron(dtoMap, boMap);
@@ -379,7 +409,7 @@ namespace armarx
 
 
     template <class DtoKeyT, class DtoValueT, class BoKeyT, class BoValueT>
-    requires (!(aron::DtoAndBoAreSame<DtoKeyT, BoKeyT> and aron::DtoAndBoAreSame<DtoValueT, BoValueT>))
+    requires (!(aron::detail::DtoAndBoAreSame<DtoKeyT, BoKeyT> and aron::detail::DtoAndBoAreSame<DtoValueT, BoValueT>))
     std::map<DtoKeyT, DtoValueT> toAron(const std::map<BoKeyT, BoValueT>& boMap)
     {
         armarx::aron::toAron<DtoKeyT, DtoValueT, BoKeyT, BoValueT>(boMap);
diff --git a/source/RobotAPI/libraries/aron/core/data/variant/complex/NDArray.cpp b/source/RobotAPI/libraries/aron/core/data/variant/complex/NDArray.cpp
index 111068b393c86b681179544c4d60fd02953f3f36..483088aa7ffaf706271072d5e13d55f26b8e4ec4 100644
--- a/source/RobotAPI/libraries/aron/core/data/variant/complex/NDArray.cpp
+++ b/source/RobotAPI/libraries/aron/core/data/variant/complex/NDArray.cpp
@@ -142,6 +142,7 @@ namespace armarx::aron::data
     {
         if (t.empty())
         {
+            ARMARX_TRACE;
             throw error::AronException(__PRETTY_FUNCTION__, "The type cannot be empty", getPath());
         }
 
@@ -166,6 +167,7 @@ namespace armarx::aron::data
 
     type::VariantPtr NDArray::recalculateType() const
     {
+        ARMARX_TRACE;
         throw error::NotImplementedYetException(__PRETTY_FUNCTION__);
     }
 
@@ -179,29 +181,35 @@ namespace armarx::aron::data
         case type::Descriptor::MATRIX:
         {
             auto casted = type::Matrix::DynamicCastAndCheck(type);
+            ARMARX_TRACE;
             return (aron->shape.size() == 3 &&  aron->shape[0] == casted->getRows() && aron->shape[1] == casted->getCols());
         }
         case type::Descriptor::QUATERNION:
         {
             auto casted = type::Quaternion::DynamicCastAndCheck(type);
+            ARMARX_TRACE;
             return (aron->shape.size() == 3 && aron->shape[0] == 1 && aron->shape[1] == 4);
         }
         case type::Descriptor::POINTCLOUD:
         {
             auto casted = type::PointCloud::DynamicCastAndCheck(type);
+            ARMARX_TRACE;
             return (aron->shape.size() == 3);
         }
         case type::Descriptor::IMAGE:
         {
             auto casted = type::Image::DynamicCastAndCheck(type);
+            ARMARX_TRACE;
             return (aron->shape.size() == 3);
         }
         case type::Descriptor::NDARRAY:
         {
             auto casted = type::NDArray::DynamicCastAndCheck(type);
+            ARMARX_TRACE;
             return (aron->shape.size() == (unsigned int) casted->getNumberDimensions());
         }
         default:
+            ARMARX_TRACE;
             return false;
         }
     }
diff --git a/source/RobotAPI/libraries/aron/core/data/variant/container/Dict.cpp b/source/RobotAPI/libraries/aron/core/data/variant/container/Dict.cpp
index 478c6a2c80a4984fcc4fb19ee9dba611eb384af9..9724ae6279a2b2a2140d5964d7d101f6e9fbabc8 100644
--- a/source/RobotAPI/libraries/aron/core/data/variant/container/Dict.cpp
+++ b/source/RobotAPI/libraries/aron/core/data/variant/container/Dict.cpp
@@ -25,10 +25,12 @@
 #include "Dict.h"
 
 // ArmarX
-#include <RobotAPI/libraries/aron/core/data/variant/Factory.h>
-
 #include <SimoxUtility/algorithm/string/string_conversion.h>
 
+#include <ArmarXCore/util/CPPUtility/trace.h>
+
+#include <RobotAPI/libraries/aron/core/data/variant/Factory.h>
+
 namespace armarx::aron::data
 {
 
@@ -135,6 +137,7 @@ namespace armarx::aron::data
     {
         if (hasElement(key))
         {
+            ARMARX_TRACE;
             throw error::AronException(__PRETTY_FUNCTION__, "The key '"+key+"' already exists in a aron dict.");
         }
         setElement(key, data);
@@ -150,6 +153,7 @@ namespace armarx::aron::data
         auto it = childrenNavigators.find(key);
         if (it == childrenNavigators.end())
         {
+            ARMARX_TRACE;
             throw error::AronException(__PRETTY_FUNCTION__, "Could not find key '" + key + "'. But I found the following keys: [" + simox::alg::join(this->getAllKeys(), ", ") + "]", getPath());
         }
         return it->second;
@@ -201,8 +205,10 @@ namespace armarx::aron::data
         return "armarx::aron::data::Dict";
     }
 
+    // TODO
     type::VariantPtr Dict::recalculateType() const
     {
+        ARMARX_TRACE;
         throw error::NotImplementedYetException(__PRETTY_FUNCTION__);
     }
 
@@ -216,42 +222,67 @@ namespace armarx::aron::data
         {
             case type::Descriptor::OBJECT:
             {
+                ARMARX_TRACE;
                 auto objectTypeNav = type::Object::DynamicCastAndCheck(type);
                 for (const auto& [key, nav] : childrenNavigators)
                 {
                     if (!objectTypeNav->hasMemberType(key))
                     {
+                        ARMARX_TRACE;
                         return false;
                     }
-                    if (!nav || !objectTypeNav->getMemberType(key))
+
+                    auto childTypeNav = objectTypeNav->getMemberType(key);
+                    if (!nav)
                     {
-                        return false;
+                        ARMARX_TRACE;
+                        if (childTypeNav && childTypeNav->getMaybe() == type::Maybe::NONE)
+                        {
+                            ARMARX_TRACE;
+                            return false;
+                        }
+                        ARMARX_TRACE;
+                        return true;
                     }
-                    if (!nav->fullfillsType(objectTypeNav->getMemberType(key)))
+                    if (!nav->fullfillsType(childTypeNav))
                     {
+                        ARMARX_TRACE;
                         return false;
                     }
                 }
+                ARMARX_TRACE;
                 return true;
             }
             case type::Descriptor::DICT:
             {
+                ARMARX_TRACE;
                 auto dictTypeNav = type::Dict::DynamicCastAndCheck(type);
                 for (const auto& [key, nav] : childrenNavigators)
                 {
                     (void) key;
-                    if (!nav || !dictTypeNav->getAcceptedType())
+                    auto childTypeNav = dictTypeNav->getAcceptedType();
+                    if (!nav)
                     {
-                        return false;
+                        ARMARX_TRACE;
+                        if (childTypeNav && childTypeNav->getMaybe() == type::Maybe::NONE)
+                        {
+                            ARMARX_TRACE;
+                            return false;
+                        }
+                        ARMARX_TRACE;
+                        return true;
                     }
-                    if (!nav->fullfillsType(dictTypeNav->getAcceptedType()))
+                    if (!nav->fullfillsType(childTypeNav))
                     {
+                        ARMARX_TRACE;
                         return false;
                     }
                 }
+                ARMARX_TRACE;
                 return true;
             }
             default:
+                ARMARX_TRACE;
                 return false;
         }
     }
@@ -275,11 +306,13 @@ namespace armarx::aron::data
     {
         if (!path.hasElement())
         {
+            ARMARX_TRACE;
             throw error::AronException(__PRETTY_FUNCTION__, "Could not navigate without a valid path", path);
         }
         std::string el = path.getFirstElement();
         if (!hasElement(el))
         {
+            ARMARX_TRACE;
             throw error::ValueNotValidException(__PRETTY_FUNCTION__, "Could not find an element of a path.", el, path);
         }
 
@@ -292,6 +325,7 @@ namespace armarx::aron::data
             Path next = path.withDetachedFirstElement();
             if (!childrenNavigators.at(el))
             {
+                ARMARX_TRACE;
                 throw error::AronException(__PRETTY_FUNCTION__, "Could not navigate into a NULL member. Seems like the member is optional and not set.", next);
             }
             return childrenNavigators.at(el)->navigateAbsolute(next);
diff --git a/source/RobotAPI/libraries/aron/core/data/variant/container/List.cpp b/source/RobotAPI/libraries/aron/core/data/variant/container/List.cpp
index 84bf1a2005b2d57f03065de58f65cf31870c8ea8..c53b51ee1b04c3e903b4ddd718b9793d75303412 100644
--- a/source/RobotAPI/libraries/aron/core/data/variant/container/List.cpp
+++ b/source/RobotAPI/libraries/aron/core/data/variant/container/List.cpp
@@ -26,10 +26,12 @@
 
 // ArmarX
 #include <ArmarXCore/core/exceptions/Exception.h>
+#include <ArmarXCore/util/CPPUtility/trace.h>
+
 #include <RobotAPI/libraries/aron/core/data/variant/Factory.h>
 #include <RobotAPI/libraries/aron/core/type/variant/container/List.h>
-#include <RobotAPI/libraries/aron/core/type/variant/container/Tuple.h>
 #include <RobotAPI/libraries/aron/core/type/variant/container/Pair.h>
+#include <RobotAPI/libraries/aron/core/type/variant/container/Tuple.h>
 
 namespace armarx::aron::data
 {
@@ -125,7 +127,8 @@ namespace armarx::aron::data
     {
         if (i > aron->elements.size())
         {
-            error::AronException(__PRETTY_FUNCTION__, "Cannot set a listelement at index " + std::to_string(i) + " because this list has size " + std::to_string(aron->elements.size()));
+            ARMARX_TRACE;
+            throw error::AronException(__PRETTY_FUNCTION__, "Cannot set a listelement at index " + std::to_string(i) + " because this list has size " + std::to_string(aron->elements.size()));
         }
 
         if (i == aron->elements.size())
@@ -163,6 +166,7 @@ namespace armarx::aron::data
     {
         if (i >= childrenNavigators.size())
         {
+            ARMARX_TRACE;
             throw error::ValueNotValidException(__PRETTY_FUNCTION__, "The index is out of bounds (size = " + std::to_string(childrenNavigators.size()) + ")", std::to_string(i), getPath());
         }
         return childrenNavigators[i];
@@ -206,6 +210,7 @@ namespace armarx::aron::data
     // TODO
     type::VariantPtr List::recalculateType() const
     {
+        ARMARX_TRACE;
         throw error::NotImplementedYetException(__PRETTY_FUNCTION__);
     }
 
@@ -218,18 +223,28 @@ namespace armarx::aron::data
         {
             case type::Descriptor::LIST:
             {
+                ARMARX_TRACE;
                 auto listTypeNav = type::List::DynamicCastAndCheck(type);
                 for (const auto& nav : childrenNavigators)
                 {
-                    if (!nav && !listTypeNav->getAcceptedType())
+                    auto childTypeNav = listTypeNav->getAcceptedType();
+                    if (!nav)
                     {
-                        return false;
+                        if (childTypeNav && childTypeNav->getMaybe() == type::Maybe::NONE)
+                        {
+                            ARMARX_TRACE;
+                            return false;
+                        }
+                        ARMARX_TRACE;
+                        return true;
                     }
-                    if (!nav->fullfillsType(listTypeNav->getAcceptedType()))
+                    if (!nav->fullfillsType(childTypeNav))
                     {
+                        ARMARX_TRACE;
                         return false;
                     }
                 }
+                ARMARX_TRACE;
                 return true;
             }
             case type::Descriptor::TUPLE:
@@ -238,15 +253,30 @@ namespace armarx::aron::data
                 unsigned int i = 0;
                 for (const auto& nav : childrenNavigators)
                 {
-                    if (!nav && !tupleTypeNav->getAcceptedType(i))
+                    if (!tupleTypeNav->hasAcceptedType(i))
+                    {
+                        ARMARX_TRACE;
+                        return false;
+                    }
+
+                    auto childTypeNav = tupleTypeNav->getAcceptedType(i);
+                    if (!nav)
                     {
+                        if (childTypeNav && childTypeNav->getMaybe() == type::Maybe::NONE)
+                        {
+                            ARMARX_TRACE;
+                            return false;
+                        }
+                        ARMARX_TRACE;
                         return false;
                     }
                     if (!nav->fullfillsType(tupleTypeNav->getAcceptedType(i)))
                     {
+                        ARMARX_TRACE;
                         return false;
                     }
                 }
+                ARMARX_TRACE;
                 return true;
             }
             case type::Descriptor::PAIR:
@@ -254,19 +284,36 @@ namespace armarx::aron::data
                 auto pairTypeNav = type::Pair::DynamicCastAndCheck(type);
                 if (childrenSize() != 2)
                 {
+                    ARMARX_TRACE;
                     return false;
                 }
-                if (!childrenNavigators[0] && !pairTypeNav->getFirstAcceptedType())
+                auto firstChildTypeNav = pairTypeNav->getFirstAcceptedType();
+                if (!childrenNavigators[0])
                 {
+                    if (firstChildTypeNav && firstChildTypeNav->getMaybe() == type::Maybe::NONE)
+                    {
+                        ARMARX_TRACE;
+                        return false;
+                    }
+                    ARMARX_TRACE;
                     return false;
                 }
-                if (!childrenNavigators[1] && !pairTypeNav->getSecondAcceptedType())
+                auto secondChildTypeNav = pairTypeNav->getSecondAcceptedType();
+                if (!childrenNavigators[1])
                 {
+                    if (secondChildTypeNav && secondChildTypeNav->getMaybe() == type::Maybe::NONE)
+                    {
+                        ARMARX_TRACE;
+                        return false;
+                    }
+                    ARMARX_TRACE;
                     return false;
                 }
-                return childrenNavigators[0]->fullfillsType(pairTypeNav->getFirstAcceptedType()) && childrenNavigators[1]->fullfillsType(pairTypeNav->getSecondAcceptedType());
+                ARMARX_TRACE;
+                return childrenNavigators[0]->fullfillsType(firstChildTypeNav) && childrenNavigators[1]->fullfillsType(secondChildTypeNav);
             }
             default:
+                ARMARX_TRACE;
                 return false;
         }
     }
@@ -290,6 +337,7 @@ namespace armarx::aron::data
         unsigned int i = std::stoi(path.getFirstElement());
         if (!hasElement(i))
         {
+            ARMARX_TRACE;
             throw error::ValueNotValidException(__PRETTY_FUNCTION__, "Could not find an element of a path.", std::to_string(i), std::to_string(childrenSize()));
         }
 
@@ -302,6 +350,7 @@ namespace armarx::aron::data
             Path next = path.withDetachedFirstElement();
             if (!childrenNavigators.at(i))
             {
+                ARMARX_TRACE;
                 throw error::AronException(__PRETTY_FUNCTION__, "Could not navigate into a NULL member. Seems like the member is optional and not set.", next);
             }
             return childrenNavigators.at(i)->navigateAbsolute(next);
diff --git a/source/RobotAPI/libraries/aron/core/data/variant/primitive/Bool.cpp b/source/RobotAPI/libraries/aron/core/data/variant/primitive/Bool.cpp
index 0e68bbc6dc16c373dd63c4626a45f5b1377afad4..2f7fe6fc8e486c43c32875c1cf072e721146c402 100644
--- a/source/RobotAPI/libraries/aron/core/data/variant/primitive/Bool.cpp
+++ b/source/RobotAPI/libraries/aron/core/data/variant/primitive/Bool.cpp
@@ -95,6 +95,7 @@ namespace armarx::aron::data
         }
         else
         {
+            ARMARX_TRACE;
             throw error::AronException(__PRETTY_FUNCTION__, "Could not set from string. Got: '" + setter + "'");
         }
     }
diff --git a/source/RobotAPI/libraries/aron/core/rw.h b/source/RobotAPI/libraries/aron/core/rw.h
index 6257f2422687591b0991afed8a0577ee127207ef..95b6aac606f47d3c46de34ac5ec077ded28c41a4 100644
--- a/source/RobotAPI/libraries/aron/core/rw.h
+++ b/source/RobotAPI/libraries/aron/core/rw.h
@@ -26,7 +26,7 @@ namespace armarx::aron
     }
 
     template<class ReaderT, class DtoT, class BoT>
-    requires (data::isReader<ReaderT> && !DtoAndBoAreSame<DtoT, BoT>)
+    requires (data::isReader<ReaderT> && !detail::DtoAndBoAreSame<DtoT, BoT>)
     inline void read(ReaderT& aron_r, typename ReaderT::InputType& input, BoT& ret)
     {
         DtoT aron;
@@ -36,7 +36,7 @@ namespace armarx::aron
     }
 
     template<class WriterT, class DtoT, class BoT>
-    requires (data::isWriter<WriterT> && !DtoAndBoAreSame<DtoT, BoT>)
+    requires (data::isWriter<WriterT> && !detail::DtoAndBoAreSame<DtoT, BoT>)
     inline void write(WriterT& aron_w, const BoT& input, typename WriterT::ReturnType& ret, const armarx::aron::Path& aron_p = armarx::aron::Path())
     {
         DtoT aron;
diff --git a/source/RobotAPI/libraries/aron/core/type/variant/container/Tuple.cpp b/source/RobotAPI/libraries/aron/core/type/variant/container/Tuple.cpp
index 0879de17b8e9258a211646e2b7c8d7c4bdc37ace..51d45e3975bb162460fd06893e91f388ac52b9f1 100644
--- a/source/RobotAPI/libraries/aron/core/type/variant/container/Tuple.cpp
+++ b/source/RobotAPI/libraries/aron/core/type/variant/container/Tuple.cpp
@@ -64,6 +64,11 @@ namespace armarx::aron::type
         return acceptedTypes;
     }
 
+    bool Tuple::hasAcceptedType(unsigned int i) const
+    {
+        return i < acceptedTypes.size();
+    }
+
     VariantPtr Tuple::getAcceptedType(unsigned int i) const
     {
         return acceptedTypes[i];
diff --git a/source/RobotAPI/libraries/aron/core/type/variant/container/Tuple.h b/source/RobotAPI/libraries/aron/core/type/variant/container/Tuple.h
index d464f83269d5074e1ec6e759119b433c76de0f7d..3281584c15d6b4bb3e50c83ce598634a2bbec324 100644
--- a/source/RobotAPI/libraries/aron/core/type/variant/container/Tuple.h
+++ b/source/RobotAPI/libraries/aron/core/type/variant/container/Tuple.h
@@ -46,6 +46,7 @@ namespace armarx::aron::type
 
         // public member functions
         std::vector<VariantPtr> getAcceptedTypes() const;
+        bool hasAcceptedType(unsigned int i) const;
         VariantPtr getAcceptedType(unsigned int i) const;
         void addAcceptedType(const VariantPtr&);
 
diff --git a/source/RobotAPI/libraries/aron/test/AronConversionTester.cpp b/source/RobotAPI/libraries/aron/test/AronConversionTester.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..aac543a04b6ba1696dedc7a21c7d4ea125896e4e
--- /dev/null
+++ b/source/RobotAPI/libraries/aron/test/AronConversionTester.cpp
@@ -0,0 +1,38 @@
+/**
+ * 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::aron_cpp_to_python_conv_test
+ * @author     Rainer Kartmann ( rainer dot kartmann at kit dot edu )
+ * @date       2023
+ * @copyright  http://www.gnu.org/licenses/gpl-2.0.txt
+ *             GNU General Public License
+ */
+
+
+#include "AronConversionTester.h"
+
+#include <ArmarXCore/core/exceptions/local/ExpressionException.h>
+
+
+namespace armarx::aron::test
+{
+
+    AronConversionTester::AronConversionTester(dti::AronConversionTestInterfacePrx python) : interface(python)
+    {
+        ARMARX_CHECK(python);
+    }
+
+
+} // namespace armarx::aron::test
diff --git a/source/RobotAPI/libraries/aron/test/AronConversionTester.h b/source/RobotAPI/libraries/aron/test/AronConversionTester.h
new file mode 100644
index 0000000000000000000000000000000000000000..b7ad4b8dfdcf55a37f8efc3116c27440d925d428
--- /dev/null
+++ b/source/RobotAPI/libraries/aron/test/AronConversionTester.h
@@ -0,0 +1,111 @@
+/**
+ * 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::aron_cpp_to_python_conv_test
+ * @author     Rainer Kartmann ( rainer dot kartmann at kit dot edu )
+ * @date       2023
+ * @copyright  http://www.gnu.org/licenses/gpl-2.0.txt
+ *             GNU General Public License
+ */
+
+
+#pragma once
+
+#include <ArmarXCore/core/exceptions/local/ExpressionException.h>
+#include <ArmarXCore/core/logging/Logging.h>
+
+#include <RobotAPI/interface/aron/test/AronConversionTestInterface.h>
+
+
+namespace armarx::aron::test
+{
+
+    /**
+     * @brief Helper class for implementing distributed ARON conversion tests
+     * based on the `dti::AronConversionTestInterfacePrx`.
+     *
+     * Example usage:
+     *
+     * @code
+     *
+     * armarx::aron::test::dti::AronConversionTestInterfacePrx pythonComponent = ...;
+     *
+     * auto myAronClassProbeFn = []()
+     * {
+     *     my::arondto::MyAronClass probe;
+     *     probe.data = "42";
+     *     return probe,
+     * };
+     *
+     * armarx::aron::test::AronConversionTester tester(pythonComponent);
+     *
+     * tester.test<my::arondto::MyAronClass>(myAronClassProbeFn, "MyAronClass");
+     *
+     * @endcode
+     *
+     * Note that the `pythonComponent` must point to a corresponding
+     * implementation of the `AronConversionTestInterfacePrx`.
+     */
+    class AronConversionTester
+    {
+    public:
+        template <class AronClassT>
+        using ProbeFn = std::function<AronClassT()>;
+
+
+    public:
+        AronConversionTester(dti::AronConversionTestInterfacePrx interface);
+
+        /**
+         * @brief Test the conversion of a specific ARON class.
+         *
+         * @param probeFn A factory function creating a test instance of the
+         *      ARON class.
+         * @param aronClassName The name of the ARON class. Can be used by the
+         *      other component to decide which class to convert to.
+         */
+        template <class AronClassT>
+        void
+        test(ProbeFn<AronClassT> probeFn, const std::string& aronClassName)
+        {
+            std::stringstream ss;
+            ss << "Test for ARON class '" << aronClassName << "': ";
+
+            const AronClassT probe = probeFn();
+
+            dto::TestAronConversionRequest req;
+            req.aronClassName = aronClassName;
+            req.probe = probe.toAronDTO();
+
+            dto::TestAronConversionResponse res = interface->testAronConversion(req);
+
+            if (res.success)
+            {
+                const AronClassT probeOut = AronClassT::FromAron(res.probe);
+                ARMARX_CHECK(probeOut == probe);
+
+                ARMARX_IMPORTANT << ss.str() << "Success";
+            }
+            else
+            {
+                ARMARX_WARNING << ss.str() << "Conversion in Python component failed: \n" << res.errorMessage;
+            }
+        }
+
+    public:
+        dti::AronConversionTestInterfacePrx interface;
+    };
+
+} // namespace armarx::aron::test
diff --git a/source/RobotAPI/libraries/aron/test/CMakeLists.txt b/source/RobotAPI/libraries/aron/test/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..3a199acf0f19c13f6253e66947e540bfe3950efd
--- /dev/null
+++ b/source/RobotAPI/libraries/aron/test/CMakeLists.txt
@@ -0,0 +1,25 @@
+set(LIB_NAME arontest)
+
+armarx_component_set_name("${LIB_NAME}")
+armarx_set_target("Library: ${LIB_NAME}")
+
+
+armarx_add_library(
+    LIBS
+        # ArmarXCore
+        ArmarXCore
+        # RobotAPI
+        RobotAPICore
+        RobotAPIInterfaces
+        aron
+
+    HEADERS
+        AronConversionTester.h
+
+    SOURCES
+        AronConversionTester.cpp
+)
+
+
+add_library(aron::test ALIAS arontest)
+add_library(${PROJECT_NAME}::Aron::test ALIAS arontest)
diff --git a/source/RobotAPI/libraries/obstacle_avoidance/CMakeLists.txt b/source/RobotAPI/libraries/obstacle_avoidance/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..dfd09c4a46abb303d29f4a0e5385fb6aa0a16b7b
--- /dev/null
+++ b/source/RobotAPI/libraries/obstacle_avoidance/CMakeLists.txt
@@ -0,0 +1,28 @@
+set(LIB_NAME obstacle_avoidance)
+
+armarx_component_set_name("${LIB_NAME}")
+armarx_set_target("Library: ${LIB_NAME}")
+
+armarx_add_library(
+    LIBS
+        # ArmarX
+        ArmarXCore
+        # This package
+        RobotAPI::Core
+        RobotAPI::armem
+        RobotAPI::armem_vision
+        RobotAPI::ArmarXObjects
+        aroncommon
+        # System / External
+#        Eigen3::Eigen
+    HEADERS
+        CollisionModelHelper.h
+    SOURCES
+        CollisionModelHelper.cpp
+)
+
+add_library(
+        "RobotAPI::${LIB_NAME}"
+        ALIAS
+        ${LIB_NAME}
+)
diff --git a/source/RobotAPI/libraries/obstacle_avoidance/CollisionModelHelper.cpp b/source/RobotAPI/libraries/obstacle_avoidance/CollisionModelHelper.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d53a8dd6a89f0cd37f609c9a4742d97d86f4deba
--- /dev/null
+++ b/source/RobotAPI/libraries/obstacle_avoidance/CollisionModelHelper.cpp
@@ -0,0 +1,179 @@
+/*
+ * 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
+ * @author     Christoph Pohl ( christoph dot pohl at kit dot edu )
+ * @date       17.02.23
+ * @copyright  http://www.gnu.org/licenses/gpl-2.0.txt
+ *             GNU General Public License
+ */
+
+#include "CollisionModelHelper.h"
+
+#include <VirtualRobot/ManipulationObject.h>
+#include <VirtualRobot/SceneObjectSet.h>
+#include <VirtualRobot/Visualization/CoinVisualization/CoinVisualizationFactory.h>
+#include <VirtualRobot/Visualization/TriMeshModel.h>
+
+#include <ArmarXCore/core/exceptions/local/ExpressionException.h>
+
+#include <RobotAPI/components/ArViz/Client/elements/Mesh.h>
+
+
+namespace armarx::obstacle_avoidance
+{
+
+    VirtualRobot::ManipulationObjectPtr
+    CollisionModelHelper::asManipulationObject(const objpose::ObjectPose& objectPose)
+    {
+        const ObjectFinder finder;
+
+        const VirtualRobot::SceneObjectSetPtr sceneObjects(new VirtualRobot::SceneObjectSet);
+        if (auto obstacle = finder.loadManipulationObject(objectPose))
+        {
+            obstacle->setGlobalPose(objectPose.objectPoseGlobal);
+            return obstacle;
+        }
+
+        ARMARX_WARNING << "Failed to load scene object `" << objectPose.objectID << "`";
+        return nullptr;
+    }
+
+    VirtualRobot::SceneObjectSetPtr
+    CollisionModelHelper::asSceneObjects(const objpose::ObjectPoseSeq& objectPoses)
+    {
+        const ObjectFinder finder;
+
+        VirtualRobot::SceneObjectSetPtr sceneObjects(new VirtualRobot::SceneObjectSet);
+        for (const auto& objectPose : objectPoses)
+        {
+            if (auto obstacle = finder.loadManipulationObject(objectPose))
+            {
+                obstacle->setGlobalPose(objectPose.objectPoseGlobal);
+                sceneObjects->addSceneObject(obstacle);
+            }
+        }
+
+        return sceneObjects;
+    }
+
+    VirtualRobot::SceneObjectSetPtr
+    CollisionModelHelper::asSceneObjects(const OccupancyGrid& occupancyGrid,
+                                         const OccupancyGridHelper::Params& params)
+    {
+        const OccupancyGridHelper ocHelper(occupancyGrid, params);
+        const auto obstacles = ocHelper.obstacles();
+
+        const float boxSize = occupancyGrid.resolution;
+        const float resolution = occupancyGrid.resolution;
+
+        VirtualRobot::SceneObjectSetPtr sceneObjects(new VirtualRobot::SceneObjectSet);
+
+        ARMARX_CHECK_EQUAL(occupancyGrid.frame, GlobalFrame)
+            << "Only occupancy grid in global frame supported.";
+
+        VirtualRobot::CoinVisualizationFactory factory;
+
+        const auto& world_T_map = occupancyGrid.pose;
+
+        for (int x = 0; x < obstacles.rows(); x++)
+        {
+            for (int y = 0; y < obstacles.cols(); y++)
+            {
+                if (obstacles(x, y))
+                {
+                    const Eigen::Vector3f pos{
+                        static_cast<float>(x) * resolution, static_cast<float>(y) * resolution, 0};
+
+                    // FIXME: change to Isometry3f
+                    Eigen::Affine3f map_T_obj = Eigen::Affine3f::Identity();
+                    map_T_obj.translation() = pos;
+
+                    Eigen::Affine3f world_T_obj = world_T_map * map_T_obj;
+
+                    // ARMARX_INFO << world_T_obj.translation();
+
+                    auto cube = factory.createBox(boxSize, boxSize, boxSize);
+
+                    const VirtualRobot::CollisionModelPtr collisionModel(
+                        new VirtualRobot::CollisionModel(cube));
+
+                    const VirtualRobot::SceneObjectPtr sceneObject(new VirtualRobot::SceneObject(
+                        "box_" + std::to_string(sceneObjects->getSize()), cube, collisionModel));
+                    sceneObject->setGlobalPose(world_T_obj.matrix());
+
+                    sceneObjects->addSceneObject(sceneObject);
+                }
+            }
+        }
+
+        return sceneObjects;
+    }
+
+    CollisionModelHelper::CollisionModelHelper(const objpose::ObjectPoseClient& client) :
+        objectPoseClient_(client)
+    {
+    }
+
+    VirtualRobot::SceneObjectSetPtr
+    CollisionModelHelper::fetchSceneObjects()
+    {
+        const objpose::ObjectPoseSeq objectPoses = objectPoseClient_.fetchObjectPoses();
+        return asSceneObjects(objectPoses);
+    }
+
+    CollisionModelHelper::ManipulationObjectSetPtr
+    CollisionModelHelper::fetchManipulationObjects()
+    {
+        const objpose::ObjectPoseSeq objectPoses = objectPoseClient_.fetchObjectPoses();
+        return asManipulationObjects(objectPoses);
+    }
+
+    CollisionModelHelper::ManipulationObjectSetPtr
+    CollisionModelHelper::asManipulationObjects(const objpose::ObjectPoseSeq& objectPoses)
+    {
+        ManipulationObjectSet set;
+
+        for (const auto& pose : objectPoses)
+        {
+            set.emplace_back(*asManipulationObject(pose));
+        }
+
+        return std::make_shared<ManipulationObjectSet>(set);
+    }
+
+    void
+    CollisionModelHelper::visualizeCollisionModel(const VirtualRobot::CollisionModelPtr& model,
+                                                  viz::Client& arviz)
+    {
+        armarx::viz::Mesh mesh(model->getName());
+        auto faces = model->getTriMeshModel()->faces;
+        std::vector<armarx::viz::data::Face> viz_faces;
+        std::transform(
+            faces.begin(),
+            faces.end(),
+            std::back_inserter(viz_faces),
+            [](const auto& face)
+            {
+                return armarx::viz::data::Face(
+                    face.id1, face.id2, face.id3, face.idColor1, face.idColor2, face.idColor3);
+            });
+        mesh.vertices(model->getTriMeshModel()->vertices)
+            .faces(viz_faces)
+            .pose(model->getGlobalPose());
+        arviz.commitLayerContaining("CollisionModel", mesh);
+    }
+
+} // namespace armarx::obstacle_avoidance
\ No newline at end of file
diff --git a/source/RobotAPI/libraries/obstacle_avoidance/CollisionModelHelper.h b/source/RobotAPI/libraries/obstacle_avoidance/CollisionModelHelper.h
new file mode 100644
index 0000000000000000000000000000000000000000..d56a2d5bda01b7492f6b73f5ce3f9416bf7b0db7
--- /dev/null
+++ b/source/RobotAPI/libraries/obstacle_avoidance/CollisionModelHelper.h
@@ -0,0 +1,62 @@
+/*
+ * 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
+ * @author     Christoph Pohl ( christoph dot pohl at kit dot edu )
+ * @date       17.02.23
+ * @copyright  http://www.gnu.org/licenses/gpl-2.0.txt
+ *             GNU General Public License
+ */
+
+#pragma once
+
+#include <VirtualRobot/VirtualRobot.h>
+
+#include <RobotAPI/components/ArViz/Client/Client.h>
+#include <RobotAPI/libraries/ArmarXObjects/ObjectPoseClient.h>
+#include <RobotAPI/libraries/ArmarXObjects/forward_declarations.h>
+#include <RobotAPI/libraries/armem_vision/OccupancyGridHelper.h>
+#include <RobotAPI/libraries/armem_vision/types.h>
+
+namespace armarx::obstacle_avoidance
+{
+
+    class CollisionModelHelper
+    {
+    public:
+        using ManipulationObjectSet = std::vector<VirtualRobot::ManipulationObject>;
+        using ManipulationObjectSetPtr = std::shared_ptr<ManipulationObjectSet>;
+
+        static VirtualRobot::ManipulationObjectPtr
+        asManipulationObject(const objpose::ObjectPose& objectPose);
+        static ManipulationObjectSetPtr
+        asManipulationObjects(const objpose::ObjectPoseSeq& objectPoses);
+        static VirtualRobot::SceneObjectSetPtr
+        asSceneObjects(const objpose::ObjectPoseSeq& objectPoses);
+        static VirtualRobot::SceneObjectSetPtr
+        asSceneObjects(const armem::vision::OccupancyGrid& occupancyGrid,
+                       const OccupancyGridHelper::Params& params);
+        static void visualizeCollisionModel(const VirtualRobot::CollisionModelPtr& model,
+                                            viz::Client& arviz);
+
+
+        CollisionModelHelper(const objpose::ObjectPoseClient& client);
+        VirtualRobot::SceneObjectSetPtr fetchSceneObjects();
+        ManipulationObjectSetPtr fetchManipulationObjects();
+
+    private:
+        objpose::ObjectPoseClient objectPoseClient_;
+    };
+} // namespace armarx::obstacle_avoidance
diff --git a/source/RobotAPI/libraries/skills/manager/SkillManagerComponentPlugin.cpp b/source/RobotAPI/libraries/skills/manager/SkillManagerComponentPlugin.cpp
index 23a708aceace48317d04884a8579fd21001b92c3..60a38b465ddb8bd9d6cbdac5ec4952606624880c 100644
--- a/source/RobotAPI/libraries/skills/manager/SkillManagerComponentPlugin.cpp
+++ b/source/RobotAPI/libraries/skills/manager/SkillManagerComponentPlugin.cpp
@@ -33,7 +33,9 @@ namespace armarx
         }
         else
         {
-            ARMARX_INFO << "Trying to add a provider with name '" << info.providerName << "' but the provider already exists.";
+            ARMARX_INFO << "Trying to add a provider with name '" << info.providerName << "' but the provider already exists. "
+                        << "Overwriting the old provider info.";
+            skillProviderMap[info.providerName] = info.provider;
         }
     }
 
@@ -47,7 +49,7 @@ namespace armarx
         }
         else
         {
-            ARMARX_INFO << "Trying to remove a provider with name '" << providerName << "' but it couldn't found.";
+            ARMARX_INFO << "Trying to remove a provider with name '" << providerName << "' but it couldn't be found.";
         }
     }
 
@@ -79,31 +81,64 @@ namespace armarx
             providerName = info.skillId.providerName;
         }
 
+        bool remove = false;
         if (auto it = skillProviderMap.find(providerName); it != skillProviderMap.end())
         {
-            skills::callback::dti::SkillProviderCallbackInterfacePrx myPrx;
-            getProxy(myPrx, -1);
+            const auto& n = it->first;
+            const auto& s = it->second;
 
-            skills::provider::dto::SkillExecutionRequest exInfo;
-            exInfo.skillName = info.skillId.skillName;
-            exInfo.executorName = info.executorName;
-            exInfo.callbackInterface = myPrx;
-            exInfo.params = info.params;
+            if (s)
+            {
+                skills::callback::dti::SkillProviderCallbackInterfacePrx myPrx;
+                getProxy(myPrx, -1);
+
+                skills::provider::dto::SkillExecutionRequest exInfo;
+                exInfo.skillName = info.skillId.skillName;
+                exInfo.executorName = info.executorName;
+                exInfo.callbackInterface = myPrx;
+                exInfo.params = info.params;
+
+                return s->executeSkill(exInfo);
+            }
+            else
+            {
+                remove = true;
+            }
 
-            return it->second->executeSkill(exInfo);
+            if (remove)
+            {
+                std::scoped_lock l(skillProviderMapMutex);
+                if (auto it = skillProviderMap.find(providerName); it != skillProviderMap.end())
+                {
+                    ARMARX_WARNING << __PRETTY_FUNCTION__ << ": Found disconnected skill provider '" << n << "' during execution. Removing it from skills.";
+                    it = skillProviderMap.erase(it);
+                }
+            }
         }
         else
         {
             ARMARX_ERROR << "Could not execute a skill of provider '" + providerName + "' because the provider does not exist.";
             throw skills::error::SkillException(__PRETTY_FUNCTION__, "Skill execution failed. Could not execute a skill of provider '" + providerName + "' because the provider does not exist.");
         }
+        return {}; // Never happens
     }
 
     void SkillManagerComponentPluginUser::abortSkill(const std::string& providerName, const std::string& skillName, const Ice::Current &current)
     {
+        std::scoped_lock l(skillProviderMapMutex);
         if (auto it = skillProviderMap.find(providerName); it != skillProviderMap.end())
         {
-            it->second->abortSkill(skillName);
+            const auto& n = it->first;
+            const auto& s = it->second;
+            if (s)
+            {
+                s->abortSkill(skillName);
+            }
+            else
+            {
+                ARMARX_WARNING << __PRETTY_FUNCTION__ << ": Found disconnected skill provider '" << n << "'. Removing it from skills.";
+                it = skillProviderMap.erase(it);
+            }
         }
     }
 
@@ -116,10 +151,23 @@ namespace armarx
     skills::manager::dto::SkillDescriptionMapMap SkillManagerComponentPluginUser::getSkillDescriptions(const Ice::Current &current)
     {
         skills::manager::dto::SkillDescriptionMapMap ret;
-        for (const auto& [n, s] : skillProviderMap)
+
+        std::scoped_lock l(skillProviderMapMutex);
+        for (auto it = skillProviderMap.cbegin(); it != skillProviderMap.cend();)
         {
-            skills::provider::dto::SkillDescriptionMap m = s->getSkillDescriptions();
-            ret.insert({n, m});
+            const auto& n = it->first;
+            const auto& s = it->second;
+            if (s)
+            {
+                skills::provider::dto::SkillDescriptionMap m = s->getSkillDescriptions();
+                ret.insert({n, m});
+                ++it;
+            }
+            else
+            {
+                ARMARX_WARNING << __PRETTY_FUNCTION__ << ": Found disconnected skill provider '" << n << "'. Removing it from skills.";
+                it = skillProviderMap.erase(it);
+            }
         }
         return ret;
     }
@@ -127,10 +175,23 @@ namespace armarx
     skills::manager::dto::SkillStatusUpdateMapMap SkillManagerComponentPluginUser::getSkillExecutionStatuses(const Ice::Current &current)
     {
         skills::manager::dto::SkillStatusUpdateMapMap ret;
-        for (const auto& [n, s] : skillProviderMap)
+
+        std::scoped_lock l(skillProviderMapMutex);
+        for (auto it = skillProviderMap.cbegin(); it != skillProviderMap.cend();)
         {
-            skills::provider::dto::SkillStatusUpdateMap m = s->getSkillExecutionStatuses();
-            ret.insert({n, m});
+            const auto& n = it->first;
+            const auto& s = it->second;
+            if (s)
+            {
+                skills::provider::dto::SkillStatusUpdateMap m = s->getSkillExecutionStatuses();
+                ret.insert({n, m});
+                it++;
+            }
+            else
+            {
+                ARMARX_WARNING << __PRETTY_FUNCTION__ << ": Found disconnected skill provider '" << n << "'. Removing it from skills.";
+                it = skillProviderMap.erase(it);
+            }
         }
         return ret;
     }
diff --git a/source/RobotAPI/libraries/skills/provider/detail/SkillImplementationWrapper.cpp b/source/RobotAPI/libraries/skills/provider/detail/SkillImplementationWrapper.cpp
index 1fb8c3ac52010943e01b044d0e99ce144739a2b6..81e91b131294d542c286659e0691056ea0bc0894 100644
--- a/source/RobotAPI/libraries/skills/provider/detail/SkillImplementationWrapper.cpp
+++ b/source/RobotAPI/libraries/skills/provider/detail/SkillImplementationWrapper.cpp
@@ -86,7 +86,7 @@ namespace armarx
             }
             catch (const std::exception& ex)
             {
-                std::string message = "SkillError 101e: An error occured during the check whether skill '" + skillName + "' is available. The error was: " + ex.what();
+                std::string message = "SkillError 101e: An error occured during the check whether skill '" + skillName + "' is available. The error was: " + GetHandledExceptionString();
                 ARMARX_ERROR_S << message;
                 resetExecParam();
                 return TerminatedSkillStatusUpdate({{skill->getSkillId(), executorName, parameterization, createErrorMessage(message)}, TerminatedSkillStatus::Failed});
@@ -102,7 +102,7 @@ namespace armarx
             }
             catch (const std::exception& ex)
             {
-                std::string message = "SkillError 201e: An error occured during the reset of skill '" + skillName + "'. The error was: " + ex.what();
+                std::string message = "SkillError 201e: An error occured during the reset of skill '" + skillName + "'. The error was: " + GetHandledExceptionString();
                 ARMARX_ERROR_S << message;
 
                 updateStatus(SkillStatus::Failed);
@@ -116,7 +116,7 @@ namespace armarx
             }
             catch (const std::exception& ex)
             {
-                std::string message = "SkillError 301e: An error occured during waiting for skill dependencies of skill '" + skillName + "'. The error was: " + ex.what();
+                std::string message = "SkillError 301e: An error occured during waiting for skill dependencies of skill '" + skillName + "'. The error was: " + GetHandledExceptionString();
                 ARMARX_ERROR_S << message;
 
                 updateStatus(SkillStatus::Failed);
@@ -143,7 +143,7 @@ namespace armarx
             }
             catch (const std::exception& ex)
             {
-                std::string message = "SkillError 401e: An error occured during the initialization of skill '" + skillName + "'. The error was: " + ex.what();
+                std::string message = "SkillError 401e: An error occured during the initialization of skill '" + skillName + "'. The error was: " + GetHandledExceptionString();
                 ARMARX_ERROR_S << message;
                 skill->exitSkill({executorName, aron_params}); // try to exit skill. Ignore return value
 
@@ -174,7 +174,7 @@ namespace armarx
             }
             catch (const std::exception& ex)
             {
-                std::string message = "SkillError 501e: An error occured during the main method of skill '" + skillName + "'. The error was: " + ex.what();
+                std::string message = "SkillError 501e: An error occured during the main method of skill '" + skillName + "'. The error was: " + GetHandledExceptionString();
                 ARMARX_ERROR_S << message;
                 skill->exitSkill({executorName, aron_params}); // try to exit skill. Ignore return value
 
@@ -199,7 +199,7 @@ namespace armarx
             }
             catch (const std::exception& ex)
             {
-                std::string message = "SkillError 601e: An error occured during the exit method of skill '" + skillName + "'. The error was: " + ex.what();
+                std::string message = "SkillError 601e: An error occured during the exit method of skill '" + skillName + "'. The error was: " + GetHandledExceptionString();
                 ARMARX_ERROR_S << message;
 
                 updateStatus(SkillStatus::Failed);
diff --git a/source/RobotAPI/libraries/skills/provider/mixins/RobotWritingSkillMixin.h b/source/RobotAPI/libraries/skills/provider/mixins/RobotWritingSkillMixin.h
new file mode 100644
index 0000000000000000000000000000000000000000..34856452c4b8bd3b4e61dd69ee03eb122d409566
--- /dev/null
+++ b/source/RobotAPI/libraries/skills/provider/mixins/RobotWritingSkillMixin.h
@@ -0,0 +1,28 @@
+#pragma once
+
+
+// Others
+#include <RobotAPI/libraries/armem_robot_state/client/common/VirtualRobotWriter.h>
+
+namespace armarx::skills::mixin
+{
+    struct RobotWritingSkillMixin
+    {
+        armem::robot_state::VirtualRobotWriter robotWriter;
+
+        RobotWritingSkillMixin(armem::client::MemoryNameSystem& mns) :
+            robotWriter(mns)
+        {}
+    };
+
+    struct SpecificRobotWritingSkillMixin
+    {
+        std::string robotName;
+        armem::robot_state::VirtualRobotWriter robotWriter;
+
+        SpecificRobotWritingSkillMixin(const std::string& rn, armem::client::MemoryNameSystem& mns) :
+            robotName(rn),
+            robotWriter(mns)
+        {}
+    };
+}