The Auto Servo Tuning of linuxcncMulti is modelled on the AST of the
SINUMERIK (HMI Operate, "Automat. Servo Optim."): the frequency
responses of a servo axis are measured with a function generator and the
position controller of LinuxCNC is optimised on them. The SINUMERIK
owns the whole cascade - current, speed and position controller - in its
drives. LinuxCNC owns the position controller (pid: P as the Kv factor,
FF1 and FF2 as the velocity and acceleration feedforward) and the
setpoint filters in HAL; the speed loop is closed in the drive (an
analog velocity drive, a CSV drive on EtherCAT) and is measured as the
plant "velocity setpoint → actual velocity", the current loop stays the
drive’s own.
This chapter describes the first stage, the measurement. The evaluation
of the position loop with the strategies, the page in mchmi and the
EtherCAT part follow in the next stages (docs/multichannel/ast.md).
The function generator: mcast
mcast (loadrt mcast count=N, one instance per joint) sits between the
position controller and the drive:
net u pid.x.output => mcast.0.cmd-in net drive-in mcast.0.input-out => hm2_5i25.0.7i77.0.1.analogout0 # or the CSV setpoint net pos-fb ... => mcast.0.pos-fb # the joint's feedback
The controller’s output enters on cmd-in, the excitation is added and
the sum leaves on input-out. Nothing changes while no run is active:
the excitation is 0 and the sum equals the controller’s output. A run
starts with the rising edge of enable and lasts duration seconds;
its signal is selected by mode:
| mode | signal |
|---|---|
1 |
band-limited pseudo-random noise: chips at 2 |
2 |
a logarithmic sine sweep (chirp) from |
3 |
a step: 0 for half a second, then |
4 |
a sine at |
The amplitude ramps in and out over ramp seconds. The travel guard
is the safety of the measurement: when the joint leaves its start
position by more than travel-limit the excitation goes to 0 in the
same servo cycle, fault = 1 and the run ends; a falling enable ends
a run with fault = 2. running, done, progress and travel
report the run; inject-out, input-out and vel-out (the velocity,
vel-fb with use-vel-fb = 1 or derived from pos-fb) are what the
recorder stores.
With open-loop = 1 the controller’s output is not passed on during a
run: the position loop is open and the axis is "free", as in the
SINUMERIK’s measurement of the speed loop. The default keeps the loop
closed - the controller holds the axis, the excitation acts as a
disturbance, and the plant is computed from the measured response and
the controller’s known gains (below). That is the recommended way: the
axis does not drift and nothing jumps when the run ends.
The measurement and its evaluation
mcast-measure runs one measurement from the console against the
running HAL (the machine or a simulation):
mcast-measure --instance mcast.0 --pid pid.x --mode prbs --amplitude 2 \
--f-min 1 --f-max 200 --duration 10 --travel-limit 1 --out x_ast.json
It sets the instance’s parameters, records the excitation, the
controller’s output, the plant input, the velocity and the position at
the servo rate (through sampler, like the circularity test), enables
the run, waits for its end and prints the evaluation: the static gain,
the bandwidth, the resonances found and the coherence; --out writes
the AST file (JSON: settings, the controller’s gains, all samples, the
responses in dB and degrees) for the later stages and for an offline
look.
The evaluation (lib/python/mcast.py, numpy) estimates the frequency
response by the Welch cross-spectrum (H1 = Syu / Suu with the
coherence) in the band of the excitation. The plant is the direct
estimate from the drive’s input - the controller’s output plus the
excitation - to the velocity: y = G u holds with the position loop
closed as well, the estimate is exact without measurement noise and
good while the excitation dominates the noise, which the amplitude and
the coherence show. --pid names the pid instance whose gains are
recorded with the run; they also allow the indirect estimate from the
response to the excitation alone, G = H_r / (1 - H_r C / s) with the
controller C and the integrator velocity → position, which the
evaluation keeps as a check (it amplifies the estimation error where
the loop gain is high, at the low frequencies).
The simulated plant: mcast_plant
For the simulation and the tests mcast_plant stands in for the drive
and the mechanics: the speed loop as a first-order lag (tau), the
mechanics as one resonance (f-res, zeta), a dead time (delay) and
a velocity noise; vel-cmd in, vel, pos and torque (the motor
acceleration, what a drive reports as its actual torque) out. The test
tests/multichannel/ast closes a position loop around it, measures with
noise and checks that the gain, the resonance and the coherence come
out, and that the guard trips on a step beyond the travel limit.
The position loop and its optimisation
lib/python/mcast_opt.py puts LinuxCNC’s position loop on the measured
plant: the setpoint filters F (biquad notch or low-pass on the pid’s
output, modelled with the component’s own coefficients), the controller
C (the discrete pid with P, I, D at the servo period), the plant G and
the integrator velocity → position give the open loop L = C F G / s
and the closed loop T = L / (1 + L). The figures are those of the
SINUMERIK’s AST: the phase margin at the gain crossover, the gain margin
at the phase crossover, the bandwidth (-3 dB of T, and the -90 degree
crossing of T - the "Reglerbandbreite" of the article) and the peak of
the closed loop.
The strategies set the margins to keep:
| strategy | phase margin | gain margin | closed-loop peak |
|---|---|---|---|
schnell (fast) |
40 deg |
8 dB |
3 dB |
normal |
55 deg |
12 dB |
2 dB |
robust |
70 deg |
15 dB |
1 dB |
The optimisation finds the largest P (the Kv factor) that keeps the margins and the peak - a logarithmic scan and a bisection on the measured curves, no model fit. Resonances of the plant beyond the bandwidth that lift the closed loop above -10 dB (the article’s rule) get a notch filter at their frequency (Q 3), at most four filters, and P is searched again with them. The feedforward follows from the plant: FF1 = 1 / gain (the velocity feedforward of a velocity drive), FF2 = equivalent lag / gain, the lag from the slope of the plant’s phase at low frequencies (the speed loop’s lag plus the dead time) - the article’s "FFW maximieren". A manual set of parameters is evaluated the same way without a new measurement, so the curves answer every change at once (the "Manuell" column of Operate).
The result carries P, I, D, FF1, FF2, the filters and the figures;
report() writes it as text, apply_lines() gives the halcmd setp
lines for the pid and the biquad instances (type 2 notch, 1 low-pass,
enable 0 for an unused one) and ini_values() the [JOINT_n] keys
(P, I, D, FF1, FF2, AST_FILTER_k = type f0 Q). The test
tests/multichannel/ast/test_opt.py checks the margins of a known loop,
the strategies, the feedforward, the notch on a strong resonance and
the biquad model against the analytic filter.
The page in mchmi: Antriebsoptimierung
The page Antriebs-optim. of the diagnosis area is the operator’s view, laid out after Operate’s "Automat. Servo Optim.":
-
The form: the axis (one key per joint of
[AST]JOINTS, named by its letter in the channel), the strategy (schnell / normal / robust) and the run - amplitude, f max, duration and the travel limit of the guard, with the defaults of[AST](AMPLITUDE,F_MIN,F_MAX,DURATION,TRAVEL_LIMIT,USE_VEL_FB). -
The table Reglerdaten: the parameter sets Manuell, Optimiert, Aktiv (the gains and filters in HAL now) and Original (the INI at the first visit) with P (Kv), I, D, FF1, FF2, the four filters and, once a measurement exists, their figures: phase margin, gain margin, the bandwidths (-3 dB, -90 degrees) and the peak.
-
The Bode diagram (amplitude in dB and phase over the frequency, log) with a legend of check marks: the measured plant, the coherence, the filters, the open and the closed loop of the set chosen with Anzeige, and the closed loop of the active set for comparison; the -10 dB line, -90 and -180 degrees and the bandwidth are marked.
The softkeys: Messen (a second press within four seconds starts the
run; the machine must be on and idle; Abbrechen while it runs),
Optimieren (the strategy on the last measurement), Übernehmen
Optimiert / Übernehmen Manuell (the set into HAL with setp on the
pid and the biquad instances of [AST]FILTERS_n, and into the INI:
[JOINT_n] P, I, D, FF1, FF2, AST_FILTER_k, the INI backed up as
.bak; the section is found in an #INCLUDE file too), Wert - /
Wert + (the selected row of the manual set by 5 %, a filter’s
frequency likewise), and on the second key page Zurück zu Original,
Optimiert → Manuell, Filtertyp (off, notch, low-pass of the
selected filter row), Speichern (the AST file, the picture and the
report under ast/ below [DISPLAY]PROGRAM_PREFIX), Laden (the
newest file of the axis, evaluated again - the offline look of Operate)
and Anzeige (which set the loop curves are drawn for).
The INI: [AST] JOINTS lists the joints with a mcast instance,
PID_n the pid of joint n (default pid.n), MCAST_n its instance
(default mcast.n), FILTERS_n the biquad instances of its setpoint
filters in the chain (pid → filters → mcast → drive; none means
the optimisation proposes filters that cannot be applied). The sim
configs/sim/multichannel/ast shows the chain for three axes on the
simulated plant with a different resonance each.
EtherCAT drives: the speed loop of the drive
A drive on EtherCAT (CiA 402, through linuxcnc-ethercat) reports more
than an analog one: its actual torque (object 0x6077) and velocity
(0x606C) come as PDOs every servo cycle. The torque goes to torque-in
of mcast (the pin of lcec’s drive, or an analog input that carries a
torque signal; 0 when there is none), and the recording holds it:
-
the mechanical frequency response torque → velocity (the curve Mechanikfrequenzgang of the legend) with its resonances - the "Systemstrecke" of the SINUMERIK;
-
the open speed loop of the drive (curve Offener Drehzahlregelkreis), which needs no torque: the drive’s closed speed loop is the plant normalised to unity gain, T_v, and its open loop L_v = T_v / (1 - T_v); its phase and gain margins and its crossover are the figures of the drive’s own tuning.
The key page Antrieb (the third page of softkeys) works on this: Drehzahlregler rechnen shows the margins of the drive’s loop and, with a torque recorded, the PI speed controller on the mechanics for the chosen strategy: the largest Kp with the strategy’s margins as a P controller, Tn five times the crossover period (not below 5 ms, the article’s rule), Kp searched again with it. Drehzahlregler schreiben writes Kp, Tn or Ki and the notch filters into the drive through SDOs, Antrieb lesen shows the drive’s present values, Antriebs-Autotuning triggers the drive’s own tuning where the family knows the command.
The drive family and the slave come from the INI: [AST] DRIVE_n =
delta-a3 | sinamics-coe | generic, SLAVE_n = the slave’s position on
the bus, MASTER (0). A family is a table lib/python/mcast_drives/
<family>.json that maps the logical parameters (speed_kp, speed_tn
or speed_ki, inertia_ratio, notch1_f, notch1_q or
notch1_depth, notch2_…, lowpass_f, auto_tune as a command) to
the drive’s objects with index, subindex, type, scale and unit; the
reading and writing use the IgH tool (ethercat upload / download).
The tables of the Delta ASDA-A3-E (its parameters Pg.nnn on
0x2000 + g * 0x100 + nnn) and of SINAMICS with CoE (p<n> on 0x2000 + n)
carry the mapping as documented but are marked unverified until a
drive confirmed them: the page says so after a write, and a dry run is
available in mcast_ecat.write_params. The current loop of the drive
stays with its own identification; an EtherCAT cycle of 1 kHz limits
the evaluation to roughly 400 Hz.
Files
| File | Content |
|---|---|
|
the function generator with the travel guard |
|
the simulated plant |
|
settings, the Welch estimate, the closed-loop correction, the measurement, the AST file |
|
the measurement from the console |
|
the evaluation on a known plant, the halrun run with the guard |