From a6feb58837fa97167f5340abaa7b1175ca858450 Mon Sep 17 00:00:00 2001
From: Scott Lahteine <thinkyhead@users.noreply.github.com>
Date: Fri, 16 Mar 2018 00:46:42 -0500
Subject: [PATCH] Delta support for multiple hotends with offsets (#10118)

---
 Marlin/src/gcode/calibrate/G28.cpp      |  6 ++++--
 Marlin/src/gcode/config/M218.cpp        |  5 +++++
 Marlin/src/gcode/feature/pause/M125.cpp |  2 +-
 Marlin/src/gcode/feature/pause/M600.cpp |  2 +-
 Marlin/src/module/delta.cpp             | 27 +++++++++++++++++--------
 Marlin/src/module/motion.cpp            |  2 +-
 Marlin/src/module/tool_change.cpp       | 17 ++++++++++++++--
 7 files changed, 46 insertions(+), 15 deletions(-)

diff --git a/Marlin/src/gcode/calibrate/G28.cpp b/Marlin/src/gcode/calibrate/G28.cpp
index 44950b7868..e15ddb5e58 100644
--- a/Marlin/src/gcode/calibrate/G28.cpp
+++ b/Marlin/src/gcode/calibrate/G28.cpp
@@ -191,7 +191,9 @@ void GcodeSuite::G28(const bool always_home_all) {
 
   // Always home with tool 0 active
   #if HOTENDS > 1
-    const uint8_t old_tool_index = active_extruder;
+    #if DISABLED(DELTA) || ENABLED(DELTA_HOME_TO_SAFE_ZONE)
+      const uint8_t old_tool_index = active_extruder;
+    #endif
     tool_change(0, 0, true);
   #endif
 
@@ -331,7 +333,7 @@ void GcodeSuite::G28(const bool always_home_all) {
   clean_up_after_endstop_or_probe_move();
 
   // Restore the active tool after homing
-  #if HOTENDS > 1
+  #if HOTENDS > 1 && (DISABLED(DELTA) || ENABLED(DELTA_HOME_TO_SAFE_ZONE))
     #if ENABLED(PARKING_EXTRUDER)
       #define NO_FETCH false // fetch the previous toolhead
     #else
diff --git a/Marlin/src/gcode/config/M218.cpp b/Marlin/src/gcode/config/M218.cpp
index 144abb2899..80e04694fc 100644
--- a/Marlin/src/gcode/config/M218.cpp
+++ b/Marlin/src/gcode/config/M218.cpp
@@ -70,6 +70,11 @@ void GcodeSuite::M218() {
     }
     SERIAL_EOL();
   }
+
+  #if ENABLED(DELTA)
+    if (target_extruder == active_extruder)
+      do_blocking_move_to_xy(current_position[X_AXIS], current_position[Y_AXIS], planner.max_feedrate_mm_s[X_AXIS]);
+  #endif
 }
 
 #endif // HOTENDS > 1
diff --git a/Marlin/src/gcode/feature/pause/M125.cpp b/Marlin/src/gcode/feature/pause/M125.cpp
index 735f40f3a5..f25b0907da 100644
--- a/Marlin/src/gcode/feature/pause/M125.cpp
+++ b/Marlin/src/gcode/feature/pause/M125.cpp
@@ -65,7 +65,7 @@ void GcodeSuite::M125() {
   // Lift Z axis
   if (parser.seenval('Z')) park_point.z = parser.linearval('Z');
 
-  #if HOTENDS > 1 && DISABLED(DUAL_X_CARRIAGE)
+  #if HOTENDS > 1 && DISABLED(DUAL_X_CARRIAGE) && DISABLED(DELTA)
     park_point.x += (active_extruder ? hotend_offset[X_AXIS][active_extruder] : 0);
     park_point.y += (active_extruder ? hotend_offset[Y_AXIS][active_extruder] : 0);
   #endif
diff --git a/Marlin/src/gcode/feature/pause/M600.cpp b/Marlin/src/gcode/feature/pause/M600.cpp
index dd7a773598..2a34f5baa4 100644
--- a/Marlin/src/gcode/feature/pause/M600.cpp
+++ b/Marlin/src/gcode/feature/pause/M600.cpp
@@ -87,7 +87,7 @@ void GcodeSuite::M600() {
   // Lift Z axis
   if (parser.seenval('Z')) park_point.z = parser.linearval('Z');
 
-  #if HOTENDS > 1 && DISABLED(DUAL_X_CARRIAGE)
+  #if HOTENDS > 1 && DISABLED(DUAL_X_CARRIAGE) && DISABLED(DELTA)
     park_point.x += (active_extruder ? hotend_offset[X_AXIS][active_extruder] : 0);
     park_point.y += (active_extruder ? hotend_offset[Y_AXIS][active_extruder] : 0);
   #endif
diff --git a/Marlin/src/module/delta.cpp b/Marlin/src/module/delta.cpp
index d93bbdc76e..4c17bf901d 100644
--- a/Marlin/src/module/delta.cpp
+++ b/Marlin/src/module/delta.cpp
@@ -115,18 +115,29 @@ void recalc_delta_settings() {
   }
 #endif
 
-#define DELTA_DEBUG() do { \
-    SERIAL_ECHOPAIR("cartesian X:", raw[X_AXIS]); \
-    SERIAL_ECHOPAIR(" Y:", raw[Y_AXIS]);          \
-    SERIAL_ECHOLNPAIR(" Z:", raw[Z_AXIS]);        \
+#define DELTA_DEBUG(VAR) do { \
+    SERIAL_ECHOPAIR("cartesian X:", VAR[X_AXIS]); \
+    SERIAL_ECHOPAIR(" Y:", VAR[Y_AXIS]);          \
+    SERIAL_ECHOLNPAIR(" Z:", VAR[Z_AXIS]);        \
     SERIAL_ECHOPAIR("delta A:", delta[A_AXIS]);   \
     SERIAL_ECHOPAIR(" B:", delta[B_AXIS]);        \
     SERIAL_ECHOLNPAIR(" C:", delta[C_AXIS]);      \
   }while(0)
 
 void inverse_kinematics(const float raw[XYZ]) {
-  DELTA_IK(raw);
-  // DELTA_DEBUG();
+  #if HOTENDS > 1
+    // Delta hotend offsets must be applied in Cartesian space with no "spoofing"
+    const float pos[XYZ] = {
+      raw[X_AXIS] - hotend_offset[X_AXIS][active_extruder],
+      raw[Y_AXIS] - hotend_offset[Y_AXIS][active_extruder],
+      raw[Z_AXIS]
+    };
+    DELTA_IK(pos);
+    //DELTA_DEBUG(pos);
+  #else
+    DELTA_IK(raw);
+    //DELTA_DEBUG(raw);
+  #endif
 }
 
 /**
@@ -136,10 +147,10 @@ void inverse_kinematics(const float raw[XYZ]) {
 float delta_safe_distance_from_top() {
   float cartesian[XYZ] = { 0, 0, 0 };
   inverse_kinematics(cartesian);
-  float distance = delta[A_AXIS];
+  float centered_extent = delta[A_AXIS];
   cartesian[Y_AXIS] = DELTA_PRINTABLE_RADIUS;
   inverse_kinematics(cartesian);
-  return FABS(distance - delta[A_AXIS]);
+  return FABS(centered_extent - delta[A_AXIS]);
 }
 
 /**
diff --git a/Marlin/src/module/motion.cpp b/Marlin/src/module/motion.cpp
index f3ec0dfe7e..f38e7a610a 100644
--- a/Marlin/src/module/motion.cpp
+++ b/Marlin/src/module/motion.cpp
@@ -610,7 +610,7 @@ float soft_endstop_min[XYZ] = { X_MIN_BED, Y_MIN_BED, Z_MIN_POS },
 
       LOOP_XYZE(i) raw[i] += segment_distance[i];
 
-      #if ENABLED(DELTA)
+      #if ENABLED(DELTA) && HOTENDS < 2
         DELTA_IK(raw); // Delta can inline its kinematics
       #else
         inverse_kinematics(raw);
diff --git a/Marlin/src/module/tool_change.cpp b/Marlin/src/module/tool_change.cpp
index 83cff7a641..93a16442b2 100644
--- a/Marlin/src/module/tool_change.cpp
+++ b/Marlin/src/module/tool_change.cpp
@@ -382,7 +382,7 @@ void tool_change(const uint8_t tmp_extruder, const float fr_mm_s/*=0.0*/, bool n
             const float z_diff = hotend_offset[Z_AXIS][active_extruder] - hotend_offset[Z_AXIS][tmp_extruder],
                         z_raise = 0.3 + (z_diff > 0.0 ? z_diff : 0.0);
 
-            // Always raise by some amount (destination copied from current_position earlier)
+            // Always raise by some amount
             current_position[Z_AXIS] += z_raise;
             planner.buffer_line_kinematic(current_position, planner.max_feedrate_mm_s[Z_AXIS], active_extruder);
             move_nozzle_servo(tmp_extruder);
@@ -492,11 +492,24 @@ void tool_change(const uint8_t tmp_extruder, const float fr_mm_s/*=0.0*/, bool n
         // Tell the planner the new "current position"
         SYNC_PLAN_POSITION_KINEMATIC();
 
+        #if ENABLED(DELTA)
+          //LOOP_XYZ(i) update_software_endstops(i); // or modify the constrain function
+          // Do a small lift to avoid the workpiece in the move back (below)
+          const bool safe_to_move = current_position[Z_AXIS] < delta_clip_start_height - 1;
+          if (safe_to_move && !no_move && IsRunning()) {
+            ++current_position[Z_AXIS];
+            planner.buffer_line_kinematic(current_position, planner.max_feedrate_mm_s[Z_AXIS], active_extruder);
+          }
+        #else
+          constexpr bool safe_to_move = true;
+        #endif
+ 
         // Move to the "old position" (move the extruder into place)
         #if ENABLED(SWITCHING_NOZZLE)
           destination[Z_AXIS] += z_diff;  // Include the Z restore with the "move back"
         #endif
-        if (!no_move && IsRunning()) {
+
+        if (safe_to_move && !no_move && IsRunning()) {
           #if ENABLED(DEBUG_LEVELING_FEATURE)
             if (DEBUGGING(LEVELING)) DEBUG_POS("Move back", destination);
           #endif
-- 
GitLab