SL_SEQ #
Brief #
The sl_seq component starts a motor without an encoder and hands it to
the observer (obs), for a PMSM and an induction motor alike.
States #
- off:
en= 0. Everything reset, obs tracks. - align: current
i_fon d at a standing frame foralign_time. PMSM: the rotor turns onto the d axis. Induction motor: the flux builds (about 3 tr, what align_time 0 uses). - I/f: the frame turns at
f, which ramps towardvel_cmdatacc, withi_fon d. The rotor follows the rotating current. obs tracks the frame beloww_hand/ 2, so it starts with the right direction, then runs free. - observer: angle0 from obs (src 2), d and q from the drive (
d_in,q_in, pmsm_ttc0 or acim_foc0),pid_en= 1, pid closes the speed loop on obs0.vel_m, while d goes from i_f to d_in overfade_timeso the current does not step. Entered once obs is ok, |f| >= w_hand and obs ran freelock_time. Back to 2 when obs drops ok or |obs0.vel_m| < w_hand - hyst, with f seeded from obs0.vel_m.
vel_ref and acc_ref replace the command into pid: they follow f in I/f
and, from the handover, ramp from the observed speed to vel_cmd at acc,
so the handover is bumpless and pid gets acceleration feedforward.
Encoder plausibility guard (optional, enc_tol > 0, needs vel_enc from
an encoder with the same sign and scale as obs0.vel_m, e.g. a spindle
orientation encoder). The tolerance is enc_tol times the slip model’s own
limit, slip_max (acim_flux0.slip_max, electrical) / polecount, so about 1
fits any motor: in I/f the frequency stays within it of the encoder speed,
so a rotor that does not follow is not left behind. In state 3 an observer
speed further than it from the encoder for enc_time
falls back to I/f, seeded from the encoder, and sets enc_err (link it to a
fault input to trip instead). Steady, slip_err is the
slip model’s error, a check on acim_flux0.tr without the MRAS (the sl_acim
template links it to acim_flux0.slip_err, for tr_ks). Outside state 3
there is no observer speed to compare, so slip_err is held at 0 and tr_ks
does not adapt on the last value. enc_tol 0 = off.
Defaults from the motor (each 0 = derived, a value set in the config wins):
align_time0 = 3 *tr(acim_flux0.tr: the flux has built), 0.3 s without tr (PMSM: the rotor has turned onto d).w_hand0 = the speed where the emf is 5 *e_min(obs0.e_min, the observer’s own trust level): 5 * e_min / (polecount * flux), flux =psi(conf0.psi, PMSM) orlmr* i_f (acim_flux0.lmr, induction motor after align). 50 rad/s without either.obs_bw= 5 *hand* polecount, the observer bandwidth. The sl_acim template links obs0.bw to it (it used to be set by hand, spindle 300); an obs0.bw in the config wins.
Speeds are mechanical rad/s. vel_e is f * polecount.
Low speed: below w_hand - hyst the drive is in I/f, with no speed loop and no torque control, so that is the lowest closed loop speed. w_hand belongs where the emf, w_hand * polecount * lmr * i_f (PMSM: psi), is about 5 times obs0.e_min, which is what w_hand 0 derives; the sl_acim template links i_f to acim_foc0.id_n, so the induction motor’s flux is the rated one.
Pins #
| Name | Description |
|---|---|
| en | input, fault0.en_pid |
| vel_cmd | input, speed command [rad/s mech], vel0.vel |
| polecount | parameter, pole pairs |
| i_f | parameter, align and I/f current on d [A peak], default 3, sl_acim links acim_foc0.id_n |
| align_time | parameter, [s], 0 = 3 * tr |
| acc | parameter, I/f acceleration [rad/s^2 mech] |
| w_hand | parameter, handover speed [rad/s mech], 0 = from e_min and the flux |
| hyst | parameter, fall back below w_hand - hyst [rad/s mech], 0 = w_hand / 3 |
| lock_time | parameter, obs free running before handover [s] |
| fade_time | parameter, i_f fades out over this after the handover [s] |
| obs_ok | input, obs0.ok |
| obs_vel | input, obs0.vel_m |
| d_in | input, d current from the drive in state 3 |
| q_in | input, q current from the drive in state 3 |
| state | output |
| f | output, I/f frequency [rad/s mech] |
| vel_e | output, to angle0.vel_cmd [rad/s electrical] |
| src | output, to angle0.src |
| track | output, to obs0.track |
| pid_en | output, to pid0.en |
| d_cmd | output, to hv0.d_cmd |
| q_cmd | output, to hv0.q_cmd |
| vel_ref | output, speed command for pid [rad/s mech], to pid0.vel_ext_cmd |
| acc_ref | output, its slope [rad/s^2], to pid0.acc_ext_cmd |
| vel_enc | input, encoder rotor speed [rad/s mech], for the guard |
| enc_tol | parameter, allowed abs(speed - vel_enc) as a multiple of slip_max, 0 = no guard |
| slip_max | parameter, slip limit [rad/s electrical], acim_flux0.slip_max |
| enc_time | parameter, observer error longer than this falls back [s] |
| enc_err | output, 1 = observer disagreed with the encoder, held until en 0 |
| slip_err | output, obs0.vel_m - vel_enc in state 3, 1 Hz low pass, 0 in the other states [rad/s mech] |
| tr | input, rotor time constant [s], acim_flux0.tr, for align_time 0 |
| psi | input, magnet flux [V s], conf0.psi, for w_hand 0 (PMSM) |
| lmr | input, magnetizing inductance [H], acim_flux0.lmr, for w_hand 0 (induction motor) |
| e_min | input, obs0.e_min [V], for w_hand 0, default 3 |
| align | output, align time in use [s] |
| hand | output, handover speed in use [rad/s mech] |
| obs_bw | output, observer bandwidth for obs0.bw, 5 x hand x polecount [rad/s electrical] |
References #
Source: .c File