diff --git a/source/RobotAPI/components/units/RobotUnit/Devices/GlobalRobotPoseSensorDevice.cpp b/source/RobotAPI/components/units/RobotUnit/Devices/GlobalRobotPoseSensorDevice.cpp
index 0a11b09754f6a47f7b52e3fe0958f66aeeb034bd..2bb041a7b577bf9a9443dcb4f405949e840a636e 100644
--- a/source/RobotAPI/components/units/RobotUnit/Devices/GlobalRobotPoseSensorDevice.cpp
+++ b/source/RobotAPI/components/units/RobotUnit/Devices/GlobalRobotPoseSensorDevice.cpp
@@ -121,10 +121,14 @@ namespace armarx
         const IceUtil::Time& sensorValuesTimestamp,
         const IceUtil::Time& timeSinceLastIteration)
     {
-
-        if (sensorGlobalPositionCorrection == nullptr or sensorRelativePosition == nullptr)
+        if (sensorGlobalPositionCorrection == nullptr)
+        {
+            ARMARX_ERROR << "The global position correction sensor is not available.";
+            return;
+        }
+        if (sensorRelativePosition == nullptr)
         {
-            ARMARX_ERROR << "one of the sensors is not available";
+            ARMARX_ERROR << "The relative position sensor is not available.";
             return;
         }
 
diff --git a/source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointCartesianWaypointController.cpp b/source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointCartesianWaypointController.cpp
index 697b087cc7f0b53edc3196b499c0f76dd3dec312..08870cfcc27981ee9e0e97f096563a35a1f51507 100644
--- a/source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointCartesianWaypointController.cpp
+++ b/source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointCartesianWaypointController.cpp
@@ -129,8 +129,8 @@ namespace armarx
         }
         //visu
         {
-            _tripFakeRobotGP.getWriteBuffer()(0, 0) = std::nanf("");
-            _tripFakeRobotGP.commitWrite();
+            _tripRt2NonRtRobotGP.getWriteBuffer().setIdentity();
+            _tripRt2NonRtRobotGP.commitWrite();
         }
     }
 
@@ -281,6 +281,9 @@ namespace armarx
             }
         }
         _tripRt2NonRt.commitWrite();
+
+        _tripRt2NonRtRobotGP.getWriteBuffer() = _rtRobot->getGlobalPose();
+        _tripRt2NonRtRobotGP.commitWrite();
     }
 
     void
@@ -412,17 +415,13 @@ namespace armarx
     NJointCartesianWaypointController::setVisualizationRobotGlobalPose(const Eigen::Matrix4f& p,
                                                                        const Ice::Current&)
     {
-        std::lock_guard g{_tripFakeRobotGPWriteMutex};
-        _tripFakeRobotGP.getWriteBuffer() = p;
-        _tripFakeRobotGP.commitWrite();
+        ; // No longer used ...
     }
 
     void
     NJointCartesianWaypointController::resetVisualizationRobotGlobalPose(const Ice::Current&)
     {
-        std::lock_guard g{_tripFakeRobotGPWriteMutex};
-        _tripFakeRobotGP.getWriteBuffer()(0, 0) = std::nanf("");
-        _tripFakeRobotGP.commitWrite();
+        ; // No longer used ...
     }
 
     void
@@ -477,7 +476,7 @@ namespace armarx
             std::lock_guard g{_tripRt2NonRtMutex};
             const auto& buf = _tripRt2NonRt.getUpToDateReadBuffer();
 
-            const Eigen::Matrix4f fakeGP = _tripFakeRobotGP.getUpToDateReadBuffer();
+            const Eigen::Matrix4f fakeGP = _tripRt2NonRtRobotGP.getUpToDateReadBuffer();
             const Eigen::Matrix4f gp = std::isfinite(fakeGP(0, 0)) ? fakeGP : buf.rootPose;
 
             if (buf.tcp != buf.tcpTarg)
diff --git a/source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointCartesianWaypointController.h b/source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointCartesianWaypointController.h
index dce6aed44f8bb931baf2a598c06f127cb9b20d66..59734617b4bb75cd3599f0d2c198beb7e7694bc0 100644
--- a/source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointCartesianWaypointController.h
+++ b/source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointCartesianWaypointController.h
@@ -146,8 +146,7 @@ namespace armarx
         mutable std::recursive_mutex _tripRt2NonRtMutex;
         TripleBuffer<RtToNonRtData> _tripRt2NonRt;
 
-        mutable std::recursive_mutex _tripFakeRobotGPWriteMutex;
-        TripleBuffer<Eigen::Matrix4f> _tripFakeRobotGP;
+        TripleBuffer<Eigen::Matrix4f> _tripRt2NonRtRobotGP;
 
         //publish data
         std::atomic_size_t _publishWpsNum{0};
