Friday, 24 January 2014

SVG to GCode converter

It was a particularly busy night at BuildBrighton, last night. Not just in the number of visitors (it was great to see so many people hanging out though, with both the main areas and the workshop filled with people all hanging around, talking nerd) but in getting stuff done.

CNC Paul made some excellent progress with the CNC software and managed finally to get the machine carving out shapes from lumps of mdf. More impressive than that even, it managed to draw/drill a matrix of dots from our own hand-crafted G-code (something we've struggled to get working for a while now).

So having carefully laser-etched, hand-drilled and manually cut out some pcbs for our electronic board game, we're hoping that it won't be long before we're letting the CNC machine do most of the work - at least, pre-drilling and routing/shaping the boards, so we can line up the pre-drilled boards and screen print the etch-resist onto them, quickly and easily.

What currently takes about an hour to do, and often leaves us with wobbly-edged boards, and off-centred drill holes, we're hoping can be reduced to minutes, once we've mastered the CNC!

And the first step towards mastery is being able to produce valid G-Code for drilling holes, from our PCB designs. As regular visitors to this blog will know, we're real fans of ExpressPCB for designing our PCBs (sometimes DipTrace if we have to export to gerber, or for creating 3d images of the boards). ExpressPCB is really easy to use, but doesn't have an export option (it's free software, provided by a manufacturer so you can email them files in their own proprietary format) so we use CutePDF to get the software to produce a PDF file of our designs.

In fact, any PCB design software can be used with CutePDF to produce PDF files of the final designs. So with this in mind, we're focussing on working with PDF files (rather than have to create a load of filters/parsers to import lots of different file types).

The general idea is this: create a PDF file and load it into Inkscape. Manually find and colour all your drill holes (we're using red to identify a hole to be drilled). Since all our PCBs use the same 2mm pads with 0.89mm hole, we don't have to worry about tool changing and different sized holes; we'll just treat all our holes as exactly the same size.

From Inkscape, delete all the unnecessary information and leave just the red drill holes, and save as a plain SVG. This is where we're going to start parsing, to create our g-code. Inkscape creates peculiar SVG data: it's strictly correct, and syntactically accurate to the SVG specifications, but it's a peculiar way of doing things.

Let's say you draw a circle, at some arbitrary point on the screen. Then you edit the co-ordinates, so that it sits at, say 10,10. When the image is saved as SVG, Inkscape keeps the original co-ordinates at which you drew the shape, and applies a matrix transformation to the shape, to get it to end up where you wanted it. It basically means that when you save even a really simple, single shape in Inkscape, the SVG is almost unsuable from the outset!

The example above shows a grid of dots, placed at 5,5mm then 10,5mm then 15,5mm.
As you can see from the crazy decimal placings after each set of co-ordinates, the dots have been placed at one point on the screen, then translated (moved) to their final resting place. The first thing we need to do, is to "bake" our co-ordinate points and translation matrices together, to get the actual point that each dot sits on.

For testing we created a grid of dots, starting at 5,5mm and spaced 10mm apart.
Then we had to parse the SVG, getting each co-ordinate point and applying the related translation matrix (if any) and spit these values back out. In the screenshot below, the results of this are shown in the centre panel

Our co-ordinate points at least now look consistent (there are a few 19.44821 values in there for example) but they don't seem to relate to the points we created in the drawing. And after a bit of digging, we found out why: the SVG specification does not allow for units - each image is simply made up of points, and then a transformation matrix (what else?) is applied to the whole image to scale it up/down, so that it matches the required units. It turns out that the default unit for Inkscape is the pixel. And Inkscape assumes a 90 DPI resolution.

Now one inch is 25.4mm, so we need to multiply each point by 25.4/90 (or about 0.282222) and doing this got us somewhere nearer, but not quite (since the dots were being handled as a single entity or group, and the entire group had a translation applied to it, so that each dot would eventually appear in the correct place in the document).

Since we're going to be working from a 0,0 origin on the CNC, we looped through all the points and found the lowest X and lowest Y values. Then subtracting these from each set of co-oridinates, we started to get something a little more useable.
In fact, after rounding to two decimal places (the CNC software only goes to 1/100th of a millimetre and the actual machine really only works to a resolution of about 1/30th of a millimetre) our final co-ordinates looked just like we wanted them to:

A grid of dots, starting at 0,0 followed by 10,0 then 20,0 and so on.
We inserted the drill plunge command between movements (Z down to zero, back up to about 6mm then move to the next point) and suddenly we've some valid-looking g-code to describe our grid of dots, from a document loaded into Inkscrape. This is great news!

The next step is, obviously, to load an actual PCB design and drill the points and see how these line up to the 1:1 printed image. It's only baby steps at this stage, but it's looking quite likely that we're going to be able to drill (and rout out) PCBs from pretty much any CAD/PCB design software after all....