Arduino CNC & GRBL

27th Jan 2022

Making Things Electronics Arduino CNC

In my most recent YouTube video I wired up my DIY CNC with it's driver board and managed to get it controlled by my computer via GRBL. The video is deliberately light on the specifics of how I set up GRBL because it doesn't make for very interesting watching. In lieu of details in the video, I am writing this article to dig into more of the details on the set up.


If you want to learn about CNC and build your own, look at GRBL, even if you don't end up using it, it's great software and easy to set up. Their project is very well documented on their Github wiki and is a great place to start.


Yes, GRBL. Not to be mistaken with Gerbil. However, maybe it is; I pronounce it "grr-bl", but maybe it is just gerbil 🤔. Anyway, GRBL is an amazing open source project started originally back in 2009. Since then, different developers have taken the lead but it continues to be a mature and actively developed open source project. The goal of GRBL is to create a simple, no fuss programmatic interface to control CNC machines (specifically 3-axis machines, more on that later) via G-Code.

Okay, next question, what is G-Code? Good question. G-Code is the most widely used industry standard language for controlling CNC machines. It looks like this:

G0 Y10
G0 Y25
G0 Y0

The above commands more of less boil down to, "move the machines y-axis from it's current location to position 10, then to 25, then to 0". The units are configured on the machine, so in my case these would be millimeters. What you will notice about the above commands is that I am just telling the machine where to go, I'm not telling it how exactly to go there. This is the magic of the GRBL firmware being installed on a microcontroller that is connected to motors etc. In my case, and the most common CNC case, GRBL is interpreting the command and figuring out what to do. It knows what signals to send to which pins on the microcontroller to drive the motors. The cool thing here is that G-Code is common to loads of different types of machines and it is the firmware of the machines that figures out exactly what it should do to create the motion described by the G-Code.

You might hear of specific "flavours" of G-Code, this is common among different firmware's that support different or more advanced features. For example, my 3d printer runs G-Code, but if I provide it with the following code M3 S100 (which sets the spindle on a CNC to run clockwise at 100RPM), it won't know what to do because funnily enough, my 3d printer doesn't have a spindle! It should be said that G-Code is huge and there are lots of different commands, GRBL only supports a subset of these. If you want more advanced features, you might want to use other firmware. I should also mention for completeness that the above is actually an "M-Code", technically these are different, but when people say "G-Code" they mean the global set of commands that control a CNC machine.


I was expecting to be bitten at some point by the setup process for GRBL but really it couldn't have been easier. Firstly you will need to install the Arduino IDE. If you are familiar with Arduino, you probably already have this, if not, give it a quick google, Arduino's getting started docs are easy to follow. After this you will need to clone the GRBL repo locally and follow some basic instructions you can find here.

Once you have followed the steps in the docs, you should have an Arduino running the GRBL firmware. At this point you can communicate with CNC controller board over serial using what ever application you like. The easy choice is using the Arduino Serial Monitor. However, if you want an interactive CNC focused UI to work with, you can install Focus by Source Rabbit. Previously this software was fully free and called G-Code Sender. Since 2021 it has become a commercial tool that you need to buy a license for. However, you can download a working version of it that you can use without a license for demo purposes.

In general, that is all it takes to get things up and running. I was amazed at how quick and easy this was. In the rest of this section I will talk in a little bit of detail about the specifics of my setup using the Arduino CNC Shield and my stepper drivers etc.

If you aren't familiar with Arduino, a "shield" is a breakout board with pins designed to slot directly onto a standard board providing it with extra hardware capabilities. If you have worked with the Raspberry Pi, the same concept exists but they call it a "hat". The Arduino CNC shield contains header pins labeled for limit switches, spindle speed control and of course stepper motor drivers among other things. As an Arduino board alone can't drive a stepper motor, the CNC shield also contains 4 ports where you can attach DRV8825 stepper motor drivers along with ports to connect the motors themselves. It might seem silly that you have to buy a bunch of driver ICs to go with the board but usually you can buy these all together as a kit. When you think about the driver ICs it also makes some sense. These ICs tend to get hot and require little heat sync to be added to them. They can be burned out fairly easily. With this in mind, it's a cheap and easy solution to add them as a replaceable component to the shield rather than to build it in.

I mentioned above that the CNC shield plugs straight into the Arduino and routes all of the pins to certain ports. It just so happens that all of these pins are the same pins the GRBL configures to support each of it's functions. This brings me to a small discovery I made which I didn't realise. The Arduino CNC shield has 4 stepper drivers labeled X, Y, Z and A. This is pretty common on CNC controllers to provide an A or "Additional" axis. On some bigger machines people sometimes use these to add a rotary axis for example. I spent some times in GRBL looking for how to drive the A-axis. Spoiler, you can't! GRBL is 3 axis only, so the A-axis on the CNC shield can't be directly controlled. I was worried when I found that out because my design requires 4 motors to be driven as the Y-axis needs 2 motors. I then discovered that the clever designers intended the A-axis on the shield to be used as a slave and provide jumpers on the board to map any axis onto the A-axis. In my case, I set up the jumper pins to map my Y-axis to the A-axis. One final note on this, in my design, my Y-axis steppers are facing in opposite directions. They need to move in sync, but they need to rotate in opposite directions. If you need to do this, all you have to do is flip the connections to the motor. Usually in a bi-polar stepper (4 wire stepper) you will have a pair of wires labeled A and a pair of wires labeled B (indicating the phases inside the motor). Simply flip these around and presto, for the same drive signal, the motors will spin in opposite directions.

