diff --git a/source/RobotAPI/components/units/RobotUnit/ControlTargets/ControlTarget1DoFActuator.h b/source/RobotAPI/components/units/RobotUnit/ControlTargets/ControlTarget1DoFActuator.h
index 857df32bb7bd1387c8892a5aaf12297085723e47..640bd4f88fa337ce1629634e3449554e315b1a61 100644
--- a/source/RobotAPI/components/units/RobotUnit/ControlTargets/ControlTarget1DoFActuator.h
+++ b/source/RobotAPI/components/units/RobotUnit/ControlTargets/ControlTarget1DoFActuator.h
@@ -65,29 +65,29 @@ namespace armarx
     make_ControlTarget1DoFActuator(ControlTarget1DoFActuatorTorque, torque, ControlModes::Torque1DoF);
     make_ControlTarget1DoFActuator(ControlTarget1DoFActuatorCurrent, current, ControlModes::Current1DoF);
 
-    class VelocityTorqueControlTarget: public ControlTarget1DoFActuatorVelocity
+    class ControlTarget1DoFActuatorTorqueVelocity: public ControlTarget1DoFActuatorVelocity
     {
     public:
         float maxTorque;
 
         const std::string& getControlMode() const override
         {
-            return ControlModes::Velocity1DoF;
+            return ControlModes::VelocityTorque;
         }
         void reset() override
         {
             ControlTarget1DoFActuatorVelocity::reset();
-            maxTorque = 10.f;
+            maxTorque = -1.0f; // if < 0, default value for joint is to be used
         }
         bool isValid() const override
         {
-            return ControlTarget1DoFActuatorVelocity::isValid() && maxTorque >= 0;
+            return ControlTarget1DoFActuatorVelocity::isValid() && std::isfinite(maxTorque);
         }
-        static ControlTargetInfo<VelocityTorqueControlTarget> GetClassMemberInfo()
+        static ControlTargetInfo<ControlTarget1DoFActuatorTorqueVelocity> GetClassMemberInfo()
         {
-            ControlTargetInfo<VelocityTorqueControlTarget> cti;
+            ControlTargetInfo<ControlTarget1DoFActuatorTorqueVelocity> cti;
             cti.addBaseClass<ControlTarget1DoFActuatorVelocity>();
-            cti.addMemberVariable(&VelocityTorqueControlTarget::maxTorque, "maxTorque");
+            cti.addMemberVariable(&ControlTarget1DoFActuatorTorqueVelocity::maxTorque, "maxTorque");
             return cti;
         }
         DETAIL_ControlTargetBase_DEFAULT_METHOD_IMPLEMENTATION
diff --git a/source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointKinematicUnitPassThroughController.cpp b/source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointKinematicUnitPassThroughController.cpp
index 61e768884245fc6a1601b3a867d160d2504037db..9245b2086e8e688fafc4ba6cae5b83b8f1fec231 100644
--- a/source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointKinematicUnitPassThroughController.cpp
+++ b/source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointKinematicUnitPassThroughController.cpp
@@ -43,7 +43,7 @@ NJointKinematicUnitPassThroughController::NJointKinematicUnitPassThroughControll
 
     ControlTargetBase* ct = useControlTarget(cfg->deviceName, controlMode);
     //get sensor
-    if (controlMode == ControlModes::Position1DoF)
+    if (ct->isA<ControlTarget1DoFActuatorPosition>())
     {
         ARMARX_CHECK_EXPRESSION(sv->asA<SensorValue1DoFActuatorPosition>());
         sensor = &(sv->asA<SensorValue1DoFActuatorPosition>()->position);
@@ -51,26 +51,16 @@ NJointKinematicUnitPassThroughController::NJointKinematicUnitPassThroughControll
         target = &(ct->asA<ControlTarget1DoFActuatorPosition>()->position);
         sensorToControlOnActivateFactor = 1;
     }
-    else if (controlMode == ControlModes::Velocity1DoF)
+    else if (ct->isA<ControlTarget1DoFActuatorVelocity>())
     {
         ARMARX_CHECK_EXPRESSION(sv->asA<SensorValue1DoFActuatorVelocity>());
         sensor = &(sv->asA<SensorValue1DoFActuatorVelocity>()->velocity);
         ARMARX_CHECK_EXPRESSION(ct->asA<ControlTarget1DoFActuatorVelocity>());
         target = &(ct->asA<ControlTarget1DoFActuatorVelocity>()->velocity);
         sensorToControlOnActivateFactor = 1;
-        resetZeroThreshold = 0.1;
+        resetZeroThreshold = 0.1f; // TODO: way to big value?!
     }
-    else if (controlMode == ControlModes::VelocityTorque)
-    {
-        ARMARX_CHECK_EXPRESSION(sv->asA<SensorValue1DoFActuatorVelocity>());
-        sensor = &(sv->asA<SensorValue1DoFActuatorVelocity>()->velocity);
-        ARMARX_CHECK_EXPRESSION(ct->asA<VelocityTorqueControlTarget>());
-        target = &(ct->asA<VelocityTorqueControlTarget>()->velocity);
-        target2 = &(ct->asA<VelocityTorqueControlTarget>()->maxTorque);
-        sensorToControlOnActivateFactor = 1;
-        resetZeroThreshold = 0.1;
-    }
-    else if (controlMode == ControlModes::Torque1DoF)
+    else if (ct->isA<ControlTarget1DoFActuatorTorque>())
     {
         ARMARX_CHECK_EXPRESSION(sv->asA<SensorValue1DoFActuatorTorque>());
         sensor = &(sv->asA<SensorValue1DoFActuatorTorque>()->torque);
diff --git a/source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointKinematicUnitPassThroughController.h b/source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointKinematicUnitPassThroughController.h
index 3119a0fc23a89029515d6829087798f358ed49b5..371a6e462f686653104f35d137125d3704bade63 100644
--- a/source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointKinematicUnitPassThroughController.h
+++ b/source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointKinematicUnitPassThroughController.h
@@ -60,10 +60,6 @@ namespace armarx
         inline void rtRun(const IceUtil::Time&, const IceUtil::Time&) override
         {
             *target = control;
-            if (target2)
-            {
-                *target2 = 8;
-            }
         }
         inline void rtPreActivateController() override
         {
@@ -93,7 +89,6 @@ namespace armarx
     protected:
         std::atomic<float> control {0};
         float* target {nullptr};
-        float* target2 {nullptr};
         const float* sensor
         {
             nullptr
diff --git a/source/RobotAPI/interface/units/RobotUnit/NJointTaskSpaceDMPController.ice b/source/RobotAPI/interface/units/RobotUnit/NJointTaskSpaceDMPController.ice
index 2eb2753c7697a43743707e03c1f0adc9b81c238b..5d1edef07e3d71d8b86fb8b222d49dce12662ae9 100644
--- a/source/RobotAPI/interface/units/RobotUnit/NJointTaskSpaceDMPController.ice
+++ b/source/RobotAPI/interface/units/RobotUnit/NJointTaskSpaceDMPController.ice
@@ -45,7 +45,9 @@ module armarx
         float DMPKd = 20;
         int kernelSize = 100;
         double tau = 1;
-        int baseMode = 1;
+        string dmpMode = "MinimumJerk";
+        string dmpStyle = "Discrete";
+        double dmpAmplitude = 1;
 
         double phaseL = 10;
         double phaseK = 10;
@@ -53,9 +55,7 @@ module armarx
         double phaseDist1 = 10;
         double phaseKpPos = 1;
         double phaseKpOri = 0.1;
-
         double timeDuration = 10;
-
         double posToOriRatio = 100;
 
         // velocity controller configuration
@@ -63,6 +63,9 @@ module armarx
         string tcpName = "";
         NJointTaskSpaceDMPControllerMode::CartesianSelection mode = NJointTaskSpaceDMPControllerMode::eAll;
 
+        double maxLinearVel;
+        double maxAngularVel;
+
     };
 
 
@@ -72,10 +75,12 @@ module armarx
         bool isFinished();
         void runDMP(Ice::DoubleSeq goals, double tau);
 
-        void setTemporalFactor(double tau);
+        void setSpeed(double times);
         void setViaPoints(double canVal, Ice::DoubleSeq point);
         void setGoals(Ice::DoubleSeq goals);
 
+        double getCanVal();
+
         void setControllerTarget(float avoidJointLimitsKp, NJointTaskSpaceDMPControllerMode::CartesianSelection mode);
         void setTorqueKp(StringFloatDictionary torqueKp);
         void setNullspaceJointVelocities(StringFloatDictionary nullspaceJointVelocities);
@@ -88,7 +93,7 @@ module armarx
         float DMPKd = 20;
         int kernelSize = 100;
         double tau = 1;
-        int baseMode = 1;
+        int dmpMode = 1;
         int dmpNum = 2;
 
         // phaseStop technique
@@ -128,4 +133,69 @@ module armarx
         void setTorqueKp(StringFloatDictionary torqueKp);
         void setNullspaceJointVelocities(StringFloatDictionary nullspaceJointVelocities);
     };
+
+    class NJointBimanualCCDMPControllerConfig extends NJointControllerConfig
+    {
+
+        // dmp configuration
+        int kernelSize = 100;
+        string dmpMode = "MinimumJerk";
+        string dmpType = "Discrete";
+
+        // phaseStop technique
+        double phaseL = 10;
+        double phaseK = 10;
+        double phaseDist0 = 50;
+        double phaseDist1 = 10;
+        double phaseKpPos = 1;
+        double phaseKpOri = 0.1;
+        double posToOriRatio = 10;
+        double timeDuration = 10;
+
+        string defautLeader = "Left";
+
+        Ice::FloatSeq leftDesiredJointValues;
+        Ice::FloatSeq rightDesiredJointValues;
+
+        float KoriFollower = 1;
+        float KposFollower = 1;
+
+        double maxLinearVel;
+        double maxAngularVel;
+
+        Ice::FloatSeq Kpos;
+        Ice::FloatSeq Dpos;
+        Ice::FloatSeq Kori;
+        Ice::FloatSeq Dori;
+
+        float knull;
+        float dnull;
+
+        float torqueLimit;
+
+        Ice::FloatSeq Kpf;
+        Ice::FloatSeq Kif;
+        Ice::FloatSeq DesiredForce;
+
+        float BoxWidth;
+
+    };
+
+    interface NJointBimanualCCDMPControllerInterface extends NJointControllerInterface
+    {
+        void learnDMPFromFiles(string whichDMP, Ice::StringSeq trajfiles);
+        bool isFinished();
+        void runDMP(Ice::DoubleSeq leftGoals, Ice::DoubleSeq rightGoals);
+
+        void setViaPoints(double canVal, Ice::DoubleSeq point);
+        void setGoals(Ice::DoubleSeq goals);
+
+        void changeLeader();
+        double getVirtualTime();
+
+        string getLeaderName();
+
+
+    };
 };
+
diff --git a/source/RobotAPI/interface/visualization/DebugDrawerInterface.ice b/source/RobotAPI/interface/visualization/DebugDrawerInterface.ice
index 629d152d94faa27ceb0b3d4f4fb6796f4bd5ed8c..1a342947e2210b180d2416b14e3bc78deedd72e8 100644
--- a/source/RobotAPI/interface/visualization/DebugDrawerInterface.ice
+++ b/source/RobotAPI/interface/visualization/DebugDrawerInterface.ice
@@ -52,11 +52,15 @@ module armarx
          byte b;
     };
 
+
     struct HsvColor
     {
-        byte h;
-        byte s;
-        byte v;
+        //! 0-360
+        float h;
+        //! 0 - 1
+        float s;
+        //! 0 - 1
+        float v;
     };
 
 
diff --git a/source/RobotAPI/libraries/CMakeLists.txt b/source/RobotAPI/libraries/CMakeLists.txt
index 63093136d096c560bce41e766cc10f9aaa44ade2..b0a1a80cab68dc9f10e178cc00da1e1b65b49c94 100644
--- a/source/RobotAPI/libraries/CMakeLists.txt
+++ b/source/RobotAPI/libraries/CMakeLists.txt
@@ -4,3 +4,5 @@ add_subdirectory(SimpleJsonLogger)
 add_subdirectory(RobotAPIVariantWidget)
 
 add_subdirectory(RobotAPINJointControllers)
