Class PIDController<T>
Generic PID (Proportional-Integral-Derivative) controller base class. Computes a corrective output from a measured error signal to continuously drive a system toward a desired setpoint.
[Serializable]
public abstract class PIDController<T>
Type Parameters
| Name | Type | Description |
|---|---|---|
T | Numeric or vector type that the controller operates on. |
Inheritance
Examples
Use the concrete FloatPIDController subclass to regulate vehicle throttle
each FixedUpdate. The error is the difference between the desired speed and the
current speed; GetOutput returns a throttle value that the car controller consumes:
[SerializeField] private FloatPIDController _throttlePID; // tuned in Inspector
[SerializeField] private PrometeoCarController _car;
private float _targetSpeed = 10f; // m/s
private void FixedUpdate()
{
float error = _targetSpeed - _car.CurrentSpeed;
float throttle = _throttlePID.GetOutput(error, Time.fixedDeltaTime);
_car.Move(new Vector2(0f, Mathf.Clamp(throttle, -1f, 1f)));
}
// Call Reset() whenever the setpoint changes abruptly — e.g. after a new waypoint
// is assigned — to flush the integral accumulator and prevent I-term windup from
// the previous tracking run.
private void OnNewWaypointAssigned()
{
_throttlePID.Reset();
}
Remarks
A PID controller is used instead of simpler bang-bang control because it produces smooth, continuous outputs that avoid abrupt jerks in vehicle motion — important both for realistic simulation fidelity and for preventing motion sickness in VR participants.
The three terms serve distinct roles: the P term reacts proportionally to the current error (how far off-target the vehicle is now); the I term accumulates persistent error over time (removes steady-state offset, e.g. a constant speed deficit on an incline); the D term damps oscillations by opposing rapid error changes (prevents overshoot). Concrete subclasses FloatPIDController and Vector3PIDController implement the type-specific arithmetic.
Constructors
PIDController()
Initializes a new instance of the PIDController class with default coefficients.
public PIDController()
PIDController(float, float, float)
Initializes a new instance of the PIDController class with specified coefficients.
public PIDController(float pFactor, float iFactor, float dFactor)
Parameters
| Name | Type | Description |
|---|---|---|
pFactor | float | Proportional gain. |
iFactor | float | Integral gain. |
dFactor | float | Derivative gain. |
Fields
Coefficients
Current set of PID tuning coefficients.
[SerializeField]
[FormerlySerializedAs("PIDCoefficients")]
public PIDController<T>.PIDFactors Coefficients
Field Value
derivativeInitialized
Guards the derivative term against an infinite spike on the very first call.
On frame zero previousError is the default value for T,
so (error - previousError) / deltaTime would produce an enormous derivative
output. This flag suppresses the D-term for the first tick and is cleared by
Reset.
protected bool derivativeInitialized
Field Value
bool
previousError
The previous error value, used to compute the derivative term.
protected T previousError
Field Value
Methods
ComputeOutput(T, float)
Performs the type-specific PID computation: calculates the proportional, integral, and derivative contributions and combines them according to the tuning coefficients.
protected abstract T ComputeOutput(T error, float deltaTime)
Parameters
| Name | Type | Description |
|---|---|---|
error | T | The current error value. |
deltaTime | float | Time in seconds since the last update. |
Returns
T — The raw PID output before any external scaling or clamping.
GetOutput(T, float)
Computes the PID controller output based on the current error and elapsed time.
public T GetOutput(T error, float deltaTime)
Parameters
| Name | Type | Description |
|---|---|---|
error | T | The difference between the desired setpoint and the current value. |
deltaTime | float | Time in seconds since the last update; must be greater than zero. |
Returns
T — The control output calculated by the PID algorithm.
Reset()
Resets the controller's internal state (derivative initialization flag and integral accumulator) while retaining the current tuning coefficients.
public void Reset()
Remarks
Call this method whenever the tracking target changes abruptly — for example, after
the vehicle is assigned a new waypoint, when the desired speed setpoint jumps
discontinuously, or when a PID-controlled loop is re-enabled after being paused.
Without a reset, the integral term retains error accumulated during the previous
tracking run and will drive the output in the wrong direction immediately after the
target change (I-term windup). Resetting also suppresses the spurious derivative
spike that would otherwise occur on the first tick after re-activation, because
previousError would hold a stale value from the prior run.