diff --git a/source/RobotAPI/components/units/RobotUnit/CMakeLists.txt b/source/RobotAPI/components/units/RobotUnit/CMakeLists.txt
index 63d1b4d00926aed6ab6ae1eeea46d7f6281c8214..f2d1ec328e91bd315d5f74bf0ab8879b85e112c0 100644
--- a/source/RobotAPI/components/units/RobotUnit/CMakeLists.txt
+++ b/source/RobotAPI/components/units/RobotUnit/CMakeLists.txt
@@ -54,6 +54,8 @@ set(LIB_FILES
     NJointControllers/NJointTCPController.cpp
     NJointControllers/NJointCartesianVelocityController.cpp
     NJointControllers/NJointCartesianTorqueController.cpp
+    NJointControllers/NJointTaskSpaceImpedanceController.cpp
+    NJointControllers/NJointCartesianVelocityControllerWithRamp.cpp
     #NJointControllers/NJointCartesianActiveImpedanceController.cpp
 
     Devices/SensorDevice.cpp
@@ -116,6 +118,7 @@ set(LIB_HEADERS
     NJointControllers/NJointTCPController.h
     NJointControllers/NJointCartesianVelocityController.h
     NJointControllers/NJointCartesianTorqueController.h
+    NJointControllers/NJointCartesianVelocityControllerWithRamp.h
     #NJointControllers/NJointCartesianActiveImpedanceController.h
 
     Devices/DeviceBase.h
diff --git a/source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointCartesianVelocityControllerWithRamp.cpp b/source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointCartesianVelocityControllerWithRamp.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..63ea69e0d6780409e3d2d9e7b875320df55097b2
--- /dev/null
+++ b/source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointCartesianVelocityControllerWithRamp.cpp
@@ -0,0 +1,359 @@
+/*
+ * This file is part of ArmarX.
+ *
+ * Copyright (C) 2011-2017, High Performance Humanoid Technologies (H2T), Karlsruhe Institute of Technology (KIT), all rights reserved.
+ *
+ * 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    ArmarX
+ * @author     Sonja Marahrens( sonja.marahrens at kit dot edu)
+ * @date       2018
+ * @copyright  http://www.gnu.org/licenses/gpl-2.0.txt
+ *             GNU General Public License
+ */
+#include "NJointCartesianVelocityControllerWithRamp.h"
+#include <VirtualRobot/RobotNodeSet.h>
+#include "../RobotUnit.h"
+
+#define DEFAULT_TCP_STRING "default TCP"
+
+namespace armarx
+{
+
+    NJointControllerRegistration<NJointCartesianVelocityControllerWithRamp> registrationControllerNJointCartesianVelocityControllerWithRamp("NJointCartesianVelocityControllerWithRamp");
+
+    std::string NJointCartesianVelocityControllerWithRamp::getClassName(const Ice::Current&) const
+    {
+        return "NJointCartesianVelocityControllerWithRamp";
+    }
+
+    NJointCartesianVelocityControllerWithRamp::NJointCartesianVelocityControllerWithRamp(
+        NJointControllerDescriptionProviderInterfacePtr prov,
+        const NJointCartesianVelocityControllerWithRampConfigPtr& config,
+        const boost::shared_ptr<VirtualRobot::Robot>& r)
+    {
+        ARMARX_CHECK_EXPRESSION(prov);
+        RobotUnitPtr robotUnit = RobotUnitPtr::dynamicCast(prov);
+        ARMARX_CHECK_EXPRESSION(robotUnit);
+        ARMARX_CHECK_EXPRESSION(!config->nodeSetName.empty());
+        VirtualRobot::RobotNodeSetPtr rns = robotUnit->getRtRobot()->getRobotNodeSet(config->nodeSetName);
+        ARMARX_CHECK_EXPRESSION_W_HINT(rns, config->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 SensorValue1DoFActuatorFilteredVelocity* filteredVelocitySensor = sv->asA<SensorValue1DoFActuatorFilteredVelocity>();
+            const SensorValue1DoFActuatorVelocity* velocitySensor = sv->asA<SensorValue1DoFActuatorVelocity>();
+            ARMARX_CHECK_EXPRESSION(filteredVelocitySensor || velocitySensor);
+            if (filteredVelocitySensor)
+            {
+                velocitySensors.push_back(&filteredVelocitySensor->filteredvelocity);
+            }
+            else if (velocitySensor)
+            {
+                velocitySensors.push_back(&velocitySensor->velocity);
+            }
+
+        };
+
+        VirtualRobot::RobotNodePtr tcp = (config->tcpName.empty() || config->tcpName == DEFAULT_TCP_STRING) ? rns->getTCP() : robotUnit->getRtRobot()->getRobotNode(config->tcpName);
+        ARMARX_CHECK_EXPRESSION_W_HINT(tcp, config->tcpName);
+
+        nodeSetName = config->nodeSetName;
+        jointLimitAvoidanceScale = config->jointLimitAvoidanceScale;
+        KpJointLimitAvoidance = config->KpJointLimitAvoidance;
+        mode = ModeFromIce(config->mode);
+
+        controller.reset(new CartesianVelocityControllerWithRamp(rns, Eigen::VectorXf::Zero(rns->getSize()), mode,
+                         config->maxPositionAcceleration, config->maxOrientationAcceleration, config->maxNullspaceAcceleration));
+    }
+
+
+    void NJointCartesianVelocityControllerWithRamp::rtPreActivateController()
+    {
+        ARMARX_IMPORTANT << "rtPreActivateController start";
+        Eigen::VectorXf currentJointVelocities(velocitySensors.size());
+        for (size_t i = 0; i < velocitySensors.size(); i++)
+        {
+            currentJointVelocities(i) = *velocitySensors.at(i);
+        }
+        controller->setCurrentJointVelocity(currentJointVelocities);
+        ARMARX_IMPORTANT << "rtPreActivateController end";
+    }
+
+    void NJointCartesianVelocityControllerWithRamp::rtRun(const IceUtil::Time& sensorValuesTimestamp, const IceUtil::Time& timeSinceLastIteration)
+    {
+        Eigen::VectorXf x;
+        if (mode == VirtualRobot::IKSolver::All)
+        {
+            x.resize(6);
+            x << rtGetControlStruct().xVel, rtGetControlStruct().yVel, rtGetControlStruct().zVel, rtGetControlStruct().rollVel, rtGetControlStruct().pitchVel, rtGetControlStruct().yawVel;
+        }
+        else if (mode == VirtualRobot::IKSolver::Position)
+        {
+            x.resize(3);
+            x << rtGetControlStruct().xVel, rtGetControlStruct().yVel, rtGetControlStruct().zVel;
+        }
+        else if (mode == VirtualRobot::IKSolver::Orientation)
+        {
+            x.resize(3);
+            x << rtGetControlStruct().rollVel, rtGetControlStruct().pitchVel, rtGetControlStruct().yawVel;
+        }
+        else
+        {
+            // No mode has been set
+            return;
+        }
+
+        Eigen::VectorXf jnv = KpJointLimitAvoidance * controller->controller.calculateJointLimitAvoidance();
+        jnv += controller->controller.calculateNullspaceVelocity(x, jointLimitAvoidanceScale, mode);
+        Eigen::VectorXf jointTargetVelocities = controller->calculate(x, jnv, timeSinceLastIteration.toSecondsDouble());
+        for (size_t i = 0; i < targets.size(); ++i)
+        {
+            targets.at(i)->velocity = jointTargetVelocities(i);
+        }
+    }
+
+
+
+    void NJointCartesianVelocityControllerWithRamp::setMaxAccelerations(float maxPositionAcceleration, float maxOrientationAcceleration, float maxNullspaceAcceleration, const Ice::Current&)
+    {
+        controller->setMaxAccelerations(maxPositionAcceleration, maxOrientationAcceleration, maxNullspaceAcceleration);
+    }
+
+    void NJointCartesianVelocityControllerWithRamp::setTargetVelocity(float vx, float vy, float vz, float vrx, float vry, float vrz, const Ice::Current&)
+    {
+        //Template --> anpassen
+        LockGuardType guard {controlDataMutex};
+        getWriterControlStruct().xVel = vx;
+        getWriterControlStruct().yVel = vy;
+        getWriterControlStruct().zVel = vz;
+        getWriterControlStruct().rollVel = vrx;
+        getWriterControlStruct().pitchVel = vry;
+        getWriterControlStruct().yawVel = vrz;
+        writeControlStruct();
+    }
+
+    void NJointCartesianVelocityControllerWithRamp::setJointLimitAvoidanceScale(float jointLimitAvoidanceScale, const Ice::Current&)
+    {
+        this->jointLimitAvoidanceScale = jointLimitAvoidanceScale;
+    }
+
+    void NJointCartesianVelocityControllerWithRamp::setKpJointLimitAvoidance(float KpJointLimitAvoidance, const Ice::Current&)
+    {
+        this->KpJointLimitAvoidance = KpJointLimitAvoidance;
+    }
+
+
+
+    void NJointCartesianVelocityControllerWithRamp::rtPostDeactivateController()
+    {
+
+    }
+
+    WidgetDescription::StringWidgetDictionary NJointCartesianVelocityControllerWithRamp::getFunctionDescriptions(const Ice::Current&) const
+    {
+        return
+        {
+            {"ControllerTarget", createTargetLayout()},
+            {"ControllerParameters", createParameterLayout()}
+        };
+    }
+
+    void NJointCartesianVelocityControllerWithRamp::callDescribedFunction(const std::string& name, const StringVariantBaseMap& valueMap, const Ice::Current&)
+    {
+        if (name == "ControllerTarget")
+        {
+            LockGuardType guard {controlDataMutex};
+            getWriterControlStruct().xVel = valueMap.at("x")->getFloat();
+            getWriterControlStruct().yVel = valueMap.at("y")->getFloat();
+            getWriterControlStruct().zVel = valueMap.at("z")->getFloat();
+            getWriterControlStruct().rollVel = valueMap.at("roll")->getFloat();
+            getWriterControlStruct().pitchVel = valueMap.at("pitch")->getFloat();
+            getWriterControlStruct().yawVel = valueMap.at("yaw")->getFloat();
+            KpJointLimitAvoidance = valueMap.at("KpJointLimitAvoidance")->getFloat();
+            jointLimitAvoidanceScale = valueMap.at("jointLimitAvoidanceScale")->getFloat();
+            writeControlStruct();
+        }
+        else if (name == "ControllerParameters")
+        {
+            LockGuardType guard {controlDataMutex};
+            setMaxAccelerations(valueMap.at("maxPositionAcceleration")->getFloat(),
+                                valueMap.at("maxOrientationAcceleration")->getFloat(),
+                                valueMap.at("maxNullspaceAcceleration")->getFloat());
+        }
+        else
+        {
+            ARMARX_WARNING << "Unknown function name called: " << name;
+        }
+    }
+
+    WidgetDescription::VBoxLayoutPtr NJointCartesianVelocityControllerWithRamp::createTargetLayout() const
+    {
+        LayoutBuilder layout;
+        layout.addSlider("x", -100, 100, 0);
+        layout.addSlider("y", -100, 100, 0);
+        layout.addSlider("z", -100, 100, 0);
+        layout.addSlider("roll", -0.5, 0.5, 0);
+        layout.addSlider("pitch", -0.5, 0.5, 0);
+        layout.addSlider("yaw", -0.5, 0.5, 0);
+        layout.newLine();
+        layout.addSlider("KpJointLimitAvoidance", -10, 10, KpJointLimitAvoidance);
+        layout.addSlider("jointLimitAvoidanceScale", -10, 10, jointLimitAvoidanceScale);
+        return layout.getLayout();
+    }
+    WidgetDescription::VBoxLayoutPtr NJointCartesianVelocityControllerWithRamp::createParameterLayout() const
+    {
+        LayoutBuilder layout;
+        layout.addSlider("maxPositionAcceleration", 0, 1000, controller->getMaxPositionAcceleration());
+        layout.addSlider("maxOrientationAcceleration", 0, 100, controller->getMaxOrientationAcceleration());
+        layout.addSlider("maxNullspaceAcceleration", 0, 100, controller->getMaxNullspaceAcceleration());
+        return layout.getLayout();
+    }
+
+
+    WidgetDescription::WidgetPtr NJointCartesianVelocityControllerWithRamp::GenerateConfigDescription(const boost::shared_ptr<VirtualRobot::Robot>& robot, const std::map<std::string, ConstControlDevicePtr>& controlDevices, const std::map<std::string, ConstSensorDevicePtr>&)
+    {
+        using namespace armarx::WidgetDescription;
+        HBoxLayoutPtr layout = new HBoxLayout;
+
+        LabelPtr label = new Label;
+        label->text = "nodeset name";
+        layout->children.emplace_back(label);
+        StringComboBoxPtr box = new StringComboBox;
+        box->defaultIndex = 0;
+
+        box->options = robot->getRobotNodeSetNames();
+        box->name = "nodeSetName";
+        layout->children.emplace_back(box);
+
+        LabelPtr labelTCP = new Label;
+        labelTCP->text = "tcp name";
+        layout->children.emplace_back(labelTCP);
+        StringComboBoxPtr boxTCP = new StringComboBox;
+        boxTCP->defaultIndex = 0;
+
+        boxTCP->options = robot->getRobotNodeNames();
+        boxTCP->options.insert(boxTCP->options.begin(), DEFAULT_TCP_STRING);
+        boxTCP->name = "tcpName";
+        layout->children.emplace_back(boxTCP);
+
+        LabelPtr labelMode = new Label;
+        labelMode->text = "mode";
+        layout->children.emplace_back(labelMode);
+        StringComboBoxPtr boxMode = new StringComboBox;
+
+        boxMode->options = {"Position", "Orientation", "Both"};
+        boxMode->name = "mode";
+        layout->children.emplace_back(boxMode);
+        layout->children.emplace_back(new HSpacer);
+        boxMode->defaultIndex = 2;
+
+
+        auto addSlider = [&](const std::string & label, float max, float defaultValue)
+        {
+            layout->children.emplace_back(new Label(false, label));
+            FloatSliderPtr floatSlider = new FloatSlider;
+            floatSlider->name = label;
+            floatSlider->min = 0;
+            floatSlider->defaultValue = defaultValue;
+            floatSlider->max = max;
+            layout->children.emplace_back(floatSlider);
+        };
+        addSlider("maxPositionAcceleration", 1000, 100);
+        addSlider("maxOrientationAcceleration", 10, 1);
+        addSlider("maxNullspaceAcceleration", 10, 2);
+        addSlider("KpJointLimitAvoidance", 10, 2);
+        addSlider("jointLimitAvoidanceScale", 10, 2);
+
+        return layout;
+    }
+
+    NJointCartesianVelocityControllerWithRampConfigPtr NJointCartesianVelocityControllerWithRamp::GenerateConfigFromVariants(const StringVariantBaseMap& values)
+    {
+        return new NJointCartesianVelocityControllerWithRampConfig(values.at("nodeSetName")->getString(), values.at("tcpName")->getString(),
+                IceModeFromString(values.at("mode")->getString()),
+                values.at("maxPositionAcceleration")->getFloat(),
+                values.at("maxOrientationAcceleration")->getFloat(),
+                values.at("maxNullspaceAcceleration")->getFloat(),
+                values.at("KpJointLimitAvoidance")->getFloat(),
+                values.at("jointLimitAvoidanceScale")->getFloat());
+    }
+
+    VirtualRobot::IKSolver::CartesianSelection NJointCartesianVelocityControllerWithRamp::ModeFromString(const std::string mode)
+    {
+        //ARMARX_IMPORTANT_S << "the mode is " << mode;
+        if (mode == "Position")
+        {
+            return VirtualRobot::IKSolver::CartesianSelection::Position;
+        }
+        if (mode == "Orientation")
+        {
+            return VirtualRobot::IKSolver::CartesianSelection::Orientation;
+        }
+        if (mode == "Both")
+        {
+            return VirtualRobot::IKSolver::CartesianSelection::All;
+        }
+        ARMARX_ERROR_S << "invalid mode " << mode;
+        return (VirtualRobot::IKSolver::CartesianSelection)0;
+    }
+
+    CartesianSelectionMode::CartesianSelection NJointCartesianVelocityControllerWithRamp::IceModeFromString(const std::string mode)
+    {
+        if (mode == "Position")
+        {
+            return CartesianSelectionMode::CartesianSelection::ePosition;
+        }
+        if (mode == "Orientation")
+        {
+            return CartesianSelectionMode::CartesianSelection::eOrientation;
+        }
+        if (mode == "Both")
+        {
+            return CartesianSelectionMode::CartesianSelection::eAll;
+        }
+        ARMARX_ERROR_S << "invalid mode " << mode;
+        return (CartesianSelectionMode::CartesianSelection)0;
+    }
+
+    VirtualRobot::IKSolver::CartesianSelection NJointCartesianVelocityControllerWithRamp::ModeFromIce(const CartesianSelectionMode::CartesianSelection mode)
+    {
+        if (mode == CartesianSelectionMode::CartesianSelection::ePosition)
+        {
+            return VirtualRobot::IKSolver::CartesianSelection::Position;
+        }
+        if (mode == CartesianSelectionMode::CartesianSelection::eOrientation)
+        {
+            return VirtualRobot::IKSolver::CartesianSelection::Orientation;
+        }
+        if (mode == CartesianSelectionMode::CartesianSelection::eAll)
+        {
+            return VirtualRobot::IKSolver::CartesianSelection::All;
+        }
+        ARMARX_ERROR_S << "invalid mode " << mode;
+        return (VirtualRobot::IKSolver::CartesianSelection)0;
+    }
+
+
+
+
+} // namespace armarx
+
+
+
+
+
diff --git a/source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointCartesianVelocityControllerWithRamp.h b/source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointCartesianVelocityControllerWithRamp.h
new file mode 100644
index 0000000000000000000000000000000000000000..f93dc8e184220fcef3496722eeffdcec16e46c35
--- /dev/null
+++ b/source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointCartesianVelocityControllerWithRamp.h
@@ -0,0 +1,144 @@
+/*
+ * This file is part of ArmarX.
+ *
+ * Copyright (C) 2011-2017, High Performance Humanoid Technologies (H2T), Karlsruhe Institute of Technology (KIT), all rights reserved.
+ *
+ * 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    ArmarX
+ * @author     Sonja Marahrens( sonja.marahrens at kit dot edu)
+ * @date       2018
+ * @copyright  http://www.gnu.org/licenses/gpl-2.0.txt
+ *             GNU General Public License
+ */
+#pragma once
+
+
+#include "NJointController.h"
+#include <VirtualRobot/Robot.h>
+#include "../RobotUnit.h"
+#include "../ControlTargets/ControlTarget1DoFActuator.h"
+#include "../SensorValues/SensorValue1DoFActuator.h"
+#include <VirtualRobot/IK/DifferentialIK.h>
+#include <RobotAPI/libraries/core/CartesianVelocityControllerWithRamp.h>
+#include <RobotAPI/interface/units/RobotUnit/NJointCartesianVelocityControllerWithRamp.h>
+
+namespace armarx
+{
+
+    TYPEDEF_PTRS_HANDLE(NJointCartesianVelocityControllerWithRamp);
+
+
+    class NJointCartesianVelocityControllerWithRampControlData
+    {
+    public:
+        float xVel = 0;
+        float yVel = 0;
+        float zVel = 0;
+        float rollVel = 0;
+        float pitchVel = 0;
+        float yawVel = 0;
+    };
+
+    class LayoutBuilder
+    {
+        WidgetDescription::VBoxLayoutPtr vlayout = new WidgetDescription::VBoxLayout;
+        WidgetDescription::HBoxLayoutPtr hlayout;
+    public:
+        LayoutBuilder()
+        {
+            newLine();
+        }
+
+        void newLine()
+        {
+            using namespace WidgetDescription;
+            hlayout = new HBoxLayout;
+            vlayout->children.emplace_back(hlayout);
+        }
+
+        void addSlider(const std::string& label, float min, float max, float value)
+        {
+            using namespace WidgetDescription;
+            hlayout->children.emplace_back(new Label(false, label));
+            FloatSliderPtr slider = new FloatSlider;
+            slider->name = label;
+            slider->min = min;
+            slider->defaultValue = value;
+            slider->max = max;
+            hlayout->children.emplace_back(slider);
+        }
+
+        WidgetDescription::VBoxLayoutPtr getLayout() const
+        {
+            return vlayout;
+        }
+
+    };
+
+
+
+    class NJointCartesianVelocityControllerWithRamp :
+        public NJointControllerWithTripleBuffer<NJointCartesianVelocityControllerWithRampControlData>,
+        public NJointCartesianVelocityControllerWithRampInterface
+    {
+    public:
+        using ConfigPtrT = NJointCartesianVelocityControllerWithRampConfigPtr;
+        NJointCartesianVelocityControllerWithRamp(NJointControllerDescriptionProviderInterfacePtr prov, const NJointCartesianVelocityControllerWithRampConfigPtr& config, const VirtualRobot::RobotPtr&);
+
+        // NJointControllerInterface interface
+        std::string getClassName(const Ice::Current&) const override;
+
+        // NJointController interface
+        void rtRun(const IceUtil::Time& sensorValuesTimestamp, const IceUtil::Time& timeSinceLastIteration) override;
+
+        static WidgetDescription::WidgetPtr GenerateConfigDescription(
+            const boost::shared_ptr<VirtualRobot::Robot>&,
+            const std::map<std::string, ConstControlDevicePtr>&,
+            const std::map<std::string, ConstSensorDevicePtr>&);
+        static NJointCartesianVelocityControllerWithRampConfigPtr GenerateConfigFromVariants(const StringVariantBaseMap& values);
+        WidgetDescription::StringWidgetDictionary getFunctionDescriptions(const Ice::Current&) const override;
+        void callDescribedFunction(const std::string& name, const StringVariantBaseMap& valueMap, const Ice::Current&) override;
+        WidgetDescription::VBoxLayoutPtr createTargetLayout() const;
+        WidgetDescription::VBoxLayoutPtr createParameterLayout() const;
+
+        static VirtualRobot::IKSolver::CartesianSelection ModeFromString(const std::string mode);
+        static CartesianSelectionMode::CartesianSelection IceModeFromString(const std::string mode);
+        static VirtualRobot::IKSolver::CartesianSelection ModeFromIce(const CartesianSelectionMode::CartesianSelection mode);
+
+    protected:
+        void rtPreActivateController() override;
+        void rtPostDeactivateController() override;
+    private:
+        std::vector<ControlTarget1DoFActuatorVelocity*> targets;
+        //std::vector<const SensorValue1DoFActuatorPosition*> sensors;
+        std::vector<const float*> velocitySensors;
+
+        std::string nodeSetName;
+        float jointLimitAvoidanceScale;
+        float KpJointLimitAvoidance;
+        VirtualRobot::IKSolver::CartesianSelection mode = VirtualRobot::IKSolver::All;
+
+        CartesianVelocityControllerWithRampPtr controller;
+
+
+        // NJointCartesianVelocityControllerWithRampInterface interface
+    public:
+        void setMaxAccelerations(float maxPositionAcceleration, float maxOrientationAcceleration, float maxNullspaceAcceleration, const Ice::Current& = Ice::Current()) override;
+        void setTargetVelocity(float vx, float vy, float vz, float vrx, float vry, float vrz, const Ice::Current&) override;
+        void setJointLimitAvoidanceScale(float jointLimitAvoidanceScale, const Ice::Current&) override;
+        void setKpJointLimitAvoidance(float KpJointLimitAvoidance, const Ice::Current&) override;
+    };
+
+} // namespace armarx
+
diff --git a/source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointTaskSpaceImpedanceController.cpp b/source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointTaskSpaceImpedanceController.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f73d4af4150497a0eabfd70200a03340ed578945
--- /dev/null
+++ b/source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointTaskSpaceImpedanceController.cpp
@@ -0,0 +1,236 @@
+/*
+ * 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    TaskSpaceActiveImpedanceControl::ArmarXObjects::NJointTaskSpaceImpedanceController
+ * @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 "NJointTaskSpaceImpedanceController.h"
+
+
+using namespace armarx;
+
+NJointControllerRegistration<NJointTaskSpaceImpedanceController> registrationControllerDSRTController("NJointTaskSpaceImpedanceController");
+
+
+NJointTaskSpaceImpedanceController::NJointTaskSpaceImpedanceController(NJointControllerDescriptionProviderInterfacePtr prov, const NJointControllerConfigPtr& config, const VirtualRobot::RobotPtr&)
+{
+
+    NJointTaskSpaceImpedanceControlConfigPtr cfg = NJointTaskSpaceImpedanceControlConfigPtr::dynamicCast(config);
+
+    ARMARX_CHECK_EXPRESSION(cfg);
+    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);
+
+    jointNames.clear();
+    ARMARX_CHECK_EXPRESSION_W_HINT(rns, cfg->nodeSetName);
+    for (size_t i = 0; i < rns->getSize(); ++i)
+    {
+        std::string jointName = rns->getNode(i)->getName();
+        jointNames.push_back(jointName);
+        ControlTargetBase* ct = prov->getControlTarget(jointName, ControlModes::Torque1DoF);
+        ARMARX_CHECK_EXPRESSION(ct);
+        const SensorValueBase* sv = prov->getSensorValue(jointName);
+        ARMARX_CHECK_EXPRESSION(sv);
+        auto casted_ct = ct->asA<ControlTarget1DoFActuatorTorque>();
+        ARMARX_CHECK_EXPRESSION(casted_ct);
+        targets.push_back(casted_ct);
+
+        const SensorValue1DoFActuatorTorque* torqueSensor = sv->asA<SensorValue1DoFActuatorTorque>();
+        const SensorValue1DoFActuatorVelocity* velocitySensor = sv->asA<SensorValue1DoFActuatorVelocity>();
+        const SensorValue1DoFActuatorPosition* positionSensor = sv->asA<SensorValue1DoFActuatorPosition>();
+        if (!torqueSensor)
+        {
+            ARMARX_WARNING << "No Torque sensor available for " << jointName;
+        }
+
+
+        torqueSensors.push_back(torqueSensor);
+        velocitySensors.push_back(velocitySensor);
+        positionSensors.push_back(positionSensor);
+    };
+    tcp = rns->getTCP();
+    ik.reset(new VirtualRobot::DifferentialIK(rns, rns->getRobot()->getRootNode(), VirtualRobot::JacobiProvider::eSVDDamped));
+
+    ARMARX_CHECK_EQUAL(cfg->desiredPose.size(), 7);
+    desiredPosition(0) = cfg->desiredPose[0];
+    desiredPosition(1) = cfg->desiredPose[1];
+    desiredPosition(2) = cfg->desiredPose[2];
+
+    desiredQuaternion.w() = cfg->desiredPose[3];
+    desiredQuaternion.x() = cfg->desiredPose[4];
+    desiredQuaternion.y() = cfg->desiredPose[5];
+    desiredQuaternion.z() = cfg->desiredPose[6];
+    //    desiredTwist = cfg->desiredTwist;
+    //    ARMARX_CHECK_EQUAL(desiredPose.rows(), 6);
+
+
+    ARMARX_CHECK_EQUAL(cfg->Kpos.size(), 3);
+    ARMARX_CHECK_EQUAL(cfg->Dpos.size(), 3);
+    ARMARX_CHECK_EQUAL(cfg->Kori.size(), 3);
+    ARMARX_CHECK_EQUAL(cfg->Dori.size(), 3);
+
+    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];
+
+    torqueLimit = cfg->torqueLimit;
+
+    desiredJointPosition.resize(targets.size());
+
+    ARMARX_CHECK_EQUAL(cfg->desiredJointPositions.size(), targets.size());
+
+    for (size_t i = 0; i < targets.size(); ++i)
+    {
+        desiredJointPosition(i) = cfg->desiredJointPositions.at(i);
+    }
+
+
+    knull = cfg->Knull;
+    dnull = cfg->Dnull;
+
+    NJointTaskSpaceImpedanceControllerControlData initData;
+    initData.desiredPose.resize(7);
+    initData.desiredPose.setZero();
+    initData.desiredTwist.resize(6);
+    initData.desiredTwist.setZero();
+
+    reinitTripleBuffer(initData);
+}
+
+void NJointTaskSpaceImpedanceController::rtRun(const IceUtil::Time& sensorValuesTimestamp, const IceUtil::Time& timeSinceLastIteration)
+{
+    Eigen::MatrixXf jacobi = ik->getJacobianMatrix(tcp, VirtualRobot::IKSolver::CartesianSelection::All);
+
+    Eigen::VectorXf qpos;
+    Eigen::VectorXf qvel;
+    qpos.resize(positionSensors.size());
+    qvel.resize(velocitySensors.size());
+
+    int jointDim = positionSensors.size();
+
+    for (size_t i = 0; i < velocitySensors.size(); ++i)
+    {
+        qpos(i) = positionSensors[i]->position;
+        qvel(i) = velocitySensors[i]->velocity;
+    }
+
+    Eigen::VectorXf tcptwist = jacobi * qvel;
+
+    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 = tcp->getPositionInRootFrame();
+    Eigen::Vector3f tcpForces = 0.001 * kpos.cwiseProduct(desiredPosition - currentTCPPosition);
+    Eigen::Vector3f tcpDesiredForce = tcpForces - dpos.cwiseProduct(currentTCPLinearVelocity);
+
+    Eigen::Matrix4f currentTCPPose = tcp->getPoseInRootFrame();
+    Eigen::Matrix3f currentRotMat = currentTCPPose.block<3, 3>(0, 0);
+    Eigen::Matrix3f desiredMat(desiredQuaternion);
+    Eigen::Matrix3f diffMat = desiredMat * currentRotMat.inverse();
+    Eigen::Quaternionf cquat(currentRotMat);
+    //    Eigen::Quaternionf diffQuaternion = desiredQuaternion * cquat.conjugate();
+    //    Eigen::AngleAxisf angleAxis(diffQuaternion);
+
+    Eigen::Vector3f rpy = VirtualRobot::MathTools::eigen3f2rpy(diffMat);
+
+    Eigen::Vector3f tcpDesiredTorque = kori.cwiseProduct(rpy) - dori.cwiseProduct(currentTCPAngularVelocity);
+    Eigen::Vector6f tcpDesiredWrench;
+    tcpDesiredWrench <<   0.001 * tcpDesiredForce, tcpDesiredTorque;
+
+    // calculate desired joint torque
+    Eigen::MatrixXf I = Eigen::MatrixXf::Identity(jointDim, jointDim);
+
+    float lambda = 2;
+
+    Eigen::MatrixXf jtpinv = ik->computePseudoInverseJacobianMatrix(jacobi.transpose(), lambda);
+
+    Eigen::VectorXf nullqerror = desiredJointPosition - qpos;
+
+    for (int i = 0; i < nullqerror.rows(); ++i)
+    {
+        if (fabs(nullqerror(i)) < 0.09)
+        {
+            nullqerror(i) = 0;
+        }
+    }
+    Eigen::VectorXf nullspaceTorque = knull * nullqerror - dnull * qvel;
+
+    Eigen::VectorXf jointDesiredTorques = jacobi.transpose() * tcpDesiredWrench + (I - jacobi.transpose() * jtpinv) * nullspaceTorque;
+
+    for (size_t i = 0; i < targets.size(); ++i)
+    {
+        float desiredTorque = jointDesiredTorques(i);
+
+        desiredTorque = (desiredTorque >  torqueLimit) ? torqueLimit : desiredTorque;
+        desiredTorque = (desiredTorque < -torqueLimit) ? -torqueLimit : desiredTorque;
+
+        debugDataInfo.getWriteBuffer().desired_torques[jointNames[i]] = jointDesiredTorques(i);
+
+        targets.at(i)->torque = desiredTorque;
+    }
+
+
+    float errorAngle = cquat.angularDistance(desiredQuaternion);
+    float posiError = (desiredPosition - currentTCPPosition).norm();
+
+    debugDataInfo.getWriteBuffer().desiredForce_x = tcpDesiredForce(0);
+    debugDataInfo.getWriteBuffer().desiredForce_y = tcpDesiredForce(1);
+    debugDataInfo.getWriteBuffer().desiredForce_z = tcpDesiredForce(2);
+    debugDataInfo.getWriteBuffer().tcpDesiredTorque_x = tcpDesiredTorque(0);
+    debugDataInfo.getWriteBuffer().tcpDesiredTorque_y = tcpDesiredTorque(1);
+    debugDataInfo.getWriteBuffer().tcpDesiredTorque_z = tcpDesiredTorque(2);
+    debugDataInfo.getWriteBuffer().quatError = errorAngle;
+    debugDataInfo.getWriteBuffer().posiError = posiError;
+    debugDataInfo.commitWrite();
+
+}
+
+void NJointTaskSpaceImpedanceController::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["desiredForce_x"] = new Variant(debugDataInfo.getUpToDateReadBuffer().desiredForce_x);
+    datafields["desiredForce_y"] = new Variant(debugDataInfo.getUpToDateReadBuffer().desiredForce_y);
+    datafields["desiredForce_z"] = new Variant(debugDataInfo.getUpToDateReadBuffer().desiredForce_z);
+
+    datafields["tcpDesiredTorque_x"] = new Variant(debugDataInfo.getUpToDateReadBuffer().tcpDesiredTorque_x);
+    datafields["tcpDesiredTorque_y"] = new Variant(debugDataInfo.getUpToDateReadBuffer().tcpDesiredTorque_y);
+    datafields["tcpDesiredTorque_z"] = new Variant(debugDataInfo.getUpToDateReadBuffer().tcpDesiredTorque_z);
+
+    datafields["quatError"] = new Variant(debugDataInfo.getUpToDateReadBuffer().quatError);
+    datafields["posiError"] = new Variant(debugDataInfo.getUpToDateReadBuffer().posiError);
+
+    debugObs->setDebugChannel("DSControllerOutput", datafields);
+
+
+}
+
+
+
diff --git a/source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointTaskSpaceImpedanceController.h b/source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointTaskSpaceImpedanceController.h
new file mode 100644
index 0000000000000000000000000000000000000000..bc0d19d0972ec7dc889dd710ed99d2cd5365add1
--- /dev/null
+++ b/source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointTaskSpaceImpedanceController.h
@@ -0,0 +1,130 @@
+/*
+ * 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    TaskSpaceActiveImpedanceControl::ArmarXObjects::NJointTaskSpaceImpedanceController
+ * @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_TaskSpaceActiveImpedanceControl_NJointTaskSpaceImpedanceController_H
+#define _ARMARX_LIB_TaskSpaceActiveImpedanceControl_NJointTaskSpaceImpedanceController_H
+
+#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 <RobotAPI/interface/units/RobotUnit/TaskSpaceActiveImpedanceControl.h>
+
+namespace armarx
+{
+    class NJointTaskSpaceImpedanceControllerControlData
+    {
+    public:
+        Eigen::VectorXf desiredPose;
+        Eigen::VectorXf desiredTwist;
+    };
+    /**
+    * @defgroup Library-NJointTaskSpaceImpedanceController NJointTaskSpaceImpedanceController
+    * @ingroup TaskSpaceActiveImpedanceControl
+    * A description of the library NJointTaskSpaceImpedanceController.
+    *
+    * @class NJointTaskSpaceImpedanceController
+    * @ingroup Library-NJointTaskSpaceImpedanceController
+    * @brief Brief description of class NJointTaskSpaceImpedanceController.
+    *
+    * Detailed description of class NJointTaskSpaceImpedanceController.
+    */
+    class NJointTaskSpaceImpedanceController : public NJointControllerWithTripleBuffer<NJointTaskSpaceImpedanceControllerControlData>, public NJointTaskSpaceImpedanceControlInterface
+    {
+    public:
+        using ConfigPtrT = NJointTaskSpaceImpedanceControlConfigPtr;
+
+        NJointTaskSpaceImpedanceController(NJointControllerDescriptionProviderInterfacePtr prov, const NJointControllerConfigPtr& config, const VirtualRobot::RobotPtr&);
+
+
+        std::string getClassName(const Ice::Current&) const
+        {
+            return "TaskSpaceImpedanceController";
+        }
+
+        // NJointController interface
+        void rtRun(const IceUtil::Time& sensorValuesTimestamp, const IceUtil::Time& timeSinceLastIteration);
+
+    protected:
+        void onPublish(const SensorAndControl&, const DebugDrawerInterfacePrx&, const DebugObserverInterfacePrx&);
+
+
+    private:
+        Eigen::Vector3f desiredPosition;
+        Eigen::Quaternionf desiredQuaternion;
+        Eigen::VectorXf desiredTwist;
+        VirtualRobot::DifferentialIKPtr ik;
+        Eigen::Vector3f kpos;
+        Eigen::Vector3f kori;
+        Eigen::Vector3f dpos;
+        Eigen::Vector3f dori;
+
+        Eigen::VectorXf desiredJointPosition;
+
+        float knull, dnull;
+
+        VirtualRobot::RobotNodePtr tcp;
+
+        std::vector<const SensorValue1DoFActuatorTorque*> torqueSensors;
+        std::vector<const SensorValue1DoFActuatorVelocity*> velocitySensors;
+        std::vector<const SensorValue1DoFActuatorPosition*> positionSensors;
+
+        std::vector<ControlTarget1DoFActuatorTorque*> targets;
+
+        struct NJointTaskSpaceImpedanceControllerDebugInfo
+        {
+            StringFloatDictionary desired_torques;
+            float desiredForce_x;
+            float desiredForce_y;
+            float desiredForce_z;
+            float tcpDesiredTorque_x;
+            float tcpDesiredTorque_y;
+            float tcpDesiredTorque_z;
+
+            float tcpDesiredAngularError_x;
+            float tcpDesiredAngularError_y;
+            float tcpDesiredAngularError_z;
+
+            float currentTCPAngularVelocity_x;
+            float currentTCPAngularVelocity_y;
+            float currentTCPAngularVelocity_z;
+
+            float currentTCPLinearVelocity_x;
+            float currentTCPLinearVelocity_y;
+            float currentTCPLinearVelocity_z;
+
+            float quatError;
+            float posiError;
+        };
+        TripleBuffer<NJointTaskSpaceImpedanceControllerDebugInfo> debugDataInfo;
+
+        float torqueLimit;
+        std::vector<std::string> jointNames;
+
+    };
+
+}
+
+#endif
diff --git a/source/RobotAPI/components/units/RobotUnit/SensorValues/SensorValue1DoFActuator.h b/source/RobotAPI/components/units/RobotUnit/SensorValues/SensorValue1DoFActuator.h
index 23e427b8d18915720554512347b11bade7b5a734..fc8b362bcd2c705f163387fa4f41884d9d92ac92 100644
--- a/source/RobotAPI/components/units/RobotUnit/SensorValues/SensorValue1DoFActuator.h
+++ b/source/RobotAPI/components/units/RobotUnit/SensorValues/SensorValue1DoFActuator.h
@@ -53,6 +53,18 @@ namespace armarx
             return svi;
         }
     };
