CNC Electronics (Custom CNC Part 3)

CNC Electronics (Custom CNC Part 3)

If you are just joining us, take a look at part 1 and 2 at:

Version 1 (G251 + parallel breakout board)

It took me a long time in life to realize I should do it right the first time, but lets not be too tough on me. It was 2008 and things were just getting started. The first real build I did consisted of 4 G251 Gecko drivers and a parallel breakout board. The Breakout board was:

It served me just fine, but don’t go buying it just now. In order to use it, you will need a computer that has a parallel port. These 25 pin connectors are hard to come by now a days and if you choose to go down this route be sure you have an old desktop computer to serve you. You will also need special software ($).

The item that I would recommend however are the G251Xs I used:

These lasted me a while (Until I burnt them up, see Part 1). They were not very expensive and were really versatile. I keep the one I have left on hand for a quick way to power higher torque steppers. After the fire, again, Part 1, I moved away from this setup, however, I kept the computer.

Version 2 (G540, 2010-2018)

The G540 is WONDERFUL! It really is, it has everything you need to get a 4 axis CNC machine working at a killer price. Now, I am realizing I haven’t talked about it. You can’t use the stepper drivers from your 3D printer to drive a big CNC router. You will need high torque stepper motors which usually run 30-50V DC at ~3 amps. I’ll tell you exactly what I used later in Version 3. Back to the G540, it has the ability to operate from 18-50VDC, drive up to 3.5 amp motors. Has built in input and output protection and an E-STOP input. Its a legend in the home CNC world:

To power this guy I used a 48V 12.5amp DC switching regulator. You will find some discussions online about switching vs non-switching but I have never had a problem with the one I used. I couldn’t find the exact one I bought but this one has the same specs:

With these items, you could not drive a CNC using the parallel port off of an old computer. This is where version 2.5 comes in. After a few months my dell computer broke down and I didn’t want to get a new one. I wanted to be able to use my laptop, which didn’t have a parallel port. To adapt the G540 to something I could use I picked up an Ethernet Smooth Stepper:

The Ethernet Smooth Stepper works with a software packaged called Mach 3 by ArtSoft. It connected over an ethernet port and provided 3 parallel ports worth of In/Outs (IOs). Mach 3 and the Ethernet Smooth stepper served me from 2009 until 2018 when I switch to an open source option. The reason I switched was that I grew tired of the old Mach 3 interface and because my old laptop was then dyeing too. Besides, by the point I switched the open source world had provided some great options. I’ll talk to those next.

Version 3 (2018+)

Finally to the good part. Lets talk about my current build. The reasons for the change were three fold.

  1. My shop laptop was dying.
  2. I was tired of the closed source nature of the Smooth Stepper & Mach 3 system.
  3. One of the ports of the G540 melted…

Reasons 1 and 2 above are mundane but reason 3 was interesting. I was cleaning my machine and disconnected all of my motor cables from the back of the G540. These cables were from When I removed them I found a single pin on a single connector on the G540 was melted and I could not plug the cable back in. No mater what I tried I could not get it to work again. I tried cleaning it, drilling it and ultimately resoldering the connector on the G540. Alas, I failed. I did double check all of my current settings and never did find a reason for the trouble. I still feel 8 years of trouble free service from the G540 was pretty good but it was time to say good bye.

To kick things off for the new build, the BIG Changes were as follows:

  • I got rid of the old computer
    • Replaced it with a Raspberry PI
  • I stopped using old, closed source software
    • Replaced it with CNCJS and GRBL MEGA 5X
  • I removed the Ethernet Smooth Stepper
    • Replaced it with and Arduino Mega + breakout board
  • Said good bye to the Gecko G540
    • Replaced with individually replaceable Stepper Drivers
  • Bought a new metal case for the whole thing

The Case

The case had to be metal and finding a good sized metal case that didn’t cost a small fraction of the total build cost proved difficult. I finally found a great solution by not looking for an electronics enclosure. I found the AC Infinity Rack Mount Drawer. It is a 3U (19″) lockable steel drawer with an Aluminum Faceplate. It is meant to go in a server rack, but it has proved more than perfect as a CNC electronics’ housing.

The case didn’t come with the pretty display or buttons and switches. Those came and will be discussed later.

Major Electronic Components

