G-code Tools
(require g-code-tools) | package: g-code-tools |
G-code is a low-level numerical control language. It interfaces between software and hardware in Computerized Numerical Control (CNC) machines. The g-code-tools module provides a structure for G-code as well as reading and writing functions. Furthermore, it provides a handful of functions for manipulating G-code.
The ad hoc nature of G-code motivates this library’s existence. G-code is often machine
specific. Not every machine will interpret commands in the same way, and not every
machine will mechanically support every defined command in G-code. One of the author’s machines
didn’t use the Cartesian coordinate system G-code assumes —
This package provides tools for programmatically modifying G-code. You can use it to create programs that convert generated G-code into machine-specific G-code.
Note:
g-code-tools is intended for use with G-code generated with another program. It provides only limited support for manual G-coders.
We try to be standard-agnostic with our assumptions, but loosely follow the LinuxCNC standard.
1 G-code Structures
A G-code program is very similar to assembly. A program is a list of commands organized into lines: one command on each line. A command is made up of codes, separated by spaces. It has two components, the name of the command and its parameters. Each of these are codes. A code is a letter and a number. The structures we provide reflect exactly this organization.
procedure
(g-code-sym? val) → boolean?
val : any/c
struct
(struct code (sym num) #:extra-constructor-name make-code) sym : g-code-sym? num : number?
; G0 (code 'G 0) ; X150.574 (code 'X 150.574) ; F500 (code 'F 500) ; Throws exn:fail (code 'Hello 16) ; Throws exn:fail (code 'g 16)
struct
(struct command (name params) #:extra-constructor-name make-command) name : code? params : (listof code?)
; G0 X100 Y100 (command (code 'G 0) (list (code 'X 100) (code 'Y 100))) ; G4 P1000 (command (code 'G 4) (list (code 'P 1000))) ; S255 (command (code 'S 255)) ; G0 X100 Y100 G1 X0 Y0 is okay, but it is invalid G-code since ; there are 2 actual commands. (command (code 'G 0) (list (code 'X 100) (code 'Y 100) (code 'G 0) (code 'X 0) (code 'Y 0)))
2 G-code Macros
Since structures are annoying to write, we provide some convenient macros for writing G-code in Racket.
; (code 'G 0) (cd G0) ; (code 'X 120.45) (cd X120.45) ; Error! (cd X 120.45)
; (command (code 'G 0) (list (code 'X 10) (code 'Y 10))) (cmd G0 X10 Y10)
; (list (command (code 'G 0) (list (code 'X 10) (code 'Y 10))) ; (command (code 'G 0) (list (code 'X 20) (code 'Y 20))) ; (command (code 'M 5) '())) (cmds (G0 X10 Y10) (G0 X20 Y20) (M5))
3 Reading and Writing
procedure
(read-g-code [in]) → (listof command?)
in : input-port? = (current-input-port)
Note that we do not yet provide useful error messages on syntactically malformed input! Furthermore, semantically invalid input will be successfully read in.
procedure
(write-g-code cmds [out] num-decs) → void?
cmds : (listof command?) out : output-port? = (current-output-port) num-decs : (nonnegative-integer?)
As for style, each command is written to a new line, and that is all. No comments or anything else is added to minimize file sizes. Before writing, every number is rounded to num-decs decimal places.
4 Code and Command Functions
procedures
cd : code? (m-code? cd) → boolean? cd : code? (f-code? cd) → boolean? cd : code? (s-code? cd) → boolean? cd : code? (r-code? cd) → boolean? cd : code? (p-code? cd) → boolean? cd : code? (x-code? cd) → boolean? cd : code? (y-code? cd) → boolean? cd : code? (z-code? cd) → boolean? cd : code? (i-code? cd) → boolean? cd : code? (j-code? cd) → boolean? cd : code? (k-code? cd) → boolean? cd : code?
procedures
(g-command? cmd) → boolean?
cmd : command? (m-command? cmd) → boolean? cmd : command? (f-command? cmd) → boolean? cmd : command? (s-command? cmd) → boolean? cmd : command? (r-command? cmd) → boolean? cmd : command? (p-command? cmd) → boolean? cmd : command? (x-command? cmd) → boolean? cmd : command? (y-command? cmd) → boolean? cmd : command? (z-command? cmd) → boolean? cmd : command? (i-command? cmd) → boolean? cmd : command? (j-command? cmd) → boolean? cmd : command? (k-command? cmd) → boolean? cmd : command?
procedure
(param-in-command? cd cmd) → boolean?
cd : code? cmd : command?
procedure
(param-by-sym sym cmd) → (or/c code? #f)
sym : g-code-sym? cmd : command?
5 Coordinates
Some commands operate on coordinates, which are specified with a certain group of codes. For example "G0 X20 Y20 Z20" tells the machine to move quickly to coordinate (20, 20, 20). The X, Y, and Z codes together specify the coordinate.
Within Racket, a coordinate is a list with one, two, or three elements depending on the number of dimensions. Each element should be a coordinate code.
procedure
(coord-code? cd) → boolean?
cd : code?
> (coord? 20)
procedures
(empty-coord? coord) → boolean?
coord : coord? (x-coord? coord) → boolean? coord : coord? (y-coord? coord) → boolean? coord : coord? (z-coord? coord) → boolean? coord : coord? (xy-coord? coord) → boolean? coord : coord? (xz-coord? coord) → boolean? coord : coord? (xyz-coord? coord) → boolean? coord : coord? (i-coord? coord) → boolean? coord : coord? (j-coord? coord) → boolean? coord : coord? (k-coord? coord) → boolean? coord : coord? (ij-coord? coord) → boolean? coord : coord? (ik-coord? coord) → boolean? coord : coord? (ijk-coord? coord) → boolean? coord : coord?
The number of codes should match the expected number of dimensions.
The order of codes should match the name of the function. For example a list of a X, Y, and Z code matches xyz-code?, but a list of a Y, X, and Z code would not.
procedure
(get-coords cmd) →
coord? coord? cmd : command?
6 Program Functions
procedure
(update-commands cmds updater) → (listof command?)
cmds : (listof command?) updater : (-> command? (or/c null command? (listof command?)))
procedure
(update-program-coords cmds updater) → (listof command?)
cmds : (listof command?) updater : (-> coord? coord?)
(map (lambda (a-cmd) (update-coords a-cmd updater)) cmds)
7 Possible New Features
The following lists (in no particular order) new functionality/changes that are planned. We make no guarantees, but we will try. Anyone is free to send a pull request!
Better support for more codes. For example, a function for changing all F codes, which represent feed rates.
Semantic validation of G-code. This means ensuring multiple commands aren’t on the same line, checking for proper parameters to commands, etc.
Tool-path simulations.
Sorting functions for minimizing non-work movement.
G-code to pict and pict to G-code conversion. Other converters?
Multi-threaded functions.
8 Changelog
- 0.1 —
2018-10-15 First release.