From b06762088dd4e2d9988159aba2afd476f621e207 Mon Sep 17 00:00:00 2001 From: Dmitry Butyugin Date: Fri, 4 Aug 2023 01:09:20 +0200 Subject: [PATCH 1/5] idex_modes: Fixed the case when carriages home in the same direction Previous version of the code assumed that dual carriages home away from each other, which is not true on some machines, which have the second dual carriage homing on the first carriage. The new code correctly identifies the relative order of the carriages now. Signed-off-by: Dmitry Butyugin --- klippy/kinematics/idex_modes.py | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/klippy/kinematics/idex_modes.py b/klippy/kinematics/idex_modes.py index b54f96579c9b..fbaa765f3fed 100644 --- a/klippy/kinematics/idex_modes.py +++ b/klippy/kinematics/idex_modes.py @@ -65,7 +65,13 @@ def toggle_active_dc_rail(self, index, override_rail=False): 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 @@ -88,7 +94,7 @@ def get_kin_range(self, toolhead, mode): 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, @@ -105,11 +111,28 @@ def get_kin_range(self, toolhead, mode): 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) 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() From 52bada4f9c630193fa6536c9e741a6082a92e58f Mon Sep 17 00:00:00 2001 From: Dmitry Butyugin Date: Sat, 26 Aug 2023 16:30:22 +0200 Subject: [PATCH 2/5] idex_modes: Disable carriages proximity checks when safe_distance == 0 This fixes discrepancies between the documentation and the actual implementation of the carriages kinematic ranges calculation. Signed-off-by: Dmitry Butyugin --- klippy/kinematics/idex_modes.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/klippy/kinematics/idex_modes.py b/klippy/kinematics/idex_modes.py index fbaa765f3fed..d07775505601 100644 --- a/klippy/kinematics/idex_modes.py +++ b/klippy/kinematics/idex_modes.py @@ -84,9 +84,15 @@ def get_kin_range(self, toolhead, mode): 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, @@ -108,9 +114,6 @@ def get_kin_range(self, toolhead, mode): # 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.get_dc_order(active_idx, inactive_idx) > 0: range_min = max(range_min, axes_pos[inactive_idx] + safe_dist) else: From d7c6fe1c4ef53c5b3885b79607786ef2f7aa34cd Mon Sep 17 00:00:00 2001 From: Dmitry Butyugin Date: Sat, 26 Aug 2023 16:42:44 +0200 Subject: [PATCH 3/5] docs: Notes about dual_carriage homing and proximity checks changes Signed-off-by: Dmitry Butyugin --- docs/Config_Changes.md | 9 +++++++++ docs/Config_Reference.md | 8 ++++++++ 2 files changed, 17 insertions(+) diff --git a/docs/Config_Changes.md b/docs/Config_Changes.md index 063af8ac390f..6d83238d0295 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 d0b617a36e40..f6a2b986faf8 100644 --- a/docs/Config_Reference.md +++ b/docs/Config_Reference.md @@ -2044,6 +2044,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 From ded3f90fc1ba47c6454291d28a9ce7ae73b57c25 Mon Sep 17 00:00:00 2001 From: Dmitry Butyugin Date: Sat, 26 Aug 2023 18:12:54 +0200 Subject: [PATCH 4/5] idex_modes: Fixed clearing of homing state after homing in certain modes In case of multi-MCU homing it is possible that the carriage position will end up outside of the allowed motion range due to latencies in data transmission between MCUs. Selecting certain modes after homing could result in home state clearing instead of blocking the motion of the active carriage. This commit fixes this undesired behavior. Signed-off-by: Dmitry Butyugin --- klippy/kinematics/idex_modes.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/klippy/kinematics/idex_modes.py b/klippy/kinematics/idex_modes.py index d07775505601..d13e3a56e8c9 100644 --- a/klippy/kinematics/idex_modes.py +++ b/klippy/kinematics/idex_modes.py @@ -118,7 +118,16 @@ def get_kin_range(self, toolhead, mode): range_min = max(range_min, axes_pos[inactive_idx] + safe_dist) else: range_max = min(range_max, axes_pos[inactive_idx] - safe_dist) - return (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 the calculated values range_max < range_min + # in certain modes, which would reset homing state instead of just + # blocking the carriage motion until a mode is selected which + # actually permits carriage motion. Using max(range_min, range_max) + # as the upper range end fixes this undesired behavior. + return (range_min, max(range_min, range_max)) def get_dc_order(self, first, second): if first == second: return 0 From 36116eb5d466cd1fddd9dd950a14255531f26b96 Mon Sep 17 00:00:00 2001 From: Dmitry Butyugin Date: Fri, 29 Sep 2023 23:23:07 +0900 Subject: [PATCH 5/5] idex_modes: Updated the code and comments for homing fix A more readable version of ded3f90fc1ba47c6454291d28a9ce7ae73b57c25 --- klippy/kinematics/idex_modes.py | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/klippy/kinematics/idex_modes.py b/klippy/kinematics/idex_modes.py index d13e3a56e8c9..2ce91afe85a5 100644 --- a/klippy/kinematics/idex_modes.py +++ b/klippy/kinematics/idex_modes.py @@ -118,16 +118,18 @@ def get_kin_range(self, toolhead, mode): range_min = max(range_min, axes_pos[inactive_idx] + safe_dist) else: range_max = min(range_max, axes_pos[inactive_idx] - safe_dist) - # 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 the calculated values range_max < range_min - # in certain modes, which would reset homing state instead of just - # blocking the carriage motion until a mode is selected which - # actually permits carriage motion. Using max(range_min, range_max) - # as the upper range end fixes this undesired behavior. - return (range_min, max(range_min, range_max)) + 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