diff --git a/source/RobotAPI/components/units/RobotUnit/ControlTargets/ControlTargetBase.h b/source/RobotAPI/components/units/RobotUnit/ControlTargets/ControlTargetBase.h
index 8b69a5d565d944c415be16a0815f26b9d5c1af07..c4e6a36af757d2d020eb6ebb0fdb1a8a2310f5f2 100644
--- a/source/RobotAPI/components/units/RobotUnit/ControlTargets/ControlTargetBase.h
+++ b/source/RobotAPI/components/units/RobotUnit/ControlTargets/ControlTargetBase.h
@@ -80,7 +80,15 @@ namespace armarx
 
         virtual std::size_t getNumberOfDataFields() const = 0;
         virtual std::vector<std::string> getDataFieldNames() const = 0;
-        virtual std::string getDataFieldAsString(std::size_t i) const = 0;
+        virtual void getDataFieldAs(std::size_t i, bool&        out) const = 0;
+        virtual void getDataFieldAs(std::size_t i, Ice::Byte&   out) const = 0;
+        virtual void getDataFieldAs(std::size_t i, Ice::Short&  out) const = 0;
+        virtual void getDataFieldAs(std::size_t i, Ice::Int&    out) const = 0;
+        virtual void getDataFieldAs(std::size_t i, Ice::Long&   out) const = 0;
+        virtual void getDataFieldAs(std::size_t i, Ice::Float&  out) const = 0;
+        virtual void getDataFieldAs(std::size_t i, Ice::Double& out) const = 0;
+        virtual void getDataFieldAs(std::size_t i, std::string& out) const = 0;
+        virtual const std::type_info& getDataFieldType(std::size_t i) const = 0;
 
         //management functions
         template<class T, class = typename std::enable_if<std::is_base_of<ControlTargetBase, T>::value>::type>
@@ -118,9 +126,41 @@ namespace armarx
     {                                                                                               \
         return ControlTargetInfo<std::decay<decltype(*this)>::type>::GetNumberOfDataFields();       \
     }                                                                                               \
