BLDC control FOC: Questions answered - Page 1
Forum section: electronics / general

author: eTobey
author_rank: Super Contributor
timestamp: December 01, 2023, 11:16:14 am
content: Hi,i had some research into BLDC FOC, and i am a bit confused. zerovectors as i understand are used, to limit the voltage magnitude.These zerovectors are shorting the phases of the motor to either GND or Vcc. But i know that shorting the phases of a motor will make it brake. That sounds like stepping on the gaspedal and the brakepedal over and over again. Wouldnt it be much better to just slightly push the gaspedal?

author: Siwastaja
author_rank: Super Contributor
timestamp: December 01, 2023, 05:12:28 pm
content: I have implemented BLDC FOC numerous times but never heard the term "zerovector"."Shorting" the phases is normal operation in all operating modes, FOC or otherwise, with any setpoint. Maybe what you are missing is how the motor inductance acts as a triangular ramp generator; you always either apply full DC input voltage, or full short alternatively and the current ripples around your desired current. No problem here.But such shorting only happens for a short time and not 100% duty cycle*. During this shorting, due to the back-EMF the rotating motor generates, current in motor windings is increasing. Once you remove the short, the inductance then pushes the inductance-stored energy into the DC link / battery if there is one. Motor will brake, and kinetic energy flows into the inverter supply side.*) except when the motor is at standstillIf you apply the short infinitely, you are just increasing the current towards infinity, saturating the motor iron, and dissipating all kinetic energy in motor winding resistance, instead of pushing it into DC link (and either into battery, or into an external resistor bank). Current and torque is uncontrolled and too much. There is usually no reason to ever do this on purpose. With FOC, the idea is to measure the current and PI feedback the duty cycle such that current is whatever value you wish. If you want to brake hard, you can choose pretty high current, but aiming for "infinite" makes no sense.

author: Siwastaja
author_rank: Super Contributor
timestamp: December 01, 2023, 06:01:00 pm
content: If you are familiar with the synchronous buck converter topology, it helps to understand motor control is basically that. Output voltage, which is smaller than input voltage, represents the RPM. Output capacitance represents the mechanical inertia. The buck inductor is motor inductance.Let's say Vin=10V, rated RPM = 1000 rpm @ 10V. Then at 20% duty cycle, in steady state conditions assuming 100% efficiency, assuming enough load to operate in Continuous Conduction Mode, output voltage would be 2V and motor would run at 200 rpm. Apply mechanical force trying to speed up the motor, and now the ideal motor would be generating infinite current, boosting it from 2V to 10V (Vin). Or, add mechanical force slowing down the motor, and now it's trying to hog infinite current from Vin. This infinite current would generate infinite torque and quickly overcome the mechanical force and find the equilibrium again.In real motors, say for example a simple brushed motor, this can be seen as high inrush currents: connect a large DC motor directly to a 12V battery and it takes massive so-called "stall" current which then diminishes once it reaches full rated RPM. This is not a good way to control motors; motor iron saturates (there is a limit how much torque it can actually generate; current keeps increasing only limited by resistance), so efficiency plummets. Too much torque and cause mechanical damage.While RPM is trivial to control by adjusting duty cycle, it clearly isn't the only thing we want to control; we want to control torque, at very leastlimitit to reduce the rate of motor reaching the speed equilibrium, to prevent things breaking up, to limit electrical current. So add current limit; for this you need to sense current and feedback the duty cycle. This is easier than it initially sounds because motors have a lot of inductance; current changes slowly. You can apply full input voltage, or zero voltage (short) and current rises or lowers. You have many microseconds to measure and react, easy peasy for most current sense amplifiers, microcontroller peripherals etc.Now instead of controlling duty cycle to control RPM and adding a current limit on top, the idea of FOC (and many other control strategies) is to make the current (~ torque) the only primary control parameter, so that RPM is not controlled at all by this scheme, but by an optional outer feedback loop (which controls the FOC input, current, capped to some limit).Now all that FOC really is, over a simple single-phase synchronous buck DC/DC, is a way of decoupling the rotational movement of a three-phase machine, from the current measurement -> duty cycle PI feedback loop. It is much easier to think about the basic concepts in the realm of a simple brushed DC motor, or synchronous buck DC/DC.I hope I can be of help here. I remember the struggles trying to understand motor control, especially FOC; from initial attempts of learning the thing, it took several years until I felt I really grok it (didn't happen until fully implementing it from scratch). Terminology and explanations often seem confusing, even if you are a seasoned player on some other field.