I would consider the major electronic components, in the order I will cover them, to be:

  • Actuator: Stepper Motors
  • Power Transmission: Cables
  • Power Source: Power Supply
  • Drivers: Stepper Drivers
  • Logic: Arduino Mega

Stepper Motors

I began my build by reusing what I had. One of my earliest purchases were powerful stepper motors for the version 1 of my CNC. I used 425oz-in NEMA 23 stepper motors. If you are not familiar, NEMA is a standard for motor mounts and sizes. These would and have provided amble torque to move my machine. I have reached in excess of 1,000 ipm with no loose of steps. Loosing steps is what happens when the machine things it has taken a step (Turned the motor a certain amount) but in reality it hasn’t. Conversely this can happen if the motor is moved when the machine doesn’t command it. Most of the time this is caused by the momentum of the machine overcoming the holding torque of the motor. To avoid this, the machine needs strong motors. But, if the motors are too strong, they will require too much power and drive the cost of the build way up. I have found that ~400oz-in is a good sweat spot for a router this size. My current recommended motors are:

These motors draw 4.0 amps at full load. Given that I have 4 motors, this means the most my system could ever draw if I maxed out my motors would be 4×4=16amps.


When I bought the G540 driver (Not used in my current build) it has DB9 connectors on the back. These looked just like serial port connectors but were rated for higher current. Given my bad luck with trying to build my own cables, I just bit the bullet and bought some premade ones that suited me well. These are the only ones I recommend:

I needed four total:

  • 2 x 12ft (A and Y axis)
  • 2 x 20ft (X and Z axis)

They are high quality, thick gauge, low resistance cables and are honestly perfect for this job.

Power Supply

I have already spoken to the Power Supply, but to rehash. I got a 48VDC switching power supply capable of delivering 12.5 amps. The one I used was similar to this one:

If you have been reading through from start to finish, you will remember that my motors (All 4 at once) could pull up to 16 amps, which is definitely more than the 12.5 max of the power supply. I did this for a few reasons but mainly, it was cost. A Power supply that could reach 16 amps was crazy expensive. I could make a reasonable assumption that I would never drive all four at full power at the same time, but this still didn’t sit well. How I compensated was to use stepper drivers that would limit the current draw to 3.0amps per motor, thus resulting is theoretical max of 12amps being drawn at any given time. I will also take this time to note that I choose to down tune my power supply to 42 volts so that I wasn’t riding right at the upper limit.

Stepper Drivers

This is what started it all, needing new drivers. When my G540 died, I was very tempted to just buy another, but they aren’t cheap (And for good reason). In the end what convinced me not to was the availability of inexpensive individual drivers I could size to my needs. Based on what I already had in my inventory, I needed something that could accept 48VDC and drive motors at 3.0 amps. After some extensive searching and comparing, I settled on:

I could get the four I needed for a fraction of the cost of a G540 and I could configure it however I wanted. You will see that they are 24-50VDC and can drive up to 4.5 Amps. One thing that made this particular driver special was that I could configure it to deliver exactly 3.0 Amps by way of its dip switches. This allowed me to safely drive all four motors without worrying about over taxing my power supply. Also note, I bought five of them. This way, if one ever does die, I will have a drop in replacement. This also allows me to eventually…. I know I’ll probably never do it…. build a fourth, rotary axis. These have now been running in my machine for close to a year and I have nothing but praise to give them. Here is my Z axis driver with all of the wires and dip switches configured:

We will cover the rest of the wiring elsewhere, but lets spend a few minutes talking about the wiring and configuration of these drivers. Please note, as I write this, I realized a few errors. In the above picture you will notice I have my DIP switches wrong (Or at least not as I intended them to be)

In the above, I have highlighted what the settings SHOULD be for my setup in orange text. I have it setup to be 3.0 Amps with full current and 3200 steps per revolution (16 microstepping). If you compare this to the image of my Z Axis driver above, you will see that I have the driver setup to be 3.5Amps with HALF Current. This means I have been driving my machine, with no problems, at 1.75 Amps, significantly less than I could be. I have no idea why I made this error, but I will go downstairs right now and fix it…