+
+add_subdirectory(DMPController)
diff --git a/source/RobotAPI/libraries/DMPController/CMakeLists.txt b/source/RobotAPI/libraries/DMPController/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..3a36d3bdcf71fb9f3726a38857d54f05bb108cec
--- /dev/null
+++ b/source/RobotAPI/libraries/DMPController/CMakeLists.txt
@@ -0,0 +1,50 @@
+set(LIB_NAME       DMPController)
+
+armarx_component_set_name("${LIB_NAME}")
+armarx_set_target("Library: ${LIB_NAME}")
+
+
+
+find_package(Eigen3 QUIET)
+find_package(Simox ${ArmarX_Simox_VERSION} QUIET)
+find_package(DMP QUIET)
+
+
+armarx_build_if(Eigen3_FOUND "Eigen3 not available")
+armarx_build_if(Simox_FOUND "Simox-VirtualRobot not available")
+armarx_build_if(DMP_FOUND "DMP not available")
+
+if (Eigen3_FOUND AND Simox_FOUND AND DMP_FOUND)
+    include_directories(${Simox_INCLUDE_DIRS})
+    include_directories(SYSTEM ${Eigen3_INCLUDE_DIR})
+    include_directories(${DMP_INCLUDE_DIRS})
+endif()
+
+set(LIBS
+    ArmarXCoreInterfaces
+    ArmarXCore
+    RobotAPIInterfaces
+    ArmarXCoreObservers
+    ArmarXCoreStatechart
+    ArmarXCoreEigen3Variants
+    VirtualRobot
+    Saba
+    SimDynamics
+    RobotUnit
+    ${DMP_LIBRARIES}
+    )
+
+set(LIB_FILES
+./TaskSpaceDMPController.cpp
+#@TEMPLATE_LINE@@COMPONENT_PATH@/@COMPONENT_NAME@.cpp
+)
+set(LIB_HEADERS
+./TaskSpaceDMPController.h
+#@TEMPLATE_LINE@@COMPONENT_PATH@/@COMPONENT_NAME@.h
+)
+
+
+armarx_add_library("${LIB_NAME}" "${LIB_FILES}" "${LIB_HEADERS}" "${LIBS}")
+
+# add unit tests
+add_subdirectory(test)
diff --git a/source/RobotAPI/libraries/DMPController/TaskSpaceDMPController.cpp b/source/RobotAPI/libraries/DMPController/TaskSpaceDMPController.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b712d6491dfee79e774e22748a6c16733af466b3
--- /dev/null
+++ b/source/RobotAPI/libraries/DMPController/TaskSpaceDMPController.cpp
@@ -0,0 +1,327 @@
+/*
+ * This file is part of ArmarX.
+ *
+ * ArmarX is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * ArmarX is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @package    RobotAPI::ArmarXObjects::DMPController
+ * @author     zhou ( you dot zhou at kit dot edu )
+ * @date       2018
+ * @copyright  http://www.gnu.org/licenses/gpl-2.0.txt
+ *             GNU General Public License
+ */
+
+#include "TaskSpaceDMPController.h"
+
+
+using namespace armarx;
+
+
+
+void TaskSpaceDMPController::flow(double deltaT, const Eigen::Matrix4f& currentPose, const Eigen::VectorXf& twist)
+{
+    if (canVal < 1e-8)
+    {
+        if (config.DMPStyle == "Periodic")
+        {
+            prepareExecution(eigen4f2vec(currentPose), goalPoseVec);
+        }
+        else
+        {
+            targetVel.setZero();
+            return;
+        }
+    }
+
+    Eigen::Vector3f currentPosition;
+    Eigen::Quaterniond currentOrientation;
+    double posiError = 0;
+    double oriError = 0;
+
+    getError(currentPose, currentPosition, currentOrientation, posiError, oriError);
+
+    double poseError = posiError + config.phaseStopParas.mm2radi * oriError;
+
+    double phaseDist;
+    if (isDisturbance)
+    {
+        phaseDist = config.phaseStopParas.backDist;
+    }
+    else
+    {
+        phaseDist = config.phaseStopParas.goDist;
+    }
+    double phaseL = config.phaseStopParas.maxValue;
+    double phaseK = config.phaseStopParas.slop;
+
+    double phaseStop = phaseL / (1 + exp(-phaseK * (poseError - phaseDist)));
+    double mpcFactor = 1 - (phaseStop / phaseL);
+
+    if (mpcFactor < 0.1)
+    {
+        isDisturbance = true;
+    }
+
+    if (mpcFactor > 0.9)
+    {
+        isDisturbance = false;
+    }
+
+    double tau = dmpPtr->getTemporalFactor();
+    double timeDuration = config.motionTimeDuration;
+    canVal -= 1 / tau * deltaT * 1 / (1 + phaseStop) ;
+
+
+    for (size_t i = 0; i < 7; ++i)
+    {
+        currentState[i].vel = currentState[i].vel * config.DMPAmplitude;
+    }
+
+    currentState = dmpPtr->calculateDirectlyVelocity(currentState, canVal / timeDuration, deltaT / timeDuration, targetPoseVec);
+
+    for (size_t i = 0; i < 7; ++i)
+    {
+        targetPoseVec[i] = currentState[i].pos;
+    }
+
+    float vel0, vel1;
+
+    Eigen::Vector3f linearVel;
+    linearVel << twist(0), twist(1), twist(2);
+    for (size_t i = 0; i < 3; i++)
+    {
+        vel0 = currentState[i].vel / timeDuration;
+        vel1 = config.phaseStopParas.Kpos * (targetPoseVec[i] - currentPosition(i)) - config.phaseStopParas.Dpos * linearVel(i);
+        targetVel(i) = mpcFactor * vel0 + (1 - mpcFactor) * vel1;
+    }
+
+
+    Eigen::Quaterniond dmpQuaternionVel;
+    dmpQuaternionVel.w() = currentState[3].vel;
+    dmpQuaternionVel.x() = currentState[4].vel;
+    dmpQuaternionVel.y() = currentState[5].vel;
+    dmpQuaternionVel.z() = currentState[6].vel;
+
+    Eigen::Quaterniond dmpQuaternionPosi;
+    dmpQuaternionPosi.w() = currentState[3].pos;
+    dmpQuaternionPosi.x() = currentState[4].pos;
+    dmpQuaternionPosi.y() = currentState[5].pos;
+    dmpQuaternionPosi.z() = currentState[6].pos;
+
+
+    Eigen::Quaterniond angularVel0 = dmpQuaternionVel * dmpQuaternionPosi.inverse();
+    angularVel0.w() *= 2;
+    angularVel0.x() *= 2;
+    angularVel0.y() *= 2;
+    angularVel0.z() *= 2;
+
+
+    double angularChange =  angularVel0.angularDistance(oldDMPAngularVelocity);
+    if (angularVel0.w() > 0 && oldDMPAngularVelocity.w() < 0 && angularChange < 1e-2)
+    {
+        angularVel0.w() = - angularVel0.w();
+        angularVel0.x() = - angularVel0.x();
+        angularVel0.y() = - angularVel0.y();
+        angularVel0.z() = - angularVel0.z();
+    }
+    oldDMPAngularVelocity = angularVel0;
+
+    Eigen::Vector3f currentAngularVel;
+    currentAngularVel << twist(3), twist(4), twist(5);
+
+    Eigen::Quaternionf targetQuaternionf;
+    targetQuaternionf.w() = targetPoseVec[3];
+    targetQuaternionf.x() = targetPoseVec[4];
+    targetQuaternionf.y() = targetPoseVec[5];
+    targetQuaternionf.z() = targetPoseVec[6];
+
+    Eigen::Matrix3f desiredMat(targetQuaternionf);
+    Eigen::Matrix3f currentMat = currentPose.block<3, 3>(0, 0);
+    Eigen::Matrix3f diffMat = desiredMat * currentMat.inverse();
+    Eigen::Vector3f diffRPY = VirtualRobot::MathTools::eigen3f2rpy(diffMat);
+    Eigen::Vector3f angularVel1 = config.phaseStopParas.Kori * diffRPY - config.phaseStopParas.Dori * currentAngularVel;
+
+    targetVel(3) = mpcFactor * angularVel0.x() / timeDuration + (1 - mpcFactor) * angularVel1(0);
+    targetVel(4) = mpcFactor * angularVel0.y() / timeDuration + (1 - mpcFactor) * angularVel1(1);
+    targetVel(5) = mpcFactor * angularVel0.z() / timeDuration + (1 - mpcFactor) * angularVel1(2);
+
+    debugData.canVal = canVal;
+    debugData.oriError = oriError;
+    debugData.posiError = posiError;
+    debugData.mpcFactor = mpcFactor;
+    debugData.poseError = poseError;
+}
+
+void TaskSpaceDMPController::learnDMPFromFiles(const std::vector<std::string>& fileNames, const std::vector<double>& ratios)
+{
+    if (ratios.size() != fileNames.size())
+    {
+        ARMARX_ERROR << "ratios should have the same size with files";
+        return;
+    }
+
+
+    DMP::Vec<DMP::SampledTrajectoryV2 > trajs;
+
+    double ratioSum = 0;
+    for (size_t i = 0; i < fileNames.size(); ++i)
+    {
+        DMP::SampledTrajectoryV2 traj;
+        traj.readFromCSVFile(fileNames.at(i));
+        traj = DMP::SampledTrajectoryV2::normalizeTimestamps(traj, 0, 1);
+        trajs.push_back(traj);
+
+        ratioSum += ratios.at(i);
+    }
+
+    if (ratioSum == 0)
+    {
+        ARMARX_ERROR << "ratios are invalid. The sum is equal to 0";
+        return;
+    }
+
+    DMP::DVec ratiosVec;
+    ratiosVec.resize(ratios.size());
+    for (size_t i = 0; i < ratios.size(); ++i)
+    {
+        ratiosVec.at(i) = ratios.at(i) / ratioSum;
+    }
+
+    ARMARX_INFO << "ratios: " << ratios.at(0);
+    dmpPtr->learnFromTrajectories(trajs);
+    dmpPtr->styleParas = dmpPtr->getStyleParasWithRatio(ratiosVec);
+}
+
+void TaskSpaceDMPController::learnDMPFromFiles(const std::vector<std::string>& fileNames)
+{
+    std::vector<double> ratios;
+    for (size_t i = 0; i < fileNames.size(); ++i)
+    {
+        if (i == 0)
+        {
+            ratios.push_back(1.0);
+        }
+        else
+        {
+            ratios.push_back(0.0);
+        }
+    }
+
+    learnDMPFromFiles(fileNames, ratios);
+}
+
+void TaskSpaceDMPController::setViaPose(double canVal, const Eigen::Matrix4f& viaPose)
+{
+
+    setViaPose(canVal, eigen4f2vec(viaPose));
+}
+
+void TaskSpaceDMPController::setViaPose(double canVal, const std::vector<double>& viaPoseWithQuaternion)
+{
+    if (canVal <= dmpPtr->getUMin())
+    {
+        goalPoseVec = viaPoseWithQuaternion;
+    }
+    dmpPtr->setViaPoint(canVal, viaPoseWithQuaternion);
+}
+
+void TaskSpaceDMPController::prepareExecution(const Eigen::Matrix4f& currentPose, const Eigen::Matrix4f& goalPose)
+{
+    std::vector<double> currentPoseVec = eigen4f2vec(currentPose);
+    std::vector<double> goalPoseVec = eigen4f2vec(goalPose);
+
+    prepareExecution(currentPoseVec, goalPoseVec);
+}
+
+void TaskSpaceDMPController::prepareExecution(const std::vector<double>& currentPoseVec, const std::vector<double>& goalPoseVec)
+{
+    ARMARX_CHECK_EQUAL(currentPoseVec.size(), 7);
+    ARMARX_CHECK_EQUAL(goalPoseVec.size(), 7);
+
+    for (size_t i = 0; i < currentPoseVec.size(); ++i)
+    {
+        currentState[i].pos = currentPoseVec.at(i);
+        currentState[i].vel = 0;
+        targetPoseVec.at(i) = currentPoseVec.at(i);
+    }
+
+    dmpPtr->prepareExecution(goalPoseVec, currentState, 1,  1);
+    this->goalPoseVec = goalPoseVec;
+    isDisturbance = false;
+    canVal = config.motionTimeDuration;
+    oldDMPAngularVelocity.setIdentity();
+
+}
+
+void TaskSpaceDMPController::setSpeed(double times)
+{
+    if (times == 0)
+    {
+        return;
+    }
+
+    config.motionTimeDuration /= times;
+}
+
+std::vector<double> TaskSpaceDMPController::eigen4f2vec(const Eigen::Matrix4f& pose)
+{
+    std::vector<double> viaPoseVec;
+    viaPoseVec.resize(7);
+
+    for (size_t i = 0; i < 3; ++i)
+    {
+        viaPoseVec.at(i) = pose(i, 3);
+    }
+
+    VirtualRobot::MathTools::Quaternion quat = VirtualRobot::MathTools::eigen4f2quat(pose);
+
+    viaPoseVec.at(3) = quat.w;
+    viaPoseVec.at(4) = quat.x;
+    viaPoseVec.at(5) = quat.y;
+    viaPoseVec.at(6) = quat.z;
+
+    return viaPoseVec;
+}
+
+void TaskSpaceDMPController::getError(const Eigen::Matrix4f& currentPose, Eigen::Vector3f& currentPosition, Eigen::Quaterniond& currentOrientation, double& posiError, double& oriError)
+{
+    currentPosition.setZero();
+    currentPosition << currentPose(0, 3), currentPose(1, 3), currentPose(2, 3);
+
+    VirtualRobot::MathTools::Quaternion quat = VirtualRobot::MathTools::eigen4f2quat(currentPose);
+    currentOrientation.w() = quat.w;
+    currentOrientation.x() = quat.x;
+    currentOrientation.y() = quat.y;
+    currentOrientation.z() = quat.z;
+
+    posiError = 0;
+    for (size_t i = 0; i < 3; ++i)
+    {
+        posiError += pow(currentPosition(i) - targetPoseVec[i], 2);
+    }
+    posiError = sqrt(posiError);
+
+    Eigen::Quaterniond targetQuaternion;
+    targetQuaternion.w() = targetPoseVec[3];
+    targetQuaternion.x() = targetPoseVec[4];
+    targetQuaternion.y() = targetPoseVec[5];
+    targetQuaternion.z() = targetPoseVec[6];
+
+    oriError = targetQuaternion.angularDistance(currentOrientation);
+    if (oriError > M_PI)
+    {
+        oriError = 2 * M_PI - oriError;
+    }
+
+}
+
+
diff --git a/source/RobotAPI/libraries/DMPController/TaskSpaceDMPController.h b/source/RobotAPI/libraries/DMPController/TaskSpaceDMPController.h
new file mode 100644
index 0000000000000000000000000000000000000000..c62fef3fb25c3bbf43fd8093db3308110b68d195
--- /dev/null
+++ b/source/RobotAPI/libraries/DMPController/TaskSpaceDMPController.h
@@ -0,0 +1,196 @@
+/*
+ * This file is part of ArmarX.
+ *
+ * ArmarX is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * ArmarX is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @package    RobotAPI::ArmarXObjects::DMPController
+ * @author     zhou ( you dot zhou at kit dot edu )
+ * @date       2018
+ * @copyright  http://www.gnu.org/licenses/gpl-2.0.txt
+ *             GNU General Public License
+ */
+
+#ifndef _ARMARX_LIB_RobotAPI_TaskSpaceDMPController_H
+#define _ARMARX_LIB_RobotAPI_TaskSpaceDMPController_H
+
+
+#include <dmp/representation/dmp/umitsmp.h>
+
+
+#include <VirtualRobot/RobotNodeSet.h>
+#include <ArmarXCore/core/logging/Logging.h>
+#include <ArmarXCore/core/exceptions/local/ExpressionException.h>
+
+
+namespace armarx
+{
+
+    struct PhaseStopParams
+    {
+        float goDist = 80;
+        float backDist = 50;
+        float maxValue = 100;
+        float slop = 1000;
+        float Kpos = 1;
+        float Dpos = 2;
+        float Kori = 1;
+        float Dori = 0;
+        float mm2radi = 10;
+    };
+
+    struct TaskSpaceDMPControllerConfig
+    {
+        int DMPKernelSize = 50;
+        std::string DMPMode = "Linear";
+        std::string DMPStyle = "Discrete";
+        float DMPAmplitude = 1;
+        float motionTimeDuration = 10;
+        PhaseStopParams phaseStopParas;
+    };
+
+    struct DebugInfo
+    {
+        double canVal;
+        double mpcFactor;
+        double poseError;
+        double posiError;
+        double oriError;
+    };
+
+    /**
+    * @defgroup Library-TaskSpaceDMPController TaskSpaceDMPController
+    * @ingroup RobotAPI
+    * A description of the library TaskSpaceDMPController.
+    *
+    * @class TaskSpaceDMPController
+    * @ingroup Library-TaskSpaceDMPController
+    * @brief Brief description of class TaskSpaceDMPController.
+    *
+    * Detailed description of class TaskSpaceDMPController.
+    */
+    class TaskSpaceDMPController
+    {
+    public:
+        TaskSpaceDMPController(std::string name, const TaskSpaceDMPControllerConfig& config, bool isPhaseStop = true)
+        {
+            this->config = config;
+
+            int ModeInd;
+            if (config.DMPMode == "MinimumJerk")
+            {
+                ModeInd = 2;
+            }
+            else
+            {
+                ModeInd = 1;
+            }
+
+
+            dmpPtr.reset(new DMP::UMITSMP(config.DMPKernelSize, ModeInd));
+            canVal = config.motionTimeDuration;
+
+            targetPoseVec.resize(7);
+            targetVel.resize(6);
+            targetVel.setZero();
+            currentState.resize(7);
+
+            this->isPhaseStop = isPhaseStop;
+            dmpName = name;
+        }
+
+        std::string getName()
+        {
+            return dmpName;
+        }
+
+
+        void flow(double deltaT, const Eigen::Matrix4f& currentPose, const Eigen::VectorXf& twist);
+
+        Eigen::VectorXf getTargetVelocity()
+        {
+            return targetVel;
+        }
+
+        std::vector<double> getTargetPose()
+        {
+            return targetPoseVec;
+        }
+
+        Eigen::Matrix4f getTargetPoseMat()
+        {
+            Eigen::Matrix4f res = VirtualRobot::MathTools::quat2eigen4f(targetPoseVec.at(4), targetPoseVec.at(5), targetPoseVec.at(6), targetPoseVec.at(3));
+            res(0, 3) = targetPoseVec.at(0);
+            res(1, 3) = targetPoseVec.at(1);
+            res(2, 3) = targetPoseVec.at(2);
+
+            return res;
+        }
+
+        void learnDMPFromFiles(const std::vector<std::string>& fileNames, const std::vector<double>& ratios);
+        void learnDMPFromFiles(const std::vector<std::string>& fileNames);
+
+        void setViaPose(double canVal, const Eigen::Matrix4f& viaPose);
+        void setViaPose(double canVal, const std::vector<double>& viaPoseWithQuaternion);
+
+        void prepareExecution(const Eigen::Matrix4f& currentPose, const Eigen::Matrix4f& goalPose);
+        void prepareExecution(const std::vector<double>& currentPoseVec, const std::vector<double>& goalPoseVec);
+
+        void setSpeed(double times);
+
+        void setGoalPose(const Eigen::Matrix4f& goalPose)
+        {
+            setViaPose(dmpPtr->getUMin(), goalPose);
+        }
+
+        void setGoalPoseVec(const std::vector<double> goalPoseVec)
+        {
+            setViaPose(dmpPtr->getUMin(), goalPoseVec);
+        }
+
+        DebugInfo debugData;
+        std::vector<double> eigen4f2vec(const Eigen::Matrix4f& pose);
+
+        DMP::UMITSMPPtr getDMP()
+        {
+            return dmpPtr;
+        }
+
+        double canVal;
+        bool isPhaseStop;
+        std::string dmpName;
+    private:
+
+
+        DMP::DVec goalPoseVec;
+
+        Eigen::VectorXf targetVel;
+        DMP::DVec targetPoseVec;
+
+        DMP::UMITSMPPtr dmpPtr;
+        DMP::Vec<DMP::DMPState > currentState;
+        TaskSpaceDMPControllerConfig config;
+
+
+        bool isDisturbance;
+
+
+        void getError(const Eigen::Matrix4f& pose, Eigen::Vector3f& position, Eigen::Quaterniond& quaternion, double& posiError, double& oriError);
+
+        Eigen::Quaterniond oldDMPAngularVelocity;
+    };
+
+    typedef boost::shared_ptr<TaskSpaceDMPController> TaskSpaceDMPControllerPtr;
+
+}
+
+#endif
diff --git a/source/RobotAPI/libraries/DMPController/test/CMakeLists.txt b/source/RobotAPI/libraries/DMPController/test/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..df7b127d74b14e3a3b6bce5c3fd556324c3dfa73
--- /dev/null
+++ b/source/RobotAPI/libraries/DMPController/test/CMakeLists.txt
@@ -0,0 +1,5 @@
+
+# Libs required for the tests
+SET(LIBS ${LIBS} ArmarXCore DMPController)
+ 
+armarx_add_test(DMPControllerTest DMPControllerTest.cpp "${LIBS}")
\ No newline at end of file
diff --git a/source/RobotAPI/libraries/DMPController/test/DMPControllerTest.cpp b/source/RobotAPI/libraries/DMPController/test/DMPControllerTest.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ce13dde7e8ae02eeeade7e2be1e52fce411acc34
--- /dev/null
+++ b/source/RobotAPI/libraries/DMPController/test/DMPControllerTest.cpp
@@ -0,0 +1,36 @@
+/*
+ * This file is part of ArmarX.
+ *
+ * ArmarX is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * ArmarX is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @package    RobotAPI::ArmarXObjects::DMPController
+ * @author     zhou ( you dot zhou at kit dot edu )
+ * @date       2018
+ * @copyright  http://www.gnu.org/licenses/gpl-2.0.txt
+ *             GNU General Public License
+ */
+
+#define BOOST_TEST_MODULE RobotAPI::ArmarXLibraries::DMPController
+
+#define ARMARX_BOOST_TEST
+
+#include <RobotAPI/Test.h>
+#include "../TaskSpaceDMPController.h"
+
+#include <iostream>
+
+BOOST_AUTO_TEST_CASE(testExample)
+{
+
+    BOOST_CHECK_EQUAL(true, true);
+}
diff --git a/source/RobotAPI/libraries/RobotAPINJointControllers/CMakeLists.txt b/source/RobotAPI/libraries/RobotAPINJointControllers/CMakeLists.txt
index 5b48d4fe03f9d108934a8a5854d23f234d75f4c4..bbef6320f875fb4b58c9980cbb209a4cd1c9884a 100644
--- a/source/RobotAPI/libraries/RobotAPINJointControllers/CMakeLists.txt
+++ b/source/RobotAPI/libraries/RobotAPINJointControllers/CMakeLists.txt
@@ -24,6 +24,7 @@ set(LIBS RobotAPIInterfaces ArmarXCoreObservers ArmarXCoreStatechart ArmarXCoreE
     Saba
     SimDynamics
     RobotUnit
+
     )
 
 set(LIB_FILES
@@ -41,22 +42,22 @@ if (DMP_FOUND )
 
     list(APPEND LIB_HEADERS
            DMPController/NJointJointSpaceDMPController.h
-           DMPController/NJointTaskSpaceDMPController.h
            DMPController/NJointJSDMPController.h
            DMPController/NJointTSDMPController.h
            DMPController/NJointCCDMPController.h
+           DMPController/NJointBimanualCCDMPController.h
 
            )
     list(APPEND LIB_FILES
            DMPController/NJointJointSpaceDMPController.cpp
-           DMPController/NJointTaskSpaceDMPController.cpp
            DMPController/NJointJSDMPController.cpp
            DMPController/NJointTSDMPController.cpp
            DMPController/NJointCCDMPController.cpp
+           DMPController/NJointBimanualCCDMPController.cpp
 
            )
 
-    list(APPEND LIBS ${DMP_LIBRARIES})
+    list(APPEND LIBS ${DMP_LIBRARIES} DMPController)
 endif ()
 
 armarx_add_library("${LIB_NAME}"  "${LIB_FILES}" "${LIB_HEADERS}" "${LIBS}")
diff --git a/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointBimanualCCDMPController.cpp b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointBimanualCCDMPController.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b0dbb2e71f80899d98427a742988be7826f8a165
--- /dev/null
+++ b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointBimanualCCDMPController.cpp
@@ -0,0 +1,914 @@
+#include "NJointBimanualCCDMPController.h"
+
+namespace armarx
+{
+    NJointControllerRegistration<NJointBimanualCCDMPController> registrationControllerNJointBimanualCCDMPController("NJointBimanualCCDMPController");
+
+    NJointBimanualCCDMPController::NJointBimanualCCDMPController(armarx::NJointControllerDescriptionProviderInterfacePtr prov, const armarx::NJointControllerConfigPtr& config, const VirtualRobot::RobotPtr&)
+    {
+        ARMARX_INFO << "Preparing ... ";
+        cfg = NJointBimanualCCDMPControllerConfigPtr::dynamicCast(config);
+        ARMARX_CHECK_EXPRESSION(prov);
+        RobotUnitPtr robotUnit = RobotUnitPtr::dynamicCast(prov);
+        ARMARX_CHECK_EXPRESSION(robotUnit);
+
+        leftRNS = robotUnit->getRtRobot()->getRobotNodeSet("LeftArm");
+        for (size_t i = 0; i < leftRNS->getSize(); ++i)
+        {
+            std::string jointName = leftRNS->getNode(i)->getName();
+
+            leftJointNames.push_back(jointName);
+            ControlTargetBase* ct = prov->getControlTarget(jointName, ControlModes::Torque1DoF);
+            const SensorValueBase* sv = prov->getSensorValue(jointName);
+            leftTargets.push_back(ct->asA<ControlTarget1DoFActuatorTorque>());
+            const SensorValue1DoFActuatorVelocity* velocitySensor = sv->asA<SensorValue1DoFActuatorVelocity>();
+            const SensorValue1DoFActuatorPosition* positionSensor = sv->asA<SensorValue1DoFActuatorPosition>();
+            const SensorValue1DoFActuatorAcceleration* accelerationSensor = sv->asA<SensorValue1DoFActuatorAcceleration>();
+
+            if (!velocitySensor)
+            {
+                ARMARX_WARNING << "No velocitySensor available for " << jointName;
+            }
+            if (!positionSensor)
+            {
+                ARMARX_WARNING << "No positionSensor available for " << jointName;
+            }
+
+            if (!accelerationSensor)
+            {
+                ARMARX_WARNING << "No accelerationSensor available for " << jointName;
+            }
+
+
+            leftVelocitySensors.push_back(velocitySensor);
+            leftPositionSensors.push_back(positionSensor);
+            leftAccelerationSensors.push_back(accelerationSensor);
+
+
+        };
+
+
+
+
+        rightRNS = robotUnit->getRtRobot()->getRobotNodeSet("RightArm");
+        for (size_t i = 0; i < rightRNS->getSize(); ++i)
+        {
+            std::string jointName = rightRNS->getNode(i)->getName();
+            rightJointNames.push_back(jointName);
+            ControlTargetBase* ct = prov->getControlTarget(jointName, ControlModes::Torque1DoF);
+            const SensorValueBase* sv = prov->getSensorValue(jointName);
+            rightTargets.push_back(ct->asA<ControlTarget1DoFActuatorTorque>());
+            const SensorValue1DoFActuatorVelocity* velocitySensor = sv->asA<SensorValue1DoFActuatorVelocity>();
+            const SensorValue1DoFActuatorPosition* positionSensor = sv->asA<SensorValue1DoFActuatorPosition>();
+            const SensorValue1DoFActuatorAcceleration* accelerationSensor = sv->asA<SensorValue1DoFActuatorAcceleration>();
+
+
+            if (!velocitySensor)
+            {
+                ARMARX_WARNING << "No velocitySensor available for " << jointName;
+            }
+            if (!positionSensor)
+            {
+                ARMARX_WARNING << "No positionSensor available for " << jointName;
+            }
+            if (!accelerationSensor)
+            {
+                ARMARX_WARNING << "No accelerationSensor available for " << jointName;
+            }
+
+            rightVelocitySensors.push_back(velocitySensor);
+            rightPositionSensors.push_back(positionSensor);
+            rightAccelerationSensors.push_back(accelerationSensor);
+
+        };
+
+
+        const SensorValueBase* svlf = prov->getSensorValue("FT L");
+        leftForceTorque = svlf->asA<SensorValueForceTorque>();
+        const SensorValueBase* svrf = prov->getSensorValue("FT R");
+        rightForceTorque = svrf->asA<SensorValueForceTorque>();
+
+        leftIK.reset(new VirtualRobot::DifferentialIK(leftRNS, leftRNS->getRobot()->getRootNode(), VirtualRobot::JacobiProvider::eSVDDamped));
+        rightIK.reset(new VirtualRobot::DifferentialIK(rightRNS, rightRNS->getRobot()->getRootNode(), VirtualRobot::JacobiProvider::eSVDDamped));
+
+
+        TaskSpaceDMPControllerConfig taskSpaceDMPConfig;
+        taskSpaceDMPConfig.motionTimeDuration = cfg->timeDuration;
+        taskSpaceDMPConfig.DMPKernelSize = cfg->kernelSize;
+        taskSpaceDMPConfig.DMPMode = cfg->dmpMode;
+        taskSpaceDMPConfig.DMPStyle = cfg->dmpType;
+        taskSpaceDMPConfig.DMPAmplitude = 1.0;
+        taskSpaceDMPConfig.phaseStopParas.goDist = cfg->phaseDist0;
+        taskSpaceDMPConfig.phaseStopParas.backDist = cfg->phaseDist1;
+        taskSpaceDMPConfig.phaseStopParas.Kpos = cfg->phaseKpPos;
+        taskSpaceDMPConfig.phaseStopParas.Dpos = 0;
+        taskSpaceDMPConfig.phaseStopParas.Kori = cfg->phaseKpOri;
+        taskSpaceDMPConfig.phaseStopParas.Dori = 0;
+        taskSpaceDMPConfig.phaseStopParas.mm2radi = cfg->posToOriRatio;
+        taskSpaceDMPConfig.phaseStopParas.maxValue = cfg->phaseL;
+        taskSpaceDMPConfig.phaseStopParas.slop = cfg->phaseK;
+
+
+        TaskSpaceDMPControllerPtr leftLeader(new TaskSpaceDMPController("leftLeader", taskSpaceDMPConfig));
+        TaskSpaceDMPControllerPtr leftFollower(new TaskSpaceDMPController("leftFollower", taskSpaceDMPConfig));
+        TaskSpaceDMPControllerPtr rightLeader(new TaskSpaceDMPController("rightLeader", taskSpaceDMPConfig));
+        TaskSpaceDMPControllerPtr rightFollower(new TaskSpaceDMPController("rightFollower", taskSpaceDMPConfig));
+
+        leftGroup.push_back(leftLeader);
+        leftGroup.push_back(rightFollower);
+
+        rightGroup.push_back(rightLeader);
+        rightGroup.push_back(leftFollower);
+
+
+        tcpLeft = leftRNS->getTCP();
+        tcpRight = rightRNS->getTCP();
+        NJointBimanualCCDMPControllerSensorData initSensorData;
+        initSensorData.deltaT = 0;
+        initSensorData.currentTime = 0;
+        initSensorData.currentLeftPose = leftRNS->getTCP()->getPoseInRootFrame();
+        initSensorData.currentRightPose = rightRNS->getTCP()->getPoseInRootFrame();
+        controllerSensorData.reinitAllBuffers(initSensorData);
+
+        leaderName = "Left";
+
+        NJointBimanualCCDMPControllerControlData initData;
+        initData.leftTargetVel.resize(6);
+        initData.leftTargetVel.setZero();
+        initData.rightTargetVel.resize(6);
+        initData.rightTargetVel.setZero();
+        reinitTripleBuffer(initData);
+
+        leftDesiredJointValues.resize(leftTargets.size());
+        ARMARX_CHECK_EQUAL(cfg->leftDesiredJointValues.size(), leftTargets.size());
+
+        for (size_t i = 0; i < leftTargets.size(); ++i)
+        {
+            leftDesiredJointValues(i) = cfg->leftDesiredJointValues.at(i);
+        }
+
+        rightDesiredJointValues.resize(rightTargets.size());
+        ARMARX_CHECK_EQUAL(cfg->rightDesiredJointValues.size(), rightTargets.size());
+
+        for (size_t i = 0; i < rightTargets.size(); ++i)
+        {
+            rightDesiredJointValues(i) = cfg->rightDesiredJointValues.at(i);
+        }
+
+        KoriFollower = cfg->KoriFollower;
+        KposFollower = cfg->KposFollower;
+
+        kpos << cfg->Kpos[0], cfg->Kpos[1], cfg->Kpos[2];
+        dpos << cfg->Dpos[0], cfg->Dpos[1], cfg->Dpos[2];
+        kori << cfg->Kori[0], cfg->Kori[1], cfg->Kori[2];
+        dori << cfg->Dori[0], cfg->Dori[1], cfg->Dori[2];
+
+
+        knull = cfg->knull;
+        dnull = cfg->dnull;
+
+        torqueLimit = cfg->torqueLimit;
+
+        kpf.resize(12);
+        kif.resize(12);
+        forceC_des.resize(12);
+
+        ARMARX_CHECK_EQUAL(cfg->Kpf.size(), kpf.rows());
+        ARMARX_CHECK_EQUAL(cfg->Kif.size(), kif.rows());
+        ARMARX_CHECK_EQUAL(cfg->DesiredForce.size(), forceC_des.rows());
+
+
+        for (size_t i = 0; i < 12; i++)
+        {
+            kpf(i) = cfg->Kpf.at(i);
+            kif(i) = cfg->Kif.at(i);
+            forceC_des(i) = cfg->DesiredForce.at(i);
+        }
+
+        boxWidth = cfg->BoxWidth;
+
+    }
+
+    std::string NJointBimanualCCDMPController::getClassName(const Ice::Current&) const
+    {
+        return "NJointBimanualCCDMPController";
+    }
+
+    void NJointBimanualCCDMPController::controllerRun()
+    {
+        if (!controllerSensorData.updateReadBuffer())
+        {
+            return;
+        }
+
+        double deltaT = controllerSensorData.getReadBuffer().deltaT;
+
+
+        Eigen::VectorXf leftTargetVel;
+        leftTargetVel.resize(6);
+        leftTargetVel.setZero();
+        Eigen::VectorXf rightTargetVel;
+        rightTargetVel.resize(6);
+        rightTargetVel.setZero();
+
+        std::vector<TaskSpaceDMPControllerPtr > currentControlGroup;
+        Eigen::Matrix4f currentLeaderPose;
+        Eigen::Matrix4f currentFollowerPose;
+        Eigen::VectorXf currentLeaderTwist;
+        Eigen::VectorXf currentFollowerTwist;
+        if (leaderName == "Left")
+        {
+            currentControlGroup = leftGroup;
+            currentLeaderPose = controllerSensorData.getReadBuffer().currentLeftPose;
+            currentFollowerPose = controllerSensorData.getReadBuffer().currentRightPose;
+            currentLeaderTwist = controllerSensorData.getReadBuffer().currentLeftTwist;
+            currentFollowerTwist = controllerSensorData.getReadBuffer().currentRightTwist;
+        }
+        else
+        {
+            currentControlGroup = rightGroup;
+            currentLeaderPose = controllerSensorData.getReadBuffer().currentRightPose;
+            currentFollowerPose = controllerSensorData.getReadBuffer().currentLeftPose;
+            currentLeaderTwist = controllerSensorData.getReadBuffer().currentRightTwist;
+            currentFollowerTwist = controllerSensorData.getReadBuffer().currentLeftTwist;
+        }
+
+        TaskSpaceDMPControllerPtr leaderDMP = currentControlGroup[0];
+        TaskSpaceDMPControllerPtr followerDMP = currentControlGroup[1];
+
+
+        leaderDMP->flow(deltaT, currentLeaderPose, currentLeaderTwist);
+
+        Eigen::Matrix4f currentFollowerLocalPose;
+        currentFollowerLocalPose.block<3, 3>(0, 0) = currentFollowerPose.block<3, 3>(0, 0) * currentLeaderPose.block<3, 3>(0, 0).inverse();
+        currentFollowerLocalPose.block<3, 1>(0, 3) = currentFollowerLocalPose.block<3, 3>(0, 0) * (currentFollowerPose.block<3, 1>(0, 3) - currentLeaderPose.block<3, 1>(0, 3));
+        followerDMP->flow(deltaT, currentFollowerLocalPose, currentFollowerTwist);
+
+        Eigen::VectorXf leaderTargetVel = leaderDMP->getTargetVelocity();
+        Eigen::Matrix4f leaderTargetPose = leaderDMP->getTargetPoseMat();
+        Eigen::Matrix4f followerLocalTargetPose = followerDMP->getTargetPoseMat();
+        Eigen::Matrix4f followerTargetPose;
+        followerTargetPose.block<3, 3>(0, 0) = followerLocalTargetPose.block<3, 3>(0, 0) * currentLeaderPose.block<3, 3>(0, 0);
+        followerTargetPose.block<3, 1>(0, 3) = currentLeaderPose.block<3, 3>(0, 0) * followerLocalTargetPose.block<3, 1>(0, 3) + currentLeaderPose.block<3, 1>(0, 3);
+
+
+        Eigen::VectorXf followerLocalTargetVel = followerDMP->getTargetVelocity();
+        Eigen::VectorXf followerTargetVel = followerLocalTargetVel;
+        //        followerTargetVel.block<3, 1>(0, 0) = currentLeaderPose.block<3, 3>(0, 0) * followerLocalTargetVel.block<3, 1>(0, 0) + leaderTargetVel.block<3, 1>(0, 0);
+        followerTargetVel.block<3, 1>(0, 0) = KposFollower * (followerTargetPose.block<3, 1>(0, 3) - currentFollowerPose.block<3, 1>(0, 3));
+
+
+        Eigen::Matrix3f followerDiffMat =  followerTargetPose.block<3, 3>(0, 0) * currentFollowerPose.block<3, 3>(0, 0).inverse();
+        Eigen::Vector3f followerDiffRPY = KoriFollower * VirtualRobot::MathTools::eigen3f2rpy(followerDiffMat);
+        followerTargetVel(3) = followerDiffRPY(0);
+        followerTargetVel(4) = followerDiffRPY(1);
+        followerTargetVel(5) = followerDiffRPY(2);
+
+        virtualtimer = leaderDMP->canVal;
+
+
+        std::vector<double> leftDMPTarget;
+        std::vector<double> rightDMPTarget;
+
+
+        std::vector<double> followerTargetPoseVec = followerDMP->eigen4f2vec(followerTargetPose);
+
+
+        Eigen::Matrix4f leftTargetPose;
+        Eigen::Matrix4f rightTargetPose;
+
+        if (leaderName == "Left")
+        {
+            leftTargetVel = leaderTargetVel;
+            rightTargetVel = followerTargetVel;
+
+            leftDMPTarget = leaderDMP->getTargetPose();
+            rightDMPTarget = followerTargetPoseVec;
+
+
+            leftTargetPose = leaderTargetPose;
+            rightTargetPose = followerTargetPose;
+        }
+        else
+        {
+            rightTargetVel = leaderTargetVel;
+            leftTargetVel = followerTargetVel;
+
+            rightDMPTarget = leaderDMP->getTargetPose();
+            leftDMPTarget = followerTargetPoseVec;
+
+            rightTargetPose = leaderTargetPose;
+            leftTargetPose = followerTargetPose;
+
+        }
+
+
+
+
+        //        debugOutputData.getWriteBuffer().latestTargetVelocities["LeftArm_xvel"] = leftTargetVel(0);
+        //        debugOutputData.getWriteBuffer().latestTargetVelocities["LeftArm_yvel"] = leftTargetVel(1);
+        //        debugOutputData.getWriteBuffer().latestTargetVelocities["LeftArm_zvel"] = leftTargetVel(2);
+        //        debugOutputData.getWriteBuffer().latestTargetVelocities["LeftArm_rollvel"] = leftTargetVel(3);
+        //        debugOutputData.getWriteBuffer().latestTargetVelocities["LeftArm_pitchvel"] = leftTargetVel(4);
+        //        debugOutputData.getWriteBuffer().latestTargetVelocities["LeftArm_yawvel"] = leftTargetVel(5);
+
+        //        debugOutputData.getWriteBuffer().latestTargetVelocities["RightArm_xvel"] = rightTargetVel(0);
+        //        debugOutputData.getWriteBuffer().latestTargetVelocities["RightArm_yvel"] = rightTargetVel(1);
+        //        debugOutputData.getWriteBuffer().latestTargetVelocities["RightArm_zvel"] = rightTargetVel(2);
+        //        debugOutputData.getWriteBuffer().latestTargetVelocities["RightArm_rollvel"] = rightTargetVel(3);
+        //        debugOutputData.getWriteBuffer().latestTargetVelocities["RightArm_pitchvel"] = rightTargetVel(4);
+        //        debugOutputData.getWriteBuffer().latestTargetVelocities["RightArm_yawvel"] = rightTargetVel(5);
+
+
+        //        debugOutputData.getWriteBuffer().dmpTargets["LeftArm_dmp_x"] = leftDMPTarget[0];
+        //        debugOutputData.getWriteBuffer().dmpTargets["LeftArm_dmp_y"] = leftDMPTarget[1];
+        //        debugOutputData.getWriteBuffer().dmpTargets["LeftArm_dmp_z"] = leftDMPTarget[2];
+        //        debugOutputData.getWriteBuffer().dmpTargets["LeftArm_dmp_qw"] = leftDMPTarget[3];
+        //        debugOutputData.getWriteBuffer().dmpTargets["LeftArm_dmp_qx"] = leftDMPTarget[4];
+        //        debugOutputData.getWriteBuffer().dmpTargets["LeftArm_dmp_qy"] = leftDMPTarget[5];
+        //        debugOutputData.getWriteBuffer().dmpTargets["LeftArm_dmp_qz"] = leftDMPTarget[6];
+
+        //        debugOutputData.getWriteBuffer().dmpTargets["RightArm_dmp_x"] = rightDMPTarget[0];
+        //        debugOutputData.getWriteBuffer().dmpTargets["RightArm_dmp_y"] = rightDMPTarget[1];
+        //        debugOutputData.getWriteBuffer().dmpTargets["RightArm_dmp_z"] = rightDMPTarget[2];
+        //        debugOutputData.getWriteBuffer().dmpTargets["RightArm_dmp_qw"] = rightDMPTarget[3];
+        //        debugOutputData.getWriteBuffer().dmpTargets["RightArm_dmp_qx"] = rightDMPTarget[4];
+        //        debugOutputData.getWriteBuffer().dmpTargets["RightArm_dmp_qy"] = rightDMPTarget[5];
+        //        debugOutputData.getWriteBuffer().dmpTargets["RightArm_dmp_qz"] = rightDMPTarget[6];
+
+        //        std::vector<double> currentLeftPoseVec = leaderDMP->eigen4f2vec(controllerSensorData.getReadBuffer().currentLeftPose);
+        //        std::vector<double> currentRightPoseVec = leaderDMP->eigen4f2vec(controllerSensorData.getReadBuffer().currentRightPose);
+
+
+        //        debugOutputData.getWriteBuffer().currentPose["leftPose_x"] = currentLeftPoseVec[0];
+        //        debugOutputData.getWriteBuffer().currentPose["leftPose_y"] = currentLeftPoseVec[1];
+        //        debugOutputData.getWriteBuffer().currentPose["leftPose_z"] = currentLeftPoseVec[2];
+        //        debugOutputData.getWriteBuffer().currentPose["leftPose_qw"] = currentLeftPoseVec[3];
+        //        debugOutputData.getWriteBuffer().currentPose["leftPose_qx"] = currentLeftPoseVec[4];
+        //        debugOutputData.getWriteBuffer().currentPose["leftPose_qy"] = currentLeftPoseVec[5];
+        //        debugOutputData.getWriteBuffer().currentPose["leftPose_qz"] = currentLeftPoseVec[6];
+
+        //        debugOutputData.getWriteBuffer().currentPose["rightPose_x"] = currentRightPoseVec[0];
+        //        debugOutputData.getWriteBuffer().currentPose["rightPose_y"] = currentRightPoseVec[1];
+        //        debugOutputData.getWriteBuffer().currentPose["rightPose_z"] = currentRightPoseVec[2];
+        //        debugOutputData.getWriteBuffer().currentPose["rightPose_qw"] = currentRightPoseVec[3];
+        //        debugOutputData.getWriteBuffer().currentPose["rightPose_qx"] = currentRightPoseVec[4];
+        //        debugOutputData.getWriteBuffer().currentPose["rightPose_qy"] = currentRightPoseVec[5];
+        //        debugOutputData.getWriteBuffer().currentPose["rightPose_qz"] = currentRightPoseVec[6];
+
+
+        //        debugOutputData.getWriteBuffer().leaderCanVal = leaderDMP->debugData.canVal;
+        //        debugOutputData.getWriteBuffer().leadermpcFactor =  leaderDMP->debugData.mpcFactor;
+        //        debugOutputData.getWriteBuffer().leadererror = leaderDMP->debugData.poseError;
+        //        debugOutputData.getWriteBuffer().leaderposError = leaderDMP->debugData.posiError;
+        //        debugOutputData.getWriteBuffer().leaderoriError = leaderDMP->debugData.oriError;
+
+        //        debugOutputData.getWriteBuffer().followerCanVal = followerDMP->debugData.canVal;
+        //        debugOutputData.getWriteBuffer().followermpcFactor =  followerDMP->debugData.mpcFactor;
+        //        debugOutputData.getWriteBuffer().followererror = followerDMP->debugData.poseError;
+        //        debugOutputData.getWriteBuffer().followerposError = followerDMP->debugData.posiError;
+        //        debugOutputData.getWriteBuffer().followeroriError = followerDMP->debugData.oriError;
+
+        //        debugOutputData.commitWrite();
+
+
+
+
+
+
+
+        LockGuardType guard {controlDataMutex};
+        getWriterControlStruct().leftTargetVel = leftTargetVel;
+        getWriterControlStruct().rightTargetVel = rightTargetVel;
+        getWriterControlStruct().leftTargetPose = leftTargetPose;
+        getWriterControlStruct().rightTargetPose = rightTargetPose;
+        writeControlStruct();
+    }
+
+    Eigen::VectorXf NJointBimanualCCDMPController::getControlWrench(const Eigen::VectorXf& tcptwist, const Eigen::Matrix4f& currentPose, const Eigen::Matrix4f& targetPose)
+    {
+        //        Eigen::Vector3f currentTCPLinearVelocity;
+        //        currentTCPLinearVelocity << 0.001 * tcptwist(0),   0.001 * tcptwist(1), 0.001 * tcptwist(2);
+        //        Eigen::Vector3f currentTCPAngularVelocity;
+        //        currentTCPAngularVelocity << tcptwist(3),   tcptwist(4),  tcptwist(5);
+
+        //        Eigen::Vector3f currentTCPPosition = currentPose.block<3,1>(0,3);
+        //        Eigen::Vector3f desiredPosition = targetPose.block<3,1>(0,3);
+        //        Eigen::Vector3f tcpForces = 0.001 * kpos.cwiseProduct(desiredPosition - currentTCPPosition);
+        //        Eigen::Vector3f tcpDesiredForce = tcpForces - dpos.cwiseProduct(currentTCPLinearVelocity);
+
+        //        Eigen::Matrix3f currentRotMat = currentPose.block<3, 3>(0, 0);
+        //        Eigen::Matrix3f diffMat = targetPose.block<3,3>(0,0) * currentRotMat.inverse();
+        //        Eigen::Vector3f rpy = VirtualRobot::MathTools::eigen3f2rpy(diffMat);
+
+        //        Eigen::Vector3f tcpDesiredTorque = kori.cwiseProduct(rpy) - dori.cwiseProduct(currentTCPAngularVelocity);
+        //        Eigen::Vector6f tcpDesiredWrench;
+        //        tcpDesiredWrench <<   0.001 * tcpDesiredForce, tcpDesiredTorque;
+
+        //        return tcpDesiredWrench;
+
+    }
+
+
+
+    void NJointBimanualCCDMPController::rtRun(const IceUtil::Time& sensorValuesTimestamp, const IceUtil::Time& timeSinceLastIteration)
+    {
+        double deltaT = timeSinceLastIteration.toSecondsDouble();
+        controllerSensorData.getWriteBuffer().currentLeftPose = tcpLeft->getPoseInRootFrame();
+        controllerSensorData.getWriteBuffer().currentRightPose = tcpRight->getPoseInRootFrame();
+        controllerSensorData.getWriteBuffer().deltaT = deltaT;
+        controllerSensorData.getWriteBuffer().currentTime += deltaT;
+        // cartesian vel controller
+        Eigen::MatrixXf I = Eigen::MatrixXf::Identity(leftTargets.size(), leftTargets.size());
+
+        Eigen::MatrixXf jacobiL = leftIK->getJacobianMatrix(tcpLeft, VirtualRobot::IKSolver::CartesianSelection::All);
+        jacobiL.block<3, 8>(0, 0) = 0.001 * jacobiL.block<3, 8>(0, 0);
+
+        Eigen::VectorXf leftqpos;
+        Eigen::VectorXf leftqvel;
+        leftqpos.resize(leftPositionSensors.size());
+        leftqvel.resize(leftVelocitySensors.size());
+        for (size_t i = 0; i < leftVelocitySensors.size(); ++i)
+        {
+            leftqpos(i) = leftPositionSensors[i]->position;
+            leftqvel(i) = leftVelocitySensors[i]->velocity;
+        }
+
+        Eigen::MatrixXf jacobiR = rightIK->getJacobianMatrix(tcpRight, VirtualRobot::IKSolver::CartesianSelection::All);
+        jacobiR.block<3, 8>(0, 0) = 0.001 * jacobiR.block<3, 8>(0, 0);
+
+
+        Eigen::VectorXf rightqpos;
+        Eigen::VectorXf rightqvel;
+        rightqpos.resize(rightPositionSensors.size());
+        rightqvel.resize(rightVelocitySensors.size());
+
+        for (size_t i = 0; i < rightVelocitySensors.size(); ++i)
+        {
+            rightqpos(i) = rightPositionSensors[i]->position;
+            rightqvel(i) = rightVelocitySensors[i]->velocity;
+        }
+
+        Eigen::VectorXf currentLeftTwist = jacobiL * leftqvel;
+        Eigen::VectorXf currentRightTwist = jacobiR * rightqvel;
+
+
+        controllerSensorData.getWriteBuffer().currentLeftTwist = currentLeftTwist;
+        controllerSensorData.getWriteBuffer().currentRightTwist = currentRightTwist;
+        controllerSensorData.commitWrite();
+
+
+        Eigen::Matrix4f leftTargetPose = rtGetControlStruct().leftTargetPose;
+        Eigen::Matrix4f rightTargetPose = rtGetControlStruct().rightTargetPose;
+        Eigen::VectorXf leftTargetVel = rtGetControlStruct().leftTargetVel;
+        Eigen::VectorXf rightTargetVel = rtGetControlStruct().rightTargetVel;
+        Eigen::Matrix4f leftCurrentPose = tcpLeft->getPoseInRootFrame();
+        Eigen::Matrix4f rightCurrentPose = tcpRight->getPoseInRootFrame();
+
+        // Todo: force control
+        int nl = leftRNS->getSize();
+        int nr = rightRNS->getSize();
+        int n = nl + nr;
+        // GraspMatrix
+        Eigen::Vector3f localDistanceCoM;
+        localDistanceCoM << 0.5 * boxWidth, 0, 0;
+
+
+        Eigen::Vector3f rl = -leftCurrentPose.block<3, 3>(0, 0) * localDistanceCoM; //tcpLeft->getRobot()->getRootNode()->toLocalCoordinateSystem(tcpLeft->toGlobalCoordinateSystemVec(localDistanceCoM));
+        Eigen::Vector3f rr = rightCurrentPose.block<3, 3>(0, 0) * localDistanceCoM;
+        Eigen::Matrix6f leftGraspMatrix = Eigen::MatrixXf::Identity(nl, nl);
+        Eigen::Matrix6f rightGraspMatrix = Eigen::MatrixXf::Identity(nr, nr);
+        leftGraspMatrix.block<3, 3>(3, 0) << 0, -rl(2), rl(1),
+                              rl(2), 0, -rl(0),
+                              -rl(1), rl(0), 0;
+        rightGraspMatrix.block<3, 3>(3, 0) << 0, -rr(2), rr(1),
+                               rr(2), 0, -rr(0),
+                               -rr(1), rr(0), 0;
+        Eigen::MatrixXf graspMatrix(6, nl + nr);
+        graspMatrix << leftGraspMatrix, rightGraspMatrix;
+
+        // constraint Jacobain and projection matrix
+        Eigen::MatrixXf jacobi(12, n);
+        jacobi.setZero(12, n);
+
+        jacobi.block < 6, 8 > (0, 0) = jacobiL;
+        jacobi.block < 6, 8 > (6, 8) = jacobiR;
+
+        Eigen::MatrixXf pinvGraspMatrix = leftIK->computePseudoInverseJacobianMatrix(graspMatrix, 1);
+        Eigen::MatrixXf jacobiC = (Eigen::MatrixXf::Identity(12, 12) - pinvGraspMatrix * graspMatrix) * jacobi;
+
+        Eigen::MatrixXf pinvJacobiC = leftIK->computePseudoInverseJacobianMatrix(jacobiC, 1);
+        Eigen::MatrixXf projection = Eigen::MatrixXf::Identity(12, 12) - pinvJacobiC * jacobiC;
+
+
+
+        // calculate inertia matrix
+        Eigen::MatrixXf leftInertialMatrix;
+        Eigen::MatrixXf rightInertialMatrix;
+        leftInertialMatrix.setZero(nl, nl);
+        rightInertialMatrix.setZero(nr, nr);
+
+        for (size_t i = 0; i < rnsLeftBody->getNodeNames().size(); ++i)
+        {
+            VirtualRobot::RobotNodePtr rnbody = rnsLeftBody->getNode(i);
+            VirtualRobot::RobotNodePtr rnjoint = leftRNS->getNode(i + 1);
+
+            Eigen::MatrixXf jacobipos_rn = 0.001 * leftIK->getJacobianMatrix(rnjoint, VirtualRobot::IKSolver::CartesianSelection::Position);
+            Eigen::MatrixXf jacobiori_rn = leftIK->getJacobianMatrix(rnjoint, VirtualRobot::IKSolver::CartesianSelection::Orientation);
+
+
+            float m = rnbody->getMass();
+            Eigen::Matrix3f InertiaMatrix = rnbody->getInertiaMatrix();
+            leftInertialMatrix += m * jacobipos_rn.transpose() * jacobipos_rn + jacobiori_rn.transpose() * InertiaMatrix * jacobiori_rn;
+        }
+
+        for (size_t i = 0; i < rnsRightBody->getNodeNames().size(); ++i)
+        {
+            VirtualRobot::RobotNodePtr rnbody = rnsRightBody->getNode(i);
+            VirtualRobot::RobotNodePtr rnjoint = rightRNS->getNode(i + 1);
+
+            Eigen::MatrixXf jacobipos_rn = 0.001 * rightIK->getJacobianMatrix(rnjoint, VirtualRobot::IKSolver::CartesianSelection::Position);
+            Eigen::MatrixXf jacobiori_rn = rightIK->getJacobianMatrix(rnjoint, VirtualRobot::IKSolver::CartesianSelection::Orientation);
+
+
+            float m = rnbody->getMass();
+            Eigen::Matrix3f InertiaMatrix = rnbody->getInertiaMatrix();
+
+            rightInertialMatrix += m * jacobipos_rn.transpose() * jacobipos_rn + jacobiori_rn.transpose() * InertiaMatrix * jacobiori_rn;
+        }
+        Eigen::MatrixXf M = Eigen::MatrixXf::Zero(n, n);
+        M.topLeftCorner(nl, nl) = leftInertialMatrix;
+        M.bottomRightCorner(nr, nr) = rightInertialMatrix;
+
+        Eigen::MatrixXf Mc = M + projection * M - M * projection;
+
+
+
+        // unconstrained space controller
+        Eigen::Vector6f leftJointControlWrench;
+        {
+            Eigen::Vector3f targetTCPLinearVelocity;
+            targetTCPLinearVelocity << 0.001 * leftTargetVel(0), 0.001 * leftTargetVel(1), 0.001 * leftTargetVel(2);
+
+            Eigen::Vector3f currentTCPLinearVelocity;
+            currentTCPLinearVelocity <<  currentLeftTwist(0),   currentLeftTwist(1),  currentLeftTwist(2);
+            Eigen::Vector3f currentTCPAngularVelocity;
+            currentTCPAngularVelocity << currentLeftTwist(3),   currentLeftTwist(4),  currentLeftTwist(5);
+            Eigen::Vector3f currentTCPPosition = leftCurrentPose.block<3, 1>(0, 3);
+            Eigen::Vector3f desiredPosition = leftTargetPose.block<3, 1>(0, 3);
+
+            Eigen::Vector3f tcpDesiredForce = 0.001 * kpos.cwiseProduct(desiredPosition - currentTCPPosition) + dpos.cwiseProduct(targetTCPLinearVelocity - currentTCPLinearVelocity);
+            Eigen::Matrix3f currentRotMat = leftCurrentPose.block<3, 3>(0, 0);
+            Eigen::Matrix3f diffMat = leftTargetPose.block<3, 3>(0, 0) * currentRotMat.inverse();
+            Eigen::Vector3f rpy = VirtualRobot::MathTools::eigen3f2rpy(diffMat);
+            Eigen::Vector3f tcpDesiredTorque = kori.cwiseProduct(rpy) - dori.cwiseProduct(currentTCPAngularVelocity);
+            leftJointControlWrench <<  tcpDesiredForce, tcpDesiredTorque;
+        }
+
+
+        Eigen::Vector6f rightJointControlWrench;
+        {
+            Eigen::Vector3f currentTCPLinearVelocity;
+            currentTCPLinearVelocity <<  currentRightTwist(0),  currentRightTwist(1), currentRightTwist(2);
+            Eigen::Vector3f currentTCPAngularVelocity;
+            currentTCPAngularVelocity << currentRightTwist(3),   currentRightTwist(4),  currentRightTwist(5);
+            Eigen::Vector3f currentTCPPosition = rightCurrentPose.block<3, 1>(0, 3);
+            Eigen::Vector3f desiredPosition = rightTargetPose.block<3, 1>(0, 3);
+
+            Eigen::Vector3f tcpDesiredForce = 0.001 * kpos.cwiseProduct(desiredPosition - currentTCPPosition) - dpos.cwiseProduct(currentTCPLinearVelocity);
+            Eigen::Matrix3f currentRotMat = rightCurrentPose.block<3, 3>(0, 0);
+            Eigen::Matrix3f diffMat = rightTargetPose.block<3, 3>(0, 0) * currentRotMat.inverse();
+            Eigen::Vector3f rpy = VirtualRobot::MathTools::eigen3f2rpy(diffMat);
+            Eigen::Vector3f tcpDesiredTorque = kori.cwiseProduct(rpy) - dori.cwiseProduct(currentTCPAngularVelocity);
+            rightJointControlWrench <<   tcpDesiredForce, tcpDesiredTorque;
+        }
+
+        Eigen::VectorXf leftNullspaceTorque = knull * (leftDesiredJointValues - leftqpos) - dnull * leftqvel;
+        Eigen::VectorXf rightNullspaceTorque = knull * (rightDesiredJointValues - rightqpos) - dnull * rightqvel;
+
+        float lambda = 2;
+        Eigen::MatrixXf jtpinvL = leftIK->computePseudoInverseJacobianMatrix(jacobiL.transpose(), lambda);
+        Eigen::VectorXf leftJointDesiredTorques = jacobiL.transpose() * leftJointControlWrench + (I - jacobiL.transpose() * jtpinvL) * leftNullspaceTorque;
+
+        Eigen::MatrixXf jtpinvR = leftIK->computePseudoInverseJacobianMatrix(jacobiR.transpose(), lambda);
+        Eigen::VectorXf rightJointDesiredTorques = jacobiR.transpose() * rightJointControlWrench + (I - jacobiR.transpose() * jtpinvR) * rightNullspaceTorque;
+
+        Eigen::VectorXf torqueNotC(16);
+        torqueNotC << leftJointDesiredTorques, rightJointDesiredTorques;
+
+        // constrained space control
+
+        Eigen::MatrixXf mu = (Eigen::MatrixXf::Identity(12, 12) - projection) * M * Mc.inverse();
+        Eigen::VectorXf forceC = Eigen::VectorXf::Zero(12);
+        Eigen::Vector3f leftForce = leftCurrentPose.block<3, 3>(0, 0) * leftForceTorque->force;
+        Eigen::Vector3f leftTorque = leftCurrentPose.block<3, 3>(0, 0) * leftForceTorque->torque;
+        Eigen::Vector3f rightForce = rightCurrentPose.block<3, 3>(0, 0) * rightForceTorque->force;
+        Eigen::Vector3f rightTorque = rightCurrentPose.block<3, 3>(0, 0) * rightForceTorque->torque;
+        for (int i = 0; i < 3; i++)
+        {
+            forceC(i) = forceC_des(i) + kpf(i) * (forceC_des(i) - leftForce(i)); // TODO: add PID controller
+            forceC(i + 3) = forceC_des(i + 3) + kpf(i + 3) * (forceC_des(i + 3) - leftTorque(i)); // TODO: add PID controller
+            forceC(i + 6) = forceC_des(i + 6) + kpf(i + 6) * (forceC_des(i + 6) - rightForce(i)); // TODO: add PID controller
+            forceC(i + 9) = forceC_des(i + 9) + kpf(i + 9) * (forceC_des(i + 9) - rightTorque(i)); // TODO: add PID controller
+        }
+        Eigen::VectorXf qacc;
+        qacc.resize(n);
+        for (size_t i = 0; i < leftAccelerationSensors.size(); ++i)
+        {
+            qacc(i) = 0.001 * leftAccelerationSensors[i]->acceleration;
+        }
+
+        for (size_t i = 0; i < rightAccelerationSensors.size(); ++i)
+        {
+            qacc(i + leftAccelerationSensors.size()) = 0.001 * rightAccelerationSensors[i]->acceleration;
+        }
+
+        Eigen::VectorXf torqueC = mu * (torqueNotC + (Eigen::MatrixXf::Identity(n, n) - projection) * qacc) - jacobiC.transpose() * forceC;
+
+        // all torques
+        Eigen::VectorXf torqueInput = projection * torqueNotC + torqueC;
+        leftJointDesiredTorques = torqueInput.head(nl);
+        rightJointDesiredTorques = torqueInput.block<8, 1>(8, 0);
+
+        // torque limit
+        for (size_t i = 0; i < leftTargets.size(); ++i)
+        {
+            float desiredTorque = leftJointDesiredTorques(i);
+
+            if (isnan(desiredTorque))
+            {
+                desiredTorque = 0;
+            }
+
+            desiredTorque = (desiredTorque >  torqueLimit) ? torqueLimit : desiredTorque;
+            desiredTorque = (desiredTorque < -torqueLimit) ? -torqueLimit : desiredTorque;
+
+            debugDataInfo.getWriteBuffer().desired_torques[leftJointNames[i]] = leftJointDesiredTorques(i);
+
+            leftTargets.at(i)->torque = desiredTorque;
+        }
+
+
+
+        for (size_t i = 0; i < rightTargets.size(); ++i)
+        {
+            float desiredTorque = rightJointDesiredTorques(i);
+
+            if (isnan(desiredTorque))
+            {
+                desiredTorque = 0;
+            }
+
+            desiredTorque = (desiredTorque >  torqueLimit) ? torqueLimit : desiredTorque;
+            desiredTorque = (desiredTorque < -torqueLimit) ? -torqueLimit : desiredTorque;
+
+            debugDataInfo.getWriteBuffer().desired_torques[rightJointNames[i]] = rightJointDesiredTorques(i);
+
+            rightTargets.at(i)->torque = desiredTorque;
+        }
+
+        //        debugDataInfo.getWriteBuffer().desiredForce_x = tcpDesiredForce(0);
+        //        debugDataInfo.getWriteBuffer().desiredForce_y = tcpDesiredForce(1);
+        //        debugDataInfo.getWriteBuffer().desiredForce_z = tcpDesiredForce(2);
+        //        debugDataInfo.getWriteBuffer().leftTcpDesiredTorque_x = tcpDesiredTorque(0);
+        //        debugDataInfo.getWriteBuffer().leftTcpDesiredTorque_y = tcpDesiredTorque(1);
+        //        debugDataInfo.getWriteBuffer().tcpDesiredTorque_z = tcpDesiredTorque(2);
+        //        debugDataInfo.getWriteBuffer().quatError = errorAngle;
+        //        debugDataInfo.getWriteBuffer().posiError = posiError;
+        debugDataInfo.getWriteBuffer().leftTargetPose_x = leftTargetPose(0, 3);
+        debugDataInfo.getWriteBuffer().leftTargetPose_y = leftTargetPose(1, 3);
+        debugDataInfo.getWriteBuffer().leftTargetPose_z = leftTargetPose(2, 3);
+        debugDataInfo.getWriteBuffer().leftCurrentPose_x = leftCurrentPose(0, 3);
+        debugDataInfo.getWriteBuffer().leftCurrentPose_y = leftCurrentPose(1, 3);
+        debugDataInfo.getWriteBuffer().leftCurrentPose_z = leftCurrentPose(2, 3);
+
+
+        debugDataInfo.getWriteBuffer().rightTargetPose_x = rightTargetPose(0, 3);
+        debugDataInfo.getWriteBuffer().rightTargetPose_y = rightTargetPose(1, 3);
+        debugDataInfo.getWriteBuffer().rightTargetPose_z = rightTargetPose(2, 3);
+
+        debugDataInfo.getWriteBuffer().rightCurrentPose_x = rightCurrentPose(0, 3);
+        debugDataInfo.getWriteBuffer().rightCurrentPose_y = rightCurrentPose(1, 3);
+        debugDataInfo.getWriteBuffer().rightCurrentPose_z = rightCurrentPose(2, 3);
+
+
+        debugDataInfo.commitWrite();
+
+
+
+        //        Eigen::VectorXf leftTargetVel = rtGetControlStruct().leftTargetVel;
+        //        float normLinearVelocity = leftTargetVel.block<3, 1>(0, 0).norm();
+        //        if (normLinearVelocity > cfg->maxLinearVel)
+        //        {
+        //            leftTargetVel.block<3, 1>(0, 0) = cfg->maxLinearVel * leftTargetVel.block<3, 1>(0, 0) / normLinearVelocity;
+        //        }
+        //        float normAngularVelocity = leftTargetVel.block<3, 1>(3, 0).norm();
+        //        if (normAngularVelocity > cfg->maxAngularVel)
+        //        {
+        //            leftTargetVel.block<3, 1>(3, 0) = cfg->maxAngularVel * leftTargetVel.block<3, 1>(3, 0) / normAngularVelocity;
+        //        }
+
+        //        Eigen::VectorXf leftNullSpaceJointVelocity = cfg->knull * (leftDesiredJointValues - leftqpos);
+        //        Eigen::MatrixXf jtpinvL = leftIK->computePseudoInverseJacobianMatrix(jacobiL, leftIK->getJacobiRegularization(VirtualRobot::IKSolver::CartesianSelection::All));
+        //        Eigen::VectorXf jnvL = jtpinvL * leftTargetVel + (I - jtpinvL * jacobiL) * leftNullSpaceJointVelocity;
+
+        //        for (size_t i = 0; i < leftTargets.size(); ++i)
+        //        {
+        //            leftTargets.at(i)->velocity = jnvL(i);
+        //        }
+
+        //        Eigen::VectorXf rightTargetVel = rtGetControlStruct().rightTargetVel;
+        //        normLinearVelocity = rightTargetVel.block<3, 1>(0, 0).norm();
+        //        if (normLinearVelocity > cfg->maxLinearVel)
+        //        {
+        //            rightTargetVel.block<3, 1>(0, 0) = cfg->maxLinearVel * rightTargetVel.block<3, 1>(0, 0) / normLinearVelocity;
+        //        }
+        //        normAngularVelocity = leftTargetVel.block<3, 1>(3, 0).norm();
+        //        if (normAngularVelocity > cfg->maxAngularVel)
+        //        {
+        //            rightTargetVel.block<3, 1>(3, 0) = cfg->maxAngularVel * rightTargetVel.block<3, 1>(3, 0) / normAngularVelocity;
+        //        }
+        //        Eigen::VectorXf rightNullSpaceJointVelocity = cfg->knull * (rightDesiredJointValues - rightqpos);
+        //        Eigen::MatrixXf jtpinvR = rightIK->computePseudoInverseJacobianMatrix(jacobiR, rightIK->getJacobiRegularization(VirtualRobot::IKSolver::CartesianSelection::All));
+        //        Eigen::VectorXf jnvR = jtpinvR * rightTargetVel + (I - jtpinvR * jacobiR) * rightNullSpaceJointVelocity;
+
+        //        for (size_t i = 0; i < rightTargets.size(); ++i)
+        //        {
+        //            rightTargets.at(i)->velocity = jnvR(i);
+        //        }
+    }
+
+    void NJointBimanualCCDMPController::learnDMPFromFiles(const std::string& name, const Ice::StringSeq& fileNames, const Ice::Current&)
+    {
+        if (name == "LeftLeader")
+        {
+            leftGroup.at(0)->learnDMPFromFiles(fileNames);
+        }
+        else if (name == "LeftFollower")
+        {
+            rightGroup.at(1)->learnDMPFromFiles(fileNames);
+        }
+        else if (name == "RightLeader")
+        {
+            rightGroup.at(0)->learnDMPFromFiles(fileNames);
+        }
+        else
+        {
+            leftGroup.at(1)->learnDMPFromFiles(fileNames);
+        }
+    }
+
+
+    void NJointBimanualCCDMPController::setViaPoints(Ice::Double u, const Ice::DoubleSeq& viapoint, const Ice::Current&)
+    {
+        LockGuardType guard(controllerMutex);
+        if (leaderName == "Left")
+        {
+            leftGroup.at(0)->setViaPose(u, viapoint);
+        }
+        else
+        {
+            rightGroup.at(0)->setViaPose(u, viapoint);
+        }
+    }
+
+    void NJointBimanualCCDMPController::setGoals(const Ice::DoubleSeq& goals, const Ice::Current& ice)
+    {
+        LockGuardType guard(controllerMutex);
+        if (leaderName == "Left")
+        {
+            leftGroup.at(0)->setGoalPoseVec(goals);
+        }
+        else
+        {
+            rightGroup.at(0)->setGoalPoseVec(goals);
+        }
+
+    }
+
+    void NJointBimanualCCDMPController::changeLeader(const Ice::Current&)
+    {
+        LockGuardType guard(controllerMutex);
+
+        if (leaderName == "Left")
+        {
+            leaderName = "Right";
+            rightGroup.at(0)->canVal = virtualtimer;
+            rightGroup.at(1)->canVal = virtualtimer;
+        }
+        else
+        {
+            leaderName = "Left";
+            leftGroup.at(0)->canVal = virtualtimer;
+            leftGroup.at(1)->canVal = virtualtimer;
+        }
+
+    }
+
+
+
+
+
+    void NJointBimanualCCDMPController::runDMP(const Ice::DoubleSeq& leftGoals, const Ice::DoubleSeq& rightGoals, const Ice::Current&)
+    {
+        virtualtimer = cfg->timeDuration;
+
+        Eigen::Matrix4f leftPose = tcpLeft->getPoseInRootFrame();
+        Eigen::Matrix4f rightPose = tcpRight->getPoseInRootFrame();
+
+        leftGroup.at(0)->prepareExecution(leftGroup.at(0)->eigen4f2vec(leftPose), leftGoals);
+        rightGroup.at(0)->prepareExecution(rightGroup.at(0)->eigen4f2vec(rightPose), rightGoals);
+
+
+        ARMARX_INFO << "leftgroup goal local pose: " << getLocalPose(leftGoals, rightGoals);
+
+        leftGroup.at(1)->prepareExecution(getLocalPose(leftPose, rightPose), getLocalPose(leftGoals, rightGoals));
+        rightGroup.at(1)->prepareExecution(getLocalPose(rightPose, leftPose), getLocalPose(rightGoals, leftGoals));
+
+        controllerTask->start();
+    }
+
+    Eigen::Matrix4f NJointBimanualCCDMPController::getLocalPose(const Eigen::Matrix4f& newCoordinate, const Eigen::Matrix4f& globalTargetPose)
+    {
+        Eigen::Matrix4f localPose;
+        localPose.block<3, 3>(0, 0) = globalTargetPose.block<3, 3>(0, 0) * newCoordinate.block<3, 3>(0, 0).inverse();
+        localPose.block<3, 1>(0, 3) = localPose.block<3, 3>(0, 0) * (globalTargetPose.block<3, 1>(0, 3) - newCoordinate.block<3, 1>(0, 3));
+
+        return localPose;
+    }
+
+
+    void NJointBimanualCCDMPController::onPublish(const SensorAndControl&, const DebugDrawerInterfacePrx&, const DebugObserverInterfacePrx& debugObs)
+    {
+
+        StringVariantBaseMap datafields;
+        auto values = debugDataInfo.getUpToDateReadBuffer().desired_torques;
+        for (auto& pair : values)
+        {
+            datafields[pair.first] = new Variant(pair.second);
+        }
+
+        datafields["leftTargetPose_x"] = new Variant(debugDataInfo.getUpToDateReadBuffer().leftTargetPose_x);
+        datafields["leftTargetPose_y"] = new Variant(debugDataInfo.getUpToDateReadBuffer().leftTargetPose_y);
+        datafields["leftTargetPose_z"] = new Variant(debugDataInfo.getUpToDateReadBuffer().leftTargetPose_z);
+        datafields["rightTargetPose_x"] = new Variant(debugDataInfo.getUpToDateReadBuffer().rightTargetPose_x);
+        datafields["rightTargetPose_y"] = new Variant(debugDataInfo.getUpToDateReadBuffer().rightTargetPose_y);
+        datafields["rightTargetPose_z"] = new Variant(debugDataInfo.getUpToDateReadBuffer().rightTargetPose_z);
+
+
+        datafields["leftCurrentPose_x"] = new Variant(debugDataInfo.getUpToDateReadBuffer().leftCurrentPose_x);
+        datafields["leftCurrentPose_y"] = new Variant(debugDataInfo.getUpToDateReadBuffer().leftCurrentPose_y);
+        datafields["leftCurrentPose_z"] = new Variant(debugDataInfo.getUpToDateReadBuffer().leftCurrentPose_z);
+        datafields["rightCurrentPose_x"] = new Variant(debugDataInfo.getUpToDateReadBuffer().rightCurrentPose_x);
+        datafields["rightCurrentPose_y"] = new Variant(debugDataInfo.getUpToDateReadBuffer().rightCurrentPose_y);
+        datafields["rightCurrentPose_z"] = new Variant(debugDataInfo.getUpToDateReadBuffer().rightCurrentPose_z);
+
+        //        StringVariantBaseMap datafields;
+        //        auto values = debugOutputData.getUpToDateReadBuffer().latestTargetVelocities;
+        //        for (auto& pair : values)
+        //        {
+        //            datafields[pair.first] = new Variant(pair.second);
+        //        }
+
+        //        auto dmpTargets = debugOutputData.getUpToDateReadBuffer().dmpTargets;
+        //        for (auto& pair : dmpTargets)
+        //        {
+        //            datafields[pair.first] = new Variant(pair.second);
+        //        }
+
+        //        auto currentPose = debugOutputData.getUpToDateReadBuffer().currentPose;
+        //        for (auto& pair : currentPose)
+        //        {
+        //            datafields[pair.first] = new Variant(pair.second);
+        //        }
+
+        //        datafields["leaderCanVal"] = new Variant(debugOutputData.getUpToDateReadBuffer().leaderCanVal);
+        //        datafields["leadermpcFactor"] = new Variant(debugOutputData.getUpToDateReadBuffer().leadermpcFactor);
+        //        datafields["leaderError"] = new Variant(debugOutputData.getUpToDateReadBuffer().leadererror);
+        //        datafields["leaderposError"] = new Variant(debugOutputData.getUpToDateReadBuffer().leaderposError);
+        //        datafields["leaderoriError"] = new Variant(debugOutputData.getUpToDateReadBuffer().leaderoriError);
+
+        //        datafields["followerCanVal"] = new Variant(debugOutputData.getUpToDateReadBuffer().followerCanVal);
+        //        datafields["followermpcFactor"] = new Variant(debugOutputData.getUpToDateReadBuffer().followermpcFactor);
+        //        datafields["followerError"] = new Variant(debugOutputData.getUpToDateReadBuffer().followererror);
+        //        datafields["followerposError"] = new Variant(debugOutputData.getUpToDateReadBuffer().followerposError);
+        //        datafields["followeroriError"] = new Variant(debugOutputData.getUpToDateReadBuffer().followeroriError);
+
+        debugObs->setDebugChannel("DMPController", datafields);
+    }
+
+    void NJointBimanualCCDMPController::onInitComponent()
+    {
+        ARMARX_INFO << "init ...";
+        controllerTask = new PeriodicTask<NJointBimanualCCDMPController>(this, &NJointBimanualCCDMPController::controllerRun, 0.3);
+    }
+
+    void NJointBimanualCCDMPController::onDisconnectComponent()
+    {
+        controllerTask->stop();
+        ARMARX_INFO << "stopped ...";
+    }
+
+
+
+}
diff --git a/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointBimanualCCDMPController.h b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointBimanualCCDMPController.h
new file mode 100644
index 0000000000000000000000000000000000000000..ee7f250502ec24d64950d9ab09884d1cc93d64d9
--- /dev/null
+++ b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointBimanualCCDMPController.h
@@ -0,0 +1,218 @@
+
+#pragma once
+
+#include <RobotAPI/components/units/RobotUnit/NJointControllers/NJointController.h>
+#include <VirtualRobot/Robot.h>
+#include <RobotAPI/components/units/RobotUnit/RobotUnit.h>
+#include <RobotAPI/components/units/RobotUnit/ControlTargets/ControlTarget1DoFActuator.h>
+#include <RobotAPI/components/units/RobotUnit/SensorValues/SensorValue1DoFActuator.h>
+#include <VirtualRobot/IK/DifferentialIK.h>
+#include <dmp/representation/dmp/umitsmp.h>
+#include <RobotAPI/interface/units/RobotUnit/NJointTaskSpaceDMPController.h>
+#include <RobotAPI/libraries/core/CartesianVelocityController.h>
+#include <RobotAPI/libraries/DMPController/TaskSpaceDMPController.h>
+
+#include <RobotAPI/components/units/RobotUnit/SensorValues/SensorValueForceTorque.h>
+
+
+using namespace DMP;
+namespace armarx
+{
+
+
+    TYPEDEF_PTRS_HANDLE(NJointBimanualCCDMPController);
+    TYPEDEF_PTRS_HANDLE(NJointBimanualCCDMPControllerControlData);
+
+    typedef std::pair<double, DVec > ViaPoint;
+    typedef std::vector<ViaPoint > ViaPointsSet;
+    class NJointBimanualCCDMPControllerControlData
+    {
+    public:
+        Eigen::VectorXf leftTargetVel;
+        Eigen::VectorXf rightTargetVel;
+
+        Eigen::Matrix4f leftTargetPose;
+        Eigen::Matrix4f rightTargetPose;
+    };
+
+    class NJointBimanualCCDMPController :
+        public NJointControllerWithTripleBuffer<NJointBimanualCCDMPControllerControlData>,
+        public NJointBimanualCCDMPControllerInterface
+    {
+    public:
+        using ConfigPtrT = NJointBimanualCCDMPControllerConfigPtr;
+        NJointBimanualCCDMPController(NJointControllerDescriptionProviderInterfacePtr prov, const NJointControllerConfigPtr& config, const VirtualRobot::RobotPtr&);
+
+        // NJointControllerInterface interface
+        std::string getClassName(const Ice::Current&) const;
+
+        // NJointController interface
+
+        void rtRun(const IceUtil::Time& sensorValuesTimestamp, const IceUtil::Time& timeSinceLastIteration);
+
+        // NJointBimanualCCDMPControllerInterface interface
+        void learnDMPFromFiles(const std::string&, const Ice::StringSeq&, const Ice::Current&);
+        bool isFinished(const Ice::Current&)
+        {
+            return false;
+        }
+
+        void runDMP(const Ice::DoubleSeq& leftGoals, const Ice::DoubleSeq& rightGoals, const Ice::Current&);
+        void setViaPoints(Ice::Double u, const Ice::DoubleSeq& viapoint, const Ice::Current&);
+        void setGoals(const Ice::DoubleSeq& goals, const Ice::Current&);
+
+        void changeLeader(const Ice::Current&);
+
+        double getVirtualTime(const Ice::Current&)
+        {
+            return virtualtimer;
+        }
+
+        std::string getLeaderName(const Ice::Current&)
+        {
+            return leaderName;
+        }
+
+    protected:
+
+        virtual void onPublish(const SensorAndControl&, const DebugDrawerInterfacePrx&, const DebugObserverInterfacePrx&);
+
+        void onInitComponent();
+        void onDisconnectComponent();
+        void controllerRun();
+    private:
+
+        Eigen::VectorXf getControlWrench(const Eigen::VectorXf& twist, const Eigen::Matrix4f& currentPose, const Eigen::Matrix4f& targetPose);
+
+        Eigen::Matrix4f getLocalPose(const Eigen::Matrix4f& newCoordinate, const Eigen::Matrix4f& globalTargetPose);
+        Eigen::Matrix4f getLocalPose(const std::vector<double>& newCoordinateVec, const std::vector<double>& globalTargetPoseVec)
+        {
+            Eigen::Matrix4f newCoordinate = VirtualRobot::MathTools::quat2eigen4f(newCoordinateVec.at(4), newCoordinateVec.at(5), newCoordinateVec.at(6), newCoordinateVec.at(3));
+            newCoordinate(0, 3) = newCoordinateVec.at(0);
+            newCoordinate(1, 3) = newCoordinateVec.at(1);
+            newCoordinate(2, 3) = newCoordinateVec.at(2);
+
+            Eigen::Matrix4f globalTargetPose = VirtualRobot::MathTools::quat2eigen4f(globalTargetPoseVec.at(4), globalTargetPoseVec.at(5), globalTargetPoseVec.at(6), globalTargetPoseVec.at(3));
+            globalTargetPose(0, 3) = globalTargetPoseVec.at(0);
+            globalTargetPose(1, 3) = globalTargetPoseVec.at(1);
+            globalTargetPose(2, 3) = globalTargetPoseVec.at(2);
+
+            return getLocalPose(newCoordinate, globalTargetPose);
+
+        }
+
+        struct DebugBufferData
+        {
+            StringFloatDictionary desired_torques;
+            float leftTargetPose_x;
+            float leftTargetPose_y;
+            float leftTargetPose_z;
+            float rightTargetPose_x;
+            float rightTargetPose_y;
+            float rightTargetPose_z;
+
+            float leftCurrentPose_x;
+            float leftCurrentPose_y;
+            float leftCurrentPose_z;
+            float rightCurrentPose_x;
+            float rightCurrentPose_y;
+            float rightCurrentPose_z;
+
+            //            StringFloatDictionary latestTargetVelocities;
+            //            StringFloatDictionary dmpTargets;
+            //            StringFloatDictionary currentPose;
+
+            //            double leadermpcFactor;
+            //            double leadererror;
+            //            double leaderposError;
+            //            double leaderoriError;
+            //            double leaderCanVal;
+
+            //            double followermpcFactor;
+            //            double followererror;
+            //            double followerposError;
+            //            double followeroriError;
+            //            double followerCanVal;
+
+
+        };
+
+        TripleBuffer<DebugBufferData> debugDataInfo;
+
+        struct NJointBimanualCCDMPControllerSensorData
+        {
+            double currentTime;
+            double deltaT;
+            Eigen::Matrix4f currentLeftPose;
+            Eigen::Matrix4f currentRightPose;
+            Eigen::VectorXf currentLeftTwist;
+            Eigen::VectorXf currentRightTwist;
+        };
+        TripleBuffer<NJointBimanualCCDMPControllerSensorData> controllerSensorData;
+
+
+        std::vector<ControlTarget1DoFActuatorTorque*> leftTargets;
+        std::vector<const SensorValue1DoFActuatorAcceleration*> leftAccelerationSensors;
+        std::vector<const SensorValue1DoFActuatorVelocity*> leftVelocitySensors;
+        std::vector<const SensorValue1DoFActuatorPosition*> leftPositionSensors;
+
+        std::vector<ControlTarget1DoFActuatorTorque*> rightTargets;
+        std::vector<const SensorValue1DoFActuatorAcceleration*> rightAccelerationSensors;
+        std::vector<const SensorValue1DoFActuatorVelocity*> rightVelocitySensors;
+        std::vector<const SensorValue1DoFActuatorPosition*> rightPositionSensors;
+
+        const SensorValueForceTorque* rightForceTorque;
+        const SensorValueForceTorque* leftForceTorque;
+
+        NJointBimanualCCDMPControllerConfigPtr cfg;
+        VirtualRobot::DifferentialIKPtr leftIK;
+        VirtualRobot::DifferentialIKPtr rightIK;
+
+        std::vector<TaskSpaceDMPControllerPtr > leftGroup;
+        std::vector<TaskSpaceDMPControllerPtr > rightGroup;
+
+        std::string leaderName;
+
+        VirtualRobot::RobotNodePtr tcpLeft;
+        VirtualRobot::RobotNodePtr tcpRight;
+
+        double virtualtimer;
+
+        mutable MutexType controllerMutex;
+        PeriodicTask<NJointBimanualCCDMPController>::pointer_type controllerTask;
+
+        Eigen::VectorXf leftDesiredJointValues;
+        Eigen::VectorXf rightDesiredJointValues;
+
+        float KoriFollower;
+        float KposFollower;
+        float DposFollower;
+        float DoriFollower;
+
+        Eigen::VectorXf forceC_des;
+        float boxWidth;
+
+        Eigen::Vector3f kpos;
+        Eigen::Vector3f kori;
+        Eigen::Vector3f dpos;
+        Eigen::Vector3f dori;
+        Eigen::Vector6f kpf;
+        Eigen::Vector6f kif;
+
+        float knull;
+        float dnull;
+
+        std::vector<std::string> leftJointNames;
+        std::vector<std::string> rightJointNames;
+
+        float torqueLimit;
+        VirtualRobot::RobotNodeSetPtr leftRNS;
+        VirtualRobot::RobotNodeSetPtr rightRNS;
+        VirtualRobot::RobotNodeSetPtr rnsLeftBody;
+        VirtualRobot::RobotNodeSetPtr rnsRightBody;
+
+        // NJointBimanualCCDMPControllerInterface interface
+    };
+
+} // namespace armarx
+
diff --git a/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointCCDMPController.cpp b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointCCDMPController.cpp
index 46cda82c25f0d6d0b4db74b101c05a4ab5d44562..ee30c07a9ce7da07abdcb52adc9d4b20d4c8df06 100644
--- a/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointCCDMPController.cpp
+++ b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointCCDMPController.cpp
@@ -17,7 +17,7 @@ namespace armarx
         for (size_t i = 0; i < rns->getSize(); ++i)
         {
             std::string jointName = rns->getNode(i)->getName();
-            ControlTargetBase* ct = useControlTarget(jointName, ControlModes::Velocity1DoF);
+            ControlTargetBase* ct = useControlTarget(jointName, ControlModes::VelocityTorque);
             const SensorValueBase* sv = useSensorValue(jointName);
             targets.push_back(ct->asA<ControlTarget1DoFActuatorVelocity>());
 
@@ -45,6 +45,7 @@ namespace armarx
         torquePIDs.resize(tcpController->rns->getSize(), pidController());
 
 
+        ik.reset(new VirtualRobot::DifferentialIK(rns, rns->getRobot()->getRootNode(), VirtualRobot::JacobiProvider::eSVDDamped));
 
         // set DMP
         isDisturbance = false;
@@ -55,7 +56,7 @@ namespace armarx
         dmpTypes = cfg->dmpTypes;
         for (size_t i = 0; i < dmpPtrList.size(); ++i)
         {
-            dmpPtrList[i].reset(new UMIDMP(cfg->kernelSize, cfg->DMPKd, cfg->baseMode, cfg->tau));
+            dmpPtrList[i].reset(new UMITSMP(cfg->kernelSize, 2, cfg->tau));
             canVals[i] = timeDurations[i];
         }
         finished = false;
@@ -72,12 +73,14 @@ namespace armarx
 
         // initialize tcp position and orientation
         Eigen::Matrix4f pose = tcp->getPoseInRootFrame();
-        oldPose = pose;
         tcpPosition(0) = pose(0, 3);
         tcpPosition(1) = pose(1, 3);
         tcpPosition(2) = pose(2, 3);
-        tcpOrientation = VirtualRobot::MathTools::eigen4f2rpy(pose);
-
+        VirtualRobot::MathTools::Quaternion tcpQ = VirtualRobot::MathTools::eigen4f2quat(pose);
+        tcpOrientation.w() = tcpQ.w;
+        tcpOrientation.x() = tcpQ.x;
+        tcpOrientation.y() = tcpQ.y;
+        tcpOrientation.z() = tcpQ.z;
 
         NJointCCDMPControllerSensorData initSensorData;
         initSensorData.deltaT = 0;
@@ -88,15 +91,13 @@ namespace armarx
 
         currentStates.resize(cfg->dmpNum);
         targetSubStates.resize(cfg->dmpNum);
-        targetState.resize(6);
+        targetState.resize(7);
 
         targetVels.resize(6);
+        targetVels.setZero();
         NJointCCDMPControllerControlData initData;
         initData.targetTSVel.resize(6);
-        for (size_t i = 0; i < 6; ++i)
-        {
-            initData.targetTSVel[i] = 0;
-        }
+        initData.targetTSVel.setZero();
         initData.nullspaceJointVelocities.resize(tcpController->rns->getSize(), 0);
         initData.torqueKp.resize(tcpController->rns->getSize(), 0);
         initData.torqueKd.resize(tcpController->rns->getSize(), 0);
@@ -125,21 +126,32 @@ namespace armarx
         Eigen::Matrix4f currentPose = controllerSensorData.getReadBuffer().currentPose;
         Eigen::Vector3f currentPosition;
         currentPosition << currentPose(0, 3), currentPose(1, 3), currentPose(2, 3);
-        Eigen::Vector3f currentRPY = VirtualRobot::MathTools::eigen4f2rpy(currentPose);
-
         double posError = 0;
-        double oriError = 0;
         for (size_t i = 0; i < 3; ++i)
         {
             posError += pow(currentPosition(i) - targetState[i], 2);
         }
-        for (size_t i = 0; i < 3; ++i)
+        posError = sqrt(posError);
+
+
+        VirtualRobot::MathTools::Quaternion cQuat = VirtualRobot::MathTools::eigen4f2quat(currentPose);
+        Eigen::Quaterniond currentQ;
+        Eigen::Quaterniond targetQ;
+        currentQ.w() = cQuat.w;
+        currentQ.x() = cQuat.x;
+        currentQ.y() = cQuat.y;
+        currentQ.z() = cQuat.z;
+        targetQ.w() = targetState[3];
+        targetQ.x() = targetState[4];
+        targetQ.y() = targetState[5];
+        targetQ.z() = targetState[6];
+
+        double oriError = targetQ.angularDistance(currentQ);
+        if (oriError > M_PI)
         {
-            oriError += pow(currentRPY(i) - targetState[i + 3], 2);
+            oriError = 2 * M_PI - oriError;
         }
 
-        posError = sqrt(posError);
-        oriError = sqrt(oriError);
         double error = posError + posToOriRatio * oriError;
 
         double phaseDist;
@@ -168,25 +180,28 @@ namespace armarx
 
         // run DMP one after another
         Eigen::Matrix4f targetPose = Eigen::Matrix4f::Identity();
-        //bool finished = true;
+
+        Eigen::VectorXf dmpVels;
+        dmpVels.resize(6);
+        dmpVels.setZero();
         for (size_t i = 0; i < static_cast<size_t>(cfg->dmpNum); ++i)
         {
             double timeDuration = timeDurations[i];
             std::string dmpType = dmpTypes[i];
 
-            //double amplitude = 1.0;
+            double amplitude = 1.0;
             if (dmpType == "Periodic")
             {
                 if (canVals[i] <= 1e-8)
                 {
                     canVals[i] = timeDuration;
                 }
-                //amplitude = amplitudes[i];
+                amplitude = amplitudes[i];
             }
 
             if (canVals[i] > 1e-8)
             {
-                DMP::UMIDMPPtr dmpPtr = dmpPtrList[i];
+                DMP::UMITSMPPtr dmpPtr = dmpPtrList[i];
                 double dmpDeltaT = deltaT / timeDuration;
                 double tau = dmpPtr->getTemporalFactor();
                 canVals[i] -= 1 / tau * deltaT * 1 / (1 + phaseStop) ;
@@ -196,70 +211,101 @@ namespace armarx
                                    (currentStates[i], canVals[i] / timeDurations[i], dmpDeltaT, targetSubStates[i]);
 
 
-                //finished = false;
+
+                for (size_t j = 0; j < 3; ++j)
+                {
+                    dmpVels(j) += currentStates[i][j].vel / timeDurations[i];
+                }
+
+                Eigen::Quaterniond quatVel0;
+                quatVel0.w() = currentStates[i][3].vel;
+                quatVel0.x() = currentStates[i][4].vel;
+                quatVel0.y() = currentStates[i][5].vel;
+                quatVel0.z() = currentStates[i][6].vel;
+                Eigen::Quaterniond dmpQ;
+                dmpQ.w() = currentStates[i][3].pos;
+                dmpQ.x() = currentStates[i][4].pos;
+                dmpQ.y() = currentStates[i][5].pos;
+                dmpQ.z() = currentStates[i][6].pos;
+                Eigen::Quaterniond angularVel0 = 2 * quatVel0 * dmpQ.inverse();
+
+
+                Eigen::Vector3f angularVelVec;
+                angularVelVec << angularVel0.x() / timeDurations[i],
+                              angularVel0.y() / timeDurations[i],
+                              angularVel0.z() / timeDurations[i];
+
+                angularVelVec = targetPose.block<3, 3>(0, 0) * angularVelVec;
+
+                ARMARX_INFO << "i: " << i << " angularVelVec: " << angularVelVec;
+                dmpVels(3) += angularVelVec(0);
+                dmpVels(4) += angularVelVec(1);
+                dmpVels(5) += angularVelVec(2);
+
+                finished = false;
 
             }
 
 
-            Eigen::Matrix4f targetSubMat = VirtualRobot::MathTools::rpy2eigen4f(targetSubStates[i][3], targetSubStates[i][4], targetSubStates[i][5]);
+
+            Eigen::Matrix4f targetSubMat = VirtualRobot::MathTools::quat2eigen4f(targetSubStates[i][4], targetSubStates[i][5], targetSubStates[i][6], targetSubStates[i][3]);
             targetSubMat(0, 3) = targetSubStates[i][0];
             targetSubMat(1, 3) = targetSubStates[i][1];
             targetSubMat(2, 3) = targetSubStates[i][2];
 
-            ARMARX_INFO << "targetSubMat: " << targetSubMat;
-
             targetPose = targetPose * targetSubMat;
 
         }
 
-        ARMARX_INFO << "targetPose: " << targetPose;
-
-        Eigen::Vector3f targetRPY = VirtualRobot::MathTools::eigen4f2rpy(targetPose);
-        targetState[0] = targetPose(0, 3);
-        targetState[1] = targetPose(1, 3);
-        targetState[2] = targetPose(2, 3);
-        targetState[3] = targetRPY(0);
-        targetState[4] = targetRPY(1);
-        targetState[5] = targetRPY(2);
-
-        Eigen::Vector3f oldRPY = VirtualRobot::MathTools::eigen4f2rpy(oldPose);
-
-
+        //        ARMARX_INFO << "targetPose: " << targetPose;
         for (size_t i = 0; i < 3; i++)
         {
-            double vel0 = (targetState[i] - oldPose(i, 3)) / deltaT;
+            double vel0 = dmpVels(i);
             double vel1 = phaseKpPos * (targetState[i] - currentPose(i, 3));
-            targetVels[i] = mpcFactor * vel0 + (1 - mpcFactor) * vel1;
+            targetVels(i) = mpcFactor * vel0 + (1 - mpcFactor) * vel1;
         }
 
-        for (size_t i = 0; i < 3; i++)
-        {
-            double vel0 = (targetState[i + 3] - oldRPY(i)) / deltaT;
-            double vel1 = phaseKpOri * (targetState[i + 3] - currentRPY(i));
-            targetVels[i + 3] = mpcFactor * vel0 + (1 - mpcFactor) * vel1;
-        }
 
-        oldPose = targetPose;
+        Eigen::Quaterniond diffQ = targetQ * currentQ.inverse();
+        Eigen::Quaterniond quatVel1 = phaseKpOri * diffQ;
+        Eigen::Quaterniond angularVel1 = 2 * quatVel1 * currentQ.inverse();
+        targetVels(3) = mpcFactor * dmpVels(3) + (1 - mpcFactor) * angularVel1.x();
+        targetVels(4) = mpcFactor * dmpVels(4) + (1 - mpcFactor) * angularVel1.y();
+        targetVels(5) = mpcFactor * dmpVels(5) + (1 - mpcFactor) * angularVel1.z();
 
-        debugOutputData.getWriteBuffer().latestTargetVelocities["x_vel"] = targetVels[0];
-        debugOutputData.getWriteBuffer().latestTargetVelocities["y_vel"] = targetVels[1];
-        debugOutputData.getWriteBuffer().latestTargetVelocities["z_vel"] = targetVels[2];
-        debugOutputData.getWriteBuffer().latestTargetVelocities["roll_vel"] = targetVels[3];
-        debugOutputData.getWriteBuffer().latestTargetVelocities["pitch_vel"] = targetVels[4];
-        debugOutputData.getWriteBuffer().latestTargetVelocities["yaw_vel"] = targetVels[5];
+
+
+        VirtualRobot::MathTools::Quaternion tQuat = VirtualRobot::MathTools::eigen4f2quat(targetPose);
+        targetState[0] = targetPose(0, 3);
+        targetState[1] = targetPose(1, 3);
+        targetState[2] = targetPose(2, 3);
+        targetState[3] = tQuat.w;
+        targetState[4] = tQuat.x;
+        targetState[5] = tQuat.y;
+        targetState[6] = tQuat.z;
+
+
+        debugOutputData.getWriteBuffer().latestTargetVelocities["x_vel"] = targetVels(0);
+        debugOutputData.getWriteBuffer().latestTargetVelocities["y_vel"] = targetVels(1);
+        debugOutputData.getWriteBuffer().latestTargetVelocities["z_vel"] = targetVels(2);
+        debugOutputData.getWriteBuffer().latestTargetVelocities["roll_vel"] = targetVels(3);
+        debugOutputData.getWriteBuffer().latestTargetVelocities["pitch_vel"] = targetVels(4);
+        debugOutputData.getWriteBuffer().latestTargetVelocities["yaw_vel"] = targetVels(5);
         debugOutputData.getWriteBuffer().dmpTargets["dmp_x"] = targetState[0];
         debugOutputData.getWriteBuffer().dmpTargets["dmp_y"] = targetState[1];
         debugOutputData.getWriteBuffer().dmpTargets["dmp_z"] = targetState[2];
-        debugOutputData.getWriteBuffer().dmpTargets["dmp_roll"] = targetState[3];
-        debugOutputData.getWriteBuffer().dmpTargets["dmp_pitch"] = targetState[4];
-        debugOutputData.getWriteBuffer().dmpTargets["dmp_yaw"] = targetState[5];
+        debugOutputData.getWriteBuffer().dmpTargets["dmp_qw"] = targetState[3];
+        debugOutputData.getWriteBuffer().dmpTargets["dmp_qx"] = targetState[4];
+        debugOutputData.getWriteBuffer().dmpTargets["dmp_qy"] = targetState[5];
+        debugOutputData.getWriteBuffer().dmpTargets["dmp_qz"] = targetState[6];
 
         debugOutputData.getWriteBuffer().realTCP["real_x"] = currentPosition[0];
         debugOutputData.getWriteBuffer().realTCP["real_y"] = currentPosition[1];
         debugOutputData.getWriteBuffer().realTCP["real_z"] = currentPosition[2];
-        debugOutputData.getWriteBuffer().realTCP["real_roll"] = currentRPY[0];
-        debugOutputData.getWriteBuffer().realTCP["real_pitch"] = currentRPY[1];
-        debugOutputData.getWriteBuffer().realTCP["real_yaw"] = currentRPY[2];
+        debugOutputData.getWriteBuffer().realTCP["real_qw"] = cQuat.w;
+        debugOutputData.getWriteBuffer().realTCP["real_qx"] = cQuat.x;
+        debugOutputData.getWriteBuffer().realTCP["real_qy"] = cQuat.y;
+        debugOutputData.getWriteBuffer().realTCP["real_qz"] = cQuat.z;
 
         debugOutputData.getWriteBuffer().mpcFactor = mpcFactor;
         debugOutputData.getWriteBuffer().error = error;
@@ -285,68 +331,19 @@ namespace armarx
         controllerSensorData.getWriteBuffer().currentPose = tcp->getPoseInRootFrame();
         controllerSensorData.getWriteBuffer().deltaT = deltaT;
         controllerSensorData.getWriteBuffer().currentTime += deltaT;
-
         controllerSensorData.commitWrite();
         // cartesian vel controller
-        Eigen::VectorXf x;
-        auto mode = rtGetControlStruct().mode;
 
-        if (mode == VirtualRobot::IKSolver::All)
-        {
-            x.resize(6);
-            for (size_t i = 0; i < 6; i++)
-            {
-                x(i) = rtGetControlStruct().targetTSVel[i];
-            }
-        }
-        else if (mode == VirtualRobot::IKSolver::Position)
-        {
-            x.resize(3);
-            for (size_t i = 0; i < 3; i++)
-            {
-                x(i) = rtGetControlStruct().targetTSVel[i];
-            }
+        Eigen::MatrixXf jacobi = ik->getJacobianMatrix(tcp, VirtualRobot::IKSolver::CartesianSelection::All);
 
-        }
-        else if (mode == VirtualRobot::IKSolver::Orientation)
-        {
-            x.resize(3);
-            for (size_t i = 0; i < 3; i++)
-            {
-                x(i) = rtGetControlStruct().targetTSVel[i + 3];
-            }
-        }
-        else
-        {
-            // No mode has been set
-            return;
-        }
 
-        Eigen::VectorXf jnv = Eigen::VectorXf::Zero(tcpController->rns->getSize());
-        float jointLimitAvoidanceKp = rtGetControlStruct().avoidJointLimitsKp;
-        if (jointLimitAvoidanceKp > 0)
-        {
-            jnv += jointLimitAvoidanceKp * tcpController->calculateJointLimitAvoidance();
-        }
-        for (size_t i = 0; i < tcpController->rns->getSize(); i++)
-        {
-            jnv(i) += rtGetControlStruct().nullspaceJointVelocities.at(i);
-            if (torqueSensors.at(i) && gravityTorqueSensors.at(i) && rtGetControlStruct().torqueKp.at(i) != 0)
-            {
-                torquePIDs.at(i).Kp = rtGetControlStruct().torqueKp.at(i);
-                torquePIDs.at(i).Kd = rtGetControlStruct().torqueKd.at(i);
-                jnv(i) += torquePIDs.at(i).update(deltaT, torqueSensors.at(i)->torque - gravityTorqueSensors.at(i)->gravityTorque);
-            }
-            else
-            {
-                torquePIDs.at(i).lastError = 0;
-            }
-        }
+        Eigen::MatrixXf jtpinv = ik->computePseudoInverseJacobianMatrix(jacobi, ik->getJacobiRegularization(VirtualRobot::IKSolver::CartesianSelection::All));
+
+        Eigen::VectorXf jnv = jtpinv * rtGetControlStruct().targetTSVel;
 
-        Eigen::VectorXf jointTargetVelocities = tcpController->calculate(x, jnv, mode);
         for (size_t i = 0; i < targets.size(); ++i)
         {
-            targets.at(i)->velocity = jointTargetVelocities(i);
+            targets.at(i)->velocity = jnv(i);
         }
     }
 
@@ -391,7 +388,6 @@ namespace armarx
         }
 
         dmpPtrList[dmpId]->learnFromTrajectories(trajs);