diff --git a/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleDevices.cpp b/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleDevices.cpp
index e9aea0a9858d85e24b9e49ee088c18405af0668a..61d0d6c3a63f6a82f981eed63a61d6cabd57105e 100644
--- a/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleDevices.cpp
+++ b/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleDevices.cpp
@@ -722,7 +722,7 @@ namespace armarx::RobotUnitModule
             for (std::size_t idxRobot = 0; idxRobot < nodes.size(); ++idxRobot)
             {
                 const VirtualRobot::RobotNodePtr& node = nodes.at(idxRobot);
-                if (node->isRotationalJoint() || node->isTranslationalJoint())
+                if (node->isJoint())
                 {
                     const auto& name = node->getName();
                     if (sensorDevices.has(name))
diff --git a/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleLogging.cpp b/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleLogging.cpp
index 8cb11c331040c5dfd12fea456c0d2391a36c9f2b..ee8522d21984cbf6936bd1b2c259e37850398d7f 100644
--- a/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleLogging.cpp
+++ b/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleLogging.cpp
@@ -494,10 +494,13 @@ namespace armarx::RobotUnitModule
         ARMARX_TRACE;
         throwIfInControlThread(BOOST_CURRENT_FUNCTION);
         std::lock_guard<std::mutex> guard{rtLoggingMutex};
-        if (!rtDataStreamingEntry.count(receiver))
+        
+        if (rtDataStreamingEntry.count(receiver) == 0u)
         {
-            throw InvalidArgumentException{"stopDataStreaming called for a nonexistent log"};
+            ARMARX_INFO << "stopDataStreaming called for a nonexistent log";
+            return;
         }
+
         ARMARX_INFO_S << "RobotUnit: request to stop DataStreaming for " << receiver->ice_id();
         rtDataStreamingEntry.at(receiver).stopStreaming = true;
     }
diff --git a/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleRobotData.cpp b/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleRobotData.cpp
index a7083b662e54b0a0c02ad847c3e0f197bce74d58..cc1e89e592642c8adbd137c071023a472284e4ec 100644
--- a/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleRobotData.cpp
+++ b/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleRobotData.cpp
@@ -33,6 +33,44 @@
 
 namespace armarx::RobotUnitModule
 {
+
+    RobotDataPropertyDefinitions::RobotDataPropertyDefinitions(std::string prefix) :
+        ModuleBasePropertyDefinitions(prefix)
+    {
+        defineRequiredProperty<std::string>("RobotFileName",
+                                            "Robot file name, e.g. robot_model.xml");
+        defineOptionalProperty<std::string>("RobotFileNameProject",
+                                            "",
+                                            "Project in which the robot filename is located "
+                                            "(if robot is loaded from an external project)");
+
+        defineOptionalProperty<std::string>(
+            "RobotName",
+            "",
+            "Override robot name if you want to load multiple robots of the same type");
+        defineOptionalProperty<std::string>(
+            "RobotNodeSetName",
+            "Robot",
+            "Robot node set name as defined in robot xml file, e.g. 'LeftArm'");
+        defineOptionalProperty<std::string>(
+            "PlatformName",
+            "Platform",
+            "Name of the platform needs to correspond to a node in the virtual robot.");
+        defineOptionalProperty<bool>("PlatformAndLocalizationUnitsEnabled",
+                                     true,
+                                     "Enable or disable the platform and localization units.");
+        defineOptionalProperty<std::string>("PlatformInstanceName",
+                                            "Platform",
+                                            "Name of the platform instance (will publish "
+                                            "values on PlatformInstanceName + 'State')");
+    }
+
+    bool
+    RobotData::arePlatformAndLocalizationUnitsEnabled() const
+    {
+        return _arePlatformAndLocalizationUnitsEnabled;
+    }
+
     const std::string&
     RobotData::getRobotPlatformName() const
     {
@@ -112,6 +150,8 @@ namespace armarx::RobotUnitModule
         robotProjectName = getProperty<std::string>("RobotFileNameProject").getValue();
         robotFileName = getProperty<std::string>("RobotFileName").getValue();
         robotPlatformName = getProperty<std::string>("PlatformName").getValue();
+        _arePlatformAndLocalizationUnitsEnabled =
+            getProperty<bool>("PlatformAndLocalizationUnitsEnabled").getValue();
         robotPlatformInstanceName = getProperty<std::string>("PlatformInstanceName").getValue();
 
         //load robot
@@ -160,4 +200,5 @@ namespace armarx::RobotUnitModule
             robotPool.reset(new RobotPool(robot, 10));
         }
     }
+
 } // namespace armarx::RobotUnitModule
diff --git a/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleRobotData.h b/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleRobotData.h
index 7b5defcbfbec169a83e7185f688a5016851c24ab..c6e94bd515bea5a6f88597c935eb277c234a33d2 100644
--- a/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleRobotData.h
+++ b/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleRobotData.h
@@ -40,32 +40,7 @@ namespace armarx::RobotUnitModule
     class RobotDataPropertyDefinitions : public ModuleBasePropertyDefinitions
     {
     public:
-        RobotDataPropertyDefinitions(std::string prefix) : ModuleBasePropertyDefinitions(prefix)
-        {
-            defineRequiredProperty<std::string>("RobotFileName",
-                                                "Robot file name, e.g. robot_model.xml");
-            defineOptionalProperty<std::string>("RobotFileNameProject",
-                                                "",
-                                                "Project in which the robot filename is located "
-                                                "(if robot is loaded from an external project)");
-
-            defineOptionalProperty<std::string>(
-                "RobotName",
-                "",
-                "Override robot name if you want to load multiple robots of the same type");
-            defineOptionalProperty<std::string>(
-                "RobotNodeSetName",
-                "Robot",
-                "Robot node set name as defined in robot xml file, e.g. 'LeftArm'");
-            defineOptionalProperty<std::string>(
-                "PlatformName",
-                "Platform",
-                "Name of the platform needs to correspond to a node in the virtual robot.");
-            defineOptionalProperty<std::string>("PlatformInstanceName",
-                                                "Platform",
-                                                "Name of the platform instance (will publish "
-                                                "values on PlatformInstanceName + 'State')");
-        }
+        RobotDataPropertyDefinitions(std::string prefix);
     };
 
     /**
@@ -99,21 +74,26 @@ namespace armarx::RobotUnitModule
         // /////////////////////////////////// Module interface /////////////////////////////////// //
         // //////////////////////////////////////////////////////////////////////////////////////// //
     public:
+        bool arePlatformAndLocalizationUnitsEnabled() const;
+
         /**
          * @brief Returns the name of the robot's platform
          * @return The name of the robot's platform
          */
         const std::string& getRobotPlatformName() const;
+
         /**
          * @brief Returns the name of the robot's RobotNodeSet
          * @return The name of the robot's RobotNodeSet
          */
         const std::string& getRobotNodetSeName() const;
+
         /**
          * @brief Returns the name of the project containing the robot's model
          * @return The name of the project containing the robot's model
          */
         const std::string& getRobotProjectName() const;
