diff --git a/CMakeLists.txt b/CMakeLists.txt
index 99314721ad44b94b9eac660a20139fb65ad16640..043e79fb024a648724e9333574e00b72c9705a7f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -20,7 +20,7 @@ set(ARMARX_ENABLE_AUTO_CODE_FORMATTING TRUE)
 armarx_project("RobotAPI")
 depends_on_armarx_package(ArmarXGui)
 
-set(ArmarX_Simox_VERSION 2.3.71)
+set(ArmarX_Simox_VERSION 2.3.72)
 option(REQUIRE_SIMOX "If enabled the Simox dependency is a required dependency" TRUE)
 
 if(REQUIRE_SIMOX)
diff --git a/data/RobotAPI/robots/Head/KA-Head.xml b/data/RobotAPI/robots/Head/KA-Head.xml
index 4fbdcda252ecae4a50952d0cedd8e1d1bc5c5bd9..6609e8058c5a70a243a941124307f1ab21487856 100644
--- a/data/RobotAPI/robots/Head/KA-Head.xml
+++ b/data/RobotAPI/robots/Head/KA-Head.xml
@@ -473,6 +473,8 @@
         <Node name="Cameras"/>
         <Node name="Eye_Left"/>
         <Node name="Eye_Right"/>
+        <Node name="EyeLeftCamera"/>
+        <Node name="EyeRightCamera"/>
     </RobotNodeSet>
 
 
diff --git a/etc/cmake/ArmarXPackageVersion.cmake b/etc/cmake/ArmarXPackageVersion.cmake
index 855fc4134baf23365fbd04ad5674dabd14b4a1e2..8fd081103ec8a10e0558f8089ed7e076c3082a11 100644
--- a/etc/cmake/ArmarXPackageVersion.cmake
+++ b/etc/cmake/ArmarXPackageVersion.cmake
@@ -1,7 +1,7 @@
 # armarx version file
 set(ARMARX_PACKAGE_LIBRARY_VERSION_MAJOR "0")
-set(ARMARX_PACKAGE_LIBRARY_VERSION_MINOR "9")
-set(ARMARX_PACKAGE_LIBRARY_VERSION_PATCH "2")
+set(ARMARX_PACKAGE_LIBRARY_VERSION_MINOR "10")
+set(ARMARX_PACKAGE_LIBRARY_VERSION_PATCH "0")
 
 set(ARMARX_PACKAGE_LIBRARY_VERSION "${ARMARX_PACKAGE_LIBRARY_VERSION_MAJOR}.${ARMARX_PACKAGE_LIBRARY_VERSION_MINOR}.${ARMARX_PACKAGE_LIBRARY_VERSION_PATCH}")
 
diff --git a/source/RobotAPI/components/DebugDrawer/DebugDrawerHelper.cpp b/source/RobotAPI/components/DebugDrawer/DebugDrawerHelper.cpp
index a4ee8ad724be379aee10d469fa72d8e8b3e5f180..c1bb7243955f6a7ef7559338c00e77809d1c2a98 100644
--- a/source/RobotAPI/components/DebugDrawer/DebugDrawerHelper.cpp
+++ b/source/RobotAPI/components/DebugDrawer/DebugDrawerHelper.cpp
@@ -75,6 +75,11 @@ void DebugDrawerHelper::drawText(const std::string& name, const Eigen::Vector3f&
     debugDrawerPrx->setTextVisu(layerName, name, text, makeGlobal(p1), color, size);
 }
 
+void DebugDrawerHelper::drawArrow(const std::string& name, const Eigen::Vector3f& pos, const Eigen::Vector3f& direction, const DrawColor& color, float length, float width)
+{
+    debugDrawerPrx->setArrowVisu(layerName, name, makeGlobal(pos), makeGlobalDirection(direction), color, length, width);
+}
+
 PosePtr DebugDrawerHelper::makeGlobal(const Eigen::Matrix4f& pose)
 {
     return new Pose(rn->getGlobalPose(pose));
@@ -84,3 +89,8 @@ Vector3Ptr DebugDrawerHelper::makeGlobal(const Eigen::Vector3f& position)
 {
     return new Vector3(rn->getGlobalPosition(position));
 }
+
+Vector3Ptr DebugDrawerHelper::makeGlobalDirection(const Eigen::Vector3f& direction)
+{
+    return new Vector3(math::Helpers::TransformDirection(rn->getGlobalPose(), direction));
+}
diff --git a/source/RobotAPI/components/DebugDrawer/DebugDrawerHelper.h b/source/RobotAPI/components/DebugDrawer/DebugDrawerHelper.h
index 3bdaa4933cfb47767bf7e64575a01c32507ef7d3..5d95dd9c8e604b830bb7be33abab9ba96ff9d910 100644
--- a/source/RobotAPI/components/DebugDrawer/DebugDrawerHelper.h
+++ b/source/RobotAPI/components/DebugDrawer/DebugDrawerHelper.h
@@ -59,8 +59,11 @@ namespace armarx
 
         void drawText(const std::string& name, const Eigen::Vector3f& p1, const std::string& text, const DrawColor& color, int size);
 
+        void drawArrow(const std::string& name, const Eigen::Vector3f& pos, const Eigen::Vector3f& direction, const DrawColor& color, float length, float width);
+
         PosePtr makeGlobal(const Eigen::Matrix4f& pose);
         Vector3Ptr makeGlobal(const Eigen::Vector3f& position);
+        Vector3Ptr makeGlobalDirection(const Eigen::Vector3f& direction);
 
 
         Defaults defaults;
diff --git a/source/RobotAPI/components/units/RobotUnit/Units/TCPControllerSubUnit.cpp b/source/RobotAPI/components/units/RobotUnit/Units/TCPControllerSubUnit.cpp
index d82b7167c7c4aa385f3eff4164ced67688817e2f..ef3cb1009b0c1caf2ceab65a7bb4b5143d992e94 100644
--- a/source/RobotAPI/components/units/RobotUnit/Units/TCPControllerSubUnit.cpp
+++ b/source/RobotAPI/components/units/RobotUnit/Units/TCPControllerSubUnit.cpp
@@ -70,23 +70,7 @@ void TCPControllerSubUnit::setTCPVelocity(const std::string& nodeSetName, const
         ARMARX_CHECK_EXPRESSION_W_HINT(coordinateTransformationRobot->hasRobotNode(tcpName), "The robot does not have the node: " + tcpName);
         tcp = tcpName;
     }
-    auto controllerName = this->getName() + "_" + tcp + "_" + nodeSetName;
-    auto activeNJointControllers = robotUnit->getNJointControllersNotNull(robotUnit->getNJointControllerNames());
-    NJointCartesianVelocityControllerWithRampPtr tcpController;
-    bool nodeSetAlreadyControlled = false;
-    for (NJointControllerPtr controller : activeNJointControllers)
-    {
-        tcpController = NJointCartesianVelocityControllerWithRampPtr::dynamicCast(controller);
-        if (!tcpController)
-        {
-            continue;
-        }
-        if (tcpController->getNodeSetName() == nodeSetName && tcpController->getInstanceName() == controllerName)
-        {
-            nodeSetAlreadyControlled = true;
-            break;
-        }
-    }
+
     robotUnit->updateVirtualRobot(coordinateTransformationRobot);
 
     float xVel = 0.f;
@@ -135,7 +119,33 @@ void TCPControllerSubUnit::setTCPVelocity(const std::string& nodeSetName, const
         noMode = true;
     }
     ARMARX_DEBUG << "CartesianSelection-Mode: " << (int)mode;
+    auto controllerName = this->getName() + "_" + tcp + "_" + nodeSetName + "_mode_" + std::to_string((int)mode);
+    auto NJointControllers = robotUnit->getNJointControllerNames();
+    NJointCartesianVelocityControllerWithRampPtr tcpController;
+    bool nodeSetAlreadyControlled = false;
+    for (auto& name : NJointControllers)
+    {
+        NJointControllerPtr controller;
+        try
+        {
+            controller = robotUnit->getNJointControllerNotNull(name);
+        }
+        catch (...)
+        {
+            continue;
+        }
 
+        tcpController = NJointCartesianVelocityControllerWithRampPtr::dynamicCast(controller);
+        if (!tcpController)
+        {
+            continue;
+        }
+        if (tcpController->getNodeSetName() == nodeSetName && tcpController->getInstanceName() == controllerName)
+        {
+            nodeSetAlreadyControlled = true;
+            break;
+        }
+    }
 
     if (!nodeSetAlreadyControlled)
     {
diff --git a/source/RobotAPI/components/units/RobotUnit/util/ControlThreadOutputBuffer.cpp b/source/RobotAPI/components/units/RobotUnit/util/ControlThreadOutputBuffer.cpp
index 1b8ad6c412459cadbb171980839371f3461aef2a..dea0cefc31e5558e73fa18bf13d16d0fb670af61 100644
--- a/source/RobotAPI/components/units/RobotUnit/util/ControlThreadOutputBuffer.cpp
+++ b/source/RobotAPI/components/units/RobotUnit/util/ControlThreadOutputBuffer.cpp
@@ -25,7 +25,8 @@
 namespace armarx
 {
     detail::RtMessageLogEntryDummy detail::RtMessageLogEntryDummy::Instance;
-    thread_local ControlThreadOutputBuffer* ControlThreadOutputBuffer::RtLoggingInstance{nullptr};
+    detail::RtMessageLogEntryNull detail::RtMessageLogEntryNull::Instance;
+    thread_local ControlThreadOutputBuffer* ControlThreadOutputBuffer::RtLoggingInstance {nullptr};
 
     ControlThreadOutputBuffer::Entry& ControlThreadOutputBuffer::getWriteBuffer()
     {
@@ -192,27 +193,27 @@ namespace armarx
     }
 
     detail::RtMessageLogBuffer::RtMessageLogBuffer(const detail::RtMessageLogBuffer& other, bool minimize):
-        initialBufferSize{other.initialBufferSize * minimize},
-        initialBufferEntryNumbers{other.initialBufferEntryNumbers * minimize},
-        bufferMaxSize{other.bufferMaxSize * minimize},
-        bufferMaxNumberEntries{other.bufferMaxNumberEntries * minimize},
+        initialBufferSize {other.initialBufferSize * minimize},
+        initialBufferEntryNumbers {other.initialBufferEntryNumbers * minimize},
+        bufferMaxSize {other.bufferMaxSize * minimize},
+        bufferMaxNumberEntries {other.bufferMaxNumberEntries * minimize},
         buffer(
             minimize ?
             other.buffer.size() + other.maxAlign - 1 - other.bufferSpace :
             other.buffer.size(),
             0),
-        bufferSpace{buffer.size()},
-        bufferPlace{buffer.data()},
+        bufferSpace {buffer.size()},
+        bufferPlace {buffer.data()},
         entries(
             minimize ?
             other.entriesWritten :
             other.entries.size(),
             nullptr),
-        entriesWritten{0},
-        requiredAdditionalBufferSpace{other.requiredAdditionalBufferSpace},
-        requiredAdditionalEntries{other.requiredAdditionalEntries},
-        messagesLost{other.messagesLost},
-        maxAlign{1}
+        entriesWritten {0},
+        requiredAdditionalBufferSpace {other.requiredAdditionalBufferSpace},
+        requiredAdditionalEntries {other.requiredAdditionalEntries},
+        messagesLost {other.messagesLost},
+        maxAlign {1}
     {
         for (std::size_t idx = 0; idx < other.entries.size() && other.entries.at(idx); ++idx)
         {
@@ -326,9 +327,9 @@ namespace armarx
         std::size_t messageBufferSize, std::size_t messageBufferNumberEntries,
         std::size_t messageBufferMaxSize, std::size_t messageBufferMaxNumberEntries
     ):
-        sensorValuesTimestamp{IceUtil::Time::microSeconds(0)},
-        timeSinceLastIteration{IceUtil::Time::microSeconds(0)},
-        messages{messageBufferSize, messageBufferNumberEntries, messageBufferMaxSize, messageBufferMaxNumberEntries}
+        sensorValuesTimestamp {IceUtil::Time::microSeconds(0)},
+        timeSinceLastIteration {IceUtil::Time::microSeconds(0)},
+        messages {messageBufferSize, messageBufferNumberEntries, messageBufferMaxSize, messageBufferMaxNumberEntries}
     {
         //calculate size in bytes for one buffer
         const std::size_t bytes = [&]
@@ -398,11 +399,11 @@ namespace armarx
     }
 
     detail::ControlThreadOutputBufferEntry::ControlThreadOutputBufferEntry(const detail::ControlThreadOutputBufferEntry& other, bool minimize):
-        writeTimestamp{other.writeTimestamp},
-        sensorValuesTimestamp{other.sensorValuesTimestamp},
-        timeSinceLastIteration{other.timeSinceLastIteration},
-        iteration{other.iteration},
-        messages{other.messages, minimize},
+        writeTimestamp {other.writeTimestamp},
+        sensorValuesTimestamp {other.sensorValuesTimestamp},
+        timeSinceLastIteration {other.timeSinceLastIteration},
+        iteration {other.iteration},
+        messages {other.messages, minimize},
         buffer(other.buffer.size(), 0)
     {
         void* place = buffer.data();
diff --git a/source/RobotAPI/components/units/RobotUnit/util/ControlThreadOutputBuffer.h b/source/RobotAPI/components/units/RobotUnit/util/ControlThreadOutputBuffer.h
index 6d760be0fda039b74870660a410378d724bb83de..c2c4459d03c31fdc67a2a973608eb4796acbb53d 100644
--- a/source/RobotAPI/components/units/RobotUnit/util/ControlThreadOutputBuffer.h
+++ b/source/RobotAPI/components/units/RobotUnit/util/ControlThreadOutputBuffer.h
@@ -26,6 +26,8 @@
 
 #include <vector>
 
+#include <boost/format.hpp>
+
 #include <ArmarXCore/core/exceptions/local/ExpressionException.h>
 #include <ArmarXCore/core/util/PropagateConst.h>
 #include <ArmarXCore/core/util/TripleBuffer.h>
@@ -40,6 +42,23 @@ namespace armarx
 {
     namespace detail
     {
+        inline std::string armarx_sprintf_helper(boost::format& f)
+        {
+            return boost::str(f);
+        }
+
+        template<class T, class... Args>
+        inline std::string armarx_sprintf_helper(boost::format& f, T&& t, Args&& ... args)
+        {
+            return armarx_sprintf_helper(f % std::forward<T>(t), std::forward<Args>(args)...);
+        }
+        template<class... Args>
+        inline std::string armarx_sprintf(const std::string& formatString, Args&& ... args)
+        {
+            boost::format f(formatString);
+            return ::armarx::detail::armarx_sprintf_helper(f, std::forward<Args>(args)...);
+        }
+
         struct RtMessageLogEntryBase
         {
             RtMessageLogEntryBase():
@@ -80,12 +99,36 @@ namespace armarx
 
             ARMARX_MINIMAL_PLACEMENT_CONSTRUCTION_HELPER
         };
+
+        struct RtMessageLogEntryNull : RtMessageLogEntryBase
+        {
+            static RtMessageLogEntryNull Instance;
+        protected:
+            std::string format() const final override
+            {
+                return "";
+            }
+            std::size_t line() const final override
+            {
+                return 0;
+            }
+            std::string file() const final override
+            {
+                return "";
+            }
+            std::string func() const final override
+            {
+                return "";
+            }
+
+            ARMARX_MINIMAL_PLACEMENT_CONSTRUCTION_HELPER
+        };
     }
 }
 namespace armarx
 {
     class RobotUnit;
-    class ControlThreadOutputBuffer;
+    struct ControlThreadOutputBuffer;
 
     namespace RobotUnitModule
     {
@@ -117,7 +160,7 @@ namespace armarx
             void deleteAll();
 
             friend struct ControlThreadOutputBufferEntry;
-            friend class ::armarx::ControlThreadOutputBuffer;
+            friend struct ::armarx::ControlThreadOutputBuffer;
             friend class ::armarx::RobotUnit;
             friend class ::armarx::RobotUnitModule::Logging;
 
@@ -244,10 +287,20 @@ namespace armarx
 }
 
 
-#define ARMARX_RT_LOGF(...) _detail_ARMARX_RT_LOGF(__FILE__, ARMARX_FUNCTION,__LINE__, __VA_ARGS__, true)
+//    ARMARX_INFO << deactivateSpam(1) << "Redirected RT Logging:\n" << ::armarx::detail::armarx_printf_helper(f, __VA_ARGS__);
+
+#define _detail_ARMARX_RT_REDIRECT( ...) ([&]{  \
+        ::armarx::detail::armarx_sprintf(__VA_ARGS__); \
+        ARMARX_INFO << deactivateSpam(1) << "Redirected RT Logging:\n";\
+        return &::armarx::detail::RtMessageLogEntryNull::Instance;}())
+
+
+
+
+#define ARMARX_RT_LOGF(...) (*((::armarx::ControlThreadOutputBuffer::GetRtLoggingInstance())? _detail_ARMARX_RT_LOGF(__FILE__, ARMARX_FUNCTION,__LINE__, __VA_ARGS__, true) : _detail_ARMARX_RT_REDIRECT(__VA_ARGS__)))
 
 #define _detail_ARMARX_RT_LOGF(file_, func_, line_, FormatString, ...)                          \
-    (*[&]{                                                                                      \
+    ([&]{                                                                                      \
             using namespace ::armarx;                                                           \
             using RtMessageLogEntryBase = ControlThreadOutputBuffer::RtMessageLogEntryBase;     \
             struct RtMessageLogEntry : RtMessageLogEntryBase                                    \
diff --git a/source/RobotAPI/libraries/RobotStatechartHelpers/PositionControllerHelper.cpp b/source/RobotAPI/libraries/RobotStatechartHelpers/PositionControllerHelper.cpp
index 629d427a66fb670940910bcd559459e39939bd72..a54cf2fe86393f94a679b1d09d45cb5a7d48f292 100644
--- a/source/RobotAPI/libraries/RobotStatechartHelpers/PositionControllerHelper.cpp
+++ b/source/RobotAPI/libraries/RobotStatechartHelpers/PositionControllerHelper.cpp
@@ -27,6 +27,8 @@
 
 #include <RobotAPI/libraries/core/CartesianVelocityController.h>
 
+#include <VirtualRobot/math/Helpers.h>
+
 using namespace armarx;
 
 PositionControllerHelper::PositionControllerHelper(const VirtualRobot::RobotNodePtr& tcp, const VelocityControllerHelperPtr& velocityControllerHelper, const Eigen::Matrix4f& target)
@@ -57,7 +59,7 @@ void PositionControllerHelper::update()
     }
     Eigen::VectorXf cv = posController.calculate(getCurrentTarget(), VirtualRobot::IKSolver::All);
     velocityControllerHelper->setTargetVelocity(cv + feedForwardVelocity);
-    if(autoClearFeedForward)
+    if (autoClearFeedForward)
     {
         clearFeedForwardVelocity();
     }
@@ -147,6 +149,11 @@ const Eigen::Matrix4f& PositionControllerHelper::getCurrentTarget() const
     return waypoints.at(currentWaypointIndex);
 }
 
+const Eigen::Vector3f PositionControllerHelper::getCurrentTargetPosition() const
+{
+    return math::Helpers::GetPosition(waypoints.at(currentWaypointIndex));
+}
+
 size_t PositionControllerHelper::skipToClosestWaypoint(float rad2mmFactor)
 {
     float dist = FLT_MAX;
diff --git a/source/RobotAPI/libraries/RobotStatechartHelpers/PositionControllerHelper.h b/source/RobotAPI/libraries/RobotStatechartHelpers/PositionControllerHelper.h
index 92d20fa3133d90535234780b23c7a4c8899b1161..b90b2a615f0dafabae4a7a42fb4024a8f1e84d0d 100644
--- a/source/RobotAPI/libraries/RobotStatechartHelpers/PositionControllerHelper.h
+++ b/source/RobotAPI/libraries/RobotStatechartHelpers/PositionControllerHelper.h
@@ -75,6 +75,7 @@ namespace armarx
         bool isLastWaypoint() const;
 
         const Eigen::Matrix4f& getCurrentTarget() const;
+        const Eigen::Vector3f getCurrentTargetPosition() const;
 
         size_t skipToClosestWaypoint(float rad2mmFactor);
 
@@ -84,7 +85,7 @@ namespace armarx
 
         struct NullspaceOptimizationArgs
         {
-            NullspaceOptimizationArgs(){}
+            NullspaceOptimizationArgs() {}
             int loops = 100;
             float stepLength = 0.05f;
             float eps = 0.001;
diff --git a/source/RobotAPI/libraries/RobotStatechartHelpers/VelocityControllerHelper.cpp b/source/RobotAPI/libraries/RobotStatechartHelpers/VelocityControllerHelper.cpp
index c062e9509533da3b3705b2821b6c75bb4272c5e2..c1a2369f9c01964bf8282af46edbb34c97ba26d6 100644
--- a/source/RobotAPI/libraries/RobotStatechartHelpers/VelocityControllerHelper.cpp
+++ b/source/RobotAPI/libraries/RobotStatechartHelpers/VelocityControllerHelper.cpp
@@ -79,5 +79,14 @@ void VelocityControllerHelper::setNullSpaceControl(bool enabled)
 
 void VelocityControllerHelper::cleanup()
 {
-    controller->deactivateAndDeleteController();
+    if (controllerCreated)
+    {
+        // delete controller only if it was created
+        controller->deactivateAndDeleteController();
+    }
+    else
+    {
+        // if the controller existed, only deactivate it
+        controller->deactivateController();
+    }
 }
diff --git a/source/RobotAPI/libraries/core/CartesianVelocityController.cpp b/source/RobotAPI/libraries/core/CartesianVelocityController.cpp
index de66c0591d66119057275be998bbfa6faccc854b..496ad995fe58b5672c2b9189475b8bd64535e9eb 100644
--- a/source/RobotAPI/libraries/core/CartesianVelocityController.cpp
+++ b/source/RobotAPI/libraries/core/CartesianVelocityController.cpp
@@ -32,8 +32,9 @@
 
 using namespace armarx;
 
-CartesianVelocityController::CartesianVelocityController(const VirtualRobot::RobotNodeSetPtr& rns, const VirtualRobot::RobotNodePtr& tcp, const VirtualRobot::JacobiProvider::InverseJacobiMethod invJacMethod)
-    : rns(rns)
+CartesianVelocityController::CartesianVelocityController(const VirtualRobot::RobotNodeSetPtr& rns, const VirtualRobot::RobotNodePtr& tcp, const VirtualRobot::JacobiProvider::InverseJacobiMethod invJacMethod, bool considerJointLimits)
+    : rns(rns),
+      considerJointLimits(considerJointLimits)
 {
     //ARMARX_IMPORTANT << VAROUT(rns->getRobot()->getRootNode());
     ik.reset(new VirtualRobot::DifferentialIK(rns, rns->getRobot()->getRootNode(), invJacMethod));
@@ -55,9 +56,6 @@ Eigen::VectorXf CartesianVelocityController::calculate(const Eigen::VectorXf& ca
     //ARMARX_IMPORTANT << VAROUT(tcp.get());
     //ARMARX_IMPORTANT << VAROUT(ik.get());
     jacobi = ik->getJacobianMatrix(tcp, mode);
-    //ARMARX_IMPORTANT << "hi";
-    //ARMARX_IMPORTANT << jacobi;
-    inv = ik->computePseudoInverseJacobianMatrix(jacobi, ik->getJacobiRegularization(mode));
 
     //    ARMARX_IMPORTANT << "nullspaceVel " << nullspaceVel.transpose();
     Eigen::FullPivLU<Eigen::MatrixXf> lu_decomp(jacobi);
@@ -79,12 +77,22 @@ Eigen::VectorXf CartesianVelocityController::calculate(const Eigen::VectorXf& ca
     //nsv /= kernel.cols();
 
 
-    Eigen::VectorXf jointVel = inv * cartesianVel;
 
+
+    inv = ik->computePseudoInverseJacobianMatrix(jacobi, ik->getJacobiRegularization(mode));
+
+
+    if (considerJointLimits)
+    {
+        adjustJacobiForJointsAtJointLimits(mode, cartesianVel);
+    }
+
+
+    Eigen::VectorXf jointVel = inv * cartesianVel;
     jointVel += nsv;
 
 
-    if(maximumJointVelocities.rows() > 0)
+    if (maximumJointVelocities.rows() > 0)
     {
         jointVel = ::math::Helpers::LimitVectorLength(jointVel, maximumJointVelocities);
     }
@@ -155,3 +163,52 @@ Eigen::VectorXf CartesianVelocityController::calculateRegularization(VirtualRobo
     }
     return regularization.topRows(i);
 }
+
+bool CartesianVelocityController::adjustJacobiForJointsAtJointLimits(VirtualRobot::IKSolver::CartesianSelection mode, const Eigen::VectorXf& cartesianVel, float jointLimitCheckAccuracy)
+{
+
+    bool modifiedJacobi = false;
+
+    Eigen::VectorXf jointVel = inv * cartesianVel;
+    size_t size = rns->getSize();
+
+    for (size_t i = 0; i < size; ++i)
+    {
+        auto& node = rns->getNode(static_cast<int>(i));
+
+        if (node->isLimitless() || // limitless joint cannot be out of limits
+            std::abs(jointVel(i)) < 0.001f // If it the jacobi doesnt want this joint to move anyway, there is no point in recalculating the inverse jacobi
+           )
+        {
+            continue;
+        }
+
+        if ((node->getJointValue() >= node->getJointLimitHigh() - jointLimitCheckAccuracy && jointVel(i) > 0)
+            || (node->getJointValue() <= node->getJointLimitLow() + jointLimitCheckAccuracy && jointVel(i) < 0))
+        {
+            for (int k = 0; k < jacobi.rows(); ++k) // memory allocation free resetting of column
+            {
+                jacobi(k, i) = 0.0f;
+            }
+            modifiedJacobi = true;
+        }
+    }
+
+    if (modifiedJacobi)
+    {
+        // calculate inverse jacobi again since atleast one joint would be driven into the limit
+        inv = ik->computePseudoInverseJacobianMatrix(jacobi, ik->getJacobiRegularization(mode));
+    }
+
+    return modifiedJacobi;
+}
+
+bool CartesianVelocityController::getConsiderJointLimits() const
+{
+    return considerJointLimits;
+}
+
+void CartesianVelocityController::setConsiderJointLimits(bool value)
+{
+    considerJointLimits = value;
+}
diff --git a/source/RobotAPI/libraries/core/CartesianVelocityController.h b/source/RobotAPI/libraries/core/CartesianVelocityController.h
index 01398dd59581ffd1a36749e95f8a3287fbde476f..3826e0471d9eada001b8cb13b07cdde7bde8b25c 100644
--- a/source/RobotAPI/libraries/core/CartesianVelocityController.h
+++ b/source/RobotAPI/libraries/core/CartesianVelocityController.h
@@ -40,7 +40,8 @@ namespace armarx
     {
     public:
         CartesianVelocityController(const VirtualRobot::RobotNodeSetPtr& rns, const VirtualRobot::RobotNodePtr& tcp = nullptr,
-                                    const VirtualRobot::JacobiProvider::InverseJacobiMethod invJacMethod = VirtualRobot::JacobiProvider::eSVDDamped);
+                                    const VirtualRobot::JacobiProvider::InverseJacobiMethod invJacMethod = VirtualRobot::JacobiProvider::eSVDDamped,
+                                    bool considerJointLimits = true);
 
         Eigen::VectorXf calculate(const Eigen::VectorXf& cartesianVel, float KpJointLimitAvoidanceScale, VirtualRobot::IKSolver::CartesianSelection mode);
         Eigen::VectorXf calculate(const Eigen::VectorXf& cartesianVel, const Eigen::VectorXf& nullspaceVel, VirtualRobot::IKSolver::CartesianSelection mode);
@@ -49,6 +50,9 @@ namespace armarx
 
         void setCartesianRegularization(float cartesianMMRegularization, float cartesianRadianRegularization);
 
+        bool getConsiderJointLimits() const;
+        void setConsiderJointLimits(bool value);
+
         Eigen::MatrixXf jacobi;
         Eigen::MatrixXf inv;
         VirtualRobot::RobotNodeSetPtr rns;
@@ -58,7 +62,8 @@ namespace armarx
 
     private:
         Eigen::VectorXf calculateRegularization(VirtualRobot::IKSolver::CartesianSelection mode);
-
+        bool adjustJacobiForJointsAtJointLimits(VirtualRobot::IKSolver::CartesianSelection mode, const Eigen::VectorXf& cartesianVel, float jointLimitCheckAccuracy = 0.001f);
+        bool considerJointLimits = true;
         float cartesianMMRegularization;
         float cartesianRadianRegularization;
     };
diff --git a/source/RobotAPI/libraries/core/Trajectory.cpp b/source/RobotAPI/libraries/core/Trajectory.cpp
index 1d85531ea8537c614aea2c6a4d98ff8f7bb0c964..404379ab6d8c533a55a12dcea1c46ea80fe50dfd 100644
--- a/source/RobotAPI/libraries/core/Trajectory.cpp
+++ b/source/RobotAPI/libraries/core/Trajectory.cpp
@@ -131,6 +131,13 @@ namespace armarx
         return new Trajectory(*this);
     }
 
+    TrajectoryPtr Trajectory::cloneMetaData() const
+    {
+        TrajectoryPtr t = new Trajectory();
+        CopyMetaData(*this, *t);
+        return t;
+    }
+
     std::string Trajectory::output(const Ice::Current&) const
     {
 
@@ -1647,11 +1654,14 @@ namespace armarx
     }
 
 
-    void Trajectory::clear()
+    void Trajectory::clear(bool keepMetaData)
     {
         dataMap.erase(dataMap.begin(), dataMap.end());
-        dimensionNames.clear();
-        limitless.clear();
+        if (!keepMetaData)
+        {
+            dimensionNames.clear();
+            limitless.clear();
+        }
     }
 
 
diff --git a/source/RobotAPI/libraries/core/Trajectory.h b/source/RobotAPI/libraries/core/Trajectory.h
index 5f7613bdca048ee60f3efdcc43b53e7d9f79ca62..15de38e073b2924f2178df40c98d9160dfc03f9b 100644
--- a/source/RobotAPI/libraries/core/Trajectory.h
+++ b/source/RobotAPI/libraries/core/Trajectory.h
@@ -398,7 +398,7 @@ namespace armarx
         static void CopyData(const Trajectory& source, Trajectory& destination);
         static void CopyMetaData(const Trajectory& source, Trajectory& destination);
 
-        void clear();
+        void clear(bool keepMetaData = false);
         void setPositionEntry(const double t, const size_t dimIndex, const double& y);
         void setEntries(const double t, const size_t dimIndex, const Ice::DoubleSeq& y);
         bool dataExists(double t, size_t dimension = 0, size_t derivation = 0) const;
@@ -417,6 +417,7 @@ namespace armarx
 
         // VariantDataClass interface
         VariantDataClassPtr clone(const Ice::Current& c = Ice::Current()) const override;
+        TrajectoryPtr cloneMetaData() const;
         std::string output(const Ice::Current& c = Ice::Current()) const override;
         Ice::Int getType(const Ice::Current& c = Ice::Current()) const override;
         bool validate(const Ice::Current& c = Ice::Current()) override;
diff --git a/source/RobotAPI/libraries/core/TrajectoryController.cpp b/source/RobotAPI/libraries/core/TrajectoryController.cpp
index ef74dd1fc47b1f67dbc44bb97f87f5dc5346a39c..5328d534a2b6ce76915a343e2cdad3014a4ee1b4 100644
--- a/source/RobotAPI/libraries/core/TrajectoryController.cpp
+++ b/source/RobotAPI/libraries/core/TrajectoryController.cpp
@@ -48,6 +48,7 @@ namespace armarx
         //}
         positions.resize(traj->dim(), 1);
         veloctities.resize(traj->dim(), 1);
+        currentError.resize(traj->dim(), 1);
     }
 
     const Eigen::VectorXf& TrajectoryController::update(double deltaT, const Eigen::VectorXf& currentPosition)
@@ -82,7 +83,18 @@ namespace armarx
                 veloctities(i) = 0;
             }
         }
-        currentError = positions - currentPosition;
+        for (size_t i = 0; i < dim; ++i)
+        {
+            if (pid->limitless.size() > i && pid->limitless.at(i))
+            {
+                currentError(i) = math::MathUtils::AngleDelta(currentPosition(i), positions(i));
+            }
+            else
+            {
+                currentError(i) = positions(i) - currentPosition(i);
+            }
+
+        }
 
         pid->update(std::abs(deltaT), currentPosition, positions);
         veloctities += pid->getControlValue();
diff --git a/source/RobotAPI/libraries/core/test/CartesianVelocityControllerTest.cpp b/source/RobotAPI/libraries/core/test/CartesianVelocityControllerTest.cpp
index f50dedc362145b2ef1aeb812f98233ba0f6da8d4..216c48d906af3f8ea6e14f3a2a89424a1ce13c22 100644
--- a/source/RobotAPI/libraries/core/test/CartesianVelocityControllerTest.cpp
+++ b/source/RobotAPI/libraries/core/test/CartesianVelocityControllerTest.cpp
@@ -76,3 +76,82 @@ BOOST_AUTO_TEST_CASE(test1)
     BOOST_CHECK_LE((targetTcpVel - tcpVel).norm(), 0.01f);
 
 }
+
+BOOST_AUTO_TEST_CASE(testJointLimitAwareness)
+{
+    const std::string project = "RobotAPI";
+    armarx::CMakePackageFinder finder(project);
+
+    if (!finder.packageFound())
+    {
+        ARMARX_ERROR_S << "ArmarX Package " << project << " has not been found!";
+    }
+    else
+    {
+        armarx::ArmarXDataPath::addDataPaths(finder.getDataDir());
+    }
+    std::string fn = "RobotAPI/robots/Armar3/ArmarIII.xml";
+    ArmarXDataPath::getAbsolutePath(fn, fn);
+    std::string robotFilename = fn;
+    VirtualRobot::RobotPtr robot = VirtualRobot::RobotIO::loadRobot(robotFilename, VirtualRobot::RobotIO::eStructure);
+    VirtualRobot::RobotNodeSetPtr rns = robot->getRobotNodeSet("TorsoRightArm");
+    CartesianVelocityControllerPtr h(new CartesianVelocityController(rns, nullptr, VirtualRobot::JacobiProvider::eSVDDamped));
+    const Eigen::VectorXf oldJV = rns->getJointValuesEigen();
+    ARMARX_INFO << VAROUT(oldJV);
+    Eigen::VectorXf cartesianVel(6);
+    srand(123);
+
+    for (int i = 0; i < 10000; ++i)
+    {
+
+
+        cartesianVel << rand() % 100, rand() % 100, rand() % 100, 0.01 * (rand() % 100), 0.01 * (rand() % 100), 0.01 * (rand() % 100);
+        //        cartesianVel << 100,0,0;//, 0.01*(rand()%100), 0.01*(rand()%100), 0.01*(rand()%100);
+        auto mode = VirtualRobot::IKSolver::CartesianSelection::All;
+        Eigen::MatrixXf jacobi = h->ik->getJacobianMatrix(rns->getTCP(), mode);
+        Eigen::MatrixXf inv = h->ik->computePseudoInverseJacobianMatrix(jacobi, h->ik->getJacobiRegularization(mode));
+        int jointIndex = rand() % rns->getSize();
+        jacobi.block(0, jointIndex, jacobi.rows(), 1) = Eigen::VectorXf::Zero(jacobi.rows());
+        Eigen::MatrixXf inv2 = h->ik->computePseudoInverseJacobianMatrix(jacobi, h->ik->getJacobiRegularization(mode));
+
+        //    ARMARX_INFO << "diff\n" << (inv-inv2);
+        rns->setJointValues(oldJV);
+        Eigen::Vector3f posBefore = h->tcp->getPositionInRootFrame();
+
+        float accuracy = 0.001f;
+
+        Eigen::VectorXf jointVel = inv * cartesianVel;
+        rns->setJointValues(oldJV + jointVel * accuracy);
+        Eigen::VectorXf resultCartesianVel = ((h->tcp->getPositionInRootFrame() - posBefore) / accuracy);
+
+
+
+        Eigen::VectorXf jointVel2 = inv2 * cartesianVel;
+        rns->setJointValues(oldJV + jointVel2 * accuracy);
+        Eigen::VectorXf resultCartesianVel2 = ((h->tcp->getPositionInRootFrame() - posBefore) / accuracy);
+
+        Eigen::Vector3f diff = (resultCartesianVel - cartesianVel);
+        Eigen::Vector3f diff2 = (resultCartesianVel2 - cartesianVel);
+
+        if (!((diff - diff2).norm() < 0.5 || diff2.norm() < diff.norm()))
+        {
+            ARMARX_INFO << "Target cartesian velo:\n" << cartesianVel;
+            ARMARX_INFO << "jacobi\n" << jacobi;
+            ARMARX_INFO << "inv\n" << inv;
+            ARMARX_INFO << "inv2\n" << inv2;
+            ARMARX_INFO << "\n\nResulting joint cart velocity: " << resultCartesianVel << "\n jointVel:\n" << jointVel;
+            ARMARX_INFO << "\n\nResulting joint cart velocity with joint limit avoidance: " << resultCartesianVel2 << "\n jointVel:\n" << jointVel2;
+
+            ARMARX_INFO << "Diff:\n" << diff;
+            ARMARX_INFO << "Diff2:\n" << diff2;
+        }
+        else
+        {
+            ARMARX_INFO << "Success for \n" << cartesianVel;
+        }
+
+
+        BOOST_REQUIRE((diff - diff2).norm() < 1 || diff2.norm() < diff.norm());
+
+    }
+}