HackSpace magazine

How I Made A CNC Mill

By Will White. Posted

Making PCBs by hand can become a bit of a mission! Etching a board takes ages, with numerous processes. Then there is the drilling of lots of holes, which normally end up with them being out of line and the components not fitting.

It was getting to the point where I was reluctant to etch PCBs. I was sending designs off for them to be made by a board house, waiting two weeks for my custom PCBs to arrive, only to find I’d made a mistake with the design. I wanted to make a board quickly, test it, modify if necessary, before committing it to be made professionally.

I decided I wanted a mill for PCBs.

Looking about, there are many small CNC mills on the internet for around £125, but you’re not getting much for your money, compared to a 3D printer kit of a similar price. So, I decided to adapt a 3D printer into a CNC mill: this would give me a much bigger work area. Also, the spare parts would come in handy elsewhere.


Having a look in my salvaged parts bin, I could use a DC motor and some linear rails pulled from some old inkjet printers. That would work for the spindle and the Z rails. I also have some T-nuts and other bits left over from a 3D printer project, which should keep the cost down for extra parts.

Now for the donor printer – it has to have:
• A frame made from 20 × 20 aluminium profile, not one cut from sheet material.
• Linear rails or (V-groove) wheels – NOT unsupported rods, as these can flex.
• A heated build plate would be nice, as it would have a bigger power supply.

I could upgrade the motors and spindle at a later date.

I identified some new 3D printer kits for around £110. It’s also worth looking at second-hand machines, especially ones listed as ‘for parts’ or ‘not working’. I finally bought a HC Maker 7 – a CR-10 clone with a 30 × 30 cm heated bed. It was listed as not working.


I opted to use Fusion 360 to design the machine, because I could create the whole machine in software first, checking components fit together before printing them. This approach should save me a lot of time and filament by reducing the amount of 3D printing needed. In short, planning out the project first may feel like it’s using up time, but in the long term, it saves much more time (and money) than it takes up.

Every part of any project has to be a compromise. Time vs. money vs. functionality vs. aesthetics vs. quality etc. Of course, everyone wants a beautiful machine that does everything, costs nothing, and is working within seconds.

Now back to reality! I’ve got a 3D printer, therefore many of the components will be printed.

I want a machine that:
• Is as stiff as possible. This gives a better-quality nish to workpieces and can open up the range of materials to work with.
• Has minimal play in all axes.
• Can be upgraded at a later date, to use better-quality components and stronger motors.
• Can mill PCBs as a minimum.

I designed the main components with the idea of being able to replace them with 5 mm aluminium plate in the future. For now, each component was designed with consideration to its orientation during printing, as this will affect its strength.

I printed all parts on my Replicator 2X. Structural components were printed at 30% infill, four perimeters, and three top and bottom layers. Non-structural components were printed at 10% infill, two perimeters, and two top and bottom layers. All in ABS.

Other decisions to make at this stage were:
• Moving gantry or a moving bed?
• Lead screws or timing belts?


First, I reorganised the base of the printer. This entailed swapping the central bars with the outside bars along the Y axis, so that the Y-carriage will run on the edge of the frame, and the spoil board will be supported underneath.

My first problem was how to stop the machine from flexing backwards and forwards. The original printer had the Z axis attached to the base by a bolt and a small bracket. There was a lot of flex within the frame, I managed to snap one of the acrylic brackets by just moving the printer around.

My solution was to use two vertical sections of frame braced with two 45 mm sections, on each side.

The Y-carriage

I originally thought that I would trim the uprights to size at the end, but I decided to leave them to allow for thicker stock materials.

The next issue was how to stop the wheels in the Y-carriage from binding. On my first attempt at making the Y-carriage, the wheels were too close together, only by a fraction of a millimetre, but the carriage would bind up and stop moving. As each carriage took over six hours to print, it was not practical to move the holes for the axles on a trial and error basis. My donor printer uses eccentric spacers to solve this problem (a spacer with an off-centre hole). You turn the spacer in order to adjust the tension of the wheel. These spacers wouldn’t work with my design, but they did inspire the solution.

I took the spacer from my design and mounted it onto an offset cog. I then added the corresponding cog-shaped hole into the side of the Y-carriage. A few penny washers ensure everything stays in place. Now, by turning the cog into a new position and rebuilding the carriage, I can change the tension on the wheels.

The offset spacer: turn the cog to a new position and rebuild the carriage to alter the tension on the wheels