The last piece I want to cover on the set up is setting the current limits on the DRV8825 driver boards. These boards come with a tiny potentiometer built into them, the purpose of which is to set the current for the motors. Stepper motors usually give a current rating per phase in their datasheet. In my case, my steppers are 1.7A per phase max. Ideally you want to run your motors at somewhere around 10-20% less than this for safety. The driver board has a simple way of setting it via the potentiometer. As you rotate the potentiometer, you can actually measure a voltage between the potentiometer head and ground. To do this I attach wire to a tiny screwdriver and my multimeter so I can get a read out as I turn the pot. The value of this voltage is half the value of the motor current. So ignoring the safety buffer, if my motor is rated for 1.7A, I should set the voltage across this pot to be 0.85V. In reality I actually set it to 0.75V for some safety and I also found this was a sweet spot for making my motors run well. Worth noting too, as I was also confused by this before, the current value you are setting on the DRV8825 is per phase. Meaning you are matching this value directly to the per phase current value in your stepper datasheet.


With all of the above done you are officially ready to start driving your motors! However, I would recommend a quick safety tip, don't just plug it all in with the motors connected to what they are driving and start issuing commands. There is calibration to be done and the last thing you want is to break something. My advice is to set it up so that your motors can spin freely first. If you issue a few G0 commands you will see that the motors will spin a certain amount in the direction you tell them to. Now, depending on your set up, gearing, belts and pulleys etc., this amount might in theory make your machine move a huge amount, or a very tiny amount. The point is, it's not calibrated because the machine at this point doesn't know how many steps of the motor corresponds to a millimeter of travel in a given axis. Conveniently, there is a setting for this called "steps per millimeter". Next question, how do we set it? GRBL gives a nice clean interface for configuring settings on the machine, as of writing this, the latest docs can be found here.

For setting up steps per millimeter, the following serial command will set the steps per millimeter for the Y-axis to 100, $101=100. In this case, we are saying that for half a rotation of a standard 200 step (1.8 degree) motor, the machines Y-axis will move by 1mm. Depending on your gearing, this might be correct... Or it might cause your Y-axis to hit hard against it's end stops and cause untold destruction! The way you get around this is by figuring out how many steps your motor needs to take to move your machine 1mm. In the GRBL docs you will find this handy formula for calculating your steps per mm: steps_per_mm = (steps_per_revolution*microsteps)/mm_per_rev. To calculate this you need a few values from your machine and motors; steps_per_revolution you can get from your datasheet, the typical value for common steppers is 200 (1.8 degrees per step). For this example ignore microsteps by setting it's values to 1, we will come back to this later. Finally, you need to set up your motors and your axis to work out mm_per_rev. You can either wire up your motors some how to move exactly 1 revolution, or you can manually spin your motor 1 revolution. By marking some points on the pulleys etc. you can note one full rotation. In my case, I connected up my gantry to the motors, marked it's position, then rotated the motor 1 revolution, marked the final position and measured the distance between the two marks.

With your steps per mm set, you can put your axis into it's middle position and start testing out some movement. I recommend middle position because unless you know which way you have wired your motors, it might think forwards is backwards and end up crashing if you are at an end stop and you drive it the wrong direction. In my case, I was easily able to get the motors running but I ran into some issues in the way of noise, vibration and speed of movement. By default, the speed and acceleration of the machine are pr econfigured on the controller. Movement is meant to start slow, ramp up to steady state and ramp down again. When I calculated my steps per mm, it was something like 5. So to make the machine move 1 millimeter I was forcing it to jerk sharply through 5 steps while still attempting to accelerate and decelerate. At this point I was seeing that running in "full step mode" wasn't really going to work here. Due to my setup, individual steps were causing the machine to move a proportionally large distance. This isn't an ideal way to run a stepper, considering that 1.8 degrees per step is not a very fine resolution, it's actually pretty jerky as the motor moves. If you have dealt with steppers before you will know that among other things, microstepping can help with vibration and noise reduction. Not all steppers are capable of microstepping and the degree to which you can microstep differs from motor to motor. In my case, my motors are capable of 1/32 microstepping which is also the finest amount supported by DRV8825's. Keep in mind, you might not need to go to 1/32 stepping. In my case, 1/32 gives me the nicest results but you also should consider torque and speed when deciding how fine you want to microstep. For reference, when using the Arduino CNC shield, under the stepper motor drivers on the board are a set of pins, jumping these pins with the supplied jumpers is how you set the degree of the microstepping. You can find the truth table for this in the DRV8825 datasheet. A final note on microstepping, remember back to our steps per mm formula earlier, the value of microsteps in the equation should be the number of division in your setup. So it's value is 32 if you are using 1/32 stepping.

With the above done, you should be in a decent position to tweak and learn more on your own. Now that you know the questions to ask, Google is your friend! The GRBL docs are also excellent and I can't recommend them enough.

What's Next?

Next on this project I need to design and build the x-axis on my machine. I may write future articles about some specific details of the project, but the best way to follow along yourself is to check out my YouTube channel.

Keep on making things!
- Ian
If you enjoyed reading this article and would like to help funding future content, please consider supporting my work on Patreon.