diff --git a/source/RobotAPI/components/units/RobotUnit/BasicControllers.cpp b/source/RobotAPI/components/units/RobotUnit/BasicControllers.cpp index adc615c85bd1fb9281e75e21fb91dea991c30c18..3ea01e7168761901edcebf9bc6639490f27fd8df 100644 --- a/source/RobotAPI/components/units/RobotUnit/BasicControllers.cpp +++ b/source/RobotAPI/components/units/RobotUnit/BasicControllers.cpp @@ -437,6 +437,11 @@ namespace armarx return nextv; } + PositionThroughVelocityControllerWithAccelerationBounds::PositionThroughVelocityControllerWithAccelerationBounds() + { + // buffer.set_capacity(10); + } + bool PositionThroughVelocityControllerWithAccelerationBounds::validParameters() const { return maxV > 0 && @@ -467,7 +472,9 @@ namespace armarx const float posIfBrakingNow = currentPosition + brakingDistance; const float posErrorIfBrakingNow = targetPosition - posIfBrakingNow; const bool brakingNeeded = std::abs(brakingDistance) > std::abs(positionError); - const float usedDeceleration = brakingNeeded ? std::abs(currentV * currentV / 2.f / positionError) : deceleration ; + const float usedDeceleration = (brakingNeeded && positionError != 0.0f) ? + std::abs(currentV * currentV / 2.f / positionError) : + deceleration; const bool decelerate = std::abs(currentV) > maxV || // we need to slow down (to stay in [-maxV,maxV] brakingNeeded || @@ -475,7 +482,21 @@ namespace armarx const float usedacc = decelerate ? -usedDeceleration : acceleration; const float deltaVel = signV * usedacc * useddt; float newTargetVel = boost::algorithm::clamp(currentV + deltaVel, -maxV, maxV); - bool usePID = std::abs(newTargetVelPController) < std::abs(newTargetVel); + bool usePID = std::abs(newTargetVelPController) < std::abs(newTargetVel) + || std::abs(newTargetVelPController) < pControlVelLimit + || std::abs(positionError) < pControlPosErrorLimit; + // buffer.push_back({currentPosition, newTargetVelPController, newTargetVel, currentV, positionError}); + + // if (PIDModeActive != usePID) + // { + // for (auto& elem : buffer) + // { + // ARMARX_INFO << VAROUT(elem.currentPosition) << VAROUT(elem.targetVelocityPID) << VAROUT(elem.targetVelocityRAMP) << VAROUT(elem.currentV) << VAROUT(elem.currentError); + // } + // ARMARX_IMPORTANT << VAROUT(newTargetVelPController) << VAROUT(newTargetVel) << VAROUT(currentPosition) << VAROUT(usePID) << VAROUT(positionError); + // } + // ARMARX_INFO << deactivateSpam(1) << VAROUT(newTargetVelPController) << VAROUT(newTargetVel) << VAROUT(currentPosition) << VAROUT(usePID) << VAROUT(positionError) << VAROUT(targetPosition) << VAROUT(currentV) << VAROUT(deltaVel) << VAROUT(useddt) << VAROUT(usedacc); + // PIDModeActive = usePID; // ARMARX_INFO << deactivateSpam(0.2) << VAROUT(usePID) << VAROUT(dt) << VAROUT(decelerate) << VAROUT(usedacc) << VAROUT(maxDeltaV) << VAROUT(deltaVel) << VAROUT(newTargetVel) << VAROUT(newTargetVelPController) // << VAROUT(currentPosition) << VAROUT(targetPosition); // ARMARX_INFO << VAROUT(hardBrakeNeeded) << VAROUT(usedacc) << VAROUT(currentV) << VAROUT(newTargetVel) << VAROUT(decelerate) << VAROUT(brakingDistance) << VAROUT(positionError); @@ -689,6 +710,7 @@ namespace armarx //run should be static, but we need to adapt the parabs for the subcontroler -> have the subcontroler as value; PositionThroughVelocityControllerWithAccelerationBounds sub = *this; // slice parent class from this sub.currentPosition = periodicClamp(currentPosition, positionPeriodLo, positionPeriodHi); + // ARMARX_INFO << deactivateSpam(1) << VAROUT(currentPosition) << VAROUT(sub.currentPosition) << VAROUT(positionPeriodLo) << VAROUT(positionPeriodHi); sub.targetPosition = periodicClamp(targetPosition , positionPeriodLo, positionPeriodHi); const float brakingDist = brakingDistance(currentV, deceleration); diff --git a/source/RobotAPI/components/units/RobotUnit/BasicControllers.h b/source/RobotAPI/components/units/RobotUnit/BasicControllers.h index 035b8d215c3b4c7cd698e8905be48874bc87ca5d..c4235c90edfb958b0fda86d3bf76757bbaa47b8e 100644 --- a/source/RobotAPI/components/units/RobotUnit/BasicControllers.h +++ b/source/RobotAPI/components/units/RobotUnit/BasicControllers.h @@ -27,6 +27,7 @@ #include <type_traits> #include <ArmarXCore/core/util/algorithm.h> #include <RobotAPI/libraries/core/math/MathUtils.h> +#include <boost/circular_buffer.hpp> namespace armarx { @@ -87,43 +88,43 @@ namespace armarx if (newV < std::abs(v0)) { - dt0 = v0/dec; + dt0 = v0 / dec; dt1 = newDt - dt0; deltas d = accelerateToVelocity(v0, dec, 0); - newV =(distance - d.dx) / dt1; + newV = (distance - d.dx) / dt1; newAcc = dec; newDec = dec; -// // float oldDt = trapeze.at(0).dt + trapeze.at(1).dt + trapeze.at(2).dt; -// // dt0 = trapeze.at(0).dt; -// // dt1 = trapeze.at(1).dt; -// // dt2 = trapeze.at(2).dt; -// // area = trapezeArea(v0, newV, dt0, dt1, dt2); -// // auto v_pair = pq(dt1*dec, -(area*dec+v0*v0*0.5f)); -// auto v_pair = pq(-newDt * dec - v0, area * dec - v0 * v0 * 0.5f); -// if (std::isfinite(v_pair.first) && std::isfinite(v_pair.second)) -// { -// newV = std::abs(v_pair.first) < std::abs(v_pair.second) ? v_pair.first : v_pair.second; -// } -// else if (std::isfinite(v_pair.first)) -// { -// newV = v_pair.first; -// } -// else if (std::isfinite(v_pair.second)) -// { -// newV = v_pair.second; -// } -// // float f = (v0+newV)/2*((newV-v0)/dec) + dt1*newV + (newV/dec)*newV*0.5; -// dt0 = std::abs(newV - v0) / dec; -// dt1 = (newDt - std::abs(newV - v0) / dec - (newV / dec)); -// dt2 = (newV / dec); - -// float f = (v0 + newV) / 2 * (std::abs(newV - v0) / dec); -// f += (newDt - std::abs(newV - v0) / dec - (newV / dec)) * newV; -// f += (newV / dec) * newV * 0.5; - -// newAcc = dec; -// newDec = dec; + // // float oldDt = trapeze.at(0).dt + trapeze.at(1).dt + trapeze.at(2).dt; + // // dt0 = trapeze.at(0).dt; + // // dt1 = trapeze.at(1).dt; + // // dt2 = trapeze.at(2).dt; + // // area = trapezeArea(v0, newV, dt0, dt1, dt2); + // // auto v_pair = pq(dt1*dec, -(area*dec+v0*v0*0.5f)); + // auto v_pair = pq(-newDt * dec - v0, area * dec - v0 * v0 * 0.5f); + // if (std::isfinite(v_pair.first) && std::isfinite(v_pair.second)) + // { + // newV = std::abs(v_pair.first) < std::abs(v_pair.second) ? v_pair.first : v_pair.second; + // } + // else if (std::isfinite(v_pair.first)) + // { + // newV = v_pair.first; + // } + // else if (std::isfinite(v_pair.second)) + // { + // newV = v_pair.second; + // } + // // float f = (v0+newV)/2*((newV-v0)/dec) + dt1*newV + (newV/dec)*newV*0.5; + // dt0 = std::abs(newV - v0) / dec; + // dt1 = (newDt - std::abs(newV - v0) / dec - (newV / dec)); + // dt2 = (newV / dec); + + // float f = (v0 + newV) / 2 * (std::abs(newV - v0) / dec); + // f += (newDt - std::abs(newV - v0) / dec - (newV / dec)) * newV; + // f += (newV / dec) * newV * 0.5; + + // newAcc = dec; + // newDec = dec; } @@ -195,8 +196,8 @@ namespace armarx float currentPosition; float positionLimitLoSoft; float positionLimitHiSoft; -// float positionLimitLoHard; -// float positionLimitHiHard; + // float positionLimitLoHard; + // float positionLimitHiHard; bool validParameters() const; float run() const; @@ -223,13 +224,24 @@ namespace armarx float deceleration; float currentPosition; float targetPosition; - // float pControlPosErrorLimit; - // float pControlVelLimit; + float pControlPosErrorLimit = 0.01; + float pControlVelLimit = 0.001; // if target is below this threshold, PID controller will be used float p; - + PositionThroughVelocityControllerWithAccelerationBounds(); bool validParameters() const; float run() const; float estimateTime() const; + // mutable bool PIDModeActive = false; + // struct HelpStruct + // { + // float currentPosition; + // float targetVelocityPID; + // float targetVelocityRAMP; + // float currentV; + // float currentError; + // }; + + // mutable boost::circular_buffer<HelpStruct> buffer; }; float positionThroughVelocityControlWithAccelerationBounds(float dt, float maxDt, float currentV, float maxV, diff --git a/source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointKinematicUnitPassThroughController.h b/source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointKinematicUnitPassThroughController.h index a1bde0ec4e2739cc75cc48fed18690f9af6b8259..08bf67eea28b64f39b33e046010d2b7ef455a51b 100644 --- a/source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointKinematicUnitPassThroughController.h +++ b/source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointKinematicUnitPassThroughController.h @@ -63,6 +63,11 @@ namespace armarx *target = control; } inline virtual void rtPreActivateController() override + { + + } + + void reset() { control = (*sensor) * sensorToControlOnActivateFactor; if (std::abs(control) < resetZeroThreshold) diff --git a/source/RobotAPI/components/units/RobotUnit/RobotUnit.cpp b/source/RobotAPI/components/units/RobotUnit/RobotUnit.cpp index 358bdd97eea725b3c203d7520cb26a44d033d93c..90b93250b1e936dd5ac6537295b3e848085f136a 100644 --- a/source/RobotAPI/components/units/RobotUnit/RobotUnit.cpp +++ b/source/RobotAPI/components/units/RobotUnit/RobotUnit.cpp @@ -2474,7 +2474,7 @@ namespace armarx { bool collision = selfCollisionAvoidanceData.robot->getCollisionChecker()->checkCollision(selfCollisionAvoidanceData.collisionModels[it->first], selfCollisionAvoidanceData.collisionModels[it->second]); anyCollision |= collision; - distancesString += "---- " + it->first + " <-> " + it->second + " in Collsition: " + (collision ? "True" : "False") + "\n"; + distancesString += "---- " + it->first + " <-> " + it->second + " in Collision: " + (collision ? "True" : "False") + "\n"; // distances.push_back(distance); if (collision) { @@ -2581,7 +2581,7 @@ namespace armarx try { robot = VirtualRobot::RobotIO::loadRobot(robotFileName, VirtualRobot::RobotIO::eFull); - rtRobot = robot->clone(robot->getName()); + rtRobot = VirtualRobot::RobotIO::loadRobot(robotFileName, VirtualRobot::RobotIO::eStructure); rtRobot->setUpdateCollisionModel(false); rtRobot->setUpdateVisualization(false); rtRobot->setThreadsafe(false); @@ -2652,7 +2652,7 @@ namespace armarx emergencyStopMaster = new RobotUnitEmergencyStopMaster {this, getProperty<std::string>("EmergencyStopTopic").getValue()}; ManagedIceObjectPtr obj = ManagedIceObjectPtr::dynamicCast(emergencyStopMaster); ARMARX_CHECK_EXPRESSION_W_HINT(obj, "RobotUnitEmergencyStopMaster"); - getArmarXManager()->addObject(obj, getProperty<std::string>("EmergencyStopMasterName").getValue()); + getArmarXManager()->addObject(obj, getProperty<std::string>("EmergencyStopMasterName").getValue(), true); auto prx = obj->getProxy(-1); try { @@ -2734,8 +2734,9 @@ namespace armarx { node.first->setJointValueNoUpdate(node.second->position); } + // TIMING_START(RtRobotUpdate); rtRobot->applyJointValues(); - + // TIMING_END(RtRobotUpdate); rtThreadTimingsSensorDevice->rtMarkRtUpdateSensorAndControlBufferEnd(); } diff --git a/source/RobotAPI/components/units/RobotUnit/SensorValues/SensorValueForceTorque.h b/source/RobotAPI/components/units/RobotUnit/SensorValues/SensorValueForceTorque.h index 04588cb5561bed5e9c6d17628c486c5ff0ac41b8..a25d71642e109892202c81a3063e1cb2498ebb8b 100644 --- a/source/RobotAPI/components/units/RobotUnit/SensorValues/SensorValueForceTorque.h +++ b/source/RobotAPI/components/units/RobotUnit/SensorValues/SensorValueForceTorque.h @@ -35,12 +35,17 @@ namespace armarx DETAIL_SensorValueBase_DEFAULT_METHOD_IMPLEMENTATION Eigen::Vector3f torque; Eigen::Vector3f force; + Eigen::Vector3f gravityCompensatedTorque; + Eigen::Vector3f gravityCompensatedForce; + virtual std::map<std::string, VariantBasePtr> toVariants(const IceUtil::Time& timestamp) const override { return { {"torque", {new TimedVariant{Vector3{torque}, timestamp}}}, {"force", {new TimedVariant{Vector3{force }, timestamp}}}, + {"gravityCompensatedTorque", {new TimedVariant{Vector3{gravityCompensatedTorque}, timestamp}}}, + {"gravityCompensatedForce", {new TimedVariant{Vector3{gravityCompensatedForce }, timestamp}}}, }; } }; diff --git a/source/RobotAPI/components/units/RobotUnit/Units/KinematicSubUnit.cpp b/source/RobotAPI/components/units/RobotUnit/Units/KinematicSubUnit.cpp index 0899433b1f1c3f398d90a087d2be74d3b334b751..1cd5d65e4ef0ca4f5bafa04050bc182dfc26786a 100644 --- a/source/RobotAPI/components/units/RobotUnit/Units/KinematicSubUnit.cpp +++ b/source/RobotAPI/components/units/RobotUnit/Units/KinematicSubUnit.cpp @@ -21,6 +21,12 @@ */ #include "KinematicSubUnit.h" +armarx::KinematicSubUnit::KinematicSubUnit() : + reportSkipper(20.0f) +{ + +} + void armarx::KinematicSubUnit::setupData( std::string relRobFile, VirtualRobot::RobotPtr rob, @@ -129,22 +135,25 @@ void armarx::KinematicSubUnit::update(const armarx::SensorAndControl& sc, const << motorCurrents.size() << " \tmotor currents (updated = " << motorCurrentAValueChanged << ")\n" << motorTemperatures.size() << " \tmotor temperatures (updated = " << motorTemperaturesAValueChanged << ")\n"; auto prx = listenerPrx->ice_batchOneway(); - prx->reportControlModeChanged(ctrlModes, timestamp, ctrlModesAValueChanged); prx->reportJointAngles(ang, timestamp, angAValueChanged); prx->reportJointVelocities(vel, timestamp, velAValueChanged); - prx->reportJointAccelerations(acc, timestamp, accAValueChanged); prx->reportJointTorques(tor, timestamp, torAValueChanged); - if (!motorCurrents.empty()) - { - prx->reportJointCurrents(motorCurrents, timestamp, motorCurrentAValueChanged); - } - if (!motorTemperatures.empty()) - { - prx->reportJointMotorTemperatures(motorTemperatures, timestamp, motorTemperaturesAValueChanged); - } - if (!statuses.empty()) + if (reportSkipper.checkFrequency("Meta")) // only report the following data with low frequency { - prx->reportJointStatuses(statuses, timestamp, statusesAvalueChanged); + prx->reportJointAccelerations(acc, timestamp, accAValueChanged); + if (!motorCurrents.empty()) + { + prx->reportJointCurrents(motorCurrents, timestamp, motorCurrentAValueChanged); + } + if (!motorTemperatures.empty()) + { + prx->reportJointMotorTemperatures(motorTemperatures, timestamp, motorTemperaturesAValueChanged); + } + if (!statuses.empty()) + { + prx->reportJointStatuses(statuses, timestamp, statusesAvalueChanged); + } + prx->reportControlModeChanged(ctrlModes, timestamp, ctrlModesAValueChanged); } prx->ice_flushBatchRequests(); } @@ -219,7 +228,7 @@ void armarx::KinematicSubUnit::switchControlMode(const armarx::NameControlModeMa << "'. (ignoring this device)"; continue; } - auto ctrl = devs.at(name).getController(mode); + NJointKinematicUnitPassThroughControllerPtr ctrl = NJointKinematicUnitPassThroughControllerPtr::dynamicCast(devs.at(name).getController(mode)); if (!ctrl) { ARMARX_WARNING << "requested unsupported mode " << mode << " for device '" << name @@ -230,6 +239,7 @@ void armarx::KinematicSubUnit::switchControlMode(const armarx::NameControlModeMa { continue; } + ctrl->reset(); // reset immediately instead of preActivate() to avoid race condition toActivate[name] = std::move(ctrl); } const auto printToActivate = ARMARX_STREAM_PRINTER diff --git a/source/RobotAPI/components/units/RobotUnit/Units/KinematicSubUnit.h b/source/RobotAPI/components/units/RobotUnit/Units/KinematicSubUnit.h index 926a6eba2b5b2cc2012d673a8e3740772843ce93..23695b566f8e0f71426d76e38f8343601d23531c 100644 --- a/source/RobotAPI/components/units/RobotUnit/Units/KinematicSubUnit.h +++ b/source/RobotAPI/components/units/RobotUnit/Units/KinematicSubUnit.h @@ -31,6 +31,8 @@ #include <RobotAPI/components/units/KinematicUnit.h> +#include <ArmarXCore/core/util/IceReportSkipper.h> + #include "RobotUnitSubUnit.h" #include "../util.h" #include "../SensorValues/SensorValue1DoFActuator.h" @@ -57,6 +59,7 @@ namespace armarx NJointControllerPtr getController(ControlMode c) const; NJointControllerPtr getActiveController() const; }; + KinematicSubUnit(); void setupData( std::string relRobFile, @@ -89,7 +92,7 @@ namespace armarx private: std::map<std::string, ActuatorData> devs; // never use this when holding the mutex! (could cause deadlocks) - RobotUnit* robotUnit; + RobotUnit* robotUnit = NULL; mutable std::mutex dataMutex; NameControlModeMap ctrlModes; NameValueMap ang; @@ -101,6 +104,7 @@ namespace armarx NameStatusMap statuses; std::vector<std::set<std::string>> controlDeviceHardwareControlModeGroups; std::set<std::string> controlDeviceHardwareControlModeGroupsMerged; + IceReportSkipper reportSkipper; template<class ValueT, class SensorValueT, ValueT SensorValueT::* Member> static void UpdateNameValueMap(std::map<std::string, ValueT>& nvm, const std::string& name, const SensorValueBase* sv, bool& changeState) diff --git a/source/RobotAPI/gui-plugins/KinematicUnitPlugin/KinematicUnitGuiPlugin.cpp b/source/RobotAPI/gui-plugins/KinematicUnitPlugin/KinematicUnitGuiPlugin.cpp index cc713d196386cf202bfd1acb7fde45f09b49ff3f..939beb04017ada1c6b77f91217c8415fef9d96e8 100644 --- a/source/RobotAPI/gui-plugins/KinematicUnitPlugin/KinematicUnitGuiPlugin.cpp +++ b/source/RobotAPI/gui-plugins/KinematicUnitPlugin/KinematicUnitGuiPlugin.cpp @@ -716,10 +716,9 @@ bool KinematicUnitWidgetController::initGUIComboBox(VirtualRobot::RobotNodeSetPt QString name(rn[i]->getName().c_str()); ui.nodeListComboBox->addItem(name); } - + ui.nodeListComboBox->setCurrentIndex(-1); return true; } - return false; } diff --git a/source/RobotAPI/libraries/core/PIDController.cpp b/source/RobotAPI/libraries/core/PIDController.cpp index cea8fa2744f760265647b2d7f1ad18f5085733bb..12745ffe064e27a3d9d4c91b96882bcd313772ac 100644 --- a/source/RobotAPI/libraries/core/PIDController.cpp +++ b/source/RobotAPI/libraries/core/PIDController.cpp @@ -30,7 +30,7 @@ using namespace armarx; -PIDController::PIDController(float Kp, float Ki, float Kd, double maxControlValue, double maxDerivation, bool limitless, double limitlessLimitHi) : +PIDController::PIDController(float Kp, float Ki, float Kd, double maxControlValue, double maxDerivation, bool limitless) : Kp(Kp), Ki(Ki), Kd(Kd), @@ -43,8 +43,7 @@ PIDController::PIDController(float Kp, float Ki, float Kd, double maxControlValu controlValueDerivation(0), maxControlValue(maxControlValue), maxDerivation(maxDerivation), - limitless(limitless), - limitlessLimitHi(limitlessLimitHi) + limitless(limitless) { reset(); } @@ -103,7 +102,10 @@ void PIDController::update(double deltaSec, double measuredValue, double targetV //ARMARX_INFO << VAROUT(target) << ", " << VAROUT(processValue) << ", " << VAROUT(error); if (limitless) { - error = math::MathUtils::fmod(error, limitlessLimitHi - 2 * M_PI, limitlessLimitHi); + //ARMARX_INFO << VAROUT(error); + error = math::MathUtils::angleModPI(error); + //ARMARX_INFO << VAROUT(error); + //error = math::MathUtils::fmod(error, limitlessLimitHi - 2 * M_PI, limitlessLimitHi); //ARMARX_INFO << "Limitless after mod:" << VAROUT(error); } diff --git a/source/RobotAPI/libraries/core/PIDController.h b/source/RobotAPI/libraries/core/PIDController.h index 4e1f5528b4164f5800a585bb327861e74e2265b7..e3676c7590e6ded3e67233c352fa415ad6a89130 100644 --- a/source/RobotAPI/libraries/core/PIDController.h +++ b/source/RobotAPI/libraries/core/PIDController.h @@ -40,8 +40,7 @@ namespace armarx float Kd, double maxControlValue = std::numeric_limits<double>::max(), double maxDerivation = std::numeric_limits<double>::max(), - bool limitless = false, - double limitlessLimitHi = 2 * M_PI); + bool limitless = false); void update(double deltaSec, double measuredValue, double targetValue); void update(double measuredValue, double targetValue); void update(double measuredValue); @@ -64,7 +63,6 @@ namespace armarx double maxDerivation; bool firstRun; bool limitless; - double limitlessLimitHi; mutable RecursiveMutex mutex; }; typedef boost::shared_ptr<PIDController> PIDControllerPtr; diff --git a/source/RobotAPI/libraries/core/Trajectory.cpp b/source/RobotAPI/libraries/core/Trajectory.cpp index 07530219cc7b65f415117e5cc66617ba1c4d6947..00497e1eb2fe692669d6e201cc9c2dcb8ff389d9 100644 --- a/source/RobotAPI/libraries/core/Trajectory.cpp +++ b/source/RobotAPI/libraries/core/Trajectory.cpp @@ -1470,43 +1470,15 @@ namespace armarx { // linear interpolation - double distance = fabs(itNext->timestamp - itPrev->timestamp); - double weightPrev = fabs(t - itNext->timestamp) / distance; - double weightNext = fabs(itPrev->timestamp - t) / distance; + float f = math::MathUtils::ILerp(itPrev->timestamp, itNext->timestamp, t); if (dimension < limitless.size() && limitless.at(dimension).enabled) { - double result = 0; - double range = limitless.at(dimension).limitHi - limitless.at(dimension).limitLo; - double dist1 = next - previous; - double dist2 = next - (previous + range); - double dist3 = next - (previous - range); - //ARMARX_IMPORTANT << "LIMITLESS: checking dim " << dimension << ", prev:" << previous << ", next:" << next << ", range:" << range << ", dist1:" << dist1 << ", dist2:" << dist2 << ", dist3:" << dist3; - if (fabs(dist1) <= fabs(dist2) && fabs(dist1) <= fabs(dist3)) - { - // no issue with bounds - result = weightNext * next + weightPrev * previous; - } - else if (fabs(dist2) <= fabs(dist3) && fabs(dist2) <= fabs(dist3)) - { - // go over hi bound - result = weightNext * next + weightPrev * (previous + range); - result = math::MathUtils::fmod(result, limitless.at(dimension).limitLo, limitless.at(dimension).limitHi); - //ARMARX_IMPORTANT << "LIMITLESS - HIGH: checking dim " << dimension << ": high bounds, result: " << result << ", orig result would be " << weightNext* next + weightPrev* previous; - } - else - { - // go over lo bound - result = weightNext * next + weightPrev * (previous - range); - result = math::MathUtils::fmod(result, limitless.at(dimension).limitLo, limitless.at(dimension).limitHi); - //ARMARX_IMPORTANT << "LIMITLESS - LOW: checking dim " << dimension << ": low bounds, result: " << result << ", orig result would be " << weightNext* next + weightPrev* previous; - } - return result; + return math::MathUtils::AngleLerp(previous, next, f); } else { - //ARMARX_IMPORTANT << "LIMITLESS: dim " << dimension << ": not limitless, limitless.size()=" << limitless.size(); - return weightNext * next + weightPrev * previous; + return math::MathUtils::Lerp(previous, next, f); } } } diff --git a/source/RobotAPI/libraries/core/math/MathUtils.h b/source/RobotAPI/libraries/core/math/MathUtils.h index eae0128a8508b7963ea5820394cc9a13cbf71173..4ea7d9a7f0c08ba80382c4caa4f0722c93b1057d 100644 --- a/source/RobotAPI/libraries/core/math/MathUtils.h +++ b/source/RobotAPI/libraries/core/math/MathUtils.h @@ -126,14 +126,12 @@ namespace armarx static float fmod(float value, float boundLow, float boundHigh) { - if (value < 0) + value = std::fmod(value - boundLow, boundHigh - boundLow) + boundLow; + if (value < boundLow) { - return std::fmod(value + boundLow, boundHigh - boundLow) - boundLow; - } - else - { - return std::fmod(value - boundLow, boundHigh - boundLow) + boundLow; + value += boundHigh - boundLow; } + return value; } static float angleMod2PI(float value) @@ -143,9 +141,27 @@ namespace armarx static float angleModPI(float value) { - return angleMod2PI(value) - M_PI; + return angleMod2PI(value + M_PI) - M_PI; } + static float Lerp(float a, float b, float f) + { + return a * (1 - f) + b * f; + } + + static float ILerp(float a, float b, float f) + { + return (f - a) / (b - a); + } + + static float AngleLerp(float a, float b, float f) + { + b = fmod(b, a - M_PI, a + M_PI); + return Lerp(a, b, f); + } + + + }; } } diff --git a/source/RobotAPI/libraries/core/test/PIDControllerTest.cpp b/source/RobotAPI/libraries/core/test/PIDControllerTest.cpp index 85ec430aa338836e18686887d51811e9ac3e53f1..2fc298fddc53062028ebf8febf556ac505b5fa02 100644 --- a/source/RobotAPI/libraries/core/test/PIDControllerTest.cpp +++ b/source/RobotAPI/libraries/core/test/PIDControllerTest.cpp @@ -39,3 +39,31 @@ BOOST_AUTO_TEST_CASE(PIDControllerTest) } +void check_close(float a, float b, float tolerance) +{ + if(fabs(a - b) > tolerance) + { + ARMARX_ERROR << "fabs(a-b) > tolerance. a=" << a << " b=" << b << " tolerance=" << tolerance; + BOOST_FAIL(""); + } +} + +BOOST_AUTO_TEST_CASE(PIDControllerContinousTest) +{ + PIDController c(1, 0, 0, 10, 10, true); + + for(int a = -2; a <= 2; a++) + { + for(int b = -2; b <= 2; b++) + { + for(int t = -2; t <= 2; t++) + { + c.update(1, 0 + a*M_PI*2, t + b*M_PI*2); + check_close(c.getControlValue(), t, 0.01); + + c.update(1, t + a*M_PI*2, 0 + b*M_PI*2); + check_close(c.getControlValue(), -t, 0.01); + } + } + } +}