-        dmpPtrList[dmpId]->setOneStepMPC(true);
         dmpPtrList[dmpId]->styleParas = dmpPtrList[dmpId]->getStyleParasWithRatio(ratios);
 
 
@@ -405,28 +401,38 @@ namespace armarx
                 currentPos.vel = 0;
                 currentState.push_back(currentPos);
             }
-            for (size_t i = 0; i < 3; i++)
-            {
-                DMP::DMPState currentPos;
-                currentPos.pos = tcpOrientation(i);
-                currentPos.vel = 0;
-                currentState.push_back(currentPos);
-            }
+
+            DMP::DMPState currentPos;
+            currentPos.pos = tcpOrientation.w();
+            currentPos.vel = 0;
+            currentState.push_back(currentPos);
+
+            currentPos.pos = tcpOrientation.x();
+            currentPos.vel = 0;
+            currentState.push_back(currentPos);
+
+            currentPos.pos = tcpOrientation.y();
+            currentPos.vel = 0;
+            currentState.push_back(currentPos);
+
+            currentPos.pos = tcpOrientation.z();
+            currentPos.vel = 0;
+            currentState.push_back(currentPos);
+
         }
         else
         {
             currentState = starts;
-
-
         }
         for (size_t i = 0; i < 3; i++)
         {
             targetState[i] =  tcpPosition(i);
         }
