From 26008043a530bb2e9dd31f2e943cc9a073b391a7 Mon Sep 17 00:00:00 2001 From: Gabriel Santos Date: Sun, 2 Nov 2025 08:30:03 +0000 Subject: [PATCH] pid absolute --- .../implementations/CMakeLists.txt | 1 + .../implementations/PidAbsolute.hpp | 202 ++++++++++++++++++ numerical/math/CompilerOptimizations.hpp | 2 +- 3 files changed, 204 insertions(+), 1 deletion(-) create mode 100644 numerical/controllers/implementations/PidAbsolute.hpp diff --git a/numerical/controllers/implementations/CMakeLists.txt b/numerical/controllers/implementations/CMakeLists.txt index 70bc68c9..03e13b9a 100644 --- a/numerical/controllers/implementations/CMakeLists.txt +++ b/numerical/controllers/implementations/CMakeLists.txt @@ -10,6 +10,7 @@ target_link_libraries(numerical.controllers.implementations INTERFACE ) target_sources(numerical.controllers.implementations PRIVATE + PidAbsolute.hpp PidIncremental.hpp ) diff --git a/numerical/controllers/implementations/PidAbsolute.hpp b/numerical/controllers/implementations/PidAbsolute.hpp new file mode 100644 index 00000000..70231124 --- /dev/null +++ b/numerical/controllers/implementations/PidAbsolute.hpp @@ -0,0 +1,202 @@ +#pragma once + +#include "numerical/controllers/interfaces/PidController.hpp" +#include "numerical/math/CompilerOptimizations.hpp" +#include + +namespace controllers +{ + template + class PidAbsoluteBase + { + public: + void SetPoint(QNumberType setPoint); + void SetLimits(PidLimits limits); + void SetIntegralLimit(QNumberType integralLimit); + void SetTunings(PidTunings tunnings); + void Enable(); + QNumberType Process(QNumberType processVariable); + + protected: + PidAbsoluteBase(PidTunings tunnings, PidLimits limits, std::optional integralLimit = std::nullopt); + + private: + QNumberType Clamp(QNumberType input, QNumberType min, QNumberType max); + + private: + std::optional setPoint; + PidLimits limits; + QNumberType integralLimit; + + QNumberType kp; + QNumberType ki; + QNumberType kd; + + QNumberType integral = QNumberType(0.0f); + QNumberType previousError = QNumberType(0.0f); + }; + + template + class PidAbsoluteSynchronous + : public SynchronousPidController + , private PidAbsoluteBase + { + public: + PidAbsoluteSynchronous(PidTunings tunnings, PidLimits limits); + PidAbsoluteSynchronous(PidTunings tunnings, PidLimits limits, QNumberType integralLimit); + + // Implementation of SynchronousPidController + void SetPoint(QNumberType setPoint) override; + void SetLimits(PidLimits limits) override; + void SetTunings(PidTunings tunnings) override; + void Enable() override; + void Disable() override; + QNumberType Process(QNumberType processVariable) override; + + void SetIntegralLimit(QNumberType integralLimit); + }; + + //// Implementation //// + + template + PidAbsoluteBase::PidAbsoluteBase(PidTunings tunnings, PidLimits limits, std::optional integralLimit) + : limits{ limits } + , integralLimit{ integralLimit.value_or(limits.max) } + , kp{ tunnings.kp } + , ki{ tunnings.ki } + , kd{ tunnings.kd } + { + really_assert(limits.min < limits.max); + } + + template + void PidAbsoluteBase::SetPoint(QNumberType _setPoint) + { + this->setPoint.emplace(_setPoint); + } + + template + void PidAbsoluteBase::Enable() + { + integral = QNumberType(0.0f); + previousError = QNumberType(0.0f); + } + + template + void PidAbsoluteBase::SetLimits(PidLimits _limits) + { + really_assert(_limits.max > _limits.min); + this->limits = _limits; + } + + template + void PidAbsoluteBase::SetIntegralLimit(QNumberType _integralLimit) + { + this->integralLimit = _integralLimit; + } + + template + void PidAbsoluteBase::SetTunings(PidTunings tunings) + { + kp = tunings.kp; + ki = tunings.ki; + kd = tunings.kd; + } + + template + OPTIMIZE_FOR_SPEED + QNumberType + PidAbsoluteBase::Clamp(QNumberType input, QNumberType min, QNumberType max) + { + if (input > max) + return max; + + if (input < min) + return min; + + return input; + } + + template + OPTIMIZE_FOR_SPEED + QNumberType + PidAbsoluteBase::Process(QNumberType processVariable) + { + if (!setPoint.has_value()) + return processVariable; + + QNumberType error = *setPoint - processVariable; + + QNumberType P = kp * error; + + integral = integral + error; + integral = Clamp(integral, -integralLimit, integralLimit); + QNumberType I = ki * integral; + + QNumberType derivative = error - previousError; + QNumberType D = kd * derivative; + + QNumberType output = P + I + D; + + output = Clamp(output, limits.min, limits.max); + + previousError = error; + + return output; + } + + template + PidAbsoluteSynchronous::PidAbsoluteSynchronous(PidTunings tunnings, PidLimits limits) + : PidAbsoluteBase{ tunnings, limits } + { + } + + template + PidAbsoluteSynchronous::PidAbsoluteSynchronous(PidTunings tunnings, PidLimits limits, QNumberType integralLimit) + : PidAbsoluteBase{ tunnings, limits, integralLimit } + { + } + + template + void PidAbsoluteSynchronous::SetPoint(QNumberType setPoint) + { + PidAbsoluteBase::SetPoint(setPoint); + } + + template + void PidAbsoluteSynchronous::SetLimits(PidLimits limits) + { + PidAbsoluteBase::SetLimits(limits); + } + + template + void PidAbsoluteSynchronous::SetIntegralLimit(QNumberType integralLimit) + { + PidAbsoluteBase::SetIntegralLimit(integralLimit); + } + + template + void PidAbsoluteSynchronous::SetTunings(PidTunings tunnings) + { + PidAbsoluteBase::SetTunings(tunnings); + } + + template + void PidAbsoluteSynchronous::Enable() + { + PidAbsoluteBase::Enable(); + } + + template + void PidAbsoluteSynchronous::Disable() + { + } + + template + OPTIMIZE_FOR_SPEED + QNumberType + PidAbsoluteSynchronous::Process(QNumberType processVariable) + { + return PidAbsoluteBase::Process(processVariable); + } +} diff --git a/numerical/math/CompilerOptimizations.hpp b/numerical/math/CompilerOptimizations.hpp index d3248311..33877458 100644 --- a/numerical/math/CompilerOptimizations.hpp +++ b/numerical/math/CompilerOptimizations.hpp @@ -1,7 +1,7 @@ #pragma once #if defined(__GNUC__) && !defined(__clang__) && defined(NumericalToolbox_ENABLE_OPTIMIZATIONS) -#define OPTIMIZE_FOR_SPEED __attribute__((hot, optimize("-O3"), optimize("-ffast-math"), flatten)) inline +#define OPTIMIZE_FOR_SPEED __attribute__((hot, optimize("-O3"), optimize("-ffast-math"))) inline #elif defined(__clang__) && defined(NumericalToolbox_ENABLE_OPTIMIZATIONS) #define OPTIMIZE_FOR_SPEED __attribute__((hot, flatten)) inline #elif defined(_MSC_VER)