author: eTobey
author_rank: Super Contributor
timestamp: December 02, 2023, 01:08:00 pm
content: Quote from: Siwastaja on December 01, 2023, 06:01:00 pmThis information is all it took, to understand how it is working.I can feel your pain you had learning this, as i am right now. It is very hard to find specific information for certain aspects of FOC. I am at the point of 3rd harmonic injection, but cant find information that would help me to create the rigt curves. I also came across a sine wave and a triangular wave to use. Now what is right?Here i got the zero vector from:https://www.switchcraft.org/learning/2017/3/15/space-vector-pwm-intro

author: Siwastaja
author_rank: Super Contributor
timestamp: December 02, 2023, 01:33:30 pm
content: There were two things specifically which confused the hell out of me when trying to learn this stuff: the Space Vector Modulation thing, and for AC induction motors, the magical "flux estimator" black box. For BLDC, luckily, the latter does not exist.In all BLDC implementations I have done, I just always skipped the space vector modulation thing. None of the microcontrollers I use came with Space Vector Modulator peripheral, but they all come with classic three-phase center-aligned PWM modules (e.g., in STM32, "advanced control timer"; it can even synchronize ADC and look at analog comparator for overcurrent signal, saving MOSFETs when your PI loop is wrongly tuned). The claimed use case for Space Vector Modulator is that you don't have to perform inverse Clarke transform (from 2-phase duty cycles to 3-phase duty cycles) but could drive the modulator "directly" with the 2 phases, but OTOH, inverse Clarke is a few multiplications and additions, two lines of code and maybe 10-15 CPU instructions cycles so I don't see what's the big deal - then you can just use bog standard PWM timers.I used third harmonic injection once, and just generated the waveform in Matlab by gut feeling. The idea is that it should resemble a "softly clipped sine wave", pretty close to what you get by just multiplying and clipping a sine, but softer - no higher harmonics. What you gain is better utilization of DC link voltage especially in the case you have mismatched DC link voltage and motor nominal rating, i.e., can't go for higher voltage but want a tad more output power. I don't think there are any other advantages, maybe a tiny reduction in switching losses when running at absolute maximum output voltage. I did that only in an experimental EV conversion project where we had designed the motor windings for 300V or so but only had 96V of batteries.Re sinusoidal vs. triangular current waveform: there is a lot of confusion and probably no authoritative answer, but what is true that when a BLDC motor is driven from hall sensorsdirectlyi.e. just applying input voltage to the windings insquare wave, emulating how actual brushes work, then naturally the motor current after the motor inductance will be integral of that, triangle wave. Some people miss the important point that this is just a consequence of simplistic low-cost drive, not some kind of ideal design target. To muddy the waters, those BLDC motors that are primarily designed to be driven this stupidly, maybe possibly perhaps have different physical construction which kinda sorta evens out the rotation of the magnetic field even when driven with triangular current, and some further think that the distinctive factor is the "name": BLDC is trapezoidal, AC PMSM is sinusoidal. I don't know - but if such mechanical compensation really exists and is performed perfectly ideally, then it indeed would be ideal to use triangle wave in FOC (thus, use triangle function in Park / Inverse Park calculation). I have always used just sine wave even with cheapest of BLDC motors and with accurately interpolated angle, they run really smooth, much smoother than when driven "BLDC way" with square waves, where +/- 30deg torque ripple is easily observable. If the physical construction tries to compensate for the triangle wave, Chinese do it poorly. For a sine to perform worse than triangular, this mechanical compensation should need to work to at least 50% perfection.In essence, BLDC motor control is:* Apply a magnetic field, direction of which is 90 degrees advanced from the measured electrical positionThen for the current (torque) control:For a motor which turns very very slowly, you could just use three PI loops which measure current of each phase and output a duty cycle for that phase, then make the three current setpoints change sinusoidally and make the motor rotate that way. It works; the only problem is the delay in the feedback loop: optimal 90 degrees starts being less than 90 when speed increases, and worst, the delay isn't exactly constant per speed but depends on motor resistance which depends on temperature, so...All FOC does is, it makes the generation of sine waves a separate issue from the PI regulators; their setpoints and outputs will be constants over a short time, and sine waves applied before and after the PI loops. (Setpoints change when you desire different torque; outputs change slowly as for example temperature differences changes motor resistance.)In essence, FOC achieves this by:* measure current of two phases* calculate the third by knowing the sum of the three is zero* convert the 3-phase (120deg separated) current measurement vectors into 2-phase (90deg separated) vectors, i.e. copy the (simple) Clarke formula from Wikipedia.* rotate this 2D vector by the measured electrical angle of the rotor, so that it's rotated always to same stationary position (simple 2D vector rotation, the formula you see in computer graphics etc., for some weird reason called "Park transform" in this context; again, copy from Wikipedia). THIS is where the sine wave is introduced.* Use two PI loops, one for each component of the 2D vector* One of the component you want to usually regulate at zero - this is Id, the part which generates magnetic field into the current (or opposite) direction of the rotor. It tries to keep the rotor standstill, or if negated, fight against the magnets to weaken them.* Other one, Iq, creates magnetic field 90 degrees (or -90, if negative) from the current rotor position - this is what drives the motor forward/backward at optimum efficiency. Set at +/- desired current (torque).* Output of the two PI loops is again a stationary 2D vector, you can call it "voltage" or "duty cycle" command.* Follow the input steps in reverse and inverse order:* Opposite 2D rotation* Conversion from 2-phase to 3-phase (inverse clarke)* Write to PWM control registers of the timer peripheral and enjoy.

