# G-Code Interpreter

**URL:** <https://users.rust-lang.org/t/g-code-interpreter/10930>\
**Category:** uncategorized\
**Created:** [May 21, 2017, 11:41pm UTC](https://users.rust-lang.org/t/g-code-interpreter/10930 "2017-05-21T23:41:49Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![iAlwaysLoseThis](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/ialwayslosethis/32/2843_2.png) [@iAlwaysLoseThis](https://users.rust-lang.org/u/iAlwaysLoseThis)\
**Post date:** [May 21, 2017, 11:41pm UTC](https://users.rust-lang.org/t/g-code-interpreter/10930/1 "2017-05-21T23:41:49Z")

</div>

I'm becoming quite unimpressed with the quality of the software available for the hardware part of 3D printers. A quick look at [SkyNet3D v1.1](https://github.com/pedromreis/Skynet3d) makes me feel like it's been hacked together. I am wondering if anyone has started working on a Rust based version of a G-code interpreter. I've seen several posts that Rust can run quite well on Arm processors and I'm looking for a project to possibly start on.

I don't have a ton of Rust experience or 3D printing experience, but I have a solid knowledge of what it would take to put something like this together. I really need to focus my skill on something specific that doesn't exist yet.

---

<div class="post-metadata">

**Author:** ![Michael-F-Bryan](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/michael-f-bryan/32/28749_2.png) [@Michael-F-Bryan](https://users.rust-lang.org/u/Michael-F-Bryan)\
**Post date:** [May 22, 2017, 1:41pm UTC](https://users.rust-lang.org/t/g-code-interpreter/10930/2 "2017-05-22T13:41:31Z")

</div>

I don't believe anyone has published anything for working with gcode, searching "gcode" and "cnc" on [crates.io](http://crates.io) and google don't show any useful results.

I've considered doing something like this a couple times now. Having a `#[no_std]` library for parsing and interpreting a stream of gcode would be really useful for people wanting to do embedded systems and cnc-like applications.

What kind of stuff would you expect from a hypothetical library for interpreting gcode?

---

<div class="post-metadata">

**Author:** ![iAlwaysLoseThis](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/ialwayslosethis/32/2843_2.png) [@iAlwaysLoseThis](https://users.rust-lang.org/u/iAlwaysLoseThis)\
**Post date:** [May 22, 2017, 2:39pm UTC](https://users.rust-lang.org/t/g-code-interpreter/10930/3 "2017-05-22T14:39:34Z")

</div>

I also did a quick search and everything I find is C/C++ code written in a very non modular method. It seems like each variation of printer (Cartesian, polar, Delta) have just been #ifdef'd in where necessary. The code does work, but it's spaghetti.

My idea is simple, design a library that is well structured and performance oriented. I'd love to support

- Raspberry Pi / Compute module
- ARM Cortex series

as targets with hardware simple at first with lots of testing to ensure accuracy.

Stuff I think would do well in a library like this is

- Legible / fail-safe G-Code parsing
- Open/Closed loop motion control via traits (possibly) so different types of devices can be well supported/maintainable
- Configurable acceleration/deceleration curves
- Auto-leveling bed as default
- Well defined modules i.e.- MotionControl, LCD, GCode etc. other projects code is mostly everywhere as far as I can tell.

Anyway I'm sure a #[no\_std] library is necessary here to support as many platforms as possible.

---

<div class="post-metadata">

**Author:** ![Michael-F-Bryan](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/michael-f-bryan/32/28749_2.png) [@Michael-F-Bryan](https://users.rust-lang.org/u/Michael-F-Bryan)\
**Post date:** [May 22, 2017, 5:03pm UTC](https://users.rust-lang.org/t/g-code-interpreter/10930/4 "2017-05-22T17:03:54Z")

</div>

It sounds like what you're asking for goes much further than a simple gcode interpreter. It's fairly easy to create a "parser" which effectively takes in an iterator of characters and then transforms that into an iterator who's item is `Result<GCode, Error>`. Gcode itself is a very easy language to parse and I could probably knock up something like that in 100-200 lines of code.

What you are asking for extends much further though, and would probably end up being a fairly in-depth project.

The top-level design is fairly straightforward though. You'd set up the 3D printer library to have some sort of `Controller` struct which takes in a stream of characters (the gcode instructions), and your printer's implementation of some `Printer` trait. The controller then reads the instructions and uses your `Printer` implementation as a driver to execute the instructions.

I imagine the `Printer` trait would look something like this:

```rust
trait Printer {
  fn set_bed_height(&mut self, height: f64) -> Result<(), Error>;
  fn move_extruder(&mut self, x: f64, y: f64) -> Result<(), Error>;
  fn set_extrusion_rate(&mut self, rate: f64) -> Result<(), Error>;
}

```

Overall what you are talking about is definitely doable. With Rust it's easy to design things in a way that is modular and extensible, and which use proper dependency injection so you don't need to resort to a bunch of `#ifdef` statements to swap between printer implementations.

I'd be really keen to work on something like this if you want to take it further. Overall it would benefit the Rust embedded community massively, plus it sounds like a genuinely interesting project 🙂

---

<div class="post-metadata">

**Author:** ![iAlwaysLoseThis](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/ialwayslosethis/32/2843_2.png) [@iAlwaysLoseThis](https://users.rust-lang.org/u/iAlwaysLoseThis)\
**Post date:** [May 22, 2017, 5:37pm UTC](https://users.rust-lang.org/t/g-code-interpreter/10930/5 "2017-05-22T17:37:00Z")

</div>

Sounds great!

Any ideas for what we could name this project?

Should we keep the main modules in separate repositories with a main one using the others (Cargo is great for this!)

I'll start coming up with a outline of what's needed and where to divide it up.

Feel free to PM me.

---

<div class="post-metadata">

**Author:** ![Eh2406](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/eh2406/32/9056_2.png) [@Eh2406](https://users.rust-lang.org/u/Eh2406)\
**Post date:** [May 22, 2017, 8:05pm UTC](https://users.rust-lang.org/t/g-code-interpreter/10930/6 "2017-05-22T20:05:58Z")

</div>

+1 for separate crates where doable. A crate for parsing g-code would be useful for a desktop qaqc tool. Also, If the cnc control code only used a type that deserialized into a g-code enum, then users could swap out for one of the binary formats that never got much traction.

---

<div class="post-metadata">

**Author:** ![Michael-F-Bryan](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/michael-f-bryan/32/28749_2.png) [@Michael-F-Bryan](https://users.rust-lang.org/u/Michael-F-Bryan)\
**Post date:** [May 23, 2017, 3:02pm UTC](https://users.rust-lang.org/t/g-code-interpreter/10930/7 "2017-05-23T15:02:19Z")

</div>

As I see it, we've got a couple fairly distinct modules/crates here.

- A streaming gcode parser which can would be work regardless of if the gcodes are read from some file on a SD card, or if it were receiving via a serial line (maybe it reads from a buffered reader or whatever?)
- A platform-agnostic "controller" which can take in a stream of instructions and execute them using some platform-specific `Driver` trait
- At least one `Driver` implementation so we can test this out on actual hardware

Rust looks to be a really nice language for this! Having some generic `Driver` trait means you'd easily be able to test out and simulate a gcode program without needing to do any difficult hacking or code copying. You just write a `Driver` implementation which records what it does for playback later. Plus you get modularity and [crates.io](http://crates.io) out of the box.

@japaric may have some interesting ideas for this. He's currently doing a lot to help further the Rust embedded ecosystem and has a heap of experience with microcontrollers.

---

<div class="post-metadata">

**Author:** ![Michael-F-Bryan](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/michael-f-bryan/32/28749_2.png) [@Michael-F-Bryan](https://users.rust-lang.org/u/Michael-F-Bryan)\
**Post date:** [May 23, 2017, 4:12pm UTC](https://users.rust-lang.org/t/g-code-interpreter/10930/8 "2017-05-23T16:12:04Z")

</div>

I thought I'd get the ball rolling on the gcode parsing. I've started up a [repo](https://github.com/Michael-F-Bryan/gcode-rs) and hooked in CI.

---

<div class="post-metadata">

**Author:** ![iAlwaysLoseThis](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/ialwayslosethis/32/2843_2.png) [@iAlwaysLoseThis](https://users.rust-lang.org/u/iAlwaysLoseThis)\
**Post date:** [May 23, 2017, 4:52pm UTC](https://users.rust-lang.org/t/g-code-interpreter/10930/9 "2017-05-23T16:52:50Z")

</div>

Very nice. I will start on a simply math crate for doing the motion  
control. And try to come up with some simple test files and a list of  
G-Codes we should support. I think the Controller should perform the  
interpolation and create a buffer of positions and then the Driver can  
perform any coordinate translations for the different types of machines.

---

<div class="post-metadata">

**Author:** ![iAlwaysLoseThis](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/ialwayslosethis/32/2843_2.png) [@iAlwaysLoseThis](https://users.rust-lang.org/u/iAlwaysLoseThis)\
**Post date:** [May 23, 2017, 9:47pm UTC](https://users.rust-lang.org/t/g-code-interpreter/10930/10 "2017-05-23T21:47:22Z")

</div>

Man I am not used to writing Rust with no\_std! I wrote an entire vector math file and then remembered to add #![no\_std] and realized there is no operator overloading! I guess my hint should have been 'use std::...'

What is the suggested method of overcoming this limitation? Just write all the code with no operator overloading?

---

<div class="post-metadata">

**Author:** ![Eh2406](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/eh2406/32/9056_2.png) [@Eh2406](https://users.rust-lang.org/u/Eh2406)\
**Post date:** [May 23, 2017, 9:49pm UTC](https://users.rust-lang.org/t/g-code-interpreter/10930/11 "2017-05-23T21:49:48Z")

</div>

This looks really cool. thanks for doing this!  
Have you considered using one of the parser libraries instead of rolling your own? If they don't suit the purpose, what are they missing?

---

<div class="post-metadata">

**Author:** ![iAlwaysLoseThis](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/ialwayslosethis/32/2843_2.png) [@iAlwaysLoseThis](https://users.rust-lang.org/u/iAlwaysLoseThis)\
**Post date:** [May 23, 2017, 9:51pm UTC](https://users.rust-lang.org/t/g-code-interpreter/10930/12 "2017-05-23T21:51:01Z")

</div>

I think the #![no\_std] is the limitation.

---

<div class="post-metadata">

**Author:** ![iAlwaysLoseThis](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/ialwayslosethis/32/2843_2.png) [@iAlwaysLoseThis](https://users.rust-lang.org/u/iAlwaysLoseThis)\
**Post date:** [May 23, 2017, 10:12pm UTC](https://users.rust-lang.org/t/g-code-interpreter/10930/13 "2017-05-23T22:12:57Z")

</div>

Never mind. Core is what I want.

---

<div class="post-metadata">

**Author:** ![Michael-F-Bryan](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/michael-f-bryan/32/28749_2.png) [@Michael-F-Bryan](https://users.rust-lang.org/u/Michael-F-Bryan)\
**Post date:** [May 23, 2017, 11:08pm UTC](https://users.rust-lang.org/t/g-code-interpreter/10930/14 "2017-05-23T23:08:27Z")

</div>

Yeah, I considered it. But the problem with a lot of the libraries out there is it takes longer to learn how to use them than to write a simple recursive descent parser. Plus they often give really cryptic error messages during development due to the use of generics or unreadable macros (I'm looking at you `nom`).

So yeah, for a super simple line-base language like gcode I thought I'd roll my own recursive descent parser. I've written my fair share of interpreters and compilers in the past, so I'm hoping it shouldn't be overly difficult.

---

<div class="post-metadata">

**Author:** ![iAlwaysLoseThis](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/ialwayslosethis/32/2843_2.png) [@iAlwaysLoseThis](https://users.rust-lang.org/u/iAlwaysLoseThis)\
**Post date:** [May 24, 2017, 12:51am UTC](https://users.rust-lang.org/t/g-code-interpreter/10930/15 "2017-05-24T00:51:43Z")

</div>

I agreed that G-code is quite easy to parse. I had hoped to include almost no external libraries just to decrease any external dependencies. Not using the standard library should enable a fairly easy transition to running on embedded platforms. [Smoothieboard](http://smoothieware.org/smoothieboard) is around the level of minimum hardware I'd like to support. 8 bit AVRs running at 16 MHz isn't enough, although it may be possible once these are supported by Rust. I'd like to think an STM32F0 running at 48 MHz should be enough to run just g-code parsing and motion control of a 4 axis machine. I do want to design my own board simply because I want to include an option for closed loop motion control. Of course first step is to get g-code parsing and a stepper moving 🙂

I have 2 cnc driver boards with these chips on them -

- [Allegro 3977SEDT Driver](http://pdf1.alldatasheet.com/datasheet-pdf/view/91536/ALLEGRO/A3977SED-T.html)
- [TB6560AHQ Driver](http://www.kosmodrom.com.ua/data/cncstepdriver/TB6560AHQ.pdf)

It's important to note that these are just the driver boards, I will use a -

- [Teensy 3.2 w/ 72 MHz Cortex-M4](https://www.pjrc.com/store/teensy32.html)
- [Ardunino Due w/ 84 MHz Atmel SAM3X8E ARM Cortex-M3](https://www.arduino.cc/en/Main/arduinoBoardDue)
- [RaspberryPi](https://www.raspberrypi.org/products/)

to run tests with initially. These are low cost, Arm based systems, with at least 2 having Rust support already. I'll also have an ANET A8 3D printer soon and it has an Atmega1284 processor, far to slow in my opinion.

Interesting to note that the only the RaspberryPi has floating point hardware support. I will have to get a Teensy 3.5 & 3.6 to try as well and note the difference.

---

<div class="post-metadata">

**Author:** ![dhylands](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/dhylands/32/1684_2.png) [@dhylands](https://users.rust-lang.org/u/dhylands)\
**Post date:** [May 24, 2017, 3:01am UTC](https://users.rust-lang.org/t/g-code-interpreter/10930/16 "2017-05-24T03:01:40Z")

</div>

The [G30TH](https://www.ghielectronics.com/catalog/product/551) has an STM32F401 processor which includes 32-bit FPU.

The [NUCLEO-L432KC](https://www.digikey.com/product-detail/en/stmicroelectronics/NUCLEO-L432KC/497-16592-ND/6132763) is an 80 MHz Cortex-M4 with a 32-bit FPU as well.

Or, for a few more dollars, you can get the [NUCLEO-F446RE](https://www.digikey.com/product-detail/en/stmicroelectronics/NUCLEO-F446RE/497-15882-ND/5347712) which runs at 180 MHz (also includes a 32-bit FPU).

The 2 NUCLEO boards include debugging support. They each have a builtin stlink processor in addition to the featured processor.

---

<div class="post-metadata">

**Author:** ![Michael-F-Bryan](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/michael-f-bryan/32/28749_2.png) [@Michael-F-Bryan](https://users.rust-lang.org/u/Michael-F-Bryan)\
**Post date:** [May 25, 2017, 12:38am UTC](https://users.rust-lang.org/t/g-code-interpreter/10930/17 "2017-05-25T00:38:21Z")

</div>

@iAlwaysLoseThis, how strict do you think the gcode parser should be? I can make the parser quite strict so it'll only accept valid gcode commands. Or I could make it a bit more relaxed so if you were to pass in `R30.0` to a command which doesn't accept an `R` command, it'll just be ignored.

At the moment I'm thinking I'll ignore invalid stuff, but log it at the `info` level.

---

<div class="post-metadata">

**Author:** ![iAlwaysLoseThis](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/ialwayslosethis/32/2843_2.png) [@iAlwaysLoseThis](https://users.rust-lang.org/u/iAlwaysLoseThis)\
**Post date:** [May 25, 2017, 1:49am UTC](https://users.rust-lang.org/t/g-code-interpreter/10930/18 "2017-05-25T01:49:35Z")

</div>

I should hope that unless your writing g-code by hand there shouldn't be any syntax errors. Mostly just trying to move the tool pass the end stops. My opinion is relaxed and just log errors as we go. Don't forget to include E as an axis token (Extruder), I'm not sure how multi-head extrudors work yet. Also I love your power implementation.

Here is the first lines of a simple box generated with Simplfy3D

G90  
M82  
M106 S0  
M104 S190 T0  
M109 S190 T0  
G28 ; home all axes  
G92 E0  
G1 E-1.0000 F1800  
G1 Z0.180 F1000  
; layer 1, Z = 0.18  
T0  
; tool H0.200 W0.400  
; skirt  
G1 X52.003 Y64.991 F4800  
G1 E0.0000 F540  
G92 E0  
G1 X52.224 Y64.900 E0.0071 F1800  
G1 X147.776 Y64.900 E2.8674  
G1 X147.997 Y64.991 E2.8746  
...  
G92 E0  
G1 X52.303 Y65.300 E0.0024 F1800  
G1 X147.697 Y65.300 E2.8579  
...  
G92 E0  
G1 E-1.0000 F1800  
; layer 2, Z = 0.38  
M106 S255  
; inner perimeter  
G1 X145.400 Y70.100 F4800  
G1 Z0.380 F1000  
G1 E0.0000 F1800  
G92 E0

I'll send you the whole file when I get a chance. I haven't had much time to work on my part, but I should be able to make some progress this weekend.

---

<div class="post-metadata">

**Author:** ![iAlwaysLoseThis](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/ialwayslosethis/32/2843_2.png) [@iAlwaysLoseThis](https://users.rust-lang.org/u/iAlwaysLoseThis)\
**Post date:** [May 25, 2017, 1:52am UTC](https://users.rust-lang.org/t/g-code-interpreter/10930/19 "2017-05-25T01:52:30Z")

</div>

[http://reprap.org/wiki/G-code](http://reprap.org/wiki/G-code) is a really nice description of g-code in relation to 3d printers, but it seems to cover it all.

---

<div class="post-metadata">

**Author:** ![Michael-F-Bryan](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/michael-f-bryan/32/28749_2.png) [@Michael-F-Bryan](https://users.rust-lang.org/u/Michael-F-Bryan)\
**Post date:** [May 25, 2017, 2:19am UTC](https://users.rust-lang.org/t/g-code-interpreter/10930/20 "2017-05-25T02:19:58Z")

</div>

> [@iAlwaysLoseThis](#):
>
> Also I love your power implementation

Haha oh, you're talking about [this](https://github.com/Michael-F-Bryan/gcode-rs/blob/851b060dd27c54e840b7ac590a7e878ca7f841e2/src/helpers.rs#L32-L45)? Yeah I'm not proud of it, but it's about the only thing I could think of to get a floating point number from the fractional and integer parts and doesn't rely on `std` or nightly-only stuff. That naive implementation shouldn't be overly expensive though because most numbers used in CNC/3D printing would only go out to a couple decimal places.

I'm having a couple troubles representing a command without any dynamic memory allocation though. Turns out it's not really possible to have a list of arguments of unknown length with `no_std` (a la `Vec`), so I'm thinking I'll pull in [`arrayvec`](https://docs.rs/arrayvec) and settle for a reasonably sized buffer.

If you've got any decently sized gcode examples feel free to send them to me via pull request/issue. I've got a couple in the `tests/data/` directory which I'm using for integration tests to ensure the parser and lexer can handle non-trivial programs.

[Next page](https://users.rust-lang.org/t/g-code-interpreter/10930.md?page=2)
