aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDennis Marttinen <38858901+twelho@users.noreply.github.com>2025-01-10 15:41:09 +0000
committerGitHub <noreply@github.com>2025-01-10 10:41:09 -0500
commit7083879700800710c624c0bf08220215ba5f4a83 (patch)
tree03595e28aca8238f9f8e727ba6e1d43aed52b2e6
parent9ca71d8608f4a6013c3453ffa9e75c3739078712 (diff)
downloadkutter-7083879700800710c624c0bf08220215ba5f4a83.tar.gz
kutter-7083879700800710c624c0bf08220215ba5f4a83.tar.xz
kutter-7083879700800710c624c0bf08220215ba5f4a83.zip
force_move: Implement CLEAR for SET_KINEMATIC_POSITION (#6262)
`CLEAR` clears the homing status (resets the axis limits) without turning off the motors. This is particularly useful when implementing safe Z homing in `[homing_override]` on printers with multiple independent Z steppers (where `FORCE_MOVE` can't be used). Signed-off-by: Dennis Marttinen <twelho@welho.tech>
-rw-r--r--docs/Code_Overview.md8
-rw-r--r--docs/G-Codes.md21
-rw-r--r--klippy/extras/force_move.py7
-rw-r--r--klippy/extras/safe_z_home.py3
-rw-r--r--klippy/kinematics/cartesian.py9
-rw-r--r--klippy/kinematics/corexy.py9
-rw-r--r--klippy/kinematics/corexz.py9
-rw-r--r--klippy/kinematics/delta.py8
-rw-r--r--klippy/kinematics/deltesian.py4
-rw-r--r--klippy/kinematics/hybrid_corexy.py9
-rw-r--r--klippy/kinematics/hybrid_corexz.py9
-rw-r--r--klippy/kinematics/none.py2
-rw-r--r--klippy/kinematics/polar.py12
-rw-r--r--klippy/kinematics/rotary_delta.py8
-rw-r--r--klippy/kinematics/winch.py3
-rw-r--r--klippy/stepper.py2
16 files changed, 77 insertions, 46 deletions
diff --git a/docs/Code_Overview.md b/docs/Code_Overview.md
index 0e4836ac..9ccaa60b 100644
--- a/docs/Code_Overview.md
+++ b/docs/Code_Overview.md
@@ -359,10 +359,10 @@ Useful steps:
be efficient as it is typically only called during homing and
probing operations.
5. Other methods. Implement the `check_move()`, `get_status()`,
- `get_steppers()`, `home()`, and `set_position()` methods. These
- functions are typically used to provide kinematic specific checks.
- However, at the start of development one can use boiler-plate code
- here.
+ `get_steppers()`, `home()`, `clear_homing_state()`, and `set_position()`
+ methods. These functions are typically used to provide kinematic
+ specific checks. However, at the start of development one can use
+ boiler-plate code here.
6. Implement test cases. Create a g-code file with a series of moves
that can test important cases for the given kinematics. Follow the
[debugging documentation](Debugging.md) to convert this g-code file
diff --git a/docs/G-Codes.md b/docs/G-Codes.md
index d44017de..ff6182fa 100644
--- a/docs/G-Codes.md
+++ b/docs/G-Codes.md
@@ -585,15 +585,18 @@ state; issue a G28 afterwards to reset the kinematics. This command is
intended for low-level diagnostics and debugging.
#### SET_KINEMATIC_POSITION
-`SET_KINEMATIC_POSITION [X=<value>] [Y=<value>] [Z=<value>]`: Force
-the low-level kinematic code to believe the toolhead is at the given
-cartesian position. This is a diagnostic and debugging command; use
-SET_GCODE_OFFSET and/or G92 for regular axis transformations. If an
-axis is not specified then it will default to the position that the
-head was last commanded to. Setting an incorrect or invalid position
-may lead to internal software errors. This command may invalidate
-future boundary checks; issue a G28 afterwards to reset the
-kinematics.
+`SET_KINEMATIC_POSITION [X=<value>] [Y=<value>] [Z=<value>]
+[CLEAR=<[X][Y][Z]>]`: Force the low-level kinematic code to believe the
+toolhead is at the given cartesian position. This is a diagnostic and
+debugging command; use SET_GCODE_OFFSET and/or G92 for regular axis
+transformations. If an axis is not specified then it will default to the
+position that the head was last commanded to. Setting an incorrect or
+invalid position may lead to internal software errors. Use the CLEAR
+parameter to forget the homing state for the given axes. Note that CLEAR
+will not override the previous functionality; if an axis is not specified
+to CLEAR it will have its kinematic position set as per above. This
+command may invalidate future boundary checks; issue a G28 afterwards to
+reset the kinematics.
### [gcode]
diff --git a/klippy/extras/force_move.py b/klippy/extras/force_move.py
index 50b80141..598783a4 100644
--- a/klippy/extras/force_move.py
+++ b/klippy/extras/force_move.py
@@ -131,8 +131,13 @@ class ForceMove:
x = gcmd.get_float('X', curpos[0])
y = gcmd.get_float('Y', curpos[1])
z = gcmd.get_float('Z', curpos[2])
- logging.info("SET_KINEMATIC_POSITION pos=%.3f,%.3f,%.3f", x, y, z)
+ clear = gcmd.get('CLEAR', '').upper()
+ axes = ['X', 'Y', 'Z']
+ clear_axes = [axes.index(a) for a in axes if a in clear]
+ logging.info("SET_KINEMATIC_POSITION pos=%.3f,%.3f,%.3f clear=%s",
+ x, y, z, ','.join((axes[i] for i in clear_axes)))
toolhead.set_position([x, y, z, curpos[3]], homing_axes=(0, 1, 2))
+ toolhead.get_kinematics().clear_homing_state(clear_axes)
def load_config(config):
return ForceMove(config)
diff --git a/klippy/extras/safe_z_home.py b/klippy/extras/safe_z_home.py
index ca9b8eb5..ca0756cf 100644
--- a/klippy/extras/safe_z_home.py
+++ b/klippy/extras/safe_z_home.py
@@ -40,8 +40,7 @@ class SafeZHoming:
toolhead.set_position(pos, homing_axes=[2])
toolhead.manual_move([None, None, self.z_hop],
self.z_hop_speed)
- if hasattr(toolhead.get_kinematics(), "note_z_not_homed"):
- toolhead.get_kinematics().note_z_not_homed()
+ toolhead.get_kinematics().clear_homing_state((2,))
elif pos[2] < self.z_hop:
# If the Z axis is homed, and below z_hop, lift it to z_hop
toolhead.manual_move([None, None, self.z_hop],
diff --git a/klippy/kinematics/cartesian.py b/klippy/kinematics/cartesian.py
index 0c4bb925..2715d172 100644
--- a/klippy/kinematics/cartesian.py
+++ b/klippy/kinematics/cartesian.py
@@ -73,9 +73,10 @@ class CartKinematics:
else:
rail = self.rails[axis]
self.limits[axis] = rail.get_range()
- def note_z_not_homed(self):
- # Helper for Safe Z Home
- self.limits[2] = (1.0, -1.0)
+ def clear_homing_state(self, axes):
+ for i, _ in enumerate(self.limits):
+ if i in axes:
+ self.limits[i] = (1.0, -1.0)
def home_axis(self, homing_state, axis, rail):
# Determine movement
position_min, position_max = rail.get_range()
@@ -97,7 +98,7 @@ class CartKinematics:
else:
self.home_axis(homing_state, axis, self.rails[axis])
def _motor_off(self, print_time):
- self.limits = [(1.0, -1.0)] * 3
+ self.clear_homing_state((0, 1, 2))
def _check_endstops(self, move):
end_pos = move.end_pos
for i in (0, 1, 2):
diff --git a/klippy/kinematics/corexy.py b/klippy/kinematics/corexy.py
index d3b75500..dc80d1ee 100644
--- a/klippy/kinematics/corexy.py
+++ b/klippy/kinematics/corexy.py
@@ -43,9 +43,10 @@ class CoreXYKinematics:
rail.set_position(newpos)
if i in homing_axes:
self.limits[i] = rail.get_range()
- def note_z_not_homed(self):
- # Helper for Safe Z Home
- self.limits[2] = (1.0, -1.0)
+ def clear_homing_state(self, axes):
+ for i, _ in enumerate(self.limits):
+ if i in axes:
+ self.limits[i] = (1.0, -1.0)
def home(self, homing_state):
# Each axis is homed independently and in order
for axis in homing_state.get_axes():
@@ -63,7 +64,7 @@ class CoreXYKinematics:
# Perform homing
homing_state.home_rails([rail], forcepos, homepos)
def _motor_off(self, print_time):
- self.limits = [(1.0, -1.0)] * 3
+ self.clear_homing_state((0, 1, 2))
def _check_endstops(self, move):
end_pos = move.end_pos
for i in (0, 1, 2):
diff --git a/klippy/kinematics/corexz.py b/klippy/kinematics/corexz.py
index 72134c32..b1c46146 100644
--- a/klippy/kinematics/corexz.py
+++ b/klippy/kinematics/corexz.py
@@ -43,9 +43,10 @@ class CoreXZKinematics:
rail.set_position(newpos)
if i in homing_axes:
self.limits[i] = rail.get_range()
- def note_z_not_homed(self):
- # Helper for Safe Z Home
- self.limits[2] = (1.0, -1.0)
+ def clear_homing_state(self, axes):
+ for i, _ in enumerate(self.limits):
+ if i in axes:
+ self.limits[i] = (1.0, -1.0)
def home(self, homing_state):
# Each axis is homed independently and in order
for axis in homing_state.get_axes():
@@ -63,7 +64,7 @@ class CoreXZKinematics:
# Perform homing
homing_state.home_rails([rail], forcepos, homepos)
def _motor_off(self, print_time):
- self.limits = [(1.0, -1.0)] * 3
+ self.clear_homing_state((0, 1, 2))
def _check_endstops(self, move):
end_pos = move.end_pos
for i in (0, 1, 2):
diff --git a/klippy/kinematics/delta.py b/klippy/kinematics/delta.py
index bb81ab18..04a75547 100644
--- a/klippy/kinematics/delta.py
+++ b/klippy/kinematics/delta.py
@@ -105,6 +105,11 @@ class DeltaKinematics:
self.limit_xy2 = -1.
if tuple(homing_axes) == (0, 1, 2):
self.need_home = False
+ def clear_homing_state(self, axes):
+ # Clearing homing state for each axis individually is not implemented
+ if 0 in axes or 1 in axes or 2 in axes:
+ self.limit_xy2 = -1
+ self.need_home = True
def home(self, homing_state):
# All axes are homed simultaneously
homing_state.set_axes([0, 1, 2])
@@ -112,8 +117,7 @@ class DeltaKinematics:
forcepos[2] = -1.5 * math.sqrt(max(self.arm2)-self.max_xy2)
homing_state.home_rails(self.rails, forcepos, self.home_position)
def _motor_off(self, print_time):
- self.limit_xy2 = -1.
- self.need_home = True
+ self.clear_homing_state((0, 1, 2))
def check_move(self, move):
end_pos = move.end_pos
end_xy2 = end_pos[0]**2 + end_pos[1]**2
diff --git a/klippy/kinematics/deltesian.py b/klippy/kinematics/deltesian.py
index bb231370..e48949af 100644
--- a/klippy/kinematics/deltesian.py
+++ b/klippy/kinematics/deltesian.py
@@ -117,6 +117,10 @@ class DeltesianKinematics:
rail.set_position(newpos)
for n in homing_axes:
self.homed_axis[n] = True
+ def clear_homing_state(self, axes):
+ for i, _ in enumerate(self.limits):
+ if i in axes:
+ self.homed_axis[i] = False
def home(self, homing_state):
homing_axes = homing_state.get_axes()
home_xz = 0 in homing_axes or 2 in homing_axes
diff --git a/klippy/kinematics/hybrid_corexy.py b/klippy/kinematics/hybrid_corexy.py
index 265a0e6d..85f20bcc 100644
--- a/klippy/kinematics/hybrid_corexy.py
+++ b/klippy/kinematics/hybrid_corexy.py
@@ -75,9 +75,10 @@ class HybridCoreXYKinematics:
else:
rail = self.rails[axis]
self.limits[axis] = rail.get_range()
- def note_z_not_homed(self):
- # Helper for Safe Z Home
- self.limits[2] = (1.0, -1.0)
+ def clear_homing_state(self, axes):
+ for i, _ in enumerate(self.limits):
+ if i in axes:
+ self.limits[i] = (1.0, -1.0)
def home_axis(self, homing_state, axis, rail):
position_min, position_max = rail.get_range()
hi = rail.get_homing_info()
@@ -97,7 +98,7 @@ class HybridCoreXYKinematics:
else:
self.home_axis(homing_state, axis, self.rails[axis])
def _motor_off(self, print_time):
- self.limits = [(1.0, -1.0)] * 3
+ self.clear_homing_state((0, 1, 2))
def _check_endstops(self, move):
end_pos = move.end_pos
for i in (0, 1, 2):
diff --git a/klippy/kinematics/hybrid_corexz.py b/klippy/kinematics/hybrid_corexz.py
index 2d89e3f7..8e5c3d92 100644
--- a/klippy/kinematics/hybrid_corexz.py
+++ b/klippy/kinematics/hybrid_corexz.py
@@ -75,9 +75,10 @@ class HybridCoreXZKinematics:
else:
rail = self.rails[axis]
self.limits[axis] = rail.get_range()
- def note_z_not_homed(self):
- # Helper for Safe Z Home
- self.limits[2] = (1.0, -1.0)
+ def clear_homing_state(self, axes):
+ for i, _ in enumerate(self.limits):
+ if i in axes:
+ self.limits[i] = (1.0, -1.0)
def home_axis(self, homing_state, axis, rail):
position_min, position_max = rail.get_range()
hi = rail.get_homing_info()
@@ -97,7 +98,7 @@ class HybridCoreXZKinematics:
else:
self.home_axis(homing_state, axis, self.rails[axis])
def _motor_off(self, print_time):
- self.limits = [(1.0, -1.0)] * 3
+ self.clear_homing_state((0, 1, 2))
def _check_endstops(self, move):
end_pos = move.end_pos
for i in (0, 1, 2):
diff --git a/klippy/kinematics/none.py b/klippy/kinematics/none.py
index ff3c57a9..fda1f073 100644
--- a/klippy/kinematics/none.py
+++ b/klippy/kinematics/none.py
@@ -13,6 +13,8 @@ class NoneKinematics:
return [0, 0, 0]
def set_position(self, newpos, homing_axes):
pass
+ def clear_homing_state(self, axes):
+ pass
def home(self, homing_state):
pass
def check_move(self, move):
diff --git a/klippy/kinematics/polar.py b/klippy/kinematics/polar.py
index deed26d0..fdd428a6 100644
--- a/klippy/kinematics/polar.py
+++ b/klippy/kinematics/polar.py
@@ -51,9 +51,12 @@ class PolarKinematics:
self.limit_z = self.rails[1].get_range()
if 0 in homing_axes and 1 in homing_axes:
self.limit_xy2 = self.rails[0].get_range()[1]**2
- def note_z_not_homed(self):
- # Helper for Safe Z Home
- self.limit_z = (1.0, -1.0)
+ def clear_homing_state(self, axes):
+ if 0 in axes or 1 in axes:
+ # X and Y cannot be cleared separately
+ self.limit_xy2 = -1.
+ if 2 in axes:
+ self.limit_z = (1.0, -1.0)
def _home_axis(self, homing_state, axis, rail):
# Determine movement
position_min, position_max = rail.get_range()
@@ -86,8 +89,7 @@ class PolarKinematics:
if home_z:
self._home_axis(homing_state, 2, self.rails[1])
def _motor_off(self, print_time):
- self.limit_z = (1.0, -1.0)
- self.limit_xy2 = -1.
+ self.clear_homing_state((0, 1, 2))
def check_move(self, move):
end_pos = move.end_pos
xy2 = end_pos[0]**2 + end_pos[1]**2
diff --git a/klippy/kinematics/rotary_delta.py b/klippy/kinematics/rotary_delta.py
index 1eb050ba..46a63b82 100644
--- a/klippy/kinematics/rotary_delta.py
+++ b/klippy/kinematics/rotary_delta.py
@@ -88,6 +88,11 @@ class RotaryDeltaKinematics:
self.limit_xy2 = -1.
if tuple(homing_axes) == (0, 1, 2):
self.need_home = False
+ def clear_homing_state(self, axes):
+ # Clearing homing state for each axis individually is not implemented
+ if 0 in axes or 1 in axes or 2 in axes:
+ self.limit_xy2 = -1
+ self.need_home = True
def home(self, homing_state):
# All axes are homed simultaneously
homing_state.set_axes([0, 1, 2])
@@ -97,8 +102,7 @@ class RotaryDeltaKinematics:
forcepos[2] = -1.
homing_state.home_rails(self.rails, forcepos, self.home_position)
def _motor_off(self, print_time):
- self.limit_xy2 = -1.
- self.need_home = True
+ self.clear_homing_state((0, 1, 2))
def check_move(self, move):
end_pos = move.end_pos
end_xy2 = end_pos[0]**2 + end_pos[1]**2
diff --git a/klippy/kinematics/winch.py b/klippy/kinematics/winch.py
index 11475d24..c69d1b6d 100644
--- a/klippy/kinematics/winch.py
+++ b/klippy/kinematics/winch.py
@@ -36,6 +36,9 @@ class WinchKinematics:
def set_position(self, newpos, homing_axes):
for s in self.steppers:
s.set_position(newpos)
+ def clear_homing_state(self, axes):
+ # XXX - homing not implemented
+ pass
def home(self, homing_state):
# XXX - homing not implemented
homing_state.set_axes([0, 1, 2])
diff --git a/klippy/stepper.py b/klippy/stepper.py
index 05e56cca..fd44effb 100644
--- a/klippy/stepper.py
+++ b/klippy/stepper.py
@@ -403,7 +403,7 @@ class PrinterRail:
changed_invert = pin_params['invert'] != endstop['invert']
changed_pullup = pin_params['pullup'] != endstop['pullup']
if changed_invert or changed_pullup:
- raise error("Pinter rail %s shared endstop pin %s "
+ raise error("Printer rail %s shared endstop pin %s "
"must specify the same pullup/invert settings" % (
self.get_name(), pin_name))
mcu_endstop.add_stepper(stepper)