Okay, I’m back. That was an easy fix and everything seems to run just fine. Of note, the motors sound prettier if that’s a thing. In the above graphic you will also notice that I tied all of the +5V together. This was simply to save wiring but I really see no reason why this wasn’t just done internally. Here is my completed setup, with all four drivers and power supply installed:

Logic and Arduino Mega

We have all of the components needed to drive and move our CNC, now we have to provide the logic. I would love to tell you that it was a hard search for just exactly how I was going to provide logic for my CNC, but it wasn’t. From my Laser Cutter build I had been exposed to GRBL. GRBL is a high efficiency gcode interpreter that runs on Arduino microcontrollers. The original was purpose programmed for the Arduino UNO but a port was made for the Arduino Mega. This port expanded GRBL to 6 axis and allowed for cloned axis. Since my build the main branch of GRBL now supports cloned axis, but I have chosen to stick with the MEGA implementation as it supports up to 6 axis for future scalability. Please note, I am not using the MEGA version of GRBL, but the MEGA-5X version found here:

We will get to firmware configuration later. For now, lets talk about wiring and the Arduino itself. The Arduino Mega has 54 digital I/O pins and 16 analog inputs. It operates at 16Mhz and can connect to a computer via a USB Serial connection. It isn’t the biggest or badest Arduino board out there, but it is ample for our purposes… And it is cheap:

It comes with a bunch of pin headers, but I wanted to be able to secure the connections with screw terminals. Luck would have it that I was able to find this:

This board plugs right on top of the mega and provides screw terminal connections for every pin! There are a few similar options available but I found this one, with its prototyping breadboard like center a handy option for possible future needs. The Mega-5X code has a file in it labeled cpu_map.h and has a section that is preconfigured for RAMPS 1.4. Using a RAMPS 1.4 board is absolutely an option, but I preferred the approach I took as it had screw terminals. The cpu_map.h file defines the pinouts and those map to the screw terminal board as follows (Orange are pin I implemented):

When I first attempted this, I tried to change the pinouts to make more physical layout since, but quickly realized I didn’t know the ports or pins well enough on the Mega and abandoned changing them. It should be noted that on this board, three pins are in accessible, D59, D58 and D57. If I ever want to implement a 5th or 6th axis, I would need to remap these to pins that were accessible.

Lets quickly talk about something else that needs to be connected to this board for things to work well. The board connects to a computer via a USB port and this port could provide +5VDC to most of the peripherals, but I didn’t want to be limited to the 300ma of USB <= 2.0. I also installed a 5VDC regulator to provide ample current for the 5VDC systems to come. The exact one I used is no longer available as it was scrap to begin with. If bought new, something similar to this one would work great:

The Front Panel

The front panel of my case is a nice brushed anodized aluminum plate. Onto it I mounted a voltage and current meter as well as some basic machine state controls:

The machine state controls are:

  • Start: Cycle Start after a Park or Feedhold
    • Resumes a feed hold, a safety door/parking state when the door is closed, and the M0 program pause states.
    • If the parking compile-time option is enabled and the safety door state is ready to resume, Grbl will re-enable the spindle and coolant, move back into position, and then resume.
  • Hold: Stop moving but keep motors and spindle active
    • Places Grbl into a suspend or HOLD state.
    • If in motion, the machine will decelerate to a stop and then be suspended.
    • If jogging, a feed hold will cancel the jog motion and flush all remaining jog motions in the planner buffer. The state will return from JOG to IDLE, if was detected as ajar during the active hold.
    • By machine control definition, a feed hold does not disable the spindle or coolant. Only motion.
  • Stop: Like an Emergency Stop
    • Immediately halts and safely resets Grbl without a power-cycle.
    • If reset while in motion, Grbl will throw an alarm to indicate position may be lost from the motion halt;
    • If reset while not in motion, position is retained and re-homing is not required.
  • Park (Door Safety Feature)
    • Immediately suspends into a DOOR state and disables the spindle and coolant. If in motion, the machine will decelerate to a stop and then be suspended.
    • If executed during homing, Grbl will instead halt motion and throw a homing alarm.
    • If already in a suspend state or HOLD, the DOOR state supersedes it.
    • If the parking compile-time option is enabled, Grbl will park the spindle to a specified location.
    • Command executes when Grbl is in an IDLE, HOLD, RUN, HOMING, or JOG state. It is otherwise ignored.
    • If jogging, a safety door will cancel the jog and all queued motions in the planner buffer. When the safety door is closed and resumed, Grbl will return to an IDLE state.

