aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/Config_Changes.md9
-rw-r--r--docs/Config_Reference.md8
-rw-r--r--klippy/kinematics/idex_modes.py53
3 files changed, 62 insertions, 8 deletions
diff --git a/docs/Config_Changes.md b/docs/Config_Changes.md
index 063af8ac..6d83238d 100644
--- a/docs/Config_Changes.md
+++ b/docs/Config_Changes.md
@@ -8,6 +8,15 @@ All dates in this document are approximate.
## Changes
+20230826: If `safe_distance` is set or calculated to be 0 in `[dual_carriage]`,
+the carriages proximity checks will be disabled as per documentation. A user
+may wish to configure `safe_distance` explicitly to prevent accidental crashes
+of the carriages with each other. Additionally, the homing order of the primary
+and the dual carriage is changed in some configurations (certain configurations
+when both carriages home in the same direction, see
+[[dual_carriage] configuration reference](./Config_Reference.md#dual_carriage)
+for more details).
+
20230810: The flash-sdcard.sh script now supports both variants of the
Bigtreetech SKR-3, STM32H743 and STM32H723. For this, the original tag
of btt-skr-3 now has changed to be either btt-skr-3-h743 or btt-skr-3-h723.
diff --git a/docs/Config_Reference.md b/docs/Config_Reference.md
index 25e7cc46..24139183 100644
--- a/docs/Config_Reference.md
+++ b/docs/Config_Reference.md
@@ -2065,6 +2065,14 @@ in this section (CARRIAGE=0 will return activation to the primary carriage).
Dual carriage support is typically combined with extra extruders - the
SET_DUAL_CARRIAGE command is often called at the same time as the
ACTIVATE_EXTRUDER command. Be sure to park the carriages during deactivation.
+Note that during G28 homing, typically the primary carriage is homed first
+followed by the carriage defined in the `[dual_carriage]` config section.
+However, the `[dual_carriage]` carriage will be homed first if both carriages
+home in a positive direction and the [dual_carriage] carriage has a
+`position_endstop` greater than the primary carriage, or if both carriages home
+in a negative direction and the `[dual_carriage]` carriage has a
+`position_endstop` less than the primary carriage.
+
Additionally, one could use "SET_DUAL_CARRIAGE CARRIAGE=1 MODE=COPY" or
"SET_DUAL_CARRIAGE CARRIAGE=1 MODE=MIRROR" commands to activate either copying
or mirroring mode of the dual carriage, in which case it will follow the
diff --git a/klippy/kinematics/idex_modes.py b/klippy/kinematics/idex_modes.py
index b54f9657..2ce91afe 100644
--- a/klippy/kinematics/idex_modes.py
+++ b/klippy/kinematics/idex_modes.py
@@ -65,7 +65,13 @@ class DualCarriages:
kin.update_limits(self.axis, target_dc.get_rail().get_range())
def home(self, homing_state):
kin = self.printer.lookup_object('toolhead').get_kinematics()
- for i, dc_rail in enumerate(self.dc):
+ enumerated_dcs = list(enumerate(self.dc))
+ if (self.get_dc_order(0, 1) > 0) != \
+ self.dc[0].get_rail().get_homing_info().positive_dir:
+ # The second carriage must home first, because the carriages home in
+ # the same direction and the first carriage homes on the second one
+ enumerated_dcs.reverse()
+ for i, dc_rail in enumerated_dcs:
self.toggle_active_dc_rail(i, override_rail=True)
kin.home_axis(homing_state, self.axis, dc_rail.get_rail())
# Restore the original rails ordering
@@ -78,9 +84,15 @@ class DualCarriages:
axes_pos = [dc.get_axis_position(pos) for dc in self.dc]
dc0_rail = self.dc[0].get_rail()
dc1_rail = self.dc[1].get_rail()
- range_min = dc0_rail.position_min
- range_max = dc0_rail.position_max
+ if mode != PRIMARY or self.dc[0].is_active():
+ range_min = dc0_rail.position_min
+ range_max = dc0_rail.position_max
+ else:
+ range_min = dc1_rail.position_min
+ range_max = dc1_rail.position_max
safe_dist = self.safe_dist
+ if not safe_dist:
+ return (range_min, range_max)
if mode == COPY:
range_min = max(range_min,
@@ -88,7 +100,7 @@ class DualCarriages:
range_max = min(range_max,
axes_pos[0] - axes_pos[1] + dc1_rail.position_max)
elif mode == MIRROR:
- if dc0_rail.get_homing_info().positive_dir:
+ if self.get_dc_order(0, 1) > 0:
range_min = max(range_min,
0.5 * (sum(axes_pos) + safe_dist))
range_max = min(range_max,
@@ -102,14 +114,39 @@ class DualCarriages:
# mode == PRIMARY
active_idx = 1 if self.dc[1].is_active() else 0
inactive_idx = 1 - active_idx
- if active_idx:
- range_min = dc1_rail.position_min
- range_max = dc1_rail.position_max
- if self.dc[active_idx].get_rail().get_homing_info().positive_dir:
+ if self.get_dc_order(active_idx, inactive_idx) > 0:
range_min = max(range_min, axes_pos[inactive_idx] + safe_dist)
else:
range_max = min(range_max, axes_pos[inactive_idx] - safe_dist)
+ if range_min > range_max:
+ # During multi-MCU homing it is possible that the carriage
+ # position will end up below position_min or above position_max
+ # if position_endstop is too close to the rail motion ends due
+ # to inherent latencies of the data transmission between MCUs.
+ # This can result in an invalid range_min > range_max range
+ # in certain modes, which may confuse the kinematics code.
+ # So, return an empty range instead, which will correctly
+ # block the carriage motion until a different mode is selected
+ # which actually permits carriage motion.
+ return (range_min, range_min)
return (range_min, range_max)
+ def get_dc_order(self, first, second):
+ if first == second:
+ return 0
+ # Check the relative order of the first and second carriages and
+ # return -1 if the first carriage position is always smaller
+ # than the second one and 1 otherwise
+ first_rail = self.dc[first].get_rail()
+ second_rail = self.dc[second].get_rail()
+ first_homing_info = first_rail.get_homing_info()
+ second_homing_info = second_rail.get_homing_info()
+ if first_homing_info.positive_dir != second_homing_info.positive_dir:
+ # Carriages home away from each other
+ return 1 if first_homing_info.positive_dir else -1
+ # Carriages home in the same direction
+ if first_rail.position_endstop > second_rail.position_endstop:
+ return 1
+ return -1
def activate_dc_mode(self, index, mode):
toolhead = self.printer.lookup_object('toolhead')
toolhead.flush_step_generation()