91 lines
4.8 KiB
Markdown
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.
|