Category Archives: EMC2
Yesterday I took a few hours to go over to the Artisan’s Asylum, a “hackerspace” just outside Boston proper, to get checked out on their 2-axis Sharp CNC mill. If you live anywhere near Somerville, it’s a seriously cool place, and for $75 a month, you get access to a full shop with the aforementioned mill, a 13″ Clausing Colchester lathe, woodworking shop, and welding shop with 220V MIG and TIG machines.
My main reason to be there was that every so often, I have a part I can’t quite fit on my benchtop machines, but I was also interested to get a chance to work with a “real” CNC control, in this case, an Acu-Rite MILLPWR of early 90s vintage. Compared to a VMC, which is designed mainly for production, 2-axis knee mills like this are used to assist the machinist in making one-offs or very short runs, rather than replacing him completely. As such, they’re probably the closest “serious” industrial equivalent of what we do with little “toy” machines like mine.
While the control was organized differently than EMC or Mach, I found it very user-friendly and efficient to work with. After the jump, a few more detailed observations on what I really liked about it…
Read more of this post
Following on the previous post, I shot a quick video showing some of the new firmware features in action. Most importantly, my suspicion that it was a serial buffer overflow problem seems to have panned out. As this video shows, I can spin the encoder as hard as I can, and nothing weird happens. A more technical explanation after the jump…
Since switching to the 128-cpr encoder I’ve been having a slightly peculiar problem and I think I may have found the cause: serial buffer overflow.
What’s happening is that during program operation, when the DRO is receiving updates, if I spin the encoder very fast, the LCD display would lock up and refuse to display any values. Originally, the only way to recover was to reset the Arduino, but I made some improvements that allowed for a softer recovery. Basically, if it froze, you had to wait a second, then jiggle the encoder a little, and the display would come back. It still wasn’t robust, though, and I couldn’t see what was going on.
Well, it turns out that the Arduino’s serial buffer is a whopping 128 bytes, which isn’t very much. With 6-byte messages streaming in and 3-byte messages going out, it seems very possible that I’m getting buffer overruns. If this is in fact the problem, there are a bunch of different possible solutions, but they all basically come down to reducing the amount of data moving over the wire, particularly the update rate of the encoder.
On the incoming side, I’ve already made a major change in ditching the DRO display during program operation. Instead, I created a different page which displays the spindle and feed rate override percentage values, which are what you’d actually control in that setting. Next, I’m changing the way updates are sent so that only the “hot” parameter gets updated more than twice per second. In other words, if you’re manually jogging the X axis, then the X axis DRO will update ten times a second, but everything else will only update twice. Likewise, in program operation, if you’re tweaking the FRO, then the FRO% and velocity will update fast, but the spindle RPM will go in the slow lane. Taken together, this will reduce the number of updates without, I think, reducing any utility.
On the encoder side, there are a few possibilities. I didn’t have this problem with my old encoder, which was I think due to (1) it being only 32 CPR, so you’d have to spin it 4x faster to get the same amount of data output; and (2), it had detents, which slowed down the spin rate even further. All told, I think I liked the feel of the old encoder better. I *really* like the detents, because they allow for precise positioning. The lower pulse rate does make it less nice to use for long jogs, but since the pendant has continuous-jog buttons for both X and Y, I think the main use of the handwheel is primarily for nudging, where 32 CPR is plenty.
A true CNC MPG wheel like this one might be the best of both worlds, but it adds a lot of expense ($60-$80 vs $20-$30). I also picked up some really basic encoders of the type used in consumer audio/video equipment which I’m interested to try. They’re 24-count, detent type, and cost under $5 each. I previously tried some Panasonic encoders like this and they failed, because the output was unreliable for steady rotation, but maybe these will work better. If they do, it could trim $30 or more from the price of a finished pendant.
After a good 10 hours of knocking around and around a yard of double-sided tape, I finally have everything inside the enclosure!
The good news is that everything fits. Other than that it’s kind of a mess, which is probably to be expected from Serial #000001. The jog wheel was pulled off the shaft of a stepper, so it’s not as big or pretty as I’d want. The keypad works, but the cutout is major-league ugly, and the overlay doesn’t fit it well. And the labels don’t align as well with the buttons beneath as they should. Mounting the LCD was also a PITA as it required making a mount to fit the studs inside the enclosure. And, just when I thought I had everything ready, I realized the USB socket needs to have clearance milled out of both the top and bottom halves of the enclosure.
Nonetheless, I’m feeling pretty happy about seeing it all inside the enclosure for the first time. I had an epiphany and realized that the outlines for the cutouts for the keypad and LCD unit could be marked by printing outlines on sticker paper and sticking them right on the top of the case. All you’d have to do is clamp the case down and mill right through.
I also have an idea for improving the feel of the keypad. Tomorrow I’m going to hit the hardware store to see if I can get some 3/16″ weather stripping. The tops of the buttons are 0.167″ above the PCB, so if the weather stripping is 0.1875″ of foam, that might strike a good balance of firmness and give. I’ll keep my fingers crossed because if that doesn’t work, I’m probably going to have to go back to the drawing board. My goal has been to make this something that’s relatively easy for someone to assemble. Right now, I’m starting to push those limits a bit.
I’ve also started to go back and nibble more on the software. When I swapped in the new 128PPR encoder, I noticed a problem. Basically, if you gave the wheel a really good spin, it caused the Arduino to become unstable, and the only way to get it working properly was to reset it. The old, 32PPR encoder didn’t seem to cause this problem, but it may also have been that with detents, it simply couldn’t be spun as fast without really trying. More testing will be necessary. This is why the encoder is connected via a header, not soldered on!
In the meantime, I did some tweaking to the data input-handling routine in the Arduino, and the result is some improvement in the stability of it. Basically, I added some exception-handling code that tries to recover if the serial communications get out of whack. So far, it’s not preventing errors completely, but interestingly, if you spin the encoder and the display locks up, if you wait a second and just jiggle the wheel a little, it will “wake back up,” for lack of a better term. This makes me hopeful that there’s a specific condition or bug down there causing this that I can handle and make this really solid. As it is now, I think it’s quite usable, but it’s a long way from industrial quality. Though, it’s also a long way from industrial price….
I’m coming around to thinking that the 3-axis DRO page might only make sense when running in manual mode. Instead, I think I’m going to have a Program Run mode page that displays the FRO and SRO percentages, the spindle speed, and the velocity. That will be more useful, and, in practice, likely a lot less data coming down, which might make lockups even less likely.
Just thought I’d throw up a shot of the first completed board from last night. The photo below shows it laid on top of what I hope will become its enclosure. The tricky part, which I hope to work on this weekend, will be working out the mounting and keypad overlay.
One of the lessons I’ve taken from the success of the Shumatech DRO is the importance of having a good enclosure solution as part of the plan/kit. These are real tools meant for use in a quasi-industrial environment, so the enclosure is as important to the functionality of the pendant as the software or firmware.
At this point, my plan is to finish up the enclosure, and then start working all the kinks out of the software. I’m ready to get back into the shop for a while after spending the past few months bent over a breadboard and deciphering data sheets!
OK, so, the PCBs I was supposed to get early this week got stuck in customs in Shanghai, so I decided to take a few hours and put together a minimal Arduino-EMC case study with source code for those of you trying to follow along at home.
This example code is designed to control a normally-open switch and two LEDs, and is wired up to the machine on/off switch. I chose that configuration to test a cool new doohickey I got with my last Digikey order, which is a two-color illuminated pushbutton switch from NKK Switches (see here). It’s got a pushbutton plus two LEDs in a nice little package. It’s not sealed up the wazoo like a true industrial component, but it shouldn’t do any worse than the mice and keyboards people use in their shop. Either way, you should be able to replicate this example with any two LEDs and switch you have laying around–the Arduino and EMC parts won’t be any different.
I’ve attached all the code for this example as pages on this blog (WordPress is annoyingly whiny about file attachments other than common types like JPG, DOC, etc.). Here’s a basic outline of how to do this for yourself:
- Create the Arduino sketch using my sample code. Wire up a breadboard with 2 LEDs and a normally-open switch and connect them to the Arduino. Just to be safe, I strongly suggest firing up the Arduino serial monitor and trying to send and receive commands there just to be sure you have the circuit and Arduino working properly before proceeding.
- Once that’s known good, you’ll want to install the Python module in your /usr/bin directory. First, copy and paste the source code into a text file and save it as “simple_arduino” without any file extension. Then, move that file to your /usr/bin directory and make it executable using these commands:
sudo cp simple_arduino /usr/bin
chmod +x /usr/bin/simple_arduino
- Configure your HAL file: This uses the HALUI module to pass commands to EMC. See here for my sample HAL configscript. Make sure that your machine .ini file loads the HALUI module and runs the script.
If the comments in my code don’t answer all your questions about how it works, feel free to leave questions in the comments. Good luck and have fun experimenting!
I have an order of 12 boards on a UPS truck that refuses to show up at my office when I am there. Hopefully this will end Monday. I’m putting together a parts order so I can stuff the board and find out whether I made myself a set of green coasters. One of the joys of this game is that it’s never easy to get everything you need from Digikey or Mouser, there’s always one part that you need to order from the other guy.
This cropped up as I was shopping for encoders. The one I’ve been using contains tasty lead, which means it’s a no-no for our friends in Europe. So I found a new one for about the same price which might be much better. It’s a Honeywell 128-count encoder, which is 4x the resolution of what I was using, but it doesn’t have detents (which I like). It’s marked as end-of-life, but both suppliers have 500+ in stock, so hopefully it will be available at least for the next few months or so.
Cheap Encoders Considered Harmful
I also had a chance recently to test out some $3 Panasonic 24-count encoders I ordered on a lark with some other items. At that price, I had the idea of doing a board with 3 encoders, one for each X/Y/Z axis, plus the spindle and feed overrides. Unfortunately, my first experience with them wasn’t very encouraging. I found that they missed counts very badly when turned any more than a single click at a time. I could see them still being usable for a secondary control like an SRO/FRO, but for axis control I think they’d start to stink pretty fast. Live and learn.
Another thing I’ve had to educate myself on that has proven surprisingly complex is the world of cables and interconnects. Every electronic project I’ve done has gone great until it came time to run wires between the PCB(s) and the other bits. At that point it went one of two ways:
- Solder nice long leads on while still on the bench, then roll it all into a bird’s nest and jam it in the enclosure. Works if appearance, interference, and space aren’t concerns.
- Mount everything in the enclosure, then spend HOURS cutting, stripping, and soldering wires into place. Pray to the deity of your choice that you never need to remove or replace any of it.
For that reason, I’ve designed this to (1) require as little cabling as possible, and (2) to permit maximum flexibility where it is required. Any connector that uses .100″ spacing will work, and there are literally hundreds of options out there. Many require special tools, so I’m ordering a few different ones to see which are easiest to do without special tools. I have a funny feeling that in the end, plain-old screw terminals may prove the best compromise….
My D’OH! Moment
The first big OOPS I noticed too late in the game was that I did not provide for a reset switch for the Arduino. The on-board switch will be blocked, so this means the only way to do a reset will be to pop the cord. Normally you shouldn’t need to reset the Arduino during operation, but I’d like to provide for the option so this will get fixed on the next rev. If I’m lucky, this is the only oversight, as it’s more of an inconvenience than a fatal error.
Why I’m Not Releasing the Source Code–YET
I’ve gotten a LOT of requests for source code, and the answer is still “no.” Here’s why:
- Always trash the prototype: What I have right now is a bunch of hacks and half-measures stitched together to prove that I could get it to work. One of the most important rules of software development is to build a prototype, and then throw it out and start over when it’s time for the production code. Looking back over the four months or so since I started this, I see a lot of things I want to do differently in an architectural sense, which I’ll write more about later.
- I can’t support it: I want to spend my time building the V1 production code, not helping people to get this crud working in their setup. If I sent the code to somebody and it didn’t work, I’d feel obligated to help them, and right now, I don’t have the time to do that *and* move the more important part forward.
- So? I can use what you have: Probably not. My code is a big pile of spaghetti built around exactly the hardware setup I’ve built. Even if you had exactly the same hardware I do, you’ll find a lot of features that work halfway (on a good day). If you want to just use a few switches and an encoder with no LCD for instance, you’ll find most of it needs re-writing. In that case, you’re going to be better off starting from scratch and building it all your way. In a previous post, I laid out a roadmap for exactly how to do that. Trust me, that’s going to be easier than dissecting my code. I ran into exactly this problem when trying to re-purpose Jeff Epler’s original Arduino-EMC example and ended up redoing everything from first principles. If doing that is beyond your abilities, I suspect my code would prove equally useless.
- We shall sell no wine before its time: From a commercial standpoint, I think it makes more sense for me to not release the software until I have boards for sale. Now, I have no objection to anyone taking that and using it to build their own without buying diddlysquat from me. Likewise, once it’s out there, It’ll be open for anyone to learn from and make a better product than mine. C’est la vie. But, at this moment I do have a little wiggle room to maximize my first-mover advantage. If you’re frustrated because you want to start your project, just think of that waiting as the price you’re paying to have me do the hard work for you 🙂
I have thought about publishing a mini-tutorial on how to push single bits and signals back and forth from EMC through HAL to the Arduino and back, but this would be more hours of work, for which please see (2) above. So I’m planning to do this after the PCB and V1 software are ready. In the meantime, please don’t hate me too much!
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:
- Get comfortable with the Arduino environment and libraries.
- 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.
- 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.