lejos.util
Class PIDController

java.lang.Object
  extended by lejos.util.PIDController

public class PIDController
extends Object

Proportional <P>, Integral <I>, Derivative <D> controller implementation. P depends on the present error, I on the accumulation of past errors, and D is a prediction of future errors, based on current rate of change.

Proportional gain, Kp: Larger values typically mean faster response since the larger the error, the larger the proportional term compensation. An excessively large proportional gain will lead to process instability and oscillation.

Integral gain, Ki: Larger values imply steady state errors are eliminated more quickly. The trade-off is larger overshoot: any negative error integrated during transient response must be integrated away by positive error before reaching steady state.

Derivative gain, Kd: Larger values decrease overshoot, but slow down transient response and may lead to instability due to signal noise amplification in the differentiation of the error.

Definitions:

The proportional term P (sometimes called gain) makes a change to the output that is proportional to the current error value. The proportional response is adjusted by multiplying the error by Kp. A high proportional gain results in a large change in the output for a given change in the error.

The integral term I (sometimes called reset) accelerates the movement of the process towards the setpoint and eliminates the residual steady-state error that occurs with a proportional only controller. However, since the integral term is responding to accumulated errors from the past, it can cause the present value to overshoot the setpoint value. The magnitude of the contribution of the integral term to the overall control action is determined by the integral gain, Ki. This implementation uses I += Ki * error * dt. If error is potentially large, using a small Ki gain value may be necessary as the amplitude of I may cause instability.

Integral windup is basically what happens when the controller is pushed into a state where it has reached the maximum output power but the set point has not been reached. In this situation the integral term will continue to grow even though it can no longer have any impact on the controller output. The problem is that when the controller finally manages to get to the set point the integral term may have grown very large and this will cause an overshoot that can take a relatively long time to correct (as the integral value now needs to unwind). Two classic examples are:

This class provides two methods to manage integral windup:
  1. Disabling the integral function until the PV has entered the controllable region
  2. Preventing the integral term from accumulating above or below pre-determined bounds
The derivative term D (sometimes called rate) slows the rate of change of the controller output and this effect is most noticeable close to the controller setpoint. Hence, derivative control is used to reduce the magnitude of the overshoot produced by the integral component (I) and improve the combined controller-process stability. The rate of change of the process error is calculated by determining the slope of the error over time and multiplying this rate of change by the derivative gain Kd. The D term in the controller is highly sensitive to noise in the error term, and can cause a process to become unstable if the noise and the derivative gain Kd are sufficiently large.

It is important to tune the PID controller with an implementation of a consistent delay between calls to doPID() because the MV calc in a PID controller is time-dependent by definition. This implementation provides an optional delay (set in the constructor) and calculates the time delta (dt) between calls to doPID(int) in milliseconds.

Reference: Wikipedia- http://en.wikipedia.org/wiki/PID_controller

Author:
Kirk Thompson, 2/5/2011 <lejos@mosen.net>

Field Summary
static int PID_DEADBAND
          The deadband value ID.
static int PID_I
          The integral accumulator I value.
static int PID_I_LIMITHIGH
          The Integral high limit cutoff value ID.
static int PID_I_LIMITLOW
          The Integral low limit cutoff value ID.
static int PID_KD
          Derivitive term ID
static int PID_KI
          Integral term ID.
static int PID_KP
          Proportional term ID
static int PID_LIMITHIGH
          The MV high limit cutoff value ID.
static int PID_LIMITLOW
          The MV low limit cutoff value ID.
static int PID_PV
          The process variable (PV) value.
static int PID_RAMP_POWER
          The Ramping Exponential value ID.
static int PID_RAMP_THRESHOLD
          The Ramping Threshold value ID.
static int PID_SETPOINT
          The Setpoint value ID.
 
Constructor Summary
PIDController(int setpoint, int msdelay)
          Construct a PID controller instance using passed setpoint (SP) and millisecond delay (used before returning from a call to doPID()).
 