+    class SensorValue1DoFActuatorFilteredVelocity : virtual public SensorValueBase
+    {
+    public:
+        DETAIL_SensorValueBase_DEFAULT_METHOD_IMPLEMENTATION
+        float filteredvelocity = 0.0f;
+        static SensorValueInfo<SensorValue1DoFActuatorFilteredVelocity> GetClassMemberInfo()
+        {
+            SensorValueInfo<SensorValue1DoFActuatorFilteredVelocity> svi;
+            svi.addMemberVariable(&SensorValue1DoFActuatorFilteredVelocity::filteredvelocity, "filteredvelocity");
+            return svi;
+        }
+    };
     class SensorValue1DoFActuatorAcceleration : virtual public SensorValueBase
     {
     public:
diff --git a/source/RobotAPI/interface/CMakeLists.txt b/source/RobotAPI/interface/CMakeLists.txt
index 2ea2965e5fc0a6c23787684003fdaf66677d335a..f291a755554ae599ae14a0b484ee4a99335d066e 100644
--- a/source/RobotAPI/interface/CMakeLists.txt
+++ b/source/RobotAPI/interface/CMakeLists.txt
@@ -16,6 +16,7 @@ set(SLICE_FILES
     core/RobotState.ice
     core/RobotStateObserverInterface.ice
     core/Trajectory.ice
+    core/CartesianSelection.ice
 
     selflocalisation/SelfLocalisationProcess.ice
 
@@ -45,11 +46,13 @@ set(SLICE_FILES
     units/RobotUnit/NJointCartesianVelocityController.ice
     units/RobotUnit/NJointCartesianTorqueController.ice
     units/RobotUnit/NJointCartesianActiveImpedanceController.ice
+    units/RobotUnit/NJointCartesianVelocityControllerWithRamp.ice
     units/RobotUnit/RobotUnitInterface.ice
 
     units/RobotUnit/NJointJointSpaceDMPController.ice
     units/RobotUnit/NJointTaskSpaceDMPController.ice
 
+    units/RobotUnit/TaskSpaceActiveImpedanceControl.ice
     components/ViewSelectionInterface.ice
     components/TrajectoryPlayerInterface.ice
     components/RobotNameServiceInterface.ice
diff --git a/source/RobotAPI/interface/core/CartesianSelection.ice b/source/RobotAPI/interface/core/CartesianSelection.ice
new file mode 100644
index 0000000000000000000000000000000000000000..6fc3d9b0897a8195766ba58aca46fb2b781b6daa
--- /dev/null
+++ b/source/RobotAPI/interface/core/CartesianSelection.ice
@@ -0,0 +1,38 @@
+/*
+* 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    ArmarX::RobotAPI
+* @author     Mirko Waechter
+* @copyright  2016 Humanoids Group, HIS, KIT
+* @license    http://www.gnu.org/licenses/gpl-2.0.txt
+*             GNU General Public License
+*/
+
+#pragma once
+
+module armarx
+{
+    module CartesianSelectionMode
+    {
+        enum CartesianSelection
+        {
+            ePosition = 7,
+            eOrientation = 8,
+            eAll = 15
+        };
+    };
+
+};
+
diff --git a/source/RobotAPI/interface/units/RobotUnit/NJointCartesianVelocityControllerWithRamp.ice b/source/RobotAPI/interface/units/RobotUnit/NJointCartesianVelocityControllerWithRamp.ice
new file mode 100644
index 0000000000000000000000000000000000000000..da13b86d37334d4f63fdd28b4a4056cb44d89dee
--- /dev/null
+++ b/source/RobotAPI/interface/units/RobotUnit/NJointCartesianVelocityControllerWithRamp.ice
@@ -0,0 +1,50 @@
+/*
+ * 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::NJointControllerInterface
+ * @author     Sonja Marahrens ( sonja dot marahrens at kit dot edu )
+ * @date       2018
+ * @copyright  http://www.gnu.org/licenses/gpl-2.0.txt
+ *             GNU General Public License
+ */
+
+#pragma once
+
+#include <RobotAPI/interface/units/RobotUnit/NJointController.ice>
+#include <RobotAPI/interface/core/CartesianSelection.ice>
+
+module armarx
+{
+
+    class NJointCartesianVelocityControllerWithRampConfig extends NJointControllerConfig
+    {
+        string nodeSetName = "";
+        string tcpName = "";
+        CartesianSelectionMode::CartesianSelection mode = CartesianSelectionMode::eAll;
+        float maxPositionAcceleration = 0;
+        float maxOrientationAcceleration = 0;
+        float maxNullspaceAcceleration = 0;
+        float KpJointLimitAvoidance = 0;
+        float jointLimitAvoidanceScale = 0;
+    };
+
+    interface NJointCartesianVelocityControllerWithRampInterface extends NJointControllerInterface
+    {
+        void setMaxAccelerations(float maxPositionAcceleration, float maxOrientationAcceleration, float maxNullspaceAcceleration);
+        void setTargetVelocity(float vx, float vy, float vz, float vrx, float vry, float vrz);
+        void setJointLimitAvoidanceScale(float scale);
+        void setKpJointLimitAvoidance(float KpJointLimitAvoidance);
+    };
+};
diff --git a/source/RobotAPI/interface/units/RobotUnit/NJointCartesianVelocityControllerWithRamps.ice b/source/RobotAPI/interface/units/RobotUnit/NJointCartesianVelocityControllerWithRamps.ice
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/source/RobotAPI/interface/units/RobotUnit/NJointTaskSpaceDMPController.ice b/source/RobotAPI/interface/units/RobotUnit/NJointTaskSpaceDMPController.ice
index baf640bdab8bcdb696c8b589995cf3e4fe7b5090..ac949e0e7eb4aa0898ad8a0b3c5613dfcca9b962 100644
--- a/source/RobotAPI/interface/units/RobotUnit/NJointTaskSpaceDMPController.ice
+++ b/source/RobotAPI/interface/units/RobotUnit/NJointTaskSpaceDMPController.ice
@@ -66,6 +66,12 @@ module armarx
         double maxLinearVel;
         double maxAngularVel;
 
+        string debugName;
+
+        float Kp_LinearVel;
+        float Kd_LinearVel;
+        float Kp_AngularVel;
+        float Kd_AngularVel;
     };
 
 
@@ -110,6 +116,7 @@ module armarx
         Ice::StringSeq dmpTypes;
         Ice::DoubleSeq amplitudes;
 
+
         double posToOriRatio = 100;
 
         // velocity controller configuration
@@ -157,29 +164,34 @@ module armarx
         Ice::FloatSeq leftDesiredJointValues;
         Ice::FloatSeq rightDesiredJointValues;
 
-        float KoriFollower = 1;
-        float KposFollower = 1;
+//        float KoriFollower = 1;
+//        float KposFollower = 1;
 
         double maxLinearVel;
         double maxAngularVel;
 
-        Ice::FloatSeq Kpos;
-        Ice::FloatSeq Dpos;
-        Ice::FloatSeq Kori;
-        Ice::FloatSeq Dori;
+        Ice::FloatSeq leftKpos;
+        Ice::FloatSeq leftDpos;
+        Ice::FloatSeq leftKori;
+        Ice::FloatSeq leftDori;
+
+        Ice::FloatSeq rightKpos;
+        Ice::FloatSeq rightDpos;
+        Ice::FloatSeq rightKori;
+        Ice::FloatSeq rightDori;
 
         float knull;
         float dnull;
 
         float torqueLimit;
 
-        Ice::FloatSeq Kpf;
-        Ice::FloatSeq Kif;
-        Ice::FloatSeq DesiredForce;
+//        Ice::FloatSeq Kpf;
+//        Ice::FloatSeq Kif;
+//        Ice::FloatSeq DesiredForce;
 
-        float BoxWidth;
+//        float BoxWidth;
 
-        float FilterTimeConstant;
+//        float FilterTimeConstant;
 
 
     };
diff --git a/source/RobotAPI/interface/units/RobotUnit/TaskSpaceActiveImpedanceControl.ice b/source/RobotAPI/interface/units/RobotUnit/TaskSpaceActiveImpedanceControl.ice
new file mode 100644
index 0000000000000000000000000000000000000000..b736e4f1bfd78a226d50c19ad7f4ccef351516b5
--- /dev/null
+++ b/source/RobotAPI/interface/units/RobotUnit/TaskSpaceActiveImpedanceControl.ice
@@ -0,0 +1,53 @@
+/*
+ * 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::NJointControllerInterface
+ * @author     Mirko Waechter ( mirko dot waechter at kit dot edu )
+ * @date       2017
+ * @copyright  http://www.gnu.org/licenses/gpl-2.0.txt
+ *             GNU General Public License
+ */
+
+#pragma once
+
+#include <RobotAPI/interface/units/RobotUnit/NJointController.ice>
+
+module armarx
+{
+    class NJointTaskSpaceImpedanceControlConfig extends NJointControllerConfig
+    {
+        Ice::FloatSeq desiredPose;
+        Ice::FloatSeq desiredTwist;
+
+        Ice::FloatSeq Kpos;
+        Ice::FloatSeq Kori;
+        Ice::FloatSeq Dpos;
+        Ice::FloatSeq Dori;
+
+        string nodeSetName;
+        float torqueLimit;
+
+        float Knull;
+        float Dnull;
+
+        Ice::FloatSeq desiredJointPositions;
+    };
+
+    interface NJointTaskSpaceImpedanceControlInterface extends NJointControllerInterface
+    {
+
+    };
+
+};
diff --git a/source/RobotAPI/libraries/DMPController/TaskSpaceDMPController.cpp b/source/RobotAPI/libraries/DMPController/TaskSpaceDMPController.cpp
index b712d6491dfee79e774e22748a6c16733af466b3..462493dfb858a6b15d643f44da4ddf34a5da3ed8 100644
--- a/source/RobotAPI/libraries/DMPController/TaskSpaceDMPController.cpp
+++ b/source/RobotAPI/libraries/DMPController/TaskSpaceDMPController.cpp
@@ -88,22 +88,32 @@ void TaskSpaceDMPController::flow(double deltaT, const Eigen::Matrix4f& currentP
 
     currentState = dmpPtr->calculateDirectlyVelocity(currentState, canVal / timeDuration, deltaT / timeDuration, targetPoseVec);
 
-    for (size_t i = 0; i < 7; ++i)
-    {
-        targetPoseVec[i] = currentState[i].pos;
-    }
+//    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++)
+    if (isPhaseStopControl)
     {
-        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;
-    }
+        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;
+        }
+    }
+    else
+    {
+        for (size_t i = 0; i < 3; i++)
+        {
+            targetVel(i) = currentState[i].vel / timeDuration;
+        }
+    }
 
     Eigen::Quaterniond dmpQuaternionVel;
     dmpQuaternionVel.w() = currentState[3].vel;
