diff --git a/source/RobotAPI/components/NaturalIKTest/NaturalIKTest.cpp b/source/RobotAPI/components/NaturalIKTest/NaturalIKTest.cpp
index f230c8305809e4d0657b5fea04570c82fd462eec..feb67dc48078e393f420fe922e8e872e0683a769 100644
--- a/source/RobotAPI/components/NaturalIKTest/NaturalIKTest.cpp
+++ b/source/RobotAPI/components/NaturalIKTest/NaturalIKTest.cpp
@@ -101,78 +101,120 @@ namespace armarx
 
     RemoteGui::WidgetPtr NaturalIKTest::buildGui()
     {
-        return RemoteGui::makeVBoxLayout().addChild(
-                   RemoteGui::makeSimpleGridLayout().cols(3)
-                   .addTextLabel("X")
-                   .addChild(RemoteGui::makeFloatSlider("X").min(-500).max(500).value(0))
-                   .addChild(new RemoteGui::HSpacer)
+        RemoteGui::detail::GroupBoxBuilder leftBox = RemoteGui::makeGroupBox().label("Left").addChild(
+                    RemoteGui::makeSimpleGridLayout().cols(2)
+                    .addTextLabel("L.X")
+                    .addChild(RemoteGui::makeFloatSlider("L.X").min(-600).max(600).value(0))
 
-                   .addTextLabel("Y")
-                   .addChild(RemoteGui::makeFloatSlider("Y").min(200).max(1000).value(400))
-                   .addChild(new RemoteGui::HSpacer)
+                    .addTextLabel("L.Y")
+                    .addChild(RemoteGui::makeFloatSlider("L.Y").min(200).max(1200).value(600))
 
-                   .addTextLabel("Z")
-                   .addChild(RemoteGui::makeFloatSlider("Z").min(-600).max(600).value(0))
-                   .addChild(new RemoteGui::HSpacer)
+                    .addTextLabel("L.Z")
+                    .addChild(RemoteGui::makeFloatSlider("L.Z").min(-600).max(600).value(-200))
 
-                   .addTextLabel("scale")
-                   .addChild(RemoteGui::makeFloatSlider("scale").min(0.5).max(2).value(1.3f))
-                   .addChild(new RemoteGui::HSpacer)
+                    .addTextLabel("L.scale")
+                    .addChild(RemoteGui::makeFloatSlider("L.scale").min(0.5).max(2).value(1.3f))
 
-                   .addTextLabel("minElbZ")
-                   .addChild(RemoteGui::makeFloatSlider("minElbZ").min(500).max(2000).value(500))
-                   .addChild(new RemoteGui::HSpacer)
+                    .addTextLabel("L.minElbZ")
+                    .addChild(RemoteGui::makeFloatSlider("L.minElbZ").min(500).max(2000).value(500))
 
-                   .addChild(RemoteGui::makeCheckBox("setOri").value(true))
-                   .addChild(new RemoteGui::HSpacer)
-                   .addChild(new RemoteGui::HSpacer)
+                    .addChild(RemoteGui::makeCheckBox("L.setOri").value(true))
+                    .addChild(new RemoteGui::HSpacer)
 
-                   .addTextLabel("rX")
-                   .addChild(RemoteGui::makeFloatSlider("rX").min(-180).max(180).value(0))
-                   .addChild(new RemoteGui::HSpacer)
+                    .addTextLabel("L.rX")
+                    .addChild(RemoteGui::makeFloatSlider("L.rX").min(-180).max(180).value(0))
 
-                   .addTextLabel("rY")
-                   .addChild(RemoteGui::makeFloatSlider("rY").min(-180).max(180).value(0))
-                   .addChild(new RemoteGui::HSpacer)
+                    .addTextLabel("L.rY")
+                    .addChild(RemoteGui::makeFloatSlider("L.rY").min(-180).max(180).value(0))
 
-                   .addTextLabel("rZ")
-                   .addChild(RemoteGui::makeFloatSlider("rZ").min(-180).max(180).value(0))
-                   .addChild(new RemoteGui::HSpacer)
+                    .addTextLabel("L.rZ")
+                    .addChild(RemoteGui::makeFloatSlider("L.rZ").min(-180).max(180).value(0))
+                );
+        RemoteGui::detail::GroupBoxBuilder rightBox = RemoteGui::makeGroupBox().label("Right").addChild(
+                    RemoteGui::makeSimpleGridLayout().cols(2)
+                    .addTextLabel("R.X")
+                    .addChild(RemoteGui::makeFloatSlider("R.X").min(-600).max(600).value(0))
 
-                   .addTextLabel("elbowKp")
-                   .addChild(RemoteGui::makeFloatSlider("elbowKp").min(0).max(1).value(1))
-                   .addChild(new RemoteGui::HSpacer)
+                    .addTextLabel("R.Y")
+                    .addChild(RemoteGui::makeFloatSlider("R.Y").min(200).max(1200).value(600))
 
-                   .addTextLabel("jlaKp")
-                   .addChild(RemoteGui::makeFloatSlider("jlaKp").min(0).max(1).value(0))
-                   .addChild(new RemoteGui::HSpacer)
+                    .addTextLabel("R.Z")
+                    .addChild(RemoteGui::makeFloatSlider("R.Z").min(-600).max(600).value(-200))
 
-                   .addChild(RemoteGui::makeButton("runTest").label("run test"))
+                    .addTextLabel("R.scale")
+                    .addChild(RemoteGui::makeFloatSlider("R.scale").min(0.5).max(2).value(1.3f))
 
-               )
-               .addChild(RemoteGui::makeLabel("errors").value("<errors>"));
+                    .addTextLabel("R.minElbZ")
+                    .addChild(RemoteGui::makeFloatSlider("R.minElbZ").min(500).max(2000).value(500))
+
+                    .addChild(RemoteGui::makeCheckBox("R.setOri").value(true))
+                    .addChild(new RemoteGui::HSpacer)
+
+                    .addTextLabel("R.rX")
+                    .addChild(RemoteGui::makeFloatSlider("R.rX").min(-180).max(180).value(0))
+
+                    .addTextLabel("R.rY")
+                    .addChild(RemoteGui::makeFloatSlider("R.rY").min(-180).max(180).value(0))
+
+                    .addTextLabel("R.rZ")
+                    .addChild(RemoteGui::makeFloatSlider("R.rZ").min(-180).max(180).value(0))
+                );
+
+        return RemoteGui::makeVBoxLayout()
+               .addChild(RemoteGui::makeCheckBox("useCompositeIK").value(false))
+               .addChild(RemoteGui::makeSimpleGridLayout().cols(2).addChild(leftBox).addChild(rightBox))
+               .addChild(RemoteGui::makeSimpleGridLayout().cols(2)
+                         .addTextLabel("elbowKp")
+                         .addChild(RemoteGui::makeFloatSlider("elbowKp").min(0).max(1).value(1))
+
+                         .addTextLabel("jlaKp")
+                         .addChild(RemoteGui::makeFloatSlider("jlaKp").min(0).max(1).value(0))
+                        )
+               .addChild(RemoteGui::makeLabel("errors").value("<errors>"))
+               .addChild(RemoteGui::makeButton("runTest").label("run test"));
     }
 
     void NaturalIKTest::processGui(RemoteGui::TabProxy& prx)
     {
         prx.receiveUpdates();
-        const float x = prx.getValue<float>("X").get();
-        const float y = prx.getValue<float>("Y").get();
-        const float z = prx.getValue<float>("Z").get();
-        p.target = Eigen::Vector3f(x, y, z);
-        p.scale = prx.getValue<float>("scale").get();
-        p.ikparams.minimumElbowHeight = prx.getValue<float>("minElbZ").get();
 
-        const float rx = prx.getValue<float>("rX").get();
-        const float ry = prx.getValue<float>("rY").get();
-        const float rz = prx.getValue<float>("rZ").get();
-        p.targetRotation = Eigen::Vector3f(rx, ry, rz);
+        p.useCompositeIK = prx.getValue<bool>("useCompositeIK").get();
+
+        float x, y, z, rx, ry, rz;
+
+        x = prx.getValue<float>("R.X").get();
+        y = prx.getValue<float>("R.Y").get();
+        z = prx.getValue<float>("R.Z").get();
+        p.p_R.target = Eigen::Vector3f(x, y, z);
+        p.p_R.scale = prx.getValue<float>("R.scale").get();
+        p.p_R.ikparams.minimumElbowHeight = prx.getValue<float>("R.minElbZ").get();
+        p.p_R.setOri = prx.getValue<bool>("R.setOri").get();
+        rx = prx.getValue<float>("R.rX").get();
+        ry = prx.getValue<float>("R.rY").get();
+        rz = prx.getValue<float>("R.rZ").get();
+        p.p_R.targetRotation = Eigen::Vector3f(rx, ry, rz);
+
+        x = prx.getValue<float>("L.X").get();
+        y = prx.getValue<float>("L.Y").get();
+        z = prx.getValue<float>("L.Z").get();
+        p.p_L.target = Eigen::Vector3f(x, y, z);
+        p.p_L.scale = prx.getValue<float>("L.scale").get();
+        p.p_L.ikparams.minimumElbowHeight = prx.getValue<float>("L.minElbZ").get();
+        p.p_L.setOri = prx.getValue<bool>("L.setOri").get();
+        rx = prx.getValue<float>("L.rX").get();
+        ry = prx.getValue<float>("L.rY").get();
+        rz = prx.getValue<float>("L.rZ").get();
+        p.p_L.targetRotation = Eigen::Vector3f(rx, ry, rz);
+
 
+        p.p_R.ikparams.diffIKparams.elbowKp = prx.getValue<float>("elbowKp").get();
+        p.p_R.ikparams.diffIKparams.jointLimitAvoidanceKp = prx.getValue<float>("jlaKp").get();
+        p.p_R.ikparams.diffIKparams.returnIKSteps = true;
+
+        p.p_L.ikparams.diffIKparams.elbowKp = prx.getValue<float>("elbowKp").get();
+        p.p_L.ikparams.diffIKparams.jointLimitAvoidanceKp = prx.getValue<float>("jlaKp").get();
+        p.p_L.ikparams.diffIKparams.returnIKSteps = true;
 
-        p.ikparams.diffIKparams.elbowKp = prx.getValue<float>("elbowKp").get();
-        p.ikparams.diffIKparams.jointLimitAvoidanceKp = prx.getValue<float>("jlaKp").get();
-        p.ikparams.diffIKparams.returnIKSteps = true;
-        p.setOri = prx.getValue<bool>("setOri").get();
 
         p.targetValid = true;
         std::stringstream ss;
@@ -487,7 +529,7 @@ namespace armarx
                 nsjt->set(2, 0.2, 1);
                 ik.addNullspaceGradient(nsjt);
                 CompositeDiffIK::NullspaceJointLimitAvoidancePtr nsjla(new CompositeDiffIK::NullspaceJointLimitAvoidance(rns_R));
-                nsjla->setScale(2, 0);
+                nsjla->setWeight(2, 0);
                 ik.addNullspaceGradient(nsjla);
                 CompositeDiffIK::Result result = ik.solve(pc);
                 if (result.reached)
@@ -591,7 +633,7 @@ namespace armarx
 
         auto makeVizSide = [&](viz::Layer & layer, NaturalIK & ik, Eigen::Vector3f target, Eigen::Vector3f & err)
         {
-            ik.setScale(p.scale);
+            ik.setScale(p.p_R.scale);
 
             Eigen::Vector3f vtgt = target;
             NaturalIK::SoechtingAngles soechtingAngles = ik.CalculateSoechtingAngles(vtgt);
@@ -641,8 +683,8 @@ namespace armarx
                 continue;
             }
 
-            makeVizSide(layer_R, ik_R, p.target + offset, p.err_R);
-            makeVizSide(layer_L, ik_L, p.target + offset, p.err_L);
+            makeVizSide(layer_R, ik_R, p.p_R.target + offset, p.err_R);
+            makeVizSide(layer_L, ik_L, p.p_L.target + offset, p.err_L);
 
 
             //Eigen::Quaternionf targetOri(0.70029222965240479,
@@ -655,51 +697,128 @@ namespace armarx
             //                                 0.70710688,
             //                                -0.70710682,
             //                                0);
-            Eigen::Quaternionf referenceOri(0.70029222965240479,
-                                            -0.6757887601852417,
-                                            0.036805182695388794,
-                                            0.22703713178634644);
-            Eigen::AngleAxisf aa(p.targetRotation.norm() / 180 * M_PI, p.targetRotation.normalized());
-            Eigen::Matrix3f targetOri = referenceOri.toRotationMatrix() * aa.toRotationMatrix();
-
-            Eigen::Matrix4f target_R = math::Helpers::Pose(p.target + offset, targetOri);
+            Eigen::Quaternionf referenceOri_R(0.70029222965240479,
+                                              -0.6757887601852417,
+                                              0.036805182695388794,
+                                              0.22703713178634644);
+            Eigen::Quaternionf referenceOri_L = mirrorOri(referenceOri_R);
+
+            Eigen::AngleAxisf aa_R(p.p_R.targetRotation.norm() / 180 * M_PI, p.p_R.targetRotation.normalized());
+            Eigen::Matrix3f targetOri_R = referenceOri_R.toRotationMatrix() * aa_R.toRotationMatrix();
+            Eigen::Matrix4f target_R = math::Helpers::Pose(p.p_R.target + offset, targetOri_R);
+
+            Eigen::AngleAxisf aa_L(p.p_L.targetRotation.norm() / 180 * M_PI, p.p_L.targetRotation.normalized());
+            Eigen::Matrix3f targetOri_L = referenceOri_L.toRotationMatrix() * aa_L.toRotationMatrix();
+            Eigen::Matrix4f target_L = math::Helpers::Pose(p.p_L.target + offset, targetOri_L);
+
+            // X_Platform
+            // Y_Platform
+            // Yaw_Platform
+            // ArmL1_Cla1
+            // ArmL2_Sho1
+            // ArmL3_Sho2
+            // ArmL4_Sho3
+            // ArmL5_Elb1
+            // ArmL6_Elb2
+            // ArmL7_Wri1
+            // ArmL8_Wri2
+            // ArmR1_Cla1
+            // ArmR2_Sho1
+            // ArmR3_Sho2
+            // ArmR4_Sho3
+            // ArmR5_Elb1
+            // ArmR6_Elb2
+            // ArmR7_Wri1
+            // ArmR8_Wri2
+
+            VirtualRobot::RobotNodeSetPtr rnsP_R = robot->getRobotNodeSet("PlatformPlanningRightArm");
+            VirtualRobot::RobotNodeSetPtr rnsP = robot->getRobotNodeSet("PlatformPlanningBothArms");
+            if (p.useCompositeIK)
+            {
 
 
+                VirtualRobot::IKSolver::CartesianSelection mode_R = p.p_R.setOri ? VirtualRobot::IKSolver::CartesianSelection::All : VirtualRobot::IKSolver::CartesianSelection::Position;
+                CompositeDiffIK cik_R(rnsP_R);
+                CompositeDiffIK::TargetPtr tgt = cik_R.addTarget(arm_R.tcp, target_R, mode_R);
+                CompositeDiffIK::NullspaceJointTargetPtr nsjt(new CompositeDiffIK::NullspaceJointTarget(rnsP_R));
+                NaturalIK::SoechtingForwardPositions fwd = ik_R.solveSoechtingIK(math::Helpers::Position(target_R));
+                Eigen::Vector3f elb = fwd.elbow - fwd.shoulder;
+                float SE = fwd.soechtingAngles.SE;
+                //ARMARX_IMPORTANT << VAROUT(elb);
+                elb = Eigen::AngleAxisf(-SE, Eigen::Vector3f::UnitX()) * elb;
+                //ARMARX_IMPORTANT << VAROUT(elb);
+                float SR = std::atan2(elb(0), -elb(2));
+                SR = std::max(-0.1f, SR);
+                nsjt->set(1 + 3, SE, 1);
+                nsjt->set(2 + 3, SR, 2);
+                nsjt->set(3 + 3, -M_PI / 4, 0.5f);
+                //ARMARX_IMPORTANT << VAROUT(SE) << VAROUT(SR);
+                nsjt->kP = 1;
+                cik_R.addNullspaceGradient(nsjt);
+
+                CompositeDiffIK::NullspaceTargetPtr nst(new CompositeDiffIK::NullspaceTarget(rnsP_R, arm_R.elbow,
+                                                        math::Helpers::CreatePose(fwd.elbow, Eigen::Matrix3f::Identity()),
+                                                        VirtualRobot::IKSolver::CartesianSelection::Position));
+                nst->kP = 0;
+                cik_R.addNullspaceGradient(nst);
+
+                CompositeDiffIK::NullspaceJointLimitAvoidancePtr nsjla(new CompositeDiffIK::NullspaceJointLimitAvoidance(rnsP_R));
+                nsjla->setWeight(0, 0);
+                nsjla->setWeight(1, 0);
+                nsjla->setWeight(2, 0);
+                nsjla->setWeight(2 + 3, 0);
+                nsjla->kP = 0.1;
+                cik_R.addNullspaceGradient(nsjla);
+                CompositeDiffIK::Parameters cp;
+                cp.resetRnsValues = true;
+                cp.returnIKSteps = true;
+                CompositeDiffIK::Result cikResult = cik_R.solve(cp);
+
+                layer_iksteps.clear();
+                int i = 0;
+                for (const CompositeDiffIK::TargetStep& s : tgt->ikSteps)
+                {
+                    layer_iksteps.add(viz::Box("tcp_" + std::to_string(i)).size(20).pose(s.tcpPose).color(viz::Color::blue()));
+                    i++;
+                }
+                for (const CompositeDiffIK::NullspaceTargetStep& s : nst->ikSteps)
+                {
+                    layer_iksteps.add(viz::Box("elb_" + std::to_string(i)).size(20).pose(s.tcpPose).color(viz::Color::blue()));
+                    i++;
+                }
 
-            NaturalDiffIK::Result ikResult;
-            if (p.setOri)
-            {
-                ikResult = ik_R.calculateIK(target_R, arm_R, p.ikparams);
             }
             else
             {
-                ikResult = ik_R.calculateIKpos(math::Helpers::Position(target_R), arm_R, p.ikparams);
-            }
+                rnsP_R->getNode(0)->setJointValue(0);
+                rnsP_R->getNode(1)->setJointValue(0);
+                rnsP_R->getNode(2)->setJointValue(0);
+                NaturalDiffIK::Result ikResult;
+                if (p.p_R.setOri)
+                {
+                    ikResult = ik_R.calculateIK(target_R, arm_R, p.p_R.ikparams);
+                }
+                else
+                {
+                    ikResult = ik_R.calculateIKpos(math::Helpers::Position(target_R), arm_R, p.p_R.ikparams);
+                }
 
-            layer_iksteps.clear();
-            std::stringstream ss;
-            int i = 0;
-            for (const NaturalDiffIK::IKStep& s : ikResult.ikSteps)
-            {
-                ss << s.pdTcp.norm() << "; " << s.odTcp.norm() << "; " << s.pdElb.norm() << "\n";
-                layer_iksteps.add(viz::Box("tcp_" + std::to_string(i)).size(20).pose(s.tcpPose).color(viz::Color::blue()));
-                layer_iksteps.add(viz::Box("elb_" + std::to_string(i)).size(20).pose(s.elbPose).color(viz::Color::blue()));
-                i++;
+                layer_iksteps.clear();
+                std::stringstream ss;
+                int i = 0;
+                for (const NaturalDiffIK::IKStep& s : ikResult.ikSteps)
+                {
+                    ss << s.pdTcp.norm() << "; " << s.odTcp.norm() << "; " << s.pdElb.norm() << "\n";
+                    layer_iksteps.add(viz::Box("tcp_" + std::to_string(i)).size(20).pose(s.tcpPose).color(viz::Color::blue()));
+                    layer_iksteps.add(viz::Box("elb_" + std::to_string(i)).size(20).pose(s.elbPose).color(viz::Color::blue()));
+                    i++;
+                }
+                //ARMARX_IMPORTANT << ss.str();
             }
-            //ARMARX_IMPORTANT << ss.str();
 
-            CompositeDiffIK cik_R(rns_R);
-            cik_R.addTarget(arm_R.tcp, target_R, VirtualRobot::IKSolver::CartesianSelection::All);
-            CompositeDiffIK::NullspaceJointTargetPtr nsjt(new CompositeDiffIK::NullspaceJointTarget(rns_R));
-            nsjt->set(2, 0.2, 1);
-            cik_R.addNullspaceGradient(nsjt);
-            CompositeDiffIK::NullspaceJointLimitAvoidancePtr nsjla(new CompositeDiffIK::NullspaceJointLimitAvoidance(rns_R));
-            nsjla->set(2, 0);
-            cik_R.addNullspaceGradient(nsjla);
-            CompositeDiffIK::Paramaters cp;
-            CompositeDiffIK cikResult = cik_R.solve(cp);
 
-            vizrobot.joints(arm_R.rns->getJointValueMap());
+
+            vizrobot.joints(rnsP_R->getJointValueMap());
 
 
             arviz.commit({layer_R, layer_L, layer_robot, layer_iksteps});
@@ -711,6 +830,35 @@ namespace armarx
     }
 
 
+    Eigen::Matrix4f NaturalIKTest::mirrorPose(Eigen::Matrix4f oldPose)
+    {
+        Eigen::Quaternionf oriOld(oldPose.block<3, 3>(0, 0));
+        Eigen::Quaternionf ori;
+
+        ori.w() = oriOld.z();
+        ori.x() = oriOld.y() * -1;
+        ori.y() = oriOld.x() * -1;
+        ori.z() = oriOld.w();
+
+        Eigen::Matrix4f pose = Eigen::Matrix4f::Identity();
+        pose.block<3, 3>(0, 0) = (ori * Eigen::AngleAxisf(M_PI, Eigen::Vector3f::UnitZ())).toRotationMatrix();
+        pose(0, 3) = -oldPose(0, 3);
+        pose(1, 3) = oldPose(1, 3);
+        pose(2, 3) = oldPose(2, 3);
+
+        return pose;
+    }
+    Eigen::Quaternionf NaturalIKTest::mirrorOri(Eigen::Quaternionf oriOld)
+    {
+        Eigen::Quaternionf ori;
+
+        ori.w() = oriOld.z();
+        ori.x() = oriOld.y() * -1;
+        ori.y() = oriOld.x() * -1;
+        ori.z() = oriOld.w();
+
+        return ori;
+    }
 
 
 
diff --git a/source/RobotAPI/components/NaturalIKTest/NaturalIKTest.h b/source/RobotAPI/components/NaturalIKTest/NaturalIKTest.h
index 9f9d09cc5ca987330c552d8a508ccebaffb79eee..ca8a91ddf88ef9ce10c92027f10e2f1f69cd8b56 100644
--- a/source/RobotAPI/components/NaturalIKTest/NaturalIKTest.h
+++ b/source/RobotAPI/components/NaturalIKTest/NaturalIKTest.h
@@ -68,17 +68,24 @@ namespace armarx
     {
     public:
 
-        struct GuiParams
+        struct GuiSideParams
         {
-            std::atomic_bool targetValid = false;
             Eigen::Vector3f target;
             Eigen::Vector3f targetRotation;
-            Eigen::Vector3f err_R = Eigen::Vector3f::Zero(), err_L = Eigen::Vector3f::Zero();
             float scale = 1.3f;
             float minElbZ;
-
-            NaturalIK::Parameters ikparams;
             std::atomic_bool setOri;
+            NaturalIK::Parameters ikparams;
+        };
+
+        struct GuiParams
+        {
+            GuiSideParams p_R;
+            GuiSideParams p_L;
+            std::atomic_bool targetValid = false;
+            Eigen::Vector3f err_R = Eigen::Vector3f::Zero(), err_L = Eigen::Vector3f::Zero();
+
+            std::atomic_bool useCompositeIK;
 
         };
 
@@ -107,6 +114,8 @@ namespace armarx
 
         void vizTaskRun();
         void testTaskRun();
+        Eigen::Matrix4f mirrorPose(Eigen::Matrix4f oldPose);
+        Eigen::Quaternionf mirrorOri(Eigen::Quaternionf oriOld);
 
 
     private:
diff --git a/source/RobotAPI/libraries/diffik/CompositeDiffIK.cpp b/source/RobotAPI/libraries/diffik/CompositeDiffIK.cpp
index 0e72540bd51656cea2b5695669a1cf6d6ca1c50b..68e627eac22e1b18f4e96023e3dc0fd2f29bd6b7 100644
--- a/source/RobotAPI/libraries/diffik/CompositeDiffIK.cpp
+++ b/source/RobotAPI/libraries/diffik/CompositeDiffIK.cpp
@@ -39,9 +39,11 @@ void CompositeDiffIK::addTarget(const TargetPtr& target)
     targets.emplace_back(target);
 }
 
-void CompositeDiffIK::addTarget(const VirtualRobot::RobotNodePtr& tcp, const Eigen::Matrix4f& target, VirtualRobot::IKSolver::CartesianSelection mode)
+CompositeDiffIK::TargetPtr CompositeDiffIK::addTarget(const VirtualRobot::RobotNodePtr& tcp, const Eigen::Matrix4f& target, VirtualRobot::IKSolver::CartesianSelection mode)
 {
-    addTarget(std::make_shared<Target>(rns, tcp, target, mode));
+    TargetPtr t = std::make_shared<Target>(rns, tcp, target, mode);
+    addTarget(t);
+    return t;
 }
 
 void CompositeDiffIK::addNullspaceGradient(const CompositeDiffIK::NullspaceGradientPtr& gradient)
@@ -52,6 +54,8 @@ void CompositeDiffIK::addNullspaceGradient(const CompositeDiffIK::NullspaceGradi
 
 CompositeDiffIK::Result CompositeDiffIK::solve(Parameters params)
 {
+    //ARMARX_IMPORTANT << "###";
+    //ARMARX_IMPORTANT << VAROUT(rns->getJointValuesEigen().transpose());
     if (params.resetRnsValues)
     {
         for (VirtualRobot::RobotNodePtr rn : rns->getAllRobotNodes())
@@ -66,6 +70,7 @@ CompositeDiffIK::Result CompositeDiffIK::solve(Parameters params)
             }
         }
     }
+    //ARMARX_IMPORTANT << VAROUT(rns->getJointValuesEigen().transpose());
 
     int rows = 0;
     int cols = rns->getSize();
@@ -75,7 +80,13 @@ CompositeDiffIK::Result CompositeDiffIK::solve(Parameters params)
         rows += CartesianSelectionToSize(target->mode);
     }
 
