We Have a Winner!
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…
The Arduino has two serial buffers, one for input, one for output. Each can hold 64 bytes. With incoming messages taking up 6 bytes per message, it doesn’t take many for it to fill up, and when that happens, a “buffer overflow” occurs. It’s the computer equivalent of trying to stuff ten pounds of $#@! in a five-pound bag. Normally, the buffer is just a staging area, a loading dock where messages coming off the trucks (the wire) are quickly picked up and taken into the warehouse (processed by the main program). So long as they get picked up quick enough, things work fine.
In this case, though, the Arduino has to do more than unpack incoming serial messages, it also has to send messages back out in response to user actions (like spinning the MPG wheel). In order to work properly, the encoder is connected to what are known as Interrupt Service Routines (ISRs). Specifically, any time the value on either of the two encoder signal lines changes, the Arduino will pause whatever it’s doing and process the encoder input to notify the host PC that the encoder has turned one unit clockwise or counter-clockwise.
Under normal circumstances, the Arduino runs fast enough that it can handle a bunch of encoder pulses, process an incoming display update, then a few more encoder pulses, and get back to the display update before the buffer gets too full. But if you spin the encoder fast enough, it basically monopolizes the Arduino’s resources, and boxes start falling off the loading dock.
My solution to this was to put a “choke” on the encoder ISR. When the routine is called, it first checks to see how long it’s been since the last call (i.e. encoder count). If it was less than 5 milliseconds ago, then it ignores the encoder and returns to normal program execution before running most of the ISR. This appears to provide just enough breathing room to keep the incoming buffer from backing up.
EMC2′s halui module supports two modes of jogging: incremental, where each encoder pulse results in a fixed increment of motion (e.g. 0.010″), or velocity, where the axis moves at a rate proportional to the speed of the encoder. I’ve been testing only in incremental mode so far, and it’s not clear whether my solution to this problem would work well in velocity mode, since the behavior of the system is to essentially lock the encoder output when the rate exceeds a certain value. That being said, you have to give the encoder a *really* fast spin before it gets clipped much, so I think it’s a good solution. At the very least, it’s a truly stable solution, which makes me feel a lot better about this than I did earlier today.
At this point, I’ve got pretty much all the core building blocks working. I haven’t wired up the spindle rate override, the velocity or spindle readouts, the coolant relay, etc., but those are just more of the same that’s already seen here. So now it’s time to move on to my next big idea, which if I can get it to work will be absolutely delicious. Stay tuned….