-
-
Notifications
You must be signed in to change notification settings - Fork 234
Add 'safe_z_lift' module for safe lifting of (unhomed) Z axis #842
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
rschaeuble
wants to merge
18
commits into
KalicoCrew:main
Choose a base branch
from
rschaeuble:main
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
18 commits
Select commit
Hold shift + click to select a range
7b5001e
Add 'safe_z_lift' module
rschaeuble 810af0f
Rework; replace safe_z_lift with safe_move.
rschaeuble 887b434
introduce endstop_{min,max}_pin; add PrinterHoming.endstop_move
rschaeuble c382cd5
Fix stepper attachment
rschaeuble ac101a6
Fix bug and improve readability
rschaeuble 5975217
Code cleanup
rschaeuble a245b97
avoid rail where possible and reformat
rschaeuble 4ec89ad
another attempt at structuring endstop handling
rschaeuble 895e285
add error for unsupported/unsafe configurations
rschaeuble 1ae6969
Make code clearer
rschaeuble 6aab263
Add get_endstops_for_safe_move() to kinematics
rschaeuble 5448bc6
endstop_move: return full_move/hit_endstop/already_at_endstop
rschaeuble ae48252
expose ALLOW_UNSAFE in SAFE_MOVE
rschaeuble 97c30b5
fix formatting
rschaeuble cdfe5a2
Make it compatible with Python 3.9
rschaeuble 3b636e4
fix formatting
rschaeuble 4f7fcbe
add status
rschaeuble f8842c5
raise error if toolhead already at endstop
rschaeuble File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,144 @@ | ||
| # Safe move | ||
| # | ||
| # Allows safe moves of an axis even when unhomed, as long as an endstop is available in the respective direction. | ||
| # This is used by modules like safe_z_home and dockable_probe during their Z hops, and be used via a Gcode | ||
| # command as well. | ||
| from klippy.extras.homing import MoveResult, any_complete | ||
|
|
||
|
|
||
| class SafeMove: | ||
| """Execute safe single-axis moves using directional endstops.""" | ||
|
|
||
| def __init__(self, config): | ||
| self.printer = config.get_printer() | ||
| self.homing = self.printer.load_object(config, "homing") | ||
| gcode = self.printer.lookup_object("gcode") | ||
| gcode.register_command( | ||
| "SAFE_MOVE", self.cmd_SAFE_MOVE, desc=self.cmd_SAFE_MOVE_help | ||
| ) | ||
| self.last_axis = None | ||
| self.last_dist = None | ||
| self.last_result = None | ||
|
|
||
| def move(self, toolhead, axis, dist, speed, allow_unsafe=False): | ||
| """Move on one axis, stopping early if protected endstops trigger.""" | ||
| axis_lower = axis.lower() | ||
| if axis_lower not in "xyz": | ||
| raise self.printer.command_error( | ||
| "SAFE_MOVE: AXIS must be X, Y, or Z" | ||
| ) | ||
| if dist == 0.0: | ||
| return | ||
|
|
||
| axis_idx = "xyz".index(axis_lower) | ||
| positive = dist > 0.0 | ||
|
|
||
| kin = toolhead.get_kinematics() | ||
| endstops = self._get_endstops(kin, axis_idx, positive, allow_unsafe) | ||
|
|
||
| reactor = self.printer.get_reactor() | ||
| curtime = reactor.monotonic() | ||
| kin_status = kin.get_status(curtime) | ||
|
|
||
| axis_min = kin_status["axis_minimum"][axis_idx] | ||
| axis_max = kin_status["axis_maximum"][axis_idx] | ||
|
|
||
| was_unhomed = False | ||
| position = toolhead.get_position() | ||
| if axis_lower not in kin_status["homed_axes"]: | ||
| was_unhomed = True | ||
| # Assume a safe coordinate so the requested move stays in range. | ||
| position[axis_idx] = axis_max if dist < 0.0 else axis_min | ||
| toolhead.set_position(position, homing_axes=[axis_idx]) | ||
| position = toolhead.get_position() | ||
|
|
||
| target_pos = list(position) | ||
| target_pos[axis_idx] = position[axis_idx] + dist | ||
| # Clamp moves for homed axes to avoid out-of-range errors. | ||
| target_pos[axis_idx] = max( | ||
| axis_min, min(axis_max, target_pos[axis_idx]) | ||
| ) | ||
| if target_pos[axis_idx] == position[axis_idx]: | ||
| return | ||
|
|
||
| try: | ||
| if endstops: | ||
| epos, res = self.homing.endstop_move( | ||
| endstops, | ||
| target_pos, | ||
| speed, | ||
| complete=any_complete, | ||
| ) | ||
| self.last_dist = epos[axis_idx] - position[axis_idx] | ||
| self.last_result = res | ||
|
|
||
| if res == MoveResult.ALREADY_AT_ENDSTOP: | ||
| raise self.printer.command_error( | ||
| "Toolhead is already at endstop - unsafe to continue." | ||
| ) | ||
| elif allow_unsafe: | ||
| move_cmd = [None, None, None, None] | ||
| move_cmd[axis_idx] = target_pos[axis_idx] | ||
| toolhead.manual_move(move_cmd, speed) | ||
|
|
||
| self.last_dist = dist | ||
| self.last_result = MoveResult.FULL_MOVE | ||
| else: | ||
| raise self.printer.command_error( | ||
| "SAFE_MOVE: No endstop protects axis %s in the %s direction" | ||
| % ( | ||
| axis.upper(), | ||
| "positive" if positive else "negative", | ||
| ) | ||
| ) | ||
|
|
||
| self.last_axis = axis_lower | ||
| finally: | ||
| if was_unhomed: | ||
| kin.clear_homing_state([axis_idx]) | ||
|
|
||
| def _get_endstops(self, kin, axis_idx, positive, allow_unsafe): | ||
| endstops = kin.get_endstops_for_safe_move(axis_idx, positive) | ||
| if endstops is None: | ||
| if allow_unsafe: | ||
| return [] | ||
| raise self.printer.command_error( | ||
| f"SAFE_MOVE: kinematics do not support axis {'XYZ'[axis_idx]} in the {'positive' if positive else 'negative'} direction" | ||
| ) | ||
| if len(endstops) == 0 and not allow_unsafe: | ||
| raise self.printer.command_error( | ||
| f"SAFE_MOVE: No endstops configured for axis {'XYZ'[axis_idx]} in the {'positive' if positive else 'negative'} direction" | ||
| ) | ||
| return endstops | ||
|
|
||
| cmd_SAFE_MOVE_help = "Perform a safe axis move" | ||
|
|
||
| def cmd_SAFE_MOVE(self, gcmd): | ||
| axis = gcmd.get("AXIS", None) | ||
| if axis is None: | ||
| raise gcmd.error("AXIS must be specified") | ||
|
|
||
| dist = gcmd.get_float("DIST") | ||
| if dist == 0.0: | ||
| return | ||
| speed = gcmd.get_float("SPEED", above=0.0) | ||
| allow_unsafe = gcmd.get_int("ALLOW_UNSAFE", 0) | ||
|
|
||
| toolhead = self.printer.lookup_object("toolhead") | ||
| try: | ||
| self.move( | ||
| toolhead, axis, dist, speed, allow_unsafe=bool(allow_unsafe) | ||
| ) | ||
| except self.printer.command_error as err: | ||
| raise gcmd.error(str(err)) | ||
|
|
||
| def get_status(self, eventtime): | ||
| return { | ||
| "last_axis": self.last_axis, | ||
| "last_dist": self.last_dist, | ||
| "last_result": self.last_result, | ||
| } | ||
|
|
||
|
|
||
| def load_config(config): | ||
| return SafeMove(config) |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Goes away.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll keep this until everything else is fine and we make the final decision about the SAFE_MOVE Gcode command.