Instead of having a separate PID component with auto tuning support, it is easier for users to have only one PID component where auto tuning is a runtime option for those that want to use it. Drop the at_pid HAL component and move its implementation and documentation into the pid HAL component. The code is marked using #ifdef AUTO_TUNING to make it easy to identify in the code, and trivial to compile out for those that want to. There is some questions on how useful and efficient the implemented auto tuning method is, and while I am sure it can be improved, it did work for my machie and provided useful Pgain, Igain and Dgain values for my X and Y axis. As it is a runtime option, those that do not want automatic tuning can simply ignore this feature. Keep the at_pid(9) manual page to let earlier users know to use the pid component instead.
442 lines
18 KiB
Groff
442 lines
18 KiB
Groff
.TH PID "9" "2007-01-16" "LinuxCNC Documentation" "HAL Component"
|
|
|
|
.SH NAME
|
|
pid \- proportional/integral/derivative controller with automatic tuning support
|
|
.SH SYNOPSIS
|
|
\fBloadrt pid [num_chan=\fInum\fB | names=\fIname1\fB[,\fIname2...\fB]] [\fBdebug=\fIdbg\fR]
|
|
|
|
.SH DESCRIPTION
|
|
\fBpid\fR is a classic Proportional/Integral/Derivative controller,
|
|
used to control position or speed feedback loops for servo motors and
|
|
other closed-loop applications.
|
|
.P
|
|
\fBpid\fR supports a maximum of sixteen controllers. The number that
|
|
are actually loaded is set by the \fBnum_chan\fR argument when
|
|
the module is loaded. Alternatively, specify names= and unique names
|
|
separated by commas.
|
|
.P
|
|
The \fBnum_chan=\fR and \fBnames=\fR specifiers are mutually exclusive.
|
|
If neither \fBnum_chan=\fR nor \fBnames=\fR are specified, the default
|
|
value is three. If \fBdebug\fR 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.
|
|
|
|
.P
|
|
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.
|
|
|
|
.P
|
|
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.
|
|
.P
|
|
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.
|
|
.P
|
|
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.
|
|
.P
|
|
The PID gains, limits, and other 'tunable' features of the loop are
|
|
implemented as parameters. These are as follows:
|
|
|
|
.PP
|
|
\fBPgain\fR Proportional gain
|
|
.PD 0
|
|
.P
|
|
.PD
|
|
\fBIgain\fR Integral gain
|
|
.PD 0
|
|
.P
|
|
.PD
|
|
\fBDgain\fR Derivative gain
|
|
.PD 0
|
|
.P
|
|
.PD
|
|
\fBbias\fR Constant offset on output
|
|
.PD 0
|
|
.P
|
|
.PD
|
|
\fBFF0\fR \fR Zeroth order Feedforward gain
|
|
.PD 0
|
|
.P
|
|
.PD
|
|
\fBFF1\fR \fR First order Feedforward gain
|
|
.PD 0
|
|
.P
|
|
.PD
|
|
\fBFF2\fR \fR Second order Feedforward gain
|
|
.PD 0
|
|
.P
|
|
.PD
|
|
\fBFF3\fR \fR Third order Feedforward gain
|
|
.PD 0
|
|
.P
|
|
.PD
|
|
\fBdeadband\fR Amount of error that will be ignored
|
|
.PD 0
|
|
.P
|
|
.PD
|
|
\fBmaxerror\fR Limit on error
|
|
.PD 0
|
|
.P
|
|
.PD
|
|
\fBmaxerrorI\fR Limit on error integrator
|
|
.PD 0
|
|
.P
|
|
.PD
|
|
\fBmaxerrorD\fR Limit on error differentiator
|
|
.PD 0
|
|
.P
|
|
.PD
|
|
\fBmaxcmdD\fR Limit on command differentiator
|
|
.PD 0
|
|
.P
|
|
.PD
|
|
\fBmaxcmdDD\fR Limit on command 2nd derivative
|
|
.PD 0
|
|
.P
|
|
.PD
|
|
\fBmaxcmdDDD\fR Limit on command 3rd derivative
|
|
.PD 0
|
|
.P
|
|
.PD
|
|
\fBmaxoutput\fR Limit on output value
|
|
.P
|
|
All of the limits (max____) are implemented such that if the parameter
|
|
value is zero, there is no limit.
|
|
.P
|
|
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.
|
|
|
|
.PP
|
|
\fBerrorI\fR Integral of error
|
|
.PD 0
|
|
.P
|
|
.PD
|
|
\fBerrorD\fR Derivative of error
|
|
.PD 0
|
|
.P
|
|
.PD
|
|
\fBcommandD\fR Derivative of the command
|
|
.PD 0
|
|
.P
|
|
.PD
|
|
\fBcommandDD\fR 2nd derivative of the command
|
|
.PD 0
|
|
.P
|
|
.PD
|
|
\fBcommandDDD\fR 3rd derivative of the command
|
|
|
|
.P
|
|
The PID loop calculations are as follows (see the code in pid.c for
|
|
all the nitty gritty details):
|
|
.IP
|
|
.nf
|
|
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
|
|
.fi
|
|
|
|
.P
|
|
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 \fBAutomatic Tuning
|
|
of Simple Regulators with Specifications on Phase and Amplitude
|
|
Margins\fR 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, \fBPgain/Igain/Dgain\fR or \fBPgain/Igain/FF1\fR can be
|
|
determined using the Ziegler-Nichols algorithm. When using \fBFF1\fR
|
|
tuning, scaling must be set so that \fBoutput\fR is in user units per
|
|
second.
|
|
|
|
.P
|
|
During auto tuning, the \fBcommand\fR input should not change. The
|
|
limit cycle is setup around the commanded position. No initial tuning
|
|
values are required to start auto tuning. Only \fBtune\-cycles\fR,
|
|
\fBtune\-effort\fR and \fBtune\-mode\fR need be set before starting
|
|
auto tuning. Note that setting \fBtune\-mode\fR 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.
|
|
.P
|
|
To perform auto tuning, take the following steps. Move the axis to be
|
|
tuned somewhere near the center of it's travel. Set
|
|
\fBtune\-cycles\fR (the default value should be fine in most cases)
|
|
and \fBtune\-mode\fR. Set \fBtune\-effort\fR to a small value. Set
|
|
\fBenable\fR to true. Set \fBtune\-mode\fR to true. Set
|
|
\fBtune\-start\fR to true. If no oscillation occurs, or the
|
|
oscillation is too small, slowly increase \fBtune\-effort\fR. Auto
|
|
tuning can be aborted at any time by setting \fBenable\fR or
|
|
\fBtune\-mode\fR to false.
|
|
|
|
.SH NAMING
|
|
The names for pins, parameters, and functions are prefixed as:
|
|
\fBpid.N.\fR for N=0,1,...,num\-1 when using \fBnum_chan=num\fR
|
|
\fBnameN.\fR for nameN=name1,name2,... when using \fBnames=name1,name2,...\fR
|
|
|
|
The \fBpid.N.\fR format is shown in the following descriptions.
|
|
|
|
.SH FUNCTIONS
|
|
|
|
\fBpid.\fIN\fB.do\-pid\-calcs\fR (uses floating-point)
|
|
Does the PID calculations for control loop \fIN\fR.
|
|
|
|
.SH PINS
|
|
|
|
.TP
|
|
\fBpid.\fIN\fB.command\fR float in
|
|
The desired (commanded) value for the control loop.
|
|
.TP
|
|
\fBpid.\fIN\fB.Pgain\fR float in
|
|
Proportional gain. Results in a contribution to the output that is the error
|
|
multiplied by \fBPgain\fR.
|
|
.TP
|
|
\fBpid.\fIN\fB.Igain\fR float in
|
|
Integral gain. Results in a contribution to the output that is the integral
|
|
of the error multiplied by \fBIgain\fR. For example an error of 0.02 that
|
|
lasted 10 seconds would result in an integrated error (\fBerrorI\fR) of 0.2,
|
|
and if \fBIgain\fR is 20, the integral term would add 4.0 to the output.
|
|
.TP
|
|
\fBpid.\fIN\fB.Dgain\fR float in
|
|
Derivative gain. Results in a contribution to the output that is the rate of
|
|
change (derivative) of the error multiplied by \fBDgain\fR. For example an
|
|
error that changed from 0.02 to 0.03 over 0.2 seconds would result in an error
|
|
derivative (\fBerrorD\fR) of of 0.05, and if \fBDgain\fR is 5, the derivative
|
|
term would add 0.25 to the output.
|
|
.TP
|
|
\fBpid.\fIN\fB.feedback\fR float in
|
|
The actual (feedback) value, from some sensor such as an encoder.
|
|
.TP
|
|
\fBpid.\fIN\fB.output\fR float out
|
|
The output of the PID loop, which goes to some actuator such as a motor.
|
|
.TP
|
|
\fBpid.\fIN\fB.command\-deriv\fR float in
|
|
The derivative of the desired (commanded) value for the control loop. If no
|
|
signal is connected then the derivative will be estimated numerically.
|
|
.TP
|
|
\fBpid.\fIN\fB.feedback\-deriv\fR float in
|
|
The derivative of the actual (feedback) value for the control loop. If no
|
|
signal is connected then the derivative will be estimated numerically. When
|
|
the feedback is from a quantized position source (e.g., encoder feedback
|
|
position), behavior of the D term can be improved by using a better velocity
|
|
estimate here, such as the velocity output of encoder(9) or hostmot2(9).
|
|
.TP
|
|
\fBpid.\fIN\fB.error\-previous\-target\fR bit in
|
|
Use previous invocation's target vs. current position for error calculation,
|
|
like the motion controller expects. This may make torque-mode position loops
|
|
and loops requiring a large I gain easier to tune, by eliminating
|
|
velocity\-dependent following error.
|
|
.TP
|
|
\fBpid.\fIN\fB.error\fR float out
|
|
The difference between command and feedback.
|
|
.TP
|
|
\fBpid.\fIN\fB.enable\fR bit in
|
|
When true, enables the PID calculations. When false, \fBoutput\fR is zero,
|
|
and all internal integrators, etc, are reset.
|
|
.TP
|
|
\fBpid.\fIN\fB.index\-enable\fR bit in
|
|
On the falling edge of \fBindex\-enable\fR, pid does not update the
|
|
internal command derivative estimate. On systems which use the encoder
|
|
index pulse, this pin should be connected to the index\-enable signal.
|
|
When this is not done, and FF1 is nonzero, a step change in the input
|
|
command causes a single-cycle spike in the PID output. On systems which use
|
|
exactly one of the \fB\-deriv\fR inputs, this affects the D term as well.
|
|
.TP
|
|
\fBpid.\fIN\fB.bias\fR float in
|
|
\fBbias\fR is a constant amount that is added to the output. In most cases
|
|
it should be left at zero. However, it can sometimes be useful to compensate
|
|
for offsets in servo amplifiers, or to balance the weight of an object that
|
|
moves vertically. \fBbias\fR is turned off when the PID loop is disabled,
|
|
just like all other components of the output. If a non-zero output is needed
|
|
even when the PID loop is disabled, it should be added with an external HAL
|
|
sum2 block.
|
|
.TP
|
|
\fBpid.\fIN\fB.FF0\fR float in
|
|
Zero order feed-forward term. Produces a contribution to the output that is
|
|
\fBFF0\fR multiplied by the commanded value. For position loops, it should
|
|
usually be left at zero. For velocity loops, \fBFF0\fR can compensate for
|
|
friction or motor counter-EMF and may permit better tuning if used properly.
|
|
.TP
|
|
\fBpid.\fIN\fB.FF1\fR float in
|
|
First order feed-forward term. Produces a contribution to the output that
|
|
is \fBFF1\fR multiplied by the derivative of the commanded value. For
|
|
position loops, the contribution is proportional to speed, and can be used
|
|
to compensate for friction or motor CEMF. For velocity loops, it is
|
|
proportional to acceleration and can compensate for inertia. In both
|
|
cases, it can result in better tuning if used properly.
|
|
.TP
|
|
\fBpid.\fIN\fB.FF2\fR float in
|
|
Second order feed-forward term. Produces a contribution to the output that is
|
|
\fBFF2\fR multiplied by the second derivative of the commanded value. For
|
|
position loops, the contribution is proportional to acceleration, and can be
|
|
used to compensate for inertia. For velocity loops, the contribution is
|
|
proportional to jerk, and should usually be left at zero.
|
|
.TP
|
|
\fBpid.\fIN\fB.FF3\fR float in
|
|
Third order feed-forward term. Produces a contribution to the output that is
|
|
\fBFF3\fR multiplied by the third derivative of the commanded value. For
|
|
position loops, the contribution is proportional to jerk, and can be
|
|
used to compensate for residual errors during acceleration. For velocity
|
|
loops, the contribution is proportional to snap(jounce), and should usually
|
|
be left at zero.
|
|
.TP
|
|
\fBpid.\fIN\fB.deadband\fR float in
|
|
Defines a range of "acceptable" error. If the absolute value of \fBerror\fR
|
|
is less than \fBdeadband\fR, it will be treated as if the error is zero.
|
|
When using feedback devices such as encoders that are inherently quantized,
|
|
the deadband should be set slightly more than one-half count, to prevent
|
|
the control loop from hunting back and forth if the command is between two
|
|
adjacent encoder values. When the absolute value of the error is greater
|
|
than the deadband, the deadband value is subtracted from the error before
|
|
performing the loop calculations, to prevent a step in the transfer function
|
|
at the edge of the deadband. (See \fBBUGS\fR.)
|
|
.TP
|
|
\fBpid.\fIN\fB.maxoutput\fR float in
|
|
Output limit. The absolute value of the output will not be permitted
|
|
to exceed \fBmaxoutput\fR, unless \fBmaxoutput\fR is zero. When the output
|
|
is limited, the error integrator will hold instead of integrating, to prevent
|
|
windup and overshoot.
|
|
.TP
|
|
\fBpid.\fIN\fB.maxerror\fR float in
|
|
Limit on the internal error variable used for P, I, and D. Can be used to
|
|
prevent high \fBPgain\fR values from generating large outputs under conditions
|
|
when the error is large (for example, when the command makes a step change).
|
|
Not normally needed, but can be useful when tuning non-linear systems.
|
|
.TP
|
|
\fBpid.\fIN\fB.maxerrorD\fR float in
|
|
Limit on the error derivative. The rate of change of error used by the
|
|
\fBDgain\fR term will be limited to this value, unless the value is
|
|
zero. Can be used to limit the effect of \fBDgain\fR and prevent large
|
|
output spikes due to steps on the command and/or feedback. Not normally
|
|
needed.
|
|
.TP
|
|
\fBpid.\fIN\fB.maxerrorI\fR float in
|
|
Limit on error integrator. The error integrator used by the \fBIgain\fR
|
|
term will be limited to this value, unless it is zero. Can be used to prevent
|
|
integrator windup and the resulting overshoot during/after sustained errors.
|
|
Not normally needed.
|
|
.TP
|
|
\fBpid.\fIN\fB.maxcmdD\fR float in
|
|
Limit on command derivative. The command derivative used by \fBFF1\fR will
|
|
be limited to this value, unless the value is zero. Can be used to prevent
|
|
\fBFF1\fR from producing large output spikes if there is a step change on the
|
|
command. Not normally needed.
|
|
.TP
|
|
\fBpid.\fIN\fB.maxcmdDD\fR float in
|
|
Limit on command second derivative. The command second derivative used by
|
|
\fBFF2\fR will be limited to this value, unless the value is zero. Can be
|
|
used to prevent \fBFF2\fR from producing large output spikes if there is a
|
|
step change on the command. Not normally needed.
|
|
.TP
|
|
\fBpid.\fIN\fB.maxcmdDDD\fR float in
|
|
Limit on command third derivative. The command third derivative used by
|
|
\fBFF3\fR will be limited to this value, unless the value is zero. Can be
|
|
used to prevent \fBFF3\fR from producing large output spikes if there is a
|
|
step change on the command. Not normally needed.
|
|
.TP
|
|
\fBpid.\fIN\fB.saturated\fR bit out
|
|
When true, the current PID output is saturated. That is,
|
|
.RS 12
|
|
\fBoutput\fR = \(+- \fBmaxoutput\fR.
|
|
.RE
|
|
.TP
|
|
\fBpid.\fIN\fB.saturated\-s\fR float out
|
|
.br
|
|
.ns
|
|
.TP
|
|
\fBpid.\fIN\fB.saturated\-count\fR s32 out
|
|
When true, the output of PID was continually saturated for this many seconds
|
|
(\fBsaturated\-s\fR) or periods (\fBsaturated\-count\fR).
|
|
|
|
.SS Additional auto tuning pins
|
|
.TP
|
|
\fBpid.\fIN\fB.tune\-mode\fR bit in
|
|
When true, enables auto tune mode. When false, normal PID calculations are
|
|
performed.
|
|
.TP
|
|
\fBpid.\fIN\fB.tune\-start\fR bit io
|
|
When set to true, starts auto tuning. Cleared when the auto tuning completes.
|
|
.TP
|
|
\fBpid.\fIN\fB.tune\-type\fR u32 rw
|
|
When set to 0, \fBPgain/Igain/Dgain\fR are calculated. When set to 1,
|
|
\fBPgain/Igain/FF1\fR are calculated.
|
|
.TP
|
|
\fBpid.\fIN\fB.tune\-cycles\fR u32 rw
|
|
Determines the number of cycles to run to characterize the process.
|
|
\fBtune\-cycles\fR actually sets the number of half cycles. More cycles results
|
|
in a more accurate characterization as the average of all cycles is used.
|
|
.TP
|
|
\fBpid.\fIN\fB.tune\-effort\fR float rw
|
|
Determines the effort used in setting up the limit cycle in the process.
|
|
\fBtune\-effort\fR should be set to a positive value less than \fBmaxoutput\fR.
|
|
Start with something small and work up to a value that results in a good
|
|
portion of the maximum motor current being used. The smaller the value, the
|
|
smaller the amplitude of the limit cycle.
|
|
.TP
|
|
\fBpid.\fIN\fB.ultimate\-gain\fR float ro (only if debug=1)
|
|
Determined from process characterization. \fBultimate\-gain\fR is the ratio of
|
|
\fBtune\-effort\fR to the limit cycle amplitude multiplied by 4.0 divided by Pi.
|
|
.TP
|
|
\fBpid.\fIN\fB.ultimate\-period\fR float ro (only if debug=1)
|
|
Determined from process characterization. \fBultimate\-period\fR is the period
|
|
of the limit cycle.
|
|
|
|
.SH PARAMETERS
|
|
.TP
|
|
\fBpid.\fIN\fB.errorI\fR float ro (only if debug=1)
|
|
Integral of error. This is the value that is multiplied by \fBIgain\fR to produce the Integral term of the output.
|
|
.TP
|
|
\fBpid.\fIN\fB.errorD\fR float ro (only if debug=1)
|
|
Derivative of error. This is the value that is multiplied by \fBDgain\fR to produce the Derivative term of the output.
|
|
.TP
|
|
\fBpid.\fIN\fB.commandD\fR float ro (only if debug=1)
|
|
Derivative of command. This is the value that is multiplied by \fBFF1\fR to produce the first order feed-forward term of the output.
|
|
.TP
|
|
\fBpid.\fIN\fB.commandDD\fR float ro (only if debug=1)
|
|
Second derivative of command. This is the value that is multiplied by
|
|
\fBFF2\fR to produce the second order feed-forward term of the output.
|
|
.TP
|
|
\fBpid.\fIN\fB.commandDDD\fR float ro (only if debug=1)
|
|
Third derivative of command. This is the value that is multiplied by
|
|
\fBFF3\fR to produce the third order feed-forward term of the output.
|
|
|
|
.SH BUGS
|
|
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 \fBpid\fR. 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.
|