Modeling electromagnet pull force with pyFEMM

Strydr Silverberg ·

Being the CEO of a startup means you wear a lot of hats. An autonomous chess system looks simple from the outside, but it's really a balancing act between what's functional, what's usable, and what's actually buildable. This post is about one small corner of that: how I, a computer engineer with basically no background in magnetics or simulation, used pyFEMM to figure out the magnetic forces inside our board.

Why we needed a model

We're still deciding which sensor to use for tracking where the pieces are, and that choice changes what goes inside each piece. The gantry under the board carries an electromagnet, and depending on the design we drop either a small iron slug or a little permanent magnet into the base of every piece. Either way, the electromagnet has to pull hard enough to slide a piece across the board without dragging its neighbors along with it.

The problem was that "hard enough" is a number, and we didn't have a trustworthy one. A quick hand calculation put the pull at around 3.4 N, with an error bar big enough to drive a truck through. That's not a number you order parts against, so we needed something better.

Why magnets leak

Here's the thing that I didn't appreciate going in: magnetism always travels in closed loops. The field leaves one end of the electromagnet, crosses the gap to the piece, and then has to find its way back to the other end. The path it takes on the way back matters enormously.

For the first round of simulations I modeled the simplest electromagnet you can build: a coil of wire wound around a straight iron rod, with nothing else around it. Picture the nail-and-wire electromagnet from a grade-school science fair. Engineers call this a "bare rod," and it has a real weakness. The field shoots out the top, but to loop back to the bottom it has to swim all the way around through open air. Air is roughly a thousand times worse than iron at carrying a magnetic field, so most of the electromagnet's strength gets wasted on that return trip. Only a little is left to actually pull on the piece.

The fix is to give the field an iron shortcut home, like bending the rod into a horseshoe so both poles sit close to the piece. That extra iron is called a yoke, and it works because iron carries a magnetic field about a thousand times more easily than air. A horseshoe magnet grabs your fridge far harder than a straight bar of the same size for exactly this reason. I started with the bare rod on purpose. It's the worst case, the floor. If even that turned out strong enough, we'd be home free.

Enter FEMM

FEMM is a free, well-trusted tool for simulating magnetics problems like this one. Under the hood it's solving Maxwell's equations, the same set behind every motor, antenna, and MRI machine. The nice part is that we get to throw most of them away. Our coil current is steady, so nothing in the problem changes with time and every time-dependent term drops out, leaving a single static relationship between the field and the current that makes it. On top of that, the magnet and slug are round and share a center line, so we can tell FEMM to treat the whole thing as symmetric about that axis and solve a flat 2D slice instead of a full 3D volume. Those two simplifications are the entire reason a run takes seconds instead of hours:

```python import femm

FEMM solves Maxwell's equations for the *static* case. A steady coil current # makes a steady field, so every time-derivative drops out and what's left is # just Ampere's law, solved for the field across a mesh. Two assumptions keep # it cheap: # freq = 0 -> static: no eddy currents, no AC, just a steady DC pull # "axi" -> symmetric about the gantry axis, so a 2D slice stands in # for the full 3D magnet femm.mi_probdef(0, "millimeters", "axi", 1e-8, 0, 30) # freq units type ```

I drove all of this from Python with pyFEMM instead of clicking around the app, and that mattered more than it sounds. A single simulation barely tells you anything. The useful questions are all about trends. How fast does the pull fade as the gap grows? Does a short fat slug beat a tall skinny one? Each of those answers is dozens of runs, and scripting turns a week of tedious clicking into a loop I can rerun the moment our hardware lead changes a dimension.

Here's one solved model. Color is field strength, the white lines trace the field, and you can pick out the coil, the iron core, and the slug sitting above the gap:

![field_iron](/api/public/articles/inline-image/b477985b-4193-4c06-814a-ee6aa7d88afe)

You don't need to read the numbers to see the problem. The core glows, but almost all of that field fans out into the air around it. Only a faint wash of it reaches the slug. That's the leak, made visible.

What the simulations told us

Once the field is solved, turning it into a pulling force is almost anticlimactic. The attraction between the magnet and the slug is really just a magnetic pressure squeezing them together:

```python import math MU0 = 4e-7 * math.pi # permeability of free space

def pull_force(B_tesla, area_m2): """Pull on the slug face: magnetic pressure times area.""" pressure = B_tesla**2 / (2 * MU0) # N/m^2 -- note the square return pressure * area_m2 # newtons ```

The whole story is in that B**2. Force grows with the *square* of the field, so any field you lose to the leak gets punished twice over. Our hand calculation assumed a strong field right at the slug. The simulation showed the slug actually sees a small fraction of that, and squaring a small fraction gives a tiny force. (FEMM does this more honestly than the formula above, adding up the real, uneven field over a surface wrapped around the slug, but the idea is identical.)

That's how we landed on the headline number. At our real operating point, the bare-rod electromagnet pulls the iron slug with about 0.18 N, nearly 20 times weaker than the napkin math promised. We were one confident hand calculation away from building a machine that couldn't move its own pieces. Tellingly, the iron itself was nowhere near its limit, so the answer isn't more metal, it's a better path for the field.

Then I swept the full range of slug sizes against the pull we think it takes to actually move a piece:

![heatmap_iron](/api/public/articles/inline-image/af19d748-9796-425c-ba04-662db5a3b86c)

Across every size, the pull lands somewhere between 0.04 and 0.38 N. Enough for a light, low-friction piece, not enough for a heavy one. Two things stood out. Making the slug thicker helps more than making it wider, which is the opposite of what I'd guessed. And swapping the iron for a small permanent magnet pulls far harder, but with a catch: the magnet gets yanked by the core even when the coil is off, so the head can knock a piece out of place just by passing over it.

The takeaway was clearer than I expected. If we stick with iron, the size of the slug is the smallest lever we have. The real fixes are adding a yoke to guide the field home and tightening the gap, in that order.

Where this goes next

This model is deliberately simple. It assumes the piece is perfectly centered and ignores how one energized square might tug on the piece next to it. Those questions need a heavier 3D simulation, and that's only worth setting up once the simple case looks good. But that's the point of starting small. A few hundred lines of Python told us which design choices actually matter and killed a number we'd have built the wrong hardware around, all before cutting a single piece of steel.

Not bad for someone who couldn't have told you what any of this meant two weeks ago.