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/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/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..40dad31076f78f8753bfee2599e0649cb7dba6f1 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());
+
+    }
+}