Introduction: Make Awesome 3D Geometry by Programming CNC-code


CNC-machining makes it easy to cut out shapes very precise and consistent. But often it stays limited to cutting out 2D shapes, for obvious reasons. While learning how to use the CNC myself a while ago, I dug deeper into creating inspiring 3D geometry with the help of programming. This gave me the knowledge to be able to create quicker and more efficient custom toolpaths that would have been harder or impossible to setup with standard CAM-software.

In this instructable I'll guide you through the process of creating advanced mathematical geometry using programming in combination with cnc-machining. The knowledge you will gain from it will make you able to set up more sophisticated and more efficient toolpaths and will prevent being restricted by the limits of your CAM software.

Quite some of the knowledge in this instructable builds upon Jens Dyvik's research. A lot of the examples that will be given were made using the Colinbus at Fablab Genk but some were also made on a Shopbot. The machines I've used were set up in the metric system so don't get confused with the numbers if you normally work in imperial units.

If there's anything that is not clear or wrong, let me know so I can edit the instructable.

Step 1: Get Familiar With CNC

If you've never used a CNC before, some of the terms used in this instructable might sound weird. I therefore recommend getting familiar with a cnc before trying similar things like in this instructable. Use the CAM-software that comes with the machine you have access to as it will provide an idea on the workflow for starting a milling job.

CAM-software is unfortunately not a plug and play thing. You need to know about feedrates, rpm, milling bits and so on. And even though the software makes it easy to set up the toolpaths, you still need to work within the capabilities of what the program is capable off. Having full control over what the machine will do, as we will learn in a later step, gives us the opportunity to change every part of the toolpath setup which is not always possible in CAM-software.

Step 2: What Is G-code

G-code is the language that makes your computer communicate with the CNC-machine. Inside your CAM-software you convert your CAD-files (3D or 2D) with the post-processor to a file which your machine will understand. This is a code made or used by the machine manufacturer for their machines. It's a set of commands that tells the machine where to go and what to do and in a simplified way it says something like this:

- Put spindle speed to 18000 rotations per minute

- Set move speed to 35 mm per second

- Move to coördinate x100, y100 above the material

- Move 25 mm in z-direction down and back up

- Turn off spindle

- Go to origin / 0-point on the machine


The differences between these g-code are for example how they define the command to move, or in which units they work, or if negative numbers in the z-direction are above or below the 0-point, etc. In the next step we'll have a look at dissecting this code to be able to write your own code for the machine you use.

Step 3: Understanding the Code From the Machine You Have Access To

To understand which parts of the code does what you can create a simple example file using your cam-software. The post-processor converts the information into the right code for the machine. We can then analyze this file and reverse engineer how it works. You can just open it in notepad and read the lines of code. If you have a look at the example of the shopbot code, you'll see that a lot of the code is just coördinates which tell the machine where to move the spindle to.

And then depending on which machine you use, the rest of the code can be quite straight forward (e.g. in the example of the shopbot code M3 means to Move to a specific coördinate in 3 dimensions). Sometimes you can also find information online for a clear explanation. Some manufacturers might give the details themselves, like Shopbot for instance:

We need to know what these different commands do as in a later step we will create this kind of code ourselves using programming.

Step 4: Programming - Grasshopper

So now we have a better idea on how the code for the machine works, we can use this information to create our own post processor. I've been using Rhino with its versatile plugin Grasshopper for this. Rhino is a CAD software which combines a 2D drawing and 3D modeling environment in one. Grasshopper is a plugin for doing node-based programming inside Rhino and it widely extends its capabilities. I think there's other programming languages or software that might be able to do similar things, but I find this combo of programming and a 3D environment the easiest to do this kind of stuff because you get a visual representation of what is happening in your code.

What we'll be doing in this instructable will allow us to draw lines in 3D and make a toolpath file that will tell the machine to follow those lines. In the previous step we saw that the toolpath consists of coördinates. Which means we need to convert our lines into points, extract the coördinates from those points and turn that into the right format. We also need to keep in mind that between the lines we will want to move above the material because we don't want to cut in the material when it goes from one line to another one. So that means we need to copy the first and last point from each line and insert a z-height above our material.

Or if I would simplify the process it would become like this:

- Input lines

- Optional: Sort lines to make sure the lines are milled in the right order, if necessary. (can also be used to speed things up a lot)

- Convert lines to a list of points

- Copy first point and last point from a curve, extract coördinates, replace the z-coördinate with one that is above the material, make new point from those coördinates and insert that point in the list on the right place (before the start point and behind the last point of each line inside the material).

- Extract coördinates from each point

- Convert these coördinates to the right syntax (the g-code that works specifically on your machine)

- Combine this with the start and end-code of the file

- Turn into gcode file.

Step 5: Generate Toolpaths & Test

I made a basic grasshopper definition which I added as an example. It does the steps I described in the previous step and converts 3D lines into shopbot or colinbus code. I think it can be quite useful to better understand how it's done.