-        for (size_t i = 0; i < 3; i++)
-        {
-            targetState[i + 3] = tcpOrientation(i);
-        }
+
+        targetState[3] = tcpOrientation.w();
+        targetState[4] = tcpOrientation.x();
+        targetState[5] = tcpOrientation.y();
+        targetState[6] = tcpOrientation.z();
 
         currentStates[dmpId] = currentState;
 
@@ -439,10 +445,9 @@ namespace armarx
 
     void NJointCCDMPController::setViaPoints(int dmpId, Ice::Double u, const Ice::DoubleSeq& viapoint, const Ice::Current&)
     {
-        ViaPoint viaPoint(u, viapoint);
 
         LockGuardType guard(controllerMutex);
-        dmpPtrList[dmpId]->setViaPoint(viaPoint);
+        dmpPtrList[dmpId]->setViaPoint(u, viapoint);
     }
 
     void NJointCCDMPController::setGoals(int dmpId, const Ice::DoubleSeq& goals, const Ice::Current& ice)
diff --git a/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointCCDMPController.h b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointCCDMPController.h
index e3917f63cf874b8b1b08f6922dd66f08f4da6821..215a5e62b0965ecc1acd7de35bfaabc4056b6c4c 100644
--- a/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointCCDMPController.h
+++ b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointCCDMPController.h
@@ -7,9 +7,11 @@
 #include <RobotAPI/components/units/RobotUnit/ControlTargets/ControlTarget1DoFActuator.h>
 #include <RobotAPI/components/units/RobotUnit/SensorValues/SensorValue1DoFActuator.h>
 #include <VirtualRobot/IK/DifferentialIK.h>