To set the tension in the X axis, I first fixed the lower rail in place with the X-carriage in situ. Then, using a spare corner bracket, I moved the X-carriage to the end of its rail and clamped the upper rail in position. You need to repeat the process on the opposite side, and bolt everything in position before removing the clamps and the spare corner brackets.

Holding the mill together while it’s assembled


To keep the machines cutting in the right place, I reused some endstops from the printer. For the Z axis, I built a Hall effect endstop from open-source designs. The spindle motor is controlled from the MOSFET for the heated bed.

I had originally wanted to use GRBL (firmware) to control my machine as it’s designed for CNC routers. However, the motherboard from the original printer had been designed in a way which was not compatible with GRBL, so I had to use a 3D printer firmware. I chose Repetier-Firmware because it had a CNC mill mode, and the online setup tool was easy to use. See GRBL vs. Repetier section below.

The Repetier website has extensive documentation on how to set up your machine.

The key points were:
• Select the correct motherboard from the list, else create a custom profile.
• Add the machine dimensions.
• Check your endstop settings and motor settings.
• Tick the ‘support CNC mill’ checkbox.
• Change the ‘default printer mode’ to CNC mill.

For the first time, download the entire firmware. For adjustments to your profile, you can download the Configuration.h file and replace the existing
version in the firmware folder. Now open Repetier.ino, using the Arduino IDE, and upload the firmware to the motherboard.


I’m using Fritzing to design PCBs and exporting them as Gerber RS-274X files into FlatCAM.

FlatCAM does a good job of generating G-code from Gerber files. However, because I’m using a firmware designed for additive manufacturing and not one for subtractive manufacturing, Repetier does not like to work in the negative space. So you need to tell Repetier to permit the machine to work in the negative space by adding G1 S1 to the beginning of the G-code file.

You can do this by either editing the G-code in a text editor and adding G1 S1 to a new line below the first ‘%’, or you can get FlatCAM to do it for you automatically. Under the Options tab, find the text box to add custom G-code to the start of the file. Enter G1 S1 in that box in the line beneath the ‘%’.

While you are there, I found it worthwhile adding the lines G00 Z0.0000 and M18 Z to the end G-code box in the lines above the ‘%’; these commands move the Z axis to zero and disable the Z stepper motor (while keeping the X and Y steppers engaged) once it has finished the job. I use this to change the tool and set it to the zero position before starting the next job.

When FlatCAM writes speeds to its G-code file, it does not add G00 to the beginning of the line. Repetier does not like this, and runs the machine at any speed it fancies, so you have to add the correct syntax manually. Open the G-code file in a text editor and find the line near the top starting ‘F’ – it might say ‘F100.00’. Add G00 to the beginning of this line, so it reads ‘G00 F100.00’; this now tells Repetier to run the machine at a speed of 100 mm per minute.


I feel that I have achieved everything I set out to do with this mill. It’s got a work area of 290mm × 258mm × 99mm and can cut PCBs and other soft materials. In total, I spent £156 on this machine, of which £125 was for the donor printer. Compare that with a machine from China with a smaller work area of 240mm × 180mm × 45mm for £170, which can cut similar materials.

What I didn’t anticipate was how much I would learn along the way. I would encourage people to give it a go: create a pen plotter, a mill, or a 3D printer for yourself!

This machine is not finished – already I’m thinking how can I improve it. Dust extraction and an enclosure are first, followed by a probe for tool length, and aviation-style connectors. Eventually, I’ll give it bigger motors and a 32-bit board.

A milled PCB ready to be populated

GRBL vs. Repetier

GRBL’s primary design is for CNC mills, routers, and laser cutters. Repetier-Firmware is designed for 3D printing.

Both firmwares can be used interchangeably, but using firmware designed for a slightly different purpose normally results in some form of compromise.

Repetier adds support for SD cards and LCD screens, whilst GRBL wants a host machine to offer that support.

Repetier does not support all the functions of GRBL. Repetier currently only offers on/off control for spindle motors and no PWM control. Repetier needs to be told every time to work with negative coordinates, otherwise, it thinks it’s going to drive the hotend into the build platform.

For endstops, GRBL uses the Pin Change Interrupt (PCINT) function on the AVR chip’s dedicated pins, whilst Repetier polls the endstop pins on a regular basis. So Repetier can use any pin for the endstops, whilst GRBL has to use specific pins.

I wanted endstops on my machine, but the 3D printer’s motherboard didn’t have any free PCINT pins available. This forced my choice to use a 3D printer firmware rather then GRBL.