Saving the gcode file from the grasshopper file you do by right-clicking the yellow panel with the code (on the right in the file) and choose a stream destination, meaning where you will save the file. When you name the file make sure you chose the extension that your gcode uses. For Shopbot it's .sbp, for colinbus it's .c3d, etc... You can find out what this is by looking at the toolpath file exported from the cam-software, as we've seen in step 3.

Before you're trying your self-made code out for the first time, make sure you read through the code and see if everything looks like it should. Then run the file in the air and look what the machine does. If everything looks like it should, run the file into the material and feel the satisfaction of milling your self-programmed code.

From here the exploring in Grasshopper can start. The possibilities of combining Grasshopper with cnc-machining are endless. In the next steps I'll describe how I created some examples using these tools.

Step 6: Example 1: Convert Image to 3D-milling Using a V-bit

Inside grasshopper there's an image sampler which can read the black and white value of an image and maps that to a number between 0 and 1. With 0 being black and 1 being white. So what we can do is remap that value to a different domain that will control how deep our v-bit goes. That way we can create different line thickness inside the material as if we're pushing harder and softer with a pencil on a paper.

Since the image sampler needs points as an input we can quickly move those point to the z-depth we want. If we then sort our points into groups we can't create 3D polylines from those points and use a postprocessor like in one of the previous steps to turn this into gcode. When you're milling it out it is advisable to paint the top surface to get a nice colour contrast.

I added the original file I used, to be able to learn from it. Be aware that the postprocessor used in this example file is for a Colinbus and not a Shopbot.

You could also convert the postprocessor to take points as an input and just drill every time to a different depth with the v-bit. In that way you can create halftone images on the CNC like I did the first time I tried my own code (see previous step images).

Step 7: Example 2: Curvy Lines

This example is partially manual drawing and partially grasshopper. So what I did was creating 4 lines, of which the most top and most bottom one are basic arcs from a circle and the two lines in the middle are random curly waves I drew. I then used grasshopper to create transition lines between them; so-called "Tween curves". I wanted to create a line surface where these tween curves are the top of the surface. So what I then did was making lines in between those transition curves which the v-bit will follow.

Now we end up with the curves in 2D, but we want to make them 3D so the edges end up at the same level. So what I did was dividing the v-bit curves up into points and for each point I calculate the distance to the closest curve. Since I am using a 90 degree bit I know that the distance to the closest transition curve is also our v-bit depth (see v-bit image). If you don't understand why you can search on trigonometry. So moving the division points in the z-direction down using the distance to the closest curve, we get a 3D curve that we can use with the post-processor again.

I also sorted the curves and flipped every other curve. This increases the milling time as it makes sure that the machine doesn't move to the other side above the material with every curve.

I added the rhino and grasshopper file so you can dissect how it's made. It's an old definition so I'm pretty sure there's stuff that can be done faster or in a different way.

Step 8: Example 3: Sinus Bowl

This one I made while I was doing some exercises on learning Python inside Grasshopper. There's quite some steps involved before the final milling and I'm sure there are quicker ways to do this then how I did at the time, but here it goes.

Inside the python component I created the code to generate points for creating a 100x100 mm square sinus wave surface. (I think I learned this from some tutorial but can't remember wherefrom. If anybody knows, tell me so I can add it)

To create a smooth transition going from a flat surface to this sin wave surface I remap the numbers using a graph mapper. These will generate the scale factor we will use. It's not the cleanest way to generate this surface but it works for this application. So I scale each point in the z-direction from the highest point of our sin-surface and the pieces that will be flat are scaled with a value of 0.001 creating a flat looking surface (even though it's not perfectly flat).

I then calculated the distance between the center of the square and each of the points from the sin surface we created. I sort the list of points according to that distance and move an optional number of the list of scaled points down to create the dome shape. (Because we calculated the distance from the center it creates this circular shape).

I then order those points into lists of points to form polylines. I created these polylines add different heights so I could do a roughing in steps. So I used them with the postprocessor we've used before to do the roughing on the oak. But for the finishing path I wanted to use a spiral toolpath and had to do a workaround to achieve that:

So from the final polylines I create a 3D surface. Then I baked the 3D surface into Rhino and drew a 2d spiral above the surface. I then did an offset (with the radius of the ball nose bit) on the surface and projected the spiral onto that surface, to match the edge of the ballnose with the surface that I actually want to create. Then when setting the z-height on the machine, I move the zero point down with a distance that matches the radius of the bit. So the 0-point in z-direction is now in the center of the bit. I then use the postprocessor on that projected spiral curve and that's it!

Now a lot of this will be hard to follow by reading my text so I suggest having a look at my files to get a better understanding. You will need the python component which you can find on the food4rhino website: Here

(Edit: As of Rhino 6 GhPython is a standard grasshopper component so you don't need to install this)

And then it's up to you! I hope you learned something from this Instructable and in case you use it to make something I'd love to see the results!

CNC Contest 2016

Runner Up in the
CNC Contest 2016