+
         /**
          * @brief Returns the file name of the robot's model
          * @return The file name of the robot's model
@@ -150,6 +130,8 @@ namespace armarx::RobotUnitModule
         std::string robotFileName;
         /// @brief The name of the robot's platform
         std::string robotPlatformName;
+        /// @brief Indicates whether the robot platform unit is enabled.
+        bool _arePlatformAndLocalizationUnitsEnabled = false;
         /// @brief The name of the robot's platform instance
         std::string robotPlatformInstanceName;
 
diff --git a/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleSelfCollisionChecker.cpp b/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleSelfCollisionChecker.cpp
index a4d9867488a2a2f8e9cb176158ba18fc01a8c538..698df2657899773a1a111bd02ce561abd66308ef 100644
--- a/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleSelfCollisionChecker.cpp
+++ b/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleSelfCollisionChecker.cpp
@@ -21,12 +21,17 @@
  */
 
 #include "RobotUnitModuleSelfCollisionChecker.h"
+#include <algorithm>
+#include <cstddef>
+#include <string>
 
 #include <SimoxUtility/algorithm/string/string_tools.h>
 #include <VirtualRobot/CollisionDetection/CollisionChecker.h>
 #include <VirtualRobot/Obstacle.h>
 #include <VirtualRobot/RobotNodeSet.h>
 
+#include "ArmarXCore/core/logging/Logging.h"
+#include "ArmarXCore/core/time/Metronome.h"
 #include <ArmarXCore/core/util/OnScopeExit.h>
 
 #include <RobotAPI/components/units/RobotUnit/NJointControllers/NJointControllerBase.h>
@@ -219,6 +224,58 @@ namespace armarx::RobotUnitModule
                 node->getCollisionModel()->inflateModel(minSelfDistance / 2.f);
             }
         }
+
+        // Remove / filter collision pairs according to robot model (XML: Physics/IgnoreCollision)
+        {
+            ARMARX_VERBOSE << "Removing ignored collision pairs";
+            // introduce vector to remove elements "in-place" via remove-erase-if idiom (not possible for sets)
+            std::vector<std::pair<std::string, std::string>> validNamePairsToCheck(namePairsToCheck.begin(), namePairsToCheck.end());
+
+            const auto isCollisionIgnored = [this](const std::string& a, const std::string& b) -> bool {
+
+                if(a == FLOOR_OBJ_STR or b == FLOOR_OBJ_STR)
+                {
+                    return false;
+                }
+
+                const auto nodeA = selfCollisionAvoidanceRobot->getRobotNode(a);
+                const auto nodeB = selfCollisionAvoidanceRobot->getRobotNode(b);
+
+                if(nodeA == nullptr or nodeB == nullptr)
+                {
+                    return false;
+                }
+
+                const std::vector<std::string> nodesIgnoredByA = nodeA->getIgnoredCollisionModels();
+                const std::vector<std::string> nodesIgnoredByB = nodeB->getIgnoredCollisionModels();
+
+                if(std::find(nodesIgnoredByA.begin(), nodesIgnoredByA.end(), b) != nodesIgnoredByA.end())
+                {
+                    ARMARX_VERBOSE << "Ignoring collision between nodes: " << a << " -- " << b;
+                    return true;
+                }
+
+                if(std::find(nodesIgnoredByB.begin(), nodesIgnoredByB.end(), a) != nodesIgnoredByB.end())
+                {
+                    ARMARX_VERBOSE << "Ignoring collision between nodes: " << b << " -- " << a;
+                    return true;
+                }
+
+                return false;
+
+            };
+
+            validNamePairsToCheck.erase(std::remove_if(validNamePairsToCheck.begin(), validNamePairsToCheck.end(), [&isCollisionIgnored](const auto& p) -> bool {
+                const auto& [a, b] = p;
+                return isCollisionIgnored(a, b);
+            }), validNamePairsToCheck.end());
+
+            ARMARX_VERBOSE << "Removed " << (namePairsToCheck.size() - validNamePairsToCheck.size()) << " collision pairs.";
+
+            // copy over name pairs which should not be ignored
+            namePairsToCheck = std::set(validNamePairsToCheck.begin(), validNamePairsToCheck.end());
+        }
+
         //collect pairs
         for (const auto& pair : namePairsToCheck)
         {
@@ -227,14 +284,18 @@ namespace armarx::RobotUnitModule
                     ? floor->getSceneObject(0)
                     : selfCollisionAvoidanceRobot->getRobotNode(pair.first);
 
+            ARMARX_CHECK_NOT_NULL(first) << pair.first;
+
             VirtualRobot::SceneObjectPtr second =
                 (pair.second == FLOOR_OBJ_STR)
                     ? floor->getSceneObject(0)
                     : selfCollisionAvoidanceRobot->getRobotNode(pair.second);
 
+            ARMARX_CHECK_NOT_NULL(second) << pair.second;
+
             nodePairsToCheck.emplace_back(first, second);
         }
-        ARMARX_CHECK_EQUAL(nodePairsToCheck.size(), nodePairsToCheck.size());
+        ARMARX_CHECK_EQUAL(nodePairsToCheck.size(), namePairsToCheck.size());
     }
 
     void
