Desktop CNC Milling Machine

I'm a sucker for cheap Chinese gear.

I just bought a small (30cm x 30cm) desktop CNC mill from China, to make PCBs and other things, from CNCDIY.

Its a smallish machine, with a welded aluminium frame and recycled stepper motors. I'm still waiting on the control electronics, but it looks like it will do the job.

Some initial thoughts:

  • The wiring to the stepper motors is Cat5 - I should replace this with something with more current capacity
  • There are no home/limit switches - I will have to add these to get a usable device out of it
  • The spindle is not switched - I will have to come up with a way to PWM it from the computer
  • There is a wire soldered where the fuse should be on the stepper control board


Here is the CNC mill, complete with a rather liberal coat of bright blue paint. It is a moving workpiece machine - I would have preferred a moving gantry as it would take less space.

Control Board

The control electronics came installed in a PVC DVD case.

The board is based around an array of 3 Allegro 3977 stepper controllers. These controllers support up to 8 microsteps for increased positioning resolution (but at the cost of speed and linearity).

The small red switches (labelled 1S1, 2S1 & 3S1, but the labels are obscured in the photo) control the microstepping level, see the table in the bottom right of the board.

The pots (1W1, 2W1 & 3W1) control the maximum current through the motors. Unfortunately, the motors are covered with a thick layer of paint, so I can't tell what the current rating is.

Limit switches can be connected to P4, a pin header in parallel with a female DB9 connector. I found that the internal pullup resistors on my parallel port were insufficient (or nonexistent) so I could not get a clear reading off the switches until I added 33kΩ resistor between each of the switch lines and +5V. I did this by soldering the resistors in between the pins on the P4 pin header.

Pin Header P4
DB9 Description
1 1 Ground
2 6 Ground
3 2 ???
4 7 ???
5 3 X Home
6 8 Y Home
7 4 Z Home
8 9 A Home
9 5 +5V
10 5 +5V

An additional axis can be connected to P1, a pin header in parallel with a male DB9 connector.

Pin Header P1DB9Description
1 1 Direction
2 2 Ground
3 3 Ground
4 7 Step
5 6 Ground
6 8 Ground
7 4  
8   N/C
9 5 +5V
10   +5V


There is a single jumped marked 'X' which toggles the enable line on all the axes.

The [123]X4 jumpers seem to be related to the reference voltage for the current limiting PWM - not sure how just yet. Maybe moving it to "off" (pins 2&3) disabled current limiting?

Finally, there is a parallel port connector, also in parallel with a pin header.

Parallel Port Pin Header Description
1 1  
2 3  X Step
3 5  X Direction
4 7  Y Step
5 9  Y Direction
6 11  Z Step
7 13  Z Direction
8 15  
9 17  
10 19  
11 21  X Home
12 23  Y Home
13 25  Z Home
14 2  
15 4  A Home
16 6  
17 8  
18 10  Ground
19 12  Ground
20 14  Ground
21 16  Ground
22 18  Ground
23 20  Ground
24 22  Ground
25 24  Ground

EMC Setup

After some trial and error, these are values I found for the EMC Stepconf setup:

Setting Value
Steps per revolution 200
Microstepping 8
Leadscrew Pitch 1.75mm

PCB workflow

  • Design the schematic in Eagle
  • Layout the PCB in Eagle
  • Print out the PCB on a laser printer, think for a bit then go back and fix the problems
  • Generate GCode with PCB-GCode
  • Optimise the GCode with PCB-GCode Optimizer which can be downloaded from MediaFire. GSuite is also quite good.
  • Drive the mill with Linux EMC

22nd June 2009 Update

I soldered some microswitches salvaged from old DVD drives together and attached them to a stripped serial cable to create home/limit switches for the machine. Things aren't quite working correctly - the machine is unable to read the switches, even though I have confirmed at the parallel port connector that they are shorting to ground correctly.

23rd June 2009 Update

Trying to figure out why the switches weren't being read correctly, I moved them to the parallel port that controls the laser engraver. One switch now read correctly, but the rest didn't. After some probing with a multimeter, I realised that the lines are shorted to ground when the switches engaged (as expected), but float at 0V when the switches are free. It looks like the internal pullup resistors are worthless on the parallel ports I'm using. I've added 33kΩ resistors between each of the switches and +5V to pull the lines high. Linux EMC can now correctly read the state of all the switches.