-#include <dmp/representation/dmp/umidmp.h>
+#include <dmp/representation/dmp/umitsmp.h>
 #include <RobotAPI/interface/units/RobotUnit/NJointTaskSpaceDMPController.h>
 #include <RobotAPI/libraries/core/CartesianVelocityController.h>
+#include <RobotAPI/libraries/DMPController/TaskSpaceDMPController.h>
+
 
 
 using namespace DMP;
@@ -25,7 +27,7 @@ namespace armarx
     class NJointCCDMPControllerControlData
     {
     public:
-        std::vector<float> targetTSVel;
+        Eigen::VectorXf targetTSVel;
         // cartesian velocity control data
         std::vector<float> nullspaceJointVelocities;
         float avoidJointLimitsKp = 0;
@@ -124,7 +126,7 @@ namespace armarx
         std::string nodeSetName;
 
         // dmp parameters
-        std::vector<UMIDMPPtr > dmpPtrList;
+        std::vector<UMITSMPPtr > dmpPtrList;
         std::vector<double> canVals;
         std::vector<double> timeDurations;
         std::vector<std::string > dmpTypes;
@@ -149,15 +151,21 @@ namespace armarx
 
         double posToOriRatio;
 
-        std::vector<float> targetVels;
+        Eigen::VectorXf targetVels;
 
         std::vector<int> learnedDMP;
+
+
+
+
+
         NJointCCDMPControllerConfigPtr cfg;
         VirtualRobot::RobotNodePtr tcp;
         Eigen::Vector3f tcpPosition;
-        Eigen::Vector3f tcpOrientation;
+        Eigen::Quaterniond tcpOrientation;
 
         Eigen::Matrix4f oldPose;
+        VirtualRobot::DifferentialIKPtr ik;
 
         DMP::DVec targetState;
         mutable MutexType controllerMutex;
diff --git a/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointJSDMPController.cpp b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointJSDMPController.cpp
index 3bd5872a9f85027aa46b7b042a61f5d4d732fdb5..fd33f782b3f3e90d99d10c639a8237d93b485928 100644
--- a/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointJSDMPController.cpp
+++ b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointJSDMPController.cpp
@@ -19,7 +19,7 @@ namespace armarx
 
         for (std::string jointName : cfg->jointNames)
         {
-            ControlTargetBase* ct = useControlTarget(jointName, ControlModes::Velocity1DoF);
+            ControlTargetBase* ct = useControlTarget(jointName, ControlModes::VelocityTorque);
             const SensorValueBase* sv = useSensorValue(jointName);
             targets.insert(std::make_pair(jointName, ct->asA<ControlTarget1DoFActuatorVelocity>()));
             positionSensors.insert(std::make_pair(jointName, sv->asA<SensorValue1DoFActuatorPosition>()));
@@ -53,6 +53,7 @@ namespace armarx
 
 
         NJointJSDMPControllerSensorData initSensorData;
+        initSensorData.currentTime = 0;
         initSensorData.deltaT = 0;
         initSensorData.currentState.resize(cfg->jointNames.size());
         controllerSensorData.reinitAllBuffers(initSensorData);
@@ -157,6 +158,8 @@ namespace armarx
             controllerSensorData.getWriteBuffer().currentState[i] = currentPos;
         }
         controllerSensorData.getWriteBuffer().deltaT = timeSinceLastIteration.toSecondsDouble();
+        controllerSensorData.getWriteBuffer().currentTime += controllerSensorData.getWriteBuffer().deltaT;
+
         controllerSensorData.commitWrite();
 
         std::vector<double> targetJointVels = rtGetControlStruct().targetJointVels;
diff --git a/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointJSDMPController.h b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointJSDMPController.h
index 3b904713a90d8190b0691b2ce5d0250a5262e6ed..df54abad00d0885d671e3c2296d9d6b40ac5db6a 100644
--- a/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointJSDMPController.h
+++ b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointJSDMPController.h
@@ -76,6 +76,7 @@ namespace armarx
 
         struct NJointJSDMPControllerSensorData
         {
+            double currentTime;
             double deltaT;
             DMP::Vec<DMP::DMPState> currentState;
         };
diff --git a/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointTSDMPController.cpp b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointTSDMPController.cpp
index 2f95ef4b734ac289e4c84b6f11c4b27f426170b9..1a62a87186637a75fb9269e2b159aaf3f6b681c8 100644
--- a/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointTSDMPController.cpp
+++ b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointTSDMPController.cpp
@@ -20,7 +20,9 @@ namespace armarx
             targets.push_back(ct->asA<ControlTarget1DoFActuatorVelocity>());
 
             const SensorValue1DoFActuatorTorque* torqueSensor = sv->asA<SensorValue1DoFActuatorTorque>();
+            const SensorValue1DoFActuatorVelocity* velocitySensor = sv->asA<SensorValue1DoFActuatorVelocity>();
             const SensorValue1DoFGravityTorque* gravityTorqueSensor = sv->asA<SensorValue1DoFGravityTorque>();
+            const SensorValue1DoFActuatorPosition* positionSensor = sv->asA<SensorValue1DoFActuatorPosition>();
             if (!torqueSensor)
             {
                 ARMARX_WARNING << "No Torque sensor available for " << jointName;
@@ -32,6 +34,8 @@ namespace armarx
 
             torqueSensors.push_back(torqueSensor);
             gravityTorqueSensors.push_back(gravityTorqueSensor);
+            velocitySensors.push_back(velocitySensor);
+            positionSensors.push_back(positionSensor);
         };
 
         tcp = (cfg->tcpName.empty()) ? rns->getTCP() : rtGetRobot()->getRobotNode(cfg->tcpName);
@@ -42,42 +46,45 @@ namespace armarx
         nodeSetName = cfg->nodeSetName;
         torquePIDs.resize(tcpController->rns->getSize(), pidController());
 
+        ik.reset(new VirtualRobot::DifferentialIK(rns, rns->getRobot()->getRootNode(), VirtualRobot::JacobiProvider::eSVDDamped));
 
 
-        // set DMP
-        isDisturbance = false;
-
-        dmpPtr.reset(new UMIDMP(cfg->kernelSize, cfg->DMPKd, cfg->baseMode, cfg->tau));
-        timeDuration = cfg->timeDuration;
-        canVal = timeDuration;
         finished = false;
-
-        phaseL = cfg->phaseL;
-        phaseK = cfg->phaseK;
-        phaseDist0 = cfg->phaseDist0;
-        phaseDist1 = cfg->phaseDist1;
-        phaseKpPos = cfg->phaseKpPos;
-        phaseKpOri = cfg->phaseKpOri;
-
-        posToOriRatio = cfg->posToOriRatio;
+        TaskSpaceDMPControllerConfig taskSpaceDMPConfig;
+        taskSpaceDMPConfig.motionTimeDuration = cfg->timeDuration;
+        taskSpaceDMPConfig.DMPKernelSize = cfg->kernelSize;
+        taskSpaceDMPConfig.DMPMode = cfg->dmpMode;
+        taskSpaceDMPConfig.DMPStyle = cfg->dmpStyle;
+        taskSpaceDMPConfig.DMPAmplitude = cfg->dmpAmplitude;
+        taskSpaceDMPConfig.phaseStopParas.goDist = cfg->phaseDist0;
+        taskSpaceDMPConfig.phaseStopParas.backDist = cfg->phaseDist1;
+        taskSpaceDMPConfig.phaseStopParas.Kpos = cfg->phaseKpPos;
+        taskSpaceDMPConfig.phaseStopParas.Dpos = 0;
+        taskSpaceDMPConfig.phaseStopParas.Kori = cfg->phaseKpOri;
+        taskSpaceDMPConfig.phaseStopParas.Dori = 0;
+        taskSpaceDMPConfig.phaseStopParas.mm2radi = cfg->posToOriRatio;
+        taskSpaceDMPConfig.phaseStopParas.maxValue = cfg->phaseL;
+        taskSpaceDMPConfig.phaseStopParas.slop = cfg->phaseK;
+
+        taskSpaceDMPController.reset(new TaskSpaceDMPController("default", taskSpaceDMPConfig));
 
         // initialize tcp position and orientation
 
 
-
         NJointTSDMPControllerSensorData initSensorData;
         initSensorData.deltaT = 0;
         initSensorData.currentTime = 0;
-        initSensorData.currentState.resize(6);
+        initSensorData.currentPose.setZero();
+        initSensorData.currentTwist.setZero();
         controllerSensorData.reinitAllBuffers(initSensorData);
 
-
         targetVels.resize(6);
         NJointTSDMPControllerControlData initData;
         initData.targetTSVel.resize(6);
         for (size_t i = 0; i < 6; ++i)
         {
-            initData.targetTSVel[i] = 0;
+            initData.targetTSVel(i) = 0;
+            targetVels(i) = 0;
         }
         initData.nullspaceJointVelocities.resize(tcpController->rns->getSize(), 0);
         initData.torqueKp.resize(tcpController->rns->getSize(), 0);
@@ -85,6 +92,7 @@ namespace armarx
         initData.mode = ModeFromIce(cfg->mode);
         reinitTripleBuffer(initData);
 
+
     }
 
     std::string NJointTSDMPController::getClassName(const Ice::Current&) const