@@ -303,21 +364,23 @@ namespace armarx::RobotUnitModule
         };
         while (true)
         {
-            const auto startT = std::chrono::high_resolution_clock::now();
+            const auto freq = checkFrequency.load();
+
+            core::time::Metronome metronome(Frequency::Hertz(freq));
+
             //done
             if (isShuttingDown())
             {
                 return;
             }
-            const auto freq = checkFrequency.load();
             const bool inEmergencyStop =
                 _module<ControlThread>().getEmergencyStopState() == eEmergencyStopActive;
             if (inEmergencyStop || freq == 0)
             {
-                ARMARX_INFO << deactivateSpam() << "Self collision checker: skipping check "
+                ARMARX_VERBOSE << deactivateSpam() << "Self collision checker: skipping check "
                             << VAROUT(freq) << " " << VAROUT(inEmergencyStop);
                 //currently wait
-                std::this_thread::sleep_for(std::chrono::microseconds{1000});
+                std::this_thread::sleep_for(std::chrono::microseconds{1'000});
                 continue;
             }
             //update robot + check
@@ -332,6 +395,7 @@ namespace armarx::RobotUnitModule
                     bool allJoints0 = true;
                     for (const auto& node : selfCollisionAvoidanceRobotNodes)
                     {
+                        ARMARX_CHECK_NOT_NULL(node);
                         if (0 != node->getJointValue())
                         {
                             allJoints0 = false;
@@ -348,6 +412,10 @@ namespace armarx::RobotUnitModule
                 for (std::size_t idx = 0; idx < nodePairsToCheck.size(); ++idx)
                 {
                     const auto& pair = nodePairsToCheck.at(idx);
+
+                    ARMARX_CHECK_NOT_NULL(pair.first);
+                    ARMARX_CHECK_NOT_NULL(pair.second);
+
                     if (selfCollisionAvoidanceRobot->getCollisionChecker()->checkCollision(
                             pair.first, pair.second))
                     {
@@ -370,9 +438,16 @@ namespace armarx::RobotUnitModule
                                    << nodePairsToCheck.size() << " pairs";
                 }
             }
+
             //sleep remaining
-            std::this_thread::sleep_until(
-                startT + std::chrono::microseconds{static_cast<int64_t>(1000000 / freq)});
+            const auto duration = metronome.waitForNextTick();
+
+            if(not duration.isPositive())
+            {
+                ARMARX_WARNING << deactivateSpam(10) << 
+                    "Self collision checking took too long. "
+                    "Exceeding time budget by " << duration.toMilliSecondsDouble() << "ms.";
+            }
         }
     }
 
diff --git a/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleUnits.cpp b/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleUnits.cpp
index ad3cc0f97680eabc2519b58598823294c770733f..bd92c93f31a9007c338b9ae4bcd52d9ebe1c4d50 100644
--- a/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleUnits.cpp
+++ b/source/RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleUnits.cpp
@@ -163,29 +163,54 @@ namespace armarx::RobotUnitModule
     void
     Units::initializeDefaultUnits()
     {
+        ARMARX_TRACE;
         throwIfInControlThread(BOOST_CURRENT_FUNCTION);
         auto beg = TimeUtil::GetTime(true);
         {
+            ARMARX_TRACE;
             auto guard = getGuard();
+
+            ARMARX_TRACE;
             throwIfStateIsNot(RobotUnitState::InitializingUnits, __FUNCTION__);
             ARMARX_INFO << "initializing default units";
+
+            ARMARX_TRACE;
             initializeKinematicUnit();
             ARMARX_DEBUG << "KinematicUnit initialized";
 
-            ARMARX_DEBUG << "initializing LocalizationUnit";
-            initializeLocalizationUnit();
-            ARMARX_DEBUG << "LocalizationUnit initialized";
+            ARMARX_TRACE;
+            if (_module<RobotData>().arePlatformAndLocalizationUnitsEnabled())
+            {
+                ARMARX_DEBUG << "initializing LocalizationUnit";
+                initializeLocalizationUnit();
+                ARMARX_DEBUG << "LocalizationUnit initialized";
+            }
+            ARMARX_TRACE;
+
+            if (_module<RobotData>().arePlatformAndLocalizationUnitsEnabled())
+            {
+                ARMARX_DEBUG << "initializing PlatformUnit";
+                initializePlatformUnit();
+                ARMARX_DEBUG << "PlatformUnit initialized";
+            }
 
-            initializePlatformUnit();
-            ARMARX_DEBUG << "PlatformUnit initialized";
+            ARMARX_TRACE;
             initializeForceTorqueUnit();
             ARMARX_DEBUG << "ForceTorqueUnit initialized";
+
+            ARMARX_TRACE;
             initializeInertialMeasurementUnit();
             ARMARX_DEBUG << "InertialMeasurementUnit initialized";
+
+            ARMARX_TRACE;
             initializeTrajectoryControllerUnit();
             ARMARX_DEBUG << "TrajectoryControllerUnit initialized";
+
+            ARMARX_TRACE;
             initializeTcpControllerUnit();
             ARMARX_DEBUG << "TcpControllerUnit initialized";
+
+            ARMARX_TRACE;
         }
         ARMARX_INFO << "initializing default units...done! "
                     << (TimeUtil::GetTime(true) - beg).toMicroSeconds() << " us";
@@ -371,6 +396,8 @@ namespace armarx::RobotUnitModule
         using UnitT = PlatformSubUnit;
         using IfaceT = PlatformUnitInterface;
 
+        ARMARX_TRACE;
+
         auto guard = getGuard();
         throwIfStateIsNot(RobotUnitState::InitializingUnits, __FUNCTION__);
         //check if unit is already added
@@ -378,12 +405,14 @@ namespace armarx::RobotUnitModule
         {
             return;
         }
+        ARMARX_TRACE;
         //is there a platform dev?
         if (_module<RobotData>().getRobotPlatformName().empty())
         {
             ARMARX_INFO << "no platform unit created since no platform name was given";
             return;
         }
+        ARMARX_TRACE;
         if (!_module<Devices>().getControlDevices().has(
                 _module<RobotData>().getRobotPlatformName()))
         {
@@ -392,16 +421,19 @@ namespace armarx::RobotUnitModule
                 << _module<RobotData>().getRobotPlatformName() << "' was not found";
             return;
         }
+        ARMARX_TRACE;
         const ControlDevicePtr& controlDevice =
             _module<Devices>().getControlDevices().at(_module<RobotData>().getRobotPlatformName());
         const SensorDevicePtr& sensorDevice =
             _module<Devices>().getSensorDevices().at(_module<RobotData>().getRobotPlatformName());
         JointController* jointVel =
             controlDevice->getJointController(ControlModes::HolonomicPlatformVelocity);
+        ARMARX_TRACE;
         ARMARX_CHECK_EXPRESSION(jointVel);
         ARMARX_CHECK_EXPRESSION(
             sensorDevice->getSensorValue()->asA<SensorValueHolonomicPlatform>());
         //add it
+        ARMARX_TRACE;
         const std::string configName = getProperty<std::string>("PlatformUnitName");
         const std::string confPre = getConfigDomain() + "." + configName + ".";
         Ice::PropertiesPtr properties = getIceProperties()->clone();
@@ -411,9 +443,11 @@ namespace armarx::RobotUnitModule
                                 _module<RobotData>().getRobotPlatformInstanceName());
         ARMARX_DEBUG << "creating unit " << configName
                      << " using these properties: " << properties->getPropertiesForPrefix("");
+        ARMARX_TRACE;
         IceInternal::Handle<UnitT> unit =
             Component::create<UnitT>(properties, configName, getConfigDomain());
         //config
+        ARMARX_TRACE;
         NJointHolonomicPlatformUnitVelocityPassThroughControllerConfigPtr config =
             new NJointHolonomicPlatformUnitVelocityPassThroughControllerConfig;
         config->initialVelocityX = 0;
@@ -427,8 +461,10 @@ namespace armarx::RobotUnitModule
                 config,
                 false,
                 true));
+        ARMARX_TRACE;
         ARMARX_CHECK_EXPRESSION(ctrl);
         unit->pt = ctrl;
+        ARMARX_TRACE;
 
         NJointHolonomicPlatformRelativePositionControllerConfigPtr configRelativePositionCtrlCfg =
             new NJointHolonomicPlatformRelativePositionControllerConfig;
@@ -457,9 +493,11 @@ namespace armarx::RobotUnitModule
                 configGlobalPositionCtrlCfg,
                 false,
                 true));