@@ -150,9 +160,19 @@ void TaskSpaceDMPController::flow(double deltaT, const Eigen::Matrix4f& currentP
     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);
+
+    if (isPhaseStopControl)
+    {
+        targetVel(3) = angularVel0.x() / timeDuration;
+        targetVel(4) = angularVel0.y() / timeDuration;
+        targetVel(5) = angularVel0.z() / timeDuration;
+    }
+    else
+    {
+        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;
diff --git a/source/RobotAPI/libraries/DMPController/TaskSpaceDMPController.h b/source/RobotAPI/libraries/DMPController/TaskSpaceDMPController.h
index c62fef3fb25c3bbf43fd8093db3308110b68d195..c62ad28e2a932a29032642d0230591b23f23fd29 100644
--- a/source/RobotAPI/libraries/DMPController/TaskSpaceDMPController.h
+++ b/source/RobotAPI/libraries/DMPController/TaskSpaceDMPController.h
@@ -81,7 +81,7 @@ namespace armarx
     class TaskSpaceDMPController
     {
     public:
-        TaskSpaceDMPController(std::string name, const TaskSpaceDMPControllerConfig& config, bool isPhaseStop = true)
+        TaskSpaceDMPController(std::string name, const TaskSpaceDMPControllerConfig& config, bool isPhaseStopControl = true)
         {
             this->config = config;
 
@@ -104,7 +104,7 @@ namespace armarx
             targetVel.setZero();
             currentState.resize(7);
 
-            this->isPhaseStop = isPhaseStop;
+            this->isPhaseStopControl = isPhaseStopControl;
             dmpName = name;
         }
 
@@ -166,7 +166,7 @@ namespace armarx
         }
 
         double canVal;
-        bool isPhaseStop;
+        bool isPhaseStopControl;
         std::string dmpName;
     private:
 
diff --git a/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointBimanualCCDMPController.cpp b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointBimanualCCDMPController.cpp
index 1aefa06bbcd8af31e1e96509f0e273afe63edb8a..2563140cbc25077ea7a71edf91f193adf40e5e54 100644
--- a/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointBimanualCCDMPController.cpp
+++ b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointBimanualCCDMPController.cpp
@@ -13,7 +13,6 @@ namespace armarx
         useSynchronizedRtRobot();
 
         leftRNS = rtGetRobot()->getRobotNodeSet("LeftArm");
-        rnsLeftBody = rtGetRobot()->getRobotNodeSet("LeftArmCol");
         for (size_t i = 0; i < leftRNS->getSize(); ++i)
         {
             std::string jointName = leftRNS->getNode(i)->getName();
@@ -46,11 +45,6 @@ namespace armarx
             leftAccelerationSensors.push_back(accelerationSensor);
 
         };
-
-
-
-        rnsRightBody = rtGetRobot()->getRobotNodeSet("RightArmCol");
-
         rightRNS = rtGetRobot()->getRobotNodeSet("RightArm");
         for (size_t i = 0; i < rightRNS->getSize(); ++i)
         {
@@ -110,10 +104,10 @@ namespace armarx
         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));
+        TaskSpaceDMPControllerPtr leftLeader(new TaskSpaceDMPController("leftLeader", taskSpaceDMPConfig, false));
+        TaskSpaceDMPControllerPtr leftFollower(new TaskSpaceDMPController("leftFollower", taskSpaceDMPConfig, false));
+        TaskSpaceDMPControllerPtr rightLeader(new TaskSpaceDMPController("rightLeader", taskSpaceDMPConfig, false));
+        TaskSpaceDMPControllerPtr rightFollower(new TaskSpaceDMPController("rightFollower", taskSpaceDMPConfig, false));
 
         leftGroup.push_back(leftLeader);
         leftGroup.push_back(rightFollower);
@@ -134,7 +128,7 @@ namespace armarx
         initSensorData.currentRightPose = rightRNS->getTCP()->getPoseInRootFrame();
         controllerSensorData.reinitAllBuffers(initSensorData);
 
-        leaderName = "both";
+        leaderName = cfg->defautLeader;
 
         NJointBimanualCCDMPControllerControlData initData;
         initData.leftTargetVel.resize(6);
@@ -159,50 +153,24 @@ namespace armarx
             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];
