diff --git a/docs/G-Codes.md b/docs/G-Codes.md index 0bf8099b..026b93ec 100644 --- a/docs/G-Codes.md +++ b/docs/G-Codes.md @@ -456,12 +456,13 @@ The following commands are available when the [screws_tilt_adjust config section](Config_Reference.md#screws_tilt_adjust) is enabled (also see the [manual level guide](Manual_Level.md#adjusting-bed-leveling-screws-using-the-bed-probe)): -- `SCREWS_TILT_CALCULATE [=]`: This command - will invoke the bed screws adjustment tool. It will command the +- `SCREWS_TILT_CALCULATE [DIRECTION=CW|CCW] [=]`: + This command will invoke the bed screws adjustment tool. It will command the nozzle to different locations (as defined in the config file) probing the z height and calculate the number of knob turns to - adjust the bed level. See the PROBE command for details on the - optional probe parameters. + adjust the bed level. If DIRECTION is specified, the knob turns will all + be in the same direction, clockwise (CW) or counterclockwise (CCW). + See the PROBE command for details on the optional probe parameters. IMPORTANT: You MUST always do a G28 before using this command. ## Z Tilt diff --git a/docs/Manual_Level.md b/docs/Manual_Level.md index a50e6daf..ac75a868 100644 --- a/docs/Manual_Level.md +++ b/docs/Manual_Level.md @@ -163,17 +163,18 @@ screw_thread: CW-M3 ``` The screw1 is always the reference point for the others, so the system -assumes that screw1 is in the correct height. Always run `G28` first +assumes that screw1 is at the correct height. Always run `G28` first and then run `SCREWS_TILT_CALCULATE` - it should produce output similar to: ``` Send: G28 Recv: ok Send: SCREWS_TILT_CALCULATE -Recv: // front left screw (Base): X -5.0, Y 30.0, Z 2.48750 -Recv: // front right screw : X 155.0, Y 30.0, Z 2.36000 : Adjust -> CW 01:15 -Recv: // rear right screw : X 155.0, Y 190.0, Z 2.71500 : Adjust -> CCW 00:50 -Recv: // read left screw : X -5.0, Y 190.0, Z 2.47250 : Adjust -> CW 00:02 +Recv: // 01:20 means 1 full turn and 20 minutes, CW=clockwise, CCW=counter-clockwise +Recv: // front left screw (base) : x=-5.0, y=30.0, z=2.48750 +Recv: // front right screw : x=155.0, y=30.0, z=2.36000 : adjust CW 01:15 +Recv: // rear right screw : y=155.0, y=190.0, z=2.71500 : adjust CCW 00:50 +Recv: // read left screw : x=-5.0, y=190.0, z=2.47250 : adjust CW 00:02 Recv: ok ``` This means that: @@ -198,3 +199,12 @@ the mesh was created. For example, `SCREWS_TILT_CALCULATE MAX_DEVIATION=0.01` can be added to the custom start gcode of the slicer before the mesh is loaded. It will abort the print if the configured limit is exceeded (0.01mm in this example), giving the user a chance to adjust the screws and restart the print. + +The `DIRECTION` parameter is useful if you can turn your bed adjustment +screws in one direction only. For example, you might have screws that start +tightened in their lowest (or highest) possible position, which can only be +turned in a single direction, to raise (or lower) the bed. If you can only +turn the screws clockwise, run `SCREWS_TILT_CALCULATE DIRECTION=CW`. If you can +only turn them counter-clockwise, run `SCREWS_TILT_CALCULATE DIRECTION=CCW`. +A suitable reference point will be chosen such that the bed can be leveled +by turning all the screws in the given direction. diff --git a/klippy/extras/screws_tilt_adjust.py b/klippy/extras/screws_tilt_adjust.py index 30e091ff..3c41c211 100644 --- a/klippy/extras/screws_tilt_adjust.py +++ b/klippy/extras/screws_tilt_adjust.py @@ -1,6 +1,7 @@ # Helper script to adjust bed screws tilt using Z probe # # Copyright (C) 2019 Rui Caridade +# Copyright (C) 2021 Matthew Lloyd # # This file may be distributed under the terms of the GNU GPLv3 license. import math @@ -53,44 +54,64 @@ class ScrewsTiltAdjust: def cmd_SCREWS_TILT_CALCULATE(self, gcmd): self.max_diff = gcmd.get_float("MAX_DEVIATION", None) + # Option to force all turns to be in the given direction (CW or CCW) + direction = gcmd.get("DIRECTION", default=None) + if direction is not None: + direction = direction.upper() + if direction not in ('CW', 'CCW'): + raise gcmd.error( + "Error on '%s': DIRECTION must be either CW or CCW" % ( + gcmd.get_commandline(),)) + self.direction = direction self.probe_helper.start_probe(gcmd) def probe_finalize(self, offsets, positions): # Factors used for CW-M3, CCW-M3, CW-M4, CCW-M4, CW-M5 and CCW-M5 threads_factor = {0: 0.5, 1: 0.5, 2: 0.7, 3: 0.7, 4: 0.8, 5: 0.8} + is_clockwise_thread = (self.thread & 1) == 0 screw_diff = [] - # Process the read Z values and + # Process the read Z values + if self.direction is not None: + # Lowest or highest screw is the base position used for comparison + use_max = ((is_clockwise_thread and self.direction == 'CW') + or (not is_clockwise_thread and self.direction == 'CCW')) + min_or_max = max if use_max else min + i_base, z_base = min_or_max( + enumerate([pos[2] for pos in positions]), key=lambda (i, z): z) + else: + # First screw is the base position used for comparison + i_base, z_base = 0, positions[0][2] + # Provide the user some information on how to read the results + self.gcode.respond_info("01:20 means 1 full turn and 20 minutes, " + "CW=clockwise, CCW=counter-clockwise") for i, screw in enumerate(self.screws): - if i == 0: - # First screw is the base position used for comparison - z_base = positions[i][2] - coord_base, name_base = screw + z = positions[i][2] + coord, name = screw + if i == i_base: # Show the results - self.gcode.respond_info("%s (Base): X %.1f, Y %.1f, Z %.5f" % - (name_base, coord_base[0], - coord_base[1], z_base)) + self.gcode.respond_info( + "%s : x=%.1f, y=%.1f, z=%.5f" % + (name + ' (base)', coord[0], coord[1], z)) else: - # Calculate how knob must me adjusted for other positions - z = positions[i][2] - coord, name = screw + # Calculate how knob must be adjusted for other positions diff = z_base - z screw_diff.append(abs(diff)) if abs(diff) < 0.001: adjust = 0 else: adjust = diff / threads_factor.get(self.thread, 0.5) - if (self.thread & 1) == 1: - sign = "CW" if adjust < 0 else "CCW" + if is_clockwise_thread: + sign = "CW" if adjust >= 0 else "CCW" else: - sign = "CCW" if adjust < 0 else "CW" + sign = "CCW" if adjust >= 0 else "CW" + adjust = abs(adjust) full_turns = math.trunc(adjust) decimal_part = adjust - full_turns minutes = round(decimal_part * 60, 0) # Show the results - self.gcode.respond_info("%s : X %.1f, Y %.1f, Z %.5f : " - "Adjust -> %s %02d:%02d" % - (name, coord[0], coord[1], z, sign, - abs(full_turns), abs(minutes))) + self.gcode.respond_info( + "%s : x=%.1f, y=%.1f, z=%.5f : adjust %s %02d:%02d" % + (name, coord[0], coord[1], z, sign, full_turns, minutes)) if self.max_diff and any((d > self.max_diff) for d in screw_diff): raise self.gcode.error( "bed level exceeds configured limits ({}mm)! " \