PidConfiguration.cpp 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <AzCore/Math/MathUtils.h>
  9. #include <AzCore/Serialization/EditContext.h>
  10. #include <AzCore/Serialization/EditContextConstants.inl>
  11. #include <AzCore/Serialization/SerializeContext.h>
  12. #include <ROS2Controllers/Controllers/PidConfiguration.h>
  13. namespace ROS2Controllers
  14. {
  15. void PidConfiguration::Reflect(AZ::ReflectContext* context)
  16. {
  17. if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
  18. {
  19. serializeContext->Class<PidConfiguration>()
  20. ->Version(1)
  21. ->Field("P", &PidConfiguration::m_p)
  22. ->Field("I", &PidConfiguration::m_i)
  23. ->Field("D", &PidConfiguration::m_d)
  24. ->Field("IMin", &PidConfiguration::m_iMin)
  25. ->Field("IMax", &PidConfiguration::m_iMax)
  26. ->Field("Anti windup", &PidConfiguration::m_antiWindup)
  27. ->Field("Output limit", &PidConfiguration::m_outputLimit);
  28. if (AZ::EditContext* ec = serializeContext->GetEditContext())
  29. {
  30. ec->Class<PidConfiguration>("PID configuration", "Configures a PID controller")
  31. ->DataElement(AZ::Edit::UIHandlers::Default, &PidConfiguration::m_p, "P", "Proportional gain")
  32. ->Attribute(AZ::Edit::Attributes::Min, 0.0)
  33. ->DataElement(AZ::Edit::UIHandlers::Default, &PidConfiguration::m_i, "I", "Integral gain")
  34. ->Attribute(AZ::Edit::Attributes::Min, 0.0)
  35. ->DataElement(AZ::Edit::UIHandlers::Default, &PidConfiguration::m_d, "D", "Derivative gain")
  36. ->Attribute(AZ::Edit::Attributes::Min, 0.0)
  37. ->DataElement(AZ::Edit::UIHandlers::Default, &PidConfiguration::m_iMin, "IMin", "Minimum allowable integral term")
  38. ->Attribute(AZ::Edit::Attributes::Min, 0.0)
  39. ->DataElement(AZ::Edit::UIHandlers::Default, &PidConfiguration::m_iMax, "IMax", "Maximum allowable integral term")
  40. ->Attribute(AZ::Edit::Attributes::Min, 0.0)
  41. ->DataElement(AZ::Edit::UIHandlers::Default, &PidConfiguration::m_antiWindup, "AntiWindup", "Anti windup")
  42. ->DataElement(
  43. AZ::Edit::UIHandlers::Default,
  44. &PidConfiguration::m_outputLimit,
  45. "OutputLimit",
  46. "Limit of the PID output [0, INF]. Set to 0.0 to disable.")
  47. ->Attribute(AZ::Edit::Attributes::Min, 0.0);
  48. }
  49. }
  50. }
  51. void PidConfiguration::InitializePid()
  52. {
  53. if (m_iMin > m_iMax)
  54. {
  55. AZ_Error("PidConfiguration", false, "Invalid PID configuration.");
  56. }
  57. else
  58. {
  59. m_initialized = true;
  60. }
  61. }
  62. double PidConfiguration::ComputeCommand(double error, uint64_t deltaTimeNanoseconds)
  63. {
  64. const double dt = aznumeric_cast<double>(deltaTimeNanoseconds) / 1.e9;
  65. if (!m_initialized)
  66. {
  67. AZ_Error("PidConfiguration", false, "PID not initialized, ignoring.");
  68. return 0.0;
  69. }
  70. if (dt <= 0.0 || !azisfinite(error))
  71. {
  72. AZ_Warning("PidConfiguration", false, "Invalid PID conditions.");
  73. return 0.0;
  74. }
  75. const double proportionalTerm = m_p * error;
  76. m_integral += error * dt;
  77. if (m_antiWindup && m_i != 0)
  78. {
  79. AZStd::pair<double, double> bounds = AZStd::minmax<double>(m_iMin / m_i, m_iMax / m_i);
  80. m_integral = AZStd::clamp<double>(m_integral, bounds.first, bounds.second);
  81. }
  82. double integralTerm = m_i * m_integral;
  83. if (m_antiWindup)
  84. {
  85. integralTerm = AZStd::clamp<double>(integralTerm, m_iMin, m_iMax);
  86. }
  87. const double derivative = (error - m_previousError) / dt;
  88. const double derivativeTerm = m_d * derivative;
  89. m_previousError = error;
  90. double output = proportionalTerm + integralTerm + derivativeTerm;
  91. if (m_outputLimit > 0.0)
  92. {
  93. output = AZStd::clamp<double>(output, -m_outputLimit, m_outputLimit);
  94. }
  95. return output;
  96. }
  97. } // namespace ROS2Controllers