-    Eigen::VectorXf regularization = Eigen::VectorXf::Zero(rows);
+    Eigen::VectorXf jointRegularization = Eigen::VectorXf::Zero(cols);
+    for (size_t i = 0; i < rns->getSize(); i++)
+    {
+        jointRegularization(i) = rns->getNode(i)->isTranslationalJoint() ? params.jointRegularizationTranslation : params.jointRegularizationRotation;
+    }
+
+    Eigen::VectorXf cartesianRegularization = Eigen::VectorXf::Zero(rows);
     {
         CartesianVelocityController tmpVC(rns);
         int row = 0;
@@ -83,15 +94,18 @@ CompositeDiffIK::Result CompositeDiffIK::solve(Parameters params)
         {
             int h = CartesianSelectionToSize(target->mode);
             target->jacobi = Eigen::MatrixXf::Zero(h, cols);
-            regularization.block(row, 0, h, 1) = tmpVC.calculateRegularization(target->mode);
+            cartesianRegularization.block(row, 0, h, 1) = tmpVC.calculateRegularization(target->mode);
             row += h;
         }
     }
+    //ARMARX_IMPORTANT << "START";
+    //ARMARX_INFO << VAROUT(regularization.transpose());
 
     Eigen::VectorXf currentJointValues = rns->getJointValuesEigen();
 
     for (size_t i = 0; i <= params.steps; i++)
     {
+        //ARMARX_IMPORTANT << VAROUT(i);
         Eigen::MatrixXf jacobi = Eigen::MatrixXf::Zero(rows, cols);
         Eigen::MatrixXf invJac = Eigen::MatrixXf::Zero(cols, rows);
 
@@ -103,20 +117,51 @@ CompositeDiffIK::Result CompositeDiffIK::solve(Parameters params)
                 ik->updateJacobianMatrix(target->jacobi, target->tcp, target->mode);
                 int h = CartesianSelectionToSize(target->mode);
                 jacobi.block(row, 0, h, cols) = target->jacobi;
-                cartesianVel.block(row, 0, h, 1) = target->pCtrl.calculate(target->target, target->mode);
+                Eigen::VectorXf cv = target->pCtrl.calculate(target->target, target->mode);
+                //ARMARX_INFO << VAROUT(cv.transpose());
+                cartesianVel.block(row, 0, h, 1) = cv;
                 row += h;
+                if (params.returnIKSteps)
+                {
+                    TargetStep step;
+                    step.tcpPose = target->tcp->getPoseInRootFrame();
+                    step.cartesianVel = cv;
+                    step.posDiff = target->pCtrl.getPositionDiff(target->target);
+                    step.oriDiff = target->pCtrl.getOrientationDiff(target->target);
+                    target->ikSteps.emplace_back(step);
+                }
             }
         }