Method Summary
 Logger deregisterDataLogger()
          De-register the registered NXTDataLogger.
 int doPID(int processVariable)
          Do the PID calc for a single iteration.
 void freezeIntegral(boolean status)
          Freeze or resume integral accumulation.
 int getDelay()
          Returns the doPID() timing delay.
 float getPIDParam(int paramID)
          Get PID controller parameters.
 boolean isIntegralFrozen()
           
 boolean registerDataLogger(Logger dataLogger)
          Register a NXTDataLogger instance to log the PID variables.
 void setDelay(int msdelay)
          Set the desired delay before doPID() returns.
 void setPIDParam(int paramID, float value)
          Set PID controller parameters.
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

PID_KP

public static final int PID_KP
Proportional term ID

See Also:
setPIDParam(int, float), getPIDParam(int), Constant Field Values

PID_KI

public static final int PID_KI
Integral term ID. The I accumulator is an int so any decimal places are rounded in the calc: I += Ki * error * dt;

See Also:
setPIDParam(int, float), getPIDParam(int), Constant Field Values

PID_KD

public static final int PID_KD
Derivitive term ID

See Also:
setPIDParam(int, float), getPIDParam(int), Constant Field Values

PID_RAMP_POWER

public static final int PID_RAMP_POWER
The Ramping Exponential value ID. Used for output (MV) ramping/attenuation which determines ramp shape. 1.0=linear, Set to 0.0 to disable output ramping. Larger values >= 1 create steeper ramping curves. 0<PID_RAMP_POWER<1 will invert the curve which will cause exponential MV amplification the closer we get to the SP (would this ever be useful?).

See Also:
setPIDParam(int, float), getPIDParam(int), Constant Field Values

PID_RAMP_THRESHOLD

public static final int PID_RAMP_THRESHOLD
The Ramping Threshold value ID. Used for output ramping. When the PID Manipulated Variable (MV) is within this range (-+), output ramping is applied to MV before it is returned from doPID(int). The value passed to setPIDParam() is cast to an int.

See Also:
setPIDParam(int, float), getPIDParam(int), Constant Field Values

PID_DEADBAND

public static final int PID_DEADBAND
The deadband value ID. Used for output clipping. If MV within +- this range relative to zero, MV of zero is returned. Set to zero to effectively disable. This is useful to avoid hunting around the SP when there is a lot of slop in whatever the controller is controlling i.e. gear & link lash. The value passed to setPIDParam() is cast to an int. Using deadband is process actuator/control-specific and by definition, decreases accuracy of reaching the SP.

See Also:
setPIDParam(int, float), getPIDParam(int), Constant Field Values

PID_LIMITHIGH

public static final int PID_LIMITHIGH
The MV high limit cutoff value ID. Use for high limit cutoff for Manipulated Variable (MV). Set to a large value to effectively disable. This is applied to MV before any ramping. Default is 900 at instantiation. The value passed to setPIDParam() is cast to an int.

See Also:
setPIDParam(int, float), getPIDParam(int), Constant Field Values

PID_LIMITLOW

public static final int PID_LIMITLOW
The MV low limit cutoff value ID. Use for low limit cutoff for Manipulated Variable (MV). Set to a large negative value to effectively disable. This is applied to MV before any ramping. Default is -900. The value passed to setPIDParam() is cast to an int.

See Also:
setPIDParam(int, float), getPIDParam(int), Constant Field Values

PID_SETPOINT

public static final int PID_SETPOINT
The Setpoint value ID. This is the value the PID controller works toward by changing MV is response to the error when doPID() is called. The value passed to setPIDParam() is cast to an int.

See Also:
setPIDParam(int, float), getPIDParam(int), doPID(int), Constant Field Values

PID_I_LIMITLOW

public static final int PID_I_LIMITLOW
The Integral low limit cutoff value ID. Use for limiting accumulation of I (Ki * error * dt) less than a defined value. Set to zero to disable. Default is 0. Setting this clears the I term accumulator. The value passed to setPIDParam() is cast to an int.

This is one methodology to manage integral windup.

