4.8 KiB
FreeCAD CAM Post Processors
How it Works
FreeCAD CAM uses Python scripts to generate G-code. When you post-process a job, FreeCAD:
- Locates the selected post-processor script (e.g.,
heidenhain_1_post.py). - Passes the list of Operations (the path objects) to the script's
exportfunction. - The script iterates through the operations, reads the underlying commands (G1, G2, etc.), and formats them into the specific string dialect required by the machine.
The Files
Post processors are standard Python (.py) files located in Mod/CAM/Path/Post/scripts/ (or your user macro directory).
Key Functions
A post-processor must implement at least:
def export(objectslist, filename, argstring):
# objectslist: List of Path objects involved in the job
# filename: output file path (or "-" for memory)
# argstring: arguments passed from the job properties
# Logic to iterate objects and generate G-code string
# ...
return gcode_string
Porting from Fusion 360
You cannot directly use Fusion 360 post processors (.cps files) in FreeCAD.
The Difference
- Fusion 360 / Autodesk HSM: Uses
CPSfiles, which are JavaScript based. They rely on an event-driven system (e.g.,onOpen(),onLinear(),onRapid(),onCycle()). The engine calls these functions as it processes the toolpath. - FreeCAD: Uses Python. It gives you the entire list of path commands upfront. You iterate through them and decide how to translate each command.
Porting Strategy: The "Manual Transpiler" Approach
To "port" a Fusion 360 post to FreeCAD, you are essentially re-writing the logic from JavaScript to Python, but more importantly, you are adapting to a different data flow.
1. Data Flow Difference: Event-Driven vs. Object Iteration
- Fusion 360 (Event-Driven): The CAM engine "drives" the post. It calls
onLinear(x, y, z)oronRapid(x, y, z)for every single move. You just write the handler. - FreeCAD (Object Iteration): You receive a list of Feature Objects (e.g.,
[OpDrill, OpPocket, OpContour]). You must:- Iterate through this list.
- Extract the
Pathobject from each operation. - Iterate through the
Commandsinside that path. - Switch on the command name (
G0,G1,G2,G38.2).
2. The "Flattening" Problem (Tool Changes)
In Fusion, tool changes happens via onSection triggers. In FreeCAD, the input list might just contain operations. You need to explicitly detect when the tool changes between operations and insert your own "Tool Change" logic.
Best Practice: Implement a buildPostList(objects) function (local to your script) that flattens the hierarchy:
- Input:
[OpA (Tool 1), OpB (Tool 1), OpC (Tool 2)] - Output:
[ToolController(1), OpA, OpB, ToolController(2), OpC]
Note: Do not try to import buildPostList from Path.Post.Utils as it is internal APIs. Implement it locally.
3. Logic Mapping Table
| Logic | Fusion 360 (.cps) | FreeCAD (.py) |
|---|---|---|
| Header | onOpen() |
Function called at start of export. Manually checks valid Stock object. |
| Tool Change | onSection() (new tool detected) |
Logic inside your main loop needed to compare obj.ToolController vs current_tool. |
| Rapid Move | onRapid(_x, _y, _z) |
if cmd.Name == "G0": ... |
| Linear Move | onLinear(_x, _y, _z) |
if cmd.Name == "G1": ... |
| Arcs | onCircular(...) |
if cmd.Name in ["G2", "G3"]: ... |
| Probing | onCyclePoint(...) (probe) |
if cmd.Name == "G38.2": ... (FreeCAD uses G38.2 internally for probing) |
| Footer | onClose() |
Function called after loop. |
4. Probing Example
FreeCAD usually represents probing moves as G38.2 (Probe toward workpiece). A ported post-processor must intercept this G-code and generate the machine-specific cycle.
Example (Heidenhain):
- FreeCAD:
G38.2 Z-10 F100 - Output:
TCH PROBE 427 MEASURE COORDINATE Q263=+0.000 ... ...
Debugging & Validation
Validate Syntax
Since post-processors are loaded dynamically, syntax errors might cause silent failures or generic "Failed to load" errors. Use the bundled Python executable to validate your script syntax:
"C:\Program Files\FreeCAD 1.0\bin\python.exe" -m py_compile your_post.py
Common Gotchas
- Imports: Do not assume standard FreeCAD internal modules (like
Path.Post.Utils) expose all their helper functions. Check the source or implement helpers locally. - Output Policy: The
exportfunction can return a string. If the filename argument is"-", return the string directly (used for displaying in the editor window). If it's a path, write to the file.