+        leftKpos << cfg->leftKpos[0], cfg->leftKpos[1], cfg->leftKpos[2];
+        leftDpos << cfg->leftDpos[0], cfg->leftDpos[1], cfg->leftDpos[2];
+        leftKori << cfg->leftKori[0], cfg->leftKori[1], cfg->leftKori[2];
+        leftDori << cfg->leftDori[0], cfg->leftDori[1], cfg->leftDori[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);
-        }
+        torqueLimit = cfg->torqueLimit;
 
-        boxWidth = cfg->BoxWidth;
 
-        filtered_leftForce.setZero();
-        filtered_leftTorque.setZero();
-        filtered_rightForce.setZero();
-        filtered_rightTorque.setZero();
+        maxLinearVel = cfg->maxLinearVel;
+        maxAngularVel = cfg->maxAngularVel;
 
-        filterTimeConstant = cfg->FilterTimeConstant;
 
-        ftPIDController.resize(12);
-        for (size_t i = 0; i < ftPIDController.size(); i++)
-        {
-            ftPIDController[i].reset(new PIDController(kpf(i), kif(i), 0.0, 10, 10));
-        }
     }
 
     std::string NJointBimanualCCDMPController::getClassName(const Ice::Current&) const
@@ -275,14 +243,20 @@ namespace armarx
 
         TaskSpaceDMPControllerPtr leaderDMP = currentControlGroup[0];
         TaskSpaceDMPControllerPtr followerDMP = currentControlGroup[1];
+        virtualtimer = leaderDMP->canVal;
+
+        if(virtualtimer < 1e-8)
+        {
+            finished = true;
+        }
 
 
         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, currentFollowerPose, currentFollowerTwist);
+        currentFollowerLocalPose.block<3, 3>(0, 0) = currentLeaderPose.block<3, 3>(0, 0).inverse() * currentFollowerPose.block<3, 3>(0, 0);
+        currentFollowerLocalPose.block<3, 1>(0, 3) = currentLeaderPose.block<3, 3>(0, 0).inverse() * (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();
@@ -290,23 +264,24 @@ namespace armarx
         std::vector<double> followerLocalTargetPoseVec = followerDMP->getTargetPose();
 
         Eigen::Matrix4f followerTargetPose;
-        followerTargetPose.block<3, 3>(0, 0) = followerLocalTargetPose.block<3, 3>(0, 0) * currentLeaderPose.block<3, 3>(0, 0);
+        followerTargetPose.block<3, 3>(0, 0) = currentLeaderPose.block<3, 3>(0, 0) * followerLocalTargetPose.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.setZero();
+
         //        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));
+        //        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);
 
 
-        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;
@@ -315,6 +290,9 @@ namespace armarx
         Eigen::Matrix4f leftTargetPose;
         Eigen::Matrix4f rightTargetPose;
 
+        float leftKratio = 1.0;
+        float rightKratio = 1.0;
+
         if (leaderName == "Left")
         {
             leftTargetVel = leaderTargetVel;
@@ -325,7 +303,9 @@ namespace armarx
 
 
             leftTargetPose = leaderTargetPose;
-            rightTargetPose = followerLocalTargetPose;
+            rightTargetPose = followerTargetPose;
+
+
         }
         else if (leaderName == "right")
         {
@@ -336,90 +316,17 @@ namespace armarx
             leftDMPTarget = followerLocalTargetPoseVec;
 
             rightTargetPose = leaderTargetPose;
-            leftTargetPose = followerLocalTargetPose;
+            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;
+        getWriterControlStruct().virtualTime = virtualtimer;
+
         writeControlStruct();
     }
 
@@ -456,11 +363,11 @@ namespace armarx
         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;
@@ -473,7 +380,6 @@ namespace armarx
         }
 
         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;
@@ -490,227 +396,133 @@ namespace armarx
         Eigen::VectorXf currentLeftTwist = jacobiL * leftqvel;
         Eigen::VectorXf currentRightTwist = jacobiR * rightqvel;
 
-
         controllerSensorData.getWriteBuffer().currentLeftTwist = currentLeftTwist;
         controllerSensorData.getWriteBuffer().currentRightTwist = currentRightTwist;
         controllerSensorData.commitWrite();
 
+        jacobiL.block<3, 8>(0, 0) = 0.001 * jacobiL.block<3, 8>(0, 0);
+        jacobiR.block<3, 8>(0, 0) = 0.001 * jacobiR.block<3, 8>(0, 0);
+
 
         Eigen::Matrix4f leftTargetPose = rtGetControlStruct().leftTargetPose;
         Eigen::Matrix4f rightTargetPose = rtGetControlStruct().rightTargetPose;
-        Eigen::VectorXf leftTargetVel = rtGetControlStruct().leftTargetVel;
-        Eigen::VectorXf rightTargetVel = rtGetControlStruct().rightTargetVel;
+        double virtualtime = rtGetControlStruct().virtualTime;
         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::Matrix4f poseLeftInRightCoordinate = tcpRight->toLocalCoordinateSystem(tcpLeft->getGlobalPose());
-//        Eigen::Vector3f positionLeftInRightCoordinate;
-//        positionLeftInRightCoordinate << poseLeftInRightCoordinate(0,3), poseLeftInRightCoordinate(1,3), poseLeftInRightCoordinate(2,3);
-//        boxWidth = 0.001 * 0.5 * positionLeftInRightCoordinate.norm();
-
-
-        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::MatrixXf leftGraspMatrix = Eigen::MatrixXf::Identity(6, 6);
-        Eigen::MatrixXf rightGraspMatrix = Eigen::MatrixXf::Identity(6, 6);
-        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;
-        graspMatrix.resize(6, 12);
-        graspMatrix << leftGraspMatrix, rightGraspMatrix;
-
-        // constraint Jacobain and projection matrix
-        Eigen::MatrixXf jacobi;
-        jacobi.resize(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 proj2GraspNullspace = Eigen::MatrixXf::Identity(12, 12) - pinvGraspMatrix * graspMatrix;
-        Eigen::MatrixXf jacobiConstrained = proj2GraspNullspace * jacobi;
-
-        Eigen::MatrixXf pinvJacobiC = leftIK->computePseudoInverseJacobianMatrix(jacobiConstrained, 1);
-        Eigen::MatrixXf projection = Eigen::MatrixXf::Identity(n, n) - pinvJacobiC * jacobiConstrained;
-
-
-
-        // 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)
+        Eigen::VectorXf leftTargetVel = rtGetControlStruct().leftTargetVel;
+        float normLinearVelocity = leftTargetVel.block<3, 1>(0, 0).norm();
+        if (normLinearVelocity > maxLinearVel)
         {
-            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;
+            leftTargetVel.block<3, 1>(0, 0) = maxLinearVel * leftTargetVel.block<3, 1>(0, 0) / normLinearVelocity;
         }
-
-        for (size_t i = 0; i < rnsRightBody->getNodeNames().size(); ++i)
+        float normAngularVelocity = leftTargetVel.block<3, 1>(3, 0).norm();
+        if (normAngularVelocity > maxAngularVel)
         {
-            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;
+            leftTargetVel.block<3, 1>(3, 0) = maxAngularVel * leftTargetVel.block<3, 1>(3, 0) / normAngularVelocity;
         }
-        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;
+        Eigen::VectorXf rightTargetVel = rtGetControlStruct().rightTargetVel;
+        normLinearVelocity = rightTargetVel.block<3, 1>(0, 0).norm();
+        if (normLinearVelocity > maxLinearVel)
+        {
+            rightTargetVel.block<3, 1>(0, 0) = maxLinearVel * rightTargetVel.block<3, 1>(0, 0) / normLinearVelocity;
+        }
+        normAngularVelocity = leftTargetVel.block<3, 1>(3, 0).norm();
+        if (normAngularVelocity > maxAngularVel)
+        {
+            rightTargetVel.block<3, 1>(3, 0) = maxAngularVel * rightTargetVel.block<3, 1>(3, 0) / normAngularVelocity;
+        }
 
 
 
         // 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);
+            currentTCPLinearVelocity <<  0.001 * currentLeftTwist(0),  0.001 * currentLeftTwist(1),   0.001 * 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::Vector3f tcpDesiredForce = 0.001 * leftKpos.cwiseProduct(desiredPosition - currentTCPPosition) + leftDpos.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);
+            Eigen::Vector3f tcpDesiredTorque = leftKori.cwiseProduct(rpy) - leftDori.cwiseProduct(currentTCPAngularVelocity);
             leftJointControlWrench <<  tcpDesiredForce, tcpDesiredTorque;
         }
 
-
         Eigen::Vector6f rightJointControlWrench;
         {
+
+            Eigen::Vector3f targetTCPLinearVelocity;
+            targetTCPLinearVelocity << 0.001 * rightTargetVel(0), 0.001 * rightTargetVel(1), 0.001 * rightTargetVel(2);
+
             Eigen::Vector3f currentTCPLinearVelocity;
-            currentTCPLinearVelocity <<  currentRightTwist(0),  currentRightTwist(1), currentRightTwist(2);
+            currentTCPLinearVelocity <<   0.001 * currentRightTwist(0),   0.001 * currentRightTwist(1),  0.001 * 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::Vector3f tcpDesiredForce = 0.001 * rightKpos.cwiseProduct(desiredPosition - currentTCPPosition) + rightDpos.cwiseProduct(targetTCPLinearVelocity - 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);
+            Eigen::Vector3f tcpDesiredTorque = rightKori.cwiseProduct(rpy) - rightDori.cwiseProduct(currentTCPAngularVelocity);
             rightJointControlWrench <<   tcpDesiredForce, tcpDesiredTorque;
         }
 
-        Eigen::VectorXf forceUnconstrained(12);
-        forceUnconstrained << leftJointControlWrench, rightJointControlWrench;
-        forceUnconstrained = proj2GraspNullspace * forceUnconstrained;
 
 
+//        Eigen::VectorXf leftJointLimitAvoidance(leftRNS->getSize());
+//        for (size_t i = 0; i < leftRNS->getSize(); i++)
+//        {
+//            VirtualRobot::RobotNodePtr rn = leftRNS->getNode(i);
+//            if (rn->isLimitless())
+//            {
+//                leftJointLimitAvoidance(i) = 0;
+//            }
+//            else
+//            {
+//                float f = math::MathUtils::ILerp(rn->getJointLimitLo(), rn->getJointLimitHi(), rn->getJointValue());
+//                leftJointLimitAvoidance(i) = cos(f * M_PI);
+//            }
+//        }
+//        Eigen::VectorXf leftNullspaceTorque = knull * leftJointLimitAvoidance - dnull * leftqvel;
+//        Eigen::VectorXf rightJointLimitAvoidance(rightRNS->getSize());
+//        for (size_t i = 0; i < rightRNS->getSize(); i++)
+//        {
+//            VirtualRobot::RobotNodePtr rn = rightRNS->getNode(i);
+//            if (rn->isLimitless())
+//            {
+//                rightJointLimitAvoidance(i) = 0;
+//            }
+//            else
+//            {
+//                float f = math::MathUtils::ILerp(rn->getJointLimitLo(), rn->getJointLimitHi(), rn->getJointValue());
+//                rightJointLimitAvoidance(i) = cos(f * M_PI);
+//            }
+//        }
+//        Eigen::VectorXf rightNullspaceTorque = knull * rightJointLimitAvoidance - dnull * rightqvel;
+
 
         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::VectorXf leftJointDesiredTorques = jacobiL.transpose() * forceUnconstrained.head(6) + (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 rightJointDesiredTorques = jacobiR.transpose() * forceUnconstrained.tail<6>() + (I - jacobiR.transpose() * jtpinvR) * rightNullspaceTorque;
-
-        Eigen::VectorXf torqueUnconstrained(16);
-        torqueUnconstrained << leftJointDesiredTorques, rightJointDesiredTorques;
-
-        // constrained space control
-
-        Eigen::MatrixXf mu = (Eigen::MatrixXf::Identity(n, n) - projection) * M * Mc.inverse();
-        Eigen::VectorXf forceConstrained = Eigen::VectorXf::Zero(12);
-
-
-        double filterFactor = 1 / ((filterTimeConstant / deltaT) + 1);
-
-        filtered_leftForce = (1 - filterFactor) * filtered_leftForce + filterFactor * leftForceTorque->force;
-        filtered_leftTorque = (1 - filterFactor) * filtered_leftTorque + filterFactor * leftForceTorque->torque;
-        filtered_rightForce = (1 - filterFactor) * filtered_rightForce + filterFactor * rightForceTorque->force;
-        filtered_rightTorque = (1 - filterFactor) * filtered_rightForce + filterFactor * rightForceTorque->torque;
-
-        Eigen::VectorXf filteredForce;
-        filteredForce.resize(12);
-        filteredForce << filtered_leftForce, filtered_leftTorque, filtered_rightForce, filtered_rightTorque;
-
-        for (size_t i = 0; i < 12; i++)
-        {
-            ftPIDController[i]->update(filteredForce(i), forceC_des(i));
-            forceConstrained(i) = ftPIDController[i]->getControlValue();
-//            forceConstrained(i) = forceC_des(i) + kpf(i) * (forceC_des(i) - filtered_leftForce(i)); // TODO: add PID controller
-//            forceConstrained(i + 3) = forceC_des(i + 3) + kpf(i + 3) * (forceC_des(i + 3) - filtered_leftTorque(i)); // TODO: add PID controller
-//            forceConstrained(i + 6) = forceC_des(i + 6) + kpf(i + 6) * (forceC_des(i + 6) - filtered_rightForce(i)); // TODO: add PID controller
-//            forceConstrained(i + 9) = forceC_des(i + 9) + kpf(i + 9) * (forceC_des(i + 9) - filtered_rightTorque(i)); // TODO: add PID controller
-        }
-
-        forceConstrained.block<3,1>(0,0) = leftCurrentPose.block<3, 3>(0, 0) * forceConstrained.block<3,1>(0,0);
-        forceConstrained.block<3,1>(3,0) = leftCurrentPose.block<3, 3>(0, 0) * forceConstrained.block<3,1>(3,0);
-        forceConstrained.block<3,1>(6,0) = rightCurrentPose.block<3, 3>(0, 0) * forceConstrained.block<3,1>(6,0);
-        forceConstrained.block<3,1>(9,0) = rightCurrentPose.block<3, 3>(0, 0) * forceConstrained.block<3,1>(9,0);
-
-
-        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 torqueConstrained = mu * (torqueUnconstrained + (Eigen::MatrixXf::Identity(n, n) - projection) * qacc) - jacobiConstrained.transpose() * forceConstrained;
-
-
-        // all torques
-
 
-
-//        Eigen::VectorXf torqueInput = projection * torqueUnconstrained + projection * torqueConstrained;
-//        Eigen::VectorXf torqueInput = torqueUnconstrained + jacobi.transpose() * (Eigen::MatrixXf::Identity(12,12) - proj2GraspNullspace) * forceConstrained;
-//        Eigen::VectorXf torqueInput = torqueUnconstrained + jacobi.transpose() * forceConstrained;
-        Eigen::VectorXf torqueInput = torqueUnconstrained + projection * jacobi.transpose() * forceConstrained;
-
-        leftJointDesiredTorques = torqueInput.head(nl);
-        rightJointDesiredTorques = torqueInput.block<8, 1>(8, 0);
+        Eigen::MatrixXf jtpinvL = leftIK->computePseudoInverseJacobianMatrix(jacobiL.transpose(), lambda);
+        Eigen::MatrixXf jtpinvR = rightIK->computePseudoInverseJacobianMatrix(jacobiR.transpose(), lambda);
+        Eigen::VectorXf leftJointDesiredTorques = jacobiL.transpose() * leftJointControlWrench + (I - jacobiL.transpose() * jtpinvL) * leftNullspaceTorque;
+        Eigen::VectorXf rightJointDesiredTorques = jacobiR.transpose() * rightJointControlWrench + (I - jacobiR.transpose() * jtpinvR) * rightNullspaceTorque;
 
         // torque limit
         for (size_t i = 0; i < leftTargets.size(); ++i)
@@ -748,10 +560,21 @@ namespace armarx
 
             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().leftControlSignal_x = leftJointControlWrench(0);
+
+        debugDataInfo.getWriteBuffer().leftControlSignal_x = leftJointControlWrench(0);
+        debugDataInfo.getWriteBuffer().leftControlSignal_y = leftJointControlWrench(1);
+        debugDataInfo.getWriteBuffer().leftControlSignal_z = leftJointControlWrench(2);
+        debugDataInfo.getWriteBuffer().leftControlSignal_ro = leftJointControlWrench(3);
+        debugDataInfo.getWriteBuffer().leftControlSignal_pi = leftJointControlWrench(4);
+        debugDataInfo.getWriteBuffer().leftControlSignal_ya = leftJointControlWrench(5);
+
+        debugDataInfo.getWriteBuffer().rightControlSignal_x = rightJointControlWrench(0);
+        debugDataInfo.getWriteBuffer().rightControlSignal_y = rightJointControlWrench(1);
+        debugDataInfo.getWriteBuffer().rightControlSignal_z = rightJointControlWrench(2);
+        debugDataInfo.getWriteBuffer().rightControlSignal_ro = rightJointControlWrench(3);
+        debugDataInfo.getWriteBuffer().rightControlSignal_pi = rightJointControlWrench(4);
+        debugDataInfo.getWriteBuffer().rightControlSignal_ya = rightJointControlWrench(5);
         //        debugDataInfo.getWriteBuffer().leftTcpDesiredTorque_x = tcpDesiredTorque(0);
         //        debugDataInfo.getWriteBuffer().leftTcpDesiredTorque_y = tcpDesiredTorque(1);
         //        debugDataInfo.getWriteBuffer().tcpDesiredTorque_z = tcpDesiredTorque(2);
@@ -772,32 +595,12 @@ namespace armarx
         debugDataInfo.getWriteBuffer().rightCurrentPose_x = rightCurrentPose(0, 3);
         debugDataInfo.getWriteBuffer().rightCurrentPose_y = rightCurrentPose(1, 3);
         debugDataInfo.getWriteBuffer().rightCurrentPose_z = rightCurrentPose(2, 3);
-
-
-        for(size_t i = 0 ; i < 12; ++i)
-        {
-            std::stringstream ss;
-            ss << i;
-            std::string name = "forceConstrained_" + ss.str();
-            debugDataInfo.getWriteBuffer().constrained_force[name] = forceConstrained(i);
-        }
-
+        debugDataInfo.getWriteBuffer().virtualTime = virtualtime;
 
         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));