@@ -94,126 +102,50 @@ namespace armarx
 
     void NJointTSDMPController::controllerRun()
     {
-        if (!controllerSensorData.updateReadBuffer())
+        if (!controllerSensorData.updateReadBuffer() || !taskSpaceDMPController)
         {
             return;
         }
         double deltaT = controllerSensorData.getReadBuffer().deltaT;
-        currentState = controllerSensorData.getReadBuffer().currentState;
-
-        double mpcFactor = 1;
-        double error = 0;
-        double phaseStop = 0;
-        double posError = 0;
-        double oriError = 0;
-
-
-        if (canVal > 1e-8)
-        {
-
-            std::vector<double> currentposi;
-            std::vector<double> currentori;
-            currentposi.resize(3);
-            currentori.resize(3);
-            for (size_t i = 0; i < 3; ++i)
-            {
-                currentposi[i] = currentState[i].pos;
-                posError += pow(currentState[i].pos - targetState[i], 2);
-            }
-
-            for (size_t i = 0; i < 3; ++i)
-            {
-                currentori[i] = currentState[i + 3].pos;
-                oriError += pow(currentState[i + 3].pos - targetState[i + 3], 2);
-            }
-
-            posError = sqrt(posError);
-            oriError = sqrt(oriError);
-
-            error = posError + posToOriRatio * oriError;
-            double dmpDeltaT = deltaT / timeDuration;
-
-            double phaseDist;
-            if (isDisturbance)
-            {
-                phaseDist = phaseDist1;
-            }
-            else
-            {
-                phaseDist = phaseDist0;
-            }
-
-            phaseStop = phaseL / (1 + exp(-phaseK * (error - phaseDist)));
-            mpcFactor = 1 - (phaseStop / phaseL);
-
-            if (mpcFactor < 0.1)
-            {
-                isDisturbance = true;
-            }
-
-            if (mpcFactor > 0.9)
-            {
-                isDisturbance = false;
-            }
-
-
-            double tau = dmpPtr->getTemporalFactor();
-            canVal -= 1 / tau * deltaT * 1 / (1 + phaseStop) ;
-            currentState = dmpPtr->calculateDirectlyVelocity(currentState, canVal / timeDuration, dmpDeltaT, targetState);
-
-
-
-            double vel0, vel1;
-
-            for (size_t i = 0; i < 3; i++)
-            {
-                vel0 = currentState[i].vel / timeDuration;
-                vel1 = phaseKpPos * (targetState[i] - currentposi[i]);
-                targetVels[i] = mpcFactor * vel0 + (1 - mpcFactor) * vel1;
-            }
-            for (size_t i = 0; i < 3; i++)
-            {
-                vel0 = currentState[i + 3].vel / timeDuration;
-                vel1 = phaseKpOri * (targetState[i + 3] - currentori[i]);
-                targetVels[i + 3] = mpcFactor * vel0 + (1 - mpcFactor) * vel1;
-            }
-
-        }
-        else
-        {
-            finished = true;
-
-            for (size_t i = 0; i < targetVels.size(); ++i)
-            {
-                targetVels[i] = 0;
-            }
-        }
-        //        debugOutputData.getWriteBuffer().latestTargetVelocities["x_vel"] = targetVels[0];
-        //        debugOutputData.getWriteBuffer().latestTargetVelocities["y_vel"] = targetVels[1];
-        //        debugOutputData.getWriteBuffer().latestTargetVelocities["z_vel"] = targetVels[2];
-        //        debugOutputData.getWriteBuffer().latestTargetVelocities["roll_vel"] = targetVels[3];
-        //        debugOutputData.getWriteBuffer().latestTargetVelocities["pitch_vel"] = targetVels[4];
-        //        debugOutputData.getWriteBuffer().latestTargetVelocities["yaw_vel"] = targetVels[5];
-        //        debugOutputData.getWriteBuffer().dmpTargets["dmp_x"] = targetState[0];
-        //        debugOutputData.getWriteBuffer().dmpTargets["dmp_y"] = targetState[1];
-        //        debugOutputData.getWriteBuffer().dmpTargets["dmp_z"] = targetState[2];
-        //        debugOutputData.getWriteBuffer().dmpTargets["dmp_roll"] = targetState[3];
-        //        debugOutputData.getWriteBuffer().dmpTargets["dmp_pitch"] = targetState[4];
-        //        debugOutputData.getWriteBuffer().dmpTargets["dmp_yaw"] = targetState[5];
-
-
-        debugOutputData.getWriteBuffer().currentCanVal = canVal;
-        //        debugOutputData.getWriteBuffer().mpcFactor = mpcFactor;
-        //        debugOutputData.getWriteBuffer().error = error;
-        //        debugOutputData.getWriteBuffer().phaseStop = phaseStop;
-        //        debugOutputData.getWriteBuffer().posError = posError;
-        //        debugOutputData.getWriteBuffer().oriError = oriError;
-        //        debugOutputData.getWriteBuffer().deltaT = deltaT;
-
-
+        Eigen::Matrix4f currentPose = controllerSensorData.getReadBuffer().currentPose;
+        Eigen::VectorXf currentTwist = controllerSensorData.getReadBuffer().currentTwist;
+
+        taskSpaceDMPController->flow(deltaT, currentPose, currentTwist);
+        targetVels = taskSpaceDMPController->getTargetVelocity();
+
+
+        std::vector<double> targetState = taskSpaceDMPController->getTargetPose();
+
+
+        debugOutputData.getWriteBuffer().latestTargetVelocities["x_vel"] = targetVels[0];
+        debugOutputData.getWriteBuffer().latestTargetVelocities["y_vel"] = targetVels[1];
+        debugOutputData.getWriteBuffer().latestTargetVelocities["z_vel"] = targetVels[2];
+        debugOutputData.getWriteBuffer().latestTargetVelocities["roll_vel"] = targetVels[3];
+        debugOutputData.getWriteBuffer().latestTargetVelocities["pitch_vel"] = targetVels[4];
+        debugOutputData.getWriteBuffer().latestTargetVelocities["yaw_vel"] = targetVels[5];
+        debugOutputData.getWriteBuffer().dmpTargets["dmp_x"] = targetState[0];
+        debugOutputData.getWriteBuffer().dmpTargets["dmp_y"] = targetState[1];
+        debugOutputData.getWriteBuffer().dmpTargets["dmp_z"] = targetState[2];
+        debugOutputData.getWriteBuffer().dmpTargets["dmp_qw"] = targetState[3];
+        debugOutputData.getWriteBuffer().dmpTargets["dmp_qx"] = targetState[4];
+        debugOutputData.getWriteBuffer().dmpTargets["dmp_qy"] = targetState[5];
+        debugOutputData.getWriteBuffer().dmpTargets["dmp_qz"] = targetState[6];
+        debugOutputData.getWriteBuffer().currentPose["currentPose_x"] = currentPose(0, 3);
+        debugOutputData.getWriteBuffer().currentPose["currentPose_y"] = currentPose(1, 3);
+        debugOutputData.getWriteBuffer().currentPose["currentPose_z"] = currentPose(2, 3);
+
+        VirtualRobot::MathTools::Quaternion currentQ = VirtualRobot::MathTools::eigen4f2quat(currentPose);
+        debugOutputData.getWriteBuffer().currentPose["currentPose_qw"] = currentQ.w;
+        debugOutputData.getWriteBuffer().currentPose["currentPose_qx"] = currentQ.x;
+        debugOutputData.getWriteBuffer().currentPose["currentPose_qy"] = currentQ.y;
+        debugOutputData.getWriteBuffer().currentPose["currentPose_qz"] = currentQ.z;
+        debugOutputData.getWriteBuffer().currentCanVal = taskSpaceDMPController->debugData.canVal;
+        debugOutputData.getWriteBuffer().mpcFactor =  taskSpaceDMPController->debugData.mpcFactor;
+        debugOutputData.getWriteBuffer().error = taskSpaceDMPController->debugData.poseError;
+        debugOutputData.getWriteBuffer().posError = taskSpaceDMPController->debugData.posiError;
+        debugOutputData.getWriteBuffer().oriError = taskSpaceDMPController->debugData.oriError;
         debugOutputData.commitWrite();
 
-        //        LockGuardType guard {controlDataMutex};
         getWriterControlStruct().targetTSVel = targetVels;
         writeControlStruct();
     }