When setting up the homing under Linux EMC, I came across this gotcha: If your home position is 0, and the initial position is positive, then your home search velocity must be negative in order to seek home correctly, otherwise, it hits the other limit switch and gets very confused.

29th June 2009 Update

There was a huge amount of runout in the spindle supplied with the machine. I've picked up a second unit (a $30 special from ALDI) to play around with. Since unmounting the spindle is a bit of a pain, I tried the collet from the new one on the original spindle - no more wobble! It seems that the collet is extremely important in keeping the bit aligned.

2 July 2009 Update

I bought some 19mm pine to create a level surface on the mill. The idea is to bolt it on top of the Y axis platen. This will then be milled to create a level surface, ready for cutting PCBs on. To generate the G-Code for the surface, I used Michel Gouget's Surfacing Druid. For now, I am just using a single layer. Eventually, I plan on using 2 layers, with an array of nuts trapped between them and bolt holes going from the top to the nuts to provide a way of securing workpieces.

3 July 09 Update

The slight banding visible I believe is due to the spindle not being perfectly perpendicular to the workpiece. I will have to figure out how to measure and correct this. In the meantime, I will re-run the resurfacing at 90 degrees to even out any uneveness.

5 November 09 Update

I've noticed there is a bit of skew of in the mill, which results in double sided PCBs not aligning properly, and squares being turned into parallelograms.

To measure the skew, I cut 4 holes at the corners of a 10cmx10cm square, and measured the diagonals (A is top left to bottom right, B is bottom left to top right) and the bottom edge (C). The angle at the bottom left of the square is 'a'. Using the cosine rule: cos(a/2) = ((B/2)^2 + C^2 - (A/2)^2) / BC. For me, A = 140.38, B=141.45, C = 99.63, giving me a=89.579°.

Now that I know the angle, I can correct for the skew using the millkins kinematics module for EMC2 (trivial kinematics with skew correction).

The millkins.skew parameter tells the module how much X is skewed by when Y moves, so if Y moves 1 unit, X will move 1/tan(a) = 0.00734 units, so I will set millkins.skew to 0.00734.

4 March 10 Update

I have built a new Z axis plate for the machine to hold multiple toolheads:

The TB-350 spindle provides the ability to cut PCBs accurately, as it has very low runout figures. The mini-grinder will be used for work where torque is more important than accuracy. Finally, the plastruder will be used for 3D printing.

The TB-350 spindle was ordered without a motor, as the provided motor was 110V. Instead, I am using a Hobbymate HB3650 from Dealextreme - a 1.8kW (peak) BLDC motor designed for RC helicopters. At this time, I have to run it at very low speeds as the spindle is geared up - I will have to lathe a new pulley for it to gear the spindle down, allowing me to deliver more power at greater efficiency. The motor is driven by a Mystery 60A BLDC controller which receives a servo signal and spins the motor at a speed proportional to the requested servo position. The motor subsystem is driven by a 24V 350W switchmode power supply from Ebay.

To generate the servo signal, I have written a program utilising MHVlib, a library for AVR microcontrollers which I have designed for efficiency. This runs on an Arduino, and takes a number from the serial port, and positions the servo output based on that number. Future versions will run on the Reprap Extruder Controller board, which will drive the spindle as well as the plastruder. It will also use an optocoupler to calculate the spindle RPM and adjust the motor speed to keep the spindle at the desired RPM.

To construct the new plate to mount the spindles, I started with a 150x125x13mm block of aircraft grade aluminium (bought for $12 from a local metalworks shop). Note that at this point, I already had a failed plate mounted (one column of holes for the linear bearings were misplaced), along with the new spindle. While the new spindle is accurate, it is not particularly torquey, making metalwork difficult. Due to this, instead of milling out the whole plate, I just laid out pilot holes using GCAM, drilling 3mm deep pilot holes on the mill, and then deepening them on the drill press. Once all holes were drilled all the way through, I bored out the holes to be tapped to 4.5mm, and the other holes to 5mm. Finally, the 5mm holes were all drilled partially using a 9mm drill bit, then a 9mm mill bit, to create pockets to allow the bolt heads to site below the surface of the plate.

I finished up the plate using a small wire brush in the drill press to created a brushed effect, to hide the scratches I created while making the plate.

The plate was then mounted using a new set of SC16UU linear bearings, as the bolts in the old ones were seized (I twisted the heads off them!), rendering them useless.