+        ARMARX_TRACE;
         ARMARX_CHECK_EXPRESSION(ctrlGlobalPosition);
         unit->pt = ctrl;
         unit->globalPosCtrl = ctrlGlobalPosition;
+        ARMARX_TRACE;
 
         unit->platformSensorIndex = _module<Devices>().getSensorDevices().index(
             _module<RobotData>().getRobotPlatformName());
@@ -470,12 +508,14 @@ namespace armarx::RobotUnitModule
     void
     Units::initializeLocalizationUnit()
     {
+        ARMARX_TRACE;
         ARMARX_DEBUG << "initializeLocalizationUnit";
 
         throwIfInControlThread(BOOST_CURRENT_FUNCTION);
         using UnitT = LocalizationSubUnit;
         using IfaceT = LocalizationUnitInterface;
 
+        ARMARX_TRACE;
         auto guard = getGuard();
         throwIfStateIsNot(RobotUnitState::InitializingUnits, __FUNCTION__);
         //check if unit is already added
@@ -483,13 +523,18 @@ namespace armarx::RobotUnitModule
         {
             return;
         }
+        ARMARX_TRACE;
 
         ARMARX_DEBUG << "Getting device SensorValueHolonomicPlatformRelativePosition";
+        ARMARX_CHECK(
+            _module<Devices>().getSensorDevices().has(_module<RobotData>().getRobotPlatformName()))
+            << _module<RobotData>().getRobotPlatformName();
         const SensorDevicePtr& sensorDeviceRelativePosition =
             _module<Devices>().getSensorDevices().at(_module<RobotData>().getRobotPlatformName());
         ARMARX_CHECK_EXPRESSION(sensorDeviceRelativePosition->getSensorValue()
                                     ->asA<SensorValueHolonomicPlatformRelativePosition>());
 
+        ARMARX_TRACE;
         // const SensorDevicePtr& sensorDevicePoseCorrection = _module<Devices>().getSensorDevices().at(GlobalRobotPoseCorrectionSensorDevice::DeviceName());
         // ARMARX_CHECK_EXPRESSION(sensorDeviceRelativePosition->getSensorValue()->asA<SensorValueGlobalPoseCorrection>());
 
diff --git a/source/RobotAPI/components/units/RobotUnit/util/ControlThreadOutputBuffer.cpp b/source/RobotAPI/components/units/RobotUnit/util/ControlThreadOutputBuffer.cpp
index e1c717c58e00be94df3035916b5d3d4f0a50a589..bedfc430f0dee9f2030ac495d2ba6dd74bfa1350 100644
--- a/source/RobotAPI/components/units/RobotUnit/util/ControlThreadOutputBuffer.cpp
+++ b/source/RobotAPI/components/units/RobotUnit/util/ControlThreadOutputBuffer.cpp
@@ -82,8 +82,8 @@ namespace armarx
     ControlThreadOutputBuffer::forEachNewLoggingEntry(ConsumerFunctor consumer)
     {
         ARMARX_TRACE;
-        ARMARX_CHECK_EXPRESSION(isInitialized);
-        ARMARX_VERBOSE << VAROUT(entries.size());
+        ARMARX_CHECK(isInitialized);
+        ARMARX_DEBUG << VAROUT(entries.size());
         const size_t writePosition_local = writePosition.load(); // copy to prevent external changes
         if (writePosition_local - onePastLoggingReadPosition >= numEntries)
         {
@@ -107,7 +107,7 @@ namespace armarx
         }
         //consume all
         const std::size_t num = writePosition_local - onePastLoggingReadPosition;
-        ARMARX_VERBOSE << num << " new entries to be treated";
+        ARMARX_DEBUG << num << " new entries to be treated";
         for (std::size_t offset = 0; onePastLoggingReadPosition < writePosition_local;
              ++onePastLoggingReadPosition, ++offset)
         {
@@ -276,10 +276,8 @@ namespace armarx
         }
     }
 
-    const auto PotentiallyMinimizeMember = [](auto & member, bool minimize) {
-        return minimize ? 0 : member;
-    };
-
+    const auto PotentiallyMinimizeMember = [](auto& member, bool minimize)
+    { return minimize ? 0 : member; };
 
     detail::RtMessageLogBuffer::RtMessageLogBuffer(const detail::RtMessageLogBuffer& other,
                                                    bool minimize) :
@@ -301,13 +299,13 @@ namespace armarx
         maxAlign{1}
     {
         ARMARX_DEBUG << "copying RtMessageLogBuffer with minimize = " << minimize << " "
-                    << VAROUT(initialBufferSize) << " " << VAROUT(initialBufferEntryNumbers) << " "
-                    << VAROUT(bufferMaxSize) << " " << VAROUT(bufferMaxNumberEntries) << " "
-                    << VAROUT(buffer.size()) << " " << VAROUT(other.bufferSpace) << " "
-                    << VAROUT(bufferPlace) << " " << VAROUT(entries.size()) << " "
-                    << VAROUT(entriesWritten) << " " << VAROUT(requiredAdditionalBufferSpace) << " "
-                    << VAROUT(requiredAdditionalEntries) << " " << VAROUT(messagesLost) << " "
-                    << VAROUT(maxAlign);
+                     << VAROUT(initialBufferSize) << " " << VAROUT(initialBufferEntryNumbers) << " "
+                     << VAROUT(bufferMaxSize) << " " << VAROUT(bufferMaxNumberEntries) << " "
+                     << VAROUT(buffer.size()) << " " << VAROUT(other.bufferSpace) << " "
+                     << VAROUT(bufferPlace) << " " << VAROUT(entries.size()) << " "
+                     << VAROUT(entriesWritten) << " " << VAROUT(requiredAdditionalBufferSpace)
+                     << " " << VAROUT(requiredAdditionalEntries) << " " << VAROUT(messagesLost)
+                     << " " << VAROUT(maxAlign);
         for (std::size_t idx = 0; idx < other.entries.size() && other.entries.at(idx); ++idx)
         {
             const RtMessageLogEntryBase* entry = other.entries.at(idx);
@@ -361,10 +359,12 @@ namespace armarx
         deleteAll();
         if (requiredAdditionalEntries || entries.size() < numEntries)
         {
-            const auto numExcessEntries = std::max(requiredAdditionalEntries, numEntries - entries.size());
+            const auto numExcessEntries =
+                std::max(requiredAdditionalEntries, numEntries - entries.size());
             const auto requiredSize = entries.size() + numExcessEntries;
             ARMARX_WARNING << "Iteration " << iterationCount << " required "
-                           << requiredAdditionalEntries << " | " << numExcessEntries << " additional message entries. \n"
+                           << requiredAdditionalEntries << " | " << numExcessEntries
+                           << " additional message entries. \n"
                            << "The requested total number of entries is " << requiredSize << ". \n"
                            << "The current number of entries is " << entries.size() << ". \n"
                            << "The maximal number of entries is "
@@ -514,10 +514,10 @@ namespace armarx
     {
         ARMARX_TRACE;
         ARMARX_DEBUG << "Copy ControlThreadOutputBufferEntry with parameters: " << VAROUT(minimize)
-                    << " " << VAROUT(writeTimestamp) << " " << VAROUT(sensorValuesTimestamp) << " "
-                    << VAROUT(timeSinceLastIteration) << " " << VAROUT(iteration) << " "
-                    << VAROUT(buffer.size()) << " " << VAROUT(messages.buffer.size()) << " "
-                    << VAROUT(messages.entries.size());
+                     << " " << VAROUT(writeTimestamp) << " " << VAROUT(sensorValuesTimestamp) << " "
+                     << VAROUT(timeSinceLastIteration) << " " << VAROUT(iteration) << " "
+                     << VAROUT(buffer.size()) << " " << VAROUT(messages.buffer.size()) << " "
+                     << VAROUT(messages.entries.size());
         void* place = buffer.data();
         std::size_t space = buffer.size();
 
diff --git a/source/RobotAPI/components/units/RobotUnit/util/introspection/ClassMemberInfo.h b/source/RobotAPI/components/units/RobotUnit/util/introspection/ClassMemberInfo.h
index b247f12167424f45a2e87c690461d5aaab5516d0..129771f55fec581f806de5e09d8c7a7d928f2ac5 100644
--- a/source/RobotAPI/components/units/RobotUnit/util/introspection/ClassMemberInfo.h
+++ b/source/RobotAPI/components/units/RobotUnit/util/introspection/ClassMemberInfo.h
@@ -114,7 +114,7 @@ namespace armarx::introspection
                                                             const std::string& name)
     {
         ARMARX_TRACE;
-        ARMARX_CHECK_EQUAL(0, entries.count(name));
+        ARMARX_CHECK_EQUAL(entries.count(name), 0) << name;
         entries.add(name, Entry(name, ptr));
         return entries.at(name);
     }
diff --git a/source/RobotAPI/drivers/GamepadUnit/GamepadUnit.cpp b/source/RobotAPI/drivers/GamepadUnit/GamepadUnit.cpp
index 1431b8b5219ef4622d21024132397690a81d9526..1e7dacc348c3101705f4ae650ab978b031cd23d7 100644
--- a/source/RobotAPI/drivers/GamepadUnit/GamepadUnit.cpp
+++ b/source/RobotAPI/drivers/GamepadUnit/GamepadUnit.cpp
@@ -33,6 +33,7 @@ void GamepadUnit::onInitComponent()
     ARMARX_TRACE;
     offeringTopic(getProperty<std::string>("GamepadTopicName").getValue());
     deviceName = getProperty<std::string>("GamepadDeviceName").getValue();
+    deviceEventName = getProperty<std::string>("GamepadForceFeedbackName").getValue();
     readTask = new RunningTask<GamepadUnit>(this, &GamepadUnit::run, "GamepadUnit");
 }
 
@@ -69,15 +70,23 @@ void GamepadUnit::onConnectComponent()
             ARMARX_INFO << deactivateSpam(100000, std::to_string(dataTimestamp->getTimestamp())) << "No new signal from gamepad for " << age.toMilliSecondsDouble() << " milliseconds. Not sending data. Timeout: " <<  getProperty<int>("PublishTimeout").getValue() << " ms";
         }
     }, 30);
+    
     sendTask->start();
     ARMARX_TRACE;
     openGamepadConnection();
 }
 
+void GamepadUnit::vibrate(const ::Ice::Current&)
+{
+    ARMARX_INFO << "vibration!";
+    js.executeEffect();
+}
+
 bool GamepadUnit::openGamepadConnection()
 {
-    if (js.open(deviceName))
+    if (js.open(deviceName, deviceEventName))
     {
+
         ARMARX_TRACE;
         ARMARX_INFO << "opened a gamepad named " << js.name << " with " << js.numberOfAxis << " axis and " << js.numberOfButtons << " buttons.";
         if (js.numberOfAxis == 8 && js.numberOfButtons == 11)
@@ -185,4 +194,3 @@ armarx::PropertyDefinitionsPtr GamepadUnit::createPropertyDefinitions()
     return armarx::PropertyDefinitionsPtr(new GamepadUnitPropertyDefinitions(
             getConfigIdentifier()));
 }
-
diff --git a/source/RobotAPI/drivers/GamepadUnit/GamepadUnit.h b/source/RobotAPI/drivers/GamepadUnit/GamepadUnit.h
index 109ce81a17a98c5154b396e09064d9943be6ff0a..a2008600dc1f50432bbbf3f00c646153c7d7e83e 100644
--- a/source/RobotAPI/drivers/GamepadUnit/GamepadUnit.h
+++ b/source/RobotAPI/drivers/GamepadUnit/GamepadUnit.h
@@ -53,6 +53,7 @@ namespace armarx
             //defineOptionalProperty<std::string>("PropertyName", "DefaultValue", "Description");
             defineOptionalProperty<std::string>("GamepadTopicName", "GamepadValues", "Name of the Gamepad Topic");
             defineOptionalProperty<std::string>("GamepadDeviceName", "/dev/input/js2", "device that will be opened as a gamepad");
+            defineOptionalProperty<std::string>("GamepadForceFeedbackName", "", "device that will be used for force feedback, leave empty to disable. See RobotAPI/source/RobotAPI/drivers/GamepadUnit/README.md for more details.");
             defineOptionalProperty<int>("PublishTimeout", 2000, "In Milliseconds. Timeout after which the gamepad data is not published after, if no new data was read from the gamepad");
         }
     };
