From 117dbb67336567ea4f328eb825e1a7d914ce13e5 Mon Sep 17 00:00:00 2001 From: zhou <you.zhou@kit.edu> Date: Wed, 11 Apr 2018 18:34:30 +0200 Subject: [PATCH] added a new jointdmpctrl with tripple-buffered control thread --- .../NJointJointSpaceDMPController.ice | 1 + .../RobotAPINJointControllers/CMakeLists.txt | 2 + .../DMPController/NJointJSDMPController.cpp | 271 ++++++++++++++++++ .../DMPController/NJointJSDMPController.h | 127 ++++++++ .../NJointJointSpaceDMPController.cpp | 2 +- 5 files changed, 402 insertions(+), 1 deletion(-) create mode 100644 source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointJSDMPController.cpp create mode 100644 source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointJSDMPController.h diff --git a/source/RobotAPI/interface/units/RobotUnit/NJointJointSpaceDMPController.ice b/source/RobotAPI/interface/units/RobotUnit/NJointJointSpaceDMPController.ice index 276ecb113..947a7dbbe 100644 --- a/source/RobotAPI/interface/units/RobotUnit/NJointJointSpaceDMPController.ice +++ b/source/RobotAPI/interface/units/RobotUnit/NJointJointSpaceDMPController.ice @@ -54,5 +54,6 @@ module armarx void setTemporalFactor(double tau); void showMessages(); }; + }; #endif diff --git a/source/RobotAPI/libraries/RobotAPINJointControllers/CMakeLists.txt b/source/RobotAPI/libraries/RobotAPINJointControllers/CMakeLists.txt index da765662b..76755149a 100644 --- a/source/RobotAPI/libraries/RobotAPINJointControllers/CMakeLists.txt +++ b/source/RobotAPI/libraries/RobotAPINJointControllers/CMakeLists.txt @@ -39,11 +39,13 @@ if (DMP_FOUND) list(APPEND LIB_HEADERS DMPController/NJointJointSpaceDMPController.h DMPController/NJointTaskSpaceDMPController.h + DMPController/NJointJSDMPController.h ) list(APPEND LIB_FILES DMPController/NJointJointSpaceDMPController.cpp DMPController/NJointTaskSpaceDMPController.cpp + DMPController/NJointJSDMPController.cpp ) list(APPEND LIBS ${DMP_LIBRARIES}) diff --git a/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointJSDMPController.cpp b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointJSDMPController.cpp new file mode 100644 index 000000000..6837a99be --- /dev/null +++ b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointJSDMPController.cpp @@ -0,0 +1,271 @@ +#include "NJointJSDMPController.h" + + + +namespace armarx +{ + + NJointControllerRegistration<NJointJSDMPController> registrationControllerNJointJSDMPController("NJointJSDMPController"); + + std::string NJointJSDMPController::getClassName(const Ice::Current&) const + { + return "NJointJSDMPController"; + } + + NJointJSDMPController::NJointJSDMPController(armarx::NJointControllerDescriptionProviderInterfacePtr prov, const armarx::NJointControllerConfigPtr& config, const VirtualRobot::RobotPtr&) + { + NJointJointSpaceDMPControllerConfigPtr cfg = NJointJointSpaceDMPControllerConfigPtr::dynamicCast(config); + ARMARX_CHECK_EXPRESSION_W_HINT(cfg, "Needed type: NJointJointSpaceDMPControllerConfigPtr"); + + for (std::string jointName : cfg->jointNames) + { + ControlTargetBase* ct = prov->getControlTarget(jointName, ControlModes::Velocity1DoF); + const SensorValueBase* sv = prov->getSensorValue(jointName); + targets.insert(std::make_pair(jointName, ct->asA<ControlTarget1DoFActuatorVelocity>())); + positionSensors.insert(std::make_pair(jointName, sv->asA<SensorValue1DoFActuatorPosition>())); + torqueSensors.insert(std::make_pair(jointName, sv->asA<SensorValue1DoFActuatorTorque>())); + gravityTorqueSensors.insert(std::make_pair(jointName, sv->asA<SensorValue1DoFGravityTorque>())); + velocitySensors.insert(std::make_pair(jointName, sv->asA<SensorValue1DoFActuatorVelocity>())); + } + if (cfg->jointNames.size() == 0) + { + ARMARX_ERROR << "cfg->jointNames.size() == 0"; + } + + dmpPtr.reset(new DMP::UMIDMP(cfg->kernelSize, cfg->DMPKd, cfg->baseMode, cfg->tau)); + timeDuration = cfg->timeDuration; + phaseL = cfg->phaseL; + phaseK = cfg->phaseK; + phaseDist0 = cfg->phaseDist0; + phaseDist1 = cfg->phaseDist1; + phaseKp = cfg->phaseKp; + dimNames = cfg->jointNames; + + targetVels.resize(cfg->jointNames.size()); + NJointJSDMPControllerControlData initData; + initData.targetJointVels.resize(cfg->jointNames.size()); + for (size_t i = 0; i < cfg->jointNames.size(); ++i) + { + initData.targetJointVels[i] = 0; + } + + reinitTripleBuffer(initData); + + + NJointJSDMPControllerSensorData initSensorData; + initSensorData.deltaT = 0; + initSensorData.currentState.resize(cfg->jointNames.size()); + controllerSensorData.reinitAllBuffers(initSensorData); + + + deltaT = 0; + } + + void NJointJSDMPController::controllerRun() + { + if (canVal > 1e-8) + { + currentState = controllerSensorData.getUpToDateReadBuffer().currentState; + double deltaT = controllerSensorData.getUpToDateReadBuffer().deltaT; + double phaseStop = 0; + double error = 0; + std::vector<double> currentPosition; + currentPosition.resize(dimNames.size()); + + for (size_t i = 0; i < currentState.size(); i++) + { + DMP::DMPState currentPos = currentState[i]; + currentPosition[i] = currentPos.pos; + error += pow(currentPos.pos - targetState[i], 2); + } + + double phaseDist; + + if (isDisturbance) + { + phaseDist = phaseDist1; + } + else + { + phaseDist = phaseDist0; + } + + error = sqrt(error); + phaseStop = phaseL / (1 + exp(-phaseK * (error - phaseDist))); + double mpcFactor = 1 - (phaseStop / phaseL); + + if (mpcFactor < 0.1) + { + isDisturbance = true; + } + + if (mpcFactor > 0.9) + { + isDisturbance = false; + } + + canVal -= 1 / tau * deltaT * 1 / (1 + phaseStop); + double dmpDeltaT = deltaT / timeDuration; + dmpPtr->setTemporalFactor(tau); + + currentState = dmpPtr->calculateDirectlyVelocity(currentState, canVal / timeDuration, dmpDeltaT, targetState); + + for (size_t i = 0; i < currentState.size(); ++i) + { + double vel0 = currentState[i].vel / timeDuration; + double vel1 = phaseKp * (targetState[i] - currentPosition[i]); + double vel = mpcFactor * vel0 + (1 - mpcFactor) * vel1; + targetVels[i] = finished ? 0.0f : vel; + + debugOutputData.getWriteBuffer().latestTargetVelocities[dimNames[i]] = vel; + } + + debugOutputData.getWriteBuffer().currentCanVal = canVal; + debugOutputData.getWriteBuffer().mpcFactor = deltaT; + debugOutputData.commitWrite(); + + } + else + { + finished = true; + for (size_t i = 0; i < dimNames.size(); ++i) + { + targetVels[i] = 0; + } + } + + LockGuardType guard {controlDataMutex}; + getWriterControlStruct().targetJointVels = targetVels; + writeControlStruct(); + } + + void NJointJSDMPController::rtRun(const IceUtil::Time& sensorValuesTimestamp, const IceUtil::Time& timeSinceLastIteration) + { + for (size_t i = 0; i < dimNames.size(); i++) + { + const auto& jointName = dimNames.at(i); + DMP::DMPState currentPos; + currentPos.pos = (positionSensors.count(jointName) == 1) ? positionSensors[jointName]->position : 0.0f; + currentPos.vel = (velocitySensors.count(jointName) == 1) ? velocitySensors[jointName]->velocity : 0.0f; + currentPos.vel *= timeDuration; + controllerSensorData.getWriteBuffer().currentState[i] = currentPos; + } + controllerSensorData.getWriteBuffer().deltaT = timeSinceLastIteration.toSecondsDouble(); + controllerSensorData.commitWrite(); + + std::vector<double> targetJointVels = rtGetControlStruct().targetJointVels; + for (size_t i = 0; i < dimNames.size(); ++i) + { + targets[dimNames[i]]->velocity = targetJointVels[i]; + } + + + } + + void NJointJSDMPController::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->setOneStepMPC(true); + dmpPtr->styleParas = dmpPtr->getStyleParasWithRatio(ratios); + + ARMARX_INFO << "Learned DMP ... "; + } + + void NJointJSDMPController::runDMP(const Ice::DoubleSeq& goals, double tau, const Ice::Current&) + { + targetState.clear(); + targetState.resize(dimNames.size()); + currentState.clear(); + currentState.resize(dimNames.size()); + for (size_t i = 0; i < dimNames.size(); i++) + { + const auto& jointName = dimNames.at(i); + DMP::DMPState currentPos; + currentPos.pos = (positionSensors.count(jointName) == 1) ? positionSensors[jointName]->position : 0.0f; + currentPos.vel = (velocitySensors.count(jointName) == 1) ? velocitySensors[jointName]->velocity : 0.0f; + + currentState[i] = currentPos; + targetState.push_back(currentPos.pos); + } + dmpPtr->prepareExecution(goals, currentState, 1, tau); + + this->goals = goals; + this->tau = tau; + canVal = timeDuration; + finished = false; + isDisturbance = false; + + ARMARX_INFO << "run DMP..."; + controllerTask->start(); + } + + void NJointJSDMPController::showMessages(const Ice::Current&) + { + } + + void NJointJSDMPController::setTemporalFactor(double tau, const Ice::Current&) + { + LockGuardType guard(controllerMutex); + this->tau = tau; + } + + void NJointJSDMPController::rtPreActivateController() + { + } + + void NJointJSDMPController::rtPostDeactivateController() + { + + } + + void NJointJSDMPController::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); + } + + datafields["canVal"] = new Variant(debugOutputData.getUpToDateReadBuffer().currentCanVal); + datafields["mpcFactor"] = new Variant(debugOutputData.getUpToDateReadBuffer().mpcFactor); + debugObs->setDebugChannel("latestDMPTargetVelocities", datafields); + } + + + void NJointJSDMPController::onInitComponent() + { + ARMARX_INFO << "init ..."; + controllerTask = new PeriodicTask<NJointJSDMPController>(this, &NJointJSDMPController::controllerRun, 0.2); + } + + void NJointJSDMPController::onDisconnectComponent() + { + controllerTask->stop(); + ARMARX_INFO << "stopped ..."; + + } + + + + +} diff --git a/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointJSDMPController.h b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointJSDMPController.h new file mode 100644 index 000000000..625058be3 --- /dev/null +++ b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointJSDMPController.h @@ -0,0 +1,127 @@ + +#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 <dmp/representation/dmp/umidmp.h> +#include <ArmarXCore/core/services/tasks/RunningTask.h> +#include <RobotAPI/interface/units/RobotUnit/NJointJointSpaceDMPController.h> + +namespace armarx +{ + + TYPEDEF_PTRS_HANDLE(NJointJSDMPController); + + TYPEDEF_PTRS_HANDLE(NJointJSDMPControllerControlData); + class NJointJSDMPControllerControlData + { + public: + std::vector<double> targetJointVels; + }; + + + // class SimplePID + // { + // public: + // float Kp = 0, Kd = 0; + // float lastError = 0; + // float update(float dt, float error); + // }; + + class NJointJSDMPController : + public NJointControllerWithTripleBuffer<NJointJSDMPControllerControlData>, + public NJointJointSpaceDMPControllerInterface + { + public: + using ConfigPtrT = NJointJointSpaceDMPControllerConfigPtr; + NJointJSDMPController(NJointControllerDescriptionProviderInterfacePtr prov, const NJointControllerConfigPtr& config, const VirtualRobot::RobotPtr&); + + // NJointControllerInterface interface + std::string getClassName(const Ice::Current&) const override; + + // NJointController interface + void rtRun(const IceUtil::Time& sensorValuesTimestamp, const IceUtil::Time& timeSinceLastIteration) override; + + bool isFinished(const Ice::Current&) + { + return finished; + } + + void learnDMPFromFiles(const Ice::StringSeq& fileNames, const Ice::Current&); + void setTemporalFactor(double tau, const Ice::Current&); + + void runDMP(const Ice::DoubleSeq& goals, double tau, const Ice::Current&); + + void showMessages(const Ice::Current&); + + protected: + void rtPreActivateController() override; + void rtPostDeactivateController() override; + + virtual void onPublish(const SensorAndControl&, const DebugDrawerInterfacePrx&, const DebugObserverInterfacePrx&); + private: + + struct DebugBufferData + { + StringFloatDictionary latestTargetVelocities; + double currentCanVal; + double mpcFactor; + }; + TripleBuffer<DebugBufferData> debugOutputData; + + + struct NJointJSDMPControllerSensorData + { + double deltaT; + DMP::Vec<DMP::DMPState> currentState; + }; + TripleBuffer<NJointJSDMPControllerSensorData> controllerSensorData; + + + std::map<std::string, const SensorValue1DoFActuatorTorque*> torqueSensors; + std::map<std::string, const SensorValue1DoFGravityTorque*> gravityTorqueSensors; + std::map<std::string, const SensorValue1DoFActuatorPosition*> positionSensors; + std::map<std::string, const SensorValue1DoFActuatorVelocity*> velocitySensors; + std::map<std::string, ControlTarget1DoFActuatorVelocity*> targets; + + IceUtil::Time last; + + std::vector<double> goals; + DMP::UMIDMPPtr dmpPtr; + bool DMPAsForwardControl; + double timeDuration; + DMP::Vec<DMP::DMPState> currentState; + double canVal; + double deltaT; + + double tau; + double finished; + + // phaseStop parameters + double phaseL; + double phaseK; + double phaseDist0; + double phaseDist1; + double phaseKp; + + bool isDisturbance; + std::vector<std::string> dimNames; + DMP::DVec targetState; + std::vector<double> targetVels; + + mutable MutexType controllerMutex; + PeriodicTask<NJointJSDMPController>::pointer_type controllerTask; + // ManagedIceObject interface + protected: + void controllerRun(); + void onInitComponent(); + void onDisconnectComponent(); + + }; + +} // namespace armarx + diff --git a/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointJointSpaceDMPController.cpp b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointJointSpaceDMPController.cpp index e6882de92..737502f40 100644 --- a/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointJointSpaceDMPController.cpp +++ b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointJointSpaceDMPController.cpp @@ -52,7 +52,7 @@ namespace armarx void NJointJointSpaceDMPController::rtRun(const IceUtil::Time& sensorValuesTimestamp, const IceUtil::Time& timeSinceLastIteration) { - if (rtGetControlStruct().isStart) + if (rtGetControlStruct().isStart && !finished) { currentState.clear(); double phaseStop = 0; -- GitLab