diff --git a/source/RobotAPI/interface/units/RobotUnit/NJointJointSpaceDMPController.ice b/source/RobotAPI/interface/units/DMPController/NJointJointSpaceDMPController.ice
similarity index 100%
rename from source/RobotAPI/interface/units/RobotUnit/NJointJointSpaceDMPController.ice
rename to source/RobotAPI/interface/units/DMPController/NJointJointSpaceDMPController.ice
diff --git a/source/RobotAPI/interface/units/RobotUnit/NJointTaskSpaceDMPController.ice b/source/RobotAPI/interface/units/DMPController/NJointTaskSpaceDMPController.ice
similarity index 63%
rename from source/RobotAPI/interface/units/RobotUnit/NJointTaskSpaceDMPController.ice
rename to source/RobotAPI/interface/units/DMPController/NJointTaskSpaceDMPController.ice
index d5fc252cc50d8fbfa34e885da5cda920e4c82ecd..1ea4be9012b590015af944a8e71ecfd708413297 100644
--- a/source/RobotAPI/interface/units/RobotUnit/NJointTaskSpaceDMPController.ice
+++ b/source/RobotAPI/interface/units/DMPController/NJointTaskSpaceDMPController.ice
@@ -52,10 +52,13 @@ module armarx
         double phaseK = 10;
         double phaseDist0 = 50;
         double phaseDist1 = 10;
-        double phaseKp = 1;
+        double phaseKpPos = 1;
+        double phaseKpOri = 0.1;
 
         double timeDuration = 10;
 
+        double posToOriRatio = 100;
+
         // velocity controller configuration
         string nodeSetName = "";
         string tcpName = "";
@@ -78,5 +81,48 @@ module armarx
         void setTorqueKp(StringFloatDictionary torqueKp);
         void setNullspaceJointVelocities(StringFloatDictionary nullspaceJointVelocities);
     };
+
+    class NJointCCDMPControllerConfig extends NJointControllerConfig
+    {
+
+        // dmp configuration
+        int kernelSize = 100;
+        double tau = 1;
+        int baseMode = 1;
+        int dmpNum = 2;
+
+        // phaseStop technique
+        double phaseL = 10;
+        double phaseK = 10;
+        double phaseDist0 = 50;
+        double phaseDist1 = 10;
+        double phaseKpPos = 1;
+        double phaseKpOri = 0.1;
+
+        // misc
+        double timeDuration = 10;
+        double posToOriRatio = 100;
+
+        // velocity controller configuration
+        string nodeSetName = "";
+        string tcpName = "";
+        NJointTaskSpaceDMPControllerMode::CartesianSelection mode = NJointTaskSpaceDMPControllerMode::eAll;
+
+    };
+
+    interface NJointCCDMPControllerInterface extends NJointControllerInterface
+    {
+        void learnDMPFromFiles(int dmpId, Ice::StringSeq trajfiles);
+        bool isFinished();
+        void runDMP();
+
+        void setTemporalFactor(double tau);
+        void setViaPoints(int dmpId, double canVal, Ice::DoubleSeq point);
+        void setGoals(int dmpId, Ice::DoubleSeq goals);
+
+        void setControllerTarget(float avoidJointLimitsKp, NJointTaskSpaceDMPControllerMode::CartesianSelection mode);
+        void setTorqueKp(StringFloatDictionary torqueKp);
+        void setNullspaceJointVelocities(StringFloatDictionary nullspaceJointVelocities);
+    };
 };
 #endif
diff --git a/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointJSDMPController.h b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointJSDMPController.h
index 625058be3fa1a6d22047392e6cd4dce582590afc..16b456700cc05f175718e381eb4e7683378f3d8f 100644
--- a/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointJSDMPController.h
+++ b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointJSDMPController.h
@@ -9,7 +9,7 @@
 #include <RobotAPI/components/units/RobotUnit/SensorValues/SensorValue1DoFActuator.h>
 #include <dmp/representation/dmp/umidmp.h>
 #include <ArmarXCore/core/services/tasks/RunningTask.h>