@@ -69,7 +70,8 @@ namespace armarx
      * Detailed description of class GamepadUnit.
      */
     class GamepadUnit :
-        virtual public armarx::Component
+        virtual public armarx::Component,
+        virtual public GamepadUnitInterface
     {
     public:
         /**
@@ -108,6 +110,8 @@ namespace armarx
 
         bool openGamepadConnection();
 
+        void vibrate(const ::Ice::Current& = ::Ice::emptyCurrent) override;
+
     private:
         GamepadUnitListenerPrx topicPrx;
         RunningTask<GamepadUnit>::pointer_type readTask;
@@ -116,9 +120,9 @@ namespace armarx
         void run();
         std::mutex mutex;
         std::string deviceName;
+        std::string deviceEventName;
         Joystick js;
         GamepadData data;
         TimestampVariantPtr dataTimestamp;
     };
 }
-
diff --git a/source/RobotAPI/drivers/GamepadUnit/Joystick.h b/source/RobotAPI/drivers/GamepadUnit/Joystick.h
index 1f39074b7a1449f9d58b643d42be68f2c123c445..8befbe9d5c08bd6d13220cd7c709884c906afc7b 100644
--- a/source/RobotAPI/drivers/GamepadUnit/Joystick.h
+++ b/source/RobotAPI/drivers/GamepadUnit/Joystick.h
@@ -22,12 +22,17 @@
 
 #pragma once
 
-#include<linux/joystick.h>
-#include<sys/stat.h>
-#include<fcntl.h>
+#include <cstdint>
+
+#include <fcntl.h>
+#include <sys/poll.h>
+#include <sys/stat.h>
+#include <unistd.h>
 
 #include <ArmarXCore/core/Component.h>
 
+#include <linux/joystick.h>
+
 namespace armarx
 {
 
@@ -36,21 +41,39 @@ namespace armarx
 
     private:
         int fd = -1;
+        int fdEvent = -1;
         js_event event;
 
     public:
-
         std::vector<int16_t> axis;
         std::vector<bool> buttonsPressed;
         int numberOfAxis;
         int numberOfButtons;
         std::string name;
 
-        bool open(std::string const& deviceName)
+        bool
+        open(std::string const& deviceName, std::string const& deviceEventName)
         {
+
             fd = ::open(deviceName.c_str(), O_RDONLY);
+
+            if (!deviceEventName.empty())
+            {
+                ARMARX_INFO << "Force feedback enabled";
+                fdEvent = ::open(deviceEventName.c_str(), O_RDWR | O_CLOEXEC);
+
+                ARMARX_CHECK(fdEvent != -1);
+            } else {
+                ARMARX_INFO << "Force feedback disabled";
+            }
+
             if (fd != -1)
             {
+                // ARMARX_INFO << "before";
+                // executeEffect();
+                // ARMARX_INFO << "after";
+
+
                 ioctl(fd, JSIOCGAXES, &numberOfAxis);
                 ioctl(fd, JSIOCGBUTTONS, &numberOfButtons);
                 name.resize(255);
@@ -59,15 +82,21 @@ namespace armarx
                 name = name.c_str();
                 buttonsPressed.resize(numberOfButtons, false);
             }
+
+            ARMARX_INFO << "execute effect";
+            executeEffect();
+
             return fd != -1;
         }
 
-        bool opened() const
+        bool
+        opened() const
         {
             return fd != -1;
         }
 
-        bool pollEvent()
+        bool
+        pollEvent()
         {
             int bytes = read(fd, &event, sizeof(event));
 
@@ -89,10 +118,165 @@ namespace armarx
             return true;
         }
 
-        void close()
+        void
+        executeEffect(int gain = 100, const int nTimes = 1)
+        {
+            // this feature is disabled
+            if(fdEvent < 0) return;
+
+            // see https://docs.kernel.org/input/ff.html
+
+
+            // https://xnux.eu/devices/feature/vibrator.html
+
+            int ret;
+            // pollfd pfds[1];
+            int effects;
+
+            // fd = open_event_dev("vibrator", O_RDWR | O_CLOEXEC);
+            // syscall_error(fd < 0, "Can't open vibrator event device");
+
+            ret = ioctl(fdEvent, EVIOCGEFFECTS, &effects);
+            ARMARX_CHECK(ret >= 0);
+            // syscall_error(ret < 0, "EVIOCGEFFECTS failed");
+
+            // ARMARX_CHECK(effects & FF_RUMBLE);
+
+            // Set the gain of the device
+            {
+                // int gain; between 0 and 100
+                struct input_event ie; // structure used to communicate with the driver
+
+                ie.type = EV_FF;
+                ie.code = FF_GAIN;
+                ie.value = 0xFFFFUL * gain / 100;
+
+                if (write(fdEvent, &ie, sizeof(ie)) == -1)
+                {
+                    perror("set gain");
+                }
+            }
+
+
+            ff_effect e;
+            // e.type = FF_RUMBLE;
+            // e.id = -1;
+            // e.replay.length = 5000;
+            // e.replay.delay = 500;
+            // e.u.rumble.strong_magnitude = 1;
+
+            e.type = FF_PERIODIC;
+            e.id = -1;
+            e.replay.length = 5000;
+            e.replay.delay = 500;
+            e.u.periodic.waveform = FF_SQUARE;
+            e.u.periodic.period = 1000;
+            e.u.periodic.magnitude = 0xFF;
+            e.u.periodic.offset = 0xFF;
+
+            ret = ioctl(fdEvent, EVIOCSFF, &e);
+            ARMARX_CHECK(ret >= 0);
+
+            // syscall_error(ret < 0, "EVIOCSFF failed");
+
+            ARMARX_INFO << VAROUT(e.id);
+
+            input_event play;
+            play.type = EV_FF;
+            play.code = static_cast<std::uint16_t>(e.id);
+            play.value = 1;
+
+            ret = write(fdEvent, &play, sizeof(play));
+            ARMARX_CHECK(ret >= 0);
+
+            ARMARX_INFO << "Executing effect";
+
+
+            for (int i = 0; i < 5; i++)
+            {
+                
+                input_event statusIe; // structure used to communicate with the driver
+                statusIe.type = EV_FF_STATUS;
+                statusIe.code = e.id;
+                // statusIe.value = 0;
+
+                ret = write(fdEvent, &statusIe, sizeof(statusIe));
+
+                // ARMARX_CHECK()
+                // ret should be FF_STATUS_PLAYING
+                ARMARX_INFO << VAROUT(ret);
+
+                sleep(1);
+            }
+
+
+            // syscall_error(ret < 0, "write failed");
+
+            ARMARX_INFO << "Executing effect";
+            // sleep(6);
+
+
+            input_event stop;
+            stop.type = EV_FF;
+            stop.code = e.id;
+            stop.value = 0;
+            const int stopStatus = write(fdEvent, static_cast<const void*>(&stop), sizeof(stop));
+
+
+            ret = ioctl(fdEvent, EVIOCRMFF, e.id);
+            ARMARX_CHECK(ret >= 0);
+
+            // syscall_error(ret < 0, "EVIOCRMFF failed");
+
+            // close(fdEvent);
+
+
+            /**/
+            // Set the gain of the device
+            // {
+            //     // int gain; between 0 and 100
+            //     struct input_event ie; // structure used to communicate with the driver
+
+            //     ie.type = EV_FF;
+            //     ie.code = FF_GAIN;
+            //     ie.value = 0xFFFFUL * gain / 100;
+
+            //     if (write(fd, &ie, sizeof(ie)) == -1)
+            //     {
+            //         perror("set gain");
+            //     }
+            // }
+
+
+            // struct input_event play;
+            // struct input_event stop;
+
+            // // upload request to device
+            // ff_effect effect;
+            // const auto uploadStatus = ioctl(fd, EVIOCSFF, &effect);
+
+            // // Play n times
+            // play.type = EV_FF;
+            // play.code = effect.id;
+            // play.value = nTimes;
+
+            // const int playStatus = write(fd, static_cast<const void*>(&play), sizeof(play));
+
+            // // Stop an effect
+            // stop.type = EV_FF;
+            // stop.code = effect.id;
+            // stop.value = 0;
+            // const int stopStatus = write(fd, static_cast<const void*>(&stop), sizeof(stop));
+
+            // // remove effect
+            // ioctl(fd, EVIOCRMFF, effect.id);
+        }
+
+        void
+        close()
         {
             ::close(fd);
             fd = -1;
         }
     };
