View Full Version : Command line machining under linux with USB PIC

09-28-2013, 05:36 PM

I have a working 4-axis coordinated control system working under linux. I'll briefly summarize the project and post more if there is interest.

The system takes simple files that list x,y,z,w coordinates in an ascii file - one coordinate per line. For example, a simple rectangular cut might look like this:

------ cut here and save as "square.path"-----
0 0 0 # scripts always start at zero point
0 0 0.1 # move tool up for clearance
-1 -1 0.1 # jump to start
-1 -1 -0.1 # cutting
-1 1 -0.1
1 1 -0.1
1 -1 -0.1
-1 -1 -0.1
-1 -1 0.1 # up for clearance
0 0 0.1 # back home
------- cut here -----------

You can then send this file to the velocity profiler program "velo" with acceleration, velocity, stepper resolution and lookahead parameters.

velo -a 10 -v .2 -n 7 -r .0001 < square.path > square.steps

velo then does a (in this case) 7 segment lookahead, coordinated trapezoidal path generation with velocity and acceleration limits and produces a step file with all the steps and timings needed for the cut.

The step file is simply a sequence of bytes. The bytes encode several commands. You can think of these bytes as kind of a compressed low-level assembly language for stepper control. The first command is the DIR command which sets the default direction for all four axes. The second is a STEP command which commands a step on any combination of the four axes. The last major command is the DELAY command which programs 1-128 delay ticks between STEP commands.

These byte codes are designed to be drip-fed by the "feed" program into a P18F4525 pic through a USB interface at 200kbaud rate. The pic saves the raw step codes in a circular fifo using a high-priority interrupt. The drip feed uses flow control so that the computer keeps the fifo fill, but can't overrun the buffer. The main routine in the pic unpacks the fifo and interprets these byte codes, expanding them into delay commands. The output of the interpreted codes go into a second fifo that gets unloaded into a parallel port at a precise 20KHz interrupt rate.

So the whole tool chain could be run in realtime like this:

velo -a 10 -v .2 -n 7 -r .0001 < square.path | feed

If you have a really slow computer, you might opt to precompute the tool path and run it from a file like

feed < square.steps

I am getting error-free coordinated control of my CNC3040 from a 5-year old HP laptop. I also have a variant of the board which talks to a sparkfun quadstepper. This works real nicely for general factory control. It is easy to write programs to generate the step file for 4 arbitrary pulley velocities, or to control syringes in chemical processes. The latency is fairly low, so the control program can monitor the process and adjust the pulse spacing in real time with a PID loop.

Conceptually, this system is just like a sound card. In a sound card, the player program streams audio samples to the card and the card manages to send them at a precise 44 KHz sampling rate. In this program, the "feed" dripfeeder sends compressed step commands to the PIC, which interprets and outputs them at a precise master clock rate. The buffers and flow control ensure that even on a multi-tasking laptop that no glitches occur in the coordinated stepper pulse output.

I also have a program "jog" which lets you use the arrow keys to move the gantry around. The "feed" program always assumes that the current gantry position is at 0,0,0,0.

I've also modified the NIST G-code interpreter to output path files. Then you can do something like:

cat step.gcode | rs274 | velo | feed

and run a gcode file. This is currently at just a hacked "proof of concept" stage, but it does work.

I have linux c code, ccsc c PIC code, schematics and PCB layouts in kicad.

I would love to know if there is any interest in this beast... It's not a GUI g-code system, but it is more flexible in some ways for scientific 4-axis coordinated stepper control. One is free to approach a job in terms of an awk or python script rather than always going to a CAD package.

