Skip to content

Commit b02b45c

Browse files
authored
Merge pull request #1868 from petterreinholdtsen/pid-autotune-doc-zero
Adjusted at_pid documentation and logic
2 parents ecdea1a + 9b5c4b8 commit b02b45c

2 files changed

Lines changed: 51 additions & 40 deletions

File tree

docs/man/man9/at_pid.9

Lines changed: 33 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,11 @@
11
.TH AT_PID "9" "2007-01-16" "LinuxCNC Documentation" "HAL Component"
22

33
.SH NAME
4-
at_pid \- proportional/integral/derivative controller
4+
at_pid \- proportional/integral/derivative controller with automatic tuning support
55
.SH SYNOPSIS
66
\fBloadrt at_pid [num_chan=\fInum\fB | names=\fIname1\fB[,\fIname2...\fB]] [\fBdebug=\fIdbg\fR]
77

88
.SH DESCRIPTION
9-
\fBNOTE:\fR The auto-tuning part of this component have seen
10-
no development since 2011.
11-
.P
129
\fBat_pid\fR is a classic Proportional/Integral/Derivative controller,
1310
used to control position or speed feedback loops for servo motors and
1411
other closed-loop applications.
@@ -165,26 +162,38 @@ limit output to +/- maxoutput
165162
.fi
166163

167164
.P
168-
This component has a built in auto tune mode. It works by setting up a limit
169-
cycle to characterize the process. From this, \fBPgain/Igain/Dgain\fR or
170-
\fBPgain/Igain/FF1\fR can be determined using Ziegler-Nichols. When using
171-
\fBFF1\fR, scaling must be set so that \fBoutput\fR is in user units per second.
172-
.P
173-
During auto tuning, the \fBcommand\fR input should not change. The limit
174-
cycle is setup around the commanded position. No initial tuning values are
175-
required to start auto tuning. Only \fBtune\-cycles\fR, \fBtune\-effort\fR
176-
and \fBtune\-mode\fR need be set before starting auto tuning. When auto tuning
177-
completes, the tuning parameters will be set. If running from LinuxCNC, the
178-
FERROR setting for the axis being tuned may need to be loosened up as it must
179-
be larger than the limit cycle amplitude in order to avoid a following error.
180-
.P
181-
To perform auto tuning, take the following steps. Move the axis to be tuned,
182-
to somewhere near the center of it's travel. Set \fBtune\-cycles\fR (the
183-
default value should be fine in most cases) and \fBtune\-mode\fR. Set
184-
\fBtune\-effort\fR to a small value. Set \fBenable\fR to true. Set
185-
\fBtune\-mode\fR to true. Set \fBtune\-start\fR to true. If no oscillation
186-
occurs, or the oscillation is too small, slowly increase \fBtune\-effort\fR.
187-
Auto tuning can be aborted at any time by setting \fBenable\fR or
165+
This component has a built in auto tune mode. It works by setting up a
166+
limit cycle to characterize the process. This is called the Relay
167+
method and described in the 1984 Automation paper \fBAutomatic Tuning
168+
of Simple Regulators with Specifications on Phase and Amplitude
169+
Margins\fR by Karl Johan Åström and Tore Hägglund
170+
(doi:10.1016/0005-1098(84)90014-1),
171+
https://lup.lub.lu.se/search/ws/files/6340936/8509157.pdf. Using this
172+
method, \fBPgain/Igain/Dgain\fR or \fBPgain/Igain/FF1\fR can be
173+
determined using the Ziegler-Nichols algorithm. When using \fBFF1\fR
174+
tuning, scaling must be set so that \fBoutput\fR is in user units per
175+
second.
176+
177+
.P
178+
During auto tuning, the \fBcommand\fR input should not change. The
179+
limit cycle is setup around the commanded position. No initial tuning
180+
values are required to start auto tuning. Only \fBtune\-cycles\fR,
181+
\fBtune\-effort\fR and \fBtune\-mode\fR need be set before starting
182+
auto tuning. Note that setting \fBtune\-mode\fR to true disable the
183+
control loop. When auto tuning completes, the tuning parameters will
184+
be set, the output set to bias and the controller still be
185+
disabled. If running from LinuxCNC, the FERROR setting for the axis
186+
being tuned may need to be loosened up as it must be larger than the
187+
limit cycle amplitude in order to avoid a following error.
188+
.P
189+
To perform auto tuning, take the following steps. Move the axis to be
190+
tuned somewhere near the center of it's travel. Set
191+
\fBtune\-cycles\fR (the default value should be fine in most cases)
192+
and \fBtune\-mode\fR. Set \fBtune\-effort\fR to a small value. Set
193+
\fBenable\fR to true. Set \fBtune\-mode\fR to true. Set
194+
\fBtune\-start\fR to true. If no oscillation occurs, or the
195+
oscillation is too small, slowly increase \fBtune\-effort\fR. Auto
196+
tuning can be aborted at any time by setting \fBenable\fR or
188197
\fBtune\-mode\fR to false.
189198

190199
.SH NAMING

src/hal/components/at_pid.c

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,8 @@ RTAPI_MP_ARRAY_STRING(names, MAX_CHAN,"at_pid names");
154154
static int debug = 0; /* flag to export optional params */
155155
RTAPI_MP_INT(debug, "enables optional params");
156156

157+
#define NAME "AT_PID"
158+
157159
#define AUTO_TUNER 1
158160
#ifdef AUTO_TUNER
159161
#include "rtapi_math.h"
@@ -296,7 +298,7 @@ int rtapi_app_main(void)
296298
/* test for number of channels */
297299
if ((howmany <= 0) || (howmany > MAX_CHAN)) {
298300
rtapi_print_msg(RTAPI_MSG_ERR,
299-
"AT_PID: ERROR: invalid number of channels: %d\n", howmany);
301+
NAME ": ERROR: invalid number of channels: %d\n", howmany);
300302
return -1;
301303
}
302304
/* have good config info, connect to the HAL */
@@ -308,7 +310,7 @@ int rtapi_app_main(void)
308310
/* allocate shared memory for pid loop data */
309311
pid_array = hal_malloc(howmany * sizeof(hal_pid_t));
310312
if (pid_array == 0) {
311-
rtapi_print_msg(RTAPI_MSG_ERR, "AT_PID: ERROR: hal_malloc() failed\n");
313+
rtapi_print_msg(RTAPI_MSG_ERR, NAME ": ERROR: hal_malloc() failed\n");
312314
hal_exit(comp_id);
313315
return -1;
314316
}
@@ -326,12 +328,12 @@ int rtapi_app_main(void)
326328

327329
if (retval != 0) {
328330
rtapi_print_msg(RTAPI_MSG_ERR,
329-
"AT_PID: ERROR: loop %d var export failed\n", n);
331+
NAME ": ERROR: loop %d var export failed\n", n);
330332
hal_exit(comp_id);
331333
return -1;
332334
}
333335
}
334-
rtapi_print_msg(RTAPI_MSG_INFO, "AT_PID: installed %d PID loops\n",
336+
rtapi_print_msg(RTAPI_MSG_INFO, NAME ": installed %d PID loops\n",
335337
howmany);
336338
hal_ready(comp_id);
337339
return 0;
@@ -444,22 +446,22 @@ Pid_AutoTune(hal_pid_t *pid, long period)
444446
if(pid->cycleCount < *(pid->tuneCycles))
445447
break;
446448

447-
// Calculate PID.
449+
// Calculate PID using Relay (Åström-Hägglund) method
448450
*(pid->ultimateGain) = (4.0 * fabs(*(pid->tuneEffort)))/(PI * pid->avgAmplitude);
449451
*(pid->ultimatePeriod) = 2.0 * pid->totalTime / *(pid->tuneCycles);
450452
*(pid->ff0gain) = 0;
451453
*(pid->ff2gain) = 0;
452454

453455
if(*(pid->tuneType) == TYPE_PID){
454-
// PID.
456+
// insert ultimate gain and period in Ziegler-Nichols PID method
455457
*(pid->pgain) = 0.6 * *(pid->ultimateGain);
456-
*(pid->igain) = *(pid->pgain) / (*(pid->ultimatePeriod) / 2.0);
457-
*(pid->dgain) = *(pid->pgain) * (*(pid->ultimatePeriod) / 8.0);
458+
*(pid->igain) = 1.2 * *(pid->ultimateGain) / (*(pid->ultimatePeriod));
459+
*(pid->dgain) = (3.0/40.0) * *(pid->ultimateGain) * *(pid->ultimatePeriod);
458460
*(pid->ff1gain) = 0;
459461
}else{
460-
// PI FF1.
462+
// insert ultimate gain and period in Ziegler-Nichols PI method
461463
*(pid->pgain) = 0.45 * *(pid->ultimateGain);
462-
*(pid->igain) = *(pid->pgain) / (*(pid->ultimatePeriod) / 1.2);
464+
*(pid->igain) = 0.54 * *(pid->ultimateGain) / (*(pid->ultimatePeriod));
463465
*(pid->dgain) = 0;
464466

465467
// Scaling must be set so PID output is in user units per second.
@@ -470,8 +472,8 @@ Pid_AutoTune(hal_pid_t *pid, long period)
470472

471473
case STATE_TUNE_ABORT:
472474
default:
473-
// Force output to zero.
474-
*pid->output = 0;
475+
// Force output to bias.
476+
*pid->output = *(pid->bias);
475477

476478
// Abort any tuning cycle in progress.
477479
*pid->pTuneStart = 0;
@@ -693,8 +695,8 @@ static int export_pid(hal_pid_t * addr, char * prefix)
693695
logging if msg_level is at INFO or ALL. So we save the current value
694696
of msg_level and restore it later. If you actually need to log this
695697
function's actions, change the second line below */
696-
// msg = rtapi_get_msg_level();
697-
// rtapi_set_msg_level(RTAPI_MSG_WARN);
698+
msg = rtapi_get_msg_level();
699+
rtapi_set_msg_level(RTAPI_MSG_WARN);
698700

699701
/* export pins */
700702
retval = hal_pin_bit_newf(HAL_IN, &(addr->enable), comp_id,
@@ -966,11 +968,11 @@ static int export_pid(hal_pid_t * addr, char * prefix)
966968
hal_export_funct(buf, calc_pid, addr, 1, 0, comp_id);
967969
if (retval != 0) {
968970
rtapi_print_msg(RTAPI_MSG_ERR,
969-
"AT_PID: ERROR: do_pid_calcs funct export failed\n");
971+
NAME ": ERROR: do_pid_calcs funct export failed\n");
970972
hal_exit(comp_id);
971973
return -1;
972974
}
973975
/* restore saved message level */
974-
// rtapi_set_msg_level(msg);
976+
rtapi_set_msg_level(msg);
975977
return 0;
976978
}

0 commit comments

Comments
 (0)