Machines in the real world vary greatly. They use different controllers, have different capabilities, and are customized for different uses. One of the most powerful features of HeeksCNC is the way in which the post-processor can be extended and customized to produce exactly the g-code your machine needs to do the job you want.
Before we can customize a post-processor, it's helpful to know a bit about the different parts of the system and the different stages of the post-processing action:
Parts of the System:
I guess EVERYTHING here is HeeksCAD/HeeksCNC but I'm specifically referring to the user interface. Graphical, compiled, and written in C++, the UI both allows the user to configure things and also controls all the subsequent steps. It's the boss of everything that follows.
The 'helper' libraries
These guys do the heavy lifting. There are a couple of them and each has two parts. One part is written in C++ and compiled for speed. It does the math-intensive work. The other is written in python and provides the interface. I'll refer to the second one as the '_funcs' library. It's name follows it's C++ partner module. For example, the area library does pocketing. area_funcs.py provides interface functions for calling the area module.
The Post-processor Python files
The post-processor does two big jobs.
1) It takes the tool movements that the helper libraries generate and converts them to machine specific g-code.
2) It Parses it's own g-code to generate a 'backplot' that can be displayed heekscad/heekscnc. The backplot is the colored lines showing where the tool will move. It's also the color-coded g-code in the 'output' window.
The post processor is made up of a several different python files that define the objects. The files are all in the heekscnc/nc directory and have names that indicate their function like emc2b.py and emc2b_read.py or mach3.py and mach3_read.py. The first writes g-code and the _read.py file does backplotting. These files always go together in pairs and inherit their functionality from their more generic ancestors iso.py and nc.py.
A lot happens when you click the post-process button but it breaks down into three big stages:
Stage 1: script generation:
In this step, the list of operations in the Object tree, along with their associated geometry (solids and sketches) is converted into a python file (post.py). When this step is finished, the python file will be displayed in the 'Program window' of HeeksCNC. This step can be performed alone by clicking the 'Make Python Script' menu or button.
Stage 2: Script execution to make g-code:
The next step is to run post.py. If post.py runs correctly, it will produce g-code in the .tap file. If you haven't saved your .heeks file, the .tap will be called untitled.tap and be in your /tmp directory. If you've saved your .heeks file, you should find it in the same directory with a name that follows (eg 'myprojectname.tap'). This step can be done in isolation as well by clicking the 'run python script' menu or button. One nifty feature is that you can edit the python script manually and run it to make small changes to how it works.
Stage 3: Read G-code to backplot:
Backplotting takes the generated g-code and reads it back in to HeeksCNC to create a visual representation of the tool movement. This is extremely useful to check that the tool is doing what you expect. Under the hood, HeeksCNC backplotting is just a little more complicated. It reads the .tap file, parses it and creates an XML representation of it. It then reads the XML file in to produce graphical output. The intermediate step is necessary to properly assign colors an other attributes to the visual elements.
A step-by-step of what happens when you hit the G0 button:
- HeeksCNC (objects defined in PythonStuff.h) begins to make post.py. It writes some preliminary lines and comments and imports various objects it will need.
- HeeksCNC looks at which postprocessor you have selected in 'machine' field of Program Properties. It writes an import line for that postprocessor into post.py (something like 'import nc.emc2b')
- It writes a few more lines that mostly correspond to settings in HeeksCNC and the tools table.
- Next, it begins to iterate through the operations in the order they appear in the Objects tree. It builds up a set of python commands that will call on the helper module associated with the operation. These commands pass coordinates of geometry and tool properties to the relevent helper by invoking functions in the _funcs.py file. (area_funcs, ocl_funcs, actp_funcs).
- When it has finished the list, HeeksCNC writes the end of program python commands into post.py.
- At this point, we've finished stage one. HeeksCNC now turns around and runs the post.py program that it just wrote:
- post.py first calls program_begin in the postprocessor. This opens the .tap file for writing and writes the preliminary program_begin g-code.
- post.py execution calls the functions in _funcs.py. Along with the geometry and tool data, it also passes the function a reference to your specific postprocessor.
- The library_funcs calls the library module (remember him?, he's the compiled version that does the real work).
- The library module does its magic and gives back tool movement data but the data is too generic (arc_ccw, feed, rapid, etc) and has to tailored for each machine.
- So the library_funcs takes each movement and passes it to the postprocessor.
- The post processor is mostly a big collection of 'If' statements. It parses the tool movement command and determines the corresponding G-code which it writes into the .tap file.
- After all the calls to _funcs have been turned into g-codes, the postprocessor writes program_end g-code to .tap file and closes it. Now we're done with stage 2. You could open the .tap file in your machine controller and run it to produce a part. Well, you could if you were sure that it's correct. But since you can't see it, we better backplot it first.
- Heekscnc starts backplotting as soon as the .tap file is closed. It runs postprocessor_read.py and passes it the name of the .tap file.
- postprocessor_read.py opens the file.
- For each line in .tap file, postprocessor_read.py breaks it into 'words' and evaluates each word.
- It runs through another big collection of 'If' statements and when it finds one of the words, it assigns various attributes to the word. The attributes are kind of like 'this word is a comment' or 'this word is a rapid movement', 'This number indicates a tool change', etc.
- The whole mess of data and attributes is written into a file called backplot.xml. The file is actually written by another helper, hxml_writer.py.
- If everthing goes well, HeeksCNC can now read in backplot.xml and render a beautiful backplot. You'll notice that lines and words are color coded. The corresponding colors can be changed in the machining options->nc options->text colors section of the Options panel.
How do I write or modify a post-processor?
It's just about as easy to write a new one as it is to edit one, so let's just do that.
First, start with a post that is as close as possible to what you need.
Go to the heekscnc/nc directory and copy the files. For my example, I'll base my new post off the emc simplified (emc2b). So make a copy of emc2b.py and emc2b_read.py. The first part can be whatever you want, but the _read must be the same. So now I have emcSlip.py and emcSlip_read.py. Edit the machines.txt file and make a new entry. Mine is 'emcSlip An Example Postprocessor 0'. 'An Example Postprocessor' is what will appear in HeeksCNC. I now have a custom post-processor that does exactly what emc2b did. Time to tweak.
To change how your postprocessor behaves you'll be editing these files, particularly the non-backplot file (emcSlip.py, in my example). This file inherits from two other, very important files. nc.py is the base for nc machines. Think of it as defining all the things a machine can do. Feed, mist, drill, rapid, use metric or imperial, etc, etc etc. Iso.py is the base class of codes. The unique combination of machine characteristics and the codes to drive them make up a post processor. So your postprocessor inherits from both of those files.
If, for example, you want your post to generate something different at the beginning of the .tap file instead of the stock comments, you could change the block of code that begins: 'def program_begin(self, id, comment):' Don't change that line or the last in the section, but what's in between is fair-game.
If a function you need doesn't appear in your postprocessor but does appear in either nc.py or iso.py, you can copy the function definition into your post and change it to override the default behavior.
Most simple changes will work just fine like this and need no further changes. Occasionally, a change may break the backplot, because heekscnc doesn't know how to interpret the new g-code your postprocessor is producing. If that happens, you will have to edit the _read.py file. Opening it, you'll probably see that it's mostly empty. This file inherits from iso_read.py. Open that and you'll see that the Parser class has lots of interesting code for backplotting. Copy everything starting with 'self.pattern_main = re.compile' on and paste it at the end of your _read.py file. Then edit it to suit your needs.
Of course, there are plenty of things that can go wrong. Fortunately, you have an entire directory full of examples to study. If you can't figure something out, there are folks on #cam and #heekscad IRC channels willing to help too.