freecad-cam/Mod/CAM/docs/post.md
2026-02-01 19:47:58 +01:00

91 lines
4.8 KiB
Markdown

# FreeCAD CAM Post Processors
## How it Works
FreeCAD CAM uses **Python scripts** to generate G-code. When you post-process a job, FreeCAD:
1. Locates the selected post-processor script (e.g., `heidenhain_1_post.py`).
2. Passes the list of Operations (the path objects) to the script's `export` function.
3. 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:
```python
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 `CPS` files, 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)` or `onRapid(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:
1. Iterate through this list.
2. Extract the `Path` object from each operation.
3. Iterate through the `Commands` inside that path.
4. 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:
```bat
"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 `export` function 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.