author: eTobey
author_rank: Super Contributor
timestamp: December 02, 2023, 02:05:55 pm
content: Quote from: Siwastaja on December 02, 2023, 01:33:30 pmAre you talking about the 3rd harmonic injection there?I just found this (fromhttps://ww1.microchip.com/downloads/en/Appnotes/doc32094.pdf) :This seems pretty wrong to me: The spacevector is computated only twice in an electrical rotation? Or is it something again that i dont get?

author: Siwastaja
author_rank: Super Contributor
timestamp: December 02, 2023, 02:57:21 pm
content: No, sine in general, because at some point I was confused by poor teachers telling me stuff like "in FOC no calculation/lookup of sine function is needed" or "in space vector modulation, no calculation/lookup of sine function is needed", and I was confused as hell because fundamentally these AC motors run out of sine wave and all you have is DC so the sinehasto come from somewhere, and I was of course right. That's why I want to point out where it is hidden in these algorithms.Six, not two.This is one of those appnotes which makes my head spin. I don't understand how they manage to combine:* six steps per electrical revolution* having a requirement of sine/cosine calculation despite only using 6 steps which could be handled by a simple table lookup instead, so which way it is, do they have more resolution than 6 steps, or not?* using the PWM peripheral at the end, after all, so it seems their "space vector modulator" just means inverse clarke transform, yes, but does it do anything else, and if no, why the complexity of explanation?What task does this space vector thing here perform? What is it? I have no idea.Of course, if the angular resolution of your rotor position input is only 60 degrees (in other words, error between indicated and true angle ripples +/- 30 deg), as is the case with simple BLDC built-in HALL sensors (three sensors, three bits, 6 valid combinations out of 8 ), youwillbe outputting only 6 distinct steps per electrical rotation, and youwillbe generating significant torque ripple. In that regard, FOC does not magically give you any extra resolution compared to simple from-hall-signals-to-gate-drivers, only well responsive and accurate current (torque) control, which is its primary purpose.But the reason I don't like to fixate to the 6-sector lookup table is that in some cases, you might have more accurate position information available, for example an optical encoder, or even in a project where I only had those hall sensors, I simply added interpolation because mechanical inertia prevents quick speed changes anyway so I can predict the rotor position based on time difference of two previous position changes (velocity), and that way I was able to lower the torque ripple, low frequency audible noise and mechanical vibration, not to zero but anyway, significantly. I don't know if and how you can do better than 60deg resolution space vector modulation. I remember hearing that you pulse width modulate between two sectors/steps in the correct relation but that is getting even more complicated to implement.But maybe someone explains Space Vector Modulation to me and then I convert

author: abyrvalg
author_rank: Frequent Contributor
timestamp: December 02, 2023, 08:29:45 pm
content: SVM is for the same thing as 3rd harmonic injection - to utilize full DC voltage by shifting the 3-phase middle point up/down. I had a feeling of understanding it when I was digging into it but it have gone after months, so perhaps it was false 😁 (but the code continues to work!).The thing with “inverse Clarke is not needed with SVM” is not the goal, it is just stating that inv. Clarke is already encapsulated into SVM. There is no need for a dedicated SVM peripheral, a modest STM32F103 does it with ease, the algo is basically inv. Clarke + scaling.

author: Doctorandus_P
author_rank: Super Contributor
timestamp: December 02, 2023, 10:51:41 pm
content: I have not built a motorcontroller myself yet (Except for some simple stepper motor drivers long ago) but I have been interested in this topic for many years.I have never seen a big difference between BDLC and PMSM. Some people come with the "sinusoidal" versus "trapezoidal" argument and think it's a big thing. I say meh, that is not enough to call it a different type of motor. If you want to know what your motor does. then just put a decent sized resistor between two phases and run it with a drill or some other motor. Your motor will then generate the waveform it likes best. I have seen some youtube vid's from BLDC motors that generated trapezoidal waveforms. Car alternators are also a good example. I guess these are optimized to have a "flat top" with the aim of getting out a more DC current after rectification. You can use these as a BLDC motor if you remove the diodes and run a DC current though the armature.Also for stepper motors. There is very little difference between (bipolar) stepper motors and BLDC/PMSM. The biggest difference is that a lot of stepper motors are assymetric 2-phase while BLDC/PMSM is symmetric 3-phase, but there are 3-phase stepper motors too. (Especially for the bigger motors, I have not seen them smaller then Nema 23 size). The other (insignificant) difference is that stepper motors generally have a higher pole count. (50 pole pairs for a 200step/revolution motor).If I remember well, the difference between FOC and SVM is also quite small. FOC uses sinusoidal calculations around a (virtual) 0V. Then some cunning guy realized this "virtual 0V" in between the motor phases does not really exist (except when the motor is in "star" configuration) and it is not important for the motor itself. The motor only cares for the current though it's windings. So that cunning guy figured out that if you manipulate both ends of a field winding of a motor, you can put more voltage over it, and thus a higher current. And that is the basis of SVM. But because all three phases of the motor are connected together, you need to add a bit of math and manipulation to make it work properly.You can re-create this "virtual zero" by making a star point with three equal value resistors, and then measuring the phase voltages related to that star point.I also wonder if it works to measure that "star" point with one channel of a 4-channel oscilloscope, and then subtract it from the other channels which measure the phase voltages.In what direction do you want to go? Is it purely theoretical? Do you want to design your own motor controller? Do you have a specific application in mind?There is so much "stuff" out there on the 'net. A lot of the uC vendors have libraries for motor control, there are hundreds of open source projects, varying from speed / power delivery (VESC) to high resolution positioning.

author: Martinn
author_rank: Frequent Contributor
timestamp: December 10, 2023, 08:52:28 am
content: Quote from: Siwastaja on December 02, 2023, 01:33:30 pmI was also confused about all that "space vector modulation" stuff. As mentioned before this just amounts to a center aligned PWM. I think a lot of the bloat came from early academic work or working on fixed point controllers.One thing that I find missing in this list (otherwise excellent) is the centering of the PWM outputs, which I remember being called midpoint shift or "zero sequence modulation".There used to be a good tutorial on that from Microchip, but most animations and the ZSM viewer are broken:https://skills.microchip.com/zero-sequence-modulation-for-three-phase-motorsIn short, after you calculated the three PWM values, calculate min and max and center them around the midpoint. This increases the available bus voltage a bit.

author: Siwastaja
author_rank: Super Contributor
timestamp: December 10, 2023, 11:07:53 am
content: Yeah, it's a good note. But all microcontroller PWM modules offer center-aligned mode, even the cheapest-ass 8-bit AVR timers I'm aware of, so there is nothing to calculate. It's good to remember to configure the PWM peripheral correctly though, and that is a significant part of implementing the FOC - you also want to do things like synchronize the ADC sampling to the PWM so that it samples during the ON time of the leg where current is sensed.

author: Martinn
author_rank: Frequent Contributor
timestamp: December 10, 2023, 03:02:48 pm
content: Quote from: Siwastaja on December 10, 2023, 11:07:53 amThere is, but maybe you consider this trivial or we are not talking of the same thing.The question is how do you go from inverse P/C output to PWM counts?Say your inverse P/C step delivers output voltages of U=100 W=-50 V=-40. Units are kind of arbitrary, might be V (with some additional scaling in PWM ticks per V) or PWM ticks. Let's say it's already in PWM ticks.So if you have a PWM base resolution of 1024, you can set values 0...1023. Setting U V W to 511 will output a 50% DC waveform with effective phase-to-phase voltages of zero.The most straightforward calculation would be PWM(U)=511+100, PWM(V)=511-50 and PWM(W)=511-40.This is possible, however wastes one degree of freedom we have here: We can add an arbitrary number to these PWM counts, this will shift the center of the motor windings (assuming Y connection). The motor windings don't care because they see voltage differences only, an absolute offset cancels out.So what I have seen to be commonly done is place maximum and minimum each half way from the mid voltage (511 in this case).In the above example max=100 and min=-50, range is 150, half is 75. So we shift the voltages by +25 downwards, PWM(U)=511+100-25, PWM(V)=511-50-25 and PWM(W)=511-40-25. Now they are symmetric around 511.Why would we do that? Assume we have U=600 V=-200 W=-100. We could not achieve this with having the center at 511, because 511+600 is out of range of the PWM unit. However, 600+200=800, mid-value is 400, which means we shift 200 downwards:PWM(U)=511+600-200, PWM(V)=511-200-200 and PWM(W)=511-100-200. So midpoint centering makes better use of the available bus voltage range.This process is called zero sequence modulation or midpoint shift, which is (or at least was) explained in detail in the microchip tutorial I linked in my last post. In addition to midpoint centering, there are other strategies, like top or bottom clamp if you want to minimize transitions on one particular side of switches. Maybe that's relevant for power electronics, all I have ever seen was centering.Overview and some more detail:https://skills.microchip.com/zero-sequence-modulation-for-three-phase-motors/690363

author: Siwastaja
author_rank: Super Contributor
timestamp: December 10, 2023, 06:01:23 pm
content: Thanks for the explanation, you explained it very nicely, easy to understand. Indeed it's completely separate from the center-aligned PWM. I had ignored the whole "zero sequence modulation" concept, but it seems a useful and simple to implement trick. It would create a common mode signal but as you say, the motor does not care.

author: Harjit
author_rank: Regular Contributor
timestamp: December 31, 2023, 07:45:24 pm
content: @martinn - why would one need to do the shift? I have a mental model of "pulling" the rotor 90 deg. ahead and this is done by three phases and the three phases are sinusoids that are 120 deg. apart.Great thread - thank you!

author: Martinn
author_rank: Frequent Contributor
timestamp: January 01, 2024, 05:30:34 pm
content: Quote from: Harjit on December 31, 2023, 07:45:24 pmYou refer to the midpoint shift I explained in my last post?https://skills.microchip.com/zero-sequence-modulation-for-three-phase-motors/690363It increases the phase voltage range a bit, equivalent to increasing the bus voltage. Mostly this will increase the rotational speed, as you can compensate for a higher back EMF.Regarding your mental model: This is correct, this is how a motor looks like for a stationary observer. However, consider thinking the FOC way: Assume you are fixed to the rotor and you see fields relative to your position. Nice thing: Magnetic field is stationary! Make two simple PI controllers for keeping the magnetic field where you want it (typically 90° ahead of your rotor magnetization, which is constant from your point of view. P/C and inverse P/C does this transformation.Or, if you look at it from a different perspective, following your mental model with three sinusoidal currents in the stator windings: Why all the hassle with P/C? Why not simply generate three sinosoids, 120° apart and feed them to three current controllers controlling the phases directly?- Martin

author: Harjit
author_rank: Regular Contributor
timestamp: January 05, 2024, 04:36:22 am
content: @martinn - yes, I meant the midpoint shift. Understood on it looking like increased bus voltage.> Why all the hassle with P/C? Why not simply generate three sinosoids, 120° apart and feed them to three current controllers controlling the phases directly?Can you elaborate on this? Are you saying measure two current phases, compute the third, then run that through three PI loops with the input to the PI loops being 90 degrees ahead on each?Or are you suggesting the "Modified Synchronous Current Regulator" by Shane (https://scolton-www.s3.amazonaws.com/motordrive/SCquals.pdf)? Or?Since you have a great grasp of this, can you share your thoughts on field weakening - like what is happening?Also, I haven't seen a good way to determine the PI gains for FOC. Any suggestions?

author: Siwastaja
author_rank: Super Contributor
timestamp: January 05, 2024, 06:32:45 am
content: Quote from: Harjit on January 05, 2024, 04:36:22 amThat's what he means. It is so simple in theory - just generate the sinusoidal currents directly. I actually tried it, when trying to get grasp of FOC, and it worked with very slow motor speeds. As expected, the lag from the PI regulators messes up the desired 90deg shift. That's why you want the feedbacks run on a rotating frame of reference.Quote from: Harjit on January 05, 2024, 04:36:22 amI have one hint: add instrumentation to your code to see what's happening Something as simple as:if(current_i == LENGTH(current_log))send_current_log_through_uart();elsecurrent_log[current_i++] = measured_current;so you can get a plot like shown in the attachment (showing a tiny bit of overshoot after setpoint change).Then run the motor with various loads and make setpoint changes. The phase current PI loops seems quite forgiving to tune, order of magnitude easier than speed control loops which can get pretty tricky sometimes.

author: Martinn
author_rank: Frequent Contributor
timestamp: January 11, 2024, 07:15:41 pm
content: Quote from: Harjit on January 05, 2024, 04:36:22 amAs Siwastaja wrote the PI current controllers are very easy to tune empirically. Just apply a rectangle set waveform with 100 Hz and tune to decent response. Tune back if noise gets excessive.In all motor control you will need near realtime graphical feedback, otherwise you don't get anywhere. If you use STM32 you can use STMCubeMonitor, otherwise you'll have to write the instrumentation for yourself.I have not actively used field weakening. In FOC, you normally just apply Q current and regulate D to zero because Q creates the torque and D mostly heat. There's one exception: The motor constant together with the bus voltage determines the max. rpm. For example, if you have a 1krpm/V motor and 10 V supply, max you will get is 10 krpm. However, applying a D current that generates a magnetic field opposed to that of the rotor magnets, this decreased the magnetic field, with this back emf and finally lets you achieve higher rpm, at the cost of lower torque. Google field weakening for more in detail explanationshttps://www.powertransmission.com/articles/1375-field-weakening-what-how-and-why-to-do-it

author: Siwastaja
author_rank: Super Contributor
timestamp: January 11, 2024, 07:51:52 pm
content: d-direction current can be used to create holding torque, too. I was aiming for very low speeds for which I did not have enough encoder resolution to tune the speed PID controller loop in a satisfactory way. One way I tried to deal with was to use d current, which is a significant sacrifice in efficiency but now you are creating holding torque and smaller part of forward-moving torque so things get "stiffer". It was basically just a short moment of applying some d current while slowing down to stop, for a second. In the end, I got rid of it by just solving the speed control loop issue by adding feedforward from inertial measurements, specifically gyroscope, so the motor current reacts to motions before the encoder tick happens; it was just a few lines of code injecting a term into the motor control loop from navigation code. Sometimes such simple things are very powerful instead of trying to tune the impossible PID loop.But PI current loops are, luckily, pretty easy to get good enough. Still remember to check for over-the-limit current each time you calculate it, so you can safety-shutdown instantly so that badly tuned PI loop does not kill your power MOSFETs.

author: Martinn
author_rank: Frequent Contributor
timestamp: January 11, 2024, 08:31:49 pm
content: In my experience the dominating factor in PID tuning is the D filter. What I used as D was a filtered discrete difference. As filter I used a first order lowpass, the corner frequency being by far the most relevant parameter. Set too high, you get only noise and set too low, phase drops too early.What I also tested and worked astonishingly well is a kalman based velocity estimator (for the D part). If you have a somewhat constant system model and not too much friction, this might be worth a try. I worked on an air bearing voice coil stage with sine encoders (nm resolution). Kalman filter reduced D noise significantly.I have to admit I also at one point was so frustrated with PID tuning, made a system model and fed it into the Matlab Control System Toolbox tuner app. Gave a nice starting point for hand tuning.Low encoder resolution: Yes, probably you can stretch that a bit by measuring the edge transition timing and doing some Kalman or observer guesswork. But in the end you just have to accept a few increments of remaining error. Better use sine encoders for near-infinite resolution.And as you mentioned, all feedforward is much more effective than any control loop, position in particular. I sometimes wonder how they control direct drive CNC lathe spindles. Empty spindle might weigh 100 kg, loaded half a ton easily, changing during operation. Even on my bench lathe the VFD velocity loop does not like shifting gears, being autotuned to one gear only.