Not Grbl

Well the Grbl Firmware for the Arduino is great. It's so good that why bother writing your own? Other than for the hell of it!

Similar projects worth following
A G-Code interpreter for the Arduino series, uses only vanilla C Code (no hardware specific timers) so it will run on almost anything. The goal was to build a gCode interpreter for the Arduino ESP12E so I could use a webpage to control my CNC machine.

A simple 3 axis XY plane gCode interpreter

If you have one of these then you will need Grbl to run it.

The above image came from Protoneer so can I suggest having a look at their site.

Not Grbl

This project "Not Grbl" replaces the great Grbl firmware with an inferior partially compatible version.


  • G0 Rapid movement
  • G1 Cut movement
  • G92 Set position
  • M0 Stop (pause)
  • M3 Spindle/laser on
  • M5 Spindle/laser off
  • M17 Enable motors
  • M18 Disable motors
  • M30 End program (reset)
  • T0 Laser (if tool==1 then use special laser code)
  • T1 Engraver (default)
  • T? Tools (1-255)
  • S? Spindle (?) - Interpreted but does not actually do anything


  • G17 XY plane only
  • G21 Metric
  • G90 Absolute coordinates
  • G94 mm/min

Immediate codes:

  • ! Pause
  • ~ Resume
  • % Reset
  • ? Status

Works with the Arduino serial window (for testing only).

Works well with gcode sender by Otto Hermansson.

Also works okay with Grbl Controller by "Zapmaker".

The Arduino code has the follow defaults

Hardware mapping :

  • #define MXstep 2
  • #define MYstep 3
  • #define MZstep 4
  • #define MXDir 5
  • #define MYDir 6
  • #define MZDir 7
  • #define Enable 8
  • #define Spindle 12

Baud rate:

  • #define BAUD 9600

Stepper/controller settings:

  • #define StepsPerMM 100 // All axes

Axis directions:

  • bool xReverse=false;
  • bool yReverse=true;
  • bool zReverse=false;

General Approach

This project uses the "Blink without delay" approach to control the stepper motors.

This avoids the use of hardware specific timer (for interrupts).

In exchange the code is awkward as it has to "pass through" as fast as possible.

Basically code processes each character as it is received.

Code Overview


