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 ## 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. 20250417: SPI devices using "software SPI" are now rate limited.
Previously, the `spi_speed` in the config was ignored and the Previously, the `spi_speed` in the config was ignored and the
transmission speed was only limited by the processing speed of the transmission speed was only limited by the processing speed of the

View File

@ -55,17 +55,20 @@ class ManualStepper:
self.sync_print_time() self.sync_print_time()
def do_set_position(self, setpos): def do_set_position(self, setpos):
self.rail.set_position([setpos, 0., 0.]) self.rail.set_position([setpos, 0., 0.])
def do_move(self, movepos, speed, accel, sync=True): def _submit_move(self, movetime, movepos, speed, accel):
self.sync_print_time()
cp = self.rail.get_commanded_position() cp = self.rail.get_commanded_position()
dist = movepos - cp dist = movepos - cp
axis_r, accel_t, cruise_t, cruise_v = force_move.calc_move_time( axis_r, accel_t, cruise_t, cruise_v = force_move.calc_move_time(
dist, speed, accel) dist, speed, accel)
self.trapq_append(self.trapq, self.next_cmd_time, self.trapq_append(self.trapq, movetime,
accel_t, cruise_t, accel_t, accel_t, cruise_t, accel_t,
cp, 0., 0., axis_r, 0., 0., cp, 0., 0., axis_r, 0., 0.,
0., cruise_v, accel) 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.rail.generate_steps(self.next_cmd_time)
self.trapq_finalize_moves(self.trapq, self.next_cmd_time + 99999.9, self.trapq_finalize_moves(self.trapq, self.next_cmd_time + 99999.9,
self.next_cmd_time + 99999.9) self.next_cmd_time + 99999.9)
@ -117,7 +120,18 @@ class ManualStepper:
def dwell(self, delay): def dwell(self, delay):
self.next_cmd_time += max(0., delay) self.next_cmd_time += max(0., delay)
def drip_move(self, newpos, speed, drip_completion): 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): def get_kinematics(self):
return self return self
def get_steppers(self): def get_steppers(self):

View File

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