From cb5b7262bc33005149f8ff952c72e47312556184 Mon Sep 17 00:00:00 2001 From: Mirko Waechter <mirko.waechter@kit.edu> Date: Sat, 7 May 2016 01:44:54 +0200 Subject: [PATCH] Kinematic Unit Simulation supports now position control with PID controller instead of instantly reaching the target --- .../units/KinematicUnitSimulation.cpp | 51 ++++++++++++++++--- .../units/KinematicUnitSimulation.h | 11 +++- .../RobotAPI/libraries/core/PIDController.cpp | 13 +++++ .../RobotAPI/libraries/core/PIDController.h | 2 + 4 files changed, 68 insertions(+), 9 deletions(-) diff --git a/source/RobotAPI/components/units/KinematicUnitSimulation.cpp b/source/RobotAPI/components/units/KinematicUnitSimulation.cpp index 088be6ebe..5b81f9c98 100644 --- a/source/RobotAPI/components/units/KinematicUnitSimulation.cpp +++ b/source/RobotAPI/components/units/KinematicUnitSimulation.cpp @@ -34,13 +34,14 @@ #include <ArmarXCore/core/system/ArmarXDataPath.h> #include <ArmarXCore/core/time/TimeUtil.h> + #include <algorithm> using namespace armarx; void KinematicUnitSimulation::onInitKinematicUnit() { - + usePDControllerForPosMode = getProperty<bool>("UsePDControllerForJointControl").getValue(); for (std::vector<VirtualRobot::RobotNodePtr>::iterator it = robotNodes.begin(); it != robotNodes.end(); it++) { std::string jointName = (*it)->getName(); @@ -68,6 +69,10 @@ void KinematicUnitSimulation::onInitKinematicUnit() std::string jointName = (*it)->getName(); jointStates[jointName] = KinematicUnitSimulationJointState(); jointStates[jointName].init(); + positionControlPIDController[jointName] = PIDControllerPtr(new PIDController( + getProperty<float>("Kp").getValue(), + getProperty<float>("Ki").getValue(), + getProperty<float>("Kd").getValue())); } } @@ -102,6 +107,10 @@ void KinematicUnitSimulation::simulationFunction() bool aPosValueChanged = false; bool aVelValueChanged = false; + auto signedMin = [](float newValue, float minAbsValue) + { + return std::copysign(std::min<float>(fabs(newValue), fabs(minAbsValue)), newValue); + }; { boost::mutex::scoped_lock lock(jointStatesMutex); @@ -117,12 +126,29 @@ void KinematicUnitSimulation::simulationFunction() double change = (it->second.velocity * timeDeltaInSeconds); double randomNoiseValue = distribution(generator); - change += randomNoiseValue; + change *= 1 + randomNoiseValue; newAngle = it->second.angle + change; } else if (it->second.controlMode == ePositionControl) { - newAngle = it->second.angle; + if (!usePDControllerForPosMode) + { + newAngle = it->second.angle; + } + else + { + PIDControllerPtr pid = positionControlPIDController[it->first]; + if (pid) + { + float velValue = (it->second.velocity != 0.0f ? signedMin(pid->getControlValue(), it->second.velocity) : pid->getControlValue()); //restrain to max velocity + velValue *= 1 + distribution(generator); + pid->update(it->second.angle); + newAngle = it->second.angle + + velValue * + timeDeltaInSeconds; + + } + } } // constrain the angle @@ -233,8 +259,21 @@ void KinematicUnitSimulation::setJointAngles(const NameValueMap& targetJointAngl targetJointAngle = std::min<float>(targetJointAngle, jointInfos[targetJointName].limitHi); } - iterJoints->second.angle = targetJointAngle; - actualJointAngles[targetJointName] = iterJoints->second.angle; + if (!usePDControllerForPosMode) + { + iterJoints->second.angle = targetJointAngle; + actualJointAngles[targetJointName] = iterJoints->second.angle; + } + else + { + PIDControllerPtr pid = positionControlPIDController[it->first]; + if (pid) + { + pid->reset(); + pid->setTarget(targetJointAngle); + + } + } } else { @@ -362,7 +401,6 @@ bool mapEntryEqualsString(std::pair<std::string, KinematicUnitSimulationJointSta void KinematicUnitSimulation::requestJoints(const StringSequence& joints, const Ice::Current& c) { - ARMARX_INFO << flush; // if one of the joints belongs to this unit, lock access to this unit for other components except for the requesting one KinematicUnitSimulationJointStates::const_iterator it = std::find_first_of(jointStates.begin(), jointStates.end(), joints.begin(), joints.end(), mapEntryEqualsString); @@ -374,7 +412,6 @@ void KinematicUnitSimulation::requestJoints(const StringSequence& joints, const void KinematicUnitSimulation::releaseJoints(const StringSequence& joints, const Ice::Current& c) { - ARMARX_INFO << flush; // if one of the joints belongs to this unit, unlock access KinematicUnitSimulationJointStates::const_iterator it = std::find_first_of(jointStates.begin(), jointStates.end(), joints.begin(), joints.end(), mapEntryEqualsString); diff --git a/source/RobotAPI/components/units/KinematicUnitSimulation.h b/source/RobotAPI/components/units/KinematicUnitSimulation.h index 57e3c9f4c..4b730a0f4 100644 --- a/source/RobotAPI/components/units/KinematicUnitSimulation.h +++ b/source/RobotAPI/components/units/KinematicUnitSimulation.h @@ -29,6 +29,7 @@ #include <ArmarXCore/core/services/tasks/PeriodicTask.h> #include <ArmarXCore/core/system/ImportExportComponent.h> +#include <RobotAPI/libraries/core/PIDController.h> #include <random> #include <IceUtil/Time.h> @@ -111,7 +112,12 @@ namespace armarx KinematicUnitPropertyDefinitions(prefix) { defineOptionalProperty<int>("IntervalMs", 10, "The time in milliseconds between two calls to the simulation method."); - defineOptionalProperty<float>("Noise", 0.0f, "Noise is added in velocity mode with (rand()/RAND_MAX-0.5)*2*Noise. Value in Degree"); + defineOptionalProperty<float>("Noise", 0.0f, "Gaussian noise is added to the velocity. Value in Degree"); + defineOptionalProperty<bool>("UsePDControllerForJointControl", true, "If true a PD controller is also used in Position Mode instead of setting the joint angles instantly"); + defineOptionalProperty<float>("Kp", 3, "proportional gain of the PID position controller."); + defineOptionalProperty<float>("Ki", 0.001, "integral gain of the PID position controller."); + defineOptionalProperty<float>("Kd", 0.0, "derivative gain of the PID position controller."); + } }; @@ -173,7 +179,8 @@ namespace armarx int intervalMs; std::normal_distribution<double> distribution; std::default_random_engine generator; - + bool usePDControllerForPosMode; + std::map<std::string, PIDControllerPtr> positionControlPIDController; PeriodicTask<KinematicUnitSimulation>::pointer_type simulationTask; }; } diff --git a/source/RobotAPI/libraries/core/PIDController.cpp b/source/RobotAPI/libraries/core/PIDController.cpp index 7a82a5d6a..441fb1177 100644 --- a/source/RobotAPI/libraries/core/PIDController.cpp +++ b/source/RobotAPI/libraries/core/PIDController.cpp @@ -66,6 +66,19 @@ void PIDController::update(double measuredValue, double targetValue) lastUpdateTime = now; } + +void PIDController::update(double measuredValue) +{ + ScopedRecursiveLock lock(mutex); + update(measuredValue, target); +} + +void PIDController::setTarget(double newTarget) +{ + ScopedRecursiveLock lock(mutex); + target = newTarget; +} + void PIDController::update(double deltaSec, double measuredValue, double targetValue) { ScopedRecursiveLock lock(mutex); diff --git a/source/RobotAPI/libraries/core/PIDController.h b/source/RobotAPI/libraries/core/PIDController.h index c1c1529a4..8e9578b02 100644 --- a/source/RobotAPI/libraries/core/PIDController.h +++ b/source/RobotAPI/libraries/core/PIDController.h @@ -38,6 +38,8 @@ namespace armarx PIDController(float Kp, float Ki, float Kd); void update(double deltaSec, double measuredValue, double targetValue); void update(double measuredValue, double targetValue); + void update(double measuredValue); + void setTarget(double newTarget); double getControlValue() const; void reset(); -- GitLab