-#include <RobotAPI/interface/units/RobotUnit/NJointJointSpaceDMPController.h>
+#include <RobotAPI/interface/units/DMPController/NJointJointSpaceDMPController.h>
 
 namespace armarx
 {
diff --git a/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointJointSpaceDMPController.cpp b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointJointSpaceDMPController.cpp
index 737502f40ce26d64f24f8740ed7031bedcb23de1..0626c1976c4bfe8f6b5de2eed7ba0298006a65f2 100644
--- a/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointJointSpaceDMPController.cpp
+++ b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointJointSpaceDMPController.cpp
@@ -121,7 +121,11 @@ namespace armarx
                     double vel = mpcFactor * vel0 + (1 - mpcFactor) * vel1;
                     targets[jointName]->velocity = finished ? 0.0f : vel;
 
+                    std::string targetVelstr = jointName + "_targetvel";
+                    std::string targetStatestr = jointName + "_dmpTarget";
                     debugOutputData.getWriteBuffer().latestTargetVelocities[jointName] = vel;
+                    debugOutputData.getWriteBuffer().dmpTargetState[jointName] = targetState[i];
+
                 }
             }
 
@@ -166,8 +170,6 @@ namespace armarx
         }
         dmpPtr->learnFromTrajectories(trajs);
         dmpPtr->setOneStepMPC(true);
-
-
         dmpPtr->styleParas = dmpPtr->getStyleParasWithRatio(ratios);
 
         ARMARX_INFO << "Learned DMP ... ";
@@ -230,6 +232,12 @@ namespace armarx
             datafields[pair.first] = new Variant(pair.second);
         }
 
+        auto valuesst = debugOutputData.getUpToDateReadBuffer().dmpTargetState;
+        for (auto& pair : valuesst)
+        {
+            datafields[pair.first] = new Variant(pair.second);
+        }
+
         datafields["canVal"] = new Variant(debugOutputData.getUpToDateReadBuffer().currentCanVal);
         datafields["mpcFactor"] = new Variant(debugOutputData.getUpToDateReadBuffer().mpcFactor);
         debugObs->setDebugChannel("latestDMPTargetVelocities", datafields);
diff --git a/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointJointSpaceDMPController.h b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointJointSpaceDMPController.h
index 15e69e65aa13cd065d82fe79630372a5aa4dcb25..9d7e6a53edc234f521373d4bb7cf3f0106df8f1a 100644
--- a/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointJointSpaceDMPController.h
+++ b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointJointSpaceDMPController.h
@@ -8,7 +8,7 @@
 #include <RobotAPI/components/units/RobotUnit/ControlTargets/ControlTarget1DoFActuator.h>
 #include <RobotAPI/components/units/RobotUnit/SensorValues/SensorValue1DoFActuator.h>
 #include <dmp/representation/dmp/umidmp.h>