-    std::string getDataFieldAsString(std::size_t i) const override                                  \
+    void getDataFieldAs (std::size_t i, bool&        out) const override                            \
     {                                                                                               \
-        return ControlTargetInfo<std::decay<decltype(*this)>::type>::GetDataFieldAsString(this, i); \
+        ControlTargetInfo<std::decay<decltype(*this)>::type>::GetDataFieldAs (this, i, out);        \
+    }                                                                                               \
+    void getDataFieldAs (std::size_t i, Ice::Byte&   out) const override                            \
+    {                                                                                               \
+        ControlTargetInfo<std::decay<decltype(*this)>::type>::GetDataFieldAs (this, i, out);        \
+    }                                                                                               \
+    void getDataFieldAs (std::size_t i, Ice::Short&  out) const override                            \
+    {                                                                                               \
+        ControlTargetInfo<std::decay<decltype(*this)>::type>::GetDataFieldAs (this, i, out);        \
+    }                                                                                               \
+    void getDataFieldAs (std::size_t i, Ice::Int&    out) const override                            \
+    {                                                                                               \
+        ControlTargetInfo<std::decay<decltype(*this)>::type>::GetDataFieldAs (this, i, out);        \
+    }                                                                                               \
+    void getDataFieldAs (std::size_t i, Ice::Long&   out) const override                            \
+    {                                                                                               \
+        ControlTargetInfo<std::decay<decltype(*this)>::type>::GetDataFieldAs (this, i, out);        \
+    }                                                                                               \
+    void getDataFieldAs (std::size_t i, Ice::Float&  out) const override                            \
+    {                                                                                               \
+        ControlTargetInfo<std::decay<decltype(*this)>::type>::GetDataFieldAs (this, i, out);        \
+    }                                                                                               \
+    void getDataFieldAs (std::size_t i, Ice::Double& out) const override                            \
+    {                                                                                               \
+        ControlTargetInfo<std::decay<decltype(*this)>::type>::GetDataFieldAs (this, i, out);        \
+    }                                                                                               \
+    void getDataFieldAs (std::size_t i, std::string& out) const override                            \
+    {                                                                                               \
+        ControlTargetInfo<std::decay<decltype(*this)>::type>::GetDataFieldAs (this, i, out);        \
+    }                                                                                               \
+    const std::type_info& getDataFieldType(std::size_t i) const override                            \
+    {                                                                                               \
+        return ControlTargetInfo<std::decay<decltype(*this)>::type>::GetDataFieldType(i);           \
     }                                                                                               \
     std::vector<std::string> getDataFieldNames() const override                                     \
     {                                                                                               \
diff --git a/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleLogging.cpp b/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleLogging.cpp
index 1f58f79ae6bb6be402f4b22b45bc5e9ebb06ae7a..0994896f9a3510a8c4ce0241d981d0dad2bf03cc 100644
--- a/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleLogging.cpp
+++ b/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleLogging.cpp
@@ -20,6 +20,12 @@
  *             GNU General Public License
  */
 
+#include <regex>
+
+#include <boost/iterator/transform_iterator.hpp>
+
+#include <ArmarXCore/util/CPPUtility/trace.h>
+#include <ArmarXCore/util/CPPUtility/Iterator.h>
 #include <ArmarXCore/core/util/FileSystemPathBuilder.h>
 #include <ArmarXCore/core/ArmarXManager.h>
 
@@ -36,6 +42,7 @@ namespace armarx::RobotUnitModule
 {
     void Logging::addMarkerToRtLog(const RemoteReferenceCounterBasePtr& token, const std::string& marker, const Ice::Current&)
     {
+        ARMARX_TRACE;
         throwIfInControlThread(BOOST_CURRENT_FUNCTION);
         std::lock_guard<std::mutex> guard {rtLoggingMutex};
         if (!rtLoggingEntries.count(token->getId()))
@@ -47,6 +54,7 @@ namespace armarx::RobotUnitModule
 
     RemoteReferenceCounterBasePtr Logging::startRtLogging(const std::string& formatString, const Ice::StringSeq& loggingNames, const Ice::Current&)
     {
+        ARMARX_TRACE;
         throwIfInControlThread(BOOST_CURRENT_FUNCTION);
         StringStringDictionary alias;
         for (const auto& name : loggingNames)
@@ -58,11 +66,12 @@ namespace armarx::RobotUnitModule
 
     void Logging::stopRtLogging(const RemoteReferenceCounterBasePtr& token, const Ice::Current&)
     {
+        ARMARX_TRACE;
         throwIfInControlThread(BOOST_CURRENT_FUNCTION);
         std::lock_guard<std::mutex> guard {rtLoggingMutex};
         if (!rtLoggingEntries.count(token->getId()))
         {
-            throw InvalidArgumentException {"addMarkerToRtLog called for a nonexistent log"};
+            throw InvalidArgumentException {"stopRtLogging called for a nonexistent log"};
         }
         ARMARX_DEBUG_S << "RobotUnit: stop RtLogging for file " << rtLoggingEntries.at(token->getId())->filename;
         rtLoggingEntries.at(token->getId())->stopLogging = true;
@@ -70,24 +79,39 @@ namespace armarx::RobotUnitModule
 
     Ice::StringSeq Logging::getLoggingNames(const Ice::Current&) const
     {
+        ARMARX_TRACE;
         throwIfInControlThread(BOOST_CURRENT_FUNCTION);
         Ice::StringSeq result;
-        for (const auto& strs : sensorDeviceValueLoggingNames)
+        const auto getName = [](const auto & fieldData)
         {
-            result.insert(result.end(), strs.begin(), strs.end());
+            return fieldData.name;
+        };
+        for (const auto& data : sensorDeviceValueMetaData)
+        {
+            result.insert(
+                result.end(),
+                boost::make_transform_iterator(data.fields.begin(), getName),
+                boost::make_transform_iterator(data.fields.end(), getName));
         }
-        for (const auto& strvecss : controlDeviceValueLoggingNames)
+        for (const auto& datas : controlDeviceValueMetaData)
         {
-            for (const auto& strs : strvecss)
+            for (const auto& data : datas)
             {
-                result.insert(result.end(), strs.begin(), strs.end());
+                result.insert(
+                    result.end(),
+                    boost::make_transform_iterator(data.fields.begin(), getName),
+                    boost::make_transform_iterator(data.fields.end(), getName));
             }
         }
         return result;
     }
 
-    RemoteReferenceCounterBasePtr Logging::startRtLoggingWithAliasNames(const std::string& formatString, const StringStringDictionary& aliasNames, const Ice::Current&)
+    RemoteReferenceCounterBasePtr Logging::startRtLoggingWithAliasNames(
+        const std::string& formatString,
+        const StringStringDictionary& aliasNames,
+        const Ice::Current&)
     {
+        ARMARX_TRACE;
         throwIfInControlThread(BOOST_CURRENT_FUNCTION);
         FileSystemPathBuilder pb {formatString};
         std::lock_guard<std::mutex> guard {rtLoggingMutex};
@@ -106,22 +130,19 @@ namespace armarx::RobotUnitModule
             rtLoggingEntries.erase(pb.getPath());
             throw LogicError {"RtLogging could not open filestream for '" + pb.getPath() + "'"};
         }
+        ARMARX_INFO << "Start logging to " << e.filename
+                    << ". Names (pattern, replacement name): " << aliasNames;
 
         std::stringstream header;
-        header << "marker;iteration;timestamp";
+        header << "marker;iteration;timestamp;TimeSinceLastIteration";
         auto logDev = [&](const std::string & dev)
         {
-            for (const auto& pair : aliasNames)
+            ARMARX_TRACE_LITE;
+            for (const auto& [key, value] : aliasNames)
             {
-                std::string name = pair.first;
-                if (boost::starts_with(dev + "$", name))
+                if (MatchName(key, dev))
                 {
-                    if ((name.size() > 0 && name.back() == '$'))
-                    {
-                        name.resize(name.size() - 1);
-                    }
-                    const std::string& alias = pair.second.empty() ? name : pair.second;
-                    header << ";" << alias << dev.substr(name.size());
+                    header << ";" << (value.empty() ? dev : value);
                     return true;
                 }
             }
@@ -130,40 +151,42 @@ namespace armarx::RobotUnitModule
 
         //get logged sensor device values
         {
-            e.loggedSensorDeviceValues.reserve(sensorDeviceValueLoggingNames.size());
-            for (const auto& svfields : sensorDeviceValueLoggingNames)
+            ARMARX_TRACE;
+            e.loggedSensorDeviceValues.reserve(sensorDeviceValueMetaData.size());
+            for (const auto& valData : sensorDeviceValueMetaData)
             {
                 e.loggedSensorDeviceValues.emplace_back();
                 auto& svfieldsFlags = e.loggedSensorDeviceValues.back(); //vv
-                svfieldsFlags.reserve(svfields.size());
-                for (const auto& field : svfields)
+                svfieldsFlags.reserve(valData.fields.size());
+                for (const auto& field : valData.fields)
                 {
-                    svfieldsFlags.emplace_back(logDev(field));
+                    svfieldsFlags.emplace_back(logDev(field.name));
                 }
             }
         }
         //get logged control device values
         {
-            e.loggedControlDeviceValues.reserve(controlDeviceValueLoggingNames.size());
-            for (const auto& sjctrls : controlDeviceValueLoggingNames)
+            ARMARX_TRACE;
+            e.loggedControlDeviceValues.reserve(controlDeviceValueMetaData.size());
+            for (const auto& datas : controlDeviceValueMetaData)
             {
                 e.loggedControlDeviceValues.emplace_back();
-                auto& sjctrlsFlags = e.loggedControlDeviceValues.back(); //vv
-                sjctrlsFlags.reserve(sjctrls.size());
-                for (const auto& ctargfields : sjctrls)
+                auto& deviceCtrlFlags = e.loggedControlDeviceValues.back(); //vv
+                deviceCtrlFlags.reserve(datas.size());
+                for (const auto& valData : datas)
                 {
+                    deviceCtrlFlags.emplace_back();
+                    auto& ctrlFieldFlags = deviceCtrlFlags.back(); //v
+                    ctrlFieldFlags.reserve(valData.fields.size());
 
-                    sjctrlsFlags.emplace_back();
-                    auto& ctargfieldsFlags = sjctrlsFlags.back(); //v
-                    ctargfieldsFlags.reserve(ctargfields.size());
-
-                    for (const auto& field : ctargfields)
+                    for (const auto& field : valData.fields)
                     {
-                        ctargfieldsFlags.emplace_back(logDev(field));
+                        ctrlFieldFlags.emplace_back(logDev(field.name));
                     }
                 }
             }
         }
+        ARMARX_TRACE;
 
         //write header
         e.stream << header.str() << std::flush; // newline is written at the beginning of each log line
@@ -182,6 +205,7 @@ namespace armarx::RobotUnitModule
 
     void Logging::writeRecentIterationsToFile(const std::string& formatString, const Ice::Current&) const
     {
+        ARMARX_TRACE;
         throwIfInControlThread(BOOST_CURRENT_FUNCTION);
         std::lock_guard<std::mutex> guard {rtLoggingMutex};
         FileSystemPathBuilder pb {formatString};
@@ -200,20 +224,20 @@ namespace armarx::RobotUnitModule
         //write csv header
         {
             outCSV << "iteration;timestamp";
-            for (const auto& vs : sensorDeviceValueLoggingNames)
+            for (const auto& vs : sensorDeviceValueMetaData)
             {
-                for (const auto& s : vs)
+                for (const auto& f : vs.fields)
                 {
-                    outCSV << ";" << s;
+                    outCSV << ";" << f.name;
                 }
             }
-            for (const auto& vvs : controlDeviceValueLoggingNames)
+            for (const auto& vvs : controlDeviceValueMetaData)
             {
                 for (const auto& vs : vvs)
                 {
-                    for (const auto& s : vs)
+                    for (const auto& f : vs.fields)
                     {
-                        outCSV << ";" << s;
+                        outCSV << ";" << f.name;
                     }
                 }
             }
@@ -231,7 +255,9 @@ namespace armarx::RobotUnitModule
                     {
                         for (std::size_t idxField = 0; idxField < val->getNumberOfDataFields(); ++ idxField)
                         {
-                            outCSV  << ";" << val->getDataFieldAsString(idxField);
+                            std::string s;
+                            val->getDataFieldAs(idxField, s);
+                            outCSV  << ";" << s;
                         }
                     }
                 }
@@ -243,7 +269,9 @@ namespace armarx::RobotUnitModule
                         {
                             for (std::size_t idxField = 0; idxField < val->getNumberOfDataFields(); ++ idxField)
                             {
-                                outCSV  << ";" << val->getDataFieldAsString(idxField);
+                                std::string s;
+                                val->getDataFieldAs(idxField, s);
+                                outCSV  << ";" << s;
                             }
                         }
                     }
@@ -275,8 +303,134 @@ namespace armarx::RobotUnitModule
         }
     }
 
+    RobotUnitDataStreaming::DataStreamingDescription Logging::startDataStreaming(
+        const RobotUnitDataStreaming::ReceiverPrx& receiver,
+        const RobotUnitDataStreaming::Config& config,
+        const Ice::Current&)
+    {
+        ARMARX_TRACE;
+        throwIfInControlThread(BOOST_CURRENT_FUNCTION);
+        if (!receiver)
+        {
+            throw InvalidArgumentException {"Receiver proxy is NULL!"};
+        }
+        std::lock_guard<std::mutex> guard {rtLoggingMutex};
+        if (rtDataStreamingEntry.count(receiver))
+        {
+            throw InvalidArgumentException {"There already is a logger for the given receiver"};
+        }
+
+        RobotUnitDataStreaming::DataStreamingDescription result;
+        DataStreamingEntry& streamingEntry = rtDataStreamingEntry[receiver];
+
+        ARMARX_INFO << "start data streaming to " << receiver->ice_getIdentity().name
+                    << ". Values: " << config.loggingNames;
+        auto devMatchesAnyKey = [&](const std::string & dev)
+        {
+            for (const auto& key : config.loggingNames)
+            {
+                if (MatchName(key, dev))
+                {
+                    return true;
+                }
+            }
+            return false;
+        };
+
+        const auto handleVal = [&](
+                                   const ValueMetaData & valData,
+                                   DataStreamingEntry & streamingEntry,
+                                   RobotUnitDataStreaming::DataStreamingDescription & descr
+                               ) -> std::vector<DataStreamingEntry::OutVal>
+        {
+            ARMARX_TRACE_LITE;
+            std::vector<DataStreamingEntry::OutVal> result;
+            result.resize(valData.fields.size());
+            for (std::size_t i = 0; i < valData.fields.size(); ++i)
+            {
+                if (!devMatchesAnyKey(valData.fields.at(i).name))
+                {
+                    continue; //do not add to result and skipp during processing
+                }
+                auto& descrEntr = descr.entries[valData.fields.at(i).name];
+                //formatter failes here!
+                //*INDENT-OFF*
+                #define make_case(Type, TName)                                    \
+                    (typeid(Type) == *valData.fields.at(i).type)                  \
+                    {                                                             \
+                        descrEntr.index = streamingEntry.num##TName##s;           \
+                        descrEntr.type = RobotUnitDataStreaming::NodeType##TName; \
+                        result.at(i).idx   = streamingEntry.num##TName##s;        \
+                        result.at(i).value = DataStreamingEntry::ValueT::TName;   \
+                        ++streamingEntry.num##TName##s;                           \
+                    }
+                if      make_case(bool,        Bool)
+                else if make_case(Ice::Byte,   Byte)
+                else if make_case(Ice::Short,  Short)
+                else if make_case(Ice::Int,    Int)
+                else if make_case(Ice::Long,   Long)
+                else if make_case(Ice::Float,  Float)
+                else if make_case(Ice::Double, Double)
+                else
+                {
+                    ARMARX_CHECK_EXPRESSION(false)
+                            << "This code sould be unreachable! "
+                               "The type of "
+                            << valData.fields.at(i).name
+                            << " is not handled correctly!";
+                }
+                #undef make_case
+                //*INDENT-ON*
+            }
+            return result;
+        };
+
+        //get logged sensor device values
+        {
+            ARMARX_TRACE;
+            streamingEntry.sensDevs.reserve(sensorDeviceValueMetaData.size());
+            for (const auto& valData : sensorDeviceValueMetaData)
+            {
+                streamingEntry.sensDevs.emplace_back(
+                    handleVal(valData, streamingEntry, result));
+            }
+        }
+        //get logged control device values
+        {
+            ARMARX_TRACE;
+            streamingEntry.ctrlDevs.reserve(controlDeviceValueMetaData.size());
+            for (const auto& devData : controlDeviceValueMetaData)
+            {
+                streamingEntry.ctrlDevs.emplace_back();
+                auto& ctrlDevEntrs = streamingEntry.ctrlDevs.back();
+                ctrlDevEntrs.reserve(devData.size());
+                for (const auto& valData : devData)
+                {
+                    ctrlDevEntrs.emplace_back(
+                        handleVal(valData, streamingEntry, result));
+                }
+            }
+        }
+
+        return result;
+    }
+
+    void Logging::stopDataStreaming(const RobotUnitDataStreaming::ReceiverPrx& receiver, const Ice::Current&)
+    {
+        ARMARX_TRACE;
+        throwIfInControlThread(BOOST_CURRENT_FUNCTION);
+        std::lock_guard<std::mutex> guard {rtLoggingMutex};
+        if (!rtDataStreamingEntry.count(receiver))
+        {
+            throw InvalidArgumentException {"stopDataStreaming called for a nonexistent log"};
+        }
+        ARMARX_INFO_S << "RobotUnit: request to stop DataStreaming for " << receiver->ice_id();
+        rtDataStreamingEntry.at(receiver).stopStreaming = true;
+    }
+
     void Logging::_preFinishRunning()
     {
+        ARMARX_TRACE;
         throwIfInControlThread(BOOST_CURRENT_FUNCTION);
         defaultLogHandle = nullptr;
         if (rtLoggingTask)
@@ -294,6 +448,7 @@ namespace armarx::RobotUnitModule
 
     void Logging::_preFinishControlThreadInitialization()
     {
+        ARMARX_TRACE;
         throwIfInControlThread(BOOST_CURRENT_FUNCTION);
         controlThreadId = LogSender::getThreadId();
         ControlThreadOutputBuffer::RtLoggingInstance = &(_module<ControlThreadDataBuffer>().getControlThreadOutputBuffer());
@@ -304,6 +459,7 @@ namespace armarx::RobotUnitModule
 
     void Logging::doLogging()
     {
+        ARMARX_TRACE;
         throwIfInControlThread(BOOST_CURRENT_FUNCTION);
         std::lock_guard<std::mutex> guard {rtLoggingMutex};
         const auto now = IceUtil::Time::now();
@@ -318,117 +474,203 @@ namespace armarx::RobotUnitModule
         }
         //log all
         {
+            ARMARX_TRACE;
+            if (!rtLoggingEntries.empty() || !rtDataStreamingEntry.empty())
+            {
+                ARMARX_INFO << deactivateSpam()
+                            << "Number of logs    " << rtLoggingEntries.size() << '\n'
+                            << "Number of streams " << rtDataStreamingEntry.size();
+            }
             _module<ControlThreadDataBuffer>().getControlThreadOutputBuffer().foreachNewLoggingEntry(
-                [&](const ControlThreadOutputBuffer::Entry & data)
+                [&](const auto & data, auto i, auto num)
+            {
+                doLogging(now, data, i, num);
+            }
+            );
+        }
+        ARMARX_DEBUG_S << ::deactivateSpam() << "the last " << backlog.size() << " iterations are stored";
+        //flush all files
+        {
+            for (auto& pair : rtLoggingEntries)
+            {
+                pair.second->stream << std::flush;
+            }
+        }
+
+        //remove entries
+        {
+            ARMARX_TRACE;
+            std::vector<std::string> toRemove;
+            toRemove.reserve(rtLoggingEntries.size());
+            for (auto& [key, value] : rtLoggingEntries)
             {
-                //base (marker;iteration;timestamp)
+                if (value->stopLogging)
                 {
-                    for (auto& pair : rtLoggingEntries)
-                    {
-                        CSVLoggingEntry& e = *pair.second;
-                        e.stream << "\n"
-                                 << e.marker << ";"
-                                 << data.iteration << ";"
-                                 << data.sensorValuesTimestamp.toMicroSeconds();
-                        e.marker.clear();
-                    }
+                    //can't remove the current elemet
+                    //(this would invalidate the current iterator)
+                    toRemove.emplace_back(key);
                 }
-                //sens
+            }
+            for (const auto& rem : toRemove)
+            {
+                rtLoggingEntries.erase(rem);
+            }
+        }
+        //deal with data streaming
+        {
+            ARMARX_TRACE;
+            std::vector<RobotUnitDataStreaming::ReceiverPrx> toRemove;
+            toRemove.reserve(rtDataStreamingEntry.size());
+            for (auto& [prx, data] : rtDataStreamingEntry)
+            {
+                if (data.stopStreaming)
+                {
+                    toRemove.emplace_back(prx);
+                }
+                else
                 {
-                    //sensors
-                    for (std::size_t idxDev = 0; idxDev < data.sensors.size(); ++ idxDev)
+                    data.send(prx);
+                }
+            }
+            for (const auto& prx : toRemove)
+            {
+                rtDataStreamingEntry.erase(prx);
+            }
+        }
+    }
+
+    void Logging::doLogging(const IceUtil::Time& now, const
+                            ControlThreadOutputBuffer::Entry& data,
+                            std::size_t i, std::size_t num)
+    {
+        ARMARX_TRACE;
+        //header
+        {
+            ARMARX_TRACE;
+            //base (marker;iteration;timestamp)
+            for (auto& [_, e] : rtLoggingEntries)
+            {
+                e->stream << "\n"
+                          << e->marker << ";"
+                          << data.iteration << ";"
+                          << data.sensorValuesTimestamp.toMicroSeconds() << ";"
+                          << data.timeSinceLastIteration.toMicroSeconds();
+                e->marker.clear();
+            }
+            //streaming
+            for (auto& [_, e] : rtDataStreamingEntry)
+            {
+                e.processHeader(data);
+            }
+        }
+        //process devices
+        {
+            //sens
+            {
+                ARMARX_TRACE;
+                //sensors
+                for (std::size_t idxDev = 0; idxDev < data.sensors.size(); ++ idxDev)
+                {
+                    const SensorValueBase* val = data.sensors.at(idxDev);
+                    //dimensions of sensor value (e.g. vel, tor, f_x, f_y, ...)
+                    for (std::size_t idxField = 0; idxField < val->getNumberOfDataFields(); ++ idxField)
                     {
-                        const SensorValueBase* val = data.sensors.at(idxDev);
-                        //dimensions of sensor value (e.g. vel, tor, f_x, f_y, ...)
-                        for (std::size_t idxField = 0; idxField < val->getNumberOfDataFields(); ++ idxField)
+                        std::string str;
+                        val->getDataFieldAs(idxField, str);
+                        for (auto& [_, entry] : rtLoggingEntries)
                         {
-                            const auto str = val->getDataFieldAsString(idxField);
-                            for (auto& [_, entry] : rtLoggingEntries)
+                            if (entry->loggedSensorDeviceValues.at(idxDev).at(idxField))
                             {
-                                if (entry->loggedSensorDeviceValues.at(idxDev).at(idxField))
-                                {
-                                    entry->stream  << ";" << str;
-                                }
+                                entry->stream  << ";" << str;
                             }
                         }
+                        for (auto& [_, data] : rtDataStreamingEntry)
+                        {
+                            data.processSens(*val, idxDev, idxField);
+                        }
                     }
                 }
-                //ctrl
+            }
+            //ctrl
+            {
+                ARMARX_TRACE;
+                //joint controllers
+                for (std::size_t idxDev = 0; idxDev < data.control.size(); ++ idxDev)
                 {
-                    //joint controllers
-                    for (std::size_t idxDev = 0; idxDev < data.control.size(); ++ idxDev)
+                    const auto& vals = data.control.at(idxDev);
+                    //control value (e.g. v_platform)
+                    for (std::size_t idxVal = 0; idxVal < vals.size(); ++idxVal)
                     {
-                        const auto& vals = data.control.at(idxDev);
-                        //control value (e.g. v_platform)
-                        for (std::size_t idxVal = 0; idxVal < vals.size(); ++idxVal)
+                        const ControlTargetBase* val = vals.at(idxVal);
+                        //dimensions of control value (e.g. v_platform_x, v_platform_y, v_platform_rotate)
+                        for (std::size_t idxField = 0; idxField < val->getNumberOfDataFields(); ++ idxField)
                         {
-                            const ControlTargetBase* val = vals.at(idxVal);
-                            //dimensions of control value (e.g. v_platform_x, v_platform_y, v_platform_rotate)
-                            for (std::size_t idxField = 0; idxField < val->getNumberOfDataFields(); ++ idxField)
+                            std::string str;
+                            val->getDataFieldAs(idxField, str);
+                            for (auto& [_, entry] : rtLoggingEntries)
                             {
-                                const auto str = val->getDataFieldAsString(idxField);
-                                for (auto& [_, entry] : rtLoggingEntries)
+                                if (entry->loggedControlDeviceValues.at(idxDev).at(idxVal).at(idxField))
                                 {
-                                    if (entry->loggedControlDeviceValues.at(idxDev).at(idxVal).at(idxField))
-                                    {
-                                        entry->stream  << ";" << str;
-                                    }
+                                    entry->stream  << ";" << str;
                                 }
                             }
+                            for (auto& [_, data] : rtDataStreamingEntry)
+                            {
+                                data.processCtrl(*val, idxDev, idxVal, idxField);
+                            }
                         }
                     }
                 }
-                //store data to backlog
+            }
+        }
+        //finish processing
+        {
+            //store data to backlog
+            {
+                ARMARX_TRACE;
+                if (data.writeTimestamp + rtLoggingBacklogRetentionTime >= now)
                 {
-                    if (data.writeTimestamp + rtLoggingBacklogRetentionTime >= now)
-                    {
-                        backlog.emplace_back(data, true); //true for minimal copy
-                    }
+                    backlog.emplace_back(data, true); //true for minimal copy
                 }
-                //print + reset messages
+            }
+            //print + reset messages
+            {
+                ARMARX_TRACE;
+                for (const ::armarx::detail::RtMessageLogEntryBase* ptr : data.messages.getEntries())
                 {
-                    for (const ::armarx::detail::RtMessageLogEntryBase* ptr : data.messages.getEntries())
+                    if (!ptr)
                     {
-                        if (!ptr)
-                        {
-                            break;
-                        }
-                        ptr->print(controlThreadId);
+                        break;
                     }
+                    ptr->print(controlThreadId);
                 }
-            });
-        }
-        ARMARX_DEBUG_S << ::deactivateSpam() << "the last " << backlog.size() << " iterations are stored";
-        //flush all files
-        {
-            for (auto& pair : rtLoggingEntries)
-            {
-                pair.second->stream << std::flush;
             }
         }
+    }
 
-        //remove entries
+    bool Logging::MatchName(const std::string& pattern, const std::string& name)
+    {
+        ARMARX_TRACE;
+        if (pattern.empty())
         {
-            std::vector<std::string> toRemove;
-            toRemove.reserve(rtLoggingEntries.size());
-            for (auto& pair : rtLoggingEntries)
-            {
-                if (pair.second->stopLogging)
-                {
-                    //can't remove the current elemet
-                    //(this would invalidate the current iterator)
-                    toRemove.emplace_back(pair.first);
-                }
-            }
-            for (const auto& rem : toRemove)
-            {
-                rtLoggingEntries.erase(rem);
-            }
+            return false;
+        }
+        static const std::regex pattern_regex{R"(^\^?[- ._*a-zA-Z0-9]+\$?$)"};
+        if (!std::regex_match(pattern, pattern_regex))
+        {
+            throw InvalidArgumentException {"Pattern '" + pattern + "' is invalid"};
         }
+        static const std::regex reg_dot{"[.]"};
+        static const std::regex reg_star{"[*]"};
+        const std::string rpl1 = std::regex_replace(pattern, reg_dot,  "\\.");
+        const std::string rpl2 = std::regex_replace(rpl1,    reg_star, ".*");
+        const std::regex key_regex{rpl2};
+        return std::regex_search(name, key_regex);
     }
 
     void Logging::_postOnInitRobotUnit()
     {
+        ARMARX_TRACE;
         throwIfInControlThread(BOOST_CURRENT_FUNCTION);
         rtLoggingTimestep = getProperty<std::size_t>("RTLogging_PeriodMs");
         ARMARX_CHECK_LESS(0, rtLoggingTimestep) << "The property RTLoggingPeriodMs must not be 0";
@@ -448,9 +690,11 @@ namespace armarx::RobotUnitModule
 
     void Logging::_postFinishDeviceInitialization()
     {
+        ARMARX_TRACE;
         throwIfInControlThread(BOOST_CURRENT_FUNCTION);
         //init buffer
         {
+            ARMARX_TRACE;
             std::size_t ctrlThreadPeriodUs = static_cast<std::size_t>(getControlThreadTargetPeriod().toMicroSeconds());
             std::size_t logThreadPeriodUs = rtLoggingTimestep * 1000;
             std::size_t nBuffers = (logThreadPeriodUs / ctrlThreadPeriodUs + 1) * 100;
@@ -463,51 +707,54 @@ namespace armarx::RobotUnitModule
                         << nBuffers << "buffers "
                         << "(buffersize = " << bufferSize << " bytes)";
         }
-        //init logging names
+        //init logging names + field types
         {
+            ARMARX_TRACE;
+            const auto makeValueMetaData = [&](auto * val, const std::string & namePre)
+            {
+                ValueMetaData data;
+                const auto names = val->getDataFieldNames();
+                data.fields.resize(names.size());
+                for (const auto& [fieldIdx, fieldName] : MakeIndexedContainer(names))
+                {
+                    data.fields.at(fieldIdx).name = namePre + '.' + fieldName;
+                    data.fields.at(fieldIdx).type = &(val->getDataFieldType(fieldIdx));
+                }
+                return data;
+            };
+
             //sensorDevices
-            controlDeviceValueLoggingNames.reserve(_module<Devices>().getControlDevices().size());
+            controlDeviceValueMetaData.reserve(_module<Devices>().getControlDevices().size());
             for (const auto& cd : _module<Devices>().getControlDevices().values())
             {
-                controlDeviceValueLoggingNames.emplace_back();
-                auto& namesForDev = controlDeviceValueLoggingNames.back();
-                namesForDev.reserve(cd->getJointControllers().size());
+                ARMARX_TRACE;
+                controlDeviceValueMetaData.emplace_back();
+                auto& dataForDev = controlDeviceValueMetaData.back();
+                dataForDev.reserve(cd->getJointControllers().size());
                 for (auto jointC : cd->getJointControllers())
                 {
-                    const auto names = jointC->getControlTarget()->getDataFieldNames();
-                    namesForDev.emplace_back();
-                    auto& fullNames = namesForDev.back();
-                    fullNames.reserve(names.size());
-                    for (const auto& name :  names)
-                    {
-                        fullNames.emplace_back(
-                            "ctrl." +
-                            cd->getDeviceName() + "." +
-                            jointC->getControlMode() + "." +
-                            name);
-                    }
+                    dataForDev.emplace_back(
+                        makeValueMetaData(jointC->getControlTarget(),
+                                          "ctrl." +
+                                          cd->getDeviceName() + "." +
+                                          jointC->getControlMode()));
                 }
             }
             //sensorDevices
-            sensorDeviceValueLoggingNames.reserve(_module<Devices>().getSensorDevices().size());
+            sensorDeviceValueMetaData.reserve(_module<Devices>().getSensorDevices().size());
             for (const auto& sd : _module<Devices>().getSensorDevices().values())
             {
-                const auto names = sd->getSensorValue()->getDataFieldNames();
-                sensorDeviceValueLoggingNames.emplace_back();
-                auto& fullNames = sensorDeviceValueLoggingNames.back();
-                fullNames.reserve(names.size());
-                for (const auto& name :  names)
-                {
-                    fullNames.emplace_back(
-                        "sens." +
-                        sd->getDeviceName() + "." +
-                        name);
-                }
+                ARMARX_TRACE;
+                sensorDeviceValueMetaData.emplace_back(
+                    makeValueMetaData(sd->getSensorValue(),
+                                      "sens." +
+                                      sd->getDeviceName()));
             }
         }
         //start logging thread is done in rtinit
         //maybe add the default log
         {
+            ARMARX_TRACE;
             const auto loggingpath = getProperty<std::string>("RTLogging_DefaultLog").getValue();
             if (!loggingpath.empty())
             {
@@ -518,4 +765,117 @@ namespace armarx::RobotUnitModule
         rtLoggingTask = new RTLoggingTaskT([&] {doLogging();}, rtLoggingTimestep, false, getName() + "_RTLoggingTask");
         rtLoggingTask->setDelayWarningTolerance(rtLoggingTimestep * 10);
     }
+
+    void Logging::DataStreamingEntry::processHeader(const ControlThreadOutputBuffer::Entry& e)
+    {
+        ARMARX_TRACE;
+        if (stopStreaming)
+        {
+            return;
+        }
+        result.emplace_back();
+        auto& data = result.back();
+        data.iterationId                 = e.iteration;
+        data.timestampUSec               = e.sensorValuesTimestamp.toMicroSeconds();
+        data.timesSinceLastIterationUSec = e.timeSinceLastIteration.toMicroSeconds();
+
+        data.bools  .resize(numBools);
+        data.bytes  .resize(numBytes);
+        data.shorts .resize(numShorts);
+        data.ints   .resize(numInts);
+        data.longs  .resize(numLongs);
+        data.floats .resize(numFloats);
+        data.doubles.resize(numDoubles);
+
+    }
+
+    void WriteTo(const Logging::DataStreamingEntry::OutVal& out,
+                 const auto& val,
+                 std::size_t fidx,
+                 auto& data)
+    {
+        ARMARX_TRACE;
+        using enum_t = Logging::DataStreamingEntry::ValueT;
+        switch (out.value)
+        {
+            case enum_t::Bool   :
+                bool b;
+                val.getDataFieldAs(fidx, b);
+                data.bools.at(out.idx) = b;
+                return;
+            case enum_t::Byte   :
+                val.getDataFieldAs(fidx, data.bytes.at(out.idx));
+                return;
+            case enum_t::Short  :
+                val.getDataFieldAs(fidx, data.shorts.at(out.idx));
+                return;
+            case enum_t::Int    :
+                val.getDataFieldAs(fidx, data.ints.at(out.idx));
+                return;
+            case enum_t::Long   :
+                val.getDataFieldAs(fidx, data.longs.at(out.idx));
+                return;
+            case enum_t::Float  :
+                val.getDataFieldAs(fidx, data.floats.at(out.idx));
+                return;
+            case enum_t::Double :
+                val.getDataFieldAs(fidx, data.doubles.at(out.idx));
+                return;
+            case enum_t::Skipped:
+                return;
+        }
+    }
+
+    void Logging::DataStreamingEntry::processCtrl(
+        const ControlTargetBase& val,
+        std::size_t didx,
+        std::size_t vidx,
+        std::size_t fidx)
+    {
+        ARMARX_TRACE;
+        if (stopStreaming)
+        {
+            return;
+        }
+        auto& data = result.back();
+        const OutVal& o = ctrlDevs.at(didx).at(vidx).at(fidx);
+        WriteTo(o, val, fidx, data);
+    }
+
+    void Logging::DataStreamingEntry::processSens(
+        const SensorValueBase& val,
+        std::size_t didx,
+        std::size_t fidx)
+    {
+        ARMARX_TRACE;
+        if (stopStreaming)
+        {
+            return;
+        }
+        auto& data = result.back();
+        const OutVal& o = sensDevs.at(didx).at(fidx);
+        WriteTo(o, val, fidx, data);
+    }
+
+    void Logging::DataStreamingEntry::send(const RobotUnitDataStreaming::ReceiverPrx& r)
+    {
+        ARMARX_TRACE;
+        try
+        {
+            r->update(result);
+            connectionFailures = 0;
+            result.clear();
+        }
+        catch (...)
+        {
+            ARMARX_TRACE;
+            ++connectionFailures;
+            if (connectionFailures > 10) ///TODO make property
+            {
+                stopStreaming = true;
+                ARMARX_WARNING_S << "DataStreaming Receiver was not reachable for "
+                                 << connectionFailures << " iterations! Removing receiver";
+            }
+        }
+    }
 }
diff --git a/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleLogging.h b/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleLogging.h
index 68cc02b917827edbb5442a7ef28d7e47d50d3776..2df9d88d2d8d497d12985fca320c95a8ea0e5576 100644
--- a/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleLogging.h
+++ b/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleLogging.h
@@ -150,12 +150,24 @@ namespace armarx::RobotUnitModule
           */
         void writeRecentIterationsToFile(const std::string& formatString, const Ice::Current& = Ice::emptyCurrent) const override;
 
+        RobotUnitDataStreaming::DataStreamingDescription startDataStreaming(
+            const RobotUnitDataStreaming::ReceiverPrx& receiver,
+            const RobotUnitDataStreaming::Config&      config,
+            const Ice::Current& = Ice::emptyCurrent) override;
+
+        void stopDataStreaming(
+            const RobotUnitDataStreaming::ReceiverPrx& receiver,
+            const Ice::Current& = Ice::emptyCurrent) override;
         // //////////////////////////////////////////////////////////////////////////////////////// //
         // //////////////////////////////////// implementation //////////////////////////////////// //
         // //////////////////////////////////////////////////////////////////////////////////////// //
     private:
         /// @brief Executes the logging loop.
         void doLogging();
+        void doLogging(const IceUtil::Time& now,
+                       const ControlThreadOutputBuffer::Entry& data,
+                       std::size_t i, std::size_t num);
+        static bool MatchName(const std::string& pattern, const std::string& name);
 
         // //////////////////////////////////////////////////////////////////////////////////////// //
         // ///////////////////////////////////////// Data ///////////////////////////////////////// //
@@ -180,6 +192,54 @@ namespace armarx::RobotUnitModule
             std::string marker;
         };
 
+        struct DataStreamingEntry
+        {
+            enum class ValueT
+            {
+                Bool,
+                Byte,
+                Short,
+                Int,
+                Long,
+                Float,
+                Double,
+                Skipped
+            };
+            struct OutVal
+            {
+                std::size_t idx;
+                ValueT      value = ValueT::Skipped;
+            };
+
+            bool        stopStreaming      = false;
+
+            std::size_t numBools   = 0;
+            std::size_t numBytes   = 0;
+            std::size_t numShorts  = 0;
+            std::size_t numInts    = 0;
+            std::size_t numLongs   = 0;
+            std::size_t numFloats  = 0;
+            std::size_t numDoubles = 0;
+
+            bool        onlyNewestFrame    = false;
+            std::size_t connectionFailures = 0;
+
+            std::vector<std::vector<OutVal>>              sensDevs;
+            std::vector<std::vector<std::vector<OutVal>>> ctrlDevs;
+
+            RobotUnitDataStreaming::TimeStepSeq           result;
+            void processHeader(const ControlThreadOutputBuffer::Entry& e);
+            void processCtrl(const ControlTargetBase& val,
+                             std::size_t didx,
+                             std::size_t vidx,
+                             std::size_t fidx);
+            void processSens(const SensorValueBase& val,
+                             std::size_t didx,
+                             std::size_t fidx);
+            void send(const RobotUnitDataStreaming::ReceiverPrx& r);
+        };
+        std::map<RobotUnitDataStreaming::ReceiverPrx, DataStreamingEntry> rtDataStreamingEntry;
+
         /// @brief The thread executing the logging functions.
         RTLoggingTaskT::pointer_type rtLoggingTask;
         /// @brief All entries for logging.
@@ -192,10 +252,21 @@ namespace armarx::RobotUnitModule
         Ice::Int controlThreadId {0};
         /// @brief Mutex protecting the data structures of this class
         mutable std::mutex rtLoggingMutex;
-        /// @brief Data field names for all \ref ControlTargetBase "ControlTargets"
-        std::vector<std::vector<std::vector<std::string>>> controlDeviceValueLoggingNames;
-        /// @brief Data field names for all \ref SensorValueBase "SensorValues"
-        std::vector<std::vector<            std::string >> sensorDeviceValueLoggingNames;
+
+        struct ValueMetaData
+        {
+            struct FieldMetaData
+            {
+                std::string           name;
+                const std::type_info* type;
+            };
+            std::vector<FieldMetaData> fields;
+        };
+
+        /// @brief Data field info for all \ref ControlTargetBase "ControlTargets" (dex x jctrl)
+        std::vector<std::vector<ValueMetaData>> controlDeviceValueMetaData;
+        /// @brief Data field info for all \ref SensorValueBase "SensorValues" (dev)
+        std::vector<            ValueMetaData > sensorDeviceValueMetaData;
 
         /// @brief The initial size of the Message entry buffer
         std::size_t messageBufferSize {0};
diff --git a/source/RobotAPI/components/units/RobotUnit/SensorValues/SensorValueBase.h b/source/RobotAPI/components/units/RobotUnit/SensorValues/SensorValueBase.h
index e378603fc90b365fe739a03fd60e76e34d913c9d..18d537b291f6c204036ec14e467a92e9660144df 100644
--- a/source/RobotAPI/components/units/RobotUnit/SensorValues/SensorValueBase.h
+++ b/source/RobotAPI/components/units/RobotUnit/SensorValues/SensorValueBase.h
@@ -91,7 +91,15 @@ namespace armarx
 
         virtual std::size_t getNumberOfDataFields() const = 0;
         virtual std::vector<std::string> getDataFieldNames() const = 0;
-        virtual std::string getDataFieldAsString(std::size_t i) const = 0;
+        virtual void getDataFieldAs(std::size_t i, bool&        out) const = 0;
+        virtual void getDataFieldAs(std::size_t i, Ice::Byte&   out) const = 0;
+        virtual void getDataFieldAs(std::size_t i, Ice::Short&  out) const = 0;
+        virtual void getDataFieldAs(std::size_t i, Ice::Int&    out) const = 0;
+        virtual void getDataFieldAs(std::size_t i, Ice::Long&   out) const = 0;
+        virtual void getDataFieldAs(std::size_t i, Ice::Float&  out) const = 0;
+        virtual void getDataFieldAs(std::size_t i, Ice::Double& out) const = 0;
+        virtual void getDataFieldAs(std::size_t i, std::string& out) const = 0;
+        virtual const std::type_info& getDataFieldType(std::size_t i) const = 0;
 
         //management functions
         template<class T, class = typename std::enable_if<std::is_base_of<SensorValueBase, T>::value>::type>
@@ -130,9 +138,41 @@ namespace armarx
     {                                                                                               \
         return SensorValueInfo<std::decay<decltype(*this)>::type>::GetNumberOfDataFields();         \
     }                                                                                               \
-    std::string getDataFieldAsString(std::size_t i) const override                                  \
+    void getDataFieldAs (std::size_t i, bool&        out) const override                            \
     {                                                                                               \
-        return SensorValueInfo<std::decay<decltype(*this)>::type>::GetDataFieldAsString(this, i);   \
+        SensorValueInfo<std::decay<decltype(*this)>::type>::GetDataFieldAs (this, i, out);          \
+    }                                                                                               \
+    void getDataFieldAs (std::size_t i, Ice::Byte&   out) const override                            \
+    {                                                                                               \
+        SensorValueInfo<std::decay<decltype(*this)>::type>::GetDataFieldAs (this, i, out);          \
+    }                                                                                               \
+    void getDataFieldAs (std::size_t i, Ice::Short&  out) const override                            \
+    {                                                                                               \
+        SensorValueInfo<std::decay<decltype(*this)>::type>::GetDataFieldAs (this, i, out);          \
+    }                                                                                               \
+    void getDataFieldAs (std::size_t i, Ice::Int&    out) const override                            \
+    {                                                                                               \
+        SensorValueInfo<std::decay<decltype(*this)>::type>::GetDataFieldAs (this, i, out);          \
+    }                                                                                               \
+    void getDataFieldAs (std::size_t i, Ice::Long&   out) const override                            \
+    {                                                                                               \
+        SensorValueInfo<std::decay<decltype(*this)>::type>::GetDataFieldAs (this, i, out);          \
+    }                                                                                               \
+    void getDataFieldAs (std::size_t i, Ice::Float&  out) const override                            \
+    {                                                                                               \
+        SensorValueInfo<std::decay<decltype(*this)>::type>::GetDataFieldAs (this, i, out);          \
+    }                                                                                               \
+    void getDataFieldAs (std::size_t i, Ice::Double& out) const override                            \
+    {                                                                                               \
+        SensorValueInfo<std::decay<decltype(*this)>::type>::GetDataFieldAs (this, i, out);          \
+    }                                                                                               \
+    void getDataFieldAs (std::size_t i, std::string& out) const override                            \
+    {                                                                                               \
+        SensorValueInfo<std::decay<decltype(*this)>::type>::GetDataFieldAs (this, i, out);          \
+    }                                                                                               \
+    const std::type_info& getDataFieldType(std::size_t i) const override                            \
+    {                                                                                               \
+        return SensorValueInfo<std::decay<decltype(*this)>::type>::GetDataFieldType(i);             \
     }                                                                                               \
     std::vector<std::string> getDataFieldNames() const override                                     \
     {                                                                                               \
diff --git a/source/RobotAPI/components/units/RobotUnit/util/ControlThreadOutputBuffer.cpp b/source/RobotAPI/components/units/RobotUnit/util/ControlThreadOutputBuffer.cpp
index e753f9c4b60b13533dc2cfa20e6494a1d106ba1a..8f038519bc03b014aef5219bb939e1acf03d55af 100644
--- a/source/RobotAPI/components/units/RobotUnit/util/ControlThreadOutputBuffer.cpp
+++ b/source/RobotAPI/components/units/RobotUnit/util/ControlThreadOutputBuffer.cpp
@@ -71,7 +71,7 @@ namespace armarx
         onePastLoggingReadPosition = writePosition.load();
     }
 
-    void ControlThreadOutputBuffer::foreachNewLoggingEntry(std::function<void (const ControlThreadOutputBuffer::Entry&)> consumer)
+    void ControlThreadOutputBuffer::foreachNewLoggingEntry(ConsumerFunctor consumer)
     {
         ARMARX_CHECK_EXPRESSION(isInitialized);
         if (writePosition - onePastLoggingReadPosition >= numEntries)
@@ -87,10 +87,15 @@ namespace armarx
         auto numNewEntries = writePosition - onePastLoggingReadPosition;
         ARMARX_CHECK_EXPRESSION(numNewEntries < numEntries);
         //consume all
-        for (; onePastLoggingReadPosition < writePosition; ++onePastLoggingReadPosition)
+        const std::size_t num = writePosition - onePastLoggingReadPosition;
+        for (
+            std::size_t offset = 0;
+            onePastLoggingReadPosition < writePosition;
+            ++onePastLoggingReadPosition, ++offset
+        )
         {
             auto& entry = entries.at(toBounds(onePastLoggingReadPosition));
-            consumer(entry);
+            consumer(entry, offset, num);
             entry.messages.reset(messageBufferSize, messageBufferEntries, entry.iteration);
 
             //update how many
diff --git a/source/RobotAPI/components/units/RobotUnit/util/ControlThreadOutputBuffer.h b/source/RobotAPI/components/units/RobotUnit/util/ControlThreadOutputBuffer.h
index 6412aaba778c5137020f43ae7e9efadf3e69c640..1709023ec2cc788dd4fa9664dbe6739746bad4ae 100644
--- a/source/RobotAPI/components/units/RobotUnit/util/ControlThreadOutputBuffer.h
+++ b/source/RobotAPI/components/units/RobotUnit/util/ControlThreadOutputBuffer.h
@@ -221,6 +221,7 @@ namespace armarx
     {
         using Entry = detail::ControlThreadOutputBufferEntry;
         using RtMessageLogEntryBase = detail::RtMessageLogEntryBase;
+        using ConsumerFunctor = std::function<void (const Entry&, std::size_t, std::size_t)>;
         std::size_t initialize(
             std::size_t numEntries,
             const KeyValueVector<std::string, ControlDevicePtr>& controlDevices,
@@ -245,7 +246,7 @@ namespace armarx
 
         //logging read
         void resetLoggingPosition()  const;
-        void foreachNewLoggingEntry(std::function<void(const Entry&)> consumer);
+        void foreachNewLoggingEntry(ConsumerFunctor consumer);
 
         std::size_t getNumberOfBytes() const;
 
diff --git a/source/RobotAPI/components/units/RobotUnit/util/introspection/ClassMemberInfo.h b/source/RobotAPI/components/units/RobotUnit/util/introspection/ClassMemberInfo.h
index 65e8980af45c0a202787d0220e89bf7cf0313ea1..554b1ae3f27be04d0566d8306d8c7859f497f902 100644
--- a/source/RobotAPI/components/units/RobotUnit/util/introspection/ClassMemberInfo.h
+++ b/source/RobotAPI/components/units/RobotUnit/util/introspection/ClassMemberInfo.h
@@ -55,10 +55,39 @@ namespace armarx::introspection
         /// @brief Get all entries for member variables
         static const KeyValueVector<std::string, Entry>& GetEntries();
         static std::size_t GetNumberOfDataFields();
-        static std::string GetDataFieldAsString(const ClassType* ptr, std::size_t i);
+        static void GetDataFieldAs(const ClassType* ptr, std::size_t i, bool&        out);
+        static void GetDataFieldAs(const ClassType* ptr, std::size_t i, Ice::Byte&   out);
+        static void GetDataFieldAs(const ClassType* ptr, std::size_t i, Ice::Short&  out);
+        static void GetDataFieldAs(const ClassType* ptr, std::size_t i, Ice::Int&    out);
+        static void GetDataFieldAs(const ClassType* ptr, std::size_t i, Ice::Long&   out);
+        static void GetDataFieldAs(const ClassType* ptr, std::size_t i, Ice::Float&  out);
+        static void GetDataFieldAs(const ClassType* ptr, std::size_t i, Ice::Double& out);
+        static void GetDataFieldAs(const ClassType* ptr, std::size_t i, std::string& out);
+        static const std::type_info& GetDataFieldType(std::size_t i);
         static std::vector<std::string> GetDataFieldNames();
 
         static std::map<std::string, VariantBasePtr> ToVariants(const IceUtil::Time& timestamp, const CommonBaseT* ptr);
+    private:
+        template<class T>
+        static auto MakeConverter()
+        {
+            std::vector<std::function<void(const ClassType*, T&)>> functions;
+
+            for (std::size_t idxEntr = 0; idxEntr < GetEntries().size(); ++idxEntr)
+            {
+                for (std::size_t idxField = 0; idxField < GetEntries().at(idxEntr).getNumberOfFields(); ++idxField)
+                {
+                    functions.emplace_back(
+                        [idxEntr, idxField](const ClassType * classptr, T & out)
+                    {
+                        const Entry& e = GetEntries().at(idxEntr);
+                        e.getDataFieldAs(idxField, classptr, out);
+                    });
+                }
+            }
+            ARMARX_CHECK_EQUAL(functions.size(), GetNumberOfDataFields());
+            return functions;
+        }
 
     private:
         KeyValueVector<std::string, Entry> entries;
@@ -174,28 +203,81 @@ namespace armarx::introspection
     }
 
     template<class CommonBaseT, class ClassT>
-    std::string ClassMemberInfo<CommonBaseT, ClassT>::GetDataFieldAsString(const ClassType* ptr, std::size_t i)
+    void ClassMemberInfo<CommonBaseT, ClassT>::GetDataFieldAs(const ClassType* ptr, std::size_t i, bool&        out)
+    {
+        static const auto convert = MakeConverter<bool>();
+        ARMARX_CHECK_LESS(i, GetNumberOfDataFields());
+        convert.at(i)(ptr, out);
+    }
+    template<class CommonBaseT, class ClassT>
+    void ClassMemberInfo<CommonBaseT, ClassT>::GetDataFieldAs(const ClassType* ptr, std::size_t i, Ice::Byte&   out)
+    {
+        static const auto convert = MakeConverter<Ice::Byte>();
+        ARMARX_CHECK_LESS(i, GetNumberOfDataFields());
+        convert.at(i)(ptr, out);
+    }
+    template<class CommonBaseT, class ClassT>
+    void ClassMemberInfo<CommonBaseT, ClassT>::GetDataFieldAs(const ClassType* ptr, std::size_t i, Ice::Short&  out)
+    {
+        static const auto convert = MakeConverter<Ice::Short>();
+        ARMARX_CHECK_LESS(i, GetNumberOfDataFields());
+        convert.at(i)(ptr, out);
+    }
+    template<class CommonBaseT, class ClassT>
+    void ClassMemberInfo<CommonBaseT, ClassT>::GetDataFieldAs(const ClassType* ptr, std::size_t i, Ice::Int&    out)
+    {
+        static const auto convert = MakeConverter<Ice::Int>();
+        ARMARX_CHECK_LESS(i, GetNumberOfDataFields());
+        convert.at(i)(ptr, out);
+    }
+    template<class CommonBaseT, class ClassT>
+    void ClassMemberInfo<CommonBaseT, ClassT>::GetDataFieldAs(const ClassType* ptr, std::size_t i, Ice::Long&   out)
+    {
+        static const auto convert = MakeConverter<Ice::Long>();
+        ARMARX_CHECK_LESS(i, GetNumberOfDataFields());
+        convert.at(i)(ptr, out);
+    }
+    template<class CommonBaseT, class ClassT>
+    void ClassMemberInfo<CommonBaseT, ClassT>::GetDataFieldAs(const ClassType* ptr, std::size_t i, Ice::Float&  out)
+    {
+        static const auto convert = MakeConverter<Ice::Float>();
+        ARMARX_CHECK_LESS(i, GetNumberOfDataFields());
+        convert.at(i)(ptr, out);
+    }
+    template<class CommonBaseT, class ClassT>
+    void ClassMemberInfo<CommonBaseT, ClassT>::GetDataFieldAs(const ClassType* ptr, std::size_t i, Ice::Double& out)
+    {
+        static const auto convert = MakeConverter<Ice::Double>();
+        ARMARX_CHECK_LESS(i, GetNumberOfDataFields());
+        convert.at(i)(ptr, out);
+    }
+    template<class CommonBaseT, class ClassT>
+    void ClassMemberInfo<CommonBaseT, ClassT>::GetDataFieldAs(const ClassType* ptr, std::size_t i, std::string& out)
+    {
+        static const auto convert = MakeConverter<std::string>();
+        ARMARX_CHECK_LESS(i, GetNumberOfDataFields());
+        convert.at(i)(ptr, out);
+    }
+
+    template<class CommonBaseT, class ClassT>
+    const std::type_info& ClassMemberInfo<CommonBaseT, ClassT>::GetDataFieldType(std::size_t i)
     {
-        static const auto toString = []
+        static const auto convert = []
         {
-            std::vector<std::function<std::string(const ClassType*)>> functions;
+            std::vector<const std::type_info*> data;
 
             for (std::size_t idxEntr = 0; idxEntr < GetEntries().size(); ++idxEntr)
             {
+                const Entry& e = GetEntries().at(idxEntr);
                 for (std::size_t idxField = 0; idxField < GetEntries().at(idxEntr).getNumberOfFields(); ++idxField)
                 {
-                    functions.emplace_back(
-                        [idxEntr, idxField](const ClassType * classptr)
-                    {
-                        const Entry& e = GetEntries().at(idxEntr);
-                        return e.getFieldAsString(idxField, classptr);
-                    });
+                    data.emplace_back(&e.getFieldTypeId(idxField));
                 }
             }
-            ARMARX_CHECK_EQUAL(functions.size(), GetNumberOfDataFields());
-            return functions;
+            ARMARX_CHECK_EQUAL(data.size(), GetNumberOfDataFields());
+            return data;
         }();
         ARMARX_CHECK_LESS(i, GetNumberOfDataFields());
-        return toString.at(i)(ptr);
+        return *convert.at(i);
     }
 }
diff --git a/source/RobotAPI/components/units/RobotUnit/util/introspection/ClassMemberInfoEntry.h b/source/RobotAPI/components/units/RobotUnit/util/introspection/ClassMemberInfoEntry.h
index 1f503de0562a64730dffb2c7f18749a7b7b63862..6188648d33e64d86dbac8a168446bbe5127e6339 100644
--- a/source/RobotAPI/components/units/RobotUnit/util/introspection/ClassMemberInfoEntry.h
+++ b/source/RobotAPI/components/units/RobotUnit/util/introspection/ClassMemberInfoEntry.h
@@ -47,7 +47,7 @@ namespace armarx::introspection
             memberName {memberName},
             memberTypeName {GetTypeString<MemberType>()},
             numberOfFields {DataFieldsInfo<MemberType>::GetNumberOfFields()},
-            fieldToString {MakeFieldToStringFunctors<ClassType>(numberOfFields, ptr)},
+            fieldToType {MakeFieldToTypeFunctors<ClassType>(numberOfFields, ptr)},
             toVariants_ {MakeToVariantsFunctor<ClassType>(ptr)}
         {
             ARMARX_CHECK_NOT_EQUAL(0, numberOfFields);
@@ -91,11 +91,58 @@ namespace armarx::introspection
             ARMARX_CHECK_LESS(i, numberOfFields);
             return fieldNames.at(i);
         }
-        std::string getFieldAsString(std::size_t i, const CommonBaseType* ptr) const
+        void getDataFieldAs(std::size_t i, const CommonBaseType* ptr, bool&        out) const
         {
             ARMARX_CHECK_NOT_NULL(ptr);
             ARMARX_CHECK_LESS(i, numberOfFields);
-            return fieldToString.at(i)(ptr);
+            return fieldToType.at(i).toBool(ptr, out);
+        }
+        void getDataFieldAs(std::size_t i, const CommonBaseType* ptr, Ice::Byte&   out) const
+        {
+            ARMARX_CHECK_NOT_NULL(ptr);
+            ARMARX_CHECK_LESS(i, numberOfFields);
+            return fieldToType.at(i).toByte(ptr, out);
+        }
+        void getDataFieldAs(std::size_t i, const CommonBaseType* ptr, Ice::Short&  out) const
+        {
+            ARMARX_CHECK_NOT_NULL(ptr);
+            ARMARX_CHECK_LESS(i, numberOfFields);
+            return fieldToType.at(i).toShort(ptr, out);
+        }
+        void getDataFieldAs(std::size_t i, const CommonBaseType* ptr, Ice::Int&    out) const
+        {
+            ARMARX_CHECK_NOT_NULL(ptr);
+            ARMARX_CHECK_LESS(i, numberOfFields);
+            return fieldToType.at(i).toInt(ptr, out);
+        }
+        void getDataFieldAs(std::size_t i, const CommonBaseType* ptr, Ice::Long&   out) const
+        {
+            ARMARX_CHECK_NOT_NULL(ptr);
+            ARMARX_CHECK_LESS(i, numberOfFields);
+            return fieldToType.at(i).toLong(ptr, out);
+        }
+        void getDataFieldAs(std::size_t i, const CommonBaseType* ptr, Ice::Float&  out) const
+        {
+            ARMARX_CHECK_NOT_NULL(ptr);
+            ARMARX_CHECK_LESS(i, numberOfFields);
+            return fieldToType.at(i).toFloat(ptr, out);
+        }
+        void getDataFieldAs(std::size_t i, const CommonBaseType* ptr, Ice::Double& out) const
+        {
+            ARMARX_CHECK_NOT_NULL(ptr);
+            ARMARX_CHECK_LESS(i, numberOfFields);
+            return fieldToType.at(i).toDouble(ptr, out);
+        }
+        void getDataFieldAs(std::size_t i, const CommonBaseType* ptr, std::string& out) const
+        {
+            ARMARX_CHECK_NOT_NULL(ptr);
+            ARMARX_CHECK_LESS(i, numberOfFields);
+            return fieldToType.at(i).toString(ptr, out);
+        }
+        const std::type_info& getFieldTypeId(std::size_t i) const
+        {
+            ARMARX_CHECK_LESS(i, numberOfFields);
+            return *fieldToType.at(i).typeId;
         }
 
         //variants
@@ -110,25 +157,49 @@ namespace armarx::introspection
                                           const ClassMemberInfoEntry* thisptr,
                                           const IceUtil::Time&,
                                           const CommonBaseType*) >;
-        using FieldToStringFunctorType = std::function<std::string(const CommonBaseType*)>;
+        struct FieldToType
+        {
+            template<class T>
+            using FieldToFunctorType = std::function<void(const CommonBaseType*, T&)>;
+            FieldToFunctorType<bool>        toBool;
+            FieldToFunctorType<Ice::Byte>   toByte;
+            FieldToFunctorType<Ice::Short>  toShort;
+            FieldToFunctorType<Ice::Int>    toInt;
+            FieldToFunctorType<Ice::Long>   toLong;
+            FieldToFunctorType<Ice::Float>  toFloat;
+            FieldToFunctorType<Ice::Double> toDouble;
+            FieldToFunctorType<std::string> toString;
+            const std::type_info*           typeId;
+        };
 
         template<class ClassType, class MemberType, class MemberPtrClassType>
-        static std::vector<FieldToStringFunctorType> MakeFieldToStringFunctors(
+        static std::vector<FieldToType> MakeFieldToTypeFunctors(
             std::size_t numberOfFields,
             MemberType MemberPtrClassType::* ptr)
         {
-            std::vector<std::function<std::string(const CommonBaseType*)>> result;
+            std::vector<FieldToType> result;
             result.reserve(numberOfFields);
             for (std::size_t i = 0; i < numberOfFields; ++i)
             {
-                result.emplace_back(
-                    [i, ptr](const CommonBaseType * ptrBase)
-                {
-                    const ClassType* cptr = dynamic_cast<const ClassType*>(ptrBase);
-                    ARMARX_CHECK_NOT_NULL(cptr);
-                    return DataFieldsInfo<MemberType>::GetFieldAsString(i, cptr->*ptr);
-                }
-                );
+                result.emplace_back();
+                auto& fieldData = result.back();
+
+#define make_getter(Type) [i, ptr](const CommonBaseType * ptrBase, Type & out)  \
+    {                                                                           \
+        const ClassType* cptr = dynamic_cast<const ClassType*>(ptrBase);        \
+        ARMARX_CHECK_NOT_NULL(cptr);                                            \
+        DataFieldsInfo<MemberType>::GetDataFieldAs(i, cptr->*ptr, out);         \
+    }
+                fieldData.toBool   = make_getter(bool);
+                fieldData.toByte   = make_getter(Ice::Byte);
+                fieldData.toShort  = make_getter(Ice::Short);
+                fieldData.toInt    = make_getter(Ice::Int);
+                fieldData.toLong   = make_getter(Ice::Long);
+                fieldData.toFloat  = make_getter(Ice::Float);
+                fieldData.toDouble = make_getter(Ice::Double);
+                fieldData.toString = make_getter(std::string);
+#undef make_getter
+                fieldData.typeId   = &DataFieldsInfo<MemberType>::GetDataFieldType(i);
             }
             return result;
         }
@@ -160,7 +231,7 @@ namespace armarx::introspection
         const std::string memberTypeName;
         //elementar subparts
         const std::size_t numberOfFields;
-        const std::vector<FieldToStringFunctorType> fieldToString;
+        const std::vector<FieldToType> fieldToType;
         std::vector<std::string> fieldNames;
         //variants
         ToVariantsFunctorType toVariants_;
diff --git a/source/RobotAPI/components/units/RobotUnit/util/introspection/DataFieldsInfo.cpp b/source/RobotAPI/components/units/RobotUnit/util/introspection/DataFieldsInfo.cpp
index cf3a4e9b0ba5db52287a006a879c0b841778bf29..ff2d751a934f26a400befa995220fd38b2594532 100644
--- a/source/RobotAPI/components/units/RobotUnit/util/introspection/DataFieldsInfo.cpp
+++ b/source/RobotAPI/components/units/RobotUnit/util/introspection/DataFieldsInfo.cpp
@@ -33,15 +33,31 @@
 #include <RobotAPI/interface/units/KinematicUnitInterface.h>
 #include <RobotAPI/interface/units/KinematicUnitInterfaceStdOverloads.h>
 
-
+//Eigen::Vector3f
 namespace armarx::introspection
 {
-    std::string DataFieldsInfo<Eigen::Vector3f, void>::GetFieldAsString(std::size_t i, const Eigen::Vector3f& field)
+    std::size_t DataFieldsInfo<Eigen::Vector3f, void>::GetNumberOfFields()
+    {
+        return 3;
+    }
+    void DataFieldsInfo<Eigen::Vector3f, void>::GetDataFieldAs(std::size_t i, const Eigen::Vector3f& field, std::string& out)
     {
         ARMARX_CHECK_LESS(i, 3);
-        return to_string(field(i));
+        out = to_string(field(i));
+    }
+    void DataFieldsInfo<Eigen::Vector3f, void>::GetDataFieldAs(std::size_t i, const Eigen::Vector3f& field, float& out)
+    {
+        ARMARX_CHECK_LESS(i, 3);
+        out = field(i);
+    }
+    const std::type_info& DataFieldsInfo<Eigen::Vector3f, void>::GetDataFieldType(std::size_t i)
+    {
+        return typeid(float);
+    }
+    std::vector<std::string> DataFieldsInfo<Eigen::Vector3f, void>::GetFieldNames()
+    {
+        return {"x", "y", "z"};
     }
-
     std::map<std::string, VariantBasePtr> DataFieldsInfo<Eigen::Vector3f, void>::ToVariants(
         const Eigen::Vector3f& value,
         const std::string& name,
@@ -57,125 +73,178 @@ namespace armarx::introspection
         return {{name, {new TimedVariant(Vector3{value}, timestamp)}}};
     }
 }
-
+//Eigen::Vector##Num##Type
 namespace armarx::introspection
 {
-#define make_DataFieldsInfo_for_eigen_vector(Type,Num)                                                                              \
-    std::string DataFieldsInfo<Eigen::Vector##Num##Type, void>::GetFieldAsString(std::size_t i, const Eigen::Vector##Num##Type& field)  \
-    {                                                                                                                                   \
-        ARMARX_CHECK_LESS(i, Num);                                                                                                      \
-        return to_string(field(i));                                                                                                \
-    }                                                                                                                                   \
-    std::map<std::string, VariantBasePtr> DataFieldsInfo<Eigen::Vector##Num##Type, void>::ToVariants(                                   \
-            const Eigen::Vector##Num##Type& value,                                                                                          \
-            const std::string& name,                                                                                                        \
-            const IceUtil::Time& timestamp,                                                                                                 \
-            const std::string& frame,                                                                                                       \
-            const std::string& agent)                                                                                                       \
-    {                                                                                                                                   \
-        ARMARX_CHECK_EXPRESSION(frame.empty() && agent.empty()) << "There is no framed version of TimestampVariant";               \
-        std::map<std::string, VariantBasePtr> result;                                                                                   \
-        for(int i = 0; i < Num; ++i)                                                                                                    \
-        {                                                                                                                               \
-            result.emplace(name + "." + to_string(i), VariantBasePtr{new TimedVariant(value(i), timestamp)});                      \
-        }                                                                                                                               \
-        return result;                                                                                                                  \
-    }                                                                                                                                   \
-    std::vector<std::string> DataFieldsInfo<Eigen::Vector##Num##Type, void>::GetFieldNames()                                            \
-    {                                                                                                                                   \
-        std::vector<std::string> result;                                                                                                \
-        for(int i = 0; i < Num; ++i)                                                                                                    \
-        {                                                                                                                               \
-            result.emplace_back(to_string(i));                                                                                     \
-        }                                                                                                                               \
-        return result;                                                                                                                  \
+#define make_DataFieldsInfo_for_eigen_vector(Type,TypeName,Num)                                                                                     \
+    void DataFieldsInfo<Eigen::Vector##Num##Type, void>::GetDataFieldAs(std::size_t i, const Eigen::Vector##Num##Type& field, std::string& out)     \
+    {                                                                                                                                               \
+        ARMARX_CHECK_LESS(i, Num);                                                                                                                  \
+        out = to_string(field(i));                                                                                                                  \
+    }                                                                                                                                               \
+    void DataFieldsInfo<Eigen::Vector##Num##Type, void>::GetDataFieldAs(std::size_t i, const Eigen::Vector##Num##Type& field, Ice::TypeName& out)   \
+    {                                                                                                                                               \
+        ARMARX_CHECK_LESS(i, Num);                                                                                                                  \
+        out = field(i);                                                                                                                             \
+    }                                                                                                                                               \
+    const std::type_info& DataFieldsInfo<Eigen::Vector##Num##Type, void>::GetDataFieldType(std::size_t i)                                           \
+    {                                                                                                                                               \
+        return typeid(Ice::TypeName);                                                                                                               \
+    }                                                                                                                                               \
+    std::map<std::string, VariantBasePtr> DataFieldsInfo<Eigen::Vector##Num##Type, void>::ToVariants(                                               \
+            const Eigen::Vector##Num##Type& value,                                                                                                  \
+            const std::string& name,                                                                                                                \
+            const IceUtil::Time& timestamp,                                                                                                         \
+            const std::string& frame,                                                                                                               \
+            const std::string& agent)                                                                                                               \
+    {                                                                                                                                               \
+        ARMARX_CHECK_EXPRESSION(frame.empty() && agent.empty()) << "There is no framed version of TimestampVariant";                                \
+        std::map<std::string, VariantBasePtr> result;                                                                                               \
+        for(int i = 0; i < Num; ++i)                                                                                                                \
+        {                                                                                                                                           \
+            result.emplace(name + "." + to_string(i), VariantBasePtr{new TimedVariant(value(i), timestamp)});                                       \
+        }                                                                                                                                           \
+        return result;                                                                                                                              \
+    }                                                                                                                                               \
+    std::vector<std::string> DataFieldsInfo<Eigen::Vector##Num##Type, void>::GetFieldNames()                                                        \
+    {                                                                                                                                               \
+        std::vector<std::string> result;                                                                                                            \
+        for(int i = 0; i < Num; ++i)                                                                                                                \
+        {                                                                                                                                           \
+            result.emplace_back(to_string(i));                                                                                                      \
+        }                                                                                                                                           \
+        return result;                                                                                                                              \
     }
 
-    make_DataFieldsInfo_for_eigen_vector(f, 2)
-    make_DataFieldsInfo_for_eigen_vector(f, 4)
-    make_DataFieldsInfo_for_eigen_vector(f, 5)
-    make_DataFieldsInfo_for_eigen_vector(f, 6)
+    make_DataFieldsInfo_for_eigen_vector(f, Float, 2)
+    make_DataFieldsInfo_for_eigen_vector(f, Float, 4)
+    make_DataFieldsInfo_for_eigen_vector(f, Float, 5)
+    make_DataFieldsInfo_for_eigen_vector(f, Float, 6)
 
-    make_DataFieldsInfo_for_eigen_vector(d, 2)
-    make_DataFieldsInfo_for_eigen_vector(d, 3)
-    make_DataFieldsInfo_for_eigen_vector(d, 4)
-    make_DataFieldsInfo_for_eigen_vector(d, 5)
-    make_DataFieldsInfo_for_eigen_vector(d, 6)
+    make_DataFieldsInfo_for_eigen_vector(d, Double, 2)
+    make_DataFieldsInfo_for_eigen_vector(d, Double, 3)
+    make_DataFieldsInfo_for_eigen_vector(d, Double, 4)
+    make_DataFieldsInfo_for_eigen_vector(d, Double, 5)
+    make_DataFieldsInfo_for_eigen_vector(d, Double, 6)
 
-    make_DataFieldsInfo_for_eigen_vector(i, 2)
-    make_DataFieldsInfo_for_eigen_vector(i, 3)
-    make_DataFieldsInfo_for_eigen_vector(i, 4)
-    make_DataFieldsInfo_for_eigen_vector(i, 5)
-    make_DataFieldsInfo_for_eigen_vector(i, 6)
+    make_DataFieldsInfo_for_eigen_vector(i, Int, 2)
+    make_DataFieldsInfo_for_eigen_vector(i, Int, 3)
+    make_DataFieldsInfo_for_eigen_vector(i, Int, 4)
+    make_DataFieldsInfo_for_eigen_vector(i, Int, 5)
+    make_DataFieldsInfo_for_eigen_vector(i, Int, 6)
 #undef make_DataFieldsInfo_for_eigen_vector
 }
-
+//Eigen::Matrix4f
 namespace armarx::introspection
 {
-    std::string DataFieldsInfo<JointStatus, void>::GetFieldAsString(
-        std::size_t i, const JointStatus& field)
+    std::size_t DataFieldsInfo<Eigen::Matrix4f, void>::GetNumberOfFields()
+    {
+        return 16;
+    }
+    void DataFieldsInfo<Eigen::Matrix4f, void>::GetDataFieldAs(std::size_t i, const Eigen::Matrix4f& field, float& out)
+    {
+        ARMARX_CHECK_LESS(i, 16);
+        out = field(i / 4, i % 4);
+    }
+    void DataFieldsInfo<Eigen::Matrix4f, void>::GetDataFieldAs(std::size_t i, const Eigen::Matrix4f& field, std::string& out)
+    {
+        ARMARX_CHECK_LESS(i, 16);
+        out = to_string(field(i / 4, i % 4));
+    }
+    const std::type_info& DataFieldsInfo<Eigen::Matrix4f, void>::GetDataFieldType(std::size_t i)
+    {
+        return typeid(float);
+    }
+    std::vector<std::string> DataFieldsInfo<Eigen::Matrix4f, void>::GetFieldNames()
+    {
+        return
+        {
+            "00", "01", "02", "03",
+            "10", "11", "12", "13",
+            "20", "21", "22", "23",
+            "30", "31", "32", "33"
+        };
+    }
+    std::map<std::string, VariantBasePtr> DataFieldsInfo<Eigen::Matrix4f, void>::ToVariants(
+        const Eigen::Matrix4f& value,
+        const std::string& name,
+        const IceUtil::Time& timestamp,
+        const std::string& frame,
+        const std::string& agent)
+    {
+        if (!frame.empty())
+        {
+            return {{name, {new TimedVariant(FramedPose{value, frame, agent}, timestamp)}}};
+        }
+        ARMARX_CHECK_EXPRESSION(agent.empty()) << "No frame but an agent given";
+        return {{name, {new TimedVariant(Pose{value}, timestamp)}}};
+    }
+}
+//Eigen::Quaternionf
+namespace armarx::introspection
+{
+    std::size_t DataFieldsInfo<Eigen::Quaternionf, void>::GetNumberOfFields()
+    {
+        return 4;
+    }
+    void DataFieldsInfo<Eigen::Quaternionf, void>::GetDataFieldAs(std::size_t i, const Eigen::Quaternionf& field, float& out)
     {
         ARMARX_CHECK_LESS(i, 4);
         switch (i)
         {
             case 0:
-                return to_string(field.error);
+                out = field.w();
+                break;
             case 1:
-                return to_string(field.operation);
+                out = field.x();
+                break;
             case 2:
-                return to_string(field.enabled);
+                out = field.y();
+                break;
             case 3:
-                return to_string(field.emergencyStop);
+                out = field.z();
+                break;
         }
         throw std::logic_error
         {
             __FILE__ " : " + to_string(__LINE__) +
             " : Unreachable code reached"
         };
-    }
 
-    std::map<std::string, VariantBasePtr> DataFieldsInfo<JointStatus, void>::ToVariants(
-        const JointStatus& value,
-        const std::string& name,
-        const IceUtil::Time& timestamp,
-        const std::string& frame,
-        const std::string& agent)
-    {
-        ARMARX_CHECK_EXPRESSION(frame.empty() && agent.empty()) << "There is no framed version for JointStatus";
-        static const auto fnames = GetFieldNames();
-        return
-        {
-            {name + fnames.at(0), {new TimedVariant{to_string(value.error), timestamp}}},
-            {name + fnames.at(1), {new TimedVariant{to_string(value.operation), timestamp}}},
-            {name + fnames.at(2), {new TimedVariant{value.enabled, timestamp}}},
-            {name + fnames.at(3), {new TimedVariant{value.emergencyStop, timestamp}}}
-        };
     }
-}
-
-namespace armarx::introspection
-{
-    std::string DataFieldsInfo<Eigen::Quaternionf, void>::GetFieldAsString(
-        std::size_t i,
-        const Eigen::Quaternionf& field)
+    void DataFieldsInfo<Eigen::Quaternionf, void>::GetDataFieldAs(std::size_t i, const Eigen::Quaternionf& field, std::string& out)
     {
         ARMARX_CHECK_LESS(i, 4);
         switch (i)
         {
             case 0:
-                return to_string(field.w());
+                out = to_string(field.w());
+                break;
             case 1:
-                return to_string(field.x());
+                out = to_string(field.x());
+                break;
             case 2:
-                return to_string(field.y());
+                out = to_string(field.y());
+                break;
             case 3:
-                return to_string(field.z());
+                out = to_string(field.z());
+                break;
         }
         throw std::logic_error
         {
             __FILE__ " : " + to_string(__LINE__) +
             " : Unreachable code reached"
         };
+
+    }
+
+    const std::type_info& DataFieldsInfo<Eigen::Quaternionf, void>::GetDataFieldType(std::size_t i)
+    {
+        return typeid(float);
+    }
+    std::vector<std::string> DataFieldsInfo<Eigen::Quaternionf, void>::GetFieldNames()
+    {
+        return {"qw", "qx", "qy", "qz"};
     }
 
     std::map<std::string, VariantBasePtr> DataFieldsInfo<Eigen::Quaternionf, void>::ToVariants(
@@ -193,33 +262,27 @@ namespace armarx::introspection
         return {{name, {new TimedVariant(Quaternion{value}, timestamp)}}};
     }
 }
-
+//std::chrono::microseconds
 namespace armarx::introspection
 {
-    std::string DataFieldsInfo<Eigen::Matrix4f, void>::GetFieldAsString(std::size_t i, const Eigen::Matrix4f& field)
+    std::size_t DataFieldsInfo<std::chrono::microseconds, void>::GetNumberOfFields()
     {
-        ARMARX_CHECK_LESS(i, 16);
-        return  to_string(field(i / 4, i % 4));
+        return 1;
     }
-
-    std::map<std::string, VariantBasePtr> DataFieldsInfo<Eigen::Matrix4f, void>::ToVariants(
-        const Eigen::Matrix4f& value,
-        const std::string& name,
-        const IceUtil::Time& timestamp,
-        const std::string& frame,
-        const std::string& agent)
+    void DataFieldsInfo<std::chrono::microseconds, void>::GetDataFieldAs(std::size_t i, const std::chrono::microseconds& field, long& out)
     {
-        if (!frame.empty())
-        {
-            return {{name, {new TimedVariant(FramedPose{value, frame, agent}, timestamp)}}};
-        }
-        ARMARX_CHECK_EXPRESSION(agent.empty()) << "No frame but an agent given";
-        return {{name, {new TimedVariant(Pose{value}, timestamp)}}};
+        ARMARX_CHECK_EQUAL(i, 0);
+        out = field.count();
+    }
+    void DataFieldsInfo<std::chrono::microseconds, void>::GetDataFieldAs(std::size_t i, const std::chrono::microseconds& field, std::string& out)
+    {
+        ARMARX_CHECK_EQUAL(i, 0);
+        out = to_string(field.count());
+    }
+    const std::type_info& GetDataFieldType(std::size_t i)
+    {
+        return typeid(long);
     }
-}
-
-namespace armarx::introspection
-{
     std::map<std::string, VariantBasePtr> DataFieldsInfo<std::chrono::microseconds, void>::ToVariants(
         std::chrono::microseconds value,
         const std::string& name,
@@ -231,6 +294,28 @@ namespace armarx::introspection
         return {{name, {new TimedVariant(TimestampVariant{value.count()}, timestamp)}}};
     }
 
+}
+//IceUtil::Time
+namespace armarx::introspection
+{
+    std::size_t DataFieldsInfo<IceUtil::Time, void>::GetNumberOfFields()
+    {
+        return 1;
+    }
+    void DataFieldsInfo<IceUtil::Time, void>::GetDataFieldAs(std::size_t i, const IceUtil::Time& field, long& out)
+    {
+        ARMARX_CHECK_EQUAL(i, 0);
+        out = field.toMicroSeconds();
+    }
+    void DataFieldsInfo<IceUtil::Time, void>::GetDataFieldAs(std::size_t i, const IceUtil::Time& field, std::string& out)
+    {
+        ARMARX_CHECK_EQUAL(i, 0);
+        out = to_string(field.toMicroSeconds());
+    }
+    const std::type_info& DataFieldsInfo<IceUtil::Time, void>::GetDataFieldType(std::size_t i)
+    {
+        return typeid(long);
+    }
     std::map<std::string, VariantBasePtr> DataFieldsInfo<IceUtil::Time, void>::ToVariants(
         IceUtil::Time value,
         const std::string& name,
@@ -242,3 +327,121 @@ namespace armarx::introspection
         return {{name, {new TimedVariant(TimestampVariant{value.toMicroSeconds()}, timestamp)}}};
     }
 }
+//JointStatus
+namespace armarx::introspection
+{
+    std::size_t DataFieldsInfo<JointStatus, void>::GetNumberOfFields()
+    {
+        return 4;
+    }
+    void DataFieldsInfo<JointStatus, void>::GetDataFieldAs(
+        std::size_t i, const JointStatus& field, std::string& out)
+    {
+        ARMARX_CHECK_LESS(i, 4);
+        switch (i)
+        {
+            case 0:
+                out = to_string(field.error);
+                break;
+            case 1:
+                out = to_string(field.operation);
+                break;
+            case 2:
+                out = to_string(field.enabled);
+                break;
+            case 3:
+                out = to_string(field.emergencyStop);
+                break;
+        }
+        throw std::logic_error
+        {
+            __FILE__ " : " + to_string(__LINE__) +
+            " : Unreachable code reached"
+        };
+    }
+    void DataFieldsInfo<JointStatus, void>::GetDataFieldAs(
+        std::size_t i, const JointStatus& field, Ice::Int& out)
+    {
+        ARMARX_CHECK_EXPRESSION(i == 0 || i == 1);
+        switch (i)
+        {
+            case 0:
+                out = field.enabled;
+                break;
+            case 1:
+                out = field.emergencyStop;
+                break;
+        }
+        throw std::logic_error
+        {
+            __FILE__ " : " + to_string(__LINE__) +
+            " : Unreachable code reached"
+        };
+    }
+    void DataFieldsInfo<JointStatus, void>::GetDataFieldAs(
+        std::size_t i, const JointStatus& field, bool& out)
+    {
+        ARMARX_CHECK_EXPRESSION(i == 2 || i == 3);
+        switch (i)
+        {
+            case 2:
+                out = static_cast<Ice::Int>(field.error);
+                break;
+            case 3:
+                out = static_cast<Ice::Int>(field.operation);
+                break;
+        }
+        throw std::logic_error
+        {
+            __FILE__ " : " + to_string(__LINE__) +
+            " : Unreachable code reached"
+        };
+    }
+    const std::type_info& DataFieldsInfo<JointStatus, void>::GetDataFieldType(std::size_t i)
+    {
+        ARMARX_CHECK_LESS(i, 4);
+        switch (i)
+        {
+            case 0:
+                return typeid(Ice::Int);
+                break;
+            case 1:
+                return typeid(Ice::Int);
+                break;
+            case 2:
+                return typeid(bool);
+                break;
+            case 3:
+                return typeid(bool);
+                break;
+        }
+        throw std::logic_error
+        {
+            __FILE__ " : " + to_string(__LINE__) +
+            " : Unreachable code reached"
+        };
+    }
+
+    std::vector<std::string> DataFieldsInfo<JointStatus, void>::GetFieldNames()
+    {
+        return {"error", "operation", "enabled", "emergencyStop"};
+    }
+
+    std::map<std::string, VariantBasePtr> DataFieldsInfo<JointStatus, void>::ToVariants(
+        const JointStatus& value,
+        const std::string& name,
+        const IceUtil::Time& timestamp,
+        const std::string& frame,
+        const std::string& agent)
+    {
+        ARMARX_CHECK_EXPRESSION(frame.empty() && agent.empty()) << "There is no framed version for JointStatus";
+        static const auto fnames = GetFieldNames();
+        return
+        {
+            {name + fnames.at(0), {new TimedVariant{to_string(value.error), timestamp}}},
+            {name + fnames.at(1), {new TimedVariant{to_string(value.operation), timestamp}}},
+            {name + fnames.at(2), {new TimedVariant{value.enabled, timestamp}}},
+            {name + fnames.at(3), {new TimedVariant{value.emergencyStop, timestamp}}}
+        };
+    }
+}
diff --git a/source/RobotAPI/components/units/RobotUnit/util/introspection/DataFieldsInfo.h b/source/RobotAPI/components/units/RobotUnit/util/introspection/DataFieldsInfo.h
index c122c55b0361fbe82f7e7ce6bbffcb2fdbf9bc84..16d76a7b7bba97433af9a97e26c4fe66c387b051 100644
--- a/source/RobotAPI/components/units/RobotUnit/util/introspection/DataFieldsInfo.h
+++ b/source/RobotAPI/components/units/RobotUnit/util/introspection/DataFieldsInfo.h
@@ -35,7 +35,15 @@ namespace armarx::introspection
 {
     template<class T, class = void> struct DataFieldsInfo;
     //    static std::size_t GetNumberOfFields();
-    //    static std::string GetFieldAsString(std::size_t i, T field);
+    //    static void GetDataFieldAs(std::size_t i, T field, bool&        out);
+    //    static void GetDataFieldAs(std::size_t i, T field, Ice::Byte&   out);
+    //    static void GetDataFieldAs(std::size_t i, T field, Ice::Short&  out);
+    //    static void GetDataFieldAs(std::size_t i, T field, Ice::Int&    out);
+    //    static void GetDataFieldAs(std::size_t i, T field, Ice::Long&   out);
+    //    static void GetDataFieldAs(std::size_t i, T field, Ice::Float&  out);
+    //    static void GetDataFieldAs(std::size_t i, T field, Ice::Double& out);
+    //    static void GetDataFieldAs(std::size_t i, T field, std::string& out);
+    //    static const std::type_info& GetDataFieldType(std::size_t i);
     //    static std::vector<std::string> GetFieldNames();
     //    static std::map<std::string, VariantBasePtr> ToVariants(
     //                  T value,
@@ -45,45 +53,106 @@ namespace armarx::introspection
     //                  const std::string& agent = "")
 
     template<class T>
-    struct DataFieldsInfo<T, typename std::enable_if<std::is_fundamental<T>::value>::type>
+    struct DataFieldsInfoBase
     {
-        static std::size_t GetNumberOfFields()
+        static void GetDataFieldAs(std::size_t i, const T& field, bool& out)
         {
-            return 1;
+            throw std::logic_error {"This function should never be called"};
         }
-        static std::string GetFieldAsString(std::size_t i, T field)
+        static void GetDataFieldAs(std::size_t i, const T& field, Ice::Byte& out)
         {
-            ARMARX_CHECK_EQUAL(i, 0);
-            return to_string(field);
+            throw std::logic_error {"This function should never be called"};
         }
-        static std::vector<std::string> GetFieldNames()
+        static void GetDataFieldAs(std::size_t i, const T& field, Ice::Short& out)
         {
-            throw std::logic_error {"Fundamental types have no field names"};
+            throw std::logic_error {"This function should never be called"};
         }
-        static std::map<std::string, VariantBasePtr> ToVariants(
-            T value,
-            const std::string& name,
-            const IceUtil::Time& timestamp,
-            const std::string& frame = "",
-            const std::string& agent = "")
+        static void GetDataFieldAs(std::size_t i, const T& field, Ice::Int& out)
         {
-            ARMARX_CHECK_EXPRESSION(frame.empty() && agent.empty()) << "There is no framed version for fundamental types";
-            return {{name, {new TimedVariant(value, timestamp)}}};
+            throw std::logic_error {"This function should never be called"};
         }
-    };
-
-    template<>
-    struct DataFieldsInfo<Eigen::Vector3f, void>
-    {
-        static std::size_t GetNumberOfFields()
+        static void GetDataFieldAs(std::size_t i, const T& field, Ice::Long& out)
+        {
+            throw std::logic_error {"This function should never be called"};
+        }
+        static void GetDataFieldAs(std::size_t i, const T& field, Ice::Float& out)
+        {
+            throw std::logic_error {"This function should never be called"};
+        }
+        static void GetDataFieldAs(std::size_t i, const T& field, Ice::Double& out)
+        {
+            throw std::logic_error {"This function should never be called"};
+        }
+        static void GetDataFieldAs(std::size_t i, const T& field, std::string& out)
         {
-            return 3;
+            throw std::logic_error {"This function should never be called"};
         }
-        static std::string GetFieldAsString(std::size_t i, const Eigen::Vector3f& field);
         static std::vector<std::string> GetFieldNames()
         {
-            return {"x", "y", "z"};
+            throw std::logic_error {"This function should never be called"};
         }
+    };
+}
+//build_in_ice_types
+namespace armarx::introspection
+{
+#define make_def_for_build_in_ice_type(Type)                                        \
+    template<>                                                                      \
+    struct DataFieldsInfo<Type, void> : DataFieldsInfoBase<Type>                    \
+    {                                                                               \
+        using DataFieldsInfoBase<Type>::GetDataFieldAs;                             \
+        static std::size_t GetNumberOfFields()                                      \
+        {                                                                           \
+            return 1;                                                               \
+        }                                                                           \
+        static void GetDataFieldAs(std::size_t i, const Type& field, std::string& out)  \
+        {                                                                           \
+            ARMARX_CHECK_EQUAL(i, 0);                                               \
+            out = to_string(field);                                                 \
+        }                                                                           \
+        static void GetDataFieldAs(std::size_t i, const Type& field, Type& out)         \
+        {                                                                           \
+            ARMARX_CHECK_EQUAL(i, 0);                                               \
+            out = field;                                                            \
+        }                                                                           \
+        static const std::type_info& GetDataFieldType(std::size_t i)                \
+        {                                                                           \
+            return typeid(Type);                                                    \
+        }                                                                           \
+        static std::map<std::string, VariantBasePtr> ToVariants(                    \
+                const Type& value,                                                  \
+                const std::string& name,                                            \
+                const IceUtil::Time& timestamp,                                     \
+                const std::string& frame = "",                                      \
+                const std::string& agent = "")                                      \
+        {                                                                           \
+            ARMARX_CHECK_EXPRESSION(frame.empty() && agent.empty())                 \
+                    << "There is no framed version for build in ice types";         \
+            return {{name, {new TimedVariant(value, timestamp)}}};                  \
+        }                                                                           \
+    }
+    make_def_for_build_in_ice_type(bool);
+    make_def_for_build_in_ice_type(Ice::Byte);
+    make_def_for_build_in_ice_type(Ice::Short);
+    make_def_for_build_in_ice_type(Ice::Int);
+    make_def_for_build_in_ice_type(Ice::Long);
+    make_def_for_build_in_ice_type(Ice::Float);
+    make_def_for_build_in_ice_type(Ice::Double);
+#undef make_def_for_build_in_ice_type
+
+}
+//Eigen::Vector3f
+namespace armarx::introspection
+{
+    template<>
+    struct DataFieldsInfo<Eigen::Vector3f, void> : DataFieldsInfoBase<Eigen::Vector3f>
+    {
+        using DataFieldsInfoBase<Eigen::Vector3f>::GetDataFieldAs;
+        static std::size_t GetNumberOfFields();
+        static void GetDataFieldAs(std::size_t i, const Eigen::Vector3f& field, float& out);
+        static void GetDataFieldAs(std::size_t i, const Eigen::Vector3f& field, std::string& out);
+        static const std::type_info& GetDataFieldType(std::size_t i);
+        static std::vector<std::string> GetFieldNames();
         static std::map<std::string, VariantBasePtr> ToVariants(
             const Eigen::Vector3f& value,
             const std::string& name,
@@ -91,20 +160,24 @@ namespace armarx::introspection
             const std::string& frame = "",
             const std::string& agent = "");
     };
-
-
-
-#define make_DataFieldsInfo_for_eigen_vector(Type,Num)                                              \
-    template<>                                                                                          \
-    struct DataFieldsInfo<Eigen::Vector##Num##Type, void>                                               \
-    {                                                                                                   \
-        static std::size_t GetNumberOfFields()                                                          \
-        {                                                                                               \
-            return Num;                                                                                 \
-        }                                                                                               \
-        static std::string GetFieldAsString(std::size_t i, const Eigen::Vector##Num##Type& field);      \
-        static std::vector<std::string> GetFieldNames();                                                \
-        static std::map<std::string, VariantBasePtr> ToVariants(                                        \
+}
+//Eigen::Vector##Num##Type
+namespace armarx::introspection
+{
+#define make_DataFieldsInfo_for_eigen_vector(Type,TypeName,Num)                                             \
+    template<>                                                                                              \
+    struct DataFieldsInfo<Eigen::Vector##Num##Type, void> : DataFieldsInfoBase<Eigen::Vector##Num##Type>    \
+    {                                                                                                       \
+        using DataFieldsInfoBase<Eigen::Vector##Num##Type>::GetDataFieldAs;                                 \
+        static std::size_t GetNumberOfFields()                                                              \
+        {                                                                                                   \
+            return Num;                                                                                     \
+        }                                                                                                   \
+        static void GetDataFieldAs(std::size_t i, const Eigen::Vector##Num##Type& field, std::string& out);     \
+        static void GetDataFieldAs(std::size_t i, const Eigen::Vector##Num##Type& field, Ice::TypeName& out);   \
+        static const std::type_info& GetDataFieldType(std::size_t i);                                       \
+        static std::vector<std::string> GetFieldNames();                                                    \
+        static std::map<std::string, VariantBasePtr> ToVariants(                                            \
                 const Eigen::Vector##Num##Type& value,                                                      \
                 const std::string& name,                                                                    \
                 const IceUtil::Time& timestamp,                                                             \
@@ -112,42 +185,37 @@ namespace armarx::introspection
                 const std::string& agent = "");                                                             \
     };
 
-    make_DataFieldsInfo_for_eigen_vector(f, 2)
-    make_DataFieldsInfo_for_eigen_vector(f, 4)
-    make_DataFieldsInfo_for_eigen_vector(f, 5)
-    make_DataFieldsInfo_for_eigen_vector(f, 6)
+    make_DataFieldsInfo_for_eigen_vector(f, Float, 2)
+    make_DataFieldsInfo_for_eigen_vector(f, Float, 4)
+    make_DataFieldsInfo_for_eigen_vector(f, Float, 5)
+    make_DataFieldsInfo_for_eigen_vector(f, Float, 6)
 
-    make_DataFieldsInfo_for_eigen_vector(d, 2)
-    make_DataFieldsInfo_for_eigen_vector(d, 3)
-    make_DataFieldsInfo_for_eigen_vector(d, 4)
-    make_DataFieldsInfo_for_eigen_vector(d, 5)
-    make_DataFieldsInfo_for_eigen_vector(d, 6)
+    make_DataFieldsInfo_for_eigen_vector(d, Double, 2)
+    make_DataFieldsInfo_for_eigen_vector(d, Double, 3)
+    make_DataFieldsInfo_for_eigen_vector(d, Double, 4)
+    make_DataFieldsInfo_for_eigen_vector(d, Double, 5)
+    make_DataFieldsInfo_for_eigen_vector(d, Double, 6)
 
-    make_DataFieldsInfo_for_eigen_vector(i, 2)
-    make_DataFieldsInfo_for_eigen_vector(i, 3)
-    make_DataFieldsInfo_for_eigen_vector(i, 4)
-    make_DataFieldsInfo_for_eigen_vector(i, 5)
-    make_DataFieldsInfo_for_eigen_vector(i, 6)
+    make_DataFieldsInfo_for_eigen_vector(i, Int, 2)
+    make_DataFieldsInfo_for_eigen_vector(i, Int, 3)
+    make_DataFieldsInfo_for_eigen_vector(i, Int, 4)
+    make_DataFieldsInfo_for_eigen_vector(i, Int, 5)
+    make_DataFieldsInfo_for_eigen_vector(i, Int, 6)
 #undef make_DataFieldsInfo_for_eigen_vector
 
+}
+//Eigen::Matrix4f
+namespace armarx::introspection
+{
     template<>
-    struct DataFieldsInfo<Eigen::Matrix4f, void>
+    struct DataFieldsInfo<Eigen::Matrix4f, void> : DataFieldsInfoBase<Eigen::Matrix4f>
     {
-        static std::size_t GetNumberOfFields()
-        {
-            return 16;
-        }
-        static std::string GetFieldAsString(std::size_t i, const Eigen::Matrix4f& field);
-        static std::vector<std::string> GetFieldNames()
-        {
-            return
-            {
-                "00", "01", "02", "03",
-                "10", "11", "12", "13",
-                "20", "21", "22", "23",
-                "30", "31", "32", "33"
-            };
-        }
+        using DataFieldsInfoBase<Eigen::Matrix4f>::GetDataFieldAs;
+        static std::size_t GetNumberOfFields();
+        static void GetDataFieldAs(std::size_t i, const Eigen::Matrix4f& field, float& out);
+        static void GetDataFieldAs(std::size_t i, const Eigen::Matrix4f& field, std::string& out);
+        static const std::type_info& GetDataFieldType(std::size_t i);
+        static std::vector<std::string> GetFieldNames();
         static std::map<std::string, VariantBasePtr> ToVariants(
             const Eigen::Matrix4f& value,
             const std::string& name,
@@ -155,19 +223,19 @@ namespace armarx::introspection
             const std::string& frame = "",
             const std::string& agent = "");
     };
-
+}
+//Eigen::Quaternionf
+namespace armarx::introspection
+{
     template<>
-    struct DataFieldsInfo<Eigen::Quaternionf, void>
+    struct DataFieldsInfo<Eigen::Quaternionf, void> : DataFieldsInfoBase<Eigen::Quaternionf>
     {
-        static std::size_t GetNumberOfFields()
-        {
-            return 4;
-        }
-        static std::string GetFieldAsString(std::size_t i, const Eigen::Quaternionf& field);
-        static std::vector<std::string> GetFieldNames()
-        {
-            return {"qw", "qx", "qy", "qz"};
-        }
+        using DataFieldsInfoBase<Eigen::Quaternionf>::GetDataFieldAs;
+        static std::size_t GetNumberOfFields();
+        static void GetDataFieldAs(std::size_t i, const Eigen::Quaternionf& field, float& out);
+        static void GetDataFieldAs(std::size_t i, const Eigen::Quaternionf& field, std::string& out);
+        static const std::type_info& GetDataFieldType(std::size_t i);
+        static std::vector<std::string> GetFieldNames();
         static std::map<std::string, VariantBasePtr> ToVariants(
             const Eigen::Quaternionf& value,
             const std::string& name,
@@ -175,22 +243,18 @@ namespace armarx::introspection
             const std::string& frame = "",
             const std::string& agent = "");
     };
-
+}
+//std::chrono::microseconds
+namespace armarx::introspection
+{
     template<>
-    struct DataFieldsInfo<std::chrono::microseconds, void>
+    struct DataFieldsInfo<std::chrono::microseconds, void> : DataFieldsInfoBase<std::chrono::microseconds>
     {
-        static std::size_t GetNumberOfFields()
-        {
-            return 1;
-        }
-        static std::string GetFieldAsString(std::size_t i, std::chrono::microseconds field)
-        {
-            return to_string(field.count());
-        }
-        static std::vector<std::string> GetFieldNames()
-        {
-            throw std::logic_error {"should never be called"};
-        }
+        using DataFieldsInfoBase<std::chrono::microseconds>::GetDataFieldAs;
+        static std::size_t GetNumberOfFields();
+        static void GetDataFieldAs(std::size_t i, const std::chrono::microseconds& field, long& out);
+        static void GetDataFieldAs(std::size_t i, const std::chrono::microseconds& field, std::string& out);
+        static const std::type_info& GetDataFieldType(std::size_t i);
         static std::map<std::string, VariantBasePtr> ToVariants(
             std::chrono::microseconds value,
             const std::string& name,
@@ -198,21 +262,18 @@ namespace armarx::introspection
             const std::string& frame = "",
             const std::string& agent = "");
     };
+}
+//IceUtil::Time
+namespace armarx::introspection
+{
     template<>
-    struct DataFieldsInfo<IceUtil::Time, void>
+    struct DataFieldsInfo<IceUtil::Time, void> : DataFieldsInfoBase<IceUtil::Time>
     {
-        static std::size_t GetNumberOfFields()
-        {
-            return 1;
-        }
-        static std::string GetFieldAsString(std::size_t i, IceUtil::Time field)
-        {
-            return to_string(field.toMicroSeconds());
-        }
-        static std::vector<std::string> GetFieldNames()
-        {
-            throw std::logic_error {"should never be called"};
-        }
+        using DataFieldsInfoBase<IceUtil::Time>::GetDataFieldAs;
+        static std::size_t GetNumberOfFields();
+        static void GetDataFieldAs(std::size_t i, const IceUtil::Time& field, long& out);
+        static void GetDataFieldAs(std::size_t i, const IceUtil::Time& field, std::string& out);
+        static const std::type_info& GetDataFieldType(std::size_t i);
         static std::map<std::string, VariantBasePtr> ToVariants(
             IceUtil::Time value,
             const std::string& name,
@@ -221,26 +282,23 @@ namespace armarx::introspection
             const std::string& agent = "");
     };
 }
-
+//JointStatus
 namespace armarx
 {
     struct JointStatus;
 }
-
 namespace armarx::introspection
 {
     template<>
-    struct DataFieldsInfo<JointStatus, void>
+    struct DataFieldsInfo<JointStatus, void> : DataFieldsInfoBase<JointStatus>
     {
-        static std::size_t GetNumberOfFields()
-        {
-            return 4;
-        }
-        static std::string GetFieldAsString(std::size_t i, const JointStatus& field);
-        static std::vector<std::string> GetFieldNames()
-        {
-            return {"error", "operation", "enabled", "emergencyStop"};
-        }
+        using DataFieldsInfoBase<JointStatus>::GetDataFieldAs;
+        static std::size_t GetNumberOfFields();
+        static void GetDataFieldAs(std::size_t i, const JointStatus& field, std::string& out);
+        static void GetDataFieldAs(std::size_t i, const JointStatus& field, Ice::Int& out);
+        static void GetDataFieldAs(std::size_t i, const JointStatus& field, bool& out);
+        static const std::type_info& GetDataFieldType(std::size_t i);
+        static std::vector<std::string> GetFieldNames();
 
         static std::map<std::string, VariantBasePtr> ToVariants(
             const JointStatus& value,
@@ -250,4 +308,3 @@ namespace armarx::introspection
             const std::string& agent);
     };
 }
-
diff --git a/source/RobotAPI/interface/units/RobotUnit/RobotUnitInterface.ice b/source/RobotAPI/interface/units/RobotUnit/RobotUnitInterface.ice
index 361cf690a3498a2a9ffcb95527ef27005c54fe86..c7871f0860fbe343a1704b2022f54a8ed6cd8674 100644
--- a/source/RobotAPI/interface/units/RobotUnit/RobotUnitInterface.ice
+++ b/source/RobotAPI/interface/units/RobotUnit/RobotUnitInterface.ice
@@ -46,6 +46,7 @@
 #include <ArmarXCore/interface/core/UserException.ice>
 #include <ArmarXGui/interface/WidgetDescription.ice>
 
+//NJointController
 module armarx
 {
     interface NJointControllerInterface;
@@ -61,7 +62,7 @@ module armarx
     };
 
 
-    class NJointControllerConfig{};
+    class NJointControllerConfig {};
 
     struct NJointControllerDescription
     {
@@ -117,10 +118,10 @@ module armarx
     dictionary<string, NJointControllerInterface*> StringNJointControllerPrxDictionary;
 };
 
+//RobotUnit Utility types - ControlDevice
 module armarx
 {
     dictionary<string, Ice::StringSeq> ControlDeviceNameToControlModesDictionary;
-
     dictionary<string, string> ControlDeviceNameToNJointControllerNameDictionary;
 
     struct HWControlModeAndTargetType
@@ -146,8 +147,10 @@ module armarx
         long timestampUSec = 0;
     };
     sequence<ControlDeviceStatus> ControlDeviceStatusSeq;
-
-
+}
+//RobotUnit Utility types - SensorDevice
+module armarx
+{
     struct SensorDeviceDescription
     {
         string deviceName;
@@ -162,15 +165,76 @@ module armarx
         long timestampUSec = 0;
     };
     sequence<SensorDeviceStatus> SensorDeviceStatusSeq;
-
-
+}
+//RobotUnit Utility types - NJointController
+module armarx
+{
     struct NJointControllerClassDescription
     {
         string className;
         WidgetDescription::Widget configDescription;
     };
     sequence<NJointControllerClassDescription> NJointControllerClassDescriptionSeq;
+}
+//RobotUnit Utility types - data streaming
+module armarx
+{
+    module RobotUnitDataStreaming
+    {
+        enum DataEntryType
+        {
+            NodeTypeBool,
+            NodeTypeByte,
+            NodeTypeShort,
+            NodeTypeInt,
+            NodeTypeLong,
+            NodeTypeFloat,
+            NodeTypeDouble
+        };
+
+        struct DataEntry
+        {
+            DataEntryType  type;
+            long           index = -1;
+        };
+        dictionary<string, DataEntry> StringDataEntryMap;
+
+        struct DataStreamingDescription
+        {
+            StringDataEntryMap entries;
+        };
 
+
+        struct TimeStep
+        {
+            long iterationId;
+            long timestampUSec;
+            long timesSinceLastIterationUSec;
+            Ice::BoolSeq   bools;
+            Ice::ByteSeq   bytes;
+            Ice::ShortSeq  shorts;
+            Ice::IntSeq    ints;
+            Ice::LongSeq   longs;
+            Ice::FloatSeq  floats;
+            Ice::DoubleSeq doubles;
+        };
+        sequence<TimeStep> TimeStepSeq;
+
+        interface Receiver
+        {
+            void update(TimeStepSeq data);
+        };
+
+        struct Config
+        {
+            Ice::StringSeq loggingNames;
+        };
+    }
+}
+
+//RobotUnit Listener
+module armarx
+{
     interface RobotUnitListener
     {
         void nJointControllerStatusChanged(NJointControllerStatusSeq status);
@@ -180,7 +244,11 @@ module armarx
         void nJointControllerCreated(string instanceName);
         void nJointControllerDeleted(string instanceName);
     };
+}
 
+//RobotUnit Modules
+module armarx
+{
     module RobotUnitModule
     {
         interface RobotUnitManagementInterface extends AggregatedRobotHealthInterface
@@ -199,6 +267,9 @@ module armarx
             void stopRtLogging(RemoteReferenceCounterBase token) throws LogicError;
 
             ["cpp:const"] void writeRecentIterationsToFile(string filePathFormatString) throws LogicError, InvalidArgumentException;
+
+            RobotUnitDataStreaming::DataStreamingDescription startDataStreaming(RobotUnitDataStreaming::Receiver* receiver, RobotUnitDataStreaming::Config config);
+            void stopDataStreaming(RobotUnitDataStreaming::Receiver* receiver);
         };
         interface RobotUnitUnitInterface
         {
@@ -210,9 +281,6 @@ module armarx
             ["cpp:const"] idempotent PlatformUnitInterface* getPlatformUnit();
             ["cpp:const"] idempotent TCPControlUnitInterface* getTCPControlUnit();
             ["cpp:const"] idempotent TrajectoryPlayerInterface* getTrajectoryPlayer();
-
-
-
         };
         interface RobotUnitPublishingInterface
         {
@@ -302,16 +370,20 @@ module armarx
             ["cpp:const"] idempotent EmergencyStopState getRtEmergencyStopState();
         };
     };
+}
 
+//RobotUnit
+module armarx
+{
     interface RobotUnitInterface extends
-            RobotUnitModule::RobotUnitUnitInterface,
-            RobotUnitModule::RobotUnitDevicesInterface,
-            RobotUnitModule::RobotUnitLoggingInterface,
-            RobotUnitModule::RobotUnitPublishingInterface,
-            RobotUnitModule::RobotUnitManagementInterface,
-            RobotUnitModule::RobotUnitControlThreadInterface,
-            RobotUnitModule::RobotUnitControllerManagementInterface,
-            RobotUnitModule::RobotUnitSelfCollisionCheckerInterface
+        RobotUnitModule::RobotUnitUnitInterface,
+        RobotUnitModule::RobotUnitDevicesInterface,
+        RobotUnitModule::RobotUnitLoggingInterface,
+        RobotUnitModule::RobotUnitPublishingInterface,
+        RobotUnitModule::RobotUnitManagementInterface,
+        RobotUnitModule::RobotUnitControlThreadInterface,
+        RobotUnitModule::RobotUnitControllerManagementInterface,
+        RobotUnitModule::RobotUnitSelfCollisionCheckerInterface
     {
     };
 };