See Also:
setPIDParam(int, float), getPIDParam(int), freezeIntegral(boolean), PID_I_LIMITHIGH, Constant Field Values

PID_I_LIMITHIGH

public static final int PID_I_LIMITHIGH
The Integral high limit cutoff value ID. Use for limiting accumulation of I (Ki * error * dt) greater than a defined value. Set to zero to disable. Default is 0. Setting this clears the I term accumulator. The value passed to setPIDParam() is cast to an int.

This is one methodology to manage integral windup.

See Also:
setPIDParam(int, float), getPIDParam(int), freezeIntegral(boolean), PID_I_LIMITLOW, Constant Field Values

PID_I

public static final int PID_I
The integral accumulator I value. Read-only.Calling setPIDParam() with this is ignored. The I value is the accumulator for Ki * error * dt.

See Also:
Constant Field Values

PID_PV

public static final int PID_PV
The process variable (PV) value. Read-only.Calling setPIDParam() with this is ignored. The PV value is the last value passed to doPID().

See Also:
doPID(int), Constant Field Values
Constructor Detail

PIDController

public PIDController(int setpoint,
                     int msdelay)
Construct a PID controller instance using passed setpoint (SP) and millisecond delay (used before returning from a call to doPID()).

Parameters:
setpoint - The goal of the MV
msdelay - The delay in milliseconds. Set to 0 to disable any delay.
See Also:
doPID(int), setDelay(int)
Method Detail

setPIDParam

public void setPIDParam(int paramID,
                        float value)
Set PID controller parameters.

Parameters:
paramID - What parameter to set. See the constant definitions for this class.
value - The value to set it to. Note that some values are cast to int depending on the particular paramID value used.
See Also:
getPIDParam(int)

getPIDParam

public float getPIDParam(int paramID)
Get PID controller parameters.

Parameters:
paramID - What parameter to get. See the constant definitions for this class.
Returns:
The requested parameter value
See Also:
setPIDParam(int, float)

freezeIntegral

public void freezeIntegral(boolean status)
Freeze or resume integral accumulation. If frozen, any pre-existing integral accumulation is still used in the MV calculation. This is useful for disabling the integral function until the PV has entered the controllable region [as defined by your process requirements].

This is one methodology to manage integral windup. This is false by default at instantiation.

Parameters:
status - true to freeze, false to thaw
See Also:
isIntegralFrozen()

isIntegralFrozen

public boolean isIntegralFrozen()
Returns:
true if the integral accumulation is frozen
See Also:
freezeIntegral(boolean)

doPID

public int doPID(int processVariable)
Do the PID calc for a single iteration. Your implementation must provide the delay between calls to this method if you have not set one with setDelay() or in the constructor.

Parameters:
processVariable - The PV value from the process (sensor reading, etc.).
Returns:
The Manipulated Variable MV to input into the process (motor speed, etc.)
See Also:
setDelay(int)

registerDataLogger

public boolean registerDataLogger(Logger dataLogger)
Register a NXTDataLogger instance to log the PID variables. If the logger instance is in cached mode, the headers must not have been set before calling this method or false is returned. PIDController will set the column headers and log values on every call to doPID().

This is useful when using the NXJChartingLogger tool to visualize the PID response by monitoring the internal variables.

Parameters:
dataLogger - A NXTDataLogger instance in realtime or cached logging mode.
Returns:
true if successful, false otherwise.
See Also:
NXTDataLogger, deregisterDataLogger()

deregisterDataLogger

public Logger deregisterDataLogger()
De-register the registered NXTDataLogger.

Returns:
The NXTDataLogger that was registered, null if no logger has been registered.
See Also:
registerDataLogger(lejos.util.Logger)

setDelay

public void setDelay(int msdelay)
Set the desired delay before doPID() returns. Set to zero to effectively disable.

Parameters:
msdelay - Delay in milliseconds
See Also:
getDelay()

getDelay

public int getDelay()
Returns the doPID() timing delay.

Returns:
The delay set by setDelay()
See Also:
setDelay(int)