G-Code Interpreter


I wanted to chime in here and point people to the arm-netbook mailing list, specifically this post which is pretty recent about designing a new 3D printer that’s cheap and well-designed. There’s talk of the physical device as well as the control firmware on the board. Luke, the poster, has also complained about the state of software for desktop control of printers as well. Maybe there’s some interest in a collaboration between both parties?


I’m working on a board support crate for stm32f103’s now (using cortex-m-rtfm). My first project was going to be a zen garden, so being able to use gcode for the drawing would be nice. I’d be interested in helping out some with this.


Would you be happy with being my guinea pig? I’ve got a pretty decent initial implementation but it needs testing in real-life situations.

Here’s the first couple lines from the example:

G0      (line: 1, column: 1)
G21     (line: 1, column: 4)
G17     (line: 1, column: 7)
G90     (line: 1, column: 10)
G40     (line: 1, column: 13)
G49     (line: 1, column: 16)
G80     (line: 1, column: 19)
G71     (line: 2, column: 1)
G91     (line: 2, column: 4)
T1 M6 S12000 M3 (line: 3, column: 1)
G94 M63 P1 F1016 X0 Y0  (line: 5, column: 1)
G0 X0.033 Y15.914 M63 P1        (line: 7, column: 1)
G1 X0.033 Y15.914 M62 P1        (line: 8, column: 1)
G1 X13.855 Y13.14 M62 P1        (line: 9, column: 1)
G1 X8.012 Y1.013        (line: 10, column: 1)

That just reads in tests/data/program_3.gcode, parses it, then prints it back to the screen.


I’ll give it a shot when I get home. For my purposes I’ll only be using G0, G1, and G28 in just the X and Y axis, but I can test other stuff.


just gave it a try, but I think arrayvec isn’t importing odds as nostd:

Updating git repository `https://github.com/Michael-F-Bryan/gcode-rs`
Updating registry `https://github.com/rust-lang/crates.io-index`
Compiling log v0.3.8
Compiling odds v0.2.25
error[E0463]: can't find crate for `std`


Finally got a little work on on this. motion-rs

Also a simple math library that will be optimized for non-fpu Arm based platforms. math-rs

Not really loving the names…open to suggestions and help.


I’ve been thinking about this as well. Found a GCODE overview/design doc from the NIST.

As for Non-FPU math, since printers have fixed resolution anyways due to steppers, we could with a integer math library. for a 32 bit processor, we’d be able to represent scales from tens of meters to microns. More than enough range for a 3d printer.


I just had a great idea for a robust space efficient gcode tokenizer, so I am working on that right now.

Ideally, I think we need some kind of overarching project to refer to existing crates and help drive new ones. cortex-*-rtfm is critical of course. Just an incredibly awesome project.

I also wrote a serial port json server in rust as well.


You raise a good point. In my gcode parser I was using f32s for everything purely because it’s convenient. It should be fairly easy enough to swap this out with an integer representation later on if we feel it’s worth it.

That said, the platforms I’d be using this on (Pi, my laptop, and an STM32) all have floating point support, which is why I was okay with using floats. Would switching to a pure integer representation be beneficial?


This should be fixed now. I updated arrayvec's no_std feature in my Cargo.toml and also made sure to check that it cross-compiles correctly.

$ cargo clean
$ xargo build --target thumbv7m-none-eabi
   Compiling odds v0.2.25
   Compiling nodrop v0.1.9
   Compiling arrayvec v0.3.23
   Compiling gcode v0.1.0 (file:///home/michael/Documents/gcode)
    Finished dev [unoptimized + debuginfo] target(s) in 1.31 secs

Testing for ARM micros doesn’t work, but that’s because it isn’t yet supported by xargo.


Well it would support even cheaper ARM boards.


Should we start a github group to organize this stuff? Even if it just links to pertinent repos?

We do need a cute acronym…


I looked for ARM based 3d printer motherboards this weekend and I they are really hard to come by. Pretty much everything runs on Atmel mega 2560 which is a 8bit AVR.


The SmoothieBoard board uses an LPC1769, which is a 120 MHz Cortex-M3.

The Arduino Due has an Arduino Mega form factor, so you can use a GRBL Shield or RAMPS-FD shield

There are other 32-bit ARM boards with Arduino shield capabilities (suitable for GRBL, but not RAMPS-FD):
Netduino Plus 2, the Olimex H407 or E407

The Duet is a 3D printer board using
The gShield only has 3-axis, so it’s more suitable to a CNC mill. The RAMPS board was designed to run 3D-printers.

The Azteeg X5 mini is another board which uses the NXP1769

Many of the stepper boards designed for CNC use a parallel port style interface. These are relatively straight forward to connect to any of the 32-bit ARM development boards, perhaps needing some voltage translation.


There’s Rust-Embedded, would it be worth joining them, or should we start our own?


Well I think we are a super-package over rust-embedded. So not just embedded dev support, but firmware, control software, etc.

Also, the Due is a common board for arduino, and stepper shields are available for it.


We could call it Rust in Additive Manufacturing, RAM, with a pic of a ram in profile in the gear


builds fine here now. Once G0 codes are able to be parsed to points I can test out converting that to movement. I already have the steppers hooked up and working. Here’s what I have so far: https://github.com/etrombly/bluepill/blob/master/examples/stepper_tasks.rs

I’ll clean it up some more once I have gcode and serial working.


I’ve started adding a high level enum which will eventually allow you to access each G code and the arguments valid for it. It’ll take a while before it’s done because I’m manually adding each variant and double checking its error conditions against the spec I’m designing against.

Eventually I’ll find a nice method to abstract away defining a new variant, but until I notice a pattern which works I’ll be doing the first dozen or so manually.

Using the existing low_level representation for gcodes, here’s roughly how I imagine the firmware for a 3D printer would look.

extern crate gcode;
use gcode::{Tokenizer, BasicParser};
use gcode::low_level::{Line, Command};

// Hardcode the program for now, ideally it'd be read from an SD card
const PROGRAM: &'static str = include_str!("/path/to/program.gcode");

fn main() {

  let lexer  = Tokenizer::new(PROGRAM.chars());
  let tokens = lexer.filter_map(|t| t.ok());
  let parser = BasicParser::new(tokens);
  let lines = parser.filter_map(|l| l.ok());

  let printer = Printer::new(); 

  for line in lines {
    match line {
      Line::Cmd(cmd) => printer.execute(cmd),
      Line::ProgramNumber(_) => {}

struct Printer {
  // Internal stuff for controlling servos

impl Printer {
  fn execute(&mut self, cmd: Command) {
    // Inspect the command and its arguments, then do something


Great stuff! Was thinking about doing this myself, hopefully I can pitch in some! I agree with @DanielJoyce, though since this would be useful for milling machines too, perhaps Rust Automated Manufacturing would be a better acronym?