« Back to home

CNC Milled PCBs

As I've mentioned before on the site I have been looking for a more effective way to create prototype PCBs than sending them off to somewhere like Seeed Fusion or using the toner transfer method - I have started down the path of trying to build a small CNC machine for this purpose and even experimented with lasers as a method of preparing boards.

CN-3020T Milling Machine

A few weeks ago I had the opportunity to get a small CNC machine for a very reasonable price so I jumped at it. I am now the proud owner of a CN3020T desktop CNC router and have had a bit of time to learn how to use it. My main purpose for it is PCB creation but I have also had a chance to play with engraving and cutting other materials such as wood and plastic (it is supposedly capable of working with soft metals such as aluminium as well but I haven't had a chance to try that).

This post describes how I am going about making PCBs with a CNC machine, like many other things the process is not as simple as it looks at first glance and, having had to do numerous searches on the internet to find the information I needed I thought I would document as much as possible here to help others who are going through the same thing.

A Brief Introduction

Essentially a CNC machine is a drill that can be moved in 3 dimensional space. You place a tool bit in the drill which is then moved in the X, Y and Z directions to cut into the material you have mounted on the bed. Where a 3D printer uses an additive process to get to the end result (slowly layering material at various points to build up a solid object) a CNC is subtractive - you start with a solid piece of material and slowly cut away at it.

Software Tools

As with 3D printers a CNC is controlled by g-code and you will need a way to generate that g-code. There are no shortage of tools that will help you do that, I am just going to cover the ones I have had some success with.

To generate g-code for PCBs I have been using Line Grinder which takes a set of gerber files as input and generates g-code output. The output is in the form of three g-code files - one to do the isolation routing that defines the copper tracks on the PCB, another that controls drilling the holes for through hole components and a third that will cut the board outline from the PCB blank you routed on. Each file requires a different tool bit to do it's job. There is a similar tool called pcb2gcode which I haven't played with yet.

For general operations (cutting out shapes, cutting areas into a solid surface and etching) I have been using the gcodetools plugin for Inkscape. Inkscape is a very powerful vector drawing program that is available on a number of platforms including OS/X, Windows and Linux so this is a good solution no matter what OS you use. Inkscape can also import a large number of image formats and convert bitmap graphics to vector format so there is a lot of flexibility there. Even if your only interest is making PCBs you will still need to occasionally perform some of the basic cutting and area clearing operations so learning how to use Inkscape and gcodetools is useful.


To check the resulting g-code I recommend OpenSCAM. Despite the unfortunate name this is a very, very handy tool - essentially it is a CNC emulator - it will run the g-code you provide it and show you how the tool will move on and what the effects on the work-piece will be. I would go as far as saying this tool is essential - especially as you are learning or are experimenting.

Most CNC machines seem to be very dumb devices - the 'control box' that they come with is little more than a power supply, some regulators and a parallel port interface. All the interpretation of the g-code (translating it into actual motor movement) is done by software on the PC. There seem to be two major programs for this - LinuxCNC for Linux and Mach3 for Windows. LinuxCNC was previously known as EMC2 so you will see that name pop up a lot in searches. I am using LinuxCNC with my machine, simply because I prefer Linux over Windows and I'm too tight to pay for licenses.

LinuxCNC depends on a kernel with real time extensions so it's not really an application that you install on your favourite distro - it's more it's own (Ubuntu based) distribution with the appropriate kernel included. If at all possible you should dedicate a machine to it - I'm using an old desktop with a built in parallel port to run LinuxCNC to drive the CNC and Pronterface to drive the 3D printer.

Hardware Tools

If you are not already familiar with wood and metal working the number of tool bits available can be a bit daunting. My machine came with a small collection of bits and I have bought more of them from eBay as well. Be prepared to (and, really, expect to) break a number of them while you get used to what you can and can't do.

Testing Tool Bits

Different operations require different tools - if you are drilling holes you use a normal drill bit with the cutting edge on the tip - it travels in the Z direction only. To cut out a shape you need a bit with the cutting edge on the side of the bit - as it moves in the X and Y direction it cuts out the shape you specified. There are a range of different cutting bits with flat, conical and curved cutting edges - each of them give a slightly different result.

I have taken to cutting a sample shape at a shallow depth into soft wood like pine to see what effect a tool has - this minimises the stress on the tool and gives me a feel for what it can be used for. The image to the right shows the Garage Lab logo cut with various dremel bits (yes, you can use dremel bits with the CNC machine as well). I drew up a simple version of the logo in Inkscape and generated the g-code with gcodetools - a good example of how useful the that utility is.

General Guidance

Although g-code can use either mm or inches the preference (for CNC machines at least) tends to be for inches so if you are like me and brought up on the metric system get used to converting between the two. It's not a big problem but I find I have trouble visualising things in inches - I need to convert to mm to have a clear idea of what the size actually is.

There seems to be a huge number of parameters that need to be specified with any program that generates g-code for milling - a lot of them are straight forward and can easily be measured (tool size and length, work area size, etc) but others require a bit of playing around with to find the optimal values for you machine and set up. One that I had particular problems with was the feed rate or the speed at which the tool bit travels in inches/minute.

Different rates are used at different points in the process - there is a cutting rate (the speed used while it is actively cutting), a travel rate (when the tool is above the work piece and moving to a new location) and a penetration rate (how fast the tool is pushed into the work piece).

Your machine will have an upper limit on all rates (the motors can only move so fast after all) but the rest of them are up to you to define and will heavily depend on the capabilities of your machine, the type of material you are working on and the bit that you are using. My recommendation is to start low and work the speed up - unfortunately I tend towards the impatient side and broke a few tools simply because I was trying to move them too fast.

Making PCBs

In this section I am not going to go into a lot of details about settings, tool sizes or feed rates - as I said above, those things are very dependant on your particular setup. Instead I'm going to concentrate on broader techniques that worked for me and point out various things that tripped me up.

PCB Milling Bits

For PCB milling you will need three different tool bits - an engraving bit (which looks slightly like a spear head), a 1mm drill bit and a cylindrical edge milling bit. The photo to the right shows the bits I am using - the are a range of different types available and they are generally available cheaply on eBay. Because I don't really understand the difference between all the bits yet I wound up buying a selection and I'm going through them and seeing how they work and which bits are best suited to different materials.

Generating the G-code

I am using the Line Grinder utility I mentioned earlier to generate g-code from gerber files but much of this will be applicable to other utilities as well. Essentially you will get two (optionally three) output files from your gerber input - the isolation routing file, a drill file and perhaps an edge milling file.

Isolation Milling

The isolation milling file is run with the engraving tool (I use one with a 10 degree angle and a 0.1mm tip). This cuts away a thin line of copper around your traces while leaving the rest of the copper behind. Line Grinder also generates pad touchdowns, small dots in the center of each pad that act as a guide if you are drilling the board by hand.

Some parameters to watch out for here are the Z depth for isolation cuts and pad touchdowns and, of course, the feed rate. I had to increase the depth from the defaults used by Line Grinder - it has to be slightly deeper than the copper layer size on the blank boards you are using and the defaults assumed a very thin layer of copper. You don't want to make it too deep though - because of the shape of the tool the deeper it cuts the wider the cut will be on the surface.

The drill file is run with a 1mm drill bit and will drill the holes for the through hole components. Line Grinder generates this file as if the top copper layer was facing up - if you are only doing single sided boards you will need to flip the X co-ordinates and translate the result back into place before running it through your mill. I have been using the grecode utility to do this - it is a very handy tool to have around for basic manipulation of your g-code files.

Work Area Leveling

Because the isolation routes are cut at a very small depth it is very important to have a level work area. My mill is a cheap one and the work bed is not very level relative to the tool tip - there is up to 2mm difference across the entire bed. When you add a sacrificial layer to work on this gets worse as it introduces it's own height differences.

I found a tool called AutoLeveller which is very helpful in this situation. It will take an existing g-code file and add a level probe operation at the start and then use those measurements to adjust the actual Z height used in the rest of the file. You can easily add a probe to your mill by connecting the tool bit to an input pin on the parallel port and connecting your PCB to ground - when the two make contact the connection is shorted out and the CNC software detects the probe contact.

Cable Breakout

The connection between the controlling software and the CNC mill is usually a parallel printer cable (if you have a newer PC that doesn't have an on board printer port you will have to get a PCI printer card). To make it a bit easier to insert additional signals on the various lines (such as a surface probe) I made a small breakout board that gives me access to all 25 pins on the cable including the ability to disconnect them on an individual basis. You can see a photo of the board to the right - with luck it will be the last PCB I have to hand etch. Using this board it was simple to add the probe - I simply connected fly leads with alligator clips on the ends to one of the ground pins and one of the unused inputs to the PC.

Using AutoLeveller alone was not enough however. My original method of holding the PCB on the work area involved using two pieces of MDF, the upper piece having a hole cut in it in which the PCB could be placed. The difference in Z height across the combination was unfortunately too much for AutoLeveller to correct for so the resulting PCB had isolation cuts ranging from being too deep into the PCB and cutting through the track altogether to being mere scratches on the surface.

PCB Holding Bed

My next attempt involved using a piece of pine off-cut as the base in which I milled out a 1.5mm deep area for the PCB to fit into. The benefit of this is that the area the PCB is sitting on is definitely parallel to the tool path giving me a much more consistent depth to start with - the main differences in height will now be from the PCB itself rather than a combination of bed and sacrificial surface errors.

Combining PCBs

Most of the boards I make are fairly small, less than 50mm by 50mm. Going through the process of setting up (levelling, setting the origin, etc) for each board would not really save me a lot of time over the toner transfer method of making PCBs. What I wanted was a way to combine multiple PCB designs into a set of G-code files that would fit on a single larger sheet. I didn't want to do all of this by hand so I wrote a Python script that would do a lot of the work for me. You can see the source for it here but please be aware that it is a work in progress and very much tied to my particular configuration. It may be a useful starting point for your own scripts though.

Completed Panel

The script uses the utilities grecode and opti to do most of the work on the g-code - it expects to find these tools on the path. I have modified the opti tool to compile on Linux and accept g-code on standard input and write the modified g-code to standard output. This archive (gzipped tar file) contains the Python script, the modified source for opti, the design for the parallel port breakout board as a DesignSpark project and some sample g-code for PCBs.

The script takes a list of board names as arguments (you can specify the same name multiple times if you want multiple copies of the same board), tries to fit the boards on to a single sheet of blank PCB (the default size is 150mm by 75mm but this can be overridden with command line arguments) and then combines the g-code files.

The tool expects three g-code files for each PCB - the bottom copper isolation routing file, the drill file and the edge milling file. It uses the default file names as generated by Line Grinder and generates output with similar names. The output files are a combination of the inputs with the appropriate translation and rotation operations performed on them so they will fit into the work area.

A sample run of the utility looks something like this:

``` $ ./pcbpack.py samples/attiny84 samples/attiny85 samples/serialonepin Checking dimensions ... OK Laying out boards ... Selecting iteration #0 with area 5620.05 mm2 Selecting iteration #1 with area 4651.11 mm2 Selected layout: 'samples/attiny84' (28.68 x 46.81) @ 5.00, 5.00 - rotated = True 'samples/attiny85' (33.76 x 29.67) @ 38.68, 5.00 - rotated = False 'samples/serialonepin' (38.46 x 20.62) @ 38.68, 39.67 - rotated = False Layout image saved in 'pcbpack.png' Generating combined g-code ... Optimising .. pcbpackISOLATIONGCODE.ngc Optimising .. pcbpackDRILLGCODE.ngc Optimising .. pcbpackEDGEMILLGCODE.ngc Operation complete.

The drill files generated by Line Grinder are difficult to manipulate as they are designed to be used with the top copper layer facing upwards. Originally I used 'grecode' to flip the x axis and then translated the co-ordinates to match them up to the bottom copper layer but this turned out to be unreliable. Luckily Line Grinder generates pad touchdowns, small drilling guides in the center of each pad to help with manual drilling. The commands to generate these are nicely bracketed by '(... pad touchdown start ...)' and '(... pad touchdown end ...)' comments in the isolation milling file - the pcbpack script extracts the X and Y co-ordinates from this section of g-code and generates it's own drill file from those.

Drilling Holes

Finally I run each of the generated files through opti to minimise the travel distance of the tool (this results in a 60% to 70% reduction in travel distance, massively speeding up the milling process).

Once pcbpack has generated the output files the isolation milling file needs to be run through Auto Leveller. Auto Leveller is a Java application and at the time of writing this doesn't support command line arguments so it is difficult to automate.

Having an automated workflow makes things a lot easier - I am slowly building up a collection of Line Grinder generated files for the boards I have designed so it is fairly easy to pick a selection of boards for a milling run. Overall the process is a lot quicker and involves a lot less manual handling than the toner transfer method I was using earlier - the end results are far more consistent as well. Given that this was the goal I was after I'm satisfied.

Future Work

At the moment I'm at the stage where I can replicate what I was doing with toner transfer with the added benefit of having the boards drilled and cut for me as well. I would like to see if I can do some things that weren't previously easy or possible with the old method such as milling very fine pitch tracks for surface mount components.

Some of the component footprints are not really suitable for milling either, circular pads require a larger annular ring for example - the small pads can lift off completely during drilling requiring some messy soldering to repair. Luckily DesignSpark makes it very easy to customise the PCB footprints and update existing designs with the new version of the component.

Should You Buy a CNC Machine?

That is a hard question to give a general answer to. It really depends on what you are doing. I'm very satisfied with the purchase and I think it will at least save me a lot of time even if it doesn't save me any money. Getting boards made at a PCB fabrication service like Seeed Studio is not that expensive, it is mainly the turn around time between sending away your order and having your boards delivered. If you go through several iterations of a board this can easily add up to months. Will the CNC machine I can mill a set of boards in an hour or two so I can go through two or three iterations in a single day which is a vast improvement. On the other hand, if I needed a reasonable number of boards (10 or more for example) I would still send them off for fabrication to take advantage of the better build quality and multiple layer boards.

The mill is not just for PCB manufacturing though - I will be using it to work with other materials as well such as structural components out of wood or metal and more decorative items in wood. As a companion tool to a 3D printer it allows for a much wider range of options when it comes to creating designs.

If you wanted to use the mill purely for PCB manufacturing I would think very carefully about it first - you would have to be making a lot of boards to make it worthwhile. If you already do a reasonable amount of woodwork or mechanical construction it can become a valuable tool in that regard as well - that might be enough to tip the balance for you.