Results that change on upgrade
None of the following breaks a build. All of them change what a simulation produces, so a byte-for-byte comparison against 3.1.175 output will differ — usually because 3.1.175 was wrong.
Silent wrong geometry, now fixed. Each of these produced a plausible-looking simulation of the wrong thing.
- The kinematic pivot anchor. The pivot-transform chain entry was built as
K(0)·K(abc)⁻¹, folding the whole machine-zero forward kinematic — its linear part included — into the pre-pivot anchor. That linear part encodes each axis' motion sense and tool/workpiece-side ownership, so it mirrored the program components of every workpiece-side linear axis before the IK ran. On a table-side chain whose machine-zero linear part isdiag(1,1,-1), every program Z was mirrored and a near-180° swing amplified it into metres of machine-Z error, floating the toolpath above the workpiece. The anchor is now the translation alone, matching what HardNc has always kept. Machines whose linear axes all ride the tool side are unaffected. - G68 2D coordinate rotation was a silent no-op. TiltTransformUtil
judged the active mode from the current block but always took the matrix from the previous one, so
every G68 activation past the first block had its freshly authored rotation overwritten with an
identity that then propagated. G68 rotation did nothing at all while the block's term still read
G68, and the simulation machined the unrotated pattern. Re-running an existing G68 program now gives different — correct — geometry. - A blank line reset G90/G91. A piece with no parsing section — a blank line, a comment-only line,
%, an O-number — left the next block's single-step lookback empty, and it fell back to the G90 default. A program that was incremental throughout silently flipped to absolute mid-file. Such pieces now carry the positioning section forward like every other modal syntax. - A Siemens D offset with no
$TC_DProw resolved to zero length, in silence. A whole TRAORI program machined one tool length low. The read point now falls back to the generic tool-number-keyed height and emitsSiemensToolOffset--TcdpRowMissing. - G43.4 with an unresolvable H word activated RTCP with a zero-length tool. It now reports
Comp-ToolHeight--001as a warning and keeps processing the block. An omitted H is no longer a silent zero: it takes the equipped tool's own offset row first (HardNc parity), then a non-zero modal id, and only then warnsComp-ToolHeight--NoToolForOmittedH(plain G43) orComp-ToolHeight--NoToolForOmittedHRtcp(G43.4). A vacant table row warnsComp-ToolHeight--RowMissinginstead of compensating a zero length. G43.4survivedM02/M30and a rotary-onlyG53still coupled through RTCP. A sequence that ended one program withM02and started the next with a rotary rapid — without aG49— kept tool-centre-point control on, pinned the tip, and dragged machine XYZ through the stock. On SoftNc the program-end block is a reset edge: tool-length compensation (G43 / G44 / G43.4, SiemensTRAORI, HeidenhainM128), tilt (G68 / G68.2 / CYCLE800 /PLANE/ TRANS), G41/G42 and G81–G89 cancel on the next block, written as explicit cancel sections so modal carry cannot copy the previous state. TheM02block itself still runs under the modal state it executed with, so a retract on the same line asM30still carries tool length. A rotary-onlyG53under active RTCP now holds the linear axes at the previous machine position and stays McLinear, which is what G53 does on a control (no compensation). HardNc still carries G43.4 acrossM02— the two engines are deliberately divergent on that edge; 3.2's default is SoftNc. A tool change that leavesG43.4 Hmalive for a different tool warnsComp-ToolHeight--RtcpOutlivesToolChangeon the change block.- Fanuc
G54.1 Pn(also writtenG54 Pn) was not resolved. Additional work coordinate systems now resolve against the extended table; a selected row nobody has entered reportsCoord-WorkOffset--AdditionalZeroand runs on the machine origin.G59.1–G59.9have a provider on the ISO presets. See Work Coordinates. - Heidenhain DIN/ISO arc centres.
I/J/Kare absolute circle centres on Heidenhain — the ISO face of the klartextCCpole — not start-to-centre offsets. Reading them incrementally turned arcs into near-full phantom circles. Fixed in all three engines: the HardNc reader (IsIjkAbsolute), the SoftNc reader (IsIjkAbsolute) and the optimizer's write-back.G91is the exception: an incremental block switches the words back to start-to-centre offsets, so an arc programmed underG91is unaffected by this change. Also delivered on the 3.1.175.x service line. - Feed per tooth, MRR and cutting forces follow the equipped tool's tip, not the controller's F
word. The physics used to read the commanded CL feedrate. It now reads the step's real tip
feedrate (ActualTipFeedrate_mmds, client key
ActualTipFeedrate_mmdmin): the tip's displacement relative
to the workpiece over the step duration. On XYZ moves, CL files and RTCP with the equipped tool's own
offset the two agree (the recomputation moves forces by at most about 1e-4 relative, from the
TimeSpan-quantised step duration); they part under RTCP with a tool-length offset that does not describe the equipped tool, on rotary-axis-limited simultaneous five-axis blocks (the tip is slower than F, up to a few percent), and wherever the commanded value was stale. - A feed block that does not move lost its F word. A block that repeats the current position
(
X.. Y.. Z.. F1600.right after the same point atF800., a common CAM habit) returned on zero distance before emitting anything, so every following block showed and cut at the old feed. ItsActFeedratenow lands on a zero-length linear, arc or polar block alike. The same stale commanded value is one of the cases the tip-feedrate split above parts on. - A rotary-bearing act mixed tip travel with the commanded CL feed resolution. On a pure RTCP rapid swing the CL point stands still, the commanded feed is ~0, and dividing the equipped tool's tip sweep by that resolution saturated the step count (the play appeared to hang on one line). A rotary-bearing act now splits by posture change (each rotary-axis delta over the rotary resolution) and by spindle cycles when the spindle turns — never by tip travel over the CL-feed resolution. Step counts of existing five-axis projects therefore shift on non-RTCP rotary blocks; XYZ-only programs are unaffected.
- A
K0word on a HardNc G02/G03 saturated the turn count. Under the default G17 plane a written-but-zero plane-normal word divided the axial travel by zero, the additional-turn count saturated toint.MaxValue, and one arc block became a spiral act of roughly 302 simulated years — the play appeared to hang on a single NC line. The reading now falls back to the closed-circle rule for a zero pace, matching the guard the SoftNc side already had. - Indexed-rotary programs folded the pivot into plain moves. A block with no active G68.2 or G43.4 no longer folds the kinematic pivot transform into a plain XYZ move, which is what a real controller does with a table-side rotary program.
- The radius-compensation arc transient cache landed on the wrong block. Any non-motion line between the corner and the arc orphaned the cache, so the arc lost its leading linear bridge and began at the corner intersection instead of on the offset arc.
- Cutter radius compensation on G18 / G19 ran out of the plane. Both engines built the
perpendicular as
Z × axiswhatever plane was selected, so under G18 or G19 the whole offset went one radius along the plane normal (aG41region in the ZX plane was displaced in Y), every arc of the region reportedArc-EndpointOffRadius, and theRadiusComp--Interferencegate could not fire there. Both engines now take the perpendicular, the in-plane test for blocks without movement and the interference gate from the selected plane: the offset lies in the plane, left/right is judged looking down the plane's positive normal (the same convention that orients G02/G03), and the diagnostics behave as on G17. G17 programs are unaffected. - The G68.2 tool-axis IK fallback probed the mirrored tool axis. Both normal-only fallbacks in IsoG68p2TiltSyntax read the transposed third column instead of the third row. On the no-hint path this only skewed a warning gate, but the explicit A/B/C path seeds its hint blend from that solve, so a machine with fewer than three rotary axes composed a mirrored tilted plane.
- A Fanuc
WHILEforward jump bound to the wrongEND. Sequential loops idiomatically reuseDO 1, so a secondWHILE's falsy-condition exit bound to the first loop'sEND 1and redirected execution to a point before the secondWHILE— an unbounded loop the iteration watchdog cannot see, because it only ticks onENDreverse jumps. The jump now uses the anchored label scan the Siemens loop family already used. - Heidenhain G28 is MIRROR IMAGE, not a reference-point return. On the Heidenhain preset the
shared pipeline had been reading it as the Fanuc reference return, so a
G28 Xblock minted a phantom rapid to home while the mirror silently vanished. It is now simulated as a program-to-MC transform,ReferenceReturnSyntaxleaves the Heidenhain logic list, and klartextCYCL DEF 8records the same mirror statement so one program mirrors identically in either dialect. HardNc keeps the Fanuc reading, so the two engines are deliberately divergent on Heidenhain G28 files and any parity comparison must account for it. MathUtil.Convert_inchdmin_To_mmdsreturned mm/min, not mm/s. The body multiplied by 25.4 and never divided by 60, so a caller trusting the name got a 60× feedrate; the siblingConvert_mmdmin_To_mmdsdivides as its name demands. No shipped path called it — the CL/APT feedrate route converts inches-per-minute to mm/min itself — so this changes nothing inside the product, but a caller who had compensated for the old behaviour must remove that compensation.GetRByZ(List<PairZr>)never interpolated. The list overload looked up its ceiling node with the floor lookup, so floor equalled ceiling and the method degenerated into a step function. For a sharp cone whose inner-beam Z–R list has no node between apex and rim, that pinned the inner radius to 0 across the whole cone face and produced NaN flute vertices — the root cause of the transparent cone-tip flute that 3.1.180 addressed at the display layer. It affects every consumer of radius-by-Z interpolation, force geometry included.
Numerical results move even where nothing was renamed.
- Five-axis IK is roughly 1000× tighter. The rotary solver behind
XyzabcSolver now runs coarse→polish: the coarse stage keeps the
original dot residual so solve success and failure
semantics are unchanged, then a
[dot, cross, rr-per-axis]system polishes. The dot criterion is quadratically blind to angle error — an envelope of about 1.4e-3 rad, and the resulting tip error is that envelope times the tool length — so adding the cross term restores quadratic convergence and drops the envelope to about 1e-6 rad. Failed solves no longer pollute the implicit seed, and the measure-zero perfect-saddle case is escaped by a deterministic retry offset instead of by leftover seed pollution. - ActMcXyzLinearContour steps by euclidean tip travel instead of the
largest per-axis component, so
LinearResolution_mmnow caps actual tool-tip travel per step and a diagonal move produces up to √3× more steps at the same setting. - The SoftNc pipeline is the default engine.
- Executed
SyntaxPieces freeze to UTF-8 (below), so theirJsonObjectis a fresh read-only snapshot per call rather than a retained live graph. SyntaxPiece.SentenceIndexbecomes a session-global execution-order counter and is no longer contiguous per file.- Repeated NC diagnostics fold into per-run summaries at the run boundaries.
- HardNc tool changes fire on M06 / Heidenhain
TOOL CALLrather than on a changedTword — a bareTis magazine pre-selection, and a same-tool M06 still runs the changer cycle — and unsetHardNcEnvtooling defaults become the three-axis shape (XYZ = NaN, NaN, 0; ABC all NaN). The old defaults swung all three rotary axes home on every M06, which no post expects.