-#include <RobotAPI/interface/units/RobotUnit/NJointJointSpaceDMPController.h>
+#include <RobotAPI/interface/units/DMPController/NJointJointSpaceDMPController.h>
 
 namespace armarx
 {
@@ -69,6 +69,7 @@ namespace armarx
         struct DebugBufferData
         {
             StringFloatDictionary latestTargetVelocities;
+            StringFloatDictionary dmpTargetState;
             double currentCanVal;
             double mpcFactor;
         };
diff --git a/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointTSDMPController.cpp b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointTSDMPController.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..9480a8c0364636520ff5bc9e0c6a3c7e41a3b0d0
--- /dev/null
+++ b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointTSDMPController.cpp
@@ -0,0 +1,504 @@
+#include "NJointTSDMPController.h"
+
+namespace armarx
+{
+    NJointControllerRegistration<NJointTSDMPController> registrationControllerNJointTSDMPController("NJointTSDMPController");
+
+    NJointTSDMPController::NJointTSDMPController(armarx::NJointControllerDescriptionProviderInterfacePtr prov, const armarx::NJointControllerConfigPtr& config, const VirtualRobot::RobotPtr&)
+    {
+        cfg = NJointTaskSpaceDMPControllerConfigPtr::dynamicCast(config);
+        ARMARX_CHECK_EXPRESSION(prov);
+        RobotUnitPtr robotUnit = RobotUnitPtr::dynamicCast(prov);
+        ARMARX_CHECK_EXPRESSION(robotUnit);
+        ARMARX_CHECK_EXPRESSION(!cfg->nodeSetName.empty());
+        VirtualRobot::RobotNodeSetPtr rns = robotUnit->getRtRobot()->getRobotNodeSet(cfg->nodeSetName);
+
+        ARMARX_CHECK_EXPRESSION_W_HINT(rns, cfg->nodeSetName);
+        for (size_t i = 0; i < rns->getSize(); ++i)
+        {
+            std::string jointName = rns->getNode(i)->getName();
+            ControlTargetBase* ct = prov->getControlTarget(jointName, ControlModes::Velocity1DoF);
+            const SensorValueBase* sv = prov->getSensorValue(jointName);
+            targets.push_back(ct->asA<ControlTarget1DoFActuatorVelocity>());
+
+            const SensorValue1DoFActuatorTorque* torqueSensor = sv->asA<SensorValue1DoFActuatorTorque>();
+            const SensorValue1DoFGravityTorque* gravityTorqueSensor = sv->asA<SensorValue1DoFGravityTorque>();
+            if (!torqueSensor)
+            {
+                ARMARX_WARNING << "No Torque sensor available for " << jointName;
+            }
+            if (!gravityTorqueSensor)
+            {
+                ARMARX_WARNING << "No Gravity Torque sensor available for " << jointName;
+            }
+
+            torqueSensors.push_back(torqueSensor);
+            gravityTorqueSensors.push_back(gravityTorqueSensor);
+        };
+
+        tcp = (cfg->tcpName.empty()) ? rns->getTCP() : robotUnit->getRtRobot()->getRobotNode(cfg->tcpName);
+        ARMARX_CHECK_EXPRESSION_W_HINT(tcp, cfg->tcpName);
+
+        // set tcp controller
+        tcpController.reset(new CartesianVelocityController(rns, tcp));
+        nodeSetName = cfg->nodeSetName;
+        torquePIDs.resize(tcpController->rns->getSize(), pidController());
+
+
+
+        // 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;
+
+        // initialize tcp position and orientation
+        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);
+
+
+        NJointTSDMPControllerSensorData initSensorData;
+        initSensorData.deltaT = 0;
+        initSensorData.currentTime = 0;
+        initSensorData.currentState.resize(6);
+        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.nullspaceJointVelocities.resize(tcpController->rns->getSize(), 0);
+        initData.torqueKp.resize(tcpController->rns->getSize(), 0);
+        initData.torqueKd.resize(tcpController->rns->getSize(), 0);
+        initData.mode = ModeFromIce(cfg->mode);
+        reinitTripleBuffer(initData);
+    }
+
+    std::string NJointTSDMPController::getClassName(const Ice::Current&) const
+    {
+        return "NJointTSDMPController";
+    }
+
+    void NJointTSDMPController::controllerRun()
+    {
+        double mpcFactor = 1;
+        double error = 0;
+        double phaseStop = 0;
+        double posError = 0;
+        double oriError = 0;
+        double deltaT = 0;
+        if (canVal > 1e-8)
+        {
+            if (!controllerSensorData.updateReadBuffer())
+            {
+                return;
+            }
+            deltaT = controllerSensorData.getReadBuffer().deltaT;
+            currentState = controllerSensorData.getReadBuffer().currentState;
+
+
+            for (size_t i = 0; i < 3; ++i)
+            {
+                posError += pow(currentState[i].pos - targetState[i], 2);
+            }
+            for (size_t i = 0; i < 3; ++i)
+            {
+                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 = 0;//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] - tcpPosition[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] - tcpOrientation[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;
+
+
+        debugOutputData.commitWrite();
+
+        LockGuardType guard {controlDataMutex};
+        getWriterControlStruct().targetTSVel = targetVels;
+        writeControlStruct();
+    }
+
+
+    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;
+
+        if (deltaT == 0)
+        {
+            posVel << 0, 0 , 0;
+            oriVel << 0, 0 , 0;
+        }
+        else
+        {
+            posVel = (currPosition - tcpPosition) / deltaT;
+            oriVel = (currOrientation - tcpOrientation) / deltaT;
+        }
+
+        tcpPosition = currPosition;
+        tcpOrientation = currOrientation;
+
+        for (size_t i = 0; i < 3; i++)
+        {
+            DMP::DMPState currentPos;
+            currentPos.pos = tcpPosition(i);
+            currentPos.vel = posVel(i) * timeDuration;
+            controllerSensorData.getWriteBuffer().currentState[i] = currentPos;
+        }
+
+        for (size_t i = 0; i < 3; i++)
+        {
+            DMP::DMPState currentPos;
+            currentPos.pos = tcpOrientation(i);
+            currentPos.vel = oriVel(i) * timeDuration;
+            controllerSensorData.getWriteBuffer().currentState[i + 3] = currentPos;
+        }
+
+        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];
+            }
+
+        }
+        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::VectorXf jointTargetVelocities = tcpController->calculate(x, jnv, mode);
+        for (size_t i = 0; i < targets.size(); ++i)
+        {
+            targets.at(i)->velocity = jointTargetVelocities(i);
+        }
+    }
+
+
+    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);
+
+        ARMARX_INFO << "Learned DMP ... ";
+    }
+
+    void NJointTSDMPController::setViaPoints(Ice::Double u, const Ice::DoubleSeq& viapoint, const Ice::Current&)
+    {
+        ViaPoint viaPoint(u, viapoint);
+
+        LockGuardType guard(controllerMutex);
+        dmpPtr->setViaPoint(viaPoint);
+    }
+
+    void NJointTSDMPController::setGoals(const Ice::DoubleSeq& goals, const Ice::Current& ice)
+    {
+        setViaPoints(dmpPtr->getUMin(), goals, ice);
+    }
+
+    void NJointTSDMPController::setControllerTarget(Ice::Float avoidJointLimitsKp, NJointTaskSpaceDMPControllerMode::CartesianSelection mode, const Ice::Current&)
+    {
+        LockGuardType guard {controlDataMutex};
+        getWriterControlStruct().avoidJointLimitsKp = avoidJointLimitsKp;
+        getWriterControlStruct().mode = ModeFromIce(mode);
+        writeControlStruct();
+    }
+
+    VirtualRobot::IKSolver::CartesianSelection NJointTSDMPController::ModeFromIce(const NJointTaskSpaceDMPControllerMode::CartesianSelection mode)
+    {
+        if (mode == NJointTaskSpaceDMPControllerMode::CartesianSelection::ePosition)
+        {
+            return VirtualRobot::IKSolver::CartesianSelection::Position;
+        }
+        if (mode == NJointTaskSpaceDMPControllerMode::CartesianSelection::eOrientation)
+        {
+            return VirtualRobot::IKSolver::CartesianSelection::Orientation;
+        }
+        if (mode == NJointTaskSpaceDMPControllerMode::CartesianSelection::eAll)
+        {
+            return VirtualRobot::IKSolver::CartesianSelection::All;
+        }
+        ARMARX_ERROR_S << "invalid mode " << mode;
+        return (VirtualRobot::IKSolver::CartesianSelection)0;
+    }
+
+
+    void NJointTSDMPController::setTorqueKp(const StringFloatDictionary& torqueKp, const Ice::Current&)
+    {
+        LockGuardType guard {controlDataMutex};
+        for (size_t i = 0; i < tcpController->rns->getSize(); i++)
+        {
+            getWriterControlStruct().torqueKp.at(i) = torqueKp.at(tcpController->rns->getNode(i)->getName());
+        }
+        writeControlStruct();
+    }
+
+    void NJointTSDMPController::setNullspaceJointVelocities(const StringFloatDictionary& nullspaceJointVelocities, const Ice::Current&)
+    {
+        LockGuardType guard {controlDataMutex};
+        for (size_t i = 0; i < tcpController->rns->getSize(); i++)
+        {
+            getWriterControlStruct().nullspaceJointVelocities.at(i) = nullspaceJointVelocities.at(tcpController->rns->getNode(i)->getName());
+        }
+        writeControlStruct();
+    }
+
+    void NJointTSDMPController::runDMP(const Ice::DoubleSeq&  goals, double tau, const Ice::Current&)
+    {
+        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);
+        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()
+    {
+    }
+
+    void NJointTSDMPController::rtPostDeactivateController()
+    {
+
+    }
+
+    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 dmpTargets = debugOutputData.getUpToDateReadBuffer().dmpTargets;
+        for (auto& pair : dmpTargets)
+        {
+            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);
+
+        debugObs->setDebugChannel("DMPController", datafields);
+    }
+
+    void NJointTSDMPController::onInitComponent()
+    {
+        ARMARX_INFO << "init ...";
+        controllerTask = new PeriodicTask<NJointTSDMPController>(this, &NJointTSDMPController::controllerRun, 1);
+    }
+
+    void NJointTSDMPController::onDisconnectComponent()
+    {
+        controllerTask->stop();
+        ARMARX_INFO << "stopped ...";
+    }
+
+
+
+}
diff --git a/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointTSDMPController.h b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointTSDMPController.h
new file mode 100644
index 0000000000000000000000000000000000000000..ec8d216b992dd30b13edfa6f49b41ad987f897b3
--- /dev/null
+++ b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointTSDMPController.h
@@ -0,0 +1,158 @@
+
+#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/umidmp.h>
+#include <RobotAPI/interface/units/DMPController/NJointTaskSpaceDMPController.h>
+#include <RobotAPI/libraries/core/CartesianVelocityController.h>
+
+
+using namespace DMP;
+namespace armarx
+{
+
+
+    TYPEDEF_PTRS_HANDLE(NJointTSDMPController);
+    TYPEDEF_PTRS_HANDLE(NJointTSDMPControllerControlData);
+
+    typedef std::pair<double, DVec > ViaPoint;
+    typedef std::vector<ViaPoint > ViaPointsSet;
+    class NJointTSDMPControllerControlData
+    {
+    public:
+        std::vector<float> targetTSVel;
+        // cartesian velocity control data
+        std::vector<float> nullspaceJointVelocities;
+        float avoidJointLimitsKp = 0;
+        std::vector<float> torqueKp;
+        std::vector<float> torqueKd;
+        VirtualRobot::IKSolver::CartesianSelection mode = VirtualRobot::IKSolver::All;
+    };
+
+    class pidController
+    {
+    public:
+        float Kp = 0, Kd = 0;
+        float lastError = 0;
+        float update(float dt, float error)
+        {
+            float derivative = (error - lastError) / dt;
+            float retVal = Kp * error + Kd * derivative;
+            lastError = error;
+            return retVal;
+        }
+    };
+
+    class NJointTSDMPController :
+        public NJointControllerWithTripleBuffer<NJointTSDMPControllerControlData>,
+        public NJointTaskSpaceDMPControllerInterface
+    {
+    public:
+        using ConfigPtrT = NJointTaskSpaceDMPControllerConfigPtr;
+        NJointTSDMPController(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);
+
+        // NJointTSDMPControllerInterface interface
+        void learnDMPFromFiles(const Ice::StringSeq& fileNames, const Ice::Current&);
+        bool isFinished(const Ice::Current&)
+        {
+            return finished;
+        }
+
+        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&);
+        void setTorqueKp(const StringFloatDictionary& torqueKp, const Ice::Current&);
+        void setNullspaceJointVelocities(const StringFloatDictionary& nullspaceJointVelocities, const Ice::Current&);
+    protected:
+        void rtPreActivateController() override;
+        void rtPostDeactivateController() override;
+        VirtualRobot::IKSolver::CartesianSelection ModeFromIce(const NJointTaskSpaceDMPControllerMode::CartesianSelection mode);
+        virtual void onPublish(const SensorAndControl&, const DebugDrawerInterfacePrx&, const DebugObserverInterfacePrx&);
+
+        void onInitComponent();
+        void onDisconnectComponent();
+        void controllerRun();
+
+    private:
+        struct DebugBufferData
+        {
+            StringFloatDictionary latestTargetVelocities;
+            StringFloatDictionary dmpTargets;
+            double currentCanVal;
+            double mpcFactor;
+            double error;
+            double phaseStop;
+            double posError;
+            double oriError;
+            double deltaT;
+        };
+
+        TripleBuffer<DebugBufferData> debugOutputData;
+
+        struct NJointTSDMPControllerSensorData
+        {
+            double currentTime;
+            double deltaT;
+            DMP::Vec<DMP::DMPState> currentState;
+        };
+        TripleBuffer<NJointTSDMPControllerSensorData> controllerSensorData;
+
+
+        std::vector<const SensorValue1DoFActuatorTorque*> torqueSensors;
+        std::vector<const SensorValue1DoFGravityTorque*> gravityTorqueSensors;
+        std::vector<ControlTarget1DoFActuatorVelocity*> targets;
+
+        // velocity ik controller parameters
+        std::vector<pidController> torquePIDs;
+        CartesianVelocityControllerPtr tcpController;
+        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;
+
+        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;
+    };
+
+} // namespace armarx
+
diff --git a/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointTaskSpaceDMPController.cpp b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointTaskSpaceDMPController.cpp
index a798bf35c117202ed3b04435467eb420a659d783..f7a2de6fee95c7a188cd816158d88836c974e9c2 100644
--- a/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointTaskSpaceDMPController.cpp
+++ b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointTaskSpaceDMPController.cpp
@@ -67,7 +67,8 @@ namespace armarx
         phaseK = cfg->phaseK;
         phaseDist0 = cfg->phaseDist0;
         phaseDist1 = cfg->phaseDist1;
