Arduino-EMC Integration: How it Works

One of the things that still sets “real” CNC machines apart from DIY conversions (apart from the thousands of pounds of cast iron, spindles with more torque than a small car, etc.) is the use of dedicated control panels. Bob Warfield’s site has a great page showing a number of panels from manufacturers like Fanuc along with some very impressive homebrew solutions. Besides giving direct access to frequently-used functions, these panels also provide a more natural feel, especially for semi-manual operations, which are especially common in home shops.

Despite their utility, the vast majority of hobbyists seem to get by with mouse and keyboard-based control. There are a variety of commercial solutions available, but they’re generally not cheap. Moreover, interfacing them to the PC tends to be messy. The easiest way to do it is through the parallel port, but you run out of pins really fast. I/O cards can give you a lot more pins to play with, but they add further cost and complexity.

Enter the Arduino open-source microcontroller board. For about $30 you get a powerful, complete, easy-to-program platform with 16 I/O pins and a serial-over-USB interface to any PC. This looked like a perfect solution, and Jeff Epler, one of the main developers behind the Axis GUI, had published a demo project proving that it could be done. But while it got a lot of people excited, it didn’t seem to lead to much else: I don’t recall seeing a single post or email on the list about Arduino-based human-machine interfaces (HMI).

As I installed and ran Jeff’s code, I think I figured out why. It ran perfectly the first time, which is kind of a record for me, and got me excited too because this really proved that it worked. Lots of times people publish code that doesn’t quite compile, run, or function as it’s supposed to, and this was the sort of thing that had the potential to be quite finicky.

But while it ran exactly as described, Jeff’s code was an example of obfuscation through optimization: at every level from the firmware to the serial protocol to the Python-HAL interface, it did everything with such economy of code that it was quite difficult to make sense of, at least to a semi-engineer like myself. So rather than trying to extend Jeff’s code, I ended up starting over from scratch, writing something that is no doubt less efficient, but a lot easier for mere mortals like myself to work with. And the good news so far is that I think it’s efficient enough to get the job done.

The basic principles of the system are easy enough to understand, provided that you’re somewhat comfortable with how EMC configurations actually work:

  • HAL Config: HAL provides a virtual breadboard of sorts that lets you map pins and signals to each other. Some of these are physical, i.e. you can wire the E-stop function to be triggered by Pin 10 on the Parallel port, but they can also map a signal (e.g. “turn flood coolant on”) to a virtual pin provided by another piece of software.In this case, I use the hal_postgui config file to wire up all the functions that the Ardunio-powered panel will talk with. If you’ve wired up an e-stop switch, it’s pretty much the same idea.
  • Python-HAL User Module: HAL provides a mechanism for users to create their own modules in Python. These modules implement whatever functionality the user wants, and then expose that functionality via standard HAL pins and signals. There’s a Python script, which imports a “hal” library that allows the programmer to create HAL objects and declare the externally-visible inputs and outputs. If you’re a programmer, these can be thought of just like objects and method signatures. If you’re not, just think of it as a way for a custom program to talk with HAL in HAL’s native language.
     In this application, the Python module is responsible for managing the serial communication layer on the PC. HAL signals get converted into serial messages which can be sent to the Arduino, while the Arduino’s serial messages get converted into HAL signals. In other words, HAL talks to the Python module and the Python module talks to the Arduino over the serial port, and vice-versa.
  • The Arduino is responsible for taking serial messages and converting them to physical output signals, and for taking physical input signals and converting them into serial messages back to the PC.

When you get down to it, there’s virtually nothing going on here but translation from one layer to another, times three, and back the other way. It’s less computer science than computer plumbing, and I found more than a few idiosyncrasies along the way, particularly in getting the serial communications to work as needed.

While I may have seemed to be slagging Jeff’s code earlier for being too hard to understand, another factor is that getting this stuff working, from scratch, requires you to understand each layer (HAL-EMC, the Python user module, serial communication, and Arduino) somewhat well. Going into this I had a moderate amount of experience with the Arduino environment and have written quite a bit of software for a living, but the rest was a mystery to me, and it took a couple dozen sessions of banging my head against every available wall before I got most of it working.