+        //ARMARX_INFO << VAROUT(cartesianVel.transpose());
+        if (i == 0)
+        {
+            //ARMARX_IMPORTANT << VAROUT(jacobi);
+        }
 
-        ik->updatePseudoInverseJacobianMatrix(invJac, jacobi, 0, regularization);
+        for (int row = 0; row < rows; row++)
+        {
+            jacobi.block(row, 0, 1, cols) = jacobi.block(row, 0, 1, cols).cwiseProduct(jointRegularization.transpose());
+        }
+        if (i == 0)
+        {
+            //ARMARX_IMPORTANT << VAROUT(jacobi);
+        }
+
+        ik->updatePseudoInverseJacobianMatrix(invJac, jacobi, 0, cartesianRegularization);
 
         Eigen::VectorXf nullspaceVel = Eigen::VectorXf::Zero(cols);
 
         for (const NullspaceGradientPtr& nsGradient : nullspaceGradients)
         {
-            nullspaceVel += nsGradient->kP * nsGradient->getGradient();
+            Eigen::VectorXf nsgrad = nsGradient->kP * nsGradient->getGradient(params);
+            //ARMARX_INFO << VAROUT(nsgrad.transpose());
+            nullspaceVel += nsgrad;
+            if (i == 0)
+            {
+                //ARMARX_IMPORTANT << VAROUT(nsgrad.transpose());
+            }
         }
