Skip to content
Colin WolffSYS_DOMAIN: colinwolff.dev // NO_SOCIALS
SYS_STATUS: ONLINE

[SPEC-02 // CNC-019]

Closed-Loop Tabletop CNC Control Interface

G-code motion planner with optical encoder feedback, dynamic feed-rate correction and a deterministic step pipeline for desktop parametric machining.

[PROJECT]STATUS: WIPREV: 2026.10
// Status
WIP
// Reference
CNC-019
// Revision
2026.10
// Published
JUN 02, 2026
// Updated
OCT 08, 2026

Context

Most hobby CNC control software assumes open-loop steppers and generous tolerances. The goal here was a control interface for a desktop router that holds ±0.025 mm while cutting hardwood at 2.4 m/min — which requires knowing where the tool actually is, not where it was told to go.

Constraints

  • Step generation must be jitter-free. A missed step is a scrapped part; a late step is a visible gouge.
  • The planner runs on the same silicon as Wi-Fi, USB and the web UI. Network interrupts must never influence pulse timing.
  • Enclosure is passive-cooled and sealed against chips. No fan, no vents.
  • Operators are machinists, not engineers: the interface must expose feed override, tool number and resume, and nothing else during a cut.

Architecture

Three strictly separated layers:

  1. Parser — G-code is tokenised into a bounded op queue. Comments, modal state and units are resolved before queuing; nothing is interpreted during motion.
  2. Planner — look-ahead over 128 blocks produces a trapezoidal velocity profile per axis, clamped by junction deviation rather than naive corner rounding. Junction limits are conservative by design: it is cheaper to slow down than to lose steps.
  3. Step engine — a hardware timer ISR consumes pre-computed delay values from a ring buffer. It performs one comparison and one write per tick. It never calls into the planner, allocates, or logs.

Feedback closes the loop at the block level, not per step: encoder counts are compared against expected counts at each block boundary, and the residual is folded into the next segment. Per-step correction on a 3-axis machine trades accuracy for oscillation; block-level correction is stable and sufficient at these feeds.

Trade-offs

  • Block-level feedback cannot detect a single lost step mid-block, but a lost step mid-block at these accelerations is a mechanical fault that will show at the boundary anyway.
  • Bounded op queue means large arcs are segmented by the sender, not the controller. Deliberate: it keeps controller memory flat at 96 KB.
  • Conservative junction deviation costs roughly 8% cycle time on highly detailed geometry versus an aggressive planner. Predictable parts beat fast scrap.

Failure modes handled

  • Encoder desync beyond 3 counts triggers a controlled stop and a [FAULT] panel with the failing axis and block index.
  • Thermal derate is measured at the driver heatsink, not ambient, and reduces max feed before it reduces accuracy.
  • Power loss mid-program leaves a resume record in NVS: block index, modal state, offsets. Resume re-homes to the last known encoder position.

Status

Mechanical envelope is complete. Firmware is in soak testing: 40 hours of continuous 3D relief cutting, zero step loss, one thermal derate event that recovered without operator input. Spindle load estimation is the remaining work before release.