Using Marlin’s auto leveling for PCB milling

As I’ve stated earlier, I designed my 3D Printer with light milling operations in mind. One of the activities I intended to tackle was the subtle art of  PCB milling. It seems pretty straightforward at first: get a new/raw PCB (printed circuit board), use something like FlatCAM to generate G-Code from your Gerber files, get yourself a good milling bit and you’re done. While this is true for coarser trace widths and packages, you’ll soon run into trouble when milling something as fine pitched as an HSSOP-28 (like I’m doing for this little fella). Where 3D printing is fairly robust to submilimeter bed misalignments, milling widths of under 14mils is an unforgiving process: cut depth variations of even 0.01mm can ruin a trace and a board. Naturally, trying to mechanically level the board is the first step. However, larger boards may be somewhat bent, which can be hard to compensate (or flatten).

I’m currently using Marlin as my printer’s firmware. After watching the advances on automated bed leveling (or tramming, as some call it), I figured I could profit from such feature to accurately mill PCBs. However, after some tests, I noticed that only a 3-point leveling wasn’t enough. While the plane of the PCB is identified, curvatures or slightly bent PCBs can’t be properly compensated. Luckily for me, the masterminds behind Marlin are now implementing a grid-based leveling, that does just what I needed. It took me a couple hours and some minor tweaks to the Marlin firmware to get it running. First, checkout the result:



To get all running, I started by printing some mounting clamps for my Dremel’s flex shaft. Carrying the Dremel itself was an option, but the flex shaft is much lighter and equally stiff.

Setup for PCB milling. Quite... ahm... Messy.
Setup for PCB milling. Quite… ahm… Messy.

Next step was to convert my Z endstop into a “dual crocodile clip” configuration, as in the picture:

Crocodile clips on the board and on the tool. When both touch, bingo: Z endstop was hit.
Crocodile clips on the board and on the tool. When both touch, bingo: Z endstop was hit.

This allows for an accurate on-the-spot Z endstop. After that, on the software side. First, in Marlin’s Configuration.h, I enabled and configured the leveling. Around line 407:

Another important thing to change: since the “extruder” (the milling tool) and the probe are the same, I also changed, in Configuration.h, line 457:

Last change. Since you want to mill a PCB, you usually will be cutting in the negative Z space. This means the tooltip has to be able to go to, for example, Z=-1. This won’t happen by default, because the printer “thinks” there is no space below Z=0 (and usually, there isn’t). So, in Configuration.h, give the printer some room in the -Z direction. Be careful! This modification can lead to several headaches once you forget it is in place.

This should suffice. Essentially, we’re tricking Marling into probing only “inside” the size of the board. The downside (for now) is having to change and recompile this for different board sizes. By default, however, Marlin needs to home the X and Y axis before allowing a G29 (auto-leveling) to be performed. Even though this makes sense in the grand-scheme of things, it was a nuisance in my case. I wanted to be able to place the probe in any arbitrary point on the bed/PCB and start the leveling. For that, all I had to do was remove the “homing verification” on Marlin_main.cpp:

Done! Now I can manually carry the mill/tool/extruder/probe to the desired origin (where I want the board to be milled). There, I just need to issue the following commands:

After the process ends, your preferred GUI/interface will spit out the surface’s correction matrix calculated by Marlin:

Pronterface, showing the calibraton results on the right.
Pronterface, showing the calibraton results on the right.

That’s it. Now just print normally – the compensations for the bed’s irregularities will happen automatically on the background. The calibration data is lost at each reboot (though an EEPROM save can be enabled).

’til next time.