These buttons are simple momentary 5V buttons that are connected directly to the Arduino Mega. I got them here:

The power meter wasn’t really necessary, but since I happened to have one from another project, I thought it was a nice feature. The one I got was:

It was a cheap and a neat addition. The meter reads out the output voltage, amps, power and total energy used since turned on. The only real complaint I have about it is that the LCD is really hard to read at any angle other than dead on.


First I went over to and download the repository. I used the default RAMPS configuration to minimize how much work I would have to do. However, I still did need to make a few changes as I have my A axis cloned to my Y axis so that the two independent motors on the left and right of my machine move in unison. Once you download the code open up the config.h file. First, on line 54, change:

  #define N_AXIS_LINEAR 3     // Number of linears axis


  #define N_AXIS_LINEAR 4     // Number of linears axis

Then to clone the axis, go to line 71 and change:

  #define AXIS_4_NAME 'A' // Letter of axis number 4


  #define AXIS_4_NAME 'Y' // Letter of axis number 4

This sets up the basic mechanics. To have them home correctly, you will now need to go to lines 172-199.

  #if N_AXIS == 4 // 4 axis : homing
    #define HOMING_CYCLE_0 (1<<AXIS_3) // Home Z axis first to clear workspace.
    #define HOMING_CYCLE_1 (1<<AXIS_4) // Home 4th axis (A)
    #define HOMING_CYCLE_2 (1<<AXIS_1) // Home X axis
    #define HOMING_CYCLE_3 (1<<AXIS_2) // Home Y axis
  #elif N_AXIS == 5 // 5 axis : homing
    #define HOMING_CYCLE_0 (1<<AXIS_3) // Home Z axis first to clear workspace.
    #define HOMING_CYCLE_1 (1<<AXIS_4) // Home 4th axis (A)
    #define HOMING_CYCLE_2 (1<<AXIS_5) // Home 5th axis (B)
    #define HOMING_CYCLE_3 (1<<AXIS_1) // Home X axis
    #define HOMING_CYCLE_4 (1<<AXIS_2) // Home Y axis
  #elif N_AXIS == 6 // 6 axis : homing
    #define HOMING_CYCLE_0 (1<<AXIS_3) // Home Z axis first to clear workspace.
    #define HOMING_CYCLE_1 (1<<AXIS_4) // Home 4th axis (A)
    #define HOMING_CYCLE_2 (1<<AXIS_5) // Home 5th axis (B)
    #define HOMING_CYCLE_3 (1<<AXIS_6) // Home 6th axis (C)
    #define HOMING_CYCLE_4 (1<<AXIS_1) // Home X axis
    #define HOMING_CYCLE_5 (1<<AXIS_2) // Home Y axis
  #else // Classic 3 axis
    #define HOMING_CYCLE_0 (1<<AXIS_3) // Home Z axis first to clear workspace.
    #define HOMING_CYCLE_1 (1<<AXIS_1) // Home X axis
    #define HOMING_CYCLE_2 (1<<AXIS_2) // Home Y axis
  #define HOMING_CYCLE_0 (1<<AXIS_3)                // REQUIRED: First move Z to clear workspace.
  #define HOMING_CYCLE_1 ((1<<AXIS_1)|(1<<AXIS_2))  // OPTIONAL: Then move X,Y at the same time.
  // #define HOMING_CYCLE_2                         // OPTIONAL: Uncomment and add axes mask to enable

I went ahead and just deleted the whole section and replaced it with:

// First move Z to clear workspace.  
#define HOMING_CYCLE_0 (1<<AXIS_3)                 
// Home X axis
#define HOMING_CYCLE_1 (1<<AXIS_1)                 
// Then Home Y & A at the same time.
#define HOMING_CYCLE_2 ((1<<AXIS_2)|(1<<AXIS_4))   

From there I went down to line 622 and enabled the Parking Feature:

#define PARKING_ENABLE  // Default disabled. Uncomment to enable

Thats it for changes to the firmware. Next I burned it to the Mega using the Arduino IDE and the included instructions. Please take note, you need to read the instructions as you actually have to import GRBL as a Library into Arduino and then open a specific example to burn it.