@@ -222,52 +154,40 @@ namespace armarx
     void NJointTSDMPController::rtRun(const IceUtil::Time& sensorValuesTimestamp, const IceUtil::Time& timeSinceLastIteration)
     {
         Eigen::Matrix4f pose = tcp->getPoseInRootFrame();
-        Eigen::Vector3f currPosition;
-        Eigen::Vector3f currOrientation = VirtualRobot::MathTools::eigen4f2rpy(pose);
-        currPosition(0) = pose(0, 3);
-        currPosition(1) = pose(1, 3);
-        currPosition(2) = pose(2, 3);
-
         double deltaT = timeSinceLastIteration.toSecondsDouble();
 
-        Eigen::Vector3f posVel;
-        Eigen::Vector3f oriVel;
+        Eigen::MatrixXf jacobi = ik->getJacobianMatrix(tcp, VirtualRobot::IKSolver::CartesianSelection::All);
 
-        if (deltaT == 0)
-        {
-            posVel << 0, 0 , 0;
-            oriVel << 0, 0 , 0;
-        }
-        else
+        Eigen::VectorXf qvel;
+        qvel.resize(velocitySensors.size());
+        for (size_t i = 0; i < velocitySensors.size(); ++i)
         {
-            posVel = (currPosition - tcpPosition) / deltaT;
-            oriVel = (currOrientation - tcpOrientation) / deltaT;
+            qvel(i) = velocitySensors[i]->velocity;
         }
 
-        tcpPosition = currPosition;
-        tcpOrientation = currOrientation;
+        Eigen::VectorXf tcptwist = jacobi * qvel;
+
+        controllerSensorData.getWriteBuffer().currentPose = pose;
+        controllerSensorData.getWriteBuffer().currentTwist = tcptwist;
+        controllerSensorData.getWriteBuffer().deltaT = deltaT;
+        controllerSensorData.getWriteBuffer().currentTime += deltaT;
+        controllerSensorData.commitWrite();
+
+
+        Eigen::VectorXf targetVel = rtGetControlStruct().targetTSVel;
 
-        for (size_t i = 0; i < 3; i++)
+        float normLinearVelocity = targetVel.block<3, 1>(0, 0).norm();
+        if (normLinearVelocity > cfg->maxLinearVel)
         {
-            DMP::DMPState currentPos;
-            currentPos.pos = tcpPosition(i);
-            currentPos.vel = posVel(i) * timeDuration;
-            controllerSensorData.getWriteBuffer().currentState[i] = currentPos;
+            targetVel.block<3, 1>(0, 0) = cfg->maxLinearVel * targetVel.block<3, 1>(0, 0) / normLinearVelocity;
         }
 
-        for (size_t i = 0; i < 3; i++)
+        float normAngularVelocity = targetVel.block<3, 1>(3, 0).norm();
+        if (normAngularVelocity > cfg->maxAngularVel)
         {
-            DMP::DMPState currentPos;
-            currentPos.pos = tcpOrientation(i);
-            currentPos.vel = oriVel(i) * timeDuration;
-            controllerSensorData.getWriteBuffer().currentState[i + 3] = currentPos;
+            targetVel.block<3, 1>(3, 0) = cfg->maxAngularVel * targetVel.block<3, 1>(3, 0) / normAngularVelocity;
         }
 
-        controllerSensorData.getWriteBuffer().deltaT = deltaT;
-        controllerSensorData.getWriteBuffer().currentTime += deltaT;
-
-        controllerSensorData.commitWrite();
-
 
         // cartesian vel controller
         Eigen::VectorXf x;
@@ -278,7 +198,7 @@ namespace armarx
             x.resize(6);
             for (size_t i = 0; i < 6; i++)
             {
-                x(i) = rtGetControlStruct().targetTSVel[i];
+                x(i) = targetVel(i);
             }
         }
         else if (mode == VirtualRobot::IKSolver::Position)
@@ -286,7 +206,7 @@ namespace armarx
             x.resize(3);
             for (size_t i = 0; i < 3; i++)
             {
-                x(i) = rtGetControlStruct().targetTSVel[i];
+                x(i) = targetVel(i);
             }
 
         }
@@ -295,7 +215,7 @@ namespace armarx
             x.resize(3);
             for (size_t i = 0; i < 3; i++)
             {
-                x(i) = rtGetControlStruct().targetTSVel[i + 3];
+                x(i) = targetVel(i + 3);
             }
         }
         else
@@ -335,44 +255,28 @@ namespace armarx
 
     void NJointTSDMPController::learnDMPFromFiles(const Ice::StringSeq& fileNames, const Ice::Current&)
     {
-        DMP::Vec<DMP::SampledTrajectoryV2 > trajs;
-
-        DMP::DVec ratios;
-        for (size_t i = 0; i < fileNames.size(); ++i)
-        {
-            DMP::SampledTrajectoryV2 traj;
-            traj.readFromCSVFile(fileNames.at(i));
-            traj = DMP::SampledTrajectoryV2::normalizeTimestamps(traj, 0, 1);
-            trajs.push_back(traj);
-
-            if (i == 0)
-            {
-                ratios.push_back(1.0);
-            }
-            else
-            {
-                ratios.push_back(0.0);
-            }
-        }
-
-        dmpPtr->learnFromTrajectories(trajs);
-        dmpPtr->setOneStepMPC(true);
-        dmpPtr->styleParas = dmpPtr->getStyleParasWithRatio(ratios);
+        taskSpaceDMPController->learnDMPFromFiles(fileNames);
 
         ARMARX_INFO << "Learned DMP ... ";
     }
 
-    void NJointTSDMPController::setViaPoints(Ice::Double u, const Ice::DoubleSeq& viapoint, const Ice::Current&)
+    void NJointTSDMPController::setSpeed(Ice::Double times, const Ice::Current&)
     {
-        ViaPoint viaPoint(u, viapoint);
+        LockGuardType guard(controllerMutex);
+        taskSpaceDMPController->setSpeed(times);
+    }
 
+    void NJointTSDMPController::setViaPoints(Ice::Double u, const Ice::DoubleSeq& viapoint, const Ice::Current&)
+    {
         LockGuardType guard(controllerMutex);
-        dmpPtr->setViaPoint(viaPoint);
+        ARMARX_INFO << "setting via points ";
+        taskSpaceDMPController->setViaPose(u, viapoint);
     }
 
+
     void NJointTSDMPController::setGoals(const Ice::DoubleSeq& goals, const Ice::Current& ice)
     {
-        setViaPoints(dmpPtr->getUMin(), goals, ice);
+        taskSpaceDMPController->setGoalPoseVec(goals);
     }
 
     void NJointTSDMPController::setControllerTarget(Ice::Float avoidJointLimitsKp, NJointTaskSpaceDMPControllerMode::CartesianSelection mode, const Ice::Current&)
@@ -425,46 +329,14 @@ namespace armarx
     void NJointTSDMPController::runDMP(const Ice::DoubleSeq&  goals, double tau, const Ice::Current&)
     {
         Eigen::Matrix4f pose = tcp->getPoseInRootFrame();
-        tcpPosition(0) = pose(0, 3);
-        tcpPosition(1) = pose(1, 3);
-        tcpPosition(2) = pose(2, 3);
-        tcpOrientation = VirtualRobot::MathTools::eigen4f2rpy(pose);
-
-        ARMARX_INFO << "tcpPosition: " << tcpPosition;
-        ARMARX_INFO << "tcpOrientation: " << tcpOrientation;
-
-        currentState.clear();
-        targetState.clear();
-        for (size_t i = 0; i < 3; i++)
-        {
-            DMP::DMPState currentPos;
-            currentPos.pos = tcpPosition(i);
-            currentPos.vel = 0;
-            currentState.push_back(currentPos);
-            targetState.push_back(currentPos.pos);
-        }
-        for (size_t i = 0; i < 3; i++)
-        {
-            DMP::DMPState currentPos;
-            currentPos.pos = tcpOrientation(i);
-            currentPos.vel = 0;
-            currentState.push_back(currentPos);
-            targetState.push_back(currentPos.pos);
-        }
-        dmpPtr->prepareExecution(goals, currentState, 1,  tau);
+        taskSpaceDMPController->prepareExecution(taskSpaceDMPController->eigen4f2vec(pose), goals);
         finished = false;
-        dmpPtr->setTemporalFactor(tau);
 
         ARMARX_INFO << "run DMP";
         controllerTask->start();
 
     }
 
