Skip to content
Open
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
fdf1524
feat: Add `screw_factor` and `screw_direction` options
GiacomoGuaresi Feb 23, 2026
49fde13
chore: Clean up whitespace and line breaks in screws_tilt_adjust.py
GiacomoGuaresi Feb 23, 2026
bb98415
docs: Add detailed explanation for `screw_factor` in screws_tilt_adjust
GiacomoGuaresi Feb 23, 2026
32fd2d9
test: Add comprehensive unit tests for screws_tilt_adjust
GiacomoGuaresi Feb 23, 2026
c1f3135
refactor: Rename `screw_factor` to `screw_pitch` for clarity
GiacomoGuaresi Feb 23, 2026
a92906c
docs: Simplify `screw_direction` description in screws_tilt_adjust
GiacomoGuaresi Feb 23, 2026
1deb78f
refactor: Use `getchoice()` for `screw_direction` validation
GiacomoGuaresi Feb 23, 2026
669b96c
refactor: Extract screw thread mapping to module-level constant
GiacomoGuaresi Feb 23, 2026
90acb6b
refactor: Make `screw_thread` lookup case-insensitive
GiacomoGuaresi Feb 23, 2026
054081d
docs: Remove default values for `screw_pitch` and `screw_direction`
GiacomoGuaresi Feb 23, 2026
6cfdc0c
refactor: Format `screw_direction` getchoice call for readability
GiacomoGuaresi Feb 23, 2026
122674a
refactor: Defer `screw_direction` validation until after `screw_threa…
GiacomoGuaresi Feb 23, 2026
2341eb6
Update docs/Config_Reference.md
GiacomoGuaresi Feb 24, 2026
34aa908
chore: Consolidate screw configuration validation logic
GiacomoGuaresi Feb 24, 2026
31a1641
Merge branch 'main' into configurable-screw-for-tilt-adjust
GiacomoGuaresi Feb 25, 2026
c8293e1
chore: update the docs
GiacomoGuaresi Mar 31, 2026
a0628be
refactor: Replace screw thread map with indexed lookup table
GiacomoGuaresi Mar 31, 2026
c137209
refactor: Replace screw_thread map with indexed lookup and manual val…
GiacomoGuaresi Mar 31, 2026
8508b0c
refactor: Move screw_thread validation to use getchoice with default …
GiacomoGuaresi Mar 31, 2026
93b500c
refactor: Simplify screw configuration validation logic with explicit…
GiacomoGuaresi Mar 31, 2026
e9a4c9e
Merge branch 'main' into configurable-screw-for-tilt-adjust
GiacomoGuaresi Mar 31, 2026
01919e4
style: Apply consistent code formatting in screws_tilt_adjust module
GiacomoGuaresi Mar 31, 2026
db2b104
Merge branch 'main' into configurable-screw-for-tilt-adjust
GiacomoGuaresi Apr 5, 2026
2270664
Merge branch 'main' into configurable-screw-for-tilt-adjust
GiacomoGuaresi Apr 8, 2026
d87e749
Merge branch 'main' into configurable-screw-for-tilt-adjust
GiacomoGuaresi Apr 15, 2026
9412eb5
Merge branch 'main' into configurable-screw-for-tilt-adjust
GiacomoGuaresi Apr 22, 2026
25d755a
Merge branch 'main' into configurable-screw-for-tilt-adjust
GiacomoGuaresi Apr 29, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 27 additions & 3 deletions docs/Config_Reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -1486,10 +1486,34 @@ information.
#screw_thread: CW-M3
Comment thread
GiacomoGuaresi marked this conversation as resolved.
Outdated
# The type of screw used for bed leveling, M3, M4, or M5, and the
# rotation direction of the knob that is used to level the bed.
# Accepted values: CW-M3, CCW-M3, CW-M4, CCW-M4, CW-M5, CCW-M5, CW-M8, CCW-M8.
# Default value is CW-M3 which most printers use. A clockwise
# rotation of the knob decreases the gap between the nozzle and the
# Accepted values: CW-M3, CCW-M3, CW-M4, CCW-M4, CW-M5, CCW-M5,
# CW-M6, CCW-M6, CW-M8, CCW-M8.
# A clockwise rotation of the knob decreases the gap between the nozzle and the
# bed. Conversely, a counter-clockwise rotation increases the gap.
# This option cannot be used together with 'screw_pitch' or
# 'screw_direction'. Either this option must be specified, or both
# 'screw_pitch' and 'screw_direction' must be specified.
#screw_pitch:
# The thread pitch (in mm) of the bed leveling screw. This allows
# using any screw size, not just the predefined ones in
# 'screw_thread'. This option cannot be used together with 'screw_thread'.
# Must be specified together with 'screw_direction' if 'screw_thread'
# is not used.
# Calculation: screw_pitch is the bed movement for one full turn of
# the leveling screw. For most single-start metric screws, this is
# the thread pitch itself (for example, M3x0.5 -> 0.5, M4x0.7 -> 0.7,
# M5x0.8 -> 0.8). For multi-start screws, use the lead
# (lead = pitch * number_of_starts).
# Relation to adjustment output: required turns are calculated as
# abs(z_error) / screw_pitch, then shown as full turns and minutes
# (01:20 = 1 turn + 20/60 turn).
# Note: this is not the same as a stepper's 'rotation_distance' value
# unless your manual bed screw is exactly that same screw/lead.
#screw_direction:
# The rotation direction of the knob used to level the bed. Accepted
# values: CW, CCW. Rotation in this direction decreases the gap between the nozzle and the bed. This option
# cannot be used together with 'screw_thread'. Must be specified
# together with 'screw_pitch' if 'screw_thread' is not used.
#use_probe_xy_offsets: False
# If True, apply the `[probe]` XY offsets to the probed positions. The
# default is False.
Expand Down
81 changes: 50 additions & 31 deletions klippy/extras/screws_tilt_adjust.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,20 @@

from . import probe

# Screw thread mapping: thread_name -> (pitch, direction)
SCREW_THREAD_MAP = {
"CW-M3": (0.5, "CW"),
"CCW-M3": (0.5, "CCW"),
"CW-M4": (0.7, "CW"),
"CCW-M4": (0.7, "CCW"),
"CW-M5": (0.8, "CW"),
"CCW-M5": (0.8, "CCW"),
"CW-M6": (1.0, "CW"),
"CCW-M6": (1.0, "CCW"),
"CW-M8": (1.25, "CW"),
"CCW-M8": (1.25, "CCW"),
}


class ScrewsTiltAdjust:
def __init__(self, config):
Expand All @@ -30,21 +44,40 @@ def __init__(self, config):
raise config.error(
"screws_tilt_adjust: Must have at least three screws"
)
self.threads = {
"CW-M3": 0,
"CCW-M3": 1,
"CW-M4": 2,
"CCW-M4": 3,
"CW-M5": 4,
"CCW-M5": 5,
"CW-M6": 6,
"CCW-M6": 7,
"CW-M8": 8,
"CCW-M8": 9,
}
self.thread = config.getchoice(
"screw_thread", self.threads, default="CW-M3"
)
# Screw parameters: support both legacy 'screw_thread' and
# universal 'screw_pitch'/'screw_direction' options.
screw_thread = config.get("screw_thread", None)
Comment thread
GiacomoGuaresi marked this conversation as resolved.
screw_pitch = config.getfloat("screw_pitch", None, above=0.0)
if screw_thread is not None:
if (
screw_pitch is not None
or config.get("screw_direction", None) is not None
Comment thread
GiacomoGuaresi marked this conversation as resolved.
Outdated
):
raise config.error(
Comment thread
GiacomoGuaresi marked this conversation as resolved.
Outdated
"screws_tilt_adjust: 'screw_thread' cannot be used "
"together with 'screw_pitch' or 'screw_direction'"
)
screw_thread_result = SCREW_THREAD_MAP.get(screw_thread.upper())
if screw_thread_result is None:
raise config.error(
"screws_tilt_adjust: Invalid screw_thread '%s'. "
"Accepted values: %s"
% (screw_thread, ", ".join(sorted(SCREW_THREAD_MAP.keys())))
)
self.screw_pitch, self.screw_direction = screw_thread_result
else:
Comment thread
GiacomoGuaresi marked this conversation as resolved.
if (
screw_pitch is None
or config.get("screw_direction", None) is None
):
raise config.error(
"screws_tilt_adjust: Must specify either 'screw_thread' "
"or both 'screw_pitch' and 'screw_direction'"
)
self.screw_pitch = screw_pitch
self.screw_direction = config.getchoice(
"screw_direction", {"CW": "CW", "CCW": "CCW"}
)
# Initialize ProbePointsHelper
points = [coord for coord, name in self.screws]
self.probe_helper = probe.ProbePointsHelper(
Expand Down Expand Up @@ -89,21 +122,7 @@ def get_status(self, eventtime):
def probe_finalize(self, offsets, positions):
self.results = {}
self.max_diff_error = False
# Factors used for CW-M3, CCW-M3, CW-M4, CCW-M4, CW-M5, CCW-M5, CW-M6
# and CCW-M6
threads_factor = {
0: 0.5,
1: 0.5,
2: 0.7,
3: 0.7,
4: 0.8,
5: 0.8,
6: 1.0,
7: 1.0,
8: 1.25,
9: 1.25,
}
is_clockwise_thread = (self.thread & 1) == 0
is_clockwise_thread = self.screw_direction == "CW"
screw_diff = []
# Process the read Z values
if self.direction is not None:
Expand Down Expand Up @@ -146,7 +165,7 @@ def probe_finalize(self, offsets, positions):
if abs(diff) < 0.001:
adjust = 0
else:
adjust = diff / threads_factor.get(self.thread, 0.5)
adjust = diff / self.screw_pitch
if is_clockwise_thread:
sign = "CW" if adjust >= 0 else "CCW"
else:
Expand Down
Loading
Loading