diff --git a/source/RobotAPI/libraries/CMakeLists.txt b/source/RobotAPI/libraries/CMakeLists.txt
index 90a62cd3087bd6e2462865fb26a21c4140e4863c..5e26cffe5a1a66ffd836f782caf2b14050a58e40 100644
--- a/source/RobotAPI/libraries/CMakeLists.txt
+++ b/source/RobotAPI/libraries/CMakeLists.txt
@@ -19,3 +19,5 @@ add_subdirectory(natik)
 
 add_subdirectory(armem)
 add_subdirectory(aron)
+
+add_subdirectory(NJointControllerGuiPluginUtility)
\ No newline at end of file
diff --git a/source/RobotAPI/libraries/NJointControllerGuiPluginUtility/CMakeLists.txt b/source/RobotAPI/libraries/NJointControllerGuiPluginUtility/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..b044f98be56f2ee7fe799cf3272aac3120d30ccb
--- /dev/null
+++ b/source/RobotAPI/libraries/NJointControllerGuiPluginUtility/CMakeLists.txt
@@ -0,0 +1,23 @@
+set(LIB_NAME       NJointControllerGuiPluginUtility)
+
+armarx_component_set_name("${LIB_NAME}")
+armarx_set_target("Library: ${LIB_NAME}")
+
+set(COMPONENT_LIBS
+    SimpleConfigDialog
+    RobotAPIComponentPlugins
+)
+set(SOURCES 
+    detail/NJointControllerGuiPluginBase.cpp
+)
+set(HEADERS
+    SpinBoxToPose.h
+    SpinBoxToVector.h
+    NJointControllerGuiPluginBase.h
+)
+set(GUI_MOC_HDRS detail/NJointControllerGuiPluginBase.h)
+set(GUI_UIS)
+
+if(ArmarXGui_FOUND)
+    armarx_gui_library("${LIB_NAME}" "${SOURCES}" "${GUI_MOC_HDRS}" "${GUI_UIS}" "" "${COMPONENT_LIBS}")
+endif()
diff --git a/source/RobotAPI/libraries/NJointControllerGuiPluginUtility/NJointControllerGuiPluginBase.h b/source/RobotAPI/libraries/NJointControllerGuiPluginUtility/NJointControllerGuiPluginBase.h
new file mode 100644
index 0000000000000000000000000000000000000000..75dce9850c6af59121ba763d95ce65eda06a6376
--- /dev/null
+++ b/source/RobotAPI/libraries/NJointControllerGuiPluginUtility/NJointControllerGuiPluginBase.h
@@ -0,0 +1,110 @@
+/*
+ * This file is part of ArmarX.
+ *
+ * ArmarX is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * ArmarX is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @package    RobotAPI::ArmarXObjects::NJointControllerGuiPluginUtility
+ * @author     Raphael Grimm ( raphael dot grimm at kit dot edu )
+ * @date       2020
+ * @copyright  http://www.gnu.org/licenses/gpl-2.0.txt
+ *             GNU General Public License
+ */
+
+#pragma once
+
+#include "detail/NJointControllerGuiPluginBase.h"
+
+namespace armarx
+{
+    template<class Derived, class Proxy>
+    class NJointControllerGuiPluginBase:
+        public detail::_NJointControllerGuiPluginBase::Base
+    {
+    public:
+        NJointControllerGuiPluginBase(const std::string& ctrlClass) :
+            detail::_NJointControllerGuiPluginBase::Base(),
+            _ctrlClass{ctrlClass}
+        {}
+        ~NJointControllerGuiPluginBase()
+        {
+            deleteController();
+        }
+    public:
+        QString getWidgetName() const final override
+        {
+            return Derived::GetWidgetName();
+        }
+        QIcon getWidgetIcon() const final override
+        {
+            return Derived::GetWidgetIcon();
+        }
+        QIcon getWidgetCategoryIcon() const final override
+        {
+            return Derived::GetWidgetCategoryIcon();
+        }
+    public:
+        void createController() override
+        {
+            std::lock_guard g{_allMutex};
+            if (_controller || !_robotUnit)
+            {
+                return;
+            }
+            ARMARX_IMPORTANT << "Creating " << _ctrlClass << " '"
+                             << _controllerName << "'";
+            _controller = Proxy::checkedCast(
+                              _robotUnit->createNJointController(
+                                  _ctrlClass,
+                                  _controllerName,
+                                  readFullCFG()
+                              ));
+            ARMARX_CHECK_NOT_NULL(_controller);
+        }
+        void activateController() override
+        {
+            std::lock_guard g{_allMutex};
+            if (!_controller)
+            {
+                return;
+            }
+            _controller->activateController();
+        }
+        void deactivateController() override
+        {
+            std::lock_guard g{_allMutex};
+            if (!_controller)
+            {
+                return;
+            }
+            _controller->deactivateController();
+        }
+        void deleteController() override
+        {
+            std::lock_guard g{_allMutex};
+            if (!_controller || !_robotUnit)
+            {
+                return;
+            }
+            ARMARX_IMPORTANT << "deleting old controller '" << _controllerName << "'";
+            try
+            {
+                _controller->deactivateAndDeleteController();
+            }
+            catch (...) {}
+            _controller = nullptr;
+        }
+    protected:
+        Proxy       _controller;
+        std::string _ctrlClass;
+    };
+}
diff --git a/source/RobotAPI/libraries/NJointControllerGuiPluginUtility/SpinBoxToPose.h b/source/RobotAPI/libraries/NJointControllerGuiPluginUtility/SpinBoxToPose.h
new file mode 100644
index 0000000000000000000000000000000000000000..df5cb36988ca188cb9c8a9a0104df00efa00c3f0
--- /dev/null
+++ b/source/RobotAPI/libraries/NJointControllerGuiPluginUtility/SpinBoxToPose.h
@@ -0,0 +1,102 @@
+/*
+ * This file is part of ArmarX.
+ *
+ * ArmarX is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * ArmarX is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @package    RobotAPI::ArmarXObjects::NJointControllerGuiPluginUtility
+ * @author     Raphael Grimm ( raphael dot grimm at kit dot edu )
+ * @date       2020
+ * @copyright  http://www.gnu.org/licenses/gpl-2.0.txt
+ *             GNU General Public License
+ */
+
+#pragma once
+
+#include <SimoxUtility/math/convert.h>
+
+#include "SpinBoxToVector.h"
+
+namespace armarx
+{
+    template<class Qwid = QDoubleSpinBox>
+    class SpinBoxToPose
+    {
+        //set
+    public:
+        void setPos(const Eigen::Vector3f& pos)
+        {
+            _xyz.set(pos);
+        }
+        void setOri(const Eigen::Vector3f& rpy)
+        {
+            _rpy.set(rpy);
+        }
+        void setOri(const Eigen::Quaternionf& q)
+        {
+            setOri(simox::math::quat_to_rpy(q));
+        }
+        void setOri(const Eigen::Matrix3f& m)
+        {
+            setOri(simox::math::mat3f_to_rpy(m));
+        }
+        void setPose(const auto& pos, const auto& ori)
+        {
+            setPos(pos);
+            setOri(ori);
+        }
+        void setPose(const Eigen::Matrix4f& m)
+        {
+            setPos(simox::math::mat4f_to_pos(m));
+            setOri(simox::math::mat4f_to_rpy(m));
+        }
+        //get
+    public:
+        Eigen::Vector3f getPos() const
+        {
+            return _xyz.template get<Eigen::Vector3f>();
+        }
+        Eigen::Vector3f getRPY() const
+        {
+            return _rpy.template get<Eigen::Vector3f>();
+        }
+        Eigen::Quaternionf getQuat() const
+        {
+            return simox::math::rpy_to_quat(getRPY());
+        }
+        Eigen::Matrix3f getMat3() const
+        {
+            return simox::math::rpy_to_mat3f(getRPY());
+        }
+        Eigen::Matrix4f getMat4() const
+        {
+            return simox::math::pos_rpy_to_mat4f(getPos(), getRPY());
+        }
+        //set up
+    public:
+        void setXYZBoxes(Qwid* x, Qwid* y, Qwid* z)
+        {
+            _xyz.addBox(x);
+            _xyz.addBox(y);
+            _xyz.addBox(z);
+        }
+        void setRPYBoxes(Qwid* r, Qwid* p, Qwid* y)
+        {
+            _rpy.addBox(r);
+            _rpy.addBox(p);
+            _rpy.addBox(y);
+        }
+    private:
+        SpinBoxToVector<Qwid, 3> _xyz;
+        SpinBoxToVector<Qwid, 3> _rpy;
+    };
+}
diff --git a/source/RobotAPI/libraries/NJointControllerGuiPluginUtility/SpinBoxToVector.h b/source/RobotAPI/libraries/NJointControllerGuiPluginUtility/SpinBoxToVector.h
new file mode 100644
index 0000000000000000000000000000000000000000..b8da4b54d36b8beac8a87dc65cee3f49f51707f6
--- /dev/null
+++ b/source/RobotAPI/libraries/NJointControllerGuiPluginUtility/SpinBoxToVector.h
@@ -0,0 +1,155 @@
+/*
+ * This file is part of ArmarX.
+ *
+ * ArmarX is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * ArmarX is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @package    RobotAPI::ArmarXObjects::NJointControllerGuiPluginUtility
+ * @author     Raphael Grimm ( raphael dot grimm at kit dot edu )
+ * @date       2020
+ * @copyright  http://www.gnu.org/licenses/gpl-2.0.txt
+ *             GNU General Public License
+ */
+
+#pragma once
+
+#include <array>
+#include <vector>
+
+#include <Eigen/Dense>
+
+#include <QDoubleSpinBox>
+
+#include <VirtualRobot/RobotNodeSet.h>
+#include <VirtualRobot/Nodes/RobotNode.h>
+
+#include <ArmarXCore/core/exceptions/local/ExpressionException.h>
+
+namespace armarx
+{
+    template<class Qwid = QDoubleSpinBox, std::size_t Size = 0>
+    class SpinBoxToVector
+    {
+    public:
+        template<class Scalar, int Rows, int Cols>
+        void get(Eigen::Matrix<Scalar, Rows, Cols>& m) const
+        {
+            if constexpr(Size)
+            {
+                ARMARX_CHECK_EQUAL(Size, _spin.size());
+            }
+            if constexpr(Rows == -1 && Cols == -1)
+            {
+                m.resize(Size, 1);
+            }
+            else if constexpr(Rows == 1 && Cols == -1)
+            {
+                m.resize(Size);
+            }
+            else if constexpr(Rows == -1 && Cols == 1)
+            {
+                m.resize(Size);
+            }
+            else if constexpr(Cols == -1)
+            {
+                m.resize(Rows, Size / Rows);
+            }
+            else if constexpr(Rows == -1)
+            {
+                m.resize(Size / Cols, Cols);
+            }
+
+            ARMARX_CHECK_EQUAL(static_cast<std::size_t>(m.size()), _spin.size());
+            for (std::size_t i = 0; i < _spin.size(); ++i)
+            {
+                m.data()[i] = _spin.at(i)->value();
+            }
+        }
+        template<class Scalar>
+        void get(std::vector<Scalar>& m) const
+        {
+            if constexpr(Size)
+            {
+                ARMARX_CHECK_EQUAL(Size, _spin.size());
+            }
+            m.resize(_spin.size());
+            ARMARX_CHECK_EQUAL(m.size(), _spin.size());
+            for (std::size_t i = 0; i < _spin.size(); ++i)
+            {
+                m.at(i) = _spin.at(i)->value();
+            }
+        }
+        template<class T>
+        T get() const
+        {
+            if constexpr(Size)
+            {
+                ARMARX_CHECK_EQUAL(Size, _spin.size());
+            }
+            T m;
+            get(m);
+            return m;
+        }
+        template<class Scalar, int Rows, int Cols>
+        void set(const Eigen::Matrix<Scalar, Rows, Cols>& m)
+        {
+            if constexpr(Size)
+            {
+                ARMARX_CHECK_EQUAL(Size, _spin.size());
+            }
+            ARMARX_CHECK_EQUAL(m.size(), _spin.size());
+            for (int i = 0; i < _spin.size(); ++i)
+            {
+                _spin.at(i)->setValue(m.data()[i]);
+            }
+        }
+        void set(const VirtualRobot::RobotNodeSetPtr& set)
+        {
+            ARMARX_CHECK_NOT_NULL(set);
+            ARMARX_CHECK_EQUAL(set->getSize(), _spin.size());
+            for (std::size_t i = 0; i < _spin.size(); ++i)
+            {
+                _spin.at(i)->setValue(set->getNode(i)->getJointValue());
+            }
+        }
+    public:
+        void addBox(Qwid* s)
+        {
+            ARMARX_CHECK_NOT_NULL(s);
+            if constexpr(Size)
+            {
+                ARMARX_CHECK_LESS(_sz, Size);
+                _spin.at(_sz) = s;
+            }
+            else
+            {
+                _spin.emplace_back(s);
+            }
+            ++_sz;
+        }
+        void clear()
+        {
+            _sz = 0;
+            if constexpr(!Size)
+            {
+                _spin.clear();
+            }
+        }
+    private:
+        unsigned _sz = 0;
+        std::conditional_t <
+        Size,
+        std::array<Qwid*, Size>,
+        std::vector<Qwid*>
+        > _spin;
+    };
+}
diff --git a/source/RobotAPI/libraries/NJointControllerGuiPluginUtility/detail/NJointControllerGuiPluginBase.cpp b/source/RobotAPI/libraries/NJointControllerGuiPluginUtility/detail/NJointControllerGuiPluginBase.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e1c51ffa21d7dd4489d28d548311b66275f6e4b6
--- /dev/null
+++ b/source/RobotAPI/libraries/NJointControllerGuiPluginUtility/detail/NJointControllerGuiPluginBase.cpp
@@ -0,0 +1,116 @@
+#include <QPushButton>
+
+#include <RobotAPI/libraries/core/remoterobot/RemoteRobot.h>
+
+#include "NJointControllerGuiPluginBase.h"
+
+namespace armarx::detail::_NJointControllerGuiPluginBase
+{
+    void Base::createController() {}
+    void Base::activateController() {}
+    void Base::deactivateController() {}
+    void Base::deleteController() {}
+
+    Base::Base() :
+        _controllerName{getName() + "_Controller"}
+    {
+        std::replace(_controllerName.begin(), _controllerName.end(), '.', '_');
+        std::replace(_controllerName.begin(), _controllerName.end(), ':', '_');
+    }
+
+    Base::~Base()
+    {
+        if (_timer)
+        {
+            killTimer(_timer);
+        }
+    }
+
+    void Base::connectCreateAcivateDeactivateDelete(QPushButton* cr, QPushButton* ac, QPushButton* dc, QPushButton* de)
+    {
+        if (cr)
+        {
+            connect(cr, &QPushButton::clicked, this, &Base::createController);
+        }
+        if (ac)
+        {
+            connect(ac, &QPushButton::clicked, this, &Base::activateController);
+        }
+        if (dc)
+        {
+            connect(dc, &QPushButton::clicked, this, &Base::deactivateController);
+        }
+        if (de)
+        {
+            connect(de, &QPushButton::clicked, this, &Base::deleteController);
+        }
+    }
+
+    void Base::loadSettings(QSettings* settings)
+    {
+        std::lock_guard g{_allMutex};
+        getRobotStateComponentPlugin().setRobotStateComponentName(settings->value("rsc", "Armar6StateComponent").toString().toStdString());
+        getRobotUnitComponentPlugin().setRobotUnitName(settings->value("ru", "Armar6Unit").toString().toStdString());
+    }
+
+    void Base::saveSettings(QSettings* settings)
+    {
+        std::lock_guard g{_allMutex};
+        settings->setValue("rsc", QString::fromStdString(getRobotStateComponentPlugin().getRobotStateComponentName()));
+        settings->setValue("ru", QString::fromStdString(getRobotUnitComponentPlugin().getRobotUnitName()));
+    }
+
+    QPointer<QDialog> Base::getConfigDialog(QWidget* parent)
+    {
+        std::lock_guard g{_allMutex};
+        if (!_dialog)
+        {
+            _dialog = new SimpleConfigDialog(parent);
+            _dialog->addProxyFinder<RobotUnitInterfacePrx>({"ru", "Robot Unit", "*Unit"});
+            _dialog->addProxyFinder<RobotStateComponentInterfacePrx>({"rsc", "Robot State Component", "*Component"});
+        }
+        return qobject_cast<SimpleConfigDialog*>(_dialog);
+    }
+
+    void Base::configured()
+    {
+        std::lock_guard g{_allMutex};
+        getRobotStateComponentPlugin().setRobotStateComponentName(_dialog->getProxyName("rsc"));
+        getRobotUnitComponentPlugin().setRobotUnitName(_dialog->getProxyName("ru"));
+    }
+
+    void Base::onInitComponent()
+    {
+    }
+
+    void Base::onConnectComponent()
+    {
+        std::lock_guard g{_allMutex};
+        //robot
+        _robot = addRobot("state robot", VirtualRobot::RobotIO::eStructure);
+        _timer = startTimer(100);
+    }
+
+    void Base::onDisconnectComponent()
+    {
+        std::lock_guard g{_allMutex};
+        deleteController();
+    }
+
+    void Base::timerEvent(QTimerEvent*)
+    {
+        std::lock_guard g{_allMutex};
+        killTimer(_timer);
+        _timer = 0;
+        if (_robot)
+        {
+            synchronizeLocalClone(_robot);
+        }
+        setupGuiAfterConnect();
+    }
+
+    void Base::setupGuiAfterConnect()
+    {
+
+    }
+}
diff --git a/source/RobotAPI/libraries/NJointControllerGuiPluginUtility/detail/NJointControllerGuiPluginBase.h b/source/RobotAPI/libraries/NJointControllerGuiPluginUtility/detail/NJointControllerGuiPluginBase.h
new file mode 100644
index 0000000000000000000000000000000000000000..21b15ab25e99fd7a6c30eb7742c9bfad3d5ac17b
--- /dev/null
+++ b/source/RobotAPI/libraries/NJointControllerGuiPluginUtility/detail/NJointControllerGuiPluginBase.h
@@ -0,0 +1,84 @@
+/*
+ * This file is part of ArmarX.
+ *
+ * ArmarX is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * ArmarX is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @package    RobotAPI::ArmarXObjects::NJointControllerGuiPluginUtility
+ * @author     Raphael Grimm ( raphael dot grimm at kit dot edu )
+ * @date       2020
+ * @copyright  http://www.gnu.org/licenses/gpl-2.0.txt
+ *             GNU General Public License
+ */
+
+#pragma once
+
+#include <mutex>
+
+#include <VirtualRobot/Robot.h>
+
+#include <ArmarXCore/core/system/ImportExportComponent.h>
+
+#include <ArmarXGui/libraries/ArmarXGuiBase/ArmarXGuiPlugin.h>
+#include <ArmarXGui/libraries/ArmarXGuiBase/ArmarXComponentWidgetController.h>
+#include <ArmarXGui/libraries/SimpleConfigDialog/SimpleConfigDialog.h>
+
+#include <RobotAPI/interface/core/RobotState.h>
+#include <RobotAPI/libraries/RobotAPIComponentPlugins/RobotUnitComponentPlugin.h>
+#include <RobotAPI/libraries/RobotAPIComponentPlugins/RobotStateComponentPlugin.h>
+
+
+namespace armarx::detail::_NJointControllerGuiPluginBase
+{
+    class Base :
+        public ArmarXComponentWidgetController,
+        public virtual RobotUnitComponentPluginUser,
+        public virtual RobotStateComponentPluginUser
+    {
+        Q_OBJECT
+    public:
+        virtual NJointControllerConfigPtr readFullCFG() const = 0;
+    public Q_SLOTS: //for some reason using slots does not work -> use Q_SLOTS
+        virtual void createController();
+        virtual void activateController();
+        virtual void deactivateController();
+        virtual void deleteController();
+    public:
+        Base();
+        ~Base() override;
+
+        void connectCreateAcivateDeactivateDelete(QPushButton* cr, QPushButton* ac, QPushButton* dc, QPushButton* de);
+    public:
+        void loadSettings(QSettings* settings) override;
+        void saveSettings(QSettings* settings) override;
+        QPointer<QDialog> getConfigDialog(QWidget* parent) override;
+        void configured() override;
+    public:
+        void onInitComponent() override;
+        void onConnectComponent() override;
+        void onDisconnectComponent() override;
+    public:
+        void timerEvent(QTimerEvent*) override;
+        virtual void setupGuiAfterConnect();
+    protected:
+        QPointer<SimpleConfigDialog> _dialog;
+        int                             _timer;
+
+        mutable std::recursive_mutex     _allMutex;
+        RobotStateComponentInterfacePrx _robotStateComponent;
+        RobotUnitInterfacePrx           _robotUnit;
+        VirtualRobot::RobotPtr          _robot;
+
+        std::string                     _controllerName;
+    };
+}
+