-    void NJointTSDMPController::setTemporalFactor(double tau, const Ice::Current&)
-    {
-        LockGuardType guard(controllerMutex);
-        dmpPtr->setTemporalFactor(tau);
-    }
 
     void NJointTSDMPController::rtPreActivateController()
     {
@@ -478,24 +350,31 @@ namespace armarx
     void NJointTSDMPController::onPublish(const SensorAndControl&, const DebugDrawerInterfacePrx&, const DebugObserverInterfacePrx& debugObs)
     {
         StringVariantBaseMap datafields;
-        //        auto values = debugOutputData.getUpToDateReadBuffer().latestTargetVelocities;
-        //        for (auto& pair : values)
-        //        {
-        //            datafields[pair.first] = new Variant(pair.second);
+        auto values = debugOutputData.getUpToDateReadBuffer().latestTargetVelocities;
+        for (auto& pair : values)
+        {
+            datafields[pair.first] = new Variant(pair.second);
+        }
+
+        auto dmpTargets = debugOutputData.getUpToDateReadBuffer().dmpTargets;
+        for (auto& pair : dmpTargets)
+        {
+            datafields[pair.first] = new Variant(pair.second);
+        }
 
-        //        auto dmpTargets = debugOutputData.getUpToDateReadBuffer().dmpTargets;
-        //        for (auto& pair : dmpTargets)
-        //        {
-        //            datafields[pair.first] = new Variant(pair.second);
-        //        }
+        auto currentPose = debugOutputData.getUpToDateReadBuffer().currentPose;
+        for (auto& pair : currentPose)
+        {
+            datafields[pair.first] = new Variant(pair.second);
+        }
 
         datafields["canVal"] = new Variant(debugOutputData.getUpToDateReadBuffer().currentCanVal);
-        //        datafields["mpcFactor"] = new Variant(debugOutputData.getUpToDateReadBuffer().mpcFactor);
-        //        datafields["poseError"] = new Variant(debugOutputData.getUpToDateReadBuffer().error);
-        //        datafields["phaseStop"] = new Variant(debugOutputData.getUpToDateReadBuffer().phaseStop);
-        //        datafields["posError"] = new Variant(debugOutputData.getUpToDateReadBuffer().posError);
-        //        datafields["oriError"] = new Variant(debugOutputData.getUpToDateReadBuffer().oriError);
-        //        datafields["deltaT"] = new Variant(debugOutputData.getUpToDateReadBuffer().deltaT);
+        datafields["mpcFactor"] = new Variant(debugOutputData.getUpToDateReadBuffer().mpcFactor);
+        datafields["poseError"] = new Variant(debugOutputData.getUpToDateReadBuffer().error);
+        datafields["phaseStop"] = new Variant(debugOutputData.getUpToDateReadBuffer().phaseStop);
+        datafields["posError"] = new Variant(debugOutputData.getUpToDateReadBuffer().posError);
+        datafields["oriError"] = new Variant(debugOutputData.getUpToDateReadBuffer().oriError);
+        datafields["deltaT"] = new Variant(debugOutputData.getUpToDateReadBuffer().deltaT);
 
         debugObs->setDebugChannel("DMPController", datafields);
     }
diff --git a/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointTSDMPController.h b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointTSDMPController.h
index a072119a1b2fd8bf15ceb305f1e3397026474d10..a70f5a2962b929399e8a1a0f4e24d63a0a425687 100644
--- a/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointTSDMPController.h
+++ b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointTSDMPController.h
@@ -7,10 +7,11 @@
 #include <RobotAPI/components/units/RobotUnit/ControlTargets/ControlTarget1DoFActuator.h>
 #include <RobotAPI/components/units/RobotUnit/SensorValues/SensorValue1DoFActuator.h>
 #include <VirtualRobot/IK/DifferentialIK.h>
-#include <dmp/representation/dmp/umidmp.h>
+#include <dmp/representation/dmp/umitsmp.h>
 #include <RobotAPI/interface/units/RobotUnit/NJointTaskSpaceDMPController.h>
 #include <RobotAPI/libraries/core/CartesianVelocityController.h>
 
+#include <RobotAPI/libraries/DMPController/TaskSpaceDMPController.h>
 
 using namespace DMP;
 namespace armarx
@@ -25,7 +26,7 @@ namespace armarx
     class NJointTSDMPControllerControlData
     {
     public:
-        std::vector<float> targetTSVel;
+        Eigen::VectorXf targetTSVel;
         // cartesian velocity control data
         std::vector<float> nullspaceJointVelocities;
         float avoidJointLimitsKp = 0;
@@ -71,13 +72,20 @@ namespace armarx
         }
 
         void runDMP(const Ice::DoubleSeq& goals, Ice::Double tau, const Ice::Current&);
-        void setTemporalFactor(Ice::Double tau, const Ice::Current&);
+        void setSpeed(Ice::Double times, const Ice::Current&);
         void setViaPoints(Ice::Double u, const Ice::DoubleSeq& viapoint, const Ice::Current&);
+
         void setGoals(const Ice::DoubleSeq& goals, const Ice::Current&);
 
         void setControllerTarget(Ice::Float avoidJointLimitsKp, NJointTaskSpaceDMPControllerMode::CartesianSelection mode, const Ice::Current&);
         void setTorqueKp(const StringFloatDictionary& torqueKp, const Ice::Current&);
         void setNullspaceJointVelocities(const StringFloatDictionary& nullspaceJointVelocities, const Ice::Current&);
+
+        double getCanVal(const Ice::Current &)
+        {
+            return taskSpaceDMPController->canVal;
+        }
+
     protected:
         void rtPreActivateController() override;
         void rtPostDeactivateController() override;
@@ -91,15 +99,16 @@ namespace armarx
     private:
         struct DebugBufferData
         {
-            //            StringFloatDictionary latestTargetVelocities;
-            //            StringFloatDictionary dmpTargets;
+            StringFloatDictionary latestTargetVelocities;
+            StringFloatDictionary dmpTargets;
+            StringFloatDictionary currentPose;
             double currentCanVal;
-            //            double mpcFactor;
-            //            double error;
-            //            double phaseStop;
-            //            double posError;
-            //            double oriError;
-            //            double deltaT;
+            double mpcFactor;
+            double error;
+            double phaseStop;
+            double posError;
+            double oriError;
+            double deltaT;
         };
 
         TripleBuffer<DebugBufferData> debugOutputData;
@@ -108,7 +117,8 @@ namespace armarx
         {
             double currentTime;
             double deltaT;
-            DMP::Vec<DMP::DMPState> currentState;
+            Eigen::Matrix4f currentPose;
+            Eigen::VectorXf currentTwist;
         };
         TripleBuffer<NJointTSDMPControllerSensorData> controllerSensorData;
 
@@ -116,6 +126,11 @@ namespace armarx
         std::vector<const SensorValue1DoFActuatorTorque*> torqueSensors;
         std::vector<const SensorValue1DoFGravityTorque*> gravityTorqueSensors;
         std::vector<ControlTarget1DoFActuatorVelocity*> targets;
+        std::vector<const SensorValue1DoFActuatorVelocity*> velocitySensors;
+        std::vector<const SensorValue1DoFActuatorPosition*> positionSensors;
+
+
+        TaskSpaceDMPControllerPtr taskSpaceDMPController;
 
         // velocity ik controller parameters
         std::vector<pidController> torquePIDs;
@@ -123,35 +138,18 @@ namespace armarx
         std::string nodeSetName;
 
         // dmp parameters
-        UMIDMPPtr dmpPtr;
-        double timeDuration;
-        double canVal;
         bool finished;
-        double tau;
-        ViaPointsSet viaPoints;
-        bool isDisturbance;
 
-
-        // phaseStop parameters
-        double phaseL;
-        double phaseK;
-        double phaseDist0;
-        double phaseDist1;
-        double phaseKpPos;
-        double phaseKpOri;
-
-        double posToOriRatio;
-
-        std::vector<float> targetVels;
+        VirtualRobot::DifferentialIKPtr ik;
+        VirtualRobot::RobotNodePtr tcp;
+        Eigen::VectorXf targetVels;
 
         NJointTaskSpaceDMPControllerConfigPtr cfg;
-        VirtualRobot::RobotNodePtr tcp;
-        Eigen::Vector3f tcpPosition;
-        Eigen::Vector3f tcpOrientation;
-        DMP::Vec<DMP::DMPState> currentState;
-        DMP::DVec targetState;
         mutable MutexType controllerMutex;
         PeriodicTask<NJointTSDMPController>::pointer_type controllerTask;
+
+        // NJointTaskSpaceDMPControllerInterface interface
+
     };
 
 } // namespace armarx
diff --git a/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointTaskSpaceDMPController.cpp b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointTaskSpaceDMPController.cpp
index a210d04f27abcfafd3dcd73eef9a697ad77e02bb..0b3858033b0d6b34ae858d1379b34cdc7ccebef8 100644
--- a/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointTaskSpaceDMPController.cpp
+++ b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointTaskSpaceDMPController.cpp
@@ -335,6 +335,7 @@ namespace armarx
         writeControlStruct();
     }
 
+
     void NJointTaskSpaceDMPController::setGoals(const Ice::DoubleSeq& goals, const Ice::Current& ice)
     {
         setViaPoints(dmpPtr->getUMin(), goals, ice);
diff --git a/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointTaskSpaceDMPController.h b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointTaskSpaceDMPController.h
index edcb07cffe543ca68bd7505c501bbd705954ca85..e3bb4412951d30c4d2e22209cf67cdb5140863f0 100644
--- a/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointTaskSpaceDMPController.h
+++ b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointTaskSpaceDMPController.h
@@ -76,6 +76,7 @@ namespace armarx
         void runDMP(const Ice::DoubleSeq& goals, Ice::Double tau, const Ice::Current&);
         void setTemporalFactor(Ice::Double tau, const Ice::Current&);
         void setViaPoints(Ice::Double u, const Ice::DoubleSeq& viapoint, const Ice::Current&);
+
         void setGoals(const Ice::DoubleSeq& goals, const Ice::Current&);
 
         void setControllerTarget(Ice::Float avoidJointLimitsKp, NJointTaskSpaceDMPControllerMode::CartesianSelection mode, const Ice::Current&);
diff --git a/source/RobotAPI/libraries/core/PIDController.cpp b/source/RobotAPI/libraries/core/PIDController.cpp
index d3d1a61fb731dbfa31377e0f741282488eaf3690..928e8451aee81823951866979f5d0a30321ca70b 100644
--- a/source/RobotAPI/libraries/core/PIDController.cpp
+++ b/source/RobotAPI/libraries/core/PIDController.cpp
@@ -31,7 +31,7 @@
 using namespace armarx;
 
 
-PIDController::PIDController(float Kp, float Ki, float Kd, double maxControlValue, double maxDerivation, bool limitless) :
+PIDController::PIDController(float Kp, float Ki, float Kd, double maxControlValue, double maxDerivation, bool limitless, bool threadSafe) :
     Kp(Kp),
     Ki(Ki),
     Kd(Kd),
@@ -44,23 +44,36 @@ PIDController::PIDController(float Kp, float Ki, float Kd, double maxControlValu
     controlValueDerivation(0),
     maxControlValue(maxControlValue),
     maxDerivation(maxDerivation),
-    limitless(limitless)
+    limitless(limitless),
+    threadSafe(threadSafe)
 {
     reset();
 }
 
 void PIDController::reset()
 {
-    ScopedRecursiveLock lock(mutex);
+    ScopedRecursiveLockPtr lock = getLock();
     firstRun = true;
     previousError = 0;
     integral = 0;
     lastUpdateTime = TimeUtil::GetTime();
 }
 
+ScopedRecursiveLockPtr PIDController::getLock() const
+{
+    if (threadSafe)
+    {
+        return ScopedRecursiveLockPtr(new ScopedRecursiveLock(mutex));
+    }
+    else
+    {
+        return ScopedRecursiveLockPtr();
+    }
+}
+
 void PIDController::update(double measuredValue, double targetValue)
 {
-    ScopedRecursiveLock lock(mutex);
+    ScopedRecursiveLockPtr lock = getLock();
     IceUtil::Time now = TimeUtil::GetTime();
 
     if (firstRun)
@@ -76,25 +89,25 @@ void PIDController::update(double measuredValue, double targetValue)
 
 void PIDController::update(double measuredValue)
 {
-    ScopedRecursiveLock lock(mutex);
+    ScopedRecursiveLockPtr lock = getLock();
     update(measuredValue, target);
 }
 
 void PIDController::setTarget(double newTarget)
 {
-    ScopedRecursiveLock lock(mutex);
+    ScopedRecursiveLockPtr lock = getLock();
     target = newTarget;
 }
 
 void PIDController::setMaxControlValue(double newMax)
 {
-    ScopedRecursiveLock lock(mutex);
+    ScopedRecursiveLockPtr lock = getLock();
     maxControlValue = newMax;
 }
 
 void PIDController::update(double deltaSec, double measuredValue, double targetValue)
 {
-    ScopedRecursiveLock lock(mutex);
+    ScopedRecursiveLockPtr lock = getLock();
     processValue = measuredValue;
     target = targetValue;
 
@@ -144,7 +157,7 @@ void PIDController::update(double deltaSec, double measuredValue, double targetV
 
 double PIDController::getControlValue() const
 {
-    ScopedRecursiveLock lock(mutex);
+    ScopedRecursiveLockPtr lock = getLock();
     return controlValue;
 }
 
diff --git a/source/RobotAPI/libraries/core/PIDController.h b/source/RobotAPI/libraries/core/PIDController.h
index 0d31868f92290b356c32344f264e6f7556117492..e6e9976b94e31241d086ee513f117d8b3aa81fed 100644
--- a/source/RobotAPI/libraries/core/PIDController.h
+++ b/source/RobotAPI/libraries/core/PIDController.h
@@ -39,7 +39,7 @@ namespace armarx
                       float Kd,
                       double maxControlValue = std::numeric_limits<double>::max(),
                       double maxDerivation = std::numeric_limits<double>::max(),
-                      bool limitless = false);
+                      bool limitless = false, bool threadSafe = true);
         void update(double deltaSec, double measuredValue, double targetValue);
         void update(double measuredValue, double targetValue);
         void update(double measuredValue);
@@ -62,6 +62,9 @@ namespace armarx
         double maxDerivation;
         bool firstRun;
         bool limitless;
+        bool threadSafe = true;
+    private:
+        ScopedRecursiveLockPtr getLock() const;
         mutable RecursiveMutex mutex;
     };
     typedef boost::shared_ptr<PIDController> PIDControllerPtr;
diff --git a/source/RobotAPI/libraries/core/math/ColorUtils.h b/source/RobotAPI/libraries/core/math/ColorUtils.h
index b28b8c8ebc1e535c5cf91f1393d92416e889c9c1..fb79987b2e9ba827e23cdcef58696b259628d984 100644
--- a/source/RobotAPI/libraries/core/math/ColorUtils.h
+++ b/source/RobotAPI/libraries/core/math/ColorUtils.h
@@ -30,103 +30,126 @@ namespace armarx
     namespace colorutils
     {
 
-
-
-
-        DrawColor24Bit HsvToRgb(const HsvColor& hsv)
+        DrawColor24Bit HsvToRgb(const HsvColor& in)
         {
-            DrawColor24Bit rgb;
-            unsigned char region, remainder, p, q, t;
-
-            if (hsv.s == 0)
+            double      hh, p, q, t, ff;
+            long        i;
+            double r, g, b;
+            if (in.s <= 0.0)        // < is bogus, just shuts up warnings
             {
-                rgb.r = hsv.v;
-                rgb.g = hsv.v;
-                rgb.b = hsv.v;
-                return rgb;
+                r = in.v;
+                g = in.v;
+                b = in.v;
+                return DrawColor24Bit {(Ice::Byte)(r * 255), (Ice::Byte)(g * 255), (Ice::Byte)(b * 255)};
             }
-            constexpr float by43 = 1.0f / 43.0f;
-            region = hsv.h * by43;
-            remainder = (hsv.h - (region * 43)) * 6;
-
-            p = (hsv.v * (255 - hsv.s)) >> 8;
-            q = (hsv.v * (255 - ((hsv.s * remainder) >> 8))) >> 8;
-            t = (hsv.v * (255 - ((hsv.s * (255 - remainder)) >> 8))) >> 8;
-
-            switch (region)
+            hh = in.h;
+            if (hh >= 360.0)
+            {
+                hh = 0.0;
+            }
+            hh /= 60.0;
+            i = (long)hh;
+            ff = hh - i;
+            p = in.v * (1.0 - in.s);
+            q = in.v * (1.0 - (in.s * ff));
+            t = in.v * (1.0 - (in.s * (1.0 - ff)));
+
+            switch (i)
             {
                 case 0:
-                    rgb.r = hsv.v;
-                    rgb.g = t;
-                    rgb.b = p;
+                    r = in.v;
+                    g = t;
+                    b = p;
                     break;
                 case 1:
-                    rgb.r = q;
-                    rgb.g = hsv.v;
-                    rgb.b = p;
+                    r = q;
+                    g = in.v;
+                    b = p;
                     break;
                 case 2:
-                    rgb.r = p;
-                    rgb.g = hsv.v;
-                    rgb.b = t;
+                    r = p;
+                    g = in.v;
+                    b = t;
                     break;
+
                 case 3:
-                    rgb.r = p;
-                    rgb.g = q;
-                    rgb.b = hsv.v;
+                    r = p;
+                    g = q;
+                    b = in.v;
                     break;
                 case 4:
-                    rgb.r = t;
-                    rgb.g = p;
-                    rgb.b = hsv.v;
+                    r = t;
+                    g = p;
+                    b = in.v;
                     break;
+                case 5:
                 default:
-                    rgb.r = hsv.v;
-                    rgb.g = p;
-                    rgb.b = q;
+                    r = in.v;
+                    g = p;
+                    b = q;
                     break;
             }
 
-            return rgb;
+            return DrawColor24Bit {(Ice::Byte)(r * 255), (Ice::Byte)(g * 255), (Ice::Byte)(b * 255)};
         }
 
-        HsvColor RgbToHsv(const DrawColor24Bit& rgb)
+        HsvColor RgbToHsv(const DrawColor24Bit& in)
         {
-            HsvColor hsv;
-            unsigned char rgbMin, rgbMax;
+            double r = in.r * 0.00392156862;
+            double g = in.g * 0.00392156862;
+            double b = in.b * 0.00392156862;
+            HsvColor         out;
+            double      min, max, delta;
 
-            rgbMin = rgb.r < rgb.g ? (rgb.r < rgb.b ? rgb.r : rgb.b) : (rgb.g < rgb.b ? rgb.g : rgb.b);
-            rgbMax = rgb.r > rgb.g ? (rgb.r > rgb.b ? rgb.r : rgb.b) : (rgb.g > rgb.b ? rgb.g : rgb.b);
+            min = r < g ? r : g;
+            min = min  < b ? min  : b;
 
-            hsv.v = rgbMax;
-            if (hsv.v == 0)
+            max = r > g ? r : g;
+            max = max  > b ? max  : b;
+
+            out.v = max;                                // v
+            delta = max - min;
+            if (delta < 0.00001)
             {
-                hsv.h = 0;
-                hsv.s = 0;
-                return hsv;
+                out.s = 0;
+                out.h = 0; // undefined, maybe nan?
+                return out;
             }
-
-            hsv.s = 255 * long(rgbMax - rgbMin) / hsv.v;
-            if (hsv.s == 0)
+            if (max > 0.0)    // NOTE: if Max is == 0, this divide would cause a crash
             {
-                hsv.h = 0;
-                return hsv;
+                out.s = (delta / max);                  // s
             }
-
-            if (rgbMax == rgb.r)
+            else
+            {
+                // if max is 0, then r = g = b = 0
+                // s = 0, h is undefined
+                out.s = 0.0;
+                out.h = 0;                            // its now undefined
+                return out;
+            }
+            if (r >= max)                            // > is bogus, just keeps compilor happy
             {
-                hsv.h = 0 + 43 * (rgb.g - rgb.b) / (rgbMax - rgbMin);
+                out.h = (g - b) / delta;    // between yellow & magenta
             }
-            else if (rgbMax == rgb.g)
+            else if (g >= max)
             {
-                hsv.h = 85 + 43 * (rgb.b - rgb.r) / (rgbMax - rgbMin);
+                out.h = 2.0 + (b - r) / delta;    // between cyan & yellow
             }
             else
             {
-                hsv.h = 171 + 43 * (rgb.r - rgb.g) / (rgbMax - rgbMin);
+                out.h = 4.0 + (r - g) / delta;    // between magenta & cyan
             }
 
-            return hsv;
+            out.h *= 60.0;                              // degrees
+
+            if (out.h < 0.0)
+            {
+                out.h += 360.0;
+            }
+
+            return out;
+
+
         }
 
         /**
@@ -137,8 +160,8 @@ namespace armarx
         HsvColor HeatMapColor(float percentage)
         {
             percentage = math::MathUtils::LimitMinMax(0.0f, 1.0f, percentage);
-            constexpr float factor = 240.0 * (255.0 / 360.0);
-            return HsvColor {(unsigned char)((1.0 - percentage) * factor), 255, 255};
+
+            return HsvColor {((1.0f - percentage) * 240.f), 1.0f, 1.0f};
         }
 
         DrawColor24Bit HeatMapRGBColor(float percentage)
diff --git a/source/RobotAPI/libraries/core/test/MathUtilsTest.cpp b/source/RobotAPI/libraries/core/test/MathUtilsTest.cpp
index dd7592f4b8c5ec565a6f20abe25a1cb7c4e86947..73c9326968fc973e8e632c9de1cae7e1136a7035 100644
--- a/source/RobotAPI/libraries/core/test/MathUtilsTest.cpp
+++ b/source/RobotAPI/libraries/core/test/MathUtilsTest.cpp
@@ -25,6 +25,7 @@
 #include <RobotAPI/Test.h>
 #include <ArmarXCore/core/test/IceTestHelper.h>
 #include "../math/MathUtils.h"
+#include "../math/ColorUtils.h"
 using namespace armarx;
 
 void check_close(float a, float b, float tolerance)
@@ -60,3 +61,16 @@ BOOST_AUTO_TEST_CASE(fmodTest)
     }
 
 }
+
+BOOST_AUTO_TEST_CASE(ColorUtilTest)
+{
+    auto testColor = [](DrawColor24Bit rgb)
+    {
+        auto hsv = colorutils::RgbToHsv(rgb);
+        ARMARX_INFO << VAROUT(rgb.r) << VAROUT(rgb.g) << VAROUT(rgb.b) << " --> " << VAROUT(hsv.h) << VAROUT(hsv.s) << VAROUT(hsv.v);
+    };
+    testColor({255, 0, 0});
+    testColor({0, 255, 0});
+    testColor({0, 0, 255});
+    testColor({0, 20, 0});
+}