-        phaseKp = cfg->phaseKp;
+        phaseKpPos = cfg->phaseKpPos;
+        phaseKpOri = cfg->phaseKpOri;
 
         // initialize tcp position and orientation
         Eigen::Matrix4f pose = tcp->getPoseInRootFrame();
@@ -76,6 +77,8 @@ namespace armarx
         tcpPosition(2) = pose(2, 3);
 
         tcpOrientation = VirtualRobot::MathTools::eigen4f2rpy(pose);
+
+        posToOriRatio = cfg->posToOriRatio;
     }
 
     std::string NJointTaskSpaceDMPController::getClassName(const Ice::Current&) const
@@ -85,7 +88,7 @@ namespace armarx
 
     void NJointTaskSpaceDMPController::rtRun(const IceUtil::Time& sensorValuesTimestamp, const IceUtil::Time& timeSinceLastIteration)
     {
-        if (rtGetControlStruct().isStart)
+        if (rtGetControlStruct().isStart && !finished)
         {
             UMIDMPPtr dmpPtr = rtGetControlStruct().dmpPtr;
 
@@ -120,6 +123,9 @@ namespace armarx
             double phaseStop = 0;
             double error = 0;
             currentState.clear();
+
+            double posError = 0;
+            double oriError = 0;
             for (size_t i = 0; i < 3; i++)
             {
                 DMP::DMPState currentPos;
@@ -127,7 +133,7 @@ namespace armarx
                 currentPos.vel = posVel(i) * timeDuration;
                 currentState.push_back(currentPos);
 
-                error += pow(currentPos.pos - targetState[i], 2);
+                posError += pow(currentPos.pos - targetState[i], 2);
             }
 
             for (size_t i = 0; i < 3; i++)
@@ -137,10 +143,11 @@ namespace armarx
                 currentPos.vel = oriVel(i) * timeDuration;
                 currentState.push_back(currentPos);
 
-                error += pow(currentPos.pos - targetState[i + 3], 2);
+                oriError += pow(currentPos.pos - targetState[i + 3], 2);
             }
 
-            error = sqrt(error);
+
+            error = sqrt(posError + posToOriRatio * oriError);
 
             double phaseDist;
             if (isDisturbance)
@@ -187,14 +194,14 @@ namespace armarx
                 for (size_t i = 0; i < 3; i++)
                 {
                     vel0 = currentState[i].vel / timeDuration;
-                    vel1 = phaseKp * (targetState[i] - tcpPosition[i]);
+                    vel1 = phaseKpPos * (targetState[i] - tcpPosition[i]);
                     x(i) = mpcFactor * vel0 + (1 - mpcFactor) * vel1;
 
                 }
                 for (size_t i = 0; i < 3; i++)
                 {
                     vel0 = currentState[i + 3].vel / timeDuration;
-                    vel1 = phaseKp * (targetState[i + 3] - tcpOrientation[i]);
+                    vel1 = phaseKpOri * (targetState[i + 3] - tcpOrientation[i]);
                     x(i + 3) = mpcFactor * vel0 + (1 - mpcFactor) * vel1;
                 }
 
@@ -216,7 +223,7 @@ namespace armarx
                 for (size_t i = 0; i < 3; i++)
                 {
                     vel0 = currentState[i].vel / timeDuration;
-                    vel1 = phaseKp * (targetState[i] - tcpPosition[i]);
+                    vel1 = phaseKpPos * (targetState[i] - tcpPosition[i]);
                     x(i) = mpcFactor * vel0 + (1 - mpcFactor) * vel1;
                 }
 
@@ -234,7 +241,7 @@ namespace armarx
                 for (size_t i = 0; i < 3; i++)
                 {
                     vel0 = currentState[i + 3].vel / timeDuration;
-                    vel1 = phaseKp * (targetState[i + 3] - tcpOrientation[i]);
+                    vel1 = phaseKpOri * (targetState[i + 3] - tcpOrientation[i]);
                     x(i) = mpcFactor * vel0 + (1 - mpcFactor) * vel1;
                 }
 
@@ -281,6 +288,13 @@ namespace armarx
                 targets.at(i)->velocity = jointTargetVelocities(i);
             }
         }
