I had to come up with a catchy name for it. Here’s the story. On the Shapeoko forum a user (Joey) tried using Grbl Controller 3.0 and found that his nc file would “stutter”. I asked him for a copy and ran it through my tests – the problem was that the file had many line segments that caused an acceleration and deceleration for every segment, which would appear like a stutter effect.
Joey rightly pointed out that GCodeSender didn’t have this problem. I ran it, and sure enough, he was right, the accel/decel were gone, it ran fast and smooth. Why? The code in GCodeSender would keep sending commands to Grbl as fast as possible without waiting for an ok. The old Grbl Controller would always wait for an ok after every command. Turns out that Grbl is actually designed to accept a chain of commands and it will optimize the speeds between each command.
Now, Grbl has a limited input buffer of 128 bytes. It only takes about 8 or so commands before the buffer fills up. If you pull down the Grbl code off github, you will get a file called stream.py, which is a python script that precomputes how many bytes of data it has put into Grbl’s buffer at any given time and limits additional commands until it gets ok or error acknowledgements. You get an ok (or error) for each command, so it is really a simple problem to know when to send a command and when not to. Interestingly, the GCodeSender code does not do this computation – I am surprised no one is experiencing buffer overruns in Grbl when using GCodeSender (which happens to be written in C#).
Taking a cue from stream.py, I modified Grbl Controller to use the same approach to aggressively preload Grbl’s input buffer, without overflowing it. This had to be done in a way that also allowed the old approach to also function properly. I didn’t want to rewrite the serial logic, so it ended up being tricky to support both modes in the same code (normal and preload), but it is in there and working properly.
Thinking I had it working, I bumped up against a couple of problems:
- On fast PCs, the serial send would drop data on rare occasion. Unfortunately, this confused the preload counting logic and around half way through the file send it would just stop – because the expected number of ok’s didn’t match the actual. Turns out that QextSerialPort’s Windows library needed a minor tweak to increase the send timeout from 10 to 500 ms.
- The deluge of commands due to preload caused rapid redraw of the status window, which becomes slower to respond the more data in it. I was seeing the Raspberry Pi run a 4 minute file in 10 minutes due to CPU pegging. Fortunately I found a trick where you disable the window’s auto width computation and limit the number of “scroll to end”s and all of a sudden the performance was really good again.
And when I ran the tests, my preload mode would result in messed up cuts. Did I have a bug? No – my stepper shields’ bolt-on heat sink’s nuts had come undone due to vibration and the stepper drivers were shutting down due to overheating! Once I tightened them up, all worked well. Now I need to find that Loctite…