-        LimitInfNormTo(nullspaceVel, params.maxJointAngleStep);
+        //LimitInfNormTo(nullspaceVel, params.maxJointAngleStep);
 
         Eigen::FullPivLU<Eigen::MatrixXf> lu_decomp(jacobi);
         Eigen::MatrixXf nullspace = lu_decomp.kernel();
@@ -131,10 +176,25 @@ CompositeDiffIK::Result CompositeDiffIK::solve(Parameters params)
                 nsv += nullspace.col(i) * nullspace.col(i).dot(nullspaceVel) / nullspace.col(i).squaredNorm();
             }
         }
-        Eigen::VectorXf jv = invJac * cartesianVel + nsv;
-        LimitInfNormTo(jv, params.maxJointAngleStep);
+        Eigen::VectorXf jv = invJac * cartesianVel;
+        //ARMARX_INFO << VAROUT(jv.transpose());
+        //ARMARX_INFO << VAROUT(nsv.transpose());
+        jv = jv + nsv;
+        jv = jv * params.stepSize;
+        jv = LimitInfNormTo(jv, params.maxJointAngleStep);
+        jv = jv.cwiseProduct(jointRegularization);
+
+        //ARMARX_INFO << VAROUT(jv.transpose());
 
         Eigen::VectorXf newJointValues = currentJointValues + jv;
+        if (i == 0)
+        {
+            //ARMARX_IMPORTANT << VAROUT(cartesianVel.transpose());
+            //ARMARX_IMPORTANT << VAROUT(nullspaceVel.transpose());
+
+            //ARMARX_IMPORTANT << VAROUT(currentJointValues.transpose());
+            //ARMARX_IMPORTANT << VAROUT(newJointValues.transpose());
+        }
         rns->setJointValues(newJointValues);
         currentJointValues = newJointValues;
     }
@@ -145,6 +205,8 @@ CompositeDiffIK::Result CompositeDiffIK::solve(Parameters params)
         allReached = allReached && target->pCtrl.reached(target->target, target->mode, target->maxPosError, target->maxOriError);
     }
 
+    //ARMARX_IMPORTANT << "END";
+
 
     //ARMARX_IMPORTANT << ss.str();
 
@@ -197,10 +259,26 @@ CompositeDiffIK::NullspaceTarget::NullspaceTarget(const VirtualRobot::RobotNodeS
 
 }
 
-Eigen::VectorXf CompositeDiffIK::NullspaceTarget::getGradient()
+void CompositeDiffIK::NullspaceTarget::init(Parameters&)
 {
-    Eigen::VectorXf cartesianVel = pCtrl.calculate(target, mode);
-    return vCtrl.calculate(cartesianVel, mode);
+    ikSteps.clear();
+}
+
+Eigen::VectorXf CompositeDiffIK::NullspaceTarget::getGradient(Parameters& params)
+{
+    Eigen::VectorXf cv = pCtrl.calculate(target, mode);
+    Eigen::VectorXf jv = vCtrl.calculate(cv, mode);
+    if (params.returnIKSteps)
+    {
+        NullspaceTargetStep step;
+        step.tcpPose = tcp->getPoseInRootFrame();
+        step.posDiff = pCtrl.getPositionDiff(target);
+        step.oriDiff = pCtrl.getOrientationDiff(target);
+        step.cartesianVel = cv;
+        step.jointVel = jv;
+        ikSteps.emplace_back(step);
+    }
+    return jv;
 }
 
 Eigen::VectorXf CompositeDiffIK::LimitInfNormTo(Eigen::VectorXf vec, float maxValue)
