Skip to content

Releases: CEAD-group/nc-gcode-interpreter

v0.2.7

Choose a tag to compare

@github-actions github-actions released this 08 Sep 14:49
v0.2.7

v0.2.6

Choose a tag to compare

@github-actions github-actions released this 09 Jul 15:11
v0.2.6

v0.2.5

Choose a tag to compare

@github-actions github-actions released this 08 Jul 15:36
v0.2.5

v0.2.4

Choose a tag to compare

@github-actions github-actions released this 08 Jul 13:07
v0.2.4

v0.2.3

Choose a tag to compare

@github-actions github-actions released this 07 Jul 22:06
v0.2.3 — NcError.kind discriminator + source location on validation e…

v0.2.2

Choose a tag to compare

@github-actions github-actions released this 07 Jul 21:40
v0.2.2 — batch-path variable events + string_table in state dict (#46)

v0.2.1

Choose a tag to compare

@github-actions github-actions released this 07 Jul 20:44
CHANGELOG: date the v0.2.1 section for release

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RX8t1oNZLCC9CL8SfHEyg3

v0.2.0

Choose a tag to compare

@github-actions github-actions released this 07 Jul 15:56

Sinumerik-flavored NC G-code interpreter, released to PyPI.

pip install nc-gcode-interpreter==0.2.0

Full changelog: https://github.com/CEAD-group/nc-gcode-interpreter/blob/main/CHANGELOG.md

Added

  • dwell output column: F/S on a G4 block is the dwell time (seconds /
    spindle revolutions), a per-block parameter - it now lands in its own
    never-forward-filled dwell column instead of polluting the modal F/S
    columns (previously G4 F0.01 set the feed to 0.01 mm/min for every
    following block until the next real F word)

  • Loud warnings for known-but-uninterpreted constructs (never silently
    butcher a statement): assignments to AR/AP/RP (opening-angle and
    polar arc forms) warn once per run that the motion will be wrong; G91
    warns once that incremental dimensioning is not applied; the flattener
    warns per word for CIP/CT/POLY/thread/involute pass-through

  • TURN output column (block address, never forward-filled): additional
    full helix turns on G2/G3 blocks; previously swallowed as a user variable

  • Curve flattening: flatten_tolerance on nc_to_dataframe / nc_to_rows /
    nc_to_batches (CLI: --flatten-tolerance) converts G2/G3 arcs (I/J/K and
    CR= forms, all planes, helical, full circles) and ASPLINE/BSPLINE/CSPLINE
    splines (PW weights, SD degree) into runs of G1 rows within a single
    max-deviation tolerance of the true curve; interpolation addresses are
    consumed, source line numbers and auxiliary cells preserved; generated
    samples carry a flattened = 1 marker column so the original programmed
    points remain distinguishable

  • Optional viz extra (threejs-viewer >= 0.0.41):
    nc_gcode_interpreter.viz.view_toolpath(df) shows a toolpath in
    threejs-viewer as an animated bead tube (feed-rate float64 time base,
    programmed vs flattened point coloring), and the nc-view console command
    interprets + flattens + animates an .mpf in one step, with a nozzle
    marker riding the path tip, camera follow/look-at tracking, and travel
    moves drawn natively as a thin line in lockstep with the bead

  • Program jumps and branches: GOTOF/GOTOB/GOTO/GOTOC/GOTOS and
    CASE ... OF ... DEFAULT, with per-scope label/block-number resolution,
    jumps out of IF bodies and loops, and alarm-14080 semantics for an
    unresolved target (GOTOC warns and continues) (#29)

  • Streaming API nc_to_rows(program): yields (line_no, row) lazily while
    the interpreter runs on a background thread — batch-identical typing and
    forward-fill, constant memory, early abort by dropping the iterator,
    errors raised at the offending row, final state on the exhausted
    iterator (#35)

  • nc_to_rows(..., include_variables=True) yields (line_no, row, variables) with per-block variable-assignment deltas, exposing
    variable-only blocks that the batch DataFrame prunes (#35)

  • Spline programming: PW/SD/PL block addresses become output columns
    (not forward-filled, no TRANS offset) instead of being silently
    swallowed (#18)

  • G2/G3 arc interpolation parameters I/J/K/CR become per-block output
    columns (not forward-filled, no TRANS offset) instead of being silently
    dropped — arcs previously came out as straight-line endpoints (#37)

  • nc_to_batches(program, batch_size=...): interpret a program into a
    stream of columnar polars DataFrames built on a worker thread and handed
    over via the Arrow C data interface — bounded memory for programs too
    large to fit in one DataFrame (#37)

  • Parsing: leading-underscore identifiers (_WITH_M0), assignment to
    $AC_* system variables ($AC_TIMER[1] = 0), and the NOT logical
    operator (#37)

  • DEF STRING[n] string-variable declarations and quoted-string
    assignments; strings stay out of the numeric pipeline (a string in an
    expression, or a type mismatch, is a hard error, never a silent 0.0).
    String processing (SPRINT/INDEX/<<) remains out of scope and
    fails loudly (#40)

  • Logic, comparison and bit operators in expressions (AND/OR/XOR,
    B_AND/B_OR/B_XOR, ==/<>/</>/<=/>=) at the manual's
    priorities, so conditions like IF (A == 1 AND B == 1) work and
    comparison results are assignable (R11 = R10 >= 100) (#41)

  • $AA_IW[<axis>] / $AA_IM[<axis>] read the interpreted actual work /
    machine position of an axis, so layer loops
    (REPEAT ... UNTIL $AA_IW[Z] > H) terminate; reading before the axis is
    positioned errors loudly and the variables are read-only (#42)

  • nc-view prints a corrected retry command on the classic new-machine
    failures (missing --axis-index-map, undefined machine-parameter
    variables) instead of a bare traceback

  • docs/sinumerik-execution-model.md: how a real control executes NC code
    versus this interpreter, and why (#30)

Changed

  • Rust-side polars is gone. The Table -> Python DataFrame handoff no longer
    builds a polars DataFrame in Rust (via pyo3-polars); it builds an Arrow
    record batch with the minimal arrow-array/arrow-schema/arrow-data
    crates and hands it to Python zero-copy through the Arrow PyCapsule
    interface (__arrow_c_array__), where pl.DataFrame(...) wraps it. The
    Python API is unchanged (still returns polars.DataFrame), needs no
    pyarrow, and performance is unchanged. This drops ~60 crates from the
    python-feature build (127 -> 64), cutting a clean release build ~4x
    (83s -> 21s), and bumps PyO3 0.28 -> 0.29 (resolving the RUSTSEC pyo3
    advisories).
  • Breaking: I/J/K/CR are now treated as arc interpolation-parameter
    block addresses (output columns), so they can no longer be used as user
    variable names: I=5 followed by X=I+1 was a variable read before and is
    now an undefined-variable error. Matches Sinumerik address semantics (#37)
  • nc_to_dataframe is now the concatenation of the internal batch stream
    rather than collecting every row up front: same output, but bounded
    intermediate memory and interpretation overlapped with DataFrame assembly
    (a 1.1 GB program went from ~209 s / 6 GB to ~33 s / 3.3 GB) (#37)
  • An executed M2/M17/M30 now ends the program immediately, even
    mid-file, instead of being ignored (#29)
  • Unknown G codes now error like Sinumerik alarm 12470 instead of silently
    parsing as a subprogram call (#31)
  • Unsupported or unmodeled statements (parameterized ROT/SCALE/MIRROR
    frames, and previously jumps/LOOP before #29 implemented them) raise a
    clear UnsupportedStatement error instead of corrupting output; a frame
    instruction following another statement in the same block errors (#20,
    #32)
  • Frame semantics per the manual: absolute frame instructions (TRANS,
    bare ROT/SCALE/MIRROR) substitute — deleting previously programmed
    offsets — rather than accumulate (#20, #26)
  • Values are f64 end-to-end to match the control's 64-bit REAL:
    coordinates are bit-exact for decimal literals, DIV truncates the real
    result (7 DIV 4.1 = 1), and ==/<>/<=/>= use the manual's 1e-12
    relative tolerance (#23)
  • The ~488-command G vocabulary and its 60 G-groups moved out of the PEG
    grammar into a Rust table generated from ggroups.json; the grammar
    recognizes lexical shape only (#32)
  • Rust-side polars removed: the core returns a plain typed table and the
    Python wrapper builds the DataFrame, so any Python polars version works;
    CSV and DataFrame output are unchanged (#27)
  • Dependency refresh: pest 2.8.6, pyo3 0.28, clap 4.6, polars 1.42.1 (#28)

Fixed

  • The NC language is case-insensitive (manual 3.3.2): lowercase axis
    words (g1 x0 y0) are axis moves rather than silently-dropped subprogram
    calls, G/M values are normalized to uppercase, and user-variable
    identifiers fold case (a program that declares lAYER_HEIGHT but assigns
    LAYER_HEIGHT is one variable, not two) (#43)
  • The IC-before-position warning now states what actually happens ("axis
    incremented with IC() before any absolute position was set; assuming it
    starts at 0") instead of the vague "behavior may be indeterminate"
  • Expression evaluation: correct operator precedence (2+3*4 is now 14,
    not 20), degree-based trig per the manual, corrected ATAN2 argument
    order, and DIV by zero errors instead of panicking (#19)
  • TRANS/ATRANS translation is applied per row at output time under the
    frame active at that block; fixes double-applied offsets on IC() moves
    and axis movement as a parsing side effect (#26)
  • Unclosed or crossed IF/WHILE/FOR/LOOP/REPEAT structures are
    reported at the (innermost) opener's own line instead of as a parse
    failure at end-of-file (#33)
  • Parse errors are phrased for humans (no grammar-internal rule names),
    mistyped axis words like Y2O warn, and unresolved jump targets get
    did-you-mean suggestions — direction-aware when the label exists but only
    in the other search direction (#31)

Performance

  • Stage-1 line triage: structure-free CAM programs run through a byte
    decoder for the >99.9% trivial lines, per-line parses for the rest —
    a 319k-line program drops from ~33 s to ~9 s in nc_to_dataframe
    (NC_STAGE1=0 disables) (#34)
  • Grammar restructuring: ~15% faster parsing, plus an ignored 1M-line
    benchmark harness (#30); an earlier redundant-lookahead removal cut parse
    time ~27% (#25)

v0.1.12

Choose a tag to compare

@github-actions github-actions released this 26 Jun 10:26
703cffe

v0.1.11

Choose a tag to compare

@github-actions github-actions released this 25 Jun 22:16
34392e7