PID(9) | HAL Component | PID(9) |
pid - proportional/integral/derivative controller with automatic tuning support
loadrt pid [num_chan=num | names=name1[,name2...]] [debug=dbg]
pid is a classic Proportional/Integral/Derivative controller, used to control position or speed feedback loops for servo motors and other closed-loop applications.
pid supports a maximum of sixteen controllers. The number that are actually loaded is set by the num_chan argument when the module is loaded. Alternatively, specify names= and unique names separated by commas.
The num_chan= and names= specifiers are mutually exclusive. If neither num_chan= nor names= are specified, the default value is three. If debug is set to 1 (the default is 0), some additional HAL parameters will be exported, which might be useful for tuning, but are otherwise unnecessary.
In the following description, it is assumed that we are discussing position loops. However this component can be used to implement other loops such as speed loops, torch height control, and others.
Each loop has a number of pins and parameters, whose names begin with 'pid.N.', where 'N' is the channel number. Channel numbers start at zero.
The three most important pins are 'command', 'feedback', and 'output'. For a position loop, 'command' and 'feedback' are in position units. For a linear axis, this could be inches, mm, metres, or whatever is relevant. Likewise, for a angular axis, it could be degrees, radians, etc. The units of the 'output' pin represent the change needed to make the feedback match the command. As such, for a position loop 'output' is a velocity, in inches/sec, mm/sec, degrees/sec, etc.
Each loop has several other pins as well. 'error' is equal to 'command' minus 'feedback'. 'enable' is a bit that enables the loop. If 'enable' is false, all integrators are reset, and the output is forced to zero. If 'enable' is true, the loop operates normally.
The PID gains, limits, and other 'tunable' features of the loop are implemented as parameters. These are as follows:
Pgain Proportional gain
Igain Integral gain
Dgain Derivative gain
bias Constant offset on output
FF0 Zeroth order Feedforward gain
FF1 First order Feedforward gain
FF2 Second order Feedforward gain
FF3 Third order Feedforward gain
deadband Amount of error that will be ignored
maxerror Limit on error
maxerrorI Limit on error integrator
maxerrorD Limit on error differentiator
maxcmdD Limit on command differentiator
maxcmdDD Limit on command 2nd derivative
maxcmdDDD Limit on command 3rd derivative
maxoutput Limit on output value
All of the limits (max____) are implemented such that if the parameter value is zero, there is no limit.
A number of internal values which may be useful for testing and tuning are also available as parameters. To avoid cluttering the parameter list, these are only exported if "debug=1" is specified on the insmod command line.
errorI Integral of error
errorD Derivative of error
commandD Derivative of the command
commandDD 2nd derivative of the command
commandDDD 3rd derivative of the command
The PID loop calculations are as follows (see the code in pid.c for all the nitty gritty details):
error = command - feedback if ( abs(error) < deadband ) then error = 0 limit error to +/- maxerror errorI += error * period limit errorI to +/- maxerrorI errorD = (error - previouserror) / period limit errorD to +/- maxerrorD commandD = (command - previouscommand) / period limit commandD to +/- maxcmdD commandDD = (commandD - previouscommandD) / period limit commandDD to +/- maxcmdDD commandDDD = (commandDD - previouscommandDD) / period limit commandDDD to +/- maxcmdDDD output = bias + error * Pgain + errorI * Igain +
errorD * Dgain + command * FF0 + commandD * FF1 +
commandDD * FF2 + commandDDD * FF3 limit output to +/- maxoutput
This component has a built in auto tune mode. It works by setting up a limit cycle to characterize the process. This is called the Relay method and described in the 1984 Automation paper Automatic Tuning of Simple Regulators with Specifications on Phase and Amplitude Margins by Karl Johan Åström and Tore Hägglund (doi:10.1016/0005-1098(84)90014-1), https://lup.lub.lu.se/search/ws/files/6340936/8509157.pdf. Using this method, Pgain/Igain/Dgain or Pgain/Igain/FF1 can be determined using the Ziegler-Nichols algorithm. When using FF1 tuning, scaling must be set so that output is in user units per second.
During auto tuning, the command input should not change. The limit cycle is setup around the commanded position. No initial tuning values are required to start auto tuning. Only tune-cycles, tune-effort and tune-mode need be set before starting auto tuning. Note that setting tune-mode to true disable the control loop. When auto tuning completes, the tuning parameters will be set, the output set to bias and the controller still be disabled. If running from LinuxCNC, the FERROR setting for the axis being tuned may need to be loosened up, as it must be larger than the limit cycle amplitude in order to avoid a following error.
To perform auto tuning, take the following steps. Move the axis to be tuned somewhere near the center of it's travel. Set tune-cycles (the default value should be fine in most cases) and tune-mode. Set tune-effort to a small value. Set enable to true. Set tune-mode to true. Set tune-start to true. If no oscillation occurs, or the oscillation is too small, slowly increase tune-effort. Set tune-start to true. If no oscillation occurs, or the oscillation is too small, slowly increase tune-effort Auto tuning can be aborted at any time by setting enable or tune-mode to false.
The names for pins, parameters, and functions are prefixed as:
pid.N. for N=0,1,...,num-1 when using num_chan=num
nameN. for nameN=name1,name2,... when using
names=name1,name2,...
The pid.N. format is shown in the following descriptions.
pid.N.do-pid-calcs (uses floating-point) Does the PID calculations for control loop N.
Some people would argue that deadband should be implemented such that error is treated as zero if it is within the deadband, and be unmodified if it is outside the deadband. This was not done because it would cause a step in the transfer function equal to the size of the deadband. People who prefer that behavior are welcome to add a parameter that will change the behavior, or to write their own version of pid. However, the default behavior should not be changed.
Negative gains may lead to unwanted behavior. It is possible in some situations that negative FF gains make sense, but in general all gains should be positive. If some output is in the wrong direction, negating gains to fix it is a mistake; set the scaling correctly elsewhere instead.
2007-01-16 | LinuxCNC Documentation |