+        else
+        {
+            for (size_t i = 0; i < targets.size(); ++i)
+            {
+                targets.at(i)->velocity = 0;
+            }
+        }
     }
 
 
@@ -354,7 +368,7 @@ namespace armarx
         return (VirtualRobot::IKSolver::CartesianSelection)0;
     }
 
-    void NJointTaskSpaceDMPController::onPublish(const SensorAndControl &, const DebugDrawerInterfacePrx &, const DebugObserverInterfacePrx &debugObs)
+    void NJointTaskSpaceDMPController::onPublish(const SensorAndControl&, const DebugDrawerInterfacePrx&, const DebugObserverInterfacePrx& debugObs)
     {
         StringVariantBaseMap datafields;
         auto values = debugOutputData.getUpToDateReadBuffer().latestTargetVelocities;
diff --git a/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointTaskSpaceDMPController.h b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointTaskSpaceDMPController.h
index d133d81bb3955192594d5216ebce264d66c603b6..d45c8ce03449c3a2c1694269563a4618a657220c 100644
--- a/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointTaskSpaceDMPController.h
+++ b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointTaskSpaceDMPController.h
@@ -8,7 +8,7 @@
 #include <RobotAPI/components/units/RobotUnit/SensorValues/SensorValue1DoFActuator.h>
 #include <VirtualRobot/IK/DifferentialIK.h>
 #include <dmp/representation/dmp/umidmp.h>
-#include <RobotAPI/interface/units/RobotUnit/NJointTaskSpaceDMPController.h>
+#include <RobotAPI/interface/units/DMPController/NJointTaskSpaceDMPController.h>
 #include <RobotAPI/libraries/core/CartesianVelocityController.h>
 
 
@@ -120,7 +120,9 @@ namespace armarx
         double phaseK;
         double phaseDist0;
         double phaseDist1;
-        double phaseKp;
+        double phaseKpPos;
+        double phaseKpOri;
+        double posToOriRatio;
 
 
         bool isDisturbance;