Skip to content

PR: Add universal screw parameters to screws_tilt_adjust with backward compatibility#844

Draft
GiacomoGuaresi wants to merge 15 commits intoKalicoCrew:mainfrom
gingeradditive:configurable-screw-for-tilt-adjust
Draft

PR: Add universal screw parameters to screws_tilt_adjust with backward compatibility#844
GiacomoGuaresi wants to merge 15 commits intoKalicoCrew:mainfrom
gingeradditive:configurable-screw-for-tilt-adjust

Conversation

@GiacomoGuaresi
Copy link
Contributor

@GiacomoGuaresi GiacomoGuaresi commented Feb 23, 2026

This PR makes the screws_tilt_adjust module universal by allowing any screw thread pitch, instead of being limited to predefined screw types.

Previously, only specific screw types (M3, M4, M5, M6, M8) could be used via the screw_thread parameter.

What Changed

New Universal Parameters

  • screw_factor – screw thread pitch in millimeters
  • screw_direction – rotation direction (CW / CCW)

Backward Compatibility

  • The existing screw_thread parameter continues to work unchanged

Simplified Implementation

  • Removed hardcoded thread index mapping
  • Direct use of pitch and direction attributes

Documentation Updated

  • Added new parameter descriptions to Config_Reference.md

Why

The old implementation was restrictive: users with custom screw sizes (e.g. M10, M12, or non-standard thread pitches) could not use the tool.

This change enables universal screw support while maintaining full backward compatibility with all existing configurations.

Example Usage

# Legacy configuration (still works)
screw_thread: CW-M4

# New universal configuration (any screw size)
screw_factor: 1.0    # e.g. M6 thread pitch
screw_direction: CW

Checklist

  • PR title is clear and meaningful
  • Test case added (where possible)
  • New feature documented in the README / reference docs
  • CI is green
  • Tested on an actual printer

@GiacomoGuaresi
Copy link
Contributor Author

Hi @dalegaard , thanks a lot for the comments you left

I agree with everything you pointed out.
This PR is still a draft carried over from an old Klipper fork, and I still need to work on it to make it good enough for a proper review (that’s why it’s still marked as draft 😅).

In the meantime, I’ll address the issues you mentioned. If you have any other suggestions or feedback, I’m more than happy to hear them.

Thanks again for your feedback!

@GiacomoGuaresi GiacomoGuaresi marked this pull request as ready for review February 23, 2026 12:23
@GiacomoGuaresi GiacomoGuaresi marked this pull request as draft February 23, 2026 12:23
)
# Screw parameters: support both legacy 'screw_thread' and
# universal 'screw_pitch'/'screw_direction' options.
screw_thread = config.get("screw_thread", None)
Copy link
Contributor

Choose a reason for hiding this comment

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

Use getchoice for screw_thread and screw_direction so you don't need to do lookups later.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I looked into using getchoice for screw_thread and screw_direction. It works well for screw_direction (already done in the else branch), but for screw_thread there are a few issues:

  • Case sensitivity: the previous code did .upper() before lookup, so cw-m3 was accepted. getchoice does a case-sensitive comparison against dictionary keys, so lowercase input would break. We'd need to either add lowercase keys to SCREW_THREAD_MAP or accept this as a breaking change.

  • Error messages: getchoice raises a generic "Choice '...' is not a valid choice" message, losing our custom error text. This also breaks existing test assertions that match on specific error strings.

  • Validation order: when screw_thread is not specified and default=None, getchoice raises immediately because None is not a valid choice — before we can reach our XOR logic that checks whether the user provided the right combination of options.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think we have 3 possible approaches to the problem:

  • Use getchoice only when the option is actually present (check with config.get("screw_thread", None) first, then call getchoice), but that defeats the purpose of simplification.

  • Add both upper and lowercase keys to SCREW_THREAD_MAP to preserve case insensitivity, and accept the generic error message.

  • Keep the current manual approach for screw_thread since it handles a tuple return value and custom validation, and only use getchoice for screw_direction (which is already done).

How do you think it's best to proceed?

Copy link
Contributor

@dalegaard dalegaard Feb 25, 2026

Choose a reason for hiding this comment

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

The original code was using getchoice for the screw_thread parameter so there shouldn't be a breaking change here. Likewise, there shouldn't be any tests broken by this.
You can add None: None to SCREW_THREAD_MAP to make None pass as a valid choice.
You're right that the error message is generic, but since we use this all across the codebase it's better to use getchoice here, and then in a separate patch extend getchoice so it will output valid options when it makes sense. That way, we fix that issue across the entire codebase.
Both screw_thread and screw_direction should be using getchoice at the initial lookup, instead of doing two lookups.

if not (
(screw_thread is not None)
^ (screw_pitch is not None or screw_direction is not None)
):
Copy link
Contributor

@dalegaard dalegaard Feb 25, 2026

Choose a reason for hiding this comment

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

I know I suggested this one, but actually think it would be cleaner like:

has_screw_thread = screw_thread is not None
has screw_pitch = screw_pitch is not None or screw_direction is not None
if has_screw_thread == has_screw_pitch:

Decoding the XOR with the NOT in front is a lot harder.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants