Skip to content

bed_mesh: Add Wandering Probe Points (WPP) dynamic offset#7277

Open
famtory wants to merge 3 commits into
Klipper3d:masterfrom
famtory:bed-auto-leveling
Open

bed_mesh: Add Wandering Probe Points (WPP) dynamic offset#7277
famtory wants to merge 3 commits into
Klipper3d:masterfrom
famtory:bed-auto-leveling

Conversation

@famtory

@famtory famtory commented May 31, 2026

Copy link
Copy Markdown

What does this PR do?

This PR introduces the "Wandering Probe Points (WPP)" feature to bed_mesh.py.
Currently, traditional bed probing systems hit the exact same coordinates on the PEI surface repeatedly. Over time, this repetitive probing causes physical wear, leaves filament oozing/divots, and ultimately degrades bed leveling accuracy.

WPP solves this by applying a dynamic, persistent translational offset to the entire probing grid matrix across successive probes. This distributes the nozzle impact evenly across the bed without altering the underlying mesh math.

Key Changes

  • Added wandering_step parameter to dynamically shift dx, dy offsets for each probe cycle.
  • Prevents localized PEI degradation and reduces errors from accumulated oozing.
  • Stamped with the Famtory Conceptual Designer attribution.

Signed-off-by: Hwang Younsang famtory@gmail.com

famtory added 2 commits June 1, 2026 04:02
Signed-off-by: Hwang Younsang <famtory@gmail.com>
Signed-off-by: Hwang Younsang <famtory@gmail.com>
@dewi-ny-je

Copy link
Copy Markdown

Which probes are you thinking about? 3D/BL touch don't cause any real wear, just like klicky and similar. Do you have concrete examples of wear caused by probing?

Also, assuming someone will review the proposal, at some point you will have to sign with your real name and surname, I don't think Famtory is.

@famtory

famtory commented Jun 4, 2026

Copy link
Copy Markdown
Author

Hi @dewi-ny-je, thanks for the review!

Regarding the signature, you are absolutely right. The git commits themselves are already correctly signed off with my legal real name (Hwang Younsang), but I accidentally used my brand name in the PR description text. I have updated the PR description to match the commit signatures.

Regarding the concrete examples of wear:
While traditional probes like BLTouch or Klicky indeed do not cause physical wear, modern Nozzle-based probing systems (such as Voron Tap, load-cell based sensors, and sensorless homing) involve the physical hot nozzle repeatedly striking the bed surface.

When using high-temperature materials like ABS or PC, even a wiped nozzle can leave microscopic filament residue (ooze). Repeated probing on the exact same micro-spot over dozens of prints causes this residue to accumulate, eventually shifting the Z-offset reading and causing leveling errors. Furthermore, a hot nozzle repeatedly tapping the exact same coordinate on a textured PEI sheet will eventually create a micro-divot and degrade the PEI coating at those specific points.

Wandering the grid by a small step distributes this nozzle-tap wear evenly and avoids accumulated ooze points, significantly prolonging the lifespan of the build plate for nozzle-probing users without altering the mesh math. Let me know if you need any further clarifications!

@dewi-ny-je

Copy link
Copy Markdown

Thanks for the clarification! I had forgotten about those probing techniques.

Indeed a useful feature. Hopefully a reviewer will pick it up.
Have you advertised it in the Klipper Discord and Discourse, and also in the Voron and Ratrig Discord? With Klipper finding someone to review the changes is usually the biggest difficulty

@famtory

famtory commented Jun 4, 2026

Copy link
Copy Markdown
Author

@dewi-ny-je To be honest, I'm not very active in communities like Discord, so I just submitted it here as a start. But I really appreciate the great advice! I'll see if I can share it around. Thanks again!

@github-actions

Copy link
Copy Markdown

Thank you for your contribution to Klipper. Unfortunately, a reviewer has not assigned themselves to this GitHub Pull Request. All Pull Requests are reviewed before merging, and a reviewer will need to volunteer. Further information is available at: https://www.klipper3d.org/CONTRIBUTING.html

There are some steps that you can take now:

  1. Perform a self-review of your Pull Request by following the steps at: https://www.klipper3d.org/CONTRIBUTING.html#what-to-expect-in-a-review
    If you have completed a self-review, be sure to state the results of that self-review explicitly in the Pull Request comments. A reviewer is more likely to participate if the bulk of a review has already been completed.
  2. Consider opening a topic on the Klipper Discourse server to discuss this work. The Discourse server is a good place to discuss development ideas and to engage users interested in testing. Reviewers are more likely to prioritize Pull Requests with an active community of users.
  3. Consider helping out reviewers by reviewing other Klipper Pull Requests. Taking the time to perform a careful and detailed review of others work is appreciated. Regular contributors are more likely to prioritize the contributions of other regular contributors.

Unfortunately, if a reviewer does not assign themselves to this GitHub Pull Request then it will be automatically closed. If this happens, then it is a good idea to move further discussion to the Klipper Discourse server. Reviewers can reach out on that forum to let you know if they are interested and when they are available.

Best regards,
~ Your friendly GitIssueBot

PS: I'm just an automated script, not a human being.

@dewi-ny-je

Copy link
Copy Markdown

Has this feature the green light by @KevinOConnor assuming it is properly reviewed?

@dewi-ny-je dewi-ny-je left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Missing documentation. New config option wandering_step and gcode parameter WANDERING_STEP are added with no corresponding entries in docs/Config_Reference.md or docs/G-Codes.md. Klipper requires new config/command surface to be documented; this will block merge.
  • No tests. There's no test covering offset cycling, the is_calibrating gating, or that mesh_min/mesh_max are reset (not accumulated) across calls. A small unit test would strengthen the PR.

