# profiler.py — Changes (part 2: since the previous post) This document covers changes made **since** the previous CHANGES.txt/forum post. It does not repeat anything already covered there (D/I swap, unsafe G71->G70 transition, arc bulge extent, "Finish only" mode, safe start-of- program approach, symmetric preview, language switcher, DXF fixes). See the previous post/attachment for those. All of the below was developed interactively with Claude (AI) and tested on real hardware (LinuxCNC 2.9.8, Mesa 7I96S, Debian 13). --- ## 1. More G-code correctness / crash fixes ### 1.1 G72's D/I/R were being scaled for G7 the same way as G71's — wrongly **Background:** G71 removes material in layers stepped along **X** (radial), so its `D`/`I`/`R` words are X-quantities and correctly need the G7 (diameter) <-> G8 (radius) conversion that was added for G71 in the previous round of fixes. **Bug:** G72 is the mirror-image cycle — it steps/layers along **Z** (axial) while facing across X on each pass. Its `D`/`I`/`R` are therefore **Z-quantities**, and Z never has a "diameter" (only X does). The code was reusing the exact same G71 conversion helper for G72, silently halving values that should never have been touched. **Fix:** New `ProfileGenerator._g72_di_values()` / `_g72_retract_value()`, which return `doc`/`stock_allow`/`retract` **unconverted**. `_emit_g72`, `wrapper_rough_subprogram_gcode`'s G72 branch, and `_g70_lines` (for the G70 that follows a G72 cycle) now pick the G71 or G72 helper based on `params.cycle`, instead of always using the G71 one. ### 1.2 Retract (R) in G71 was missing the same G7 scaling fix D/I already got **Bug:** The previous round of fixes added G7/G8 conversion for G71's `D` and `I`, but missed the `R` (retract-between-passes) word — it was still emitted unconverted. In G7 (diameter) mode, entering "1" for Retract actually produced 0.5mm of real movement (visible on the DRO as double the entered value, since the DRO shows diameter). **Fix:** New `_g71_retract_value()`, applying the same `/2` conversion (G7) that `_g71_di_values()` already does for D/I. Used everywhere R is emitted for G71 (`_emit_g71`, `wrapper_rough_subprogram_gcode`'s G71 branch). ### 1.3 Diagonal rapid moves between separate G70 calls (multi-pass / spring passes) **Background:** Supporting multiple finishing passes and "spring passes" (see §2 below) as **separate, individual G70 calls** (rather than one G70 with `P>1`) turned out to be necessary to avoid a TNRC crash (§2.1). But this exposed a different problem: per the G70 spec, its X/Z position "defaults to the initial position" — which for the *first* G70 call is the safe position the wrapper explicitly moved to beforehand, but for the *second, third, ...* separate call is simply **wherever the previous call left the tool** (the end of the contour). With no explicit repositioning, LinuxCNC rapids **straight (diagonally)** from the end of one pass to the start of the next. **Fix:** The same explicit "L-shaped" safe reposition (retract X -> move Z -> approach X) already used between G71 and the first G70 is now inserted between **every** pair of separately-invoked G70 calls, whether that's multiple finishing passes, the transition into spring passes, or both. `_g70_lines()` now takes `pts` so it can compute this. ### 1.4 A profile point sitting exactly on the centerline (X=0) could hang LinuxCNC **Bug:** A profile point at X=0 (e.g. a pointed/domed tip touching the rotation axis) could hang LinuxCNC before any motion even starts, separately from (and in addition to) the Start-X-vs-doc crash already guarded against. Confirmed on hardware: not related to Start X or Clear Z (both were tried as workarounds and didn't help) -- the issue is the point itself. **Fix:** `_validate_start_x_axis_safety` now also scans every point in a G71+OD profile and raises a clear `ValueError` ("touches the axis, replace X=0.000 with a small positive value like 0.1-0.2") if any point sits at X<=0, instead of silently generating G-code that hangs the controller. ### 1.5 M5 before later tool changes Minor: `_check_m5_before_later_tool_changes` — validates that M5 (spindle stop) appears before tool changes after the first one, replacing an earlier static regex check with a proper stateful scan. --- ## 2. Tool nose radius compensation (G41/G42) support ### 2.1 Compensation dropdown + the multi-pass crash it initially caused New "Tool comp" dropdown: **No / G42 / G41** (previously this didn't exist at all). When active, the finishing pass(es) are wrapped in `G41`/`G42 ... G40` around the G70 call(s) (`_tnrc_wrap`). **Found on hardware:** `G70` with `P>1` (multiple passes in one call) combined with active compensation reliably produced `"Straight traverse in concave corner cannot be reached by the tool without gouging"` -- even on corners with plenty of geometric room for the tool's nose radius (confirmed by computing the actual corner angle: ~128 degrees, nowhere near a degenerate/needle angle). This turned out to be a limitation in LinuxCNC's own compensation engine specifically for **arc-to-line concave corners**, not a real lack of clearance. **First attempted fix:** replaced the single `G70 ... P>1` call with several separate single-pass `G70 ... E` calls (D is irrelevant for a single pass per LinuxCNC's own `distance = (pass-1)*(D-E)/P + E` formula). **Confirmed on hardware this does NOT dodge the failure either** -- offsetting the *same* contour, however it's expressed, doesn't change the corner's tangent-angle geometry, which is what the compensation engine trips on. **Current approach:** `_shift_points_x` / `build_shifted_finish_contours` -- generates genuinely separate, offset **contour subprograms** (one per pass, each with points shifted by that pass's remaining stock) and calls G70 once per contour. This is a bigger architectural change than the E-based workaround; whether it fully avoids the concave-corner failure in all cases is still being verified on hardware, and the E-based approach remains as a fallback code path if a caller doesn't supply pre-built shifted contours. ### 2.2 Finish passes re-enabled under compensation Previously, enabling TNRC force-limited "Finish passes" to 1 in the UI as a blunt guard against §2.1's crash. Now that multi-pass finishing under compensation is handled safely (via separate G70 calls + explicit repositioning, §1.3), that restriction was removed -- the dropdown works normally regardless of Tool comp state. --- ## 3. Finish allowance entered per-pass, with live total **Before:** you entered the **total** finish allowance (D) directly, and (in an earlier iteration) a small info label showed how it divided across the selected pass count. **Now:** the field ("Фініш/прохід" / "Finish/pass") is the **per-pass** depth -- e.g. enter 0.25mm, select 2 passes, and the actual G71/G70 `D` is computed as `0.25 * 2 = 0.5` automatically. A "Remaining (D)" field next to "Finish passes" shows the live computed total (`2*0.25=0.5`). Old saved sessions/projects that used the previous "total D" field are migrated automatically on load (divides the old total by the saved pass count) so they still produce the same G-code. ## 4. Spring passes (separate stage) New "Spring passes" dropdown: **No / 1-5**, independent of "Finish passes". When set, an **additional**, separate `G70 ... D0.000 E0.000 P` call is emitted after the normal finishing pass(es) -- since D=E=0, LinuxCNC's own distance formula gives 0 for every one of these passes, so each repeats the identical final cut with nothing left to remove. Useful for boring bars or other tools prone to deflecting under load, letting them "spring back" over a few repeated light passes. Safe under TNRC even with P>1, since (unlike §2.1's case) every pass targets the identical point -- no varying intermediate offset for the compensation engine to trip over. --- ## 5. ΔZ and arc-diameter (⌀X) input modes * **ΔZ**: a checkbox next to the Z field switches it to entering the distance from the previous point (e.g. straight off calipers) instead of an absolute Z coordinate; the app computes the absolute value. Works for both Add and Update. The (currently inactive) field always shows a live, correctly-computed value regardless of which one you're typing into. * **⌀X** (next to R / arc radius): lets you enter the *desired real diameter at the arc's peak or trough* instead of the radius itself, and the app solves for R numerically (bisection on the sagitta, since the relationship isn't closed-form for the general case). Recomputes automatically if the segment's start/end points change later. New `_arc_bulge_point` / `_arc_radius_for_bulge_x` helpers do the underlying geometry, shared between this feature and the gray "bulge point" preview highlight. --- ## 6. UI: dropdowns, workflow, and preview * **Coolant / OD-ID / Cycle / X programming (G7/G8) / Tool comp / Finish only** are now dropdowns rather than free-text fields or checkboxes, reducing typos and making valid values explicit. * **Generate-then-save workflow**: Save/Send buttons are disabled (and the output text greyed) until "Generate G-code" is clicked; any further edit re-disables them. Prevents accidentally sending stale G-code that doesn't match the current on-screen parameters. * **Half / Mirror preview**: shows only one half of the profile instead of the mirrored top+bottom pair; "Mirror" then picks which half. Found and fixed a real bug in the process -- when both were active, arc segments came out geometrically wrong, because the coordinates were being mirrored in X but the arc's rotation direction (CW/CCW) wasn't being mirrored along with them, breaking the center-point math for every arc in the profile. * **Fill rendering fixes**: for ID (boring) operations, the fill now paints the material *outside* the profile instead of inside the bore (previously it painted the hollow bore as if it were solid). Also, any stock length the profile doesn't explicitly reach (front or back) is now filled too -- it's still solid, unmachined material, not open air, and was rendering as plain background before. * **All Z offset / All X offset** buttons -- shift every point in the segment list by a prompted +/- amount in one action. * Assorted alignment/label fixes across the parameter panels so fields line up in a consistent two-column layout, plus hover tooltips on several fields whose full description no longer fits inline (Start X/Z, Finish only, spring passes, arc-diameter input). --- ## 7. Project import / export * **Full project files** (`.txt`, `[PARAMS]` + `[POINTS]` sections) -- save and restore every machine parameter, not just coordinates. * **Single "Import" button** auto-detects whether a file is a coordinate list or a full project (based on the `[PARAMS]` header) and dispatches accordingly, instead of needing separate import buttons. * Window title now shows the name of the last imported/exported file. * Backward-compatible migration on load for sessions/projects saved with older field names/formats (the old single-D allowance field, the old checkbox-based tool-comp/finish-only fields, older diameter-mode dropdown text). --- *As with the previous round, all of the above was tested against the specific hardware-reproduced scenarios that motivated each fix, plus manual verification of the generated G-code structure for each new code path.*