The step files are also instantly plottable in any 2d ascii plotting program. I use my own program
PDPlot X11 graphing tool (http://www.omnisterra.com/walker/linux/pdplot/intro.htm) for viewing and my 2d hierarchical cad program
Piglet Drawing Editor (http://www.omnisterra.com/walker/linux/piglet/) for doing path generation, but most any graphing/drawing programs will work.

Rick Walker

09-29-2013, 09:26 AM
It certainly sounds interesting enough, but I don't have any actual application for it (at least not right now).

Do you have facilities for detecting buffer 'starvation' in case the PC becomes overloaded?

09-29-2013, 04:38 PM
I am interested, I must admit to being an AVR person rather than PIC but... I am a linux person, this devision of labour seems to me to be the right way to do things... Use linux to build the very low level commands to move the steppers and a micro dedicated to doing that...

09-29-2013, 04:56 PM
The P18F4525 pic has about 4k of ram. I'm using most of that for the two buffers. That's several seconds of buffering.

There is a tradeoff between baud rate of the feed program and the interrupt rate of the stepper output. There are two LEDs on the pic board
that are on when the input and output FIFOs are above the high water mark. They go dark when the FIFOs gets below the 1/2 fill point. The way I have it tuned the lights stay on about 95% of the time with brief flickering as the feed program pumps the fifo back up.

I think that even if the laptop feed process gets blocked for more than a second, the FIFOs will prevent any interruption to the stepper operation.

Even so, I usually run the system as root and lightly loaded.

09-30-2013, 04:25 PM
Hi Armstrong360,

The PIC is doing a pretty simple job. It simply reads bytes from an FTDI-232 USB-serial chip with a high priority interrupt and puts them in a FIFO. It turns off the CTS flag if the FIFO gets more than 3/4 full. Then it runs a main routine that mostly just passes the info to an output buffer and expands the (DELAY N) commands by stuffing N null bytes into the output queue. Finally, it has a 20kHz interrupt routine that unpacks the output queue and puts the step/dir bytes into the parallel port connector.

The code is written in C, is only a few pages long and would be trivial to recompile for an AVR.

The interesting thing is not the PIC code, but the overall architecture of this approach.

The velocity planner is simple since it does nothing but look-ahead and trapezoidal velocity generation. It's only a couple pages of C.

The drip feeder program just opens up the USB-serial converter port, sets it raw, and turns on flow control. After that, it reads from standard input and just passes the bytes to the PIC.

The rest of the tool chain is ad-hoc using whatever tools you want to generate ASCII coordinates. You can plot them with gnu-plot, translate back-forth to DXF and so on.

At the moment, the eco-system is not very refined. However, this architecture makes it possible for a pretty low power computer to reliably drive a coordinated stepper system. For instance, it would be possible to run a CNC3040 from an android phone. The velocity profiling gets run in non-real-time and gets saved to a file. Then the phone simply drip feeds through USB. (It's not quite that simple because the phone is a USB client instead of a host, but FTDI also makes host interface chipsets that could "pull" from the phone instead).

I think the other advantage is that one doesn't always need to go through the G-code dance. For scientific or technical 3-D control it is sometimes useful to generate paths on the fly, making changes based on measurements, requiring a low latency real-time control system. By getting rid of the G-code phase, this system starts to make steppers into a real-time dynamic positioning system.

kind regards,
Rick Walker

09-30-2013, 05:02 PM
Another question - I think that device has 8-bit I/O ports - were you able to fit all step/dir outputs into a single port that can be updated in a single write? (My guess is 'yes', but I haven't programmed a PIC since 2004 so my memory of the internals is pretty rusty).

09-30-2013, 05:27 PM
Hi Doorknob,

All the 4 axis step and direction pulses are output to the parallel port as a single byte from the 20kHz interrrupt queue.

Currently the code sends the byte as (wd,ws,zd,zs,yd,ys,xd,xs) for the step and direction pulse of the w,x,y,z axes. It would be slightly more efficient to arrange them as (wd,zd,yd,xd,ws,zs,ys,xs) because I could do masking and shifting in the interpreter loop instead of bit setting. I'll leave that as a mod for the next version of the code. The place that it would streamline is in the main line interpreter block that doesn't really have much impact on performance anyway.

So, the steps all come out as a single 8-bit port write.

In addition, the PIC also has another two eight-bit I/O ports. I have commands for controlling spindle PWM speed, stepper resolution (1,1/2,1/4,1/8 step), enabling/disabling each channel driver and so on. I have enough input ports left to do xyz limit switch inputs and estop button but haven't implemented them. (I'm going to have to mod my CNC3040 controller to wire up the limit switches).

The eight bit step codes have enough entries to control all of these functions.

I think that it should be possible to hack this byte-wide interface into EMC2 or one of the other G-code controllers as an alternate physical layer. Haven't looked into it yet. Before getting too excited about it I wanted to see if there was any significant interest, or if I was just getting excited about something silly.

Rick Walker

10-01-2013, 09:31 PM
Hi Rick
Sounds like a great project - I would be very interested in trying it out.
Is the maximum step rate 20K???? I tend to use Servo motors with a relatively high encoder count so I really need the step rates up around the 100k mark.


10-01-2013, 10:29 PM
Hi Andrew,

19kHz was as fast as I could get everything to work. I'm using a 40MHz internal clock. The PIC has to read the RS232 input at 200Kbaud, which is about 20K bytes/second. Then it has to interpret, put the steps into the output queue. It then has to unpack the output queue with the 19KHz interrupt. I'm not sure if I've tried to increase the output rate now that I have the DELAY command. The current setup can do one step every cycle, but in practice, there are lots of DEL commands that get interpolated into dozens of output null steps, so the output interrupt may be capable of running faster for typical jobs. If I push it, then you might get FIFO underruns depending on the job.

My CNC3040 has 400 steps per mm or about 10,000/inch. At one step every four interrupts max rate, I get 0.5 inches per second. I can see that this might be too slow for some applications...

Are you saying you need 100k steps per second, or 100kHz resolution in the step placement?

This little PIC board is targetted for getting the cost out of the control system for hobbiest or high volume consumer applications. I think the concept is extensible, but it might require replacing the PIC with an FPGA to get to 100kHz step rate.

I have some extra proto boards and could send you one with some schematics and code if you think you'd like to play with it.

You can see in the picture that I'm just wire-wrapping the output of my generic protoboard to a parallel port breakout board. You can also see that the board pretty much has nothing on it but the central 40-pin, a crystal, 3 LEDs and an FTDI-RS232 converter chip. The board gets power through the USB input.

Let me know if you want to look at the PIC code. Maybe you can find a way to speed it up.

kind regards,
Rick Walker


10-01-2013, 10:47 PM
>> The interesting thing is not the PIC code, but the overall architecture of this approach.

Agreed, something with horse power but not real time to do the velocity planning, and something that is real time running a simple interpreter to drive the stepper drives

I like the unix / linux plumbing (of commands) to share the work, each part does one thing and passes it to the next part

10-02-2013, 05:52 PM
Hi Andrew,

Your comment about step rates have got me looking at another implementation. If I use the FT245R USB-Fifo chip, then I can support 1Mbyte/sec transfers. Instead of sending a compressed code, the host computer can send the raw step bytes. With some glue logic I can probably easily get 100k steps/second.

Back to the drawing board for rev 2.

At least the existing tool chain will be usable with almost no modification...

RIck Walker

10-03-2013, 02:02 AM
Hi Rick
Sorry for not being clear in what I would like....I would love to get around the 100K steps per second.
Sounds great to me. I would love to have a play with your system - I would be more than willing to buy a board off you if you still have one spare.

Best regards

10-03-2013, 03:44 AM
Hi Andrew,

Sorry for not being clear in what I would like....I would love to get around the 100K steps per second.

I think I understood you just fine. When I mention 1 megabyte per second, I'm trying to make a system that is capable of 100k actual steps per second. Because the update time period is fixed, it means that I always round a step to the nearest time tick. This means that if I do 100k in a 1M channel, I have to output something like (PULSE, DELAY(9), PULSE, DELAY(9) ...). If your speed is actually at 95k instead of 100k, then that means that I have to make every few DELAY(9) into DELAY(10) to get the frequency right. Therefore each pulse can have about 11% peak jitter.

In the current system, I knew the pulse rate was low, so I let the pulses get up to 1 in 4 or something like (PULSE, DELAY3...). That means my current system has a 25% jitter. I experimentally determined that this was acceptable on my steppers, still making nice pure sounds to the ear and stepping smoothly. This was acceptable because it was allowing me to do useful work with just a PIC for the converter.

If I'm going to put in engineering time to build a more expensive and complex system to hit 100k, then I want to overdesign it (or get back the jitter that I gave away to get the PIC working), and make it run at something like 10x oversampling.

If you are willing and able to evaluate (and possibly modify), or give feedback or improvement suggestions, I am happy to send you anything you need to get you going. I have a couple blank PCBs. Can you do SMT soldering? I can send you PIC code in CCSC and gcc C code for a generic linux platform. I think that should get you going at the bare metal level. If you don't have access to a compiler, then I could build a board for you and program it. However, if you find anything that needs to be tweaked, you'll have to send it back to me. This model might work once a few people have worked with the code and it has been appropriately "genericized".

Then there's the rest of the ecosystem. If you already have lots of tools to visualize X,Y,Z data files, then you are set. Otherwise, if you need an ASCII plotter program to visualize your X,Y,Z files, I can send you a link to what I use. It's a public domain program that slurps up ascii files, one x,y pair to a line and then autoscales and plots them on a linux X window. It will also output postscript and PNG files of the resulting plot. With that, I write trivial little awk scripts to plot projections of X,Y,Z data as 3d wireline views. You could also use gnuplot too. I've been generating my simple toolpaths with a combination of the piglet drawing editor, graph paper, awk, and pdplot for toolpath visualization. It's essentially an old-school set of unix tools for pretty generally prototyping any kind of data filtering imaginable. Generally, once you've played around with enough little awk, perl, or unix scripts to get a functional tool chain working, you might be tempted to identify any limiting sections of the chain and re-implement them directly in C. Linux has lots of profiling tools to identify who in the pipe is using the most CPU. I've already started this process by identifying the velocity profiler and implementing this as a fairly efficient C block. It now runs fast enough on my laptop that I can feed my CNC3040 at 5k actual steps per second on each of 4 axes in real-time with lots of reserve left over. I'm almost certain I couldn't do that if I wrote the tool in awk. However, if I did hack up a different profiler in awk, I still could still use it because the architecture lets me write an intermediate file. In fact, I could run it on my limited cell phone and it could take a week to generate an optimum toolpath. No problem. RAM/ROM/Disk is cheap.

Sorry for not being clear in what I would like....I would love to get around the 100K steps per second.

But, I should make myself clear too. My current PIC only runs the output interrupt at 19.5kHz. This is enough for smooth coordinated stepping on my CNC3040 at a maximum of 5k actual steps per second on any individual axis. If you need 100k actual steps per second (which on my platform would be a tool speed of 100k/(10k/in) = 10 inches per second, or 600 inches per minute), then we will have to figure out a different hardware platform.

I wonder if there is any CNC hobbiest or professional on this board that had FPGA expertise that would be interested in helping make a cheap backend for an FTDI-245 USB-FIFO chip? My understanding is that at least some of these FIFOs won't properly make a smooth output update rate on the output port. To do that, you need to obey the FIFO discipline and unpack the FTDI promptly, re-buffer it in some circuitry (an FPGA with internal memory), and then spool it out at a even rate using flow control to tell the computer when the internal fifo gets full and also when it needs feeding.

So in summary, you are welcome to have a part and documentation if you are interested in it at its present limit of 5k steps/second and if you have the facilities to actual make use of the hardware and software.

In particular, you can see from my picture below that I wire-wrapped my board to a parallel port header to adapt the PIC I/0 to my CNC3040. You'd need to do something similar just to get the boards working...

Did I scare you off?

kind regards,
Rick Walker

10-03-2013, 06:06 AM
Hi Rick
Clear as mud! (only joking). I will send you a PM.