G-code Tools
1 G-code Structures
g-code-sym?
code
command
program?
2 G-code Macros
cd
cmd
cmds
3 Reading and Writing
read-g-code
write-g-code
4 Code and Command Functions
g-code?
m-code?
f-code?
s-code?
r-code?
p-code?
x-code?
y-code?
z-code?
i-code?
j-code?
k-code?
g-command?
m-command?
f-command?
s-command?
r-command?
p-command?
x-command?
y-command?
z-command?
i-command?
j-command?
k-command?
named?
param-in-command?
param-by-sym
5 Coordinates
coord-code?
coord?
empty-coord?
x-coord?
y-coord?
z-coord?
xy-coord?
xz-coord?
xyz-coord?
i-coord?
j-coord?
k-coord?
ij-coord?
ik-coord?
ijk-coord?
get-coords
update-coords
6 Program Functions
update-commands
update-program-coords
7 Possible New Features
8 Changelog
7.7

G-code Tools

Gifan Thadathil

 (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 — not to mention there are multiple competing standards for G-code. Since many CNC machines make use of automatically generated G-code, it is likely the generated G-code will not work for your machine.

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:

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
Consumes anything and produces #t if val is any of 'G, 'M, 'F, 'S, 'P, 'R, 'X, 'Y, 'Z, 'I, 'J, or 'K. Produces #f otherwise.

struct

(struct code (sym num)
    #:extra-constructor-name make-code)
  sym : g-code-sym?
  num : number?
Represents a single G-code code.

; 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?)
Represents a single G-code command.

; 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)))

procedure

(program? val)  boolean?

  val : any/c
Consumes anything and produces #t if val is a list of commands.

2 G-code Macros

Since structures are annoying to write, we provide some convenient macros for writing G-code in Racket.

syntax

(cd sym+num)

Produces codes from a symbolic code.

; (code 'G 0)
(cd G0)
; (code 'X 120.45)
(cd X120.45)
; Error!
(cd X 120.45)

syntax

(cmd cd-list)

Produces a command from a list of symbolic codes.

; (command (code 'G 0) (list (code 'X 10) (code 'Y 10)))
(cmd G0 X10 Y10)

syntax

(cmds cmd-list)

Produces a program from a list of a list of symbolic codes.

; (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)
Reads in a G-code program from in. If in is not specified, then the current input port is used. Produces a list of commands where the ith line of the program corresponds to the ith command in the list.

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?)
Writes a list of commands as a G-code program to out. If out is not specified, then the current output port is used.

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

(g-code? cd)  boolean?

  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?
Consumes a code and produces #t if (code-sym cd) matches the expected symbol. Produces #f otherwise.

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?
Consumes a command and produces #t if (code-sym (command-name cmd)) matches the expected symbol. Produces #f otherwise.

procedure

(named? cd cmd)  (or/c code? #f)

  cd : code?
  cmd : command?
Consumes a code and a command. Produces #t if (command-name cmd) equals cd. Produces #f otherwise.

procedure

(param-in-command? cd cmd)  boolean?

  cd : code?
  cmd : command?
Consumes a code and a command, and produces #t if cd is a member of (command-params cmd). Produces #f otherwise.

procedure

(param-by-sym sym cmd)  (or/c code? #f)

  sym : g-code-sym?
  cmd : command?
Consumes a symbol and a command. If (command-params cmd) has a member cd such that (code-sym cd) matches sym, then cd is produced. Produces #f otherwise.

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?
Consumes a code and produces #t if the code is an X-code, Y-code, Z-code, I-code, J-code, or K-code.

procedure

(coord? val)  boolean?

  val : any/c
Consumes anything and produces #t if:
  1. val is a list.

  2. Every element of val is a coordinate code.

  3. val also satisfies one of x-code?, y-code?, etc.

> (coord? (list (code 'X 20)))

  #t

> (coord? (list (code 'Y 20)))

  #t

> (coord? (list (code 'X 20) (code 'Y 20)))

  #t

> (coord? 20)

  #f

> (coord? (code 'X 20))

  #f

> (coord? (list (code 'G 2)))

  #f

> (coord? (list (code 'Y 20) (code 'X 20)))

  #f

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?
Consumes a coordinate and produces #t if coord is in the correct form:
  1. The number of codes should match the expected number of dimensions.

  2. 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?
Consumes a command and returns two coordinates. The first coordinate contains any X, Y, and Z codes in (command-params cmd). The second coordinate contains any I, J, and K codes in (command-params cmd). If a command does not contain a code, the code will not be included in the resulting vector.

procedure

(update-coords cmd updater)  command?

  cmd : command?
  updater : (-> coord? coord?)
Consumes a command and an updater function. Produces the same command with updated coordinate codes. The coordinate codes are gathered with (get-coords cmd), and updater is applied to each coordinate. The codes in the resulting coordinates replace the old ones in cmd.

6 Program Functions

procedure

(update-commands cmds updater)  (listof command?)

  cmds : (listof command?)
  updater : (-> command? (or/c null command? (listof command?)))
Equivalent to (flatten (map updater cmds)). By using flatten, we easily add functionality over a typical map. If updater produces null, we do a remove command operation. If it produces a command, we do a replace command operation. If it produces a list of commands, we do a replace command with many commands operation.

procedure

(update-program-coords cmds updater)  (listof command?)

  cmds : (listof command?)
  updater : (-> coord? coord?)
Equivalent to

(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!

8 Changelog