CNC router needs to be given instructions (G-Code) to move a tool over and around a work-piece. The first tasks I performed with the router used instructions generated by a small utility I wrote to cut out the outline of a polygon, but I wanted a more general solution.
I am writing a utility to create G-Code from a text script. The script takes commands like a turtle draw program would use: move forward and turn. This facilitates the specification of part outlines without needing to create formal part designs in software. I am able to sketch out what I want to cut then write a script that directs the turtle around the shape. The G-Code can then be uploaded to the CNC router, and the part can be cut from flat stock.
In its initial version script is organized into sections that cut geometry. There are two initial group types: "cut" and "drill". The cut sections are meant to cut outlines of shapes. The drill section is meant to provide locations where the tool plunges into the workpiece. Both group types are defined like functions with arguments for the group and statements enclosed in braces: "expressions" and "drills".
cut(args) { expressions }
drill(args) { drills }
When interpreted by the program each group will generate a separate G-Code output file. This enables tools to be switched and/or different depths to be specified. These values are set using arguments. Arguments are specified between the parenthesis and separated by commas. There are currently four different arguments that control the group.
(top = double, bottom = double, toolrad = double, step = double)
Doubles are text representation of real numbers, including a number and optional sign and/or decimal. "top", "bottom", "toolrad", and "step" are keywords.
"top" specifies the height from which to start cutting. The values are positive for positions above the work-piece origin, and more negative as the tool plunges into the work-piece. "bottom" specifies how deep to plunge in total. "step" indicates the vertical thickness to plunge per iteration of the tool-path. If this is a drill command this would be analogous to peck-drilling. For cutting shapes, the outline will be traced starting at top, plunging by the step value each time around, and finishing after tracing the shape at the depth corresponding with the bottom.
The groups contain commands to be repeated: drilling more than one location or tracing a shape. All the commands are terminated with a semi-colon.
"drill" is the simplest of the two.
drill(top = 0.0, bottom = -1.0, step = 0.25) {
at (x,y) ;
at (x,y) ;
at (x,y) ;
}
In this command the "x" and "y" values would be real numbers indicating where on the work-piece to drill holes. In this example each hole would be drilled starting on the top of the work-piece, peck 0.25 units deeper returning to the work surface each iteration, until the total depth is achieved. The machine will then position "at" the next location and drill another hole. The "toolrad" argument has no meaning for drilling.
"cut" groups are more complicated and are where the turtle draw logic is employed. Cuts are meant to trace a shape cutting geometry from a work-piece.
cut(top = 0.0, bottom = -1.0, step = 0.25, toolrad = 5.0) {
at (x,y) ;
direction (x,y) ;
move distance ;
turn degrees ;
fillet degrees radius ;
}
The "cut" group needs to know where to start. The initial "at" command specifies the start position. The "direction" command specifies which direction the turtle is headed. The direction is a vector and is normalized automatically. A turtle heading in the positive x direction and starting at a point (10,10) would be specified as:
at (10,10) ;
direction (1,0) ;
From this point, the following command would move the tool forward 5 units.
move 5.0;
If we want to make a right turn, we need to specify how far to turn. Positive values turn left and negative values turn right. Turning right by 90 degrees can be accomplished with the following command.
turn -90.0;
Putting this together, the following script would cut a square.
cut(top = 0.0, bottom = -1.0, step = 0.25, toolrad = 5.0) {
at (0,0) ;
direction (1,0) ;
move 1;
turn -90.0 ;
move 1;
turn -90.0 ;
move 1;
turn -90.0 ;
move 1;
}
The tool starts at x=0 and y=0 and is pointing in the +Y direction. It traces a unit square clockwise on the outside of the shape. "toolrad" has meaning to the "cut" group. This is the radius of the tool in the spindle. The shape drawn is the final dimensions of the square, a unit square in this case. The tool-path followed is larger than the shape to account for the size of the router bit. You specify the tool radius and draw the shape using the finished dimensions and the required tool-paths are determined by this utility.
One additional command, "fillet", is used to turn around an arc. The following command will arc tangent to the starting direction and be tangent to a vector equivelant to the current direction turned a number of degrees.
fillet -90.0 5.0;
The following fillet example would create a circle using four arcs, with a radius of 1.0 centered around (0,0). Since the tool radius is 1.0, the tool-path would be a circle of radius 2.0. This tool-path would be traced four times, each going 0.25 units deeper into the material.
cut(top = 0.0, bottom = -1.0, step = 0.25, toolrad = 1.0) {
at (-1,0) ;
direction (1,0) ;
fillet -90.0 1.0 ;
fillet -90.0 1.0 ;
fillet -90.0 1.0 ;
fillet -90.0 1.0 ;
}
This utility is still very basic and limited. Most notably, the software does not check if the tool will intersect existing geometry. For example, the software does not check if a tool radius is too large and will intersect another feature or produce bad tool-paths. Currently the generated G-Code needs to be double checked in a G-Code viewer to see if the paths are reasonable.