diff --git a/source/RobotAPI/interface/units/RobotUnit/NJointTaskSpaceDMPController.ice b/source/RobotAPI/interface/units/RobotUnit/NJointTaskSpaceDMPController.ice index 2eb2753c7697a43743707e03c1f0adc9b81c238b..3f289eb02017607e2b57917260367b43f143c613 100644 --- a/source/RobotAPI/interface/units/RobotUnit/NJointTaskSpaceDMPController.ice +++ b/source/RobotAPI/interface/units/RobotUnit/NJointTaskSpaceDMPController.ice @@ -45,7 +45,9 @@ module armarx float DMPKd = 20; int kernelSize = 100; double tau = 1; - int baseMode = 1; + string dmpMode = "MinimumJerk"; + string dmpStyle = "Discrete"; + double dmpAmplitude = 1; double phaseL = 10; double phaseK = 10; @@ -53,9 +55,7 @@ module armarx double phaseDist1 = 10; double phaseKpPos = 1; double phaseKpOri = 0.1; - double timeDuration = 10; - double posToOriRatio = 100; // velocity controller configuration @@ -63,6 +63,9 @@ module armarx string tcpName = ""; NJointTaskSpaceDMPControllerMode::CartesianSelection mode = NJointTaskSpaceDMPControllerMode::eAll; + double maxLinearVel; + double maxAngularVel; + }; @@ -72,10 +75,12 @@ module armarx bool isFinished(); void runDMP(Ice::DoubleSeq goals, double tau); - void setTemporalFactor(double tau); + void setSpeed(double times); void setViaPoints(double canVal, Ice::DoubleSeq point); void setGoals(Ice::DoubleSeq goals); + double getCanVal(); + void setControllerTarget(float avoidJointLimitsKp, NJointTaskSpaceDMPControllerMode::CartesianSelection mode); void setTorqueKp(StringFloatDictionary torqueKp); void setNullspaceJointVelocities(StringFloatDictionary nullspaceJointVelocities); @@ -88,7 +93,7 @@ module armarx float DMPKd = 20; int kernelSize = 100; double tau = 1; - int baseMode = 1; + int dmpMode = 1; int dmpNum = 2; // phaseStop technique @@ -128,4 +133,55 @@ module armarx void setTorqueKp(StringFloatDictionary torqueKp); void setNullspaceJointVelocities(StringFloatDictionary nullspaceJointVelocities); }; + + class NJointBimanualCCDMPControllerConfig extends NJointControllerConfig + { + + // dmp configuration + int kernelSize = 100; + string dmpMode = "MinimumJerk"; + string dmpType = "Discrete"; + + // phaseStop technique + double phaseL = 10; + double phaseK = 10; + double phaseDist0 = 50; + double phaseDist1 = 10; + double phaseKpPos = 1; + double phaseKpOri = 0.1; + double posToOriRatio = 10; + double timeDuration = 10; + + string defautLeader = "Left"; + + Ice::FloatSeq leftDesiredJointValues; + Ice::FloatSeq rightDesiredJointValues; + double knull = 5; + + float KoriFollower = 1; + float KposFollower = 1; + + double maxLinearVel; + double maxAngularVel; + + + }; + + interface NJointBimanualCCDMPControllerInterface extends NJointControllerInterface + { + void learnDMPFromFiles(string whichDMP, Ice::StringSeq trajfiles); + bool isFinished(); + void runDMP(Ice::DoubleSeq leftGoals, Ice::DoubleSeq rightGoals); + + void setViaPoints(double canVal, Ice::DoubleSeq point); + void setGoals(Ice::DoubleSeq goals); + + void changeLeader(); + double getVirtualTime(); + + string getLeaderName(); + + + }; }; + diff --git a/source/RobotAPI/libraries/CMakeLists.txt b/source/RobotAPI/libraries/CMakeLists.txt index 63093136d096c560bce41e766cc10f9aaa44ade2..b0a1a80cab68dc9f10e178cc00da1e1b65b49c94 100644 --- a/source/RobotAPI/libraries/CMakeLists.txt +++ b/source/RobotAPI/libraries/CMakeLists.txt @@ -4,3 +4,5 @@ add_subdirectory(SimpleJsonLogger) add_subdirectory(RobotAPIVariantWidget) add_subdirectory(RobotAPINJointControllers) + +add_subdirectory(DMPController) diff --git a/source/RobotAPI/libraries/DMPController/CMakeLists.txt b/source/RobotAPI/libraries/DMPController/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..3a36d3bdcf71fb9f3726a38857d54f05bb108cec --- /dev/null +++ b/source/RobotAPI/libraries/DMPController/CMakeLists.txt @@ -0,0 +1,50 @@ +set(LIB_NAME DMPController) + +armarx_component_set_name("${LIB_NAME}") +armarx_set_target("Library: ${LIB_NAME}") + + + +find_package(Eigen3 QUIET) +find_package(Simox ${ArmarX_Simox_VERSION} QUIET) +find_package(DMP QUIET) + + +armarx_build_if(Eigen3_FOUND "Eigen3 not available") +armarx_build_if(Simox_FOUND "Simox-VirtualRobot not available") +armarx_build_if(DMP_FOUND "DMP not available") + +if (Eigen3_FOUND AND Simox_FOUND AND DMP_FOUND) + include_directories(${Simox_INCLUDE_DIRS}) + include_directories(SYSTEM ${Eigen3_INCLUDE_DIR}) + include_directories(${DMP_INCLUDE_DIRS}) +endif() + +set(LIBS + ArmarXCoreInterfaces + ArmarXCore + RobotAPIInterfaces + ArmarXCoreObservers + ArmarXCoreStatechart + ArmarXCoreEigen3Variants + VirtualRobot + Saba + SimDynamics + RobotUnit + ${DMP_LIBRARIES} + ) + +set(LIB_FILES +./TaskSpaceDMPController.cpp +#@TEMPLATE_LINE@@COMPONENT_PATH@/@COMPONENT_NAME@.cpp +) +set(LIB_HEADERS +./TaskSpaceDMPController.h +#@TEMPLATE_LINE@@COMPONENT_PATH@/@COMPONENT_NAME@.h +) + + +armarx_add_library("${LIB_NAME}" "${LIB_FILES}" "${LIB_HEADERS}" "${LIBS}") + +# add unit tests +add_subdirectory(test) diff --git a/source/RobotAPI/libraries/DMPController/TaskSpaceDMPController.cpp b/source/RobotAPI/libraries/DMPController/TaskSpaceDMPController.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b712d6491dfee79e774e22748a6c16733af466b3 --- /dev/null +++ b/source/RobotAPI/libraries/DMPController/TaskSpaceDMPController.cpp @@ -0,0 +1,327 @@ +/* + * 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::DMPController + * @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 "TaskSpaceDMPController.h" + + +using namespace armarx; + + + +void TaskSpaceDMPController::flow(double deltaT, const Eigen::Matrix4f& currentPose, const Eigen::VectorXf& twist) +{ + if (canVal < 1e-8) + { + if (config.DMPStyle == "Periodic") + { + prepareExecution(eigen4f2vec(currentPose), goalPoseVec); + } + else + { + targetVel.setZero(); + return; + } + } + + Eigen::Vector3f currentPosition; + Eigen::Quaterniond currentOrientation; + double posiError = 0; + double oriError = 0; + + getError(currentPose, currentPosition, currentOrientation, posiError, oriError); + + double poseError = posiError + config.phaseStopParas.mm2radi * oriError; + + double phaseDist; + if (isDisturbance) + { + phaseDist = config.phaseStopParas.backDist; + } + else + { + phaseDist = config.phaseStopParas.goDist; + } + double phaseL = config.phaseStopParas.maxValue; + double phaseK = config.phaseStopParas.slop; + + double phaseStop = phaseL / (1 + exp(-phaseK * (poseError - phaseDist))); + double mpcFactor = 1 - (phaseStop / phaseL); + + if (mpcFactor < 0.1) + { + isDisturbance = true; + } + + if (mpcFactor > 0.9) + { + isDisturbance = false; + } + + double tau = dmpPtr->getTemporalFactor(); + double timeDuration = config.motionTimeDuration; + canVal -= 1 / tau * deltaT * 1 / (1 + phaseStop) ; + + + for (size_t i = 0; i < 7; ++i) + { + currentState[i].vel = currentState[i].vel * config.DMPAmplitude; + } + + currentState = dmpPtr->calculateDirectlyVelocity(currentState, canVal / timeDuration, deltaT / timeDuration, targetPoseVec); + + 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++) + { + 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; + } + + + Eigen::Quaterniond dmpQuaternionVel; + dmpQuaternionVel.w() = currentState[3].vel; + dmpQuaternionVel.x() = currentState[4].vel; + dmpQuaternionVel.y() = currentState[5].vel; + dmpQuaternionVel.z() = currentState[6].vel; + + Eigen::Quaterniond dmpQuaternionPosi; + dmpQuaternionPosi.w() = currentState[3].pos; + dmpQuaternionPosi.x() = currentState[4].pos; + dmpQuaternionPosi.y() = currentState[5].pos; + dmpQuaternionPosi.z() = currentState[6].pos; + + + Eigen::Quaterniond angularVel0 = dmpQuaternionVel * dmpQuaternionPosi.inverse(); + angularVel0.w() *= 2; + angularVel0.x() *= 2; + angularVel0.y() *= 2; + angularVel0.z() *= 2; + + + double angularChange = angularVel0.angularDistance(oldDMPAngularVelocity); + if (angularVel0.w() > 0 && oldDMPAngularVelocity.w() < 0 && angularChange < 1e-2) + { + angularVel0.w() = - angularVel0.w(); + angularVel0.x() = - angularVel0.x(); + angularVel0.y() = - angularVel0.y(); + angularVel0.z() = - angularVel0.z(); + } + oldDMPAngularVelocity = angularVel0; + + Eigen::Vector3f currentAngularVel; + currentAngularVel << twist(3), twist(4), twist(5); + + Eigen::Quaternionf targetQuaternionf; + targetQuaternionf.w() = targetPoseVec[3]; + targetQuaternionf.x() = targetPoseVec[4]; + targetQuaternionf.y() = targetPoseVec[5]; + targetQuaternionf.z() = targetPoseVec[6]; + + Eigen::Matrix3f desiredMat(targetQuaternionf); + Eigen::Matrix3f currentMat = currentPose.block<3, 3>(0, 0); + Eigen::Matrix3f diffMat = desiredMat * currentMat.inverse(); + 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); + + debugData.canVal = canVal; + debugData.oriError = oriError; + debugData.posiError = posiError; + debugData.mpcFactor = mpcFactor; + debugData.poseError = poseError; +} + +void TaskSpaceDMPController::learnDMPFromFiles(const std::vector<std::string>& fileNames, const std::vector<double>& ratios) +{ + if (ratios.size() != fileNames.size()) + { + ARMARX_ERROR << "ratios should have the same size with files"; + return; + } + + + DMP::Vec<DMP::SampledTrajectoryV2 > trajs; + + double ratioSum = 0; + for (size_t i = 0; i < fileNames.size(); ++i) + { + DMP::SampledTrajectoryV2 traj; + traj.readFromCSVFile(fileNames.at(i)); + traj = DMP::SampledTrajectoryV2::normalizeTimestamps(traj, 0, 1); + trajs.push_back(traj); + + ratioSum += ratios.at(i); + } + + if (ratioSum == 0) + { + ARMARX_ERROR << "ratios are invalid. The sum is equal to 0"; + return; + } + + DMP::DVec ratiosVec; + ratiosVec.resize(ratios.size()); + for (size_t i = 0; i < ratios.size(); ++i) + { + ratiosVec.at(i) = ratios.at(i) / ratioSum; + } + + ARMARX_INFO << "ratios: " << ratios.at(0); + dmpPtr->learnFromTrajectories(trajs); + dmpPtr->styleParas = dmpPtr->getStyleParasWithRatio(ratiosVec); +} + +void TaskSpaceDMPController::learnDMPFromFiles(const std::vector<std::string>& fileNames) +{ + std::vector<double> ratios; + for (size_t i = 0; i < fileNames.size(); ++i) + { + if (i == 0) + { + ratios.push_back(1.0); + } + else + { + ratios.push_back(0.0); + } + } + + learnDMPFromFiles(fileNames, ratios); +} + +void TaskSpaceDMPController::setViaPose(double canVal, const Eigen::Matrix4f& viaPose) +{ + + setViaPose(canVal, eigen4f2vec(viaPose)); +} + +void TaskSpaceDMPController::setViaPose(double canVal, const std::vector<double>& viaPoseWithQuaternion) +{ + if (canVal <= dmpPtr->getUMin()) + { + goalPoseVec = viaPoseWithQuaternion; + } + dmpPtr->setViaPoint(canVal, viaPoseWithQuaternion); +} + +void TaskSpaceDMPController::prepareExecution(const Eigen::Matrix4f& currentPose, const Eigen::Matrix4f& goalPose) +{ + std::vector<double> currentPoseVec = eigen4f2vec(currentPose); + std::vector<double> goalPoseVec = eigen4f2vec(goalPose); + + prepareExecution(currentPoseVec, goalPoseVec); +} + +void TaskSpaceDMPController::prepareExecution(const std::vector<double>& currentPoseVec, const std::vector<double>& goalPoseVec) +{ + ARMARX_CHECK_EQUAL(currentPoseVec.size(), 7); + ARMARX_CHECK_EQUAL(goalPoseVec.size(), 7); + + for (size_t i = 0; i < currentPoseVec.size(); ++i) + { + currentState[i].pos = currentPoseVec.at(i); + currentState[i].vel = 0; + targetPoseVec.at(i) = currentPoseVec.at(i); + } + + dmpPtr->prepareExecution(goalPoseVec, currentState, 1, 1); + this->goalPoseVec = goalPoseVec; + isDisturbance = false; + canVal = config.motionTimeDuration; + oldDMPAngularVelocity.setIdentity(); + +} + +void TaskSpaceDMPController::setSpeed(double times) +{ + if (times == 0) + { + return; + } + + config.motionTimeDuration /= times; +} + +std::vector<double> TaskSpaceDMPController::eigen4f2vec(const Eigen::Matrix4f& pose) +{ + std::vector<double> viaPoseVec; + viaPoseVec.resize(7); + + for (size_t i = 0; i < 3; ++i) + { + viaPoseVec.at(i) = pose(i, 3); + } + + VirtualRobot::MathTools::Quaternion quat = VirtualRobot::MathTools::eigen4f2quat(pose); + + viaPoseVec.at(3) = quat.w; + viaPoseVec.at(4) = quat.x; + viaPoseVec.at(5) = quat.y; + viaPoseVec.at(6) = quat.z; + + return viaPoseVec; +} + +void TaskSpaceDMPController::getError(const Eigen::Matrix4f& currentPose, Eigen::Vector3f& currentPosition, Eigen::Quaterniond& currentOrientation, double& posiError, double& oriError) +{ + currentPosition.setZero(); + currentPosition << currentPose(0, 3), currentPose(1, 3), currentPose(2, 3); + + VirtualRobot::MathTools::Quaternion quat = VirtualRobot::MathTools::eigen4f2quat(currentPose); + currentOrientation.w() = quat.w; + currentOrientation.x() = quat.x; + currentOrientation.y() = quat.y; + currentOrientation.z() = quat.z; + + posiError = 0; + for (size_t i = 0; i < 3; ++i) + { + posiError += pow(currentPosition(i) - targetPoseVec[i], 2); + } + posiError = sqrt(posiError); + + Eigen::Quaterniond targetQuaternion; + targetQuaternion.w() = targetPoseVec[3]; + targetQuaternion.x() = targetPoseVec[4]; + targetQuaternion.y() = targetPoseVec[5]; + targetQuaternion.z() = targetPoseVec[6]; + + oriError = targetQuaternion.angularDistance(currentOrientation); + if (oriError > M_PI) + { + oriError = 2 * M_PI - oriError; + } + +} + + diff --git a/source/RobotAPI/libraries/DMPController/TaskSpaceDMPController.h b/source/RobotAPI/libraries/DMPController/TaskSpaceDMPController.h new file mode 100644 index 0000000000000000000000000000000000000000..c62fef3fb25c3bbf43fd8093db3308110b68d195 --- /dev/null +++ b/source/RobotAPI/libraries/DMPController/TaskSpaceDMPController.h @@ -0,0 +1,196 @@ +/* + * 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::DMPController + * @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_RobotAPI_TaskSpaceDMPController_H +#define _ARMARX_LIB_RobotAPI_TaskSpaceDMPController_H + + +#include <dmp/representation/dmp/umitsmp.h> + + +#include <VirtualRobot/RobotNodeSet.h> +#include <ArmarXCore/core/logging/Logging.h> +#include <ArmarXCore/core/exceptions/local/ExpressionException.h> + + +namespace armarx +{ + + struct PhaseStopParams + { + float goDist = 80; + float backDist = 50; + float maxValue = 100; + float slop = 1000; + float Kpos = 1; + float Dpos = 2; + float Kori = 1; + float Dori = 0; + float mm2radi = 10; + }; + + struct TaskSpaceDMPControllerConfig + { + int DMPKernelSize = 50; + std::string DMPMode = "Linear"; + std::string DMPStyle = "Discrete"; + float DMPAmplitude = 1; + float motionTimeDuration = 10; + PhaseStopParams phaseStopParas; + }; + + struct DebugInfo + { + double canVal; + double mpcFactor; + double poseError; + double posiError; + double oriError; + }; + + /** + * @defgroup Library-TaskSpaceDMPController TaskSpaceDMPController + * @ingroup RobotAPI + * A description of the library TaskSpaceDMPController. + * + * @class TaskSpaceDMPController + * @ingroup Library-TaskSpaceDMPController + * @brief Brief description of class TaskSpaceDMPController. + * + * Detailed description of class TaskSpaceDMPController. + */ + class TaskSpaceDMPController + { + public: + TaskSpaceDMPController(std::string name, const TaskSpaceDMPControllerConfig& config, bool isPhaseStop = true) + { + this->config = config; + + int ModeInd; + if (config.DMPMode == "MinimumJerk") + { + ModeInd = 2; + } + else + { + ModeInd = 1; + } + + + dmpPtr.reset(new DMP::UMITSMP(config.DMPKernelSize, ModeInd)); + canVal = config.motionTimeDuration; + + targetPoseVec.resize(7); + targetVel.resize(6); + targetVel.setZero(); + currentState.resize(7); + + this->isPhaseStop = isPhaseStop; + dmpName = name; + } + + std::string getName() + { + return dmpName; + } + + + void flow(double deltaT, const Eigen::Matrix4f& currentPose, const Eigen::VectorXf& twist); + + Eigen::VectorXf getTargetVelocity() + { + return targetVel; + } + + std::vector<double> getTargetPose() + { + return targetPoseVec; + } + + Eigen::Matrix4f getTargetPoseMat() + { + Eigen::Matrix4f res = VirtualRobot::MathTools::quat2eigen4f(targetPoseVec.at(4), targetPoseVec.at(5), targetPoseVec.at(6), targetPoseVec.at(3)); + res(0, 3) = targetPoseVec.at(0); + res(1, 3) = targetPoseVec.at(1); + res(2, 3) = targetPoseVec.at(2); + + return res; + } + + void learnDMPFromFiles(const std::vector<std::string>& fileNames, const std::vector<double>& ratios); + void learnDMPFromFiles(const std::vector<std::string>& fileNames); + + void setViaPose(double canVal, const Eigen::Matrix4f& viaPose); + void setViaPose(double canVal, const std::vector<double>& viaPoseWithQuaternion); + + void prepareExecution(const Eigen::Matrix4f& currentPose, const Eigen::Matrix4f& goalPose); + void prepareExecution(const std::vector<double>& currentPoseVec, const std::vector<double>& goalPoseVec); + + void setSpeed(double times); + + void setGoalPose(const Eigen::Matrix4f& goalPose) + { + setViaPose(dmpPtr->getUMin(), goalPose); + } + + void setGoalPoseVec(const std::vector<double> goalPoseVec) + { + setViaPose(dmpPtr->getUMin(), goalPoseVec); + } + + DebugInfo debugData; + std::vector<double> eigen4f2vec(const Eigen::Matrix4f& pose); + + DMP::UMITSMPPtr getDMP() + { + return dmpPtr; + } + + double canVal; + bool isPhaseStop; + std::string dmpName; + private: + + + DMP::DVec goalPoseVec; + + Eigen::VectorXf targetVel; + DMP::DVec targetPoseVec; + + DMP::UMITSMPPtr dmpPtr; + DMP::Vec<DMP::DMPState > currentState; + TaskSpaceDMPControllerConfig config; + + + bool isDisturbance; + + + void getError(const Eigen::Matrix4f& pose, Eigen::Vector3f& position, Eigen::Quaterniond& quaternion, double& posiError, double& oriError); + + Eigen::Quaterniond oldDMPAngularVelocity; + }; + + typedef boost::shared_ptr<TaskSpaceDMPController> TaskSpaceDMPControllerPtr; + +} + +#endif diff --git a/source/RobotAPI/libraries/DMPController/test/CMakeLists.txt b/source/RobotAPI/libraries/DMPController/test/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..df7b127d74b14e3a3b6bce5c3fd556324c3dfa73 --- /dev/null +++ b/source/RobotAPI/libraries/DMPController/test/CMakeLists.txt @@ -0,0 +1,5 @@ + +# Libs required for the tests +SET(LIBS ${LIBS} ArmarXCore DMPController) + +armarx_add_test(DMPControllerTest DMPControllerTest.cpp "${LIBS}") \ No newline at end of file diff --git a/source/RobotAPI/libraries/DMPController/test/DMPControllerTest.cpp b/source/RobotAPI/libraries/DMPController/test/DMPControllerTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ce13dde7e8ae02eeeade7e2be1e52fce411acc34 --- /dev/null +++ b/source/RobotAPI/libraries/DMPController/test/DMPControllerTest.cpp @@ -0,0 +1,36 @@ +/* + * 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::DMPController + * @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 + */ + +#define BOOST_TEST_MODULE RobotAPI::ArmarXLibraries::DMPController + +#define ARMARX_BOOST_TEST + +#include <RobotAPI/Test.h> +#include "../TaskSpaceDMPController.h" + +#include <iostream> + +BOOST_AUTO_TEST_CASE(testExample) +{ + + BOOST_CHECK_EQUAL(true, true); +} diff --git a/source/RobotAPI/libraries/RobotAPINJointControllers/CMakeLists.txt b/source/RobotAPI/libraries/RobotAPINJointControllers/CMakeLists.txt index 1d2c433b93afb51f8d5b3aba5788440fb6c7f0a9..4f13d687f985f1160efe1b383b1857c17533d134 100644 --- a/source/RobotAPI/libraries/RobotAPINJointControllers/CMakeLists.txt +++ b/source/RobotAPI/libraries/RobotAPINJointControllers/CMakeLists.txt @@ -23,6 +23,7 @@ set(LIBS RobotAPIInterfaces ArmarXCoreObservers ArmarXCoreStatechart ArmarXCoreE Saba SimDynamics RobotUnit + ) set(LIB_FILES @@ -40,22 +41,22 @@ if (DMP_FOUND ) list(APPEND LIB_HEADERS DMPController/NJointJointSpaceDMPController.h - DMPController/NJointTaskSpaceDMPController.h DMPController/NJointJSDMPController.h DMPController/NJointTSDMPController.h DMPController/NJointCCDMPController.h + DMPController/NJointBimanualCCDMPController.h ) list(APPEND LIB_FILES DMPController/NJointJointSpaceDMPController.cpp - DMPController/NJointTaskSpaceDMPController.cpp DMPController/NJointJSDMPController.cpp DMPController/NJointTSDMPController.cpp DMPController/NJointCCDMPController.cpp + DMPController/NJointBimanualCCDMPController.cpp ) - list(APPEND LIBS ${DMP_LIBRARIES}) + list(APPEND LIBS ${DMP_LIBRARIES} DMPController) endif () armarx_add_library("${LIB_NAME}" "${LIB_FILES}" "${LIB_HEADERS}" "${LIBS}") diff --git a/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointBimanualCCDMPController.cpp b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointBimanualCCDMPController.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2d00b4b9538bcb94c898ba813d8257d5ee6b6801 --- /dev/null +++ b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointBimanualCCDMPController.cpp @@ -0,0 +1,556 @@ +#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); + + VirtualRobot::RobotNodeSetPtr leftRNS = robotUnit->getRtRobot()->getRobotNodeSet("LeftArm"); + for (size_t i = 0; i < leftRNS->getSize(); ++i) + { + std::string jointName = leftRNS->getNode(i)->getName(); + ControlTargetBase* ct = prov->getControlTarget(jointName, ControlModes::Velocity1DoF); + const SensorValueBase* sv = prov->getSensorValue(jointName); + leftTargets.push_back(ct->asA<ControlTarget1DoFActuatorVelocity>()); + const SensorValue1DoFActuatorVelocity* velocitySensor = sv->asA<SensorValue1DoFActuatorVelocity>(); + const SensorValue1DoFActuatorPosition* positionSensor = sv->asA<SensorValue1DoFActuatorPosition>(); + if (!velocitySensor) + { + ARMARX_WARNING << "No velocitySensor available for " << jointName; + } + if (!positionSensor) + { + ARMARX_WARNING << "No positionSensor available for " << jointName; + } + + leftVelocitySensors.push_back(velocitySensor); + leftPositionSensors.push_back(positionSensor); + + + }; + + VirtualRobot::RobotNodeSetPtr rightRNS = robotUnit->getRtRobot()->getRobotNodeSet("RightArm"); + for (size_t i = 0; i < rightRNS->getSize(); ++i) + { + std::string jointName = rightRNS->getNode(i)->getName(); + ControlTargetBase* ct = prov->getControlTarget(jointName, ControlModes::Velocity1DoF); + const SensorValueBase* sv = prov->getSensorValue(jointName); + rightTargets.push_back(ct->asA<ControlTarget1DoFActuatorVelocity>()); + const SensorValue1DoFActuatorVelocity* velocitySensor = sv->asA<SensorValue1DoFActuatorVelocity>(); + const SensorValue1DoFActuatorPosition* positionSensor = sv->asA<SensorValue1DoFActuatorPosition>(); + + if (!velocitySensor) + { + ARMARX_WARNING << "No velocitySensor available for " << jointName; + } + if (!positionSensor) + { + ARMARX_WARNING << "No positionSensor available for " << jointName; + } + + rightVelocitySensors.push_back(velocitySensor); + rightPositionSensors.push_back(positionSensor); + }; + + + 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); + + + 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 = "Left"; + + 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; + } + + 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 + { + currentControlGroup = rightGroup; + currentLeaderPose = controllerSensorData.getReadBuffer().currentRightPose; + currentFollowerPose = controllerSensorData.getReadBuffer().currentLeftPose; + currentLeaderTwist = controllerSensorData.getReadBuffer().currentRightTwist; + currentFollowerTwist = controllerSensorData.getReadBuffer().currentLeftTwist; + } + + 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, currentFollowerLocalPose, currentFollowerTwist); + + Eigen::VectorXf leaderTargetVel = leaderDMP->getTargetVelocity(); + Eigen::Matrix4f leaderTargetPose = leaderDMP->getTargetPoseMat(); + Eigen::Matrix4f followerLocalTargetPose = followerDMP->getTargetPoseMat(); + 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; + + + std::vector<double> followerTargetPoseVec = followerDMP->eigen4f2vec(followerTargetPose); + + + + if (leaderName == "Left") + { + leftTargetVel = leaderTargetVel; + rightTargetVel = followerTargetVel; + + leftDMPTarget = leaderDMP->getTargetPose(); + rightDMPTarget = followerTargetPoseVec; + + } + else + { + rightTargetVel = leaderTargetVel; + leftTargetVel = followerTargetVel; + + rightDMPTarget = leaderDMP->getTargetPose(); + leftDMPTarget = followerTargetPoseVec; + + } + + + + + 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; + + writeControlStruct(); + } + + + + 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; + // cartesian vel controller + Eigen::MatrixXf I = Eigen::MatrixXf::Identity(leftTargets.size(), leftTargets.size()); + + Eigen::MatrixXf jacobiL = leftIK->getJacobianMatrix(tcpLeft, VirtualRobot::IKSolver::CartesianSelection::All); + 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); + 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; + } + + controllerSensorData.getWriteBuffer().currentLeftTwist = jacobiL * leftqvel; + controllerSensorData.getWriteBuffer().currentRightTwist = jacobiR * rightqvel; + controllerSensorData.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 = 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/NJointBimanualCCDMPController.h b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointBimanualCCDMPController.h new file mode 100644 index 0000000000000000000000000000000000000000..39a1a6e849f546f7561ce42738a6135d3cc69f1e --- /dev/null +++ b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointBimanualCCDMPController.h @@ -0,0 +1,168 @@ + +#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> + + + +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; + }; + + 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::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 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> debugOutputData; + + struct NJointBimanualCCDMPControllerSensorData + { + double currentTime; + double deltaT; + Eigen::Matrix4f currentLeftPose; + Eigen::Matrix4f currentRightPose; + Eigen::VectorXf currentLeftTwist; + Eigen::VectorXf currentRightTwist; + }; + TripleBuffer<NJointBimanualCCDMPControllerSensorData> controllerSensorData; + + + std::vector<ControlTarget1DoFActuatorVelocity*> leftTargets; + std::vector<const SensorValue1DoFActuatorVelocity*> leftVelocitySensors; + std::vector<const SensorValue1DoFActuatorPosition*> leftPositionSensors; + + std::vector<ControlTarget1DoFActuatorVelocity*> rightTargets; + std::vector<const SensorValue1DoFActuatorVelocity*> rightVelocitySensors; + std::vector<const SensorValue1DoFActuatorPosition*> rightPositionSensors; + + NJointBimanualCCDMPControllerConfigPtr cfg; + VirtualRobot::DifferentialIKPtr leftIK; + VirtualRobot::DifferentialIKPtr rightIK; + + std::vector<TaskSpaceDMPControllerPtr > leftGroup; + std::vector<TaskSpaceDMPControllerPtr > rightGroup; + + 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; + + + // NJointBimanualCCDMPControllerInterface interface + }; + +} // namespace armarx + diff --git a/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointCCDMPController.cpp b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointCCDMPController.cpp index c00253ed7a2524d5e6d8a591754f458ef2649168..7ec63cc2a13d7b3e23160096c9e7f700fc9c5c2e 100644 --- a/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointCCDMPController.cpp +++ b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointCCDMPController.cpp @@ -17,7 +17,7 @@ namespace armarx for (size_t i = 0; i < rns->getSize(); ++i) { std::string jointName = rns->getNode(i)->getName(); - ControlTargetBase* ct = prov->getControlTarget(jointName, ControlModes::Velocity1DoF); + ControlTargetBase* ct = prov->getControlTarget(jointName, ControlModes::VelocityTorque); const SensorValueBase* sv = prov->getSensorValue(jointName); targets.push_back(ct->asA<ControlTarget1DoFActuatorVelocity>()); @@ -45,6 +45,7 @@ namespace armarx torquePIDs.resize(tcpController->rns->getSize(), pidController()); + ik.reset(new VirtualRobot::DifferentialIK(rns, rns->getRobot()->getRootNode(), VirtualRobot::JacobiProvider::eSVDDamped)); // set DMP isDisturbance = false; @@ -55,7 +56,7 @@ namespace armarx dmpTypes = cfg->dmpTypes; for (size_t i = 0; i < dmpPtrList.size(); ++i) { - dmpPtrList[i].reset(new UMIDMP(cfg->kernelSize, cfg->DMPKd, cfg->baseMode, cfg->tau)); + dmpPtrList[i].reset(new UMITSMP(cfg->kernelSize, 2, cfg->tau)); canVals[i] = timeDurations[i]; } finished = false; @@ -72,12 +73,14 @@ namespace armarx // initialize tcp position and orientation Eigen::Matrix4f pose = tcp->getPoseInRootFrame(); - oldPose = pose; tcpPosition(0) = pose(0, 3); tcpPosition(1) = pose(1, 3); tcpPosition(2) = pose(2, 3); - tcpOrientation = VirtualRobot::MathTools::eigen4f2rpy(pose); - + VirtualRobot::MathTools::Quaternion tcpQ = VirtualRobot::MathTools::eigen4f2quat(pose); + tcpOrientation.w() = tcpQ.w; + tcpOrientation.x() = tcpQ.x; + tcpOrientation.y() = tcpQ.y; + tcpOrientation.z() = tcpQ.z; NJointCCDMPControllerSensorData initSensorData; initSensorData.deltaT = 0; @@ -88,15 +91,13 @@ namespace armarx currentStates.resize(cfg->dmpNum); targetSubStates.resize(cfg->dmpNum); - targetState.resize(6); + targetState.resize(7); targetVels.resize(6); + targetVels.setZero(); NJointCCDMPControllerControlData initData; initData.targetTSVel.resize(6); - for (size_t i = 0; i < 6; ++i) - { - initData.targetTSVel[i] = 0; - } + initData.targetTSVel.setZero(); initData.nullspaceJointVelocities.resize(tcpController->rns->getSize(), 0); initData.torqueKp.resize(tcpController->rns->getSize(), 0); initData.torqueKd.resize(tcpController->rns->getSize(), 0); @@ -125,21 +126,32 @@ namespace armarx Eigen::Matrix4f currentPose = controllerSensorData.getReadBuffer().currentPose; Eigen::Vector3f currentPosition; currentPosition << currentPose(0, 3), currentPose(1, 3), currentPose(2, 3); - Eigen::Vector3f currentRPY = VirtualRobot::MathTools::eigen4f2rpy(currentPose); - double posError = 0; - double oriError = 0; for (size_t i = 0; i < 3; ++i) { posError += pow(currentPosition(i) - targetState[i], 2); } - for (size_t i = 0; i < 3; ++i) + posError = sqrt(posError); + + + VirtualRobot::MathTools::Quaternion cQuat = VirtualRobot::MathTools::eigen4f2quat(currentPose); + Eigen::Quaterniond currentQ; + Eigen::Quaterniond targetQ; + currentQ.w() = cQuat.w; + currentQ.x() = cQuat.x; + currentQ.y() = cQuat.y; + currentQ.z() = cQuat.z; + targetQ.w() = targetState[3]; + targetQ.x() = targetState[4]; + targetQ.y() = targetState[5]; + targetQ.z() = targetState[6]; + + double oriError = targetQ.angularDistance(currentQ); + if (oriError > M_PI) { - oriError += pow(currentRPY(i) - targetState[i + 3], 2); + oriError = 2 * M_PI - oriError; } - posError = sqrt(posError); - oriError = sqrt(oriError); double error = posError + posToOriRatio * oriError; double phaseDist; @@ -168,8 +180,11 @@ namespace armarx // run DMP one after another Eigen::Matrix4f targetPose = Eigen::Matrix4f::Identity(); - bool finished = true; - for (size_t i = 0; i < cfg->dmpNum; ++i) + + Eigen::VectorXf dmpVels; + dmpVels.resize(6); + dmpVels.setZero(); + for (int i = 0; i < cfg->dmpNum; ++i) { double timeDuration = timeDurations[i]; std::string dmpType = dmpTypes[i]; @@ -186,7 +201,7 @@ namespace armarx if (canVals[i] > 1e-8) { - DMP::UMIDMPPtr dmpPtr = dmpPtrList[i]; + DMP::UMITSMPPtr dmpPtr = dmpPtrList[i]; double dmpDeltaT = deltaT / timeDuration; double tau = dmpPtr->getTemporalFactor(); canVals[i] -= 1 / tau * deltaT * 1 / (1 + phaseStop) ; @@ -196,70 +211,101 @@ namespace armarx (currentStates[i], canVals[i] / timeDurations[i], dmpDeltaT, targetSubStates[i]); + + for (size_t j = 0; j < 3; ++j) + { + dmpVels(j) += currentStates[i][j].vel / timeDurations[i]; + } + + Eigen::Quaterniond quatVel0; + quatVel0.w() = currentStates[i][3].vel; + quatVel0.x() = currentStates[i][4].vel; + quatVel0.y() = currentStates[i][5].vel; + quatVel0.z() = currentStates[i][6].vel; + Eigen::Quaterniond dmpQ; + dmpQ.w() = currentStates[i][3].pos; + dmpQ.x() = currentStates[i][4].pos; + dmpQ.y() = currentStates[i][5].pos; + dmpQ.z() = currentStates[i][6].pos; + Eigen::Quaterniond angularVel0 = 2 * quatVel0 * dmpQ.inverse(); + + + Eigen::Vector3f angularVelVec; + angularVelVec << angularVel0.x() / timeDurations[i], + angularVel0.y() / timeDurations[i], + angularVel0.z() / timeDurations[i]; + + angularVelVec = targetPose.block<3, 3>(0, 0) * angularVelVec; + + ARMARX_INFO << "i: " << i << " angularVelVec: " << angularVelVec; + dmpVels(3) += angularVelVec(0); + dmpVels(4) += angularVelVec(1); + dmpVels(5) += angularVelVec(2); + finished = false; } - Eigen::Matrix4f targetSubMat = VirtualRobot::MathTools::rpy2eigen4f(targetSubStates[i][3], targetSubStates[i][4], targetSubStates[i][5]); + + Eigen::Matrix4f targetSubMat = VirtualRobot::MathTools::quat2eigen4f(targetSubStates[i][4], targetSubStates[i][5], targetSubStates[i][6], targetSubStates[i][3]); targetSubMat(0, 3) = targetSubStates[i][0]; targetSubMat(1, 3) = targetSubStates[i][1]; targetSubMat(2, 3) = targetSubStates[i][2]; - ARMARX_INFO << "targetSubMat: " << targetSubMat; - targetPose = targetPose * targetSubMat; } - ARMARX_INFO << "targetPose: " << targetPose; - - Eigen::Vector3f targetRPY = VirtualRobot::MathTools::eigen4f2rpy(targetPose); - targetState[0] = targetPose(0, 3); - targetState[1] = targetPose(1, 3); - targetState[2] = targetPose(2, 3); - targetState[3] = targetRPY(0); - targetState[4] = targetRPY(1); - targetState[5] = targetRPY(2); - - Eigen::Vector3f oldRPY = VirtualRobot::MathTools::eigen4f2rpy(oldPose); - - + // ARMARX_INFO << "targetPose: " << targetPose; for (size_t i = 0; i < 3; i++) { - double vel0 = (targetState[i] - oldPose(i, 3)) / deltaT; + double vel0 = dmpVels(i); double vel1 = phaseKpPos * (targetState[i] - currentPose(i, 3)); - targetVels[i] = mpcFactor * vel0 + (1 - mpcFactor) * vel1; + targetVels(i) = mpcFactor * vel0 + (1 - mpcFactor) * vel1; } - for (size_t i = 0; i < 3; i++) - { - double vel0 = (targetState[i + 3] - oldRPY(i)) / deltaT; - double vel1 = phaseKpOri * (targetState[i + 3] - currentRPY(i)); - targetVels[i + 3] = mpcFactor * vel0 + (1 - mpcFactor) * vel1; - } - oldPose = targetPose; + Eigen::Quaterniond diffQ = targetQ * currentQ.inverse(); + Eigen::Quaterniond quatVel1 = phaseKpOri * diffQ; + Eigen::Quaterniond angularVel1 = 2 * quatVel1 * currentQ.inverse(); + targetVels(3) = mpcFactor * dmpVels(3) + (1 - mpcFactor) * angularVel1.x(); + targetVels(4) = mpcFactor * dmpVels(4) + (1 - mpcFactor) * angularVel1.y(); + targetVels(5) = mpcFactor * dmpVels(5) + (1 - mpcFactor) * angularVel1.z(); - 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]; + + + VirtualRobot::MathTools::Quaternion tQuat = VirtualRobot::MathTools::eigen4f2quat(targetPose); + targetState[0] = targetPose(0, 3); + targetState[1] = targetPose(1, 3); + targetState[2] = targetPose(2, 3); + targetState[3] = tQuat.w; + targetState[4] = tQuat.x; + targetState[5] = tQuat.y; + targetState[6] = tQuat.z; + + + debugOutputData.getWriteBuffer().latestTargetVelocities["x_vel"] = targetVels(0); + debugOutputData.getWriteBuffer().latestTargetVelocities["y_vel"] = targetVels(1); + debugOutputData.getWriteBuffer().latestTargetVelocities["z_vel"] = targetVels(2); + debugOutputData.getWriteBuffer().latestTargetVelocities["roll_vel"] = targetVels(3); + debugOutputData.getWriteBuffer().latestTargetVelocities["pitch_vel"] = targetVels(4); + debugOutputData.getWriteBuffer().latestTargetVelocities["yaw_vel"] = targetVels(5); debugOutputData.getWriteBuffer().dmpTargets["dmp_x"] = targetState[0]; debugOutputData.getWriteBuffer().dmpTargets["dmp_y"] = targetState[1]; debugOutputData.getWriteBuffer().dmpTargets["dmp_z"] = targetState[2]; - debugOutputData.getWriteBuffer().dmpTargets["dmp_roll"] = targetState[3]; - debugOutputData.getWriteBuffer().dmpTargets["dmp_pitch"] = targetState[4]; - debugOutputData.getWriteBuffer().dmpTargets["dmp_yaw"] = targetState[5]; + debugOutputData.getWriteBuffer().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().realTCP["real_x"] = currentPosition[0]; debugOutputData.getWriteBuffer().realTCP["real_y"] = currentPosition[1]; debugOutputData.getWriteBuffer().realTCP["real_z"] = currentPosition[2]; - debugOutputData.getWriteBuffer().realTCP["real_roll"] = currentRPY[0]; - debugOutputData.getWriteBuffer().realTCP["real_pitch"] = currentRPY[1]; - debugOutputData.getWriteBuffer().realTCP["real_yaw"] = currentRPY[2]; + debugOutputData.getWriteBuffer().realTCP["real_qw"] = cQuat.w; + debugOutputData.getWriteBuffer().realTCP["real_qx"] = cQuat.x; + debugOutputData.getWriteBuffer().realTCP["real_qy"] = cQuat.y; + debugOutputData.getWriteBuffer().realTCP["real_qz"] = cQuat.z; debugOutputData.getWriteBuffer().mpcFactor = mpcFactor; debugOutputData.getWriteBuffer().error = error; @@ -285,68 +331,19 @@ namespace armarx controllerSensorData.getWriteBuffer().currentPose = tcp->getPoseInRootFrame(); controllerSensorData.getWriteBuffer().deltaT = deltaT; controllerSensorData.getWriteBuffer().currentTime += deltaT; - controllerSensorData.commitWrite(); // cartesian vel controller - Eigen::VectorXf x; - auto mode = rtGetControlStruct().mode; - if (mode == VirtualRobot::IKSolver::All) - { - x.resize(6); - for (size_t i = 0; i < 6; i++) - { - x(i) = rtGetControlStruct().targetTSVel[i]; - } - } - else if (mode == VirtualRobot::IKSolver::Position) - { - x.resize(3); - for (size_t i = 0; i < 3; i++) - { - x(i) = rtGetControlStruct().targetTSVel[i]; - } + Eigen::MatrixXf jacobi = ik->getJacobianMatrix(tcp, VirtualRobot::IKSolver::CartesianSelection::All); - } - else if (mode == VirtualRobot::IKSolver::Orientation) - { - x.resize(3); - for (size_t i = 0; i < 3; i++) - { - x(i) = rtGetControlStruct().targetTSVel[i + 3]; - } - } - else - { - // No mode has been set - return; - } - Eigen::VectorXf jnv = Eigen::VectorXf::Zero(tcpController->rns->getSize()); - float jointLimitAvoidanceKp = rtGetControlStruct().avoidJointLimitsKp; - if (jointLimitAvoidanceKp > 0) - { - jnv += jointLimitAvoidanceKp * tcpController->calculateJointLimitAvoidance(); - } - for (size_t i = 0; i < tcpController->rns->getSize(); i++) - { - jnv(i) += rtGetControlStruct().nullspaceJointVelocities.at(i); - if (torqueSensors.at(i) && gravityTorqueSensors.at(i) && rtGetControlStruct().torqueKp.at(i) != 0) - { - torquePIDs.at(i).Kp = rtGetControlStruct().torqueKp.at(i); - torquePIDs.at(i).Kd = rtGetControlStruct().torqueKd.at(i); - jnv(i) += torquePIDs.at(i).update(deltaT, torqueSensors.at(i)->torque - gravityTorqueSensors.at(i)->gravityTorque); - } - else - { - torquePIDs.at(i).lastError = 0; - } - } + Eigen::MatrixXf jtpinv = ik->computePseudoInverseJacobianMatrix(jacobi, ik->getJacobiRegularization(VirtualRobot::IKSolver::CartesianSelection::All)); + + Eigen::VectorXf jnv = jtpinv * rtGetControlStruct().targetTSVel; - Eigen::VectorXf jointTargetVelocities = tcpController->calculate(x, jnv, mode); for (size_t i = 0; i < targets.size(); ++i) { - targets.at(i)->velocity = jointTargetVelocities(i); + targets.at(i)->velocity = jnv(i); } } @@ -391,7 +388,6 @@ namespace armarx } dmpPtrList[dmpId]->learnFromTrajectories(trajs); - dmpPtrList[dmpId]->setOneStepMPC(true); dmpPtrList[dmpId]->styleParas = dmpPtrList[dmpId]->getStyleParasWithRatio(ratios); @@ -405,28 +401,38 @@ namespace armarx currentPos.vel = 0; currentState.push_back(currentPos); } - for (size_t i = 0; i < 3; i++) - { - DMP::DMPState currentPos; - currentPos.pos = tcpOrientation(i); - currentPos.vel = 0; - currentState.push_back(currentPos); - } + + DMP::DMPState currentPos; + currentPos.pos = tcpOrientation.w(); + currentPos.vel = 0; + currentState.push_back(currentPos); + + currentPos.pos = tcpOrientation.x(); + currentPos.vel = 0; + currentState.push_back(currentPos); + + currentPos.pos = tcpOrientation.y(); + currentPos.vel = 0; + currentState.push_back(currentPos); + + currentPos.pos = tcpOrientation.z(); + currentPos.vel = 0; + currentState.push_back(currentPos); + } else { currentState = starts; - - } for (size_t i = 0; i < 3; i++) { targetState[i] = tcpPosition(i); } - for (size_t i = 0; i < 3; i++) - { - targetState[i + 3] = tcpOrientation(i); - } + + targetState[3] = tcpOrientation.w(); + targetState[4] = tcpOrientation.x(); + targetState[5] = tcpOrientation.y(); + targetState[6] = tcpOrientation.z(); currentStates[dmpId] = currentState; @@ -439,10 +445,9 @@ namespace armarx void NJointCCDMPController::setViaPoints(int dmpId, Ice::Double u, const Ice::DoubleSeq& viapoint, const Ice::Current&) { - ViaPoint viaPoint(u, viapoint); LockGuardType guard(controllerMutex); - dmpPtrList[dmpId]->setViaPoint(viaPoint); + dmpPtrList[dmpId]->setViaPoint(u, viapoint); } void NJointCCDMPController::setGoals(int dmpId, const Ice::DoubleSeq& goals, const Ice::Current& ice) diff --git a/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointCCDMPController.h b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointCCDMPController.h index 7dc42afd1e8c99b9a5d269727cec270753abfc5c..e318e8f68dcd518711614dd759cdf6cf575d42c0 100644 --- a/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointCCDMPController.h +++ b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointCCDMPController.h @@ -7,9 +7,11 @@ #include <RobotAPI/components/units/RobotUnit/ControlTargets/ControlTarget1DoFActuator.h> #include <RobotAPI/components/units/RobotUnit/SensorValues/SensorValue1DoFActuator.h> #include <VirtualRobot/IK/DifferentialIK.h> -#include <dmp/representation/dmp/umidmp.h> +#include <dmp/representation/dmp/umitsmp.h> #include <RobotAPI/interface/units/RobotUnit/NJointTaskSpaceDMPController.h> #include <RobotAPI/libraries/core/CartesianVelocityController.h> +#include <RobotAPI/libraries/DMPController/TaskSpaceDMPController.h> + using namespace DMP; @@ -25,7 +27,7 @@ namespace armarx class NJointCCDMPControllerControlData { public: - std::vector<float> targetTSVel; + Eigen::VectorXf targetTSVel; // cartesian velocity control data std::vector<float> nullspaceJointVelocities; float avoidJointLimitsKp = 0; @@ -124,7 +126,7 @@ namespace armarx std::string nodeSetName; // dmp parameters - std::vector<UMIDMPPtr > dmpPtrList; + std::vector<UMITSMPPtr > dmpPtrList; std::vector<double> canVals; std::vector<double> timeDurations; std::vector<std::string > dmpTypes; @@ -149,15 +151,21 @@ namespace armarx double posToOriRatio; - std::vector<float> targetVels; + Eigen::VectorXf targetVels; std::vector<int> learnedDMP; + + + + + NJointCCDMPControllerConfigPtr cfg; VirtualRobot::RobotNodePtr tcp; Eigen::Vector3f tcpPosition; - Eigen::Vector3f tcpOrientation; + Eigen::Quaterniond tcpOrientation; Eigen::Matrix4f oldPose; + VirtualRobot::DifferentialIKPtr ik; DMP::DVec targetState; mutable MutexType controllerMutex; diff --git a/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointJSDMPController.cpp b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointJSDMPController.cpp index 4a7652fe06db8b61ea3cb2a1d86d2857313f1407..b91195290ce04ac6f12ac1ce0abcfcd032009ad5 100644 --- a/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointJSDMPController.cpp +++ b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointJSDMPController.cpp @@ -19,7 +19,7 @@ namespace armarx for (std::string jointName : cfg->jointNames) { - ControlTargetBase* ct = prov->getControlTarget(jointName, ControlModes::Velocity1DoF); + ControlTargetBase* ct = prov->getControlTarget(jointName, ControlModes::VelocityTorque); const SensorValueBase* sv = prov->getSensorValue(jointName); targets.insert(std::make_pair(jointName, ct->asA<ControlTarget1DoFActuatorVelocity>())); positionSensors.insert(std::make_pair(jointName, sv->asA<SensorValue1DoFActuatorPosition>())); diff --git a/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointTSDMPController.cpp b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointTSDMPController.cpp index f14bf42830f9d87f2b58b7591962e2047ed47bc2..5de57d1714c208a1498a3fd7f8167c583a0b2246 100644 --- a/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointTSDMPController.cpp +++ b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointTSDMPController.cpp @@ -51,40 +51,42 @@ namespace armarx ik.reset(new VirtualRobot::DifferentialIK(rns, rns->getRobot()->getRootNode(), VirtualRobot::JacobiProvider::eSVDDamped)); - // set DMP - isDisturbance = false; - - dmpPtr.reset(new DMP::UMITSMP(cfg->kernelSize, cfg->baseMode, cfg->tau)); - timeDuration = cfg->timeDuration; - canVal = timeDuration; finished = false; - - phaseL = cfg->phaseL; - phaseK = cfg->phaseK; - phaseDist0 = cfg->phaseDist0; - phaseDist1 = cfg->phaseDist1; - phaseKpPos = cfg->phaseKpPos; - phaseKpOri = cfg->phaseKpOri; - - posToOriRatio = cfg->posToOriRatio; + TaskSpaceDMPControllerConfig taskSpaceDMPConfig; + taskSpaceDMPConfig.motionTimeDuration = cfg->timeDuration; + taskSpaceDMPConfig.DMPKernelSize = cfg->kernelSize; + taskSpaceDMPConfig.DMPMode = cfg->dmpMode; + taskSpaceDMPConfig.DMPStyle = cfg->dmpStyle; + taskSpaceDMPConfig.DMPAmplitude = cfg->dmpAmplitude; + 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; + + taskSpaceDMPController.reset(new TaskSpaceDMPController("default", taskSpaceDMPConfig)); // initialize tcp position and orientation - NJointTSDMPControllerSensorData initSensorData; initSensorData.deltaT = 0; initSensorData.currentTime = 0; - initSensorData.currentState.resize(7); + initSensorData.currentPose.setZero(); + initSensorData.currentTwist.setZero(); controllerSensorData.reinitAllBuffers(initSensorData); - targetVels.resize(6); NJointTSDMPControllerControlData initData; initData.targetTSVel.resize(6); for (size_t i = 0; i < 6; ++i) { - initData.targetTSVel[i] = 0; + initData.targetTSVel(i) = 0; + targetVels(i) = 0; } initData.nullspaceJointVelocities.resize(tcpController->rns->getSize(), 0); initData.torqueKp.resize(tcpController->rns->getSize(), 0); @@ -92,6 +94,7 @@ namespace armarx initData.mode = ModeFromIce(cfg->mode); reinitTripleBuffer(initData); + } std::string NJointTSDMPController::getClassName(const Ice::Current&) const @@ -101,117 +104,21 @@ namespace armarx void NJointTSDMPController::controllerRun() { - if (!controllerSensorData.updateReadBuffer()) + if (!controllerSensorData.updateReadBuffer() || !taskSpaceDMPController) { return; } double deltaT = controllerSensorData.getReadBuffer().deltaT; - currentState = controllerSensorData.getReadBuffer().currentState; - - double mpcFactor = 1; - double error = 0; - double phaseStop = 0; - double posError = 0; - double angularError = 0; - - - if (canVal > 1e-8) - { - std::vector<double> currentposi; - currentposi.resize(3); - for (size_t i = 0; i < 3; ++i) - { - currentposi[i] = currentState[i].pos; - posError += pow(currentState[i].pos - targetState[i], 2); - } - posError = sqrt(posError); - - // calculate quaternion error - Eigen::Quaterniond currentQ; - Eigen::Quaterniond targetQ; - currentQ.w() = currentState[3].pos; - currentQ.x() = currentState[4].pos; - currentQ.y() = currentState[5].pos; - currentQ.z() = currentState[6].pos; - targetQ.w() = targetState[3]; - targetQ.x() = targetState[4]; - targetQ.y() = targetState[5]; - targetQ.z() = targetState[6]; - angularError = targetQ.angularDistance(currentQ); - if (angularError > M_PI) - { - angularError = 2 * M_PI - angularError; - } - - error = posError + posToOriRatio * angularError; - double dmpDeltaT = deltaT / timeDuration; + Eigen::Matrix4f currentPose = controllerSensorData.getReadBuffer().currentPose; + Eigen::VectorXf currentTwist = controllerSensorData.getReadBuffer().currentTwist; - double phaseDist; - if (isDisturbance) - { - phaseDist = phaseDist1; - } - else - { - phaseDist = phaseDist0; - } + taskSpaceDMPController->flow(deltaT, currentPose, currentTwist); + targetVels = taskSpaceDMPController->getTargetVelocity(); - phaseStop = phaseL / (1 + exp(-phaseK * (error - phaseDist))); - mpcFactor = 1 - (phaseStop / phaseL); - if (mpcFactor < 0.1) - { - isDisturbance = true; - } + std::vector<double> targetState = taskSpaceDMPController->getTargetPose(); - if (mpcFactor > 0.9) - { - isDisturbance = false; - } - - double tau = dmpPtr->getTemporalFactor(); - canVal -= 1 / tau * deltaT * 1 / (1 + phaseStop) ; - currentState = dmpPtr->calculateDirectlyVelocity(currentState, canVal / timeDuration, dmpDeltaT, targetState); - - - - float vel0, vel1; - - for (size_t i = 0; i < 3; i++) - { - vel0 = currentState[i].vel / timeDuration; - vel1 = phaseKpPos * (targetState[i] - currentposi[i]); - targetVels[i] = mpcFactor * vel0 + (1 - mpcFactor) * vel1; - } - - Eigen::Quaterniond quatVel0; - quatVel0.w() = currentState[3].vel; - quatVel0.x() = currentState[4].vel; - quatVel0.y() = currentState[5].vel; - quatVel0.z() = currentState[6].vel; - Eigen::Quaterniond angularVel0 = 2 * quatVel0 * currentQ.inverse(); - - Eigen::Quaterniond diffQ = targetQ * currentQ.inverse(); - Eigen::Quaterniond quatVel1 = phaseKpOri * diffQ; - Eigen::Quaterniond angularVel1 = 2 * quatVel1 * currentQ.inverse(); - - ARMARX_INFO << "angular vel: " << angularVel0.x() << " " << angularVel0.y() << " " << angularVel0.z(); - - targetVels[3] = mpcFactor * angularVel0.x() / timeDuration + (1 - mpcFactor) * angularVel1.x(); - targetVels[4] = mpcFactor * angularVel0.y() / timeDuration + (1 - mpcFactor) * angularVel1.y(); - targetVels[5] = mpcFactor * angularVel0.z() / timeDuration + (1 - mpcFactor) * angularVel1.z(); - - } - else - { - finished = true; - - for (size_t i = 0; i < targetVels.size(); ++i) - { - targetVels[i] = 0; - } - } debugOutputData.getWriteBuffer().latestTargetVelocities["x_vel"] = targetVels[0]; debugOutputData.getWriteBuffer().latestTargetVelocities["y_vel"] = targetVels[1]; debugOutputData.getWriteBuffer().latestTargetVelocities["z_vel"] = targetVels[2]; @@ -225,28 +132,22 @@ namespace armarx debugOutputData.getWriteBuffer().dmpTargets["dmp_qx"] = targetState[4]; debugOutputData.getWriteBuffer().dmpTargets["dmp_qy"] = targetState[5]; debugOutputData.getWriteBuffer().dmpTargets["dmp_qz"] = targetState[6]; - - - // ARMARX_INFO << "targetVels: " << targetVels[0] << " " << - // targetVels[1] << " " << - // targetVels[2] << " " << - // targetVels[3] << " " << - // targetVels[4] << " " << - // targetVels[5]; - - - debugOutputData.getWriteBuffer().currentCanVal = canVal; - debugOutputData.getWriteBuffer().mpcFactor = mpcFactor; - debugOutputData.getWriteBuffer().error = error; - debugOutputData.getWriteBuffer().phaseStop = phaseStop; - debugOutputData.getWriteBuffer().posError = posError; - debugOutputData.getWriteBuffer().oriError = angularError; - debugOutputData.getWriteBuffer().deltaT = deltaT; - - + 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.commitWrite(); - // LockGuardType guard {controlDataMutex}; getWriterControlStruct().targetTSVel = targetVels; writeControlStruct(); } @@ -255,59 +156,39 @@ namespace armarx void NJointTSDMPController::rtRun(const IceUtil::Time& sensorValuesTimestamp, const IceUtil::Time& timeSinceLastIteration) { Eigen::Matrix4f pose = tcp->getPoseInRootFrame(); - Eigen::Vector3f currPosition; - currPosition << pose(0, 3), pose(1, 3), pose(2, 3); - VirtualRobot::MathTools::Quaternion currOrientation = VirtualRobot::MathTools::eigen4f2quat(pose); - tcpPosition = currPosition; - tcpOrientation.w() = currOrientation.w; - tcpOrientation.x() = currOrientation.x; - tcpOrientation.y() = currOrientation.y; - tcpOrientation.z() = currOrientation.z; - - double deltaT = timeSinceLastIteration.toSecondsDouble(); Eigen::MatrixXf jacobi = ik->getJacobianMatrix(tcp, VirtualRobot::IKSolver::CartesianSelection::All); - Eigen::VectorXf qpos; Eigen::VectorXf qvel; - qpos.resize(positionSensors.size()); qvel.resize(velocitySensors.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; + controllerSensorData.getWriteBuffer().currentPose = pose; + controllerSensorData.getWriteBuffer().currentTwist = tcptwist; + controllerSensorData.getWriteBuffer().deltaT = deltaT; + controllerSensorData.getWriteBuffer().currentTime += deltaT; + controllerSensorData.commitWrite(); + - for (size_t i = 0; i < 3; i++) + Eigen::VectorXf targetVel = rtGetControlStruct().targetTSVel; + + float normLinearVelocity = targetVel.block<3, 1>(0, 0).norm(); + if (normLinearVelocity > cfg->maxLinearVel) { - DMP::DMPState currentPos; - currentPos.pos = tcpPosition(i); - currentPos.vel = tcptwist(i) * timeDuration; - controllerSensorData.getWriteBuffer().currentState[i] = currentPos; + targetVel.block<3, 1>(0, 0) = cfg->maxLinearVel * targetVel.block<3, 1>(0, 0) / normLinearVelocity; } - Eigen::Quaterniond angularVel; - angularVel.w() = 0; - angularVel.x() = tcptwist(3); - angularVel.y() = tcptwist(4); - angularVel.z() = tcptwist(5); - - Eigen::Quaterniond quatVel = 0.5 * angularVel * tcpOrientation; - controllerSensorData.getWriteBuffer().currentState[3].pos = tcpOrientation.w(); - controllerSensorData.getWriteBuffer().currentState[3].vel = quatVel.w(); - controllerSensorData.getWriteBuffer().currentState[4].pos = tcpOrientation.x(); - controllerSensorData.getWriteBuffer().currentState[4].vel = quatVel.x(); - controllerSensorData.getWriteBuffer().currentState[5].pos = tcpOrientation.y(); - controllerSensorData.getWriteBuffer().currentState[5].vel = quatVel.y(); - controllerSensorData.getWriteBuffer().currentState[6].pos = tcpOrientation.z(); - controllerSensorData.getWriteBuffer().currentState[6].vel = quatVel.z(); - controllerSensorData.getWriteBuffer().deltaT = deltaT; - controllerSensorData.getWriteBuffer().currentTime += deltaT; - controllerSensorData.commitWrite(); + float normAngularVelocity = targetVel.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; + } // cartesian vel controller @@ -319,7 +200,7 @@ namespace armarx x.resize(6); for (size_t i = 0; i < 6; i++) { - x(i) = rtGetControlStruct().targetTSVel[i]; + x(i) = targetVel(i); } } else if (mode == VirtualRobot::IKSolver::Position) @@ -327,7 +208,7 @@ namespace armarx x.resize(3); for (size_t i = 0; i < 3; i++) { - x(i) = rtGetControlStruct().targetTSVel[i]; + x(i) = targetVel(i); } } @@ -336,7 +217,7 @@ namespace armarx x.resize(3); for (size_t i = 0; i < 3; i++) { - x(i) = rtGetControlStruct().targetTSVel[i + 3]; + x(i) = targetVel(i + 3); } } else @@ -376,43 +257,28 @@ namespace armarx void NJointTSDMPController::learnDMPFromFiles(const Ice::StringSeq& fileNames, const Ice::Current&) { - DMP::Vec<DMP::SampledTrajectoryV2 > trajs; - - DMP::DVec ratios; - for (size_t i = 0; i < fileNames.size(); ++i) - { - DMP::SampledTrajectoryV2 traj; - traj.readFromCSVFile(fileNames.at(i)); - traj = DMP::SampledTrajectoryV2::normalizeTimestamps(traj, 0, 1); - trajs.push_back(traj); - - if (i == 0) - { - ratios.push_back(1.0); - } - else - { - ratios.push_back(0.0); - } - } - - dmpPtr->learnFromTrajectories(trajs); - dmpPtr->styleParas = dmpPtr->getStyleParasWithRatio(ratios); + taskSpaceDMPController->learnDMPFromFiles(fileNames); ARMARX_INFO << "Learned DMP ... "; } - void NJointTSDMPController::setViaPoints(Ice::Double u, const Ice::DoubleSeq& viapoint, const Ice::Current&) + void NJointTSDMPController::setSpeed(Ice::Double times, const Ice::Current&) { - ViaPoint viaPoint(u, viapoint); + LockGuardType guard(controllerMutex); + taskSpaceDMPController->setSpeed(times); + } + void NJointTSDMPController::setViaPoints(Ice::Double u, const Ice::DoubleSeq& viapoint, const Ice::Current&) + { LockGuardType guard(controllerMutex); - dmpPtr->setViaPoint(viaPoint); + ARMARX_INFO << "setting via points "; + taskSpaceDMPController->setViaPose(u, viapoint); } + void NJointTSDMPController::setGoals(const Ice::DoubleSeq& goals, const Ice::Current& ice) { - setViaPoints(dmpPtr->getUMin(), goals, ice); + taskSpaceDMPController->setGoalPoseVec(goals); } void NJointTSDMPController::setControllerTarget(Ice::Float avoidJointLimitsKp, NJointTaskSpaceDMPControllerMode::CartesianSelection mode, const Ice::Current&) @@ -465,66 +331,14 @@ namespace armarx void NJointTSDMPController::runDMP(const Ice::DoubleSeq& goals, double tau, const Ice::Current&) { Eigen::Matrix4f pose = tcp->getPoseInRootFrame(); - tcpPosition(0) = pose(0, 3); - tcpPosition(1) = pose(1, 3); - tcpPosition(2) = pose(2, 3); - VirtualRobot::MathTools::Quaternion currentQ = VirtualRobot::MathTools::eigen4f2quat(pose); - - tcpOrientation.w() = currentQ.w; - tcpOrientation.x() = currentQ.x; - tcpOrientation.y() = currentQ.y; - tcpOrientation.z() = currentQ.z; - - ARMARX_INFO << "tcpPosition: " << tcpPosition; - ARMARX_INFO << "tcpOrientation: " << tcpOrientation.w() << " " << tcpOrientation.x() << " " << tcpOrientation.y() << " " << tcpOrientation.z(); - - currentState.clear(); - targetState.clear(); - for (size_t i = 0; i < 3; i++) - { - DMP::DMPState currentPos; - currentPos.pos = tcpPosition(i); - currentPos.vel = 0; - currentState.push_back(currentPos); - targetState.push_back(currentPos.pos); - } - - DMP::DMPState currentPos; - currentPos.pos = tcpOrientation.w(); - currentPos.vel = 0; - currentState.push_back(currentPos); - targetState.push_back(currentPos.pos); - - currentPos.pos = tcpOrientation.x(); - currentPos.vel = 0; - currentState.push_back(currentPos); - targetState.push_back(currentPos.pos); - - currentPos.pos = tcpOrientation.y(); - currentPos.vel = 0; - currentState.push_back(currentPos); - targetState.push_back(currentPos.pos); - - currentPos.pos = tcpOrientation.z(); - currentPos.vel = 0; - currentState.push_back(currentPos); - targetState.push_back(currentPos.pos); - - - dmpPtr->prepareExecution(goals, currentState, 1, tau); + taskSpaceDMPController->prepareExecution(taskSpaceDMPController->eigen4f2vec(pose), goals); finished = false; - dmpPtr->setTemporalFactor(tau); ARMARX_INFO << "run DMP"; controllerTask->start(); } - void NJointTSDMPController::setTemporalFactor(double tau, const Ice::Current&) - { - LockGuardType guard(controllerMutex); - dmpPtr->setTemporalFactor(tau); - } void NJointTSDMPController::rtPreActivateController() { @@ -550,6 +364,12 @@ namespace armarx 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); diff --git a/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointTSDMPController.h b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointTSDMPController.h index 4479ca64e4c3afa837d703c6fa61c2221f9b6fc6..dbbdb6698058364d79ec25bbc4739ca296dabd6e 100644 --- a/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointTSDMPController.h +++ b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointTSDMPController.h @@ -11,6 +11,7 @@ #include <RobotAPI/interface/units/RobotUnit/NJointTaskSpaceDMPController.h> #include <RobotAPI/libraries/core/CartesianVelocityController.h> +#include <RobotAPI/libraries/DMPController/TaskSpaceDMPController.h> using namespace DMP; namespace armarx @@ -25,7 +26,7 @@ namespace armarx class NJointTSDMPControllerControlData { public: - std::vector<float> targetTSVel; + Eigen::VectorXf targetTSVel; // cartesian velocity control data std::vector<float> nullspaceJointVelocities; float avoidJointLimitsKp = 0; @@ -71,13 +72,20 @@ namespace armarx } void runDMP(const Ice::DoubleSeq& goals, Ice::Double tau, const Ice::Current&); - void setTemporalFactor(Ice::Double tau, const Ice::Current&); + void setSpeed(Ice::Double times, const Ice::Current&); void setViaPoints(Ice::Double u, const Ice::DoubleSeq& viapoint, const Ice::Current&); + void setGoals(const Ice::DoubleSeq& goals, const Ice::Current&); void setControllerTarget(Ice::Float avoidJointLimitsKp, NJointTaskSpaceDMPControllerMode::CartesianSelection mode, const Ice::Current&); void setTorqueKp(const StringFloatDictionary& torqueKp, const Ice::Current&); void setNullspaceJointVelocities(const StringFloatDictionary& nullspaceJointVelocities, const Ice::Current&); + + double getCanVal(const Ice::Current &) + { + return taskSpaceDMPController->canVal; + } + protected: void rtPreActivateController() override; void rtPostDeactivateController() override; @@ -93,6 +101,7 @@ namespace armarx { StringFloatDictionary latestTargetVelocities; StringFloatDictionary dmpTargets; + StringFloatDictionary currentPose; double currentCanVal; double mpcFactor; double error; @@ -108,7 +117,8 @@ namespace armarx { double currentTime; double deltaT; - DMP::Vec<DMP::DMPState> currentState; + Eigen::Matrix4f currentPose; + Eigen::VectorXf currentTwist; }; TripleBuffer<NJointTSDMPControllerSensorData> controllerSensorData; @@ -119,44 +129,27 @@ namespace armarx std::vector<const SensorValue1DoFActuatorVelocity*> velocitySensors; std::vector<const SensorValue1DoFActuatorPosition*> positionSensors; + + TaskSpaceDMPControllerPtr taskSpaceDMPController; + // velocity ik controller parameters std::vector<pidController> torquePIDs; CartesianVelocityControllerPtr tcpController; std::string nodeSetName; // dmp parameters - DMP::UMITSMPPtr dmpPtr; - double timeDuration; - double canVal; bool finished; - double tau; - ViaPointsSet viaPoints; - bool isDisturbance; - VirtualRobot::DifferentialIKPtr ik; VirtualRobot::RobotNodePtr tcp; - - // phaseStop parameters - double phaseL; - double phaseK; - double phaseDist0; - double phaseDist1; - double phaseKpPos; - double phaseKpOri; - - double posToOriRatio; - - bool startRun; - std::vector<float> targetVels; + Eigen::VectorXf targetVels; NJointTaskSpaceDMPControllerConfigPtr cfg; - Eigen::Vector3f tcpPosition; - Eigen::Quaterniond tcpOrientation; - DMP::Vec<DMP::DMPState> currentState; - DMP::DVec targetState; mutable MutexType controllerMutex; PeriodicTask<NJointTSDMPController>::pointer_type controllerTask; + + // NJointTaskSpaceDMPControllerInterface interface + }; } // namespace armarx diff --git a/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointTaskSpaceDMPController.cpp b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointTaskSpaceDMPController.cpp index f7a2de6fee95c7a188cd816158d88836c974e9c2..aba323812c91a3ae20b88e267db5c2ab0bd371e0 100644 --- a/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointTaskSpaceDMPController.cpp +++ b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointTaskSpaceDMPController.cpp @@ -337,6 +337,7 @@ namespace armarx writeControlStruct(); } + void NJointTaskSpaceDMPController::setGoals(const Ice::DoubleSeq& goals, const Ice::Current& ice) { setViaPoints(dmpPtr->getUMin(), goals, ice); diff --git a/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointTaskSpaceDMPController.h b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointTaskSpaceDMPController.h index b5f3fa66e39c20002747e7e02372e7f45c5aed86..796044be71f4be83d31dbc18f121a4b6babc77ae 100644 --- a/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointTaskSpaceDMPController.h +++ b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointTaskSpaceDMPController.h @@ -76,6 +76,7 @@ namespace armarx void runDMP(const Ice::DoubleSeq& goals, Ice::Double tau, const Ice::Current&); void setTemporalFactor(Ice::Double tau, const Ice::Current&); void setViaPoints(Ice::Double u, const Ice::DoubleSeq& viapoint, const Ice::Current&); + void setGoals(const Ice::DoubleSeq& goals, const Ice::Current&); void setControllerTarget(Ice::Float avoidJointLimitsKp, NJointTaskSpaceDMPControllerMode::CartesianSelection mode, const Ice::Current&);