-}
+} // namespace armarx
diff --git a/source/RobotAPI/gui-plugins/HandUnitPlugin/HandUnitConfigDialog.cpp b/source/RobotAPI/gui-plugins/HandUnitPlugin/HandUnitConfigDialog.cpp
index 2e4c5851c2417c67158785cb31226b03fff7c269..55776817eee69b3f783cda883871b88ec9679439 100644
--- a/source/RobotAPI/gui-plugins/HandUnitPlugin/HandUnitConfigDialog.cpp
+++ b/source/RobotAPI/gui-plugins/HandUnitPlugin/HandUnitConfigDialog.cpp
@@ -36,11 +36,11 @@ armarx::HandUnitConfigDialog::HandUnitConfigDialog(QWidget* parent) :
 
 
     proxyFinderLeftHand = new IceProxyFinder<HandUnitInterfacePrx>(this);
-    proxyFinderLeftHand->setSearchMask("*Unit");
+    proxyFinderLeftHand->setSearchMask("*LeftHandUnit");
     ui->proxyFinderContainerLeftHand->addWidget(proxyFinderLeftHand, 0, 0, 1, 1);
 
     proxyFinderRightHand = new IceProxyFinder<HandUnitInterfacePrx>(this);
-    proxyFinderRightHand->setSearchMask("*Unit");
+    proxyFinderRightHand->setSearchMask("*RightHandUnit");
     ui->proxyFinderContainerRightHand->addWidget(proxyFinderRightHand, 0, 0, 1, 1);
 }
 
diff --git a/source/RobotAPI/interface/units/GamepadUnit.ice b/source/RobotAPI/interface/units/GamepadUnit.ice
index 671e1de9b99591f0d4e23ab923feac8a5e1d535d..c63ddcfdad36942cfcca6c65155c8e96c6847f79 100644
--- a/source/RobotAPI/interface/units/GamepadUnit.ice
+++ b/source/RobotAPI/interface/units/GamepadUnit.ice
@@ -62,8 +62,9 @@ module armarx
         bool rightStickButton;
 
     };
-    interface GamepadUnitInterface extends armarx::SensorActorUnitInterface
+    interface GamepadUnitInterface // extends armarx::SensorActorUnitInterface
     {
+        void vibrate();
     };
 
     interface GamepadUnitListener
@@ -78,4 +79,3 @@ module armarx
     };
 
 };
-