mcu: Support multi-mcu homing
Support endstops and probes attached to a different micro-controller than their associated steppers. Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
parent
2e131497ca
commit
950477849d
|
@ -119,7 +119,9 @@ different names for the stepper (eg, `stepper_x` vs `stepper_a`).
|
||||||
Below are common stepper definitions.
|
Below are common stepper definitions.
|
||||||
|
|
||||||
See the [rotation distance document](Rotation_Distance.md) for
|
See the [rotation distance document](Rotation_Distance.md) for
|
||||||
information on calculating the `rotation_distance` parameter.
|
information on calculating the `rotation_distance` parameter. See the
|
||||||
|
[Multi-MCU homing](Multi_MCU_Homing.md) document for information on
|
||||||
|
homing using multiple micro-controllers.
|
||||||
|
|
||||||
```
|
```
|
||||||
[stepper_x]
|
[stepper_x]
|
||||||
|
@ -152,8 +154,10 @@ microsteps:
|
||||||
# distance the axis travels for one full rotation of the final gear.
|
# distance the axis travels for one full rotation of the final gear.
|
||||||
# The default is to not use a gear ratio.
|
# The default is to not use a gear ratio.
|
||||||
endstop_pin:
|
endstop_pin:
|
||||||
# Endstop switch detection pin. This parameter must be provided for
|
# Endstop switch detection pin. If this endstop pin is on a
|
||||||
# the X, Y, and Z steppers on cartesian style printers.
|
# different mcu than the stepper motor then it enables "multi-mcu
|
||||||
|
# homing". This parameter must be provided for the X, Y, and Z
|
||||||
|
# steppers on cartesian style printers.
|
||||||
#position_min: 0
|
#position_min: 0
|
||||||
# Minimum valid distance (in mm) the user may command the stepper to
|
# Minimum valid distance (in mm) the user may command the stepper to
|
||||||
# move to. The default is 0mm.
|
# move to. The default is 0mm.
|
||||||
|
@ -1611,7 +1615,9 @@ stepper_z config section.
|
||||||
```
|
```
|
||||||
[probe]
|
[probe]
|
||||||
pin:
|
pin:
|
||||||
# Probe detection pin. This parameter must be provided.
|
# Probe detection pin. If the pin is on a different microcontroller
|
||||||
|
# than the Z steppers then it enables "multi-mcu homing". This
|
||||||
|
# parameter must be provided.
|
||||||
#deactivate_on_each_sample: True
|
#deactivate_on_each_sample: True
|
||||||
# This determines if Klipper should execute deactivation gcode
|
# This determines if Klipper should execute deactivation gcode
|
||||||
# between each probe attempt when performing a multiple probe
|
# between each probe attempt when performing a multiple probe
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
# Multiple Micro-controller Homing and Probing
|
||||||
|
|
||||||
|
Klipper supports a mechanism for homing with an endstop attached to
|
||||||
|
one micro-controller while its stepper motors are on a different
|
||||||
|
micro-controller. This support is referred to as "multi-mcu
|
||||||
|
homing". This feature is also used when a Z probe is on a different
|
||||||
|
micro-controller than the Z stepper motors.
|
||||||
|
|
||||||
|
This feature can be useful to simplify wiring, as it may be more
|
||||||
|
convenient to attach an endstop or probe to a closer micro-controller.
|
||||||
|
However, using this feature may result in "overshoot" of the stepper
|
||||||
|
motors during homing and probing operations.
|
||||||
|
|
||||||
|
The overshoot occurs due to possible message transmission delays
|
||||||
|
between the micro-controller monitoring the endstop and the
|
||||||
|
micro-controllers moving the stepper motors. The Klipper code is
|
||||||
|
designed to limit this delay to no more than 25ms. (When multi-mcu
|
||||||
|
homing is activated, the micro-controllers send periodic status
|
||||||
|
messages and check that corresponding status messages are received
|
||||||
|
within 25ms.)
|
||||||
|
|
||||||
|
So, for example, if homing at 10mm/s then it is possible for an
|
||||||
|
overshoot of up to 0.250mm (10mm/s * .025s == 0.250mm). Care should be
|
||||||
|
taken when configuring multi-mcu homing to account for this type of
|
||||||
|
overshoot. Using slower homing or probing speeds can reduce the
|
||||||
|
overshoot.
|
||||||
|
|
||||||
|
Stepper motor overshoot should not adversely impact the precision of
|
||||||
|
the homing and probing procedure. The Klipper code will detect the
|
||||||
|
overshoot and account for it in its calculations. However, it is
|
||||||
|
important that the hardware design is capable of handling overshoot
|
||||||
|
without causing damage to the machine.
|
||||||
|
|
||||||
|
Should Klipper detect a communication issue between micro-controllers
|
||||||
|
during multi-mcu homing then it will raise a "Communication timeout
|
||||||
|
during homing" error.
|
||||||
|
|
||||||
|
Note that an axis with multiple steppers (eg, `stepper_z` and
|
||||||
|
`stepper_z1`) need to be on the same micro-controller in order to use
|
||||||
|
multi-mcu homing. For example, if an endstop is on a separate
|
||||||
|
micro-controller from `stepper_z` then `stepper_z1` must be on the
|
||||||
|
same micro-controller as `stepper_z`.
|
|
@ -41,18 +41,19 @@ communication with the Klipper developers.
|
||||||
using adxl345 accelerometer hardware to measure resonance.
|
using adxl345 accelerometer hardware to measure resonance.
|
||||||
- [Pressure advance](Pressure_Advance.md): Calibrate extruder
|
- [Pressure advance](Pressure_Advance.md): Calibrate extruder
|
||||||
pressure.
|
pressure.
|
||||||
- [Slicers](Slicers.md): Configure "slicer" software for Klipper.
|
- [G-Codes](G-Codes.md): Information on commands supported by Klipper.
|
||||||
- [Command Templates](Command_Templates.md): G-Code macros and
|
- [Command Templates](Command_Templates.md): G-Code macros and
|
||||||
conditional evaluation.
|
conditional evaluation.
|
||||||
- [Status Reference](Status_Reference.md): Information available to
|
- [Status Reference](Status_Reference.md): Information available to
|
||||||
macros (and similar).
|
macros (and similar).
|
||||||
- [TMC Drivers](TMC_Drivers.md): Using Trinamic stepper motor drivers
|
- [TMC Drivers](TMC_Drivers.md): Using Trinamic stepper motor drivers
|
||||||
with Klipper.
|
with Klipper.
|
||||||
|
- [Multi-MCU Homing](Multi_MCU_Homing.md): Homing and probing using multiple micro-controllers.
|
||||||
|
- [Slicers](Slicers.md): Configure "slicer" software for Klipper.
|
||||||
- [Skew correction](skew_correction.md): Adjustments for axes not
|
- [Skew correction](skew_correction.md): Adjustments for axes not
|
||||||
perfectly square.
|
perfectly square.
|
||||||
- [PWM tools](Using_PWM_Tools.md): Guide on how to use PWM controlled
|
- [PWM tools](Using_PWM_Tools.md): Guide on how to use PWM controlled
|
||||||
tools such as lasers or spindles.
|
tools such as lasers or spindles.
|
||||||
- [G-Codes](G-Codes.md): Information on commands supported by Klipper.
|
|
||||||
|
|
||||||
## Developer Documentation
|
## Developer Documentation
|
||||||
|
|
||||||
|
|
|
@ -94,14 +94,15 @@ nav:
|
||||||
- Resonance_Compensation.md
|
- Resonance_Compensation.md
|
||||||
- Measuring_Resonances.md
|
- Measuring_Resonances.md
|
||||||
- Pressure_Advance.md
|
- Pressure_Advance.md
|
||||||
- Slicers.md
|
- G-Codes.md
|
||||||
- Command templates:
|
- Command templates:
|
||||||
- Command_Templates.md
|
- Command_Templates.md
|
||||||
- Status_Reference.md
|
- Status_Reference.md
|
||||||
- TMC_Drivers.md
|
- TMC_Drivers.md
|
||||||
|
- Multi_MCU_Homing.md
|
||||||
|
- Slicers.md
|
||||||
- skew_correction.md
|
- skew_correction.md
|
||||||
- Using_PWM_Tools.md
|
- Using_PWM_Tools.md
|
||||||
- G-Codes.md
|
|
||||||
- Developer Documentation:
|
- Developer Documentation:
|
||||||
- Code_Overview.md
|
- Code_Overview.md
|
||||||
- Kinematics.md
|
- Kinematics.md
|
||||||
|
|
|
@ -125,6 +125,9 @@ class MCU_trsync:
|
||||||
s.note_homing_end()
|
s.note_homing_end()
|
||||||
return params['trigger_reason']
|
return params['trigger_reason']
|
||||||
|
|
||||||
|
TRSYNC_TIMEOUT = 0.025
|
||||||
|
TRSYNC_SINGLE_MCU_TIMEOUT = 0.250
|
||||||
|
|
||||||
class MCU_endstop:
|
class MCU_endstop:
|
||||||
RETRY_QUERY = 1.000
|
RETRY_QUERY = 1.000
|
||||||
def __init__(self, mcu, pin_params):
|
def __init__(self, mcu, pin_params):
|
||||||
|
@ -139,15 +142,27 @@ class MCU_endstop:
|
||||||
self._rest_ticks = 0
|
self._rest_ticks = 0
|
||||||
ffi_main, ffi_lib = chelper.get_ffi()
|
ffi_main, ffi_lib = chelper.get_ffi()
|
||||||
self._trdispatch = ffi_main.gc(ffi_lib.trdispatch_alloc(), ffi_lib.free)
|
self._trdispatch = ffi_main.gc(ffi_lib.trdispatch_alloc(), ffi_lib.free)
|
||||||
self._trsync = MCU_trsync(mcu, self._trdispatch)
|
self._trsyncs = [MCU_trsync(mcu, self._trdispatch)]
|
||||||
def get_mcu(self):
|
def get_mcu(self):
|
||||||
return self._mcu
|
return self._mcu
|
||||||
def add_stepper(self, stepper):
|
def add_stepper(self, stepper):
|
||||||
if stepper.get_mcu() is not self._mcu:
|
trsyncs = {trsync.get_mcu(): trsync for trsync in self._trsyncs}
|
||||||
raise pins.error("Endstop and stepper must be on the same mcu")
|
trsync = trsyncs.get(stepper.get_mcu())
|
||||||
self._trsync.add_stepper(stepper)
|
if trsync is None:
|
||||||
|
trsync = MCU_trsync(stepper.get_mcu(), self._trdispatch)
|
||||||
|
self._trsyncs.append(trsync)
|
||||||
|
trsync.add_stepper(stepper)
|
||||||
|
# Check for unsupported multi-mcu shared stepper rails
|
||||||
|
sname = stepper.get_name()
|
||||||
|
if sname.startswith('stepper_'):
|
||||||
|
for ot in self._trsyncs:
|
||||||
|
for s in ot.get_steppers():
|
||||||
|
if ot is not trsync and s.get_name().startswith(sname[:9]):
|
||||||
|
cerror = self._mcu.get_printer().config_error
|
||||||
|
raise cerror("Multi-mcu homing not supported on"
|
||||||
|
" multi-mcu shared axis")
|
||||||
def get_steppers(self):
|
def get_steppers(self):
|
||||||
return self._trsync.get_steppers()
|
return [s for trsync in self._trsyncs for s in trsync.get_steppers()]
|
||||||
def _build_config(self):
|
def _build_config(self):
|
||||||
# Setup config
|
# Setup config
|
||||||
self._mcu.add_config_cmd("config_endstop oid=%d pin=%s pull_up=%d"
|
self._mcu.add_config_cmd("config_endstop oid=%d pin=%s pull_up=%d"
|
||||||
|
@ -157,7 +172,7 @@ class MCU_endstop:
|
||||||
" rest_ticks=0 pin_value=0 trsync_oid=0 trigger_reason=0"
|
" rest_ticks=0 pin_value=0 trsync_oid=0 trigger_reason=0"
|
||||||
% (self._oid,), on_restart=True)
|
% (self._oid,), on_restart=True)
|
||||||
# Lookup commands
|
# Lookup commands
|
||||||
cmd_queue = self._trsync.get_command_queue()
|
cmd_queue = self._trsyncs[0].get_command_queue()
|
||||||
self._home_cmd = self._mcu.lookup_command(
|
self._home_cmd = self._mcu.lookup_command(
|
||||||
"endstop_home oid=%c clock=%u sample_ticks=%u sample_count=%c"
|
"endstop_home oid=%c clock=%u sample_ticks=%u sample_count=%c"
|
||||||
" rest_ticks=%u pin_value=%c trsync_oid=%c trigger_reason=%c",
|
" rest_ticks=%u pin_value=%c trsync_oid=%c trigger_reason=%c",
|
||||||
|
@ -173,8 +188,12 @@ class MCU_endstop:
|
||||||
self._rest_ticks = rest_ticks
|
self._rest_ticks = rest_ticks
|
||||||
reactor = self._mcu.get_printer().get_reactor()
|
reactor = self._mcu.get_printer().get_reactor()
|
||||||
self._trigger_completion = reactor.completion()
|
self._trigger_completion = reactor.completion()
|
||||||
etrsync = self._trsync
|
expire_timeout = TRSYNC_TIMEOUT
|
||||||
etrsync.start(print_time, self._trigger_completion, .250)
|
if len(self._trsyncs) == 1:
|
||||||
|
expire_timeout = TRSYNC_SINGLE_MCU_TIMEOUT
|
||||||
|
for trsync in self._trsyncs:
|
||||||
|
trsync.start(print_time, self._trigger_completion, expire_timeout)
|
||||||
|
etrsync = self._trsyncs[0]
|
||||||
ffi_main, ffi_lib = chelper.get_ffi()
|
ffi_main, ffi_lib = chelper.get_ffi()
|
||||||
ffi_lib.trdispatch_start(self._trdispatch, etrsync.REASON_HOST_REQUEST)
|
ffi_lib.trdispatch_start(self._trdispatch, etrsync.REASON_HOST_REQUEST)
|
||||||
self._home_cmd.send(
|
self._home_cmd.send(
|
||||||
|
@ -183,7 +202,7 @@ class MCU_endstop:
|
||||||
etrsync.get_oid(), etrsync.REASON_ENDSTOP_HIT], reqclock=clock)
|
etrsync.get_oid(), etrsync.REASON_ENDSTOP_HIT], reqclock=clock)
|
||||||
return self._trigger_completion
|
return self._trigger_completion
|
||||||
def home_wait(self, home_end_time):
|
def home_wait(self, home_end_time):
|
||||||
etrsync = self._trsync
|
etrsync = self._trsyncs[0]
|
||||||
etrsync.set_home_end_time(home_end_time)
|
etrsync.set_home_end_time(home_end_time)
|
||||||
if self._mcu.is_fileoutput():
|
if self._mcu.is_fileoutput():
|
||||||
self._trigger_completion.complete(True)
|
self._trigger_completion.complete(True)
|
||||||
|
@ -191,10 +210,10 @@ class MCU_endstop:
|
||||||
self._home_cmd.send([self._oid, 0, 0, 0, 0, 0, 0, 0])
|
self._home_cmd.send([self._oid, 0, 0, 0, 0, 0, 0, 0])
|
||||||
ffi_main, ffi_lib = chelper.get_ffi()
|
ffi_main, ffi_lib = chelper.get_ffi()
|
||||||
ffi_lib.trdispatch_stop(self._trdispatch)
|
ffi_lib.trdispatch_stop(self._trdispatch)
|
||||||
res = etrsync.stop()
|
res = [trsync.stop() for trsync in self._trsyncs]
|
||||||
if res == etrsync.REASON_COMMS_TIMEOUT:
|
if any([r == etrsync.REASON_COMMS_TIMEOUT for r in res]):
|
||||||
return -1.
|
return -1.
|
||||||
if res != etrsync.REASON_ENDSTOP_HIT:
|
if res[0] != etrsync.REASON_ENDSTOP_HIT:
|
||||||
return 0.
|
return 0.
|
||||||
if self._mcu.is_fileoutput():
|
if self._mcu.is_fileoutput():
|
||||||
return home_end_time
|
return home_end_time
|
||||||
|
|
Loading…
Reference in New Issue