using UnityEngine; namespace NWH.Common.Utility { /// /// Implementation of PID controller based on: /// https://github.com/ms-iot/pid-controller/blob/master/PidController/PidController/PidController.cs /// public class PIDController { public float maxValue; public float minValue; private float _processVariable; public PIDController(float gainProportional, float gainIntegral, float gainDerivative, float outputMin, float outputMax) { GainDerivative = gainDerivative; GainIntegral = gainIntegral; GainProportional = gainProportional; maxValue = outputMax; minValue = outputMin; } /// /// The derivative term is proportional to the rate of /// change of the error /// public float GainDerivative { get; set; } /// /// The integral term is proportional to both the magnitude /// of the error and the duration of the error /// public float GainIntegral { get; set; } /// /// The proportional term produces an output value that /// is proportional to the current error value /// /// /// Tuning theory and industrial practice indicate that the /// proportional term should contribute the bulk of the output change. /// public float GainProportional { get; set; } /// /// Adjustment made by considering the accumulated error over time /// /// /// An alternative formulation of the integral action, is the /// proportional-summation-difference used in discrete-time systems /// public float IntegralTerm { get; private set; } /// /// The current value /// public float ProcessVariable { get { return _processVariable; } set { ProcessVariableLast = _processVariable; _processVariable = value; } } /// /// The last reported value (used to calculate the rate of change) /// public float ProcessVariableLast { get; private set; } /// /// The desired value /// public float SetPoint { get; set; } = 0; /// /// The controller output /// /// /// timespan of the elapsed time /// since the previous time that ControlVariable was called /// /// Value of the variable that needs to be controlled public float ControlVariable(float timeSinceLastUpdate) { float error = SetPoint - ProcessVariable; // integral term calculation IntegralTerm += GainIntegral * error * timeSinceLastUpdate; IntegralTerm = Mathf.Clamp(IntegralTerm, minValue, maxValue); // derivative term calculation float dInput = _processVariable - ProcessVariableLast; float derivativeTerm = GainDerivative * (dInput / timeSinceLastUpdate); // proportional term calcullation float proportionalTerm = GainProportional * error; float output = proportionalTerm + IntegralTerm - derivativeTerm; output = Mathf.Clamp(output, minValue, maxValue); return output; } } }