Skip to content

Commit 9b5c4b8

Browse files
Adjusted at_pid documentation and logic
Made sure output is set to bias, not zero, when tuning cycle ends. Added reference to paper describing the tuning method implemented. Reinserted code to supress some messages while running, similar to the pid component. Adjusted man page text to better explain how to use auto tuning.
1 parent feb8b23 commit 9b5c4b8

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)