@@ -807,18 +610,6 @@ namespace armarx
         //        {
         //            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;
@@ -916,14 +707,15 @@ namespace armarx
         leftGroup.at(1)->prepareExecution(getLocalPose(leftPose, rightPose), getLocalPose(leftGoals, rightGoals));
         rightGroup.at(1)->prepareExecution(getLocalPose(rightPose, leftPose), getLocalPose(rightGoals, leftGoals));
 
+        finished = false;
         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));
+        localPose.block<3, 3>(0, 0) = newCoordinate.block<3, 3>(0, 0).inverse() * globalTargetPose.block<3, 3>(0, 0);
+        localPose.block<3, 1>(0, 3) = newCoordinate.block<3, 3>(0, 0).inverse() * (globalTargetPose.block<3, 1>(0, 3) - newCoordinate.block<3, 1>(0, 3));
 
         return localPose;
     }
@@ -961,36 +753,23 @@ namespace armarx
         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);
-        //        }
+        datafields["leftControlSignal_x"] = new Variant(debugDataInfo.getUpToDateReadBuffer().leftControlSignal_x);
+        datafields["leftControlSignal_y"] = new Variant(debugDataInfo.getUpToDateReadBuffer().leftControlSignal_y);
+        datafields["leftControlSignal_z"] = new Variant(debugDataInfo.getUpToDateReadBuffer().leftControlSignal_z);
+        datafields["leftControlSignal_ro"] = new Variant(debugDataInfo.getUpToDateReadBuffer().leftControlSignal_ro);
+        datafields["leftControlSignal_pi"] = new Variant(debugDataInfo.getUpToDateReadBuffer().leftControlSignal_pi);
+        datafields["leftControlSignal_ya"] = new Variant(debugDataInfo.getUpToDateReadBuffer().leftControlSignal_ya);
 
-        //        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["rightControlSignal_x"] = new Variant(debugDataInfo.getUpToDateReadBuffer().rightControlSignal_x);
+        datafields["rightControlSignal_y"] = new Variant(debugDataInfo.getUpToDateReadBuffer().rightControlSignal_y);
+        datafields["rightControlSignal_z"] = new Variant(debugDataInfo.getUpToDateReadBuffer().rightControlSignal_z);
+        datafields["rightControlSignal_ro"] = new Variant(debugDataInfo.getUpToDateReadBuffer().rightControlSignal_ro);
+        datafields["rightControlSignal_pi"] = new Variant(debugDataInfo.getUpToDateReadBuffer().rightControlSignal_pi);
+        datafields["rightControlSignal_ya"] = new Variant(debugDataInfo.getUpToDateReadBuffer().rightControlSignal_ya);
+
+        datafields["virtual_timer"] = new Variant(debugDataInfo.getUpToDateReadBuffer().virtualTime);
 
-        //        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);
     }
diff --git a/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointBimanualCCDMPController.h b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointBimanualCCDMPController.h
index ad39aac384d72d7345e38d4c35cebaa64d8d2887..9b62d80f6a10a21d917143993c881df08b658c70 100644
--- a/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointBimanualCCDMPController.h
+++ b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointBimanualCCDMPController.h
@@ -15,6 +15,7 @@
 #include <RobotAPI/components/units/RobotUnit/SensorValues/SensorValueForceTorque.h>
 
 #include <RobotAPI/libraries/core/PIDController.h>
+#include <RobotAPI/libraries/core/math/MathUtils.h>
 
 
 using namespace DMP;
@@ -35,6 +36,9 @@ namespace armarx
 
         Eigen::Matrix4f leftTargetPose;
         Eigen::Matrix4f rightTargetPose;
+
+        double virtualTime;
+
     };
 
     class NJointBimanualCCDMPController :
@@ -56,7 +60,7 @@ namespace armarx
         void learnDMPFromFiles(const std::string&, const Ice::StringSeq&, const Ice::Current&);
         bool isFinished(const Ice::Current&)
         {
-            return false;
+            return finished;
         }
 
         void runDMP(const Ice::DoubleSeq& leftGoals, const Ice::DoubleSeq& rightGoals, const Ice::Current&);
@@ -121,6 +125,21 @@ namespace armarx
             float rightCurrentPose_y;
             float rightCurrentPose_z;
 
+            float leftControlSignal_x;
+            float leftControlSignal_y;
+            float leftControlSignal_z;
+            float leftControlSignal_ro;
+            float leftControlSignal_pi;
+            float leftControlSignal_ya;
+
+
+            float rightControlSignal_x;
+            float rightControlSignal_y;
+            float rightControlSignal_z;
+            float rightControlSignal_ro;
+            float rightControlSignal_pi;
+            float rightControlSignal_ya;
+
             //            StringFloatDictionary latestTargetVelocities;
             //            StringFloatDictionary dmpTargets;
             //            StringFloatDictionary currentPose;
@@ -137,9 +156,11 @@ namespace armarx
             //            double followeroriError;
             //            double followerCanVal;
 
+            double virtualTime;
 
         };
 
+        bool finished;
         TripleBuffer<DebugBufferData> debugDataInfo;
 
         struct NJointBimanualCCDMPControllerSensorData
@@ -152,6 +173,8 @@ namespace armarx
             Eigen::VectorXf currentRightTwist;
 
 
+
+
         };
         TripleBuffer<NJointBimanualCCDMPControllerSensorData> controllerSensorData;
 
@@ -199,12 +222,16 @@ namespace armarx
         Eigen::VectorXf forceC_des;
         float boxWidth;
 
-        Eigen::Vector3f kpos;
-        Eigen::Vector3f kori;
-        Eigen::Vector3f dpos;
-        Eigen::Vector3f dori;
-        Eigen::VectorXf kpf;
-        Eigen::VectorXf kif;
+        Eigen::Vector3f leftKpos;
+        Eigen::Vector3f leftKori;
+        Eigen::Vector3f leftDpos;
+        Eigen::Vector3f leftDori;
+
+        Eigen::Vector3f rightKpos;
+        Eigen::Vector3f rightKori;
+        Eigen::Vector3f rightDpos;
+        Eigen::Vector3f rightDori;
+
 
         float knull;
         float dnull;
@@ -215,17 +242,10 @@ namespace armarx
         float torqueLimit;
         VirtualRobot::RobotNodeSetPtr leftRNS;
         VirtualRobot::RobotNodeSetPtr rightRNS;
-        VirtualRobot::RobotNodeSetPtr rnsLeftBody;
-        VirtualRobot::RobotNodeSetPtr rnsRightBody;
-
-        Eigen::Vector3f filtered_leftForce;
-        Eigen::Vector3f filtered_leftTorque;
-        Eigen::Vector3f filtered_rightForce;
-        Eigen::Vector3f filtered_rightTorque;
-        float filterTimeConstant;
 
-        std::vector<PIDControllerPtr> ftPIDController;
 
+        float maxLinearVel;
+        float maxAngularVel;
 
         // NJointBimanualCCDMPControllerInterface interface
     };
diff --git a/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointBimanualDMPForceController.cpp b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointBimanualDMPForceController.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..7112666794b57434aeee754772966f7e437bfb7d
--- /dev/null
+++ b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointBimanualDMPForceController.cpp
@@ -0,0 +1,1098 @@
+#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");
+        rnsLeftBody = robotUnit->getRtRobot()->getRobotNodeSet("LeftArmCol");
+        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);
+
+        };
+
+
+
+        rnsRightBody = robotUnit->getRtRobot()->getRobotNodeSet("RightArmCol");
+
+        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);
+
+        bothLeaderGroup.push_back(leftLeader);
+        bothLeaderGroup.push_back(rightLeader);
+
+
+        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 = "both";
+
+        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;
+
+        filtered_leftForce.setZero();
+        filtered_leftTorque.setZero();
+        filtered_rightForce.setZero();
+        filtered_rightTorque.setZero();
+
+        //        offset_leftForce.setZero();
+        //        offset_leftTorque.setZero();
+        //        offset_rightForce.setZero();
+        //        offset_rightTorque.setZero();
+
+        offset_leftForce(0) = -4.34;
+        offset_leftForce(1) = -8.21;
+        offset_leftForce(2) = 15.59;
+
+        offset_leftTorque(0) = 1.42;
+        offset_leftTorque(1) = 0.29;
+        offset_leftTorque(2) = 0.09;
+
+        offset_rightForce(0) = 2.88;
+        offset_rightForce(1) = 11.15;
+        offset_rightForce(2) = -20.18;
+
+        offset_rightTorque(0) = -1.83;
+        offset_rightTorque(1) = 0.34;
+        offset_rightTorque(2) = -0.01;
+
+
+        filterTimeConstant = cfg->FilterTimeConstant;
+
+        ftPIDController.resize(12);
+        for (size_t i = 0; i < ftPIDController.size(); i++)
+        {
+            ftPIDController[i].reset(new PIDController(kpf(i), kif(i), 0.0, 10, 10));
+        }
+
+        isForceCompensateDone = false;
+
+    }
+
+    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 if (leaderName == "right")
+        {
+            currentControlGroup = rightGroup;
+            currentLeaderPose = controllerSensorData.getReadBuffer().currentRightPose;
+            currentFollowerPose = controllerSensorData.getReadBuffer().currentLeftPose;
+            currentLeaderTwist = controllerSensorData.getReadBuffer().currentRightTwist;
+            currentFollowerTwist = controllerSensorData.getReadBuffer().currentLeftTwist;
+        }
+        else
+        {
+            currentControlGroup = bothLeaderGroup;
+
+            TaskSpaceDMPControllerPtr leaderDMPleft = currentControlGroup[0];
+            TaskSpaceDMPControllerPtr leaderDMPright = currentControlGroup[1];
+            leaderDMPleft->flow(deltaT, controllerSensorData.getReadBuffer().currentLeftPose, controllerSensorData.getReadBuffer().currentLeftTwist);
+            leaderDMPright->flow(deltaT, controllerSensorData.getReadBuffer().currentRightPose, controllerSensorData.getReadBuffer().currentRightTwist);
+
+            Eigen::VectorXf leftTargetVel = leaderDMPleft->getTargetVelocity();
+            Eigen::Matrix4f leftTargetPose = leaderDMPleft->getTargetPoseMat();
+            Eigen::VectorXf rightTargetVel = leaderDMPright->getTargetVelocity();
+            Eigen::Matrix4f rightTargetPose = leaderDMPright->getTargetPoseMat();
+
+            virtualtimer = leaderDMPleft->canVal;
+            LockGuardType guard {controlDataMutex};
+            getWriterControlStruct().leftTargetVel = leftTargetVel;
+            getWriterControlStruct().rightTargetVel = rightTargetVel;
+            getWriterControlStruct().leftTargetPose = leftTargetPose;
+            getWriterControlStruct().rightTargetPose = rightTargetPose;
+            writeControlStruct();
+
+            return;
+        }
+
+        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, currentFollowerPose, currentFollowerTwist);
+
+        Eigen::VectorXf leaderTargetVel = leaderDMP->getTargetVelocity();
+        Eigen::Matrix4f leaderTargetPose = leaderDMP->getTargetPoseMat();
+        Eigen::Matrix4f followerLocalTargetPose = followerDMP->getTargetPoseMat();
+        std::vector<double> followerLocalTargetPoseVec = followerDMP->getTargetPose();
+
+        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;
+
+        Eigen::Matrix4f leftTargetPose;
+        Eigen::Matrix4f rightTargetPose;
+
+        if (leaderName == "Left")
+        {
+            leftTargetVel = leaderTargetVel;
+            rightTargetVel = followerTargetVel;
+
+            leftDMPTarget = leaderDMP->getTargetPose();
+            rightDMPTarget = followerLocalTargetPoseVec;
+
+
+            leftTargetPose = leaderTargetPose;
+            rightTargetPose = followerLocalTargetPose;
+        }
+        else if (leaderName == "right")
+        {
+            rightTargetVel = leaderTargetVel;
+            leftTargetVel = followerTargetVel;
+
+            rightDMPTarget = leaderDMP->getTargetPose();
+            leftDMPTarget = followerLocalTargetPoseVec;
+
+            rightTargetPose = leaderTargetPose;
+            leftTargetPose = followerLocalTargetPose;
+
+        }
+
+
+
+
+
+        //        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;
+
+
+        //        if(controllerSensorData.getWriteBuffer().currentTime > 0.3 && !isForceCompensateDone)
+        //        {
+        //            offset_leftForce = filtered_leftForce;
+        //            offset_leftTorque = filtered_leftTorque;
+        //            offset_rightForce = filtered_rightForce;
+        //            offset_rightTorque = filtered_rightTorque;
+        //            isForceCompensateDone = true;
+
+
+        //            filtered_leftForce.setZero();
+        //            filtered_leftTorque.setZero();
+        //            filtered_rightForce.setZero();
+        //            filtered_rightTorque.setZero();
+        //        }
+
+        //        if(controllerSensorData.getWriteBuffer().currentTime <= 0.3)
+        //        {
+        //            // torque limit
+        //            for (size_t i = 0; i < leftTargets.size(); ++i)
+        //            {
+        //                leftTargets.at(i)->torque = 0;
+        //            }
+
+        //            for (size_t i = 0; i < rightTargets.size(); ++i)
+        //            {
+        //                rightTargets.at(i)->torque = 0;
+        //            }
+
+        //            return;
+        //        }
+
+        // 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::Matrix4f poseLeftInRightCoordinate = tcpRight->toLocalCoordinateSystem(tcpLeft->getGlobalPose());
+        //        Eigen::Vector3f positionLeftInRightCoordinate;
+        //        positionLeftInRightCoordinate << poseLeftInRightCoordinate(0,3), poseLeftInRightCoordinate(1,3), poseLeftInRightCoordinate(2,3);
+        //        boxWidth = 0.001 * 0.5 * positionLeftInRightCoordinate.norm();
+
+
+        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::MatrixXf leftGraspMatrix = Eigen::MatrixXf::Identity(6, 6);
+        Eigen::MatrixXf rightGraspMatrix = Eigen::MatrixXf::Identity(6, 6);
+        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;
+        graspMatrix.resize(6, 12);
+        graspMatrix << leftGraspMatrix, rightGraspMatrix;
+
+        // constraint Jacobain and projection matrix
+        Eigen::MatrixXf jacobi;
+        jacobi.resize(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 proj2GraspNullspace = Eigen::MatrixXf::Identity(12, 12) - pinvGraspMatrix * graspMatrix;
+        Eigen::MatrixXf jacobiConstrained = proj2GraspNullspace * jacobi;
+
+        Eigen::MatrixXf pinvJacobiC = leftIK->computePseudoInverseJacobianMatrix(jacobiConstrained, 1);
+        Eigen::MatrixXf projection = Eigen::MatrixXf::Identity(n, n) - pinvJacobiC * jacobiConstrained;
+
+
+
+        // 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;
+
+
+        // force filter and measure
+        double filterFactor = 1 / ((filterTimeConstant / deltaT) + 1);
+
+        filtered_leftForce = (1 - filterFactor) * filtered_leftForce + filterFactor * (leftForceTorque->force - offset_leftForce);
+        filtered_leftTorque = (1 - filterFactor) * filtered_leftTorque + filterFactor * (leftForceTorque->torque - offset_leftTorque);
+        filtered_rightForce = (1 - filterFactor) * filtered_rightForce + filterFactor * (rightForceTorque->force - offset_rightForce);
+        filtered_rightTorque = (1 - filterFactor) * filtered_rightForce + filterFactor * (rightForceTorque->torque - offset_rightTorque);
+
+        Eigen::VectorXf filteredForce;
+        filteredForce.resize(12);
+        filteredForce << filtered_leftForce, filtered_leftTorque, filtered_rightForce, filtered_rightTorque;
+        filteredForce.block<3, 1>(0, 0) = leftCurrentPose.block<3, 3>(0, 0) * filteredForce.block<3, 1>(0, 0);
+        filteredForce.block<3, 1>(3, 0) = leftCurrentPose.block<3, 3>(0, 0) * filteredForce.block<3, 1>(3, 0);
+        filteredForce.block<3, 1>(6, 0) = rightCurrentPose.block<3, 3>(0, 0) * filteredForce.block<3, 1>(6, 0);
+        filteredForce.block<3, 1>(9, 0) = rightCurrentPose.block<3, 3>(0, 0) * filteredForce.block<3, 1>(9, 0);
+
+
+        // calculate force control part
+        Eigen::VectorXf constrainedForceMeasure = proj2GraspNullspace  * filteredForce;
+
+        constrainedForceMeasure.block<3, 1>(0, 0) = leftCurrentPose.block<3, 3>(0, 0).transpose() * constrainedForceMeasure.block<3, 1>(0, 0);
+        constrainedForceMeasure.block<3, 1>(3, 0) = leftCurrentPose.block<3, 3>(0, 0).transpose() * constrainedForceMeasure.block<3, 1>(3, 0);
+        constrainedForceMeasure.block<3, 1>(6, 0) = rightCurrentPose.block<3, 3>(0, 0).transpose() * constrainedForceMeasure.block<3, 1>(6, 0);
+        constrainedForceMeasure.block<3, 1>(9, 0) = rightCurrentPose.block<3, 3>(0, 0).transpose() * constrainedForceMeasure.block<3, 1>(9, 0);
+        Eigen::VectorXf forceConstrained = Eigen::VectorXf::Zero(12);
+        for (size_t i = 0; i < 12; i++)
+        {
+            ftPIDController[i]->update(constrainedForceMeasure(i), forceC_des(i));
+            forceConstrained(i) = ftPIDController[i]->getControlValue() + forceC_des(i);
+            //            forceConstrained(i) = forceC_des(i) + kpf(i) * (forceC_des(i) - filtered_leftForce(i)); // TODO: add PID controller
+            //            forceConstrained(i + 3) = forceC_des(i + 3) + kpf(i + 3) * (forceC_des(i + 3) - filtered_leftTorque(i)); // TODO: add PID controller
+            //            forceConstrained(i + 6) = forceC_des(i + 6) + kpf(i + 6) * (forceC_des(i + 6) - filtered_rightForce(i)); // TODO: add PID controller
+            //            forceConstrained(i + 9) = forceC_des(i + 9) + kpf(i + 9) * (forceC_des(i + 9) - filtered_rightTorque(i)); // TODO: add PID controller
+        }
+        forceConstrained.block<3, 1>(0, 0) = leftCurrentPose.block<3, 3>(0, 0) * forceConstrained.block<3, 1>(0, 0);
+        forceConstrained.block<3, 1>(3, 0) = leftCurrentPose.block<3, 3>(0, 0) * forceConstrained.block<3, 1>(3, 0);
+        forceConstrained.block<3, 1>(6, 0) = rightCurrentPose.block<3, 3>(0, 0) * forceConstrained.block<3, 1>(6, 0);
+        forceConstrained.block<3, 1>(9, 0) = rightCurrentPose.block<3, 3>(0, 0) * forceConstrained.block<3, 1>(9, 0);
+
+
+
+
+
+
+        // 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 targetTCPLinearVelocity;
+            targetTCPLinearVelocity << 0.001 * rightTargetVel(0), 0.001 * rightTargetVel(1), 0.001 * rightTargetVel(2);
+
+            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(targetTCPLinearVelocity - 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 forceUnconstrained(12);
+        forceUnconstrained << leftJointControlWrench, rightJointControlWrench;
+
+        Eigen::VectorXf unConstrainedForceMeasure = pinvGraspMatrix * graspMatrix * filteredForce;
+
+        Eigen::MatrixXf taskSpaceInertia = (jacobi * M.inverse() *  jacobi.transpose()).inverse();
+
+
+
+        forceUnconstrained = taskSpaceInertia * forceUnconstrained ;//+ unConstrainedForceMeasure) - unConstrainedForceMeasure;
+
+        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::MatrixXf jtpinvR = leftIK->computePseudoInverseJacobianMatrix(jacobiR.transpose(), lambda);
+        forceUnconstrained.head(8) = forceUnconstrained.head(8) + (I - jacobiL.transpose() * jtpinvL) * leftNullspaceTorque;
+        forceUnconstrained.tail<8>() = forceUnconstrained.tail<8>() + (I - jacobiR.transpose() * jtpinvR) * rightNullspaceTorque;
+
+
+        //
+        ////        Eigen::VectorXf leftJointDesiredTorques = jacobiL.transpose() * leftJointControlWrench + (I - jacobiL.transpose() * jtpinvL) * leftNullspaceTorque;
+        //        Eigen::VectorXf leftJointDesiredTorques = jacobiL.transpose() * forceUnconstrained.head(6) + (I - jacobiL.transpose() * jtpinvL) * leftNullspaceTorque;
+
+        //
+        ////        Eigen::VectorXf rightJointDesiredTorques = jacobiR.transpose() * rightJointControlWrench + (I - jacobiR.transpose() * jtpinvR) * rightNullspaceTorque;
+        //        Eigen::VectorXf rightJointDesiredTorques = jacobiR.transpose() * forceUnconstrained.tail<6>() + (I - jacobiR.transpose() * jtpinvR) * rightNullspaceTorque;
+
+        //        Eigen::VectorXf torqueUnconstrained(16);
+        //        torqueUnconstrained << leftJointDesiredTorques, rightJointDesiredTorques;
+
+        // constrained space control
+
+        //        Eigen::MatrixXf mu = (Eigen::MatrixXf::Identity(n, n) - projection) * M * Mc.inverse();
+        //        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 torqueConstrained = mu * (torqueUnconstrained + (Eigen::MatrixXf::Identity(n, n) - projection) * qacc) - jacobiConstrained.transpose() * forceConstrained;
+
+
+        // all torques
+
+
+
+        //        Eigen::VectorXf torqueInput = projection * torqueUnconstrained + projection * torqueConstrained;
+        //        Eigen::VectorXf torqueInput = torqueUnconstrained + jacobi.transpose() * (Eigen::MatrixXf::Identity(12,12) - proj2GraspNullspace) * forceConstrained;
+        //        Eigen::VectorXf torqueInput = torqueUnconstrained + jacobi.transpose() * forceConstrained;
+        Eigen::VectorXf torqueInput = jacobi.transpose() * (forceUnconstrained + forceConstrained);
+
+        Eigen::VectorXf leftJointDesiredTorques = torqueInput.head(nl);
+        Eigen::VectorXf 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);
+
+
+        for (size_t i = 0 ; i < 12; ++i)
+        {
+            std::stringstream ss;
+            ss << i;
+            std::string name = "forceConstrained_" + ss.str();
+            debugDataInfo.getWriteBuffer().constrained_force[name] = filteredForce(i);
+        }
+
+
+        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);
+        }
+
+        auto constrained_force = debugDataInfo.getUpToDateReadBuffer().constrained_force;
+        for (auto& pair : constrained_force)
+        {
+            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/NJointBimanualDMPForceController.h b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointBimanualDMPForceController.h
new file mode 100644
index 0000000000000000000000000000000000000000..7b1e430c6f2de6615f4dce83e07027c19455a98a
--- /dev/null
+++ b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointBimanualDMPForceController.h
@@ -0,0 +1,240 @@
+
+#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>
+
+#include <RobotAPI/libraries/core/PIDController.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;
+            StringFloatDictionary constrained_force;
+            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::vector<TaskSpaceDMPControllerPtr > bothLeaderGroup;
+
+
+        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::VectorXf kpf;
+        Eigen::VectorXf 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;
+
+        Eigen::Vector3f filtered_leftForce;
+        Eigen::Vector3f filtered_leftTorque;
+        Eigen::Vector3f filtered_rightForce;
+        Eigen::Vector3f filtered_rightTorque;
+        float filterTimeConstant;
+
+        std::vector<PIDControllerPtr> ftPIDController;
+
+        Eigen::Vector3f offset_leftForce;
+        Eigen::Vector3f offset_leftTorque;
+        Eigen::Vector3f offset_rightForce;
+        Eigen::Vector3f offset_rightTorque;
+
+        bool isForceCompensateDone;
+
+        // NJointBimanualCCDMPControllerInterface interface
+    };
+
+} // namespace armarx
+
diff --git a/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointTSDMPController.cpp b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointTSDMPController.cpp
index 1a62a87186637a75fb9269e2b159aaf3f6b681c8..4ce687e3eb4680d31dcdcda379534ade1020e833 100644
--- a/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointTSDMPController.cpp
+++ b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointTSDMPController.cpp
@@ -92,6 +92,12 @@ namespace armarx
         initData.mode = ModeFromIce(cfg->mode);
         reinitTripleBuffer(initData);
 
+        debugName = cfg->debugName;
+
+        KpF = cfg->Kp_LinearVel;
+        KoF = cfg->Kp_AngularVel;
+        DpF = cfg->Kd_LinearVel;
+        DoF = cfg->Kd_AngularVel;
 
     }
 
@@ -111,49 +117,57 @@ namespace armarx
         Eigen::VectorXf currentTwist = controllerSensorData.getReadBuffer().currentTwist;
 
         taskSpaceDMPController->flow(deltaT, currentPose, currentTwist);
+
+        if (taskSpaceDMPController->canVal < 1e-8)
+        {
+            finished = true;
+        }
         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;
+        targetPose = taskSpaceDMPController->getTargetPoseMat();
+        //        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.getWriteBuffer().mpcFactor =  taskSpaceDMPController->debugData.mpcFactor;
+        //        debugOutputData.getWriteBuffer().error = taskSpaceDMPController->debugData.poseError;
+        //        debugOutputData.getWriteBuffer().posError = taskSpaceDMPController->debugData.posiError;
+        //        debugOutputData.getWriteBuffer().oriError = taskSpaceDMPController->debugData.oriError;
+        //        debugOutputData.getWriteBuffer().deltaT = deltaT;
+
         debugOutputData.commitWrite();
 
         getWriterControlStruct().targetTSVel = targetVels;
+        getWriterControlStruct().targetPose = targetPose;
+
         writeControlStruct();
     }
 
 
     void NJointTSDMPController::rtRun(const IceUtil::Time& sensorValuesTimestamp, const IceUtil::Time& timeSinceLastIteration)
     {
-        Eigen::Matrix4f pose = tcp->getPoseInRootFrame();
+        Eigen::Matrix4f currentPose = tcp->getPoseInRootFrame();
         double deltaT = timeSinceLastIteration.toSecondsDouble();
 
         Eigen::MatrixXf jacobi = ik->getJacobianMatrix(tcp, VirtualRobot::IKSolver::CartesianSelection::All);
@@ -167,7 +181,7 @@ namespace armarx
 
         Eigen::VectorXf tcptwist = jacobi * qvel;
 
-        controllerSensorData.getWriteBuffer().currentPose = pose;
+        controllerSensorData.getWriteBuffer().currentPose = currentPose;
         controllerSensorData.getWriteBuffer().currentTwist = tcptwist;
         controllerSensorData.getWriteBuffer().deltaT = deltaT;
         controllerSensorData.getWriteBuffer().currentTime += deltaT;
@@ -175,17 +189,29 @@ namespace armarx
 
 
         Eigen::VectorXf targetVel = rtGetControlStruct().targetTSVel;
+        Eigen::Matrix4f targetPose = rtGetControlStruct().targetPose;
 
-        float normLinearVelocity = targetVel.block<3, 1>(0, 0).norm();
+
+        Eigen::Matrix3f diffMat = targetPose.block<3, 3>(0, 0) * currentPose.block<3, 3>(0, 0).inverse();
+        Eigen::Vector3f errorRPY = VirtualRobot::MathTools::eigen3f2rpy(diffMat);
+
+
+        Eigen::VectorXf rtTargetVel;
+        rtTargetVel.resize(6);
+        rtTargetVel.block<3, 1>(0, 0) = KpF * (targetPose.block<3, 1>(0, 3) - currentPose.block<3, 1>(0, 3)) + DpF * (targetVel.block<3, 1>(0, 0) - tcptwist.block<3, 1>(0, 0));
+        rtTargetVel.block<3, 1>(3, 0) = KoF * errorRPY + DoF * (targetVel.block<3, 1>(3, 0) - tcptwist.block<3, 1>(3, 0));
+
+
+        float normLinearVelocity = rtTargetVel.block<3, 1>(0, 0).norm();
         if (normLinearVelocity > cfg->maxLinearVel)
         {
-            targetVel.block<3, 1>(0, 0) = cfg->maxLinearVel * targetVel.block<3, 1>(0, 0) / normLinearVelocity;
+            rtTargetVel.block<3, 1>(0, 0) = cfg->maxLinearVel * rtTargetVel.block<3, 1>(0, 0) / normLinearVelocity;
         }
 
-        float normAngularVelocity = targetVel.block<3, 1>(3, 0).norm();
+        float normAngularVelocity = rtTargetVel.block<3, 1>(3, 0).norm();
         if (normAngularVelocity > cfg->maxAngularVel)
         {
-            targetVel.block<3, 1>(3, 0) = cfg->maxAngularVel * targetVel.block<3, 1>(3, 0) / normAngularVelocity;
+            rtTargetVel.block<3, 1>(3, 0) = cfg->maxAngularVel * rtTargetVel.block<3, 1>(3, 0) / normAngularVelocity;
         }
 
 
@@ -198,7 +224,7 @@ namespace armarx
             x.resize(6);
             for (size_t i = 0; i < 6; i++)
             {
-                x(i) = targetVel(i);
+                x(i) = rtTargetVel(i);
             }
         }
         else if (mode == VirtualRobot::IKSolver::Position)
@@ -206,7 +232,7 @@ namespace armarx
             x.resize(3);
             for (size_t i = 0; i < 3; i++)
             {
-                x(i) = targetVel(i);
+                x(i) = rtTargetVel(i);
             }
 
         }
@@ -215,11 +241,12 @@ namespace armarx
             x.resize(3);
             for (size_t i = 0; i < 3; i++)
             {
-                x(i) = targetVel(i + 3);
+                x(i) = rtTargetVel(i + 3);
             }
         }
         else
         {
+
             // No mode has been set
             return;
         }
@@ -250,6 +277,8 @@ namespace armarx
         {
             targets.at(i)->velocity = jointTargetVelocities(i);
         }
+
+
     }
 
 
@@ -349,34 +378,44 @@ namespace armarx
 
     void NJointTSDMPController::onPublish(const SensorAndControl&, const DebugDrawerInterfacePrx&, const DebugObserverInterfacePrx& debugObs)
     {
+        std::string datafieldName = debugName;
         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["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);
+        //        auto values = debugOutputData.getUpToDateReadBuffer().latestTargetVelocities;
+        //        for (auto& pair : values)
+        //        {
+        //            datafieldName = pair.first  + "_" + debugName;
+        //            datafields[datafieldName] = new Variant(pair.second);
+        //        }
+
+        //        auto dmpTargets = debugOutputData.getUpToDateReadBuffer().dmpTargets;
+        //        for (auto& pair : dmpTargets)
+        //        {
+        //            datafieldName = pair.first  + "_" + debugName;
+        //            datafields[datafieldName] = new Variant(pair.second);
+        //        }
+
+        //        auto currentPose = debugOutputData.getUpToDateReadBuffer().currentPose;
+        //        for (auto& pair : currentPose)
+        //        {
+        //            datafieldName = pair.first + "_" + debugName;
+        //            datafields[datafieldName] = new Variant(pair.second);
+        //        }
+
+        datafieldName = "canVal_" + debugName;
+        datafields[datafieldName] = new Variant(debugOutputData.getUpToDateReadBuffer().currentCanVal);
+        //        datafieldName = "mpcFactor_" + debugName;
+        //        datafields[datafieldName] = new Variant(debugOutputData.getUpToDateReadBuffer().mpcFactor);
+        //        datafieldName = "error_" + debugName;
+        //        datafields[datafieldName] = new Variant(debugOutputData.getUpToDateReadBuffer().error);
+        //        datafieldName = "posError_" + debugName;
+        //        datafields[datafieldName] = new Variant(debugOutputData.getUpToDateReadBuffer().posError);
+        //        datafieldName = "oriError_" + debugName;
+        //        datafields[datafieldName] = new Variant(debugOutputData.getUpToDateReadBuffer().oriError);
+        //        datafieldName = "deltaT_" + debugName;
+        //        datafields[datafieldName] = new Variant(debugOutputData.getUpToDateReadBuffer().deltaT);
+        //        datafieldName = "DMPController_" + debugName;
+
+        debugObs->setDebugChannel(datafieldName, datafields);
     }
 
     void NJointTSDMPController::onInitComponent()
diff --git a/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointTSDMPController.h b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointTSDMPController.h
index a70f5a2962b929399e8a1a0f4e24d63a0a425687..c3473908f7d29783ea091533c8e86525eb0b7a6f 100644
--- a/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointTSDMPController.h
+++ b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointTSDMPController.h
@@ -27,6 +27,7 @@ namespace armarx
     {
     public:
         Eigen::VectorXf targetTSVel;
+        Eigen::Matrix4f targetPose;
         // cartesian velocity control data
         std::vector<float> nullspaceJointVelocities;
         float avoidJointLimitsKp = 0;
@@ -81,7 +82,7 @@ namespace armarx
         void setTorqueKp(const StringFloatDictionary& torqueKp, const Ice::Current&);
         void setNullspaceJointVelocities(const StringFloatDictionary& nullspaceJointVelocities, const Ice::Current&);
 
-        double getCanVal(const Ice::Current &)
+        double getCanVal(const Ice::Current&)
         {
             return taskSpaceDMPController->canVal;
         }
@@ -143,13 +144,19 @@ namespace armarx
         VirtualRobot::DifferentialIKPtr ik;
         VirtualRobot::RobotNodePtr tcp;
         Eigen::VectorXf targetVels;
+        Eigen::Matrix4f targetPose;
 
         NJointTaskSpaceDMPControllerConfigPtr cfg;
         mutable MutexType controllerMutex;
         PeriodicTask<NJointTSDMPController>::pointer_type controllerTask;
 
-        // NJointTaskSpaceDMPControllerInterface interface
 
+        std::string debugName;
+
+        float KpF;
+        float DpF;
+        float KoF;
+        float DoF;
     };
 
 } // namespace armarx
diff --git a/source/RobotAPI/libraries/core/CMakeLists.txt b/source/RobotAPI/libraries/core/CMakeLists.txt
index dc91c6a504edfc82e05c44ed64af3367e00ade53..76beb836204971595ff2b84c4b2f973ea488bb09 100644
--- a/source/RobotAPI/libraries/core/CMakeLists.txt
+++ b/source/RobotAPI/libraries/core/CMakeLists.txt
@@ -41,6 +41,9 @@ set(LIB_FILES
     math/TimeSeriesUtils.cpp
     CartesianVelocityController.cpp
     CartesianPositionController.cpp
+    CartesianVelocityRamp.cpp
+    JointVelocityRamp.cpp
+    CartesianVelocityControllerWithRamp.cpp
 )
 
 set(LIB_HEADERS
@@ -77,6 +80,10 @@ set(LIB_HEADERS
     math/TimeSeriesUtils.h
     CartesianVelocityController.h
     CartesianPositionController.h
+    CartesianVelocityRamp.h
+    JointVelocityRamp.h
+    CartesianVelocityControllerWithRamp.h
+    EigenHelpers.h
 )
 
 
diff --git a/source/RobotAPI/libraries/core/CartesianVelocityController.cpp b/source/RobotAPI/libraries/core/CartesianVelocityController.cpp
index 3e7765206e1dfd0375da9bc64c2a3f1fc326fdfd..d873e26c9078764965ba7f49f3f95de7ee63bcb9 100644
--- a/source/RobotAPI/libraries/core/CartesianVelocityController.cpp
+++ b/source/RobotAPI/libraries/core/CartesianVelocityController.cpp
@@ -37,9 +37,17 @@ CartesianVelocityController::CartesianVelocityController(const VirtualRobot::Rob
     ik.reset(new VirtualRobot::DifferentialIK(rns, rns->getRobot()->getRootNode(), VirtualRobot::JacobiProvider::eSVDDamped));
     this->tcp = tcp ? tcp : rns->getTCP();
 
+    this->cartesianMMRegularization = 100;
+    this->cartesianRadianRegularization = 1;
 }
 
-Eigen::VectorXf CartesianVelocityController::calculate(Eigen::VectorXf cartesianVel, Eigen::VectorXf nullspaceVel, VirtualRobot::IKSolver::CartesianSelection mode)
+Eigen::VectorXf CartesianVelocityController::calculate(const Eigen::VectorXf& cartesianVel, float KpJointLimitAvoidanceScale, VirtualRobot::IKSolver::CartesianSelection mode)
+{
+    Eigen::VectorXf nullspaceVel = calculateNullspaceVelocity(cartesianVel, KpJointLimitAvoidanceScale, mode);
+    return calculate(cartesianVel, nullspaceVel, mode);
+}
+
+Eigen::VectorXf CartesianVelocityController::calculate(const Eigen::VectorXf& cartesianVel, const Eigen::VectorXf& nullspaceVel, VirtualRobot::IKSolver::CartesianSelection mode)
 {
     //ARMARX_IMPORTANT << VAROUT(rns.get());
     //ARMARX_IMPORTANT << VAROUT(tcp.get());
@@ -52,11 +60,11 @@ Eigen::VectorXf CartesianVelocityController::calculate(Eigen::VectorXf cartesian
     Eigen::FullPivLU<Eigen::MatrixXf> lu_decomp(jacobi);
     //ARMARX_IMPORTANT << "The rank of the jacobi is " << lu_decomp.rank();
     //ARMARX_IMPORTANT << "Null space: " << lu_decomp.kernel();
-    Eigen::MatrixXf kernel = lu_decomp.kernel();
-    Eigen::VectorXf nsv = Eigen::VectorXf::Zero(kernel.rows());
-    for (int i = 0; i < kernel.cols(); i++)
+    Eigen::MatrixXf nullspace = lu_decomp.kernel();
+    Eigen::VectorXf nsv = Eigen::VectorXf::Zero(nullspace.rows());
+    for (int i = 0; i < nullspace.cols(); i++)
     {
-        nsv += kernel.col(i) * kernel.col(i).dot(nullspaceVel) / kernel.col(i).squaredNorm();
+        nsv += nullspace.col(i) * nullspace.col(i).dot(nullspaceVel) / nullspace.col(i).squaredNorm();
     }
 
     //nsv /= kernel.cols();
@@ -85,3 +93,46 @@ Eigen::VectorXf CartesianVelocityController::calculateJointLimitAvoidance()
     }
     return r;
 }
+
+Eigen::VectorXf CartesianVelocityController::calculateNullspaceVelocity(const Eigen::VectorXf& cartesianVel, float KpScale, VirtualRobot::IKSolver::CartesianSelection mode)
+{
+    Eigen::VectorXf regularization = calculateRegularization(mode);
+    Eigen::VectorXf vel = cartesianVel * regularization;
+    return KpScale * vel.norm() * calculateJointLimitAvoidance();
+}
+
+void CartesianVelocityController::setCartesianRegularization(float cartesianMMRegularization, float cartesianRadianRegularization)
+{
+    this->cartesianMMRegularization = cartesianMMRegularization;
+    this->cartesianRadianRegularization = cartesianRadianRegularization;
+}
+
+Eigen::VectorXf CartesianVelocityController::calculateRegularization(VirtualRobot::IKSolver::CartesianSelection mode)
+{
+    Eigen::VectorXf regularization(6);
+
+    int i = 0;
+
+    if (mode & VirtualRobot::IKSolver::X)
+    {
+        regularization(i++) = 1 / cartesianMMRegularization;
+    }
+
+    if (mode & VirtualRobot::IKSolver::Y)
+    {
+        regularization(i++) = 1 / cartesianMMRegularization;
+    }
+
+    if (mode & VirtualRobot::IKSolver::Z)
+    {
+        regularization(i++) = 1 / cartesianMMRegularization;
+    }
+
+    if (mode & VirtualRobot::IKSolver::Orientation)
+    {
+        regularization(i++) = 1 / cartesianRadianRegularization;
+        regularization(i++) = 1 / cartesianRadianRegularization;
+        regularization(i++) = 1 / cartesianRadianRegularization;
+    }
+    return regularization.topRows(i);
+}
diff --git a/source/RobotAPI/libraries/core/CartesianVelocityController.h b/source/RobotAPI/libraries/core/CartesianVelocityController.h
index e55ec62c33b48b83cba6c1131750b5eb9e6e7b61..66fbcf4bb8ddc7462e2cc087a811cbb5971ff076 100644
--- a/source/RobotAPI/libraries/core/CartesianVelocityController.h
+++ b/source/RobotAPI/libraries/core/CartesianVelocityController.h
@@ -41,16 +41,24 @@ namespace armarx
     public:
         CartesianVelocityController(const VirtualRobot::RobotNodeSetPtr& rns, const VirtualRobot::RobotNodePtr& tcp = nullptr);
 
-        Eigen::VectorXf calculate(Eigen::VectorXf cartesianVel, Eigen::VectorXf nullspaceVel, VirtualRobot::IKSolver::CartesianSelection mode);
+        Eigen::VectorXf calculate(const Eigen::VectorXf& cartesianVel, float KpJointLimitAvoidanceScale, VirtualRobot::IKSolver::CartesianSelection mode);
+        Eigen::VectorXf calculate(const Eigen::VectorXf& cartesianVel, const Eigen::VectorXf& nullspaceVel, VirtualRobot::IKSolver::CartesianSelection mode);
         Eigen::VectorXf calculateJointLimitAvoidance();
+        Eigen::VectorXf calculateNullspaceVelocity(const Eigen::VectorXf& cartesianVel, float KpScale, VirtualRobot::IKSolver::CartesianSelection mode);
+
+        void setCartesianRegularization(float cartesianMMRegularization, float cartesianRadianRegularization);
 
         Eigen::MatrixXf jacobi;
         Eigen::MatrixXf inv;
         VirtualRobot::RobotNodeSetPtr rns;
-
-    private:
         VirtualRobot::DifferentialIKPtr ik;
         VirtualRobot::RobotNodePtr tcp;
+
+    private:
+        Eigen::VectorXf calculateRegularization(VirtualRobot::IKSolver::CartesianSelection mode);
+
+        float cartesianMMRegularization;
+        float cartesianRadianRegularization;
     };
 }
 
diff --git a/source/RobotAPI/libraries/core/CartesianVelocityControllerWithRamp.cpp b/source/RobotAPI/libraries/core/CartesianVelocityControllerWithRamp.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..264db7d88a2101edcf3d674e3ccfa4abbfae8734
--- /dev/null
+++ b/source/RobotAPI/libraries/core/CartesianVelocityControllerWithRamp.cpp
@@ -0,0 +1,83 @@
+/*
+ * This file is part of ArmarX.
+ *
+ * Copyright (C) 2012-2016, High Performance Humanoid Technologies (H2T),
+ * Karlsruhe Institute of Technology (KIT), all rights reserved.
+ *
+ * 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/>.
+ *
+ * @author     Sonja Marahrens (sonja dot marahrens)
+ * @copyright  http://www.gnu.org/licenses/gpl-2.0.txt
+ *             GNU General Public License
+ */
+
+#include "CartesianVelocityControllerWithRamp.h"
+
+using namespace armarx;
+
+CartesianVelocityControllerWithRamp::CartesianVelocityControllerWithRamp(const VirtualRobot::RobotNodeSetPtr& rns, const Eigen::VectorXf& currentJointVelocity, VirtualRobot::IKSolver::CartesianSelection mode,
+        float maxPositionAcceleration, float maxOrientationAcceleration, float maxNullspaceAcceleration, const VirtualRobot::RobotNodePtr& tcp)
+    : controller(rns, tcp), mode(mode)
+{
+    setMaxAccelerations(maxPositionAcceleration, maxOrientationAcceleration, maxNullspaceAcceleration);
+    setCurrentJointVelocity(currentJointVelocity);
+}
+
+void CartesianVelocityControllerWithRamp::setCurrentJointVelocity(const Eigen::VectorXf& currentJointVelocity)
+{
+    Eigen::MatrixXf jacobi = controller.ik->getJacobianMatrix(controller.tcp, mode);
+
+    Eigen::FullPivLU<Eigen::MatrixXf> lu_decomp(jacobi);
+    Eigen::MatrixXf nullspace = lu_decomp.kernel();
+    Eigen::VectorXf nsv = Eigen::VectorXf::Zero(nullspace.rows());
+    for (int i = 0; i < nullspace.cols(); i++)
+    {
+        nsv += nullspace.col(i) * nullspace.col(i).dot(currentJointVelocity) / nullspace.col(i).squaredNorm();
+    }
+
+    cartesianVelocityRamp.setState(jacobi * currentJointVelocity, mode);
+    nullSpaceVelocityRamp.setState(nsv);
+}
+
+Eigen::VectorXf CartesianVelocityControllerWithRamp::calculate(const Eigen::VectorXf& cartesianVel, float jointLimitAvoidanceScale, float dt)
+{
+    Eigen::VectorXf nullspaceVel = controller.calculateNullspaceVelocity(cartesianVel, jointLimitAvoidanceScale, mode);
+    return calculate(cartesianVel, nullspaceVel, dt);
+}
+
+Eigen::VectorXf CartesianVelocityControllerWithRamp::calculate(const Eigen::VectorXf& cartesianVel, const Eigen::VectorXf& nullspaceVel, float dt)
+{
+    return controller.calculate(cartesianVelocityRamp.update(cartesianVel, dt), nullSpaceVelocityRamp.update(nullspaceVel, dt), mode);
+}
+
+void CartesianVelocityControllerWithRamp::setMaxAccelerations(float maxPositionAcceleration, float maxOrientationAcceleration, float maxNullspaceAcceleration)
+{
+    cartesianVelocityRamp.setMaxOrientationAcceleration(maxOrientationAcceleration);
+    cartesianVelocityRamp.setMaxPositionAcceleration(maxPositionAcceleration);
+    nullSpaceVelocityRamp.setMaxAccelaration(maxNullspaceAcceleration);
+}
+
+float CartesianVelocityControllerWithRamp::getMaxOrientationAcceleration()
+{
+    return cartesianVelocityRamp.getMaxOrientationAcceleration();
+}
+
+float CartesianVelocityControllerWithRamp::getMaxPositionAcceleration()
+{
+    return cartesianVelocityRamp.getMaxPositionAcceleration();
+}
+
+float CartesianVelocityControllerWithRamp::getMaxNullspaceAcceleration()
+{
+    return nullSpaceVelocityRamp.getMaxAccelaration();
+}
diff --git a/source/RobotAPI/libraries/core/CartesianVelocityControllerWithRamp.h b/source/RobotAPI/libraries/core/CartesianVelocityControllerWithRamp.h
new file mode 100644
index 0000000000000000000000000000000000000000..a32b443a67476363b1456cfa583cc99eb7deb549
--- /dev/null
+++ b/source/RobotAPI/libraries/core/CartesianVelocityControllerWithRamp.h
@@ -0,0 +1,69 @@
+/*
+ * This file is part of ArmarX.
+ *
+ * Copyright (C) 2012-2016, High Performance Humanoid Technologies (H2T),
+ * Karlsruhe Institute of Technology (KIT), all rights reserved.
+ *
+ * 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/>.
+ *
+ * @author     Sonja Marahrens (sonja dot marahrens)
+ * @copyright  http://www.gnu.org/licenses/gpl-2.0.txt
+ *             GNU General Public License
+ */
+
+#pragma once
+
+#include "CartesianVelocityController.h"
+#include "CartesianVelocityRamp.h"
+#include "JointVelocityRamp.h"
+
+#include <boost/shared_ptr.hpp>
+
+#include <VirtualRobot/RobotNodeSet.h>
+
+#include <VirtualRobot/IK/DifferentialIK.h>
+#include <VirtualRobot/Robot.h>
+#include <Eigen/Dense>
+
+
+namespace armarx
+{
+    class CartesianVelocityControllerWithRamp;
+    typedef boost::shared_ptr<CartesianVelocityControllerWithRamp> CartesianVelocityControllerWithRampPtr;
+
+    class CartesianVelocityControllerWithRamp
+    {
+    public:
+        CartesianVelocityControllerWithRamp(const VirtualRobot::RobotNodeSetPtr& rns, const Eigen::VectorXf& currentJointVelocity, VirtualRobot::IKSolver::CartesianSelection mode,
+                                            float maxPositionAcceleration, float maxOrientationAcceleration, float maxNullspaceAcceleration,
+                                            const VirtualRobot::RobotNodePtr& tcp = nullptr);
+
+        void setCurrentJointVelocity(const Eigen::VectorXf& currentJointVelocity);
+
+        Eigen::VectorXf calculate(const Eigen::VectorXf& cartesianVel, float jointLimitAvoidanceScale, float dt);
+        Eigen::VectorXf calculate(const Eigen::VectorXf& cartesianVel, const Eigen::VectorXf& nullspaceVel, float dt);
+
+        void setMaxAccelerations(float maxPositionAcceleration, float maxOrientationAcceleration, float maxNullspaceAcceleration);
+
+        float getMaxOrientationAcceleration();
+        float getMaxPositionAcceleration();
+        float getMaxNullspaceAcceleration();
+
+
+        CartesianVelocityController controller;
+    private:
+        VirtualRobot::IKSolver::CartesianSelection mode;
+        CartesianVelocityRamp cartesianVelocityRamp;
+        JointVelocityRamp nullSpaceVelocityRamp;
+    };
+}
diff --git a/source/RobotAPI/libraries/core/CartesianVelocityRamp.cpp b/source/RobotAPI/libraries/core/CartesianVelocityRamp.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b5ed838bd322bd78581b68c52328454d3556dcb9
--- /dev/null
+++ b/source/RobotAPI/libraries/core/CartesianVelocityRamp.cpp
@@ -0,0 +1,86 @@
+/*
+ * This file is part of ArmarX.
+ *
+ * Copyright (C) 2012-2016, High Performance Humanoid Technologies (H2T),
+ * Karlsruhe Institute of Technology (KIT), all rights reserved.
+ *
+ * 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/>.
+ *
+ * @author     Sonja Marahrens (sonja dot marahrens)
+ * @copyright  http://www.gnu.org/licenses/gpl-2.0.txt
+ *             GNU General Public License
+ */
+
+#include "CartesianVelocityRamp.h"
+
+using namespace armarx;
+
+CartesianVelocityRamp::CartesianVelocityRamp()
+{ }
+
+void CartesianVelocityRamp::setState(const Eigen::VectorXf& state, VirtualRobot::IKSolver::CartesianSelection mode)
+{
+    this->state = state;
+    this->mode = mode;
+}
+
+Eigen::VectorXf CartesianVelocityRamp::update(const Eigen::VectorXf& target, float dt)
+{
+    if (dt <= 0)
+    {
+        return state;
+    }
+    Eigen::VectorXf delta = target - state;
+    int i = 0;
+    float factor = 1 ;
+
+    if (mode & VirtualRobot::IKSolver::Position)
+    {
+        Eigen::Vector3f posDelta = delta.block<3, 1>(i, 0);
+        float posFactor = posDelta.norm() / maxPositionAcceleration / dt;
+        factor = std::max(factor, posFactor);
+        i += 3;
+    }
+
+    if (mode & VirtualRobot::IKSolver::Orientation)
+    {
+        Eigen::Vector3f oriDelta = delta.block<3, 1>(i, 0);
+        float oriFactor = oriDelta.norm() / maxOrientationAcceleration / dt;
+        factor = std::max(factor, oriFactor);
+    }
+
+    state += delta / factor;
+    return state;
+}
+
+void CartesianVelocityRamp::setMaxPositionAcceleration(float maxPositionAcceleration)
+{
+    this->maxPositionAcceleration = maxPositionAcceleration;
+
+}
+
+void CartesianVelocityRamp::setMaxOrientationAcceleration(float maxOrientationAcceleration)
+{
+    this->maxOrientationAcceleration = maxOrientationAcceleration;
+
+}
+
+float CartesianVelocityRamp::getMaxPositionAcceleration()
+{
+    return maxPositionAcceleration;
+}
+
+float CartesianVelocityRamp::getMaxOrientationAcceleration()
+{
+    return maxOrientationAcceleration;
+}
diff --git a/source/RobotAPI/libraries/core/CartesianVelocityRamp.h b/source/RobotAPI/libraries/core/CartesianVelocityRamp.h
new file mode 100644
index 0000000000000000000000000000000000000000..51abe44bc22a8647062397e9ee2fb123129ae7c4
--- /dev/null
+++ b/source/RobotAPI/libraries/core/CartesianVelocityRamp.h
@@ -0,0 +1,59 @@
+/*
+ * This file is part of ArmarX.
+ *
+ * Copyright (C) 2012-2016, High Performance Humanoid Technologies (H2T),
+ * Karlsruhe Institute of Technology (KIT), all rights reserved.
+ *
+ * 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/>.
+ *
+ * @author     Sonja Marahrens (sonja dot marahrens)
+ * @copyright  http://www.gnu.org/licenses/gpl-2.0.txt
+ *             GNU General Public License
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+#include <VirtualRobot/IK/DifferentialIK.h>
+#include <VirtualRobot/Robot.h>
+#include <Eigen/Dense>
+
+namespace armarx
+{
+    class CartesianVelocityRamp;
+    typedef boost::shared_ptr<CartesianVelocityRamp> CartesianVelocityRampPtr;
+
+    class CartesianVelocityRamp
+    {
+    public:
+        CartesianVelocityRamp();
+        void setState(const Eigen::VectorXf& state, VirtualRobot::IKSolver::CartesianSelection mode);
+
+        Eigen::VectorXf update(const Eigen::VectorXf& target, float dt);
+
+        void setMaxPositionAcceleration(float maxPositionAcceleration);
+        void setMaxOrientationAcceleration(float maxOrientationAcceleration);
+
+        float getMaxPositionAcceleration();
+        float getMaxOrientationAcceleration();
+
+    private:
+        float maxPositionAcceleration = 0;
+        float maxOrientationAcceleration = 0;
+
+        Eigen::VectorXf state = Eigen::VectorXf::Zero(6);
+        VirtualRobot::IKSolver::CartesianSelection mode = VirtualRobot::IKSolver::CartesianSelection::All;
+
+
+    };
+}
diff --git a/source/RobotAPI/libraries/core/EigenHelpers.h b/source/RobotAPI/libraries/core/EigenHelpers.h
new file mode 100644
index 0000000000000000000000000000000000000000..742bcca37d57df9541eebf9eb508197a46bed251
--- /dev/null
+++ b/source/RobotAPI/libraries/core/EigenHelpers.h
@@ -0,0 +1,117 @@
+/*
+ * This file is part of ArmarX.
+ *
+ * Copyright (C) 2012-2016, High Performance Humanoid Technologies (H2T),
+ * Karlsruhe Institute of Technology (KIT), all rights reserved.
+ *
+ * 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/>.
+ *
+ * @author     Simon Ottenhaus (simon dot ottenhaus at kit dot edu)
+ * @copyright  http://www.gnu.org/licenses/gpl-2.0.txt
+ *             GNU General Public License
+ */
+
+#pragma once
+
+#include <eigen3/Eigen/Core>
+
+namespace armarx
+{
+
+    template<class ScalarType>
+    inline Eigen::Matrix<ScalarType, Eigen::Dynamic, 1> MakeVectorX(std::initializer_list<ScalarType> ilist)
+    {
+        Eigen::Matrix<ScalarType, Eigen::Dynamic, 1> r(ilist.size());
+        std::size_t i = 0;
+        for (const auto e : ilist)
+        {
+            r(i++) = e;
+        }
+        return r;
+    }
+    inline Eigen::Matrix<float, Eigen::Dynamic, 1> MakeVectorXf(std::initializer_list<float> ilist)
+    {
+        return MakeVectorX<float>(ilist);
+    }
+
+    template<class ScalarType, class...Ts>
+    inline Eigen::Matrix<ScalarType, Eigen::Dynamic, 1> MakeVectorXWarnNarrowing(Ts&& ...ts)
+    {
+        return MakeVectorX<ScalarType>(std::initializer_list<ScalarType> {std::forward<Ts>(ts)...});
+    }
+    template<class ScalarType, class...Ts>
+    inline Eigen::Matrix<ScalarType, Eigen::Dynamic, 1> MakeVectorXIgnoreNarrowing(Ts&& ...ts)
+    {
+        return MakeVectorX<ScalarType>(std::initializer_list<ScalarType> {static_cast<ScalarType>(std::forward<Ts>(ts))...});
+    }
+    template<class ScalarType, class...Ts>
+    inline Eigen::Matrix<ScalarType, Eigen::Dynamic, 1> MakeVectorX(Ts&& ...ts)
+    {
+        return MakeVectorX<ScalarType>(std::initializer_list<ScalarType> {static_cast<ScalarType>(std::forward<Ts>(ts))...});
+    }
+
+    inline Eigen::Matrix<float, Eigen::Dynamic, 1> MakeVectorXf(std::vector<float> vec)
+    {
+        Eigen::Matrix<float, Eigen::Dynamic, 1> r(vec.size());
+        std::size_t i = 0;
+        for (const auto e : vec)
+        {
+            r(i++) = e;
+        }
+        return r;
+    }
+
+    /* Qt-Creator does not support variable amount of parameters. The following methods are only for Qt-Creator. */
+    inline Eigen::Matrix<float, Eigen::Dynamic, 1> MakeVectorXf(float f1)
+    {
+        return MakeVectorX<float>(f1);
+    }
+    inline Eigen::Matrix<float, Eigen::Dynamic, 1> MakeVectorXf(float f1, float f2)
+    {
+        return MakeVectorX<float>(f1, f2);
+    }
+    inline Eigen::Matrix<float, Eigen::Dynamic, 1> MakeVectorXf(float f1, float f2, float f3)
+    {
+        return MakeVectorX<float>(f1, f2, f3);
+    }
+    inline Eigen::Matrix<float, Eigen::Dynamic, 1> MakeVectorXf(float f1, float f2, float f3, float f4)
+    {
+        return MakeVectorX<float>(f1, f2, f3, f4);
+    }
+    inline Eigen::Matrix<float, Eigen::Dynamic, 1> MakeVectorXf(float f1, float f2, float f3, float f4, float f5)
+    {
+        return MakeVectorX<float>(f1, f2, f3, f4, f5);
+    }
+    inline Eigen::Matrix<float, Eigen::Dynamic, 1> MakeVectorXf(float f1, float f2, float f3, float f4, float f5, float f6)
+    {
+        return MakeVectorX<float>(f1, f2, f3, f4, f5, f6);
+    }
+    inline Eigen::Matrix<float, Eigen::Dynamic, 1> MakeVectorXf(float f1, float f2, float f3, float f4, float f5, float f6, float f7)
+    {
+        return MakeVectorX<float>(f1, f2, f3, f4, f5, f6, f7);
+    }
+    inline Eigen::Matrix<float, Eigen::Dynamic, 1> MakeVectorXf(float f1, float f2, float f3, float f4, float f5, float f6, float f7, float f8)
+    {
+        return MakeVectorX<float>(f1, f2, f3, f4, f5, f6, f7, f8);
+    }
+    inline Eigen::Matrix<float, Eigen::Dynamic, 1> MakeVectorXf(float f1, float f2, float f3, float f4, float f5, float f6, float f7, float f8, float f9)
+    {
+        return MakeVectorX<float>(f1, f2, f3, f4, f5, f6, f7, f8, f9);
+    }
+    inline Eigen::Matrix<float, Eigen::Dynamic, 1> MakeVectorXf(float f1, float f2, float f3, float f4, float f5, float f6, float f7, float f8, float f9, float f10)
+    {
+        return MakeVectorX<float>(f1, f2, f3, f4, f5, f6, f7, f8, f9, f10);
+    }
+
+
+}
diff --git a/source/RobotAPI/libraries/core/JointVelocityRamp.cpp b/source/RobotAPI/libraries/core/JointVelocityRamp.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f0488c9e3e4c743b1add06c1e9bbe13cf7a92ebc
--- /dev/null
+++ b/source/RobotAPI/libraries/core/JointVelocityRamp.cpp
@@ -0,0 +1,60 @@
+/*
+ * This file is part of ArmarX.
+ *
+ * Copyright (C) 2012-2016, High Performance Humanoid Technologies (H2T),
+ * Karlsruhe Institute of Technology (KIT), all rights reserved.
+ *
+ * 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/>.
+ *
+ * @author     Sonja Marahrens (sonja dot marahrens)
+ * @copyright  http://www.gnu.org/licenses/gpl-2.0.txt
+ *             GNU General Public License
+ */
+
+#include "JointVelocityRamp.h"
+
+using namespace armarx;
+
+
+JointVelocityRamp::JointVelocityRamp()
+{ }
+
+void JointVelocityRamp::setState(const Eigen::VectorXf& state)
+{
+    this->state = state;
+}
+
+Eigen::VectorXf JointVelocityRamp::update(const Eigen::VectorXf& target, float dt)
+{
+
+    Eigen::VectorXf delta = target - state;
+
+    float factor = delta.norm() / maxAcceleration;
+    factor = std::max(factor, 1.f);
+
+    state += delta / factor * dt;
+    return state;
+
+}
+
+void JointVelocityRamp::setMaxAccelaration(float maxAcceleration)
+{
+    this->maxAcceleration = maxAcceleration;
+
+}
+
+float JointVelocityRamp::getMaxAccelaration()
+{
+    return maxAcceleration;
+}
+
diff --git a/source/RobotAPI/libraries/core/JointVelocityRamp.h b/source/RobotAPI/libraries/core/JointVelocityRamp.h
new file mode 100644
index 0000000000000000000000000000000000000000..c31b4a4c2a5448653c7a7f7bbe2dd095f9573b2a
--- /dev/null
+++ b/source/RobotAPI/libraries/core/JointVelocityRamp.h
@@ -0,0 +1,51 @@
+/*
+ * This file is part of ArmarX.
+ *
+ * Copyright (C) 2012-2016, High Performance Humanoid Technologies (H2T),
+ * Karlsruhe Institute of Technology (KIT), all rights reserved.
+ *
+ * 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/>.
+ *
+ * @author     Sonja Marahrens (sonja dot marahrens)
+ * @copyright  http://www.gnu.org/licenses/gpl-2.0.txt
+ *             GNU General Public License
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+#include <Eigen/Dense>
+
+namespace armarx
+{
+    class JointVelocityRamp;
+    typedef boost::shared_ptr<JointVelocityRamp> JointVelocityRampPtr;
+
+    class JointVelocityRamp
+    {
+    public:
+        JointVelocityRamp();
+
+        void setState(const Eigen::VectorXf& state);
+        Eigen::VectorXf update(const Eigen::VectorXf& target, float dt);
+
+        void setMaxAccelaration(float maxAcceleration);
+        float getMaxAccelaration();
+
+    private:
+
+        Eigen::VectorXf state;
+        float maxAcceleration;
+
+    };
+}
diff --git a/source/RobotAPI/libraries/core/math/ColorUtils.h b/source/RobotAPI/libraries/core/math/ColorUtils.h
index fb79987b2e9ba827e23cdcef58696b259628d984..6bbb60e30da1f2576192e6427f6e9a08d99de926 100644
--- a/source/RobotAPI/libraries/core/math/ColorUtils.h
+++ b/source/RobotAPI/libraries/core/math/ColorUtils.h
@@ -95,9 +95,9 @@ namespace armarx
 
         HsvColor RgbToHsv(const DrawColor24Bit& in)
         {
-            double r = in.r * 0.00392156862;
-            double g = in.g * 0.00392156862;
-            double b = in.b * 0.00392156862;
+            double r = 0.00392156862 * in.r;
+            double g = 0.00392156862 * in.g;
+            double b = 0.00392156862 * in.b;
             HsvColor         out;
             double      min, max, delta;
 
diff --git a/source/RobotAPI/libraries/core/test/CMakeLists.txt b/source/RobotAPI/libraries/core/test/CMakeLists.txt
index 38dff717efe933335499c980fc31a8efd8efd9cc..a78cfe8edfe93fb1a6c2c22258f8e44c77f7a6d7 100644
--- a/source/RobotAPI/libraries/core/test/CMakeLists.txt
+++ b/source/RobotAPI/libraries/core/test/CMakeLists.txt
@@ -5,3 +5,6 @@ armarx_add_test(PIDControllerTest PIDControllerTest.cpp "${LIBS}")
 
 armarx_add_test(MathUtilsTest MathUtilsTest.cpp "${LIBS}")
 armarx_add_test(CartesianVelocityControllerTest CartesianVelocityControllerTest.cpp "${LIBS}")
+
+armarx_add_test(CartesianVelocityRampTest CartesianVelocityRampTest.cpp "${LIBS}")
+armarx_add_test(CartesianVelocityControllerWithRampTest CartesianVelocityControllerWithRampTest.cpp "${LIBS}")
diff --git a/source/RobotAPI/libraries/core/test/CartesianVelocityControllerWithRampTest.cpp b/source/RobotAPI/libraries/core/test/CartesianVelocityControllerWithRampTest.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..487018abde075ae58f1eca8696b84a76685e002a
--- /dev/null
+++ b/source/RobotAPI/libraries/core/test/CartesianVelocityControllerWithRampTest.cpp
@@ -0,0 +1,111 @@
+/*
+* 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    ArmarX::RobotAPI::Test
+* @author     Nils Adermann (naderman at naderman dot de)
+* @date       2010
+* @copyright  http://www.gnu.org/licenses/gpl-2.0.txt
+*             GNU General Public License
+*/
+
+#define BOOST_TEST_MODULE RobotAPI::CartesianVelocityController::Test
+#define ARMARX_BOOST_TEST
+#include <RobotAPI/Test.h>
+#include <ArmarXCore/core/test/IceTestHelper.h>
+#include <ArmarXCore/core/system/ArmarXDataPath.h>
+#include <VirtualRobot/XML/RobotIO.h>
+#include <ArmarXCore/core/system/cmake/CMakePackageFinder.h>
+#include "../CartesianVelocityControllerWithRamp.h"
+
+using namespace armarx;
+
+BOOST_AUTO_TEST_CASE(CartesianVelocityRampTest)
+{
+    Eigen::VectorXf state(6);
+    state << 0, 0, 0, 0, 0, 0;
+    float dt = 0.1f;
+
+    CartesianVelocityRamp c;
+    c.setState(state, VirtualRobot::IKSolver::CartesianSelection::All);
+    c.setMaxPositionAcceleration(100);
+    c.setMaxOrientationAcceleration(1);
+
+    Eigen::VectorXf target(6);
+    target << 200, 0, 0, 3, 0, 0;
+
+
+
+    for (size_t i = 0; i < 30; i++)
+    {
+        state = c.update(target, dt);
+        ARMARX_IMPORTANT << "state:" << state;
+    }
+
+}
+
+
+BOOST_AUTO_TEST_CASE(test1)
+{
+    const std::string project = "RobotAPI";
+    armarx::CMakePackageFinder finder(project);
+
+    if (!finder.packageFound())
+    {
+        ARMARX_ERROR_S << "ArmarX Package " << project << " has not been found!";
+    }
+    else
+    {
+        armarx::ArmarXDataPath::addDataPaths(finder.getDataDir());
+    }
+    std::string fn = "RobotAPI/robots/Armar3/ArmarIII.xml";
+    ArmarXDataPath::getAbsolutePath(fn, fn);
+    std::string robotFilename = fn;
+    VirtualRobot::RobotPtr robot = VirtualRobot::RobotIO::loadRobot(robotFilename, VirtualRobot::RobotIO::eStructure);
+    VirtualRobot::RobotNodeSetPtr rns = robot->getRobotNodeSet("HipYawRightArm");
+
+
+    Eigen::VectorXf currentjointVel(8);
+    currentjointVel << 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1;
+
+
+    Eigen::VectorXf targetTcpVel(6);
+    targetTcpVel << 20, 0, 0, 0, 0, 0;
+
+    CartesianVelocityControllerWithRampPtr h(new CartesianVelocityControllerWithRamp(rns, currentjointVel, VirtualRobot::IKSolver::CartesianSelection::All, 100, 1, 1));
+    Eigen::MatrixXf jacobi = h->controller.ik->getJacobianMatrix(rns->getTCP(), VirtualRobot::IKSolver::CartesianSelection::All);
+    ARMARX_IMPORTANT << "Initial TCP Vel: " << (jacobi * currentjointVel).transpose();
+
+
+    float dt = 0.1f;
+
+    for (size_t n = 0; n < 10; n++)
+    {
+        //ARMARX_IMPORTANT << rns->getJointValues();
+        Eigen::VectorXf vel = h->calculate(targetTcpVel, 2, dt);
+        ARMARX_IMPORTANT << "jv: " << vel.transpose();
+        Eigen::VectorXf tcpVel = (h->controller.jacobi * vel);
+        ARMARX_IMPORTANT << "cv: " << tcpVel.transpose();
+        for (size_t i = 0; i < rns->getSize(); i++)
+        {
+            rns->getNode(i)->setJointValue(rns->getNode(i)->getJointValue() + vel(i) * dt);
+        }
+    }
+    /*
+    Eigen::VectorXf tcpVel = (h->jacobi * vel).transpose();
+    ARMARX_IMPORTANT << tcpVel;
+    BOOST_CHECK_LE((targetTcpVel - tcpVel).norm(), 0.01f);
+    */
+
+}
diff --git a/source/RobotAPI/libraries/core/test/CartesianVelocityRampTest.cpp b/source/RobotAPI/libraries/core/test/CartesianVelocityRampTest.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..5bfd4e36b8216ae4367ea582e18f382e1d3cb06f
--- /dev/null
+++ b/source/RobotAPI/libraries/core/test/CartesianVelocityRampTest.cpp
@@ -0,0 +1,53 @@
+/*
+* 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    ArmarX::RobotAPI::Test
+* @author     Nils Adermann (naderman at naderman dot de)
+* @date       2010
+* @copyright  http://www.gnu.org/licenses/gpl-2.0.txt
+*             GNU General Public License
+*/
+
+#define BOOST_TEST_MODULE RobotAPI::CartesianVelocityRamp::Test
+#define ARMARX_BOOST_TEST
+#include <RobotAPI/Test.h>
+#include <ArmarXCore/core/test/IceTestHelper.h>
+#include <ArmarXCore/core/system/ArmarXDataPath.h>
+#include <VirtualRobot/XML/RobotIO.h>
+#include <ArmarXCore/core/system/cmake/CMakePackageFinder.h>
+#include "../CartesianVelocityRamp.h"
+#include <RobotAPI/libraries/core/EigenHelpers.h>
+
+using namespace armarx;
+
+
+
+BOOST_AUTO_TEST_CASE(testBoth)
+{
+    Eigen::VectorXf state = MakeVectorXf(0, 0, 0, 0, 0, 0);
+    float dt = 0.1f;
+
+    CartesianVelocityRamp c;
+    c.setState(state, VirtualRobot::IKSolver::CartesianSelection::All);
+    c.setMaxPositionAcceleration(100);
+    c.setMaxOrientationAcceleration(1);
+
+    Eigen::VectorXf target = MakeVectorXf(100, 0, 0, 0, 0, 0);
+    state = c.update(target, dt);
+
+    Eigen::VectorXf expected = MakeVectorXf(10, 0, 0, 0, 0, 0);
+    BOOST_CHECK_LE((state - expected).norm(), 0.01f);
+
+}