Comment thread klippy/extras/bed_mesh.py Outdated
if is_calibrating:
self.wandering_state += 1
logging.info("bed_mesh: wandering step=%.2f, "
"offset=(%.2f, %.2f)" % (step, dx, dy))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

update_config — wandering offset block (~lines 619–652)

  • [CRITICAL] No boundary clamping — the shift can push probe points out of range. The offset is added directly to mesh_min/mesh_max (and origin), but neither update_config nor generate_points validates that the resulting points stay within the bed / probe-movable area (generate_points only checks that point spacing isn't < 1mm). If wandering_step is configured for a mesh whose min/max is already at the edge of the probe range — a very common setup, since people maximize mesh coverage — the shifted point will trigger a "Move out of range" kinematics error, or worse, drive the nozzle off the bed. The wear-spreading goal inherently wants the mesh near the edges, which is exactly where this is most dangerous. This needs explicit clamping of shifted_min/shifted_max/shifted_orig to the valid probe area (and for round beds, against radius), or at minimum a documented requirement that the configured mesh leave wandering_step of margin on all sides.

  • [PROBLEM] wandering_state is not persisted — contradicts the "persistent" design goal. The PR description promises "persistent translational offsets ... across successive measurement cycles," but wandering_state is an in-memory integer initialized to 0 in __init__. Every Klipper restart / FIRMWARE_RESTART resets it to 0, so the pattern always restarts at offset (0,0). For users who calibrate once per print and restart between prints (the typical workflow), the nozzle keeps landing on (0,0) and the feature effectively does nothing. To deliver the stated benefit, the counter should be persisted (e.g. via [save_variables] or a SAVE_CONFIG-backed value) and restored on startup.

  • [PROBLEM] Counter advances even when calibration later fails. self.wandering_state += 1 runs inside update_config, before generate_points and before probing actually executes. update_config is called inside the try in cmd_BED_MESH_CALIBRATE; if generate_points raises (e.g. "min/max points too close") or the probe run aborts, the state has already advanced and that offset is skipped on the next run. Advancing the counter only after a successful calibration would be more robust.

  • [SUGGESTION] Inconsistent step magnitude across the pattern. The 9-point pattern mixes orthogonal moves (distance step) and diagonal moves (distance step*√2 ≈ 1.41·step). That's probably fine for wear-spreading, but it's worth a comment noting the diagonal entries land ~41% farther out than step, since that affects the edge-margin requirement above.

  • [SUGGESTION] logging.info on every calibrate. Minor, but logging the wandering offset at info on each calibration adds noise to klippy.log. Consider logging.debug, or keep it but be aware reviewers may push back.

Comment thread klippy/extras/bed_mesh.py
self._profile_name = None
return True
def update_config(self, gcmd):
def update_config(self, gcmd, is_calibrating=False):

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider adding a test to ensure that a dump/preview won't advance the counter or change the offset relative to the active state (it doesn't perturb the wandering state)

Comment thread klippy/extras/bed_mesh.py Outdated
# Mesh Bed Leveling
#
# Copyright (C) 2018-2019 Eric Callahan <arksine.code@gmail.com>
# Wandering Probe Points (WPP) Feature Concept & Implementation

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Per-feature copyright header is unusual for this repo.
Adding # Wandering Probe Points (WPP) ... Copyright (C) 2026 Famtory near the file's top copyright line is not how Klipper typically tracks contributions (attribution lives in git history)

@famtory

famtory commented Jun 20, 2026

Copy link
Copy Markdown
Author

Hi @dewi-ny-je,
Thanks again for taking the time to review this one as well! Your insights are incredibly valuable.

I have just pushed an update addressing the core issues you pointed out:

  1. Documentation & Boundary Warning: Added wandering_step and WANDERING_STEP to docs/Config_Reference.md and docs/G-Codes.md. I included an explicit warning that users must leave a safe margin of at least ~1.41 * wandering_step from physical limits to avoid "Move out of range" errors during diagonal shifts.
  2. State Persistence: Wired up the wandering state to Klipper's save_variables module. If configured by the user, the state is now properly persisted across firmware restarts!
  3. Robust Counter Advance: Moved the counter increment logic to probe_finalize so it only advances after a successful calibration, avoiding false increments on failed or aborted probes.
  4. Log Noise: Reduced the wandering offset log level to logging.debug.
  5. Formatting: Removed the inline copyright header to match Klipper's standard git-based attribution.

Regarding the unit tests, I will look into Klipper's batch test framework to see if I can cleanly mock the is_calibrating and offset cycling logic soon, but I hope this clears the immediate functional and hard requirements!

Hopefully, this makes it easier for @KevinOConnor to review when he has the time. Let me know what you think!

@famtory famtory force-pushed the bed-auto-leveling branch from 9eaf41c to 604a109 Compare June 20, 2026 12:25
- Document wandering_step config and WANDERING_STEP g-code parameter.
- Add warning about leaving margin for WPP expansion (~1.41x step).
- Change WPP logging to debug level.
- Persist wandering_state across restarts via save_variables if available.
- Only advance wandering_state after a successful calibration (probe_finalize).
- Remove inline feature copyright header.

Signed-off-by: Hwang Younsang <famtory@gmail.com>
@dewi-ny-je

Copy link
Copy Markdown

That's all I can do, it was an automated review (filtered by me to what made sense to me).

Also, I honestly didn't know about save_variables.
But now I wonder why do we need to do a save_config and restart when this approach could allow immediate saving of bed meshes, z_offsets and maybe something more.

But it's not a topic for this PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants