aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKevin O'Connor <kevin@koconnor.net>2025-03-21 23:04:46 -0400
committerKevin O'Connor <kevin@koconnor.net>2025-05-12 20:15:03 -0400
commit7201f41664ffa658e90146187ce57ad70b71d11c (patch)
tree3bec429048d8f80d6d342cbe3bc6b30329e0c50d
parentd40fd2190d740cf5388299e7f803a9790108a2dd (diff)
downloadkutter-7201f41664ffa658e90146187ce57ad70b71d11c.tar.gz
kutter-7201f41664ffa658e90146187ce57ad70b71d11c.tar.xz
kutter-7201f41664ffa658e90146187ce57ad70b71d11c.zip
manual_stepper: Support registering as an additional axis
Add a new G-Code command that can register a manual_stepper as an additional axis on standard G-Code G1 commands. Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
-rw-r--r--docs/G-Codes.md12
-rw-r--r--klippy/extras/manual_stepper.py57
-rw-r--r--test/klippy/manual_stepper.test15
3 files changed, 83 insertions, 1 deletions
diff --git a/docs/G-Codes.md b/docs/G-Codes.md
index b8a0ce69..6d69dd9c 100644
--- a/docs/G-Codes.md
+++ b/docs/G-Codes.md
@@ -968,6 +968,18 @@ scheduled to run after the stepper move completes, however if a manual
stepper move uses SYNC=0 then future G-Code movement commands may run
in parallel with the stepper movement.
+`MANUAL_STEPPER STEPPER=config_name GCODE_AXIS=[A-Z]`: If the
+`GCODE_AXIS` parameter is specified then it configures the stepper
+motor as an extra axis on `G1` move commands. For example, if one
+were to issue a `MANUAL_STEPPER ... GCODE_AXIS=R` command then one
+could issue commands like `G1 X10 Y20 R30` to move the stepper motor.
+The resulting moves will occur synchronously with the associated
+toolhead xyz movements. If the motor is associated with a
+`GCODE_AXIS` then one may no longer issue movements using the above
+`MANUAL_STEPPER` command - one may unregister the stepper with a
+`MANUAL_STEPPER ... GCODE_AXIS=` command to resume manual control of
+the motor.
+
### [mcp4018]
The following command is available when a
diff --git a/klippy/extras/manual_stepper.py b/klippy/extras/manual_stepper.py
index c15ce235..4c24ff75 100644
--- a/klippy/extras/manual_stepper.py
+++ b/klippy/extras/manual_stepper.py
@@ -1,8 +1,9 @@
# Support for a manual controlled stepper
#
-# Copyright (C) 2019-2021 Kevin O'Connor <kevin@koconnor.net>
+# Copyright (C) 2019-2025 Kevin O'Connor <kevin@koconnor.net>
#
# This file may be distributed under the terms of the GNU GPLv3 license.
+import logging
import stepper, chelper
from . import force_move
@@ -28,6 +29,8 @@ class ManualStepper:
self.trapq_finalize_moves = ffi_lib.trapq_finalize_moves
self.rail.setup_itersolve('cartesian_stepper_alloc', b'x')
self.rail.set_trapq(self.trapq)
+ # Registered with toolhead as an axtra axis
+ self.axis_gcode_id = None
# Register commands
stepper_name = config.get_name().split()[1]
gcode = self.printer.lookup_object('gcode')
@@ -88,6 +91,10 @@ class ManualStepper:
triggered, check_trigger)
cmd_MANUAL_STEPPER_help = "Command a manually configured stepper"
def cmd_MANUAL_STEPPER(self, gcmd):
+ if gcmd.get('GCODE_AXIS', None) is not None:
+ return self.command_with_gcode_axis(gcmd)
+ if self.axis_gcode_id is not None:
+ raise gcmd.error("Must unregister from gcode axis first")
enable = gcmd.get_int('ENABLE', None)
if enable is not None:
self.do_enable(enable)
@@ -107,6 +114,54 @@ class ManualStepper:
self.do_move(movepos, speed, accel, sync)
elif gcmd.get_int('SYNC', 0):
self.sync_print_time()
+ # Register as a gcode axis
+ def command_with_gcode_axis(self, gcmd):
+ gcode_move = self.printer.lookup_object("gcode_move")
+ toolhead = self.printer.lookup_object('toolhead')
+ gcode_axis = gcmd.get('GCODE_AXIS').upper()
+ if self.axis_gcode_id is not None:
+ if gcode_axis:
+ raise gcmd.error("Must unregister axis first")
+ # Unregister
+ toolhead.remove_extra_axis(self)
+ toolhead.unregister_step_generator(self.rail.generate_steps)
+ self.axis_gcode_id = None
+ return
+ if (len(gcode_axis) != 1 or not gcode_axis.isupper()
+ or gcode_axis in "XYZEFN"):
+ if not gcode_axis:
+ # Request to unregister already unregistered axis
+ return
+ raise gcmd.error("Not a valid GCODE_AXIS")
+ for ea in toolhead.get_extra_axes():
+ if ea is not None and ea.get_axis_gcode_id() == gcode_axis:
+ raise gcmd.error("Axis '%s' already registered" % (gcode_axis,))
+ self.axis_gcode_id = gcode_axis
+ toolhead.add_extra_axis(self, self.get_position()[0])
+ toolhead.register_step_generator(self.rail.generate_steps)
+ def process_move(self, print_time, move, ea_index):
+ axis_r = move.axes_r[ea_index]
+ start_pos = move.start_pos[ea_index]
+ accel = move.accel * axis_r
+ start_v = move.start_v * axis_r
+ cruise_v = move.cruise_v * axis_r
+ self.trapq_append(self.trapq, print_time,
+ move.accel_t, move.cruise_t, move.decel_t,
+ start_pos, 0., 0.,
+ 1., 0., 0.,
+ start_v, cruise_v, accel)
+ def check_move(self, move, ea_index):
+ # XXX - support out of bounds checks
+ # XXX - support max accel/velocity
+ # XXX - support non-kinematic max accel/velocity
+ pass
+ def calc_junction(self, prev_move, move, ea_index):
+ # XXX - support max instantaneous velocity change
+ return move.max_cruise_v2
+ def get_axis_gcode_id(self):
+ return self.axis_gcode_id
+ def get_trapq(self):
+ return self.trapq
# Toolhead wrappers to support homing
def flush_step_generation(self):
self.sync_print_time()
diff --git a/test/klippy/manual_stepper.test b/test/klippy/manual_stepper.test
index af0d406a..d19c39c5 100644
--- a/test/klippy/manual_stepper.test
+++ b/test/klippy/manual_stepper.test
@@ -22,3 +22,18 @@ M84
# Verify stepper_buzz
STEPPER_BUZZ STEPPER="manual_stepper basic_stepper"
STEPPER_BUZZ STEPPER="manual_stepper homing_stepper"
+
+# Register with g-code
+MANUAL_STEPPER STEPPER=basic_stepper GCODE_AXIS=A
+G28
+G1 X20 Y20 Z10
+G1 A10 X22
+
+# Test unregistering
+MANUAL_STEPPER STEPPER=basic_stepper GCODE_AXIS=
+G1 X15
+
+# Test registering again
+G28
+MANUAL_STEPPER STEPPER=basic_stepper GCODE_AXIS=A
+G1 X20 Y20 Z10 A20