@@ -228,10 +306,35 @@ CompositeDiffIK::NullspaceJointTarget::NullspaceJointTarget(const VirtualRobot::
 void CompositeDiffIK::NullspaceJointTarget::set(int index, float target, float weight)
 {
     this->target(index) = target;
-    this->weight(weight) = weight;
+    this->weight(index) = weight;
+}
+
+void CompositeDiffIK::NullspaceJointTarget::set(const std::string& jointName, float target, float weight)
+{
+    int index = rns->getRobotNodeIndex(jointName);
+    if (index < 0)
+    {
+        throw LocalException("RobotNodeSet has no joint ") << jointName;
+    }
+    set(index, target, weight);
 }
 
-Eigen::VectorXf CompositeDiffIK::NullspaceJointTarget::getGradient()
+void CompositeDiffIK::NullspaceJointTarget::set(const VirtualRobot::RobotNodePtr& rn, float target, float weight)
+{
+    int index = rns->getRobotNodeIndex(rn);
+    if (index < 0)
+    {
+        throw LocalException("RobotNodeSet has no joint ") << rn->getName();
+    }
+    set(index, target, weight);
+}
+
+void CompositeDiffIK::NullspaceJointTarget::init(CompositeDiffIK::Parameters&)
+{
+
+}
+
+Eigen::VectorXf CompositeDiffIK::NullspaceJointTarget::getGradient(Parameters& params)
 {
     return (target - rns->getJointValuesEigen()).cwiseProduct(weight);
 }
@@ -248,12 +351,45 @@ CompositeDiffIK::NullspaceJointLimitAvoidance::NullspaceJointLimitAvoidance(cons
 
 }
 
-void CompositeDiffIK::NullspaceJointLimitAvoidance::setScale(int index, float weight)
+void CompositeDiffIK::NullspaceJointLimitAvoidance::setWeight(int index, float weight)
 {
     this->weight(index) = weight;
 }
 
-Eigen::VectorXf CompositeDiffIK::NullspaceJointLimitAvoidance::getGradient()
+void CompositeDiffIK::NullspaceJointLimitAvoidance::setWeight(const std::string& jointName, float weight)
+{
+    int index = rns->getRobotNodeIndex(jointName);
+    if (index < 0)
+    {
+        throw LocalException("RobotNodeSet has no joint ") << jointName;
+    }
+    setWeight(index, weight);
+}
+
+void CompositeDiffIK::NullspaceJointLimitAvoidance::setWeight(const VirtualRobot::RobotNodePtr& rn, float weight)
+{
+    int index = rns->getRobotNodeIndex(rn);
+    if (index < 0)
+    {
+        throw LocalException("RobotNodeSet has no joint ") << rn->getName();
+    }
+    setWeight(index, weight);
+}
+
+void CompositeDiffIK::NullspaceJointLimitAvoidance::setWeights(const VirtualRobot::RobotNodeSetPtr& rns, float weight)
+{
+    for (const VirtualRobot::RobotNodePtr& rn : rns->getAllRobotNodes())
+    {
+        setWeight(rn, weight);
+    }
+}
+
+void CompositeDiffIK::NullspaceJointLimitAvoidance::init(CompositeDiffIK::Parameters&)
+{
+
+}
+
+Eigen::VectorXf CompositeDiffIK::NullspaceJointLimitAvoidance::getGradient(Parameters& params)
 {
     Eigen::VectorXf r(rns->getSize());
     for (size_t i = 0; i < rns->getSize(); i++)
diff --git a/source/RobotAPI/libraries/diffik/CompositeDiffIK.h b/source/RobotAPI/libraries/diffik/CompositeDiffIK.h
index 5bf5f383b440df5e719d7c93ca6031c415d3beed..9f657626983dc69d8959ed69f9beb3f077a7ce44 100644
--- a/source/RobotAPI/libraries/diffik/CompositeDiffIK.h
+++ b/source/RobotAPI/libraries/diffik/CompositeDiffIK.h
@@ -39,14 +39,37 @@ namespace armarx
     class CompositeDiffIK
     {
     public:
+        struct Parameters
+        {
+            Parameters() {}
+            // IK params
+            size_t steps = 40;
+
+            float maxJointAngleStep = 0.2f;
+            float stepSize = 0.5f;
+            bool resetRnsValues = true;
+            bool returnIKSteps = false;
+            float jointRegularizationTranslation = 1000;
+            float jointRegularizationRotation = 1;
+        };
+
         class NullspaceGradient
         {
         public:
-            virtual Eigen::VectorXf getGradient() = 0;
+            virtual void init(Parameters& params) = 0;
+            virtual Eigen::VectorXf getGradient(Parameters& params) = 0;
             float kP = 1;
         };
         typedef std::shared_ptr<class NullspaceGradient> NullspaceGradientPtr;
 
+        struct NullspaceTargetStep
+        {
+            Eigen::Vector3f posDiff;
+            Eigen::Vector3f oriDiff;
+            Eigen::Matrix4f tcpPose;
+            Eigen::VectorXf cartesianVel;
+            Eigen::VectorXf jointVel;
+        };
         class NullspaceTarget : public NullspaceGradient
         {
         public:
@@ -58,7 +81,10 @@ namespace armarx
             CartesianPositionController pCtrl;
             CartesianVelocityController vCtrl;
 
-            Eigen::VectorXf getGradient() override;
+            void init(Parameters&) override;
+            Eigen::VectorXf getGradient(Parameters& params) override;
+
+            std::vector<NullspaceTargetStep> ikSteps;
         };
         typedef std::shared_ptr<class NullspaceTarget> NullspaceTargetPtr;
 
@@ -68,12 +94,15 @@ namespace armarx
             NullspaceJointTarget(const VirtualRobot::RobotNodeSetPtr& rns);
             NullspaceJointTarget(const VirtualRobot::RobotNodeSetPtr& rns, const Eigen::VectorXf& target, const Eigen::VectorXf& weight);
             void set(int index, float target, float weight);
+            void set(const std::string& jointName, float target, float weight);
+            void set(const VirtualRobot::RobotNodePtr& rn, float target, float weight);
 
             VirtualRobot::RobotNodeSetPtr rns;
             Eigen::VectorXf target;
             Eigen::VectorXf weight;
 
-            Eigen::VectorXf getGradient() override;
+            void init(Parameters&) override;
+            Eigen::VectorXf getGradient(Parameters& params) override;
         };
         typedef std::shared_ptr<class NullspaceJointTarget> NullspaceJointTargetPtr;
 
@@ -82,15 +111,27 @@ namespace armarx
         public:
             NullspaceJointLimitAvoidance(const VirtualRobot::RobotNodeSetPtr& rns);
             NullspaceJointLimitAvoidance(const VirtualRobot::RobotNodeSetPtr& rns, const Eigen::VectorXf& weight);
-            void setScale(int index, float weight);
+            void setWeight(int index, float weight);
+            void setWeight(const std::string& jointName, float weight);
+            void setWeight(const VirtualRobot::RobotNodePtr& rn, float weight);
+            void setWeights(const VirtualRobot::RobotNodeSetPtr& rns, float weight);
+
 
             VirtualRobot::RobotNodeSetPtr rns;
             Eigen::VectorXf weight;
 
-            Eigen::VectorXf getGradient() override;
+            void init(Parameters&) override;
+            Eigen::VectorXf getGradient(Parameters& params) override;
         };
         typedef std::shared_ptr<class NullspaceJointLimitAvoidance> NullspaceJointLimitAvoidancePtr;
 
+        struct TargetStep
+        {
+            Eigen::Vector3f posDiff;
+            Eigen::Vector3f oriDiff;
+            Eigen::Matrix4f tcpPose;
+            Eigen::VectorXf cartesianVel;
+        };
 
         class Target
         {
@@ -103,34 +144,13 @@ namespace armarx
             CartesianPositionController pCtrl;
             float maxPosError = 10.f;
             float maxOriError = 0.05f;
+
+            std::vector<TargetStep> ikSteps;
         };
         typedef std::shared_ptr<Target> TargetPtr;
 
-        struct Parameters
-        {
-            Parameters() {}
-            // IK params
-            size_t steps = 40;
 
-            float maxJointAngleStep = 0.1f;
-            bool resetRnsValues = true;
-            bool returnIKSteps = false;
-        };
-        struct IKStep
-        {
-            Eigen::VectorXf jointValues;
-            Eigen::Vector3f pdTcp;
-            Eigen::Vector3f odTcp;
-            Eigen::Vector3f pdElb;
-            Eigen::Matrix4f tcpPose;
-            Eigen::Matrix4f elbPose;
-            Eigen::VectorXf cartesianVel;
-            Eigen::VectorXf cartesianVelElb;
-            Eigen::VectorXf jvElb;
-            Eigen::VectorXf jvLA;
-            Eigen::VectorXf jv;
-            Eigen::VectorXf jvClamped;
-        };
+
 
         struct Result
         {
@@ -145,7 +165,6 @@ namespace armarx
             Eigen::VectorXf jointLimitMargins;
             float minimumJointLimitMargin;
             Eigen::Vector3f elbowPosDiff;
-            std::vector<IKStep> ikSteps;
         };
 
         static Eigen::VectorXf LimitInfNormTo(Eigen::VectorXf vec, float maxValue);
@@ -153,7 +172,7 @@ namespace armarx
         CompositeDiffIK(const VirtualRobot::RobotNodeSetPtr& rns);
 
         void addTarget(const TargetPtr& target);
-        void addTarget(const VirtualRobot::RobotNodePtr& tcp, const Eigen::Matrix4f& target, VirtualRobot::IKSolver::CartesianSelection mode);
+        TargetPtr addTarget(const VirtualRobot::RobotNodePtr& tcp, const Eigen::Matrix4f& target, VirtualRobot::IKSolver::CartesianSelection mode);
         void addNullspaceGradient(const NullspaceGradientPtr& gradient);
 
         Result solve(Parameters params);
diff --git a/source/RobotAPI/libraries/natik/NaturalIK.cpp b/source/RobotAPI/libraries/natik/NaturalIK.cpp
index f0ad1b7309e7f33c84764363ca5cd150a370b18b..76bd6e75e6301cb29a80b608d8fd6fb2b7303b46 100644
--- a/source/RobotAPI/libraries/natik/NaturalIK.cpp
+++ b/source/RobotAPI/libraries/natik/NaturalIK.cpp
@@ -178,8 +178,10 @@ NaturalIK::SoechtingForwardPositions NaturalIK::forwardKinematics(SoechtingAngle
     //ARMARX_IMPORTANT << VAROUT(elb.transpose()) << VAROUT(wri.transpose());
 
     NaturalIK::SoechtingForwardPositions res;
+    res.shoulder = shoulderPos;
     res.elbow = shoulderPos + elb;
     res.wrist = shoulderPos + elb + wri;
+    res.soechtingAngles = sa;
 
     return res;
 }
diff --git a/source/RobotAPI/libraries/natik/NaturalIK.h b/source/RobotAPI/libraries/natik/NaturalIK.h
index d6315096a58084776797e6ce5551b65651ff4026..7e1ecb940cc7adb84c0091e4e1f3427923559c74 100644
--- a/source/RobotAPI/libraries/natik/NaturalIK.h
+++ b/source/RobotAPI/libraries/natik/NaturalIK.h
@@ -64,11 +64,6 @@ namespace armarx
             VirtualRobot::RobotNodePtr tcp;
         };
 
-        struct SoechtingForwardPositions
-        {
-            Eigen::Vector3f elbow;
-            Eigen::Vector3f wrist;
-        };
 
         struct SoechtingAngles
         {
@@ -91,6 +86,14 @@ namespace armarx
             static constexpr float MMM_SHOULDER_POS = (MMM_LSC2LS + MMM_BT2LSC) * MMM_L;
         };
 
+        struct SoechtingForwardPositions
+        {
+            Eigen::Vector3f shoulder;
+            Eigen::Vector3f elbow;
+            Eigen::Vector3f wrist;
+            SoechtingAngles soechtingAngles;
+        };
+
     public:
         NaturalIK(std::string side, Eigen::Vector3f shoulderPos = Eigen::Vector3f::Zero(), float scale = 1);