loop () {

// Some LED flasshing code to show it is busy

tokeniseGCode(); // Tokenise a character at a time from the serial stream

parseGCode(); // Parse the code on end of line received

advanceSteppers(); // Advance the stepper motors one step


More about the code later.

Serial Control

Uses XON/XOFF to control the serial flow.

But G Code Sender and Grbl Controller wait for an "ok" from "Not Grbl" before sending the next command.

Actually Grbl Controller sends 10 commands before waiting for an "ok" which is no problem.

So "Not Grbl" will reply with an "ok" after every command is sent and interpreted (but usually before the command is executed".

Motion Control

Steppers have a maximum under load (pulse per second (pps) or speed that they can start and stop from without losing steps. For most steppers this is in the order of 500 pps. Not Grbl at the beginning of a movement will ramp up from 500 pps to the specified speed and ramp down to 500 pps before the end of the movement.

The ramps will slow the average speed of short segments so filtering out of these short segments from the gCode will help a lot (particularly with laser over burning).

Maximum Stepper Speed

On my Arduino UNO the "pass through" frequency varied from 12kHz (idle) down to about 8kHz (working). This implies a maximum pulse rate of 8kHz (or 4800mm/min on my 100 steps per MM machine). In reality 2400 mm/min would be a practical maximum.

I don't think many steppers will work to 8kHz anyway.

Immediate Codes

  • ! Pause
  • ~ Resume
  • % Reset
  • ? Status

Basically immediate codes (providing they are not in-bedded in comment fields) will executed after the Enter key.

Laser Control

if Tool 0 (i.e. "T0") is added to the top of your G Code then:

  • G0 codes will turn the laser off and G1 Codes will turn the laser on.
  • All Z movements will be updated immediately but with no actual motion.
  • These code will override the M3/M5 commands.

Nothing stopping you from using the default tool (i.e. "T1") and using the M3/M5 codes to turn on/off the laser.

The spindle control command (S) is recognised but not implemented.

Hardware Mapping

The current hardware mapping models D2-D8 and D12 at present (see below):

The above image came from Protoneer so can I suggest having a look at their site.


The code has been tested with a Chinese Laser Engrave and works within expectations.

It is about 500 lines long:

// Simple 3 axis XY plane gCode interpreter
// Implemented:
// G0 Rapid movement...
Read more »


The graphic library used in ArcDouble.

a - 47.48 kB - 08/18/2016 at 08:15



The graphic library header used in ArcDouble.

h - 10.11 kB - 08/18/2016 at 08:15



A 3d integer line routine.

C Source File - 1.41 kB - 08/18/2016 at 08:15



Draws two arcs.

cbp - 1.01 kB - 08/18/2016 at 08:15



Draws two arcs.

C Source File - 1.37 kB - 08/18/2016 at 08:15


View all 6 files

  • My CNC Machine

    agp.cooper06/30/2017 at 03:22 0 comments

    Just a picture of my CNC machine

  • ESP8266 Timer0 and ISR

    agp.cooper10/12/2016 at 13:26 2 comments

    A timer and interrupt system for the ESP8266

    The current method of managing timing signals for Not-GRBL is by a "blink without delay" style of programming.

    It is somewhat restrictive but it works.

    This style of programming is also called "polling" and is basically the same a the "Ticker" library.

    What is really needed is access to a hardware timer and an Interrupt Service Vector.

    The ESP8266 provided a simple non-resetable up counter (the so called software timer) called timer0.

    Basically this timer counts clock cycles (i.e. at 80 MHz).

    Here is a bit of code the write my own "servo sweep":

    #define servoPin D4
    volatile int servoPulse=0;
    volatile int servoAngle=90;
    volatile unsigned long next;
    void inline servoISR(void){
      if (servoPulse==0) {
      } else {
    void setup()
      // Servo initialisation (uses D4)
      // Serial.begin(9600);
      // Serial.println();
    void loop()
      const int minAngle=16;
      const int maxAngle=176;
      const int midAngle=96;
      static int servoDir=1;
      // Next position
      if (servoAngle>maxAngle) servoAngle=maxAngle;
      if (servoAngle<minAngle) servoAngle=minAngle;
      if (servoAngle==maxAngle) servoDir=-servoDir;
      if (servoAngle==minAngle) servoDir=-servoDir;
      // Serial.println(servoAngle);

    Here is the critical bit of code:


    What does it do?

    • Initialises the timer
    • Attach the interrupt service routine (ISR)
    • Gets the current clock count and add 1000 clock cycle to it
    • Tell the timer to call the ISR after 1000 clock cycles

    It takes about 180 clock cycles to call the ISR.


    Other processes use the same timer and it has been reported that a 2 ms tick will crash the ESP6288 if you are using WiFi.

    Other timers

    There is also a timer1 (that needs investigation).


  • The Ticker Library

    agp.cooper09/02/2016 at 09:00 0 comments

    The Ticker Library

    The code in "Not Grbl" does not use any hardware timers because I want to eventually migrate to the EPS2688 and the hardware on this CPU is not well documented (unlike the AVRs). The code use "Blink without delay()" type code. On an Nano the code loops through at a rate of about 8 kHz. Plenty fast for a gCode interpreter/stepper controller.

    As the Ticker Library works on the EPS2688 series of boards (I have a WeMos D1R1 and an EPS-12E), I thought I would have a look.

    I tested the code on my Dalek motor/sensor board. It worked but not as expected. Basically the Library uses the millis() routine to manage/schedule the attach class. It is not interrupt based. So it basically it is "Blink without delay()" type code. So don't add a long delay() in anywhere if you use it. It is very tidy and nice to use but as I use micros() rather than millis() in "Not Grbl". It is therefore not a suitable library for use at present.


  • Project Complete?

    agp.cooper08/18/2016 at 07:50 0 comments

    Project Complete

    I have not looked at this project for a while and it works fine anytime I use it (mainly for my laser engraver).

    There may be some future upgrades but that can be done when required.

    The only thing I have noticed is that with the laser there is a distinct spot with fast movements that is very likely associated with the speed ramp down and ramp up between each movement command.

    This ramp down and ramp up limits movement changes to an acceleration of less than 1 g and gives the steppers a distinctive low pitch grumble.

    There are other ways of dealing with this but it is a simple system, works well and not worth upgrading.

    I added a couple of useful files if your looking for motion control code:

    • ArcDouble (not used for Not Grbl) but draws two arcs .
    • 3DStepper does the 3d stepper motion magic.


View all 4 project logs

Enjoy this project?



agp.cooper wrote 09/18/2017 at 06:00 point

You may also want to have a look at my GCode Cleaner. It strips out as many short segments as you find tolerable. I use it for may laser to speed things up and to stop burning.

  Are you sure? yes | no

agp.cooper wrote 09/18/2017 at 05:49 point

HEy, Thats great. I am rather surprised that someone actually looked at the code!

  Are you sure? yes | no

Obadiah Grotts wrote 09/18/2017 at 05:30 point

I modified your code to allow for a servo instead of a spindle. Works great on my CopperScribe!

  Are you sure? yes | no

ryannining wrote 03/30/2017 at 06:47 point

Very nice, easy to understand code.

I will try use it for esp8266 ESP01 with a expansion IO 8 bit.

  Are you sure? yes | no

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates