Java program to probe Z for PCB milling

 In my first attempt at PCB milling last weekend I had my PCB bend by as little as 0.04mm.
Clamping a PCB in a vice the center will bend upwards or one side be lower/higher then the other.
Even if you can't see it and can't meassure it with hand tools but only with the z-probe of your CNC.
Given a cutting depth of 0.02mm to barely remove the copper layer, this is too much.
So last night at the CCC-Freiburg meeting I wrote myself a small Java program.

It takes the g-code output of PCB2GCode. (See last blog posting about parameters.)
You have to have your PCB mounted already, positioned your cutting tool and set an initial Z=0.
You also need an electrical Z probe (simple cable clamped to the PCB and your actual cutting tool with an input pin configured as probe shortened to GND or VCC when both touch).

Then it determines the position and size of the PCB and asks you to take a number of Z-probe meassurements on your CNC to see very precicely what height the PCB actually starts at in these locations.
(It will be more likely to be Z=-0.0123 or Z=0.0234 instad of a perfect Z=0.00000)
It tells you exactly the G-code you have to copy&past&run for MACH3.
(including G20/G21 setup of the proper unit first, to raise yourtool  and jog to the right location.)
By default it asks for a 3x3 grid of 9 meassurements.
One per corner, one in the center and one in the center of each side.

Then it reads the g-code again and writes a new g-code file with the following changes:
  1. Adds a bilinear interpolation of you real position Z=0 as an offset for each Z position mentioned in the code.
  2. Adds a Z value to all movements in X+Y that don't already have one using the last Z position seen plus the offset.
  3. Breaks up all movements that are longer then 1/6th of the diagonal of your PCB into smaller movements to follow the curvature of the PCB.

Update: Version 2


Milling PCBs using PCB2GCode

I'm trying my hands at milling a PCB.
It will be a USB isolator for my CNC.
Here I'm collecting my notes as a step by step guide to do the same again later.

Even if you are etching your PCB, drilling mounting holes and vias automatically could be a reason to visit your local CCC Erfa Kreis, Hackerspace or FabLab.


You start with Gerber files. (If you have hpgl or svg data, your CAM software should already be able to do this without pcb2gcode.)
  • .gbs - Gerber Bottom Solder Mask Data
  • .gbo - Gerber Bottom Overlay Data
  • .gbl - Gerber Bottom Layer Data
  • .gbp - Gerber Bottom Paste Mask Data
  • .gdd - Gerber Drill Drawing Data
  • .gko - Gerber Keep Out Layer
  • .gpb - Gerber Pad Master Bottom Data
  • .gpt - Gerber Pad Master Top Data
  • .gtl - Gerber Top Layer Data
  • .gto - Gerber Top Overlay Data
  • .gtp - Gerber Top Paste Mask Data
  • .txt (not human readable)
( filesuffix.com helped be with that list)


The go-to tool seems to be PCB2GCode.
Sadly it is only available for Linux. Not for Windows (where my MACH3 CAM software lives) nor MacOS.
However there seems to also be a beta website PCB2GCode online by Fablab Amersfoort.


The PCB2GCode website tells you to look at pcb2gcode --help. Nothing more.
No example. Not even an explanation of the file endings listed above. (They speak of .gbr wich is the only extension you'll not find a file for.)
Top-layer (.GTL) and bottom layer (.GBL) are easy.
TODO: Outline I have not a clue.
TODO: Drill data seems to be missing for me. :(


pcb2gcode --front USB_Isolator.GTL --back USB_Isolator.GBL --metric --zsafe 5 --zchange 100 --zwork -0.02 --offset 0.02 --mill-feed 100 --mill-speed 6000
Importing front side... done
Importing back side... done
Importing outline... not specified
Calculated board dimensions: 1.7in x 1.7in
Current Layer: back, exporting to back.ngc.
Warning: pcb2gcode hasn't been able to fulfill all clearance requirements and tried a best effort approach instead. You may want to check the g-code output and possibly use a smaller milling width.
Current Layer: front, exporting to front.ngc.
Warning: pcb2gcode hasn't been able to fulfill all clearance requirements and tried a best effort approach instead. You may want to check the g-code output and possibly use a smaller milling width.
No drill file specified.


Attention: Website only expect everything to be in these strange and obsolete "inches" thing.
The command line tool can be changed via
"--metric                            use metric units for parameters. does not affect gcode output"
for it's parameters but the output will still be imperial g-code.
No Rebels seem to have converted this imperial stronghold into metric units yet.

The website seems to require a drill file. The command line tool can do without.

--zwork The default seems to be "0.0008 inches = 0.02032 millimeters" for isolation milling.
--offset  You need to set half your tool diameter or a greater value for the --offset parameter.
--zsafe travel height
--zchange z height for changing from milling to drilling tool
--mill-feed feed rate
--mill-speed spindle RPM


Even when set to metric, MACH3 shows the maximum dimensions in imperial inches.
Use an electrical probe to set Z=0.
I made a special probe cable for this purpose as the toolheight-sensor wouldn't reliably touch the top side of the PCB.
Also make sure the PCB is insulated against the machine so the probe isn't always triggered.

I used paper to do this and also to level out the board (after meassuring all 4 corners).
TODO: My board was still slightly bent. I need a way to compensate for Z-differences in the 4 corners+center by software.

--mill-feed 100 --mill-speed 6000 seems to be a good value to start with.


I tried a chinese engraving tip and it wasn't a good fit.
The tiny Z errors and the fact that the engraving tip quickly gets bigger the deeper it gets are a bad combination.
The smallest flat cutter I could find is 0.8mm. Way too large. I need to look for something along the lines of 0.1mm.


DONE:  Wrote a program to take 9 Z meassurements and adjust the g-code PCB3GCode returns.

(EMC2 specific) There seems to be script named "etch_z_adjust" that uses the electrical probe to meassure the exact Z=0 height every 10cm before starting to mill.

A thin layer of cutting oil seems to help too.

(Reprap specific) This "PcbSubtraction " pcb2gcode postprocessor adds probe commands to the g-code itself but is limited to 315 probes per PCB.

There is also a MACH3 visual basic macro but I just can't find the actual code to try it.


electrical noise issues with CNC

Starting yesterday I got terrible electrical noise issues with my CNC milling machine.


  • I was able to see the noise on my super-cheap pocket-oscilloscope
  • Replacing the RS485-cable with a shielded one and connecting the shield to GND on the USB2RS485 converter helped a bit
  • I'm investigating some USB isolators one, two and RS485 isolators
  • It was pointed out to me that the VFD is not connected to PE. PE ends in the line-filter. I should change that.
  • Connecting VFD-GND to the Spindle case reduced the noise as meassured on the Z-stepper case a lot but did not eleminate it.
  • Noise is greatest on the VFD line filter case, second on the spindle and steppers, least on the USB cable shield and RS485 cable shield now. 
  • Currently revisiting CNC Noise
  • Connecting VFD-GND to mains PE (protective earth) didn't change a thing. At best it made the noise much worse. 

The Players

  1. Touchscreen PC running MACH3
  2. Huanyang VFD inverter - controller and power supply for the spindle (motor that does the milling)
  3. powered USB hub
  4. USB to RS485 interface
  5. Control box containing:
  6. USB control board -  creating opto-isolated STEP+DIR signals for the
  7. 4x Stepper Driver Boards

 The Problem

Whenever the spindle is running and USB from the USB control board is connected to either the USB hub or the PC, the steppers twitch and jog around wildly.
This issue did not happen since october and just started yesterday.
4 hours earlier I dan 6+hour milling jobs without even loosing a single step.
Changes made:
  • coiled up cable to some lamps
  • coiled up power+USB cable to PC (undone, no change)
  • coiled up DC power cable of USB hub (undone, added ferrit core, no change)
  • switched oin a refrigator in the room (undone, no change)

The Setup

All share the same power socket.

PC connected to  Powered USB Hub.
USB Hub has ferrite core on it's DC supply power.

Powered USB Hub is connected to USB-RS485 converter.
RS485 converter connected to VFD via TX+ and TX- but not GND

VFD connected to spindle via shielded cable.
Shield on the cable not connected to anything.
VFD connected to mains via line filter element.

Powered USB Hub is connected to USB control board via USB cable with 2 ferrite cores.

USB control board connected to Stepper Driver Boards via +5V, STEP and DIR.

Stepper Driver Boards connected to their own 24V? 48V?  power supply.
Stepper power supply connected to mains via filter element.

Page 17 of the manual of the USB control board (link below):
 Photo of the inside of the Control Box containing the USB control board, the 4 stepper driver boards and their power supply:

Possible solutions

  • Should I connect GND on the USB control board to GND on the stepper power supply even though the manual doesn't mention it?
The stepper driver boards get A+ A- B+ B- as STEP+DIR. So they clearly expect a differential input independent from GND. getting A+=B+=+5V and A-=STEP B-=Dir that is exactly what they get.
  • Should I add a capacitor between USB control board GND and it's +5V to filter anything but DC?
  since the stepper driver boards get a differential input and don't care for either.
  • Should the GND contact on the VFD be connected to anything?
Manual of the VFD only mentions to use that to give muiltiple spindles a single connection to ground.
  •  Maybe I should connect the VFD GND to the spindle case as mentioned here?
Original wiring didn't do this.
DONE, did not solve the problem
  • ????? 
The PC power cable and the RS485 cable seem to have a large influence on the frequency of these interferences.