manual_stepper: Implement "drip moves" for manual stepper STOP_ON_ENDSTOP

Currently, `MANUAL_STEPPER STOP_ON_ENDSTOP=1` type commands will move
until hitting the endstop, but it will still always consume the total
amount of move time.  That is, following moves can't be started until
the total possible time of the homing move is completed.

Implement "drip moves" so that the code only schedules the movement in
small segments.  This allows following movements to be scheduled
without a significant delay.

Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
Kevin O'Connor 2025-04-12 16:54:49 -04:00
parent 765de72f9e
commit db7a9cf071
3 changed files with 27 additions and 6 deletions

View file

@ -8,6 +8,11 @@ All dates in this document are approximate.
## Changes
20250418: The manual_stepper `STOP_ON_ENDSTOP` feature may now take
less time to complete. Previously, the command would wait the entire
time the move could possibly take even if the endstop triggered
earlier. Now, the command finishes shortly after the endstop trigger.
20250417: SPI devices using "software SPI" are now rate limited.
Previously, the `spi_speed` in the config was ignored and the
transmission speed was only limited by the processing speed of the

View file

@ -55,17 +55,20 @@ class ManualStepper:
self.sync_print_time()
def do_set_position(self, setpos):
self.rail.set_position([setpos, 0., 0.])
def do_move(self, movepos, speed, accel, sync=True):
self.sync_print_time()
def _submit_move(self, movetime, movepos, speed, accel):
cp = self.rail.get_commanded_position()
dist = movepos - cp
axis_r, accel_t, cruise_t, cruise_v = force_move.calc_move_time(
dist, speed, accel)
self.trapq_append(self.trapq, self.next_cmd_time,
self.trapq_append(self.trapq, movetime,
accel_t, cruise_t, accel_t,
cp, 0., 0., axis_r, 0., 0.,
0., cruise_v, accel)
self.next_cmd_time = self.next_cmd_time + accel_t + cruise_t + accel_t
return movetime + accel_t + cruise_t + accel_t
def do_move(self, movepos, speed, accel, sync=True):
self.sync_print_time()
self.next_cmd_time = self._submit_move(self.next_cmd_time, movepos,
speed, accel)
self.rail.generate_steps(self.next_cmd_time)
self.trapq_finalize_moves(self.trapq, self.next_cmd_time + 99999.9,
self.next_cmd_time + 99999.9)
@ -117,7 +120,18 @@ class ManualStepper:
def dwell(self, delay):
self.next_cmd_time += max(0., delay)
def drip_move(self, newpos, speed, drip_completion):
self.do_move(newpos[0], speed, self.homing_accel)
# Submit move to trapq
self.sync_print_time()
maxtime = self._submit_move(self.next_cmd_time, newpos[0],
speed, self.homing_accel)
# Drip updates to motors
toolhead = self.printer.lookup_object('toolhead')
toolhead.drip_update_time(maxtime, drip_completion, self.steppers)
# Clear trapq of any remaining parts of movement
reactor = self.printer.get_reactor()
self.trapq_finalize_moves(self.trapq, reactor.NEVER, 0)
self.rail.set_position([newpos[0], 0., 0.])
self.sync_print_time()
def get_kinematics(self):
return self
def get_steppers(self):

View file

@ -503,7 +503,7 @@ class ToolHead:
def get_extruder(self):
return self.extruder
# Homing "drip move" handling
def drip_update_time(self, next_print_time, drip_completion):
def drip_update_time(self, next_print_time, drip_completion, addstepper=()):
# Transition from "NeedPrime"/"Priming"/main state to "Drip" state
self.special_queuing_state = "Drip"
self.need_check_pause = self.reactor.NEVER
@ -526,6 +526,8 @@ class ToolHead:
npt = min(self.print_time + DRIP_SEGMENT_TIME, next_print_time)
self.note_mcu_movequeue_activity(npt + self.kin_flush_delay,
set_step_gen_time=True)
for stepper in addstepper:
stepper.generate_steps(npt)
self._advance_move_time(npt)
# Exit "Drip" state
self.reactor.update_timer(self.flush_timer, self.reactor.NOW)