Problem
Contact probes that touch the build surface with the nozzle (Voron TAP, load-cell probes, etc.) probe the same fixed points every time QUAD_GANTRY_LEVEL (and Z_TILT_ADJUST) runs. On a PEI sheet, repeatedly tapping the exact same spots gradually marks/wears the coating there. This typically happens 1–2× per print (e.g. a preheat-time QGL plus a print-start QGL), concentrating the wear on a handful of points.
The points of [quad_gantry_level] / [z_tilt] are static (read from config), and the QUAD_GANTRY_LEVEL command does not accept points as parameters, so there is currently no built-in way to spread this wear.
Prior art
The popular community tool KAMP (Klipper-Adaptive-Meshing-Purging) already addresses this for bed_mesh via a fuzz_amount setting that randomizes the mesh bounds by up to N mm, described as spreading out “wear from nozzle-based probes”. But KAMP only covers the mesh — the QGL / Z-tilt points stay fixed, and those are hit on every leveling, even when no mesh is done.
Proposal
Add an optional per-run jitter to the probe points of [quad_gantry_level] and [z_tilt] (it composes naturally with [bed_mesh] too), e.g.:
[quad_gantry_level]
points:
50,50
50,300
300,300
300,50
fuzz: 3.0 # max random offset (mm) added to each point's X and Y, per run (0 = off, default)
Behavior:
- Each configured point gets an independent random offset in
[-fuzz, +fuzz]on X and Y, re-rolled on every leveling run (starting from the original points, never accumulating). - Offsets are clamped to the axis limits (minus a small margin) so probing never goes out of range.
- Small magnitudes (2–3 mm) are irrelevant to leveling accuracy — the points stay near the gantry corners — but meaningfully distribute surface wear over time.
Since [quad_gantry_level], [z_tilt] and [bed_mesh] all build their points through ProbePointsHelper, this could live there once and be shared by all three (opt-in, default off → no behavior change for existing configs).
Proof of concept
I implemented this as an out-of-tree extras module that overrides quad_gantry_level.probe_helper.probe_points at runtime before each level, invoked via a rename_existing wrapper on QUAD_GANTRY_LEVEL (mirroring how KAMP wraps BED_MESH_CALIBRATE). Tested on Klipper v0.13.0 with Voron TAP — it works reliably: the QGL probes the jittered points and each leveling touches a slightly different spot.
Code (proof of concept):
Would a native fuzz option in ProbePointsHelper (shared by QGL / Z-tilt / mesh) be welcome? I’m happy to submit a PR.