Postprocessing - sliptonic/FreeCAD GitHub Wiki

🏠 Home | 📋 Current State | 📖 API Reference


How does post processing work...really.

What exactly is “post processing”?

Structure of a Gcode Program (FreeCAD’s opinionated view)

Machine and Postprocessor Configuration

Machine Configuration

User Preferences

Job Configuration

Custom Postprocessors

Options selected at postprocessing time.

Stages of Postprocessing

Stage 0: Configuration

Stage 1: Ordering

Stage 2: Command Expansion

Stage 3: Command Conversion

Stage 4: Filter and optimize

Stage 5: Write to disk

What happens when you push the button?

Post Processor Structure

Invoking Post Processing from a script

Relationship to CAM_Sanity

What exactly is “post processing”? {#what-exactly-is-“post-processing”?}

A CAM job is more than a container of operations and tools. It encodes the CAM programmer’s intention for the manufacturing of the part. A few of the things implied in the job are:

  • The stock size and material
  • The part orientation and placement relative to an origin point
  • The tools to be used and how we will refer to them.
  • The feed rate and spindle speed of those tools
  • The order of operations
  • Where the tool will move in space for each operation
  • Which coordinate systems on the machine (fixtures) will be used.
  • How the final output should be formatted

While this list is extensive, it is not complete. Many things can’t be known by the CAM system and must be determined later. Some of these are:

  • Exactly which machine to use
  • The length of the tool from the spindle nose
  • How the fixtures relate to one another and the machine’s coordinate system
  • The specific gcode dialect required by the machine
  • Where the tool is positioned at the beginning
  • How tool changes are executed

Post-processing is the act of converting the CAM Job(s) into gcode program(s) that can execute on a machine.

Structure of a Gcode Program (FreeCAD’s opinionated view) {#structure-of-a-gcode-program-(freecad’s-opinionated-view)}

Gcode is an old standard. The actual program can be structured many different ways. In FreeCAD conversation, we shall refer to different parts of a gcode program like this.

Our postprocessing system aims to reliably and predictably construct programs that follow this format.

  1. SAFETY BLOCK
  2. HEADER
    3) This is COMMENT ONLY.
    4) Includes information for the operator to understand context.
  3. PREAMBLE
    6) Active commands to establish a machine safe known condition.
    7) Applies across the entire gcode file
    8) With POSTAMBLE, brackets the body
  4. JOB(s)
    10) PREJOB block
    11) BODY SECTIONS
    1. TOOLCHANGE(s)
      1. PRE BLOCK
      2. Gcode
      3. POST blocks
    2. FIXTURE(S)
      1. PRE BLOCK
      2. Gcode
      3. POST blocks
    3. OPERATION(s)
      1. PRE BLOCK
      2. Gcode
      3. POST blocks
    4. ROTARY
      1. PRE BLOCK
      2. Gcode
      3. POST blocks
    5. POSTJOB block
  5. POSTAMBLE
  6. Gcode to safe the machine
  7. Gcode to exit program
  8. FOOTER
  9. Comment only

Machine and Postprocessor Configuration {#machine-and-postprocessor-configuration}

Post-processing is already complicated but it gets worse. There are many different types of machines and machine controllers on the market. Some have been in active use for decades and new ones are being built every day. Each machine, in production, may have features that necessitate unique gcode output. It is vital that the end user be able to customize how the final output is produced. This is a big challenge and requires us to strike a careful balance.

We need a system that is:

  • Simple enough for a novice user to customize for common changes
  • Powerful enough to handle complex tasks that occur in professional settings.
  • Flexible enough to handle virtually any kind of CNC machine or control
  • Fast, reliable, and predictable
  • Scriptable
  • Understandable enough for the general community to contribute
  • Maintainable and extensible by the development community

To accomplish this, we allow customization at several levels

  1. Machine configuration
  2. User preferences
  3. Job configuration
  4. Custom postprocessors
  5. Options selected at post processing time.

Machine Configuration {#machine-configuration}

Most users will interact with a small number of machines regularly. For hobbyists, this number is probably one. For small and medium sized shops, the number is still small, perhaps less than ten.
Machine configuration has implications beyond post-processing. Configuration details include:

  • settings that will apply to ALL jobs generated for the machine.
  • Selecting which postprocessing script is used to convert FreeCAD Path.Commands into formatted gcode.
  • Selecting how Path commands will be handled.
    • Arc splitting
    • Canned cycle expansion, etc.
  • Configuring how gcode will be output.
    • Line numbering
    • Precision
    • Etc

User Preferences {#user-preferences}

User preferences have limited impact on postprocessing

  • Default location to write output
  • Postprocessors available during machine configuration

Job Configuration {#job-configuration}

  • The main configuration point in the job is to select the target machine from the list of configured machines available.
  • Job configuration is streamlined with the use of job templates.

Custom Postprocessors {#custom-postprocessors}

We strive to make the base postprocessor system flexible and configurable to meet most needs.
Occasionally, a machine may have features that are not generally applicable. These are implemented in postprocessor classes that inherit from the base postprocessor and extend it.

Creation of a custom postprocessor should be rare.

Options selected at postprocessing time. {#options-selected-at-postprocessing-time.}

The UI should be flexible to allow the user to override key settings without redefining the machine or job. The options should apply only to the job(s) currently being postprocessed.

Stages of Postprocessing {#stages-of-postprocessing}

Postprocessing goes through clear stages.

  1. Stage 0 - Configuration
    • Create a configuration blob that takes into account
      1. Machine configuration
      2. User preferences
      3. Job settings
      4. Last minute options
    • Instantiate a postprocessor with the configuration.
  2. Stage 1 - Ordering
    • Generate the list of ‘postable’ (objects that produce gcode)
    • Evaluate selected fixtures (WCS)
    • Explode arrays
    • Sequence operations, toolchanges, fixture changes appropriately
  3. Stage 2 - Command Expansion
    • Header construction (phase 1)
    • Canned Cycle Expansion
      1. Cycle initiation G98/G99
      2. G80 cycle termination
    • Cycle translation
      1. expand drill cycles
    • Arc splitting
  4. Stage 3 - Command Conversion
    • Command suppression
    • Comment formatting
    • Unit conversion
    • Syntax
    • Precision
    • Block Delete
    • Modal axes and feed filtering
    • Insertion of output blocks (True G-Code)
      1. preamble/postamble
      2. pre/post job
      3. pre/post op
      4. pre/post fixture change
  5. Stage 4 - Gcode Optimization
    • Comment filtering
    • Deduplication
    • line numbering
  6. Stage 5 - Output Production
    • file name generation
    • writing to disk
    • Generation of related documents (sanity)

Stage 0: Configuration {#stage-0:-configuration}

Stage 0 builds a configuration data structure that can be passed through the postprocessing pipeline. This isolates the postprocessing system from the configuration, job, Machine, and other details that may change over time.

Stage 1: Ordering {#stage-1:-ordering}

Gather the list of 'postable objects' from the job and order them in the correct sequence.
A postable is any object that has a Path property. These are the objects that contribute gcode to the final output. They include operations, dressups, tool-controllers, customs, and other supplemental objects.

The specific order of the postables depends on choices made in the Job. If the user wishes to do repeated work in multiple fixtures, certain postables must be repeated for each fixture and additional commands added to change fixtures at the right time.

Also, If two operations use the same tool controller, duplicate tool change commands need not be output between them and can be suppressed.

The step is handled by an important piece of logic called _buildPostList() which is implemented in the base class of the postprocessor. (/Mod/CAM/Path/Post/Processor.py).

>>>postlist = self.post._buildPostList()

The postlist _buildPostList() method returns a list of tuples, each containing a section name and a list of operations. Here's the structure:
[
(section1_name, [operation1, operation2, ...]),
(section2_name, [operation1, operation2, ...]),
...
]

section_name: A string identifier for the section (e.g., a fixture name like "G54" or "G55" when ordered by fixture). Section_names are most important when splitting output into multiple files. The section names will be used in filename generation.

operations: A list of objects that contain Path Commands to be processed, which can include:

  • Fixture setup commands (from __fixtureSetup())
    • Tool controllers (from PathUtil.toolControllerForOp())
    • Path operations (from self._operations)

For example, when ordered by fixture, the output might look like:

[
("G54", [fixture_setup, tool_controller1, op1, op2, ...]),
("G55", [fixture_setup, tool_controller2, op3, ...]),
...
]

Stage 2: Command Expansion {#stage-2:-command-expansion}

After stage 1, the interim output effectively captures the full intent of the CAM programmer. The order of operations is completely expressed including duplicating operations, tool changes, etc.

However, two problems remain:
First, these are still FreeCAD Path Commands not gcode. Important context information may be encoded in command annotations. Modal commands like G98/G99 are not present.

Second, the Gcode implied by these commands may not be supported by the target machine.
For example, The selected machine cannot process gcode canned cycles like (G81, G73, G85). In many cases we are able to translate these high level objects into lower level gcode commands like G0 and G1.

Stage 2 focuses on expanding the set of commands into a structure that more closely approximates gcode and is complete enough for final translation.

Stage 2 is also the last point where we have access to the full context where the postables objects. Command expansion can use this opportunity to gather and consolidate data for later output. Example, Constructing an object to summarize and output header comments.

Stage 3: Command Conversion {#stage-3:-command-conversion}

Stage 3 is the point where FreeCAD’s internal Path Commands are converted to gcode.
This involves

  • Unit conversion with precision
  • Line formatting
  • Comment formatting
  • Command suppression
  • Comment suppression
  • Syntax conversion
  • Gcode word filtering (suppress redundant axis and feed words)
  • Insertion of machine specific blocks

Example: CAM has included commands to change tools. The actual CNC machine may require specific gcode to retract the spindle, and move to a safe location before the tool can be changed.

Example: Changing fixtures safely may require moving the cutting tool to a safe location so the tool doesn’t collide with the part during the fixture change.

Stage 4: Filter and optimize {#stage-4:-filter-and-optimize}

At this point, the command set is functionally complete from the perspective of the CNC machine but may not be optimum. Each operation and command has been processed but the entire result has not been considered as a whole. This means that moves between operations may be inefficient.

Example: One operation moves up to a Clearance height and the next operation moves back down to the previous height.

Example: Multiple lateral moves may be more efficiently collapsed into a single move.

After redundant and inefficient moves have been optimized, the final output can have line numbers applied.

Stage 5: Write to disk {#stage-5:-write-to-disk}

At this point, the CAM job has been fully converted into gcode parts. The only thing remaining is to write the output to persistent storage. Surprisingly, this is something that the postprocessors do not do at all. That task is left to the calling routine.

Helper logic exists to name files, avoid name collisions, avoid inadvertently overwriting files, and generating names that are safe for the platform.

It is also at this stage where an editor may present the final output to the user to inspect/change before writing to disk.

What happens when you push the button? {#what-happens-when-you-push-the-button?}

This section needs to be rewritten. It is included here only for reference and is being deprecated by the revised postprocessing flow

This describes the process as it works from the GUI. However, the post processing system is designed to be modular and usable both from the GUI and from macros or external scripts.

The process starts when the user clicks the 'Post-Process' button.

The button is only enabled if the user has selected a Job or a document object that is part of a Job.

Pressing the button activates the command CAM_Post. The command is defined in Mod/CAM/Path/Post/Command.py:CommandPathPost

>>>Gui.runCommand('CAM_Post',0)
(running this command without selecting a job or document object inside a job will do nothing)

Post processors are implemented as python modules. The command first resolves which python module to use. The logic is in the method _resolve_post_processor_name().

The user may have:

  • Set a global defaults
  • Defined a default in the current document
  • Have no preferred post at all

If no preferred post is found, the user is prompted to select one from a list of available postprocessors. Unless the user cancels the dialog, this method will always return a valid postprocessor name.

Next the command uses the PostProcessorFactory to instantiate a postprocessor object from the identified module. The factory requires a postprocessor name and a job object. The factory is defined in
Mod/CAM/Path/Post/Processor:PostProcessorFactory.

The same thing can be done direction in python
>>>post = PostProcessorFactory.get_post_processor(<<job_REF>>, "generic")

With a valid postprocessor initialized, the only thing remaining is to call its export() method. This will be done by the CAM_Post command.
The corresponding python:
>>>result = post.export()

The returned result is a list of sections. Each section is intended to be a separate gcode file. The calling function, GUI command (or some external code) is responsible for writing the results to final output files. See the section below on writing output

Post Processor Structure {#post-processor-structure}

Postprocessors are derived from a base class defined in
/Mod/CAM/Path/Post/Processor.py.

Posts included with FreeCAD are in the directory /Mod/CAM/Path/Post/scripts/

Custom posts may exist in the user's macro directory or CAMAssets location and will be discoverable by the system.

Regardless of location, the post must have a filename that matches the format <name>_post.py

A valid post must implement at least the following methods:

method
export() The main function to generate gcode
tooltip() Returns a tooltip for the post when shown in the list of valid postprocessors
tooltipArgs() Returns the args that the post accepts to configure operation. The args can be configured in the global or job preferences.

The base class also implements

Method
_buildPostList() determines the specific objects and order to postprocess Returns a list of objects

An example postprocessor is included at
/Mod/CAM/Path/Post/scripts/generic_post.py

Old style postprocessors are adapted to the current framework with a WrapperPost defined in
/Mod/CAM/Path/Post/Processor.py:WrapperPost

Tests {#tests}

Tests are defined in
/Mod/CAM/Tests/TestPathPost.py

Tests can be run from the command line
./bin/FreeCADCmd -t TestCAMApp (optionally, include the specific test name)

Invoking Post Processing from a script {#invoking-post-processing-from-a-script}

The simplest example can be replicated in just five lines.

from Path.Post.Processor import PostProcessorFactory
doc = FreeCAD.open(FreeCAD.getHomePath() + "/Mod/CAM/Tests/boxtest.fcstd")
job = doc.getObject("Job")
post = PostProcessorFactory.get_post_processor(job, "linuxcnc")
sections = post.export()

Relationship to CAM_Sanity {#relationship-to-cam_sanity}

CAM_Sanity is a tool to provide useful information to the operator or CAM programmer about a Job. It’s output is an HTML report that can be shown in a browser. It shows useful information about setup, fixtures, runtime, and other items.

In order to generate the needed data, CAM_Sanity must postprocess the job. However, the user may not wish to write it to disk yet or overwrite an existing file already on the disk. For this reason, CAM_Sanity can invoke the postprocessing logic in the same way as the CAM_Post command but without writing to disk.

Features

Many features are supported natively now. A complete list of features and related tests is available

⚠️ **GitHub.com Fallback** ⚠️