Skip to main content

Field-Oriented Control (FOC)

Here's the core difficulty FOC is built to solve: the three phase currents are all constantly changing sine waves, 120° apart, and what we actually care about, torque, comes from a somewhat awkward combination of all three at once. Trying to directly regulate three interacting, constantly-moving sine waves with three separate PID loops is clumsy and doesn't converge cleanly, because the "error" itself is a moving target.

The big idea behind FOC: stop describing the currents from the stationary point of view of someone standing next to the motor, and instead describe them from a point of view that spins with the rotor. If you're riding along with the rotor's magnet, the field that's supposed to be dragging you around isn't spinning relative to you at all, it's sitting still. Two sine waves, 90° apart, viewed from a reference frame that rotates in exact sync with them, don't look like sine waves anymore, they look like two constant, unmoving numbers. A hard, constantly-changing problem becomes an easy, constant one, just by changing your point of view.

The rotating d,q coordinate frame superimposed on the stationary three-phase abc system

Source: Wikimedia Commons

Getting to that rotating point of view takes two coordinate transforms:

The Clarke Transform: Three Current Readings Become Two

Three phase currents sound like three independent pieces of information, but they're not quite. All three windings connect together at a shared center point, and at that junction current can't pile up or vanish, whatever flows in from one wire has to flow back out through the other two. That forces Ia+Ib+IcI_a + I_b + I_c to equal zero at every instant, which means knowing any two of the three currents automatically tells you the third: if Ia=5AI_a = 5\text{A} and Ib=3AI_b = -3\text{A}, then IcI_c has no choice but to be 2A-2\text{A}. Three numbers, but only two of them are ever actually free to vary.

The awkward part is that the two you'd naturally reach for, say IaI_a and IbI_b, don't point in convenient directions to work with. Each phase current pushes along its own winding's physical axis, and those three axes sit 120° apart, not a tidy, perpendicular x/y layout. As established back in Sinusoidal Commutation, all three currents combine at every instant into one single, smoothly-rotating magnetic field vector, so what's actually wanted is a clean, perpendicular way to describe that one vector, not three overlapping, redundant readings of it. That's exactly what the Clarke transform does: it repackages the three phase currents into two perpendicular, still-stationary axes, conventionally called α\alpha and β\beta, that describe the same combined vector the way ordinary x/y coordinates would:

Iα=IaIβ=Ia+2Ib3I_\alpha = I_a \qquad\qquad I_\beta = \frac{I_a + 2 I_b}{\sqrt{3}}

Nothing physical has changed, this is the same current, the same combined vector, just described with two perpendicular numbers instead of three redundant, 120°-apart ones.

Watch the two frames on the right side of the animation: the three aa, bb, cc vectors up top and the two α\alpha, β\beta vectors below both sweep around at the same rate, tracing out the same combined vector, just described by two numbers instead of three.

The Park Transform: Standing Still Relative to the Rotor

The Park transform takes that stationary (α,β)(\alpha, \beta) description and rotates it by the rotor's own electrical angle θ\theta (read straight from the encoder), landing on two new axes, dd and qq, that spin together with the rotor:

Id=Iαcosθ+IβsinθIq=Iαsinθ+IβcosθI_d = I_\alpha \cos\theta + I_\beta \sin\theta \qquad\qquad I_q = -I_\alpha \sin\theta + I_\beta \cos\theta

Because dd and qq spin in lockstep with the same electrical angle the current itself is rotating at, a properly commutated motor's currents stop looking sinusoidal in this frame, they collapse into two steady, DC-like quantities:

Watch the bottom row this time: while the abc frame up top keeps spinning, the dd/qq waveforms below go completely flat, constant lines, and the vector in the rotating dqdq frame stops moving entirely. That's the whole payoff of Park's transform: riding along with the rotor turns a moving target into a stationary one.

  • IdI_d, the component of current pointing along the rotor magnet's own axis. This doesn't produce torque; it either strengthens or weakens the magnetic field itself. For most FRC-style surface-mount permanent-magnet motors, the torque-per-amp is maximized by holding Id=0I_d = 0.
  • IqI_q, the component of current at 90° to the magnet, exactly the "always push tangentially, never toward or away from the center" direction that produces the most torque for a given current. Torque comes out directly proportional to IqI_q:
TktIqT \approx k_t \cdot I_q

Closing the Loop

This is the payoff: IdI_d and IqI_q are just steady numbers now, which means they can be regulated with two ordinary PI controllers, exactly the same closed-loop tool used everywhere else in Closed Loop Control, just running on the motor controller instead of the roboRIO. Once the controller has computed the correction it wants in the dd/qq frame, an inverse Park transform rotates it back into the stationary α/β\alpha/\beta frame, and Space Vector PWM (an inverse Clarke transform, essentially) turns that back into the three PWM duty cycles that actually drive the inverter's switches.

A simplified indirect field-oriented control block diagram: current sensing, Clarke/Park transforms, PI
controllers, inverse Park, and the inverter driving the motor

Source: Wikimedia Commons

All of this, sense the currents, rotate them into the rotor's frame, correct two steady numbers, rotate the correction back out, resynthesize the PWM, runs many thousands of times per second inside the motor controller itself. The result is a motor that produces smooth, nearly ripple-free torque, runs quieter, and gets more torque out of every amp it draws, at the cost of needing a fast onboard processor and a precise, low-latency rotor angle. This is exactly what modern FRC "smart" brushless controllers (like the TalonFX controllers built into the Kraken motors) are doing internally when running in FOC mode.

It's worth walking through one of those thousands-per-second iterations, because a PI controller is inherently reactive, it only ever computes a correction for an error that's already happened, and that sounds like it should leave the motor perpetually a step behind. Say IqI_q's target is 20A and the latest measurement comes back at 18A, a 2A shortfall. The controller didn't know that gap existed until it measured it, and by the time it computes a correction and rotates it back out through the inverse Park transform and Space Vector PWM, the new duty cycle it produces is answering for a gap that, strictly speaking, already happened. That duty cycle nudges the phase voltages up slightly, but current in a real winding can't jump to meet a new voltage instantly, it climbs toward it along the circuit's own exponential curve, governed by the electrical time constant τ=L/R\tau = L/R, typically a few milliseconds, the same time constant. If the loop only measured and corrected once every few milliseconds, that lag would matter, current would forever be chasing a target that had already moved on by the time a correction arrived. But at tens of kilohertz, the next measurement lands roughly fifty microseconds later, long before the current has climbed any meaningful fraction of the way through that exponential. So the loop measures again, finds the error only marginally smaller, say 1.8A instead of 2A, and nudges the correction again, thousands of times every second. Each individual nudge is technically late, computed from an error that already existed by the time it's acted on, but the nudges arrive so much faster than the physical current can possibly respond that the staircase of small, reactive corrections converges onto essentially the same smooth curve a perfectly clairvoyant, non-reactive controller would have produced. The reactivity is real, it just never gets enough time between corrections to turn into anything visible.

That steady, well-regulated IqI_q is exactly what makes commanding motor current directly from robot code practical in the first place, without FOC holding it smooth, a raw current setpoint would be fighting the same ripple problem this whole page exists to solve.

That's the last of the commutation schemes this section covers. Before comparing all four head to head, Torque, Current, Speed, and Voltage covers two more relationships every motor obeys, regardless of which of these schemes is driving it.