While I’ll be documenting and publishing my source code in more detail, for those immediately interested in trying this out, here’s my cheat sheet for getting into it:

  1. Get comfortable with the Arduino environment and libraries.
  2. Get comfortable with basic Python (it’s easy if you’ve used Java, PHP, or Ruby before), and particularly the PySerial library. One of the trickiest parts for me was understanding how to send structured data over the serial line; it’s a VERY low-level protocol compared to anything remotely modern. The best way (I think) is to structure everything as fixed-length messages along the lines of this example. Before you try to talk with EMC, write a Python program that sends and receives messages from the Arduino. Once you’ve got that working, you’re about 80% of the way there.
  3. Work through the HAL Advanced Tutorial first, then do the Creating Userspace Python Components tutorial.

Once I got the basic pieces working, I began working towards a more complete system, including an encoder for jogging, a 25-key keypad, and a 20×4 LCD. While the Arduino only has 16 usable I/O pins, I was able to fit 25 keys in by using a matrix scanning approach, just as you would with an LED matrix. While you could step up to an Arduino Mega and get a lot more I/O pins, I wanted to keep the initial version cheap and accessible for those who already had an Arduino on hand.

I initially chose to use the LCD partly for the heck of it, as I happened to have one in my parts pile, but also because it created a lot of opportunity for powerful display features. With just 6 digital pins, I got the ability to display darn near anything that could be rendered as text. Part of me would have liked to have physical LEDs right on the keypad for certain things (like designating the active axis for manual jogging), but I’ve found ways to display it on the LCD that I think are pretty good. On the flip side, it’s allowed me to create a remote display of a number of things that I think will be quite useful, especially if your main monitor is not right next to your machine. In the long run, I think this will provide a lot more upside than the regular LEDs would.


10 responses to “Arduino-EMC Integration: How it Works

  1. Pingback: EMC with Arduino for USB I/O? - Largest Machinist Community on the net!

  2. smoothspan December 1, 2010 at 10:31 am

    Hey, cool blog and Arduino post.

    I keep thinking the Arduino would make a great step driver–sort of like a Smoothstepper.



    • tmbg February 8, 2011 at 2:48 pm


      The problem with the arduino as a step driver is the comms are limited to USB, and it’s not really realtime enough.


      • Colin February 8, 2011 at 3:14 pm

        Bob made the point in another post that the SmoothStepper works great with Mach, and that’s CNC-over-USB, with Windows, no less. With USB, you are going to have to do buffering or something to make sure the outboard step generator doesn’t run out of things to do, but the SmoothStepper is proof it can be done well enough.

  3. GTI-Sam January 15, 2011 at 12:39 pm

    Really cool!!

  4. Bob Warfield February 8, 2011 at 3:33 pm

    Not only does it work “well enough”, it works far better than the parallel port compromise.

    Note that Gecko is introducing a series of drives that have a motion control language instead of step/dir. I am hopeful Mach will interface.

    The neat thing about the Arduinos is they are cheap. Smoothstepper is too expensive and too poorly supported for what it is.

    Now if it was me, I’d make the protocol to the Arduino be “pidgeon g-code”. Give it just enough commands to do G1/G2/G3 motions. Let the controller hand off those codes to it as soon as it gets them. The controller would do all of the coordinate transforms for work offsets and the like. You’d need to make sure this protocol allowed enough flexibility for the trajectory planner–I don’t know whether g-code’s semantics do, so that’s a compromise to consider.

    If you want to get fancy, give it some I/O to control relays and such. Perhaps a spindle speed output signal. Hey, pretty soon you have pretty potent little controller. The performance can’t possibly have to be that great when you look at what some of the older CNC controls had for cpu horsepower.

    That would be a simple yet powerful protocol that follows open standards.



  5. S. Junior March 31, 2011 at 8:16 am

    Hello! I’m trying to do that here but I do not have good knowledge in electronics and the programming could please pass the parts list and code the project?
    Much respect and thanks from Brazil.

  6. Mike June 28, 2011 at 8:49 am

    Hello, I wonder if a board like the chipkit UNO32 (arduino compatible) with a modified version of the Gcode interpreter used on the RepRap like this would work for this purpose? I suggest the chipkit because it runs at 80MHZ compared to the 16MHZ of the arduino plus it has 42I/O lines in a UNO package. Plus it’s 32 bit…… at roughly the same price.They also make a Mega version with 83 I/O. I am planning on using one of these with EMC2 following Colins project…..

    BTW thanks this is an awesome project!!!!


  7. dewy721 April 4, 2012 at 12:30 am

    Good job on the breakdown. I was having a hard time transcribing the concept in to English. Mind if I link your post?

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: