diff --git a/source/RobotAPI/components/units/RobotUnit/CMakeLists.txt b/source/RobotAPI/components/units/RobotUnit/CMakeLists.txt
index 2bbf03b242fa4be240287ca624050274f0af19ca..89a1d7833a64a2bdab3d46d00f07a619f60f32fb 100644
--- a/source/RobotAPI/components/units/RobotUnit/CMakeLists.txt
+++ b/source/RobotAPI/components/units/RobotUnit/CMakeLists.txt
@@ -40,6 +40,7 @@ set(LIB_FILES
     NJointControllers/NJointTrajectoryController.cpp
     NJointControllers/NJointKinematicUnitPassThroughController.cpp
     NJointControllers/NJointHolonomicPlatformUnitVelocityPassThroughController.cpp
+    NJointControllers/NJointTCPController.cpp
 
     Devices/SensorDevice.cpp
     Devices/ControlDevice.cpp
@@ -79,6 +80,7 @@ set(LIB_HEADERS
     NJointControllers/NJointTrajectoryController.h
     NJointControllers/NJointKinematicUnitPassThroughController.h
     NJointControllers/NJointHolonomicPlatformUnitVelocityPassThroughController.h
+    NJointControllers/NJointTCPController.h
 
     Devices/DeviceBase.h
     Devices/SensorDevice.h
diff --git a/source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointTCPController.cpp b/source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointTCPController.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..7f0ef41fa60c6d2881a1575312b3854a925ad2d9
--- /dev/null
+++ b/source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointTCPController.cpp
@@ -0,0 +1,199 @@
+/*
+ * 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     Mirko Waechter( mirko.waechter at kit dot edu)
+ * @date       2017
+ * @copyright  http://www.gnu.org/licenses/gpl-2.0.txt
+ *             GNU General Public License
+ */
+#include "NJointTCPController.h"
+#include <VirtualRobot/RobotNodeSet.h>
+#include "../RobotUnit.h"
+
+#define DEFAULT_TCP_STRING "default TCP"
+
+namespace armarx
+{
+
+    NJointControllerRegistration<NJointTCPController> registrationControllerNJointTCPController("NJointTCPController");
+
+    std::string NJointTCPController::getClassName(const Ice::Current&) const
+    {
+        return "NJointTCPController";
+    }
+
+    void NJointTCPController::rtPreActivateController()
+    {
+        xVel = 0;
+        yVel = 0;
+        zVel = 0;
+        rollVel = 0;
+        pitchVel = 0;
+        yawVel = 0;
+    }
+
+    void NJointTCPController::rtRun(const IceUtil::Time& sensorValuesTimestamp, const IceUtil::Time& timeSinceLastIteration)
+    {
+        Eigen::VectorXf x(6);
+        x << this->xVel, yVel, zVel, rollVel, pitchVel, yawVel;
+        Eigen::MatrixXf jacobiInv = ik->getPseudoInverseJacobianMatrix(tcp);
+        Eigen::VectorXf jointTargetVelocities = jacobiInv * x;
+        for (size_t i = 0; i < targets.size(); ++i)
+        {
+            targets.at(i)->velocity = jointTargetVelocities(i);
+        }
+    }
+
+
+    ::armarx::WidgetDescription::WidgetSeq createSliders()
+    {
+        using namespace armarx::WidgetDescription;
+        ::armarx::WidgetDescription::WidgetSeq widgets;
+        auto addSlider = [&](const std::string & label, float limit)
+        {
+            widgets.emplace_back(new Label(false, label));
+            {
+                FloatSliderPtr c_x = new FloatSlider;
+                c_x->name = label;
+                c_x->min = -limit;
+                c_x->defaultValue = 0.0f;
+                c_x->max = limit;
+                widgets.emplace_back(c_x);
+            }
+        };
+
+        addSlider("x", 100);
+        addSlider("y", 100);
+        addSlider("z", 100);
+        addSlider("r", 0.5);
+        addSlider("p", 0.5);
+        addSlider("y", 0.5);
+        return widgets;
+    }
+
+    WidgetDescription::WidgetPtr NJointTCPController::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->defaultIndex = 0;
+
+        boxMode->options = {"Position", "Orientation", "Both"};
+        boxMode->name = "mode";
+        layout->children.emplace_back(boxMode);
+
+
+        //        auto sliders = createSliders();
+        //        layout->children.insert(layout->children.end(),
+        //                                sliders.begin(),
+        //                                sliders.end());
+        layout->children.emplace_back(new HSpacer);
+        return layout;
+    }
+
+    NJointTCPControllerConfigPtr NJointTCPController::GenerateConfigFromVariants(const StringVariantBaseMap& values)
+    {
+        return new NJointTCPControllerConfig {values.at("nodeSetName")->getString(), values.at("tcpName")->getString()};
+    }
+
+    NJointTCPController::NJointTCPController(NJointControllerDescriptionProviderInterfacePtr prov, NJointTCPControllerConfigPtr 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());
+        auto nodeset = robotUnit->getRtRobot()->getRobotNodeSet(config->nodeSetName);
+        ARMARX_CHECK_EXPRESSION_W_HINT(nodeset, config->nodeSetName);
+        for (size_t i = 0; i < nodeset->getSize(); ++i)
+        {
+            auto jointName = nodeset->getNode(i)->getName();
+            ControlTargetBase* ct = prov->getControlTarget(jointName, ControlModes::Velocity1DoF);
+            const SensorValueBase* sv = prov->getSensorValue(jointName);
+            targets.push_back(ct->asA<ControlTarget1DoFActuatorVelocity>());
+            sensors.push_back(sv->asA<SensorValue1DoFActuatorPosition>());
+        };
+        ik.reset(new VirtualRobot::DifferentialIK(nodeset, robotUnit->getRtRobot()->getRootNode(), VirtualRobot::JacobiProvider::eSVDDamped));
+        tcp = (config->tcpName.empty() || config->tcpName == DEFAULT_TCP_STRING) ? nodeset->getTCP() : robotUnit->getRtRobot()->getRobotNode(config->tcpName);
+        ARMARX_CHECK_EXPRESSION_W_HINT(tcp, config->tcpName);
+    }
+
+    void NJointTCPController::rtPostDeactivateController()
+    {
+
+    }
+
+    WidgetDescription::StringWidgetDictionary NJointTCPController::getFunctionDescriptions(const Ice::Current&) const
+    {
+        using namespace armarx::WidgetDescription;
+        HBoxLayoutPtr layout = new HBoxLayout;
+        auto sliders = createSliders();
+        layout->children.insert(layout->children.end(),
+                                sliders.begin(),
+                                sliders.end());
+        return {{"ControllerConfig", layout}};
+    }
+
+    void NJointTCPController::callDescribedFunction(const std::string& name, const StringVariantBaseMap& valueMap, const Ice::Current&)
+    {
+        if (name == "ControllerConfig")
+        {
+            xVel = valueMap.at("x")->getFloat();
+            yVel = valueMap.at("y")->getFloat();
+            zVel = valueMap.at("z")->getFloat();
+            rollVel = valueMap.at("r")->getFloat();
+            pitchVel = valueMap.at("p")->getFloat();
+            yawVel = valueMap.at("y")->getFloat();
+        }
+        else
+        {
+            ARMARX_WARNING << "Unknown function name called: " << name;
+        }
+    }
+
+
+
+} // namespace armarx
+
+
+
+
diff --git a/source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointTCPController.h b/source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointTCPController.h
new file mode 100644
index 0000000000000000000000000000000000000000..356457a7ea461d0f0755ff4b71328b2d1109be3e
--- /dev/null
+++ b/source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointTCPController.h
@@ -0,0 +1,98 @@
+/*
+ * 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     Mirko Waechter( mirko.waechter at kit dot edu)
+ * @date       2017
+ * @copyright  http://www.gnu.org/licenses/gpl-2.0.txt
+ *             GNU General Public License
+ */
+#pragma once
+
+
+#include "NJointController.h"
+#include <VirtualRobot/Robot.h>
+#include <RobotAPI/components/units/RobotUnit/ControlTargets/ControlTarget1DoFActuator.h>
+#include <RobotAPI/components/units/RobotUnit/SensorValues/SensorValue1DoFActuator.h>
+#include <VirtualRobot/IK/DifferentialIK.h>
+
+namespace armarx
+{
+
+    TYPEDEF_PTRS_HANDLE(NJointTCPController);
+    TYPEDEF_PTRS_HANDLE(NJointTCPControllerConfig);
+
+    class NJointTCPControllerConfig : virtual public NJointControllerConfig
+    {
+    public:
+        NJointTCPControllerConfig(std::string const& nodeSetName, const std::string& tcpName):
+            nodeSetName(nodeSetName),
+            tcpName(tcpName)
+        {}
+
+        const std::string nodeSetName;
+        const std::string tcpName;
+    };
+
+
+    class NJointTCPController : public NJointController
+    {
+    public:
+        using ConfigPtrT = NJointTCPControllerConfigPtr;
+        NJointTCPController(NJointControllerDescriptionProviderInterfacePtr prov, const NJointControllerConfigPtr& config, const VirtualRobot::RobotPtr&);
+
+        // NJointControllerInterface interface
+        std::string getClassName(const Ice::Current&) const override;
+        WidgetDescription::StringWidgetDictionary getFunctionDescriptions(const Ice::Current&) const override;
+        void callDescribedFunction(const std::string& name, const StringVariantBaseMap& valueMap, const Ice::Current&) 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 NJointTCPControllerConfigPtr GenerateConfigFromVariants(const StringVariantBaseMap& values);
+        NJointTCPController(
+            NJointControllerDescriptionProviderInterfacePtr prov,
+            NJointTCPControllerConfigPtr config,
+            const boost::shared_ptr<VirtualRobot::Robot>& r);
+    protected:
+        void rtPreActivateController() override;
+        void rtPostDeactivateController() override;
+    private:
+        std::vector<ControlTarget1DoFActuatorVelocity*> targets;
+        std::vector<const SensorValue1DoFActuatorPosition*> sensors;
+
+        std::atomic<float> xVel;
+        std::atomic<float> yVel;
+        std::atomic<float> zVel;
+        std::atomic<float> rollVel;
+        std::atomic<float> pitchVel;
+        std::atomic<float> yawVel;
+        VirtualRobot::RobotNodePtr tcp;
+        VirtualRobot::DifferentialIKPtr ik;
+
+
+
+
+
+    };
+
+} // namespace armarx
+