Browse Source

Add duplication and auto-park mode for dual x-carriage support.

Robert F-C 10 years ago
parent
commit
9547fb9dfb
5 changed files with 315 additions and 58 deletions
  1. 1
    0
      .gitignore
  2. 25
    3
      Marlin/Configuration_adv.h
  3. 215
    22
      Marlin/Marlin_main.cpp
  4. 64
    30
      Marlin/stepper.cpp
  5. 10
    3
      Marlin/stepper.h

+ 1
- 0
.gitignore View File

3
 *~
3
 *~
4
 *.orig
4
 *.orig
5
 *.rej
5
 *.rej
6
+*.bak

+ 25
- 3
Marlin/Configuration_adv.h View File

155
 // Configuration for second X-carriage
155
 // Configuration for second X-carriage
156
 // Note: the first x-carriage is defined as the x-carriage which homes to the minimum endstop;
156
 // Note: the first x-carriage is defined as the x-carriage which homes to the minimum endstop;
157
 // the second x-carriage always homes to the maximum endstop.
157
 // the second x-carriage always homes to the maximum endstop.
158
-#define X2_MIN_POS 88     // set minimum to ensure second x-carriage doesn't hit the parked first X-carriage
159
-#define X2_MAX_POS 350.45 // set maximum to the distance between toolheads when both heads are homed 
158
+#define X2_MIN_POS 80     // set minimum to ensure second x-carriage doesn't hit the parked first X-carriage
159
+#define X2_MAX_POS 353    // set maximum to the distance between toolheads when both heads are homed 
160
 #define X2_HOME_DIR 1     // the second X-carriage always homes to the maximum endstop position
160
 #define X2_HOME_DIR 1     // the second X-carriage always homes to the maximum endstop position
161
 #define X2_HOME_POS X2_MAX_POS // default home position is the maximum carriage position 
161
 #define X2_HOME_POS X2_MAX_POS // default home position is the maximum carriage position 
162
     // However: In this mode the EXTRUDER_OFFSET_X value for the second extruder provides a software 
162
     // However: In this mode the EXTRUDER_OFFSET_X value for the second extruder provides a software 
169
 #define X2_STEP_PIN 25
169
 #define X2_STEP_PIN 25
170
 #define X2_DIR_PIN 23
170
 #define X2_DIR_PIN 23
171
 
171
 
172
-#endif // DUAL_X_CARRIAGE
172
+// There are a few selectable movement modes for dual x-carriages using M605 S<mode>
173
+//    Mode 0: Full control. The slicer has full control over both x-carriages and can achieve optimal travel results
174
+//                           as long as it supports dual x-carriages. (M605 S0)
175
+//    Mode 1: Auto-park mode. The firmware will automatically park and unpark the x-carriages on tool changes so
176
+//                           that additional slicer support is not required. (M605 S1)
177
+//    Mode 2: Duplication mode. The firmware will transparently make the second x-carriage and extruder copy all  
178
+//                           actions of the first x-carriage. This allows the printer to print 2 arbitrary items at
179
+//                           once. (2nd extruder x offset and temp offset are set using: M605 S2 [Xnnn] [Rmmm])
180
+
181
+// This is the default power-up mode which can be later using M605. 
182
+#define DEFAULT_DUAL_X_CARRIAGE_MODE 0 
183
+
184
+// As the x-carriages are independent we can now account for any relative Z offset
185
+#define EXTRUDER1_Z_OFFSET 0.0           // z offset relative to extruder 0
186
+
187
+// Default settings in "Auto-park Mode" 
188
+#define TOOLCHANGE_PARK_ZLIFT   0.2      // the distance to raise Z axis when parking an extruder
189
+#define TOOLCHANGE_UNPARK_ZLIFT 1        // the distance to raise Z axis when unparking an extruder
190
+
191
+// Default x offset in duplication mode (typically set to half print bed width)
192
+#define DEFAULT_DUPLICATION_X_OFFSET 100
193
+
194
+#endif //DUAL_X_CARRIAGE
173
     
195
     
174
 //homing hits the endstop, then retracts by this distance, before it tries to slowly bump again:
196
 //homing hits the endstop, then retracts by this distance, before it tries to slowly bump again:
175
 #define X_HOME_RETRACT_MM 5 
197
 #define X_HOME_RETRACT_MM 5 

+ 215
- 22
Marlin/Marlin_main.cpp View File

139
 // M503 - print the current settings (from memory not from eeprom)
139
 // M503 - print the current settings (from memory not from eeprom)
140
 // M540 - Use S[0|1] to enable or disable the stop SD card print on endstop hit (requires ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED)
140
 // M540 - Use S[0|1] to enable or disable the stop SD card print on endstop hit (requires ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED)
141
 // M600 - Pause for filament change X[pos] Y[pos] Z[relative lift] E[initial retract] L[later retract distance for removal]
141
 // M600 - Pause for filament change X[pos] Y[pos] Z[relative lift] E[initial retract] L[later retract distance for removal]
142
+// M605 - Set dual x-carriage movement mode: S<mode> [ X<duplication x-offset> R<duplication temp offset> ]
142
 // M907 - Set digital trimpot motor current using axis codes.
143
 // M907 - Set digital trimpot motor current using axis codes.
143
 // M908 - Control digital trimpot directly.
144
 // M908 - Control digital trimpot directly.
144
 // M350 - Set microstepping mode.
145
 // M350 - Set microstepping mode.
168
 float add_homeing[3]={0,0,0};
169
 float add_homeing[3]={0,0,0};
169
 float min_pos[3] = { X_MIN_POS, Y_MIN_POS, Z_MIN_POS };
170
 float min_pos[3] = { X_MIN_POS, Y_MIN_POS, Z_MIN_POS };
170
 float max_pos[3] = { X_MAX_POS, Y_MAX_POS, Z_MAX_POS };
171
 float max_pos[3] = { X_MAX_POS, Y_MAX_POS, Z_MAX_POS };
171
-// Extruder offset, only in XY plane
172
+
173
+// Extruder offset
172
 #if EXTRUDERS > 1
174
 #if EXTRUDERS > 1
173
-float extruder_offset[2][EXTRUDERS] = {
175
+#ifndef DUAL_X_CARRIAGE
176
+  #define NUM_EXTRUDER_OFFSETS 2 // only in XY plane
177
+#else
178
+  #define NUM_EXTRUDER_OFFSETS 3 // supports offsets in XYZ plane
179
+#endif
180
+float extruder_offset[NUM_EXTRUDER_OFFSETS][EXTRUDERS] = {
174
 #if defined(EXTRUDER_OFFSET_X) && defined(EXTRUDER_OFFSET_Y)
181
 #if defined(EXTRUDER_OFFSET_X) && defined(EXTRUDER_OFFSET_Y)
175
   EXTRUDER_OFFSET_X, EXTRUDER_OFFSET_Y
182
   EXTRUDER_OFFSET_X, EXTRUDER_OFFSET_Y
176
 #endif
183
 #endif
691
   #endif
698
   #endif
692
   #if X_HOME_DIR != -1 || X2_HOME_DIR != 1
699
   #if X_HOME_DIR != -1 || X2_HOME_DIR != 1
693
     #error "Please use canonical x-carriage assignment" // the x-carriages are defined by their homing directions
700
     #error "Please use canonical x-carriage assignment" // the x-carriages are defined by their homing directions
694
-  #endif
701
+  #endif  
695
 
702
 
703
+#define DXC_FULL_CONTROL_MODE 0
704
+#define DXC_AUTO_PARK_MODE    1
705
+#define DXC_DUPLICATION_MODE  2
706
+static int dual_x_carriage_mode = DEFAULT_DUAL_X_CARRIAGE_MODE;
707
+ 
696
 static float x_home_pos(int extruder) {
708
 static float x_home_pos(int extruder) {
697
   if (extruder == 0)
709
   if (extruder == 0)
698
     return base_home_pos(X_AXIS) + add_homeing[X_AXIS];
710
     return base_home_pos(X_AXIS) + add_homeing[X_AXIS];
708
   return (extruder == 0) ? X_HOME_DIR : X2_HOME_DIR;
720
   return (extruder == 0) ? X_HOME_DIR : X2_HOME_DIR;
709
 }
721
 }
710
 
722
 
711
-static float inactive_x_carriage_pos = X2_MAX_POS;
712
-#endif
723
+static float inactive_extruder_x_pos = X2_MAX_POS; // used in mode 0 & 1
724
+static bool active_extruder_parked = false; // used in mode 1 & 2
725
+static float raised_parked_position[NUM_AXIS]; // used in mode 1 
726
+static unsigned long delayed_move_time = 0; // used in mode 1 
727
+static float duplicate_extruder_x_offset = DEFAULT_DUPLICATION_X_OFFSET; // used in mode 2
728
+static float duplicate_extruder_temp_offset = 0; // used in mode 2
729
+bool extruder_duplication_enabled = false; // used in mode 2
730
+#endif //DUAL_X_CARRIAGE    
713
 
731
 
714
 static void axis_is_at_home(int axis) {
732
 static void axis_is_at_home(int axis) {
715
 #ifdef DUAL_X_CARRIAGE
733
 #ifdef DUAL_X_CARRIAGE
716
-  if (axis == X_AXIS && active_extruder != 0) {
717
-    current_position[X_AXIS] = x_home_pos(active_extruder);
718
-    min_pos[X_AXIS] =          X2_MIN_POS;
719
-    max_pos[X_AXIS] =          max(extruder_offset[X_AXIS][1], X2_MAX_POS);
720
-    return;
734
+  if (axis == X_AXIS) {
735
+    if (active_extruder != 0) {
736
+      current_position[X_AXIS] = x_home_pos(active_extruder);
737
+      min_pos[X_AXIS] =          X2_MIN_POS;
738
+      max_pos[X_AXIS] =          max(extruder_offset[X_AXIS][1], X2_MAX_POS);
739
+      return;
740
+    }
741
+    else if (dual_x_carriage_mode == DXC_DUPLICATION_MODE && active_extruder == 0) {
742
+      current_position[X_AXIS] = base_home_pos(X_AXIS) + add_homeing[X_AXIS];
743
+      min_pos[X_AXIS] =          base_min_pos(X_AXIS) + add_homeing[X_AXIS]; 
744
+      max_pos[X_AXIS] =          min(base_max_pos(X_AXIS) + add_homeing[X_AXIS], 
745
+                                  max(extruder_offset[X_AXIS][1], X2_MAX_POS) - duplicate_extruder_x_offset);
746
+      return;
747
+    }
721
   }
748
   }
722
 #endif
749
 #endif
723
   current_position[axis] = base_home_pos(axis) + add_homeing[axis];
750
   current_position[axis] = base_home_pos(axis) + add_homeing[axis];
869
       for(int8_t i=0; i < NUM_AXIS; i++) {
896
       for(int8_t i=0; i < NUM_AXIS; i++) {
870
         destination[i] = current_position[i];
897
         destination[i] = current_position[i];
871
       }
898
       }
872
-          feedrate = 0.0;
899
+      feedrate = 0.0;
873
 
900
 
874
 #ifdef DELTA
901
 #ifdef DELTA
875
           // A delta can only safely home all axis at the same time
902
           // A delta can only safely home all axis at the same time
920
         int x_axis_home_dir = home_dir(X_AXIS);
947
         int x_axis_home_dir = home_dir(X_AXIS);
921
        #else
948
        #else
922
         int x_axis_home_dir = x_home_dir(active_extruder);
949
         int x_axis_home_dir = x_home_dir(active_extruder);
950
+        extruder_duplication_enabled = false;
923
        #endif
951
        #endif
924
 
952
 
925
         plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
953
         plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
950
       {
978
       {
951
       #ifdef DUAL_X_CARRIAGE
979
       #ifdef DUAL_X_CARRIAGE
952
         int tmp_extruder = active_extruder;
980
         int tmp_extruder = active_extruder;
981
+        extruder_duplication_enabled = false;
953
         active_extruder = !active_extruder;
982
         active_extruder = !active_extruder;
954
         HOMEAXIS(X);
983
         HOMEAXIS(X);
955
-        inactive_x_carriage_pos = current_position[X_AXIS];
984
+        inactive_extruder_x_pos = current_position[X_AXIS];
956
         active_extruder = tmp_extruder;
985
         active_extruder = tmp_extruder;
957
-      #endif
958
         HOMEAXIS(X);
986
         HOMEAXIS(X);
987
+        // reset state used by the different modes
988
+        memcpy(raised_parked_position, current_position, sizeof(raised_parked_position));
989
+        delayed_move_time = 0;
990
+        active_extruder_parked = true; 
991
+      #else      
992
+        HOMEAXIS(X);
993
+      #endif         
959
       }
994
       }
960
 
995
 
961
       if((home_all_axis) || (code_seen(axis_codes[Y_AXIS]))) {
996
       if((home_all_axis) || (code_seen(axis_codes[Y_AXIS]))) {
1199
         break;
1234
         break;
1200
       }
1235
       }
1201
       if (code_seen('S')) setTargetHotend(code_value(), tmp_extruder);
1236
       if (code_seen('S')) setTargetHotend(code_value(), tmp_extruder);
1237
+#ifdef DUAL_X_CARRIAGE
1238
+      if (dual_x_carriage_mode == DXC_DUPLICATION_MODE && tmp_extruder == 0)
1239
+        setTargetHotend1(code_value() == 0.0 ? 0.0 : code_value() + duplicate_extruder_temp_offset);
1240
+#endif          
1202
       setWatch();
1241
       setWatch();
1203
       break;
1242
       break;
1204
     case 140: // M140 set bed temp
1243
     case 140: // M140 set bed temp
1252
       #endif
1291
       #endif
1253
       if (code_seen('S')) {
1292
       if (code_seen('S')) {
1254
         setTargetHotend(code_value(), tmp_extruder);
1293
         setTargetHotend(code_value(), tmp_extruder);
1294
+#ifdef DUAL_X_CARRIAGE
1295
+        if (dual_x_carriage_mode == DXC_DUPLICATION_MODE && tmp_extruder == 0)
1296
+          setTargetHotend1(code_value() == 0.0 ? 0.0 : code_value() + duplicate_extruder_temp_offset);
1297
+#endif          
1255
         CooldownNoWait = true;
1298
         CooldownNoWait = true;
1256
       } else if (code_seen('R')) {
1299
       } else if (code_seen('R')) {
1257
         setTargetHotend(code_value(), tmp_extruder);
1300
         setTargetHotend(code_value(), tmp_extruder);
1301
+#ifdef DUAL_X_CARRIAGE
1302
+        if (dual_x_carriage_mode == DXC_DUPLICATION_MODE && tmp_extruder == 0)
1303
+          setTargetHotend1(code_value() == 0.0 ? 0.0 : code_value() + duplicate_extruder_temp_offset);
1304
+#endif          
1258
         CooldownNoWait = false;
1305
         CooldownNoWait = false;
1259
       }
1306
       }
1260
       #ifdef AUTOTEMP
1307
       #ifdef AUTOTEMP
1671
       {
1718
       {
1672
         extruder_offset[Y_AXIS][tmp_extruder] = code_value();
1719
         extruder_offset[Y_AXIS][tmp_extruder] = code_value();
1673
       }
1720
       }
1721
+      #ifdef DUAL_X_CARRIAGE
1722
+      if(code_seen('Z'))
1723
+      {
1724
+        extruder_offset[Z_AXIS][tmp_extruder] = code_value();
1725
+      }
1726
+      #endif       
1674
       SERIAL_ECHO_START;
1727
       SERIAL_ECHO_START;
1675
       SERIAL_ECHOPGM(MSG_HOTEND_OFFSET);
1728
       SERIAL_ECHOPGM(MSG_HOTEND_OFFSET);
1676
       for(tmp_extruder = 0; tmp_extruder < EXTRUDERS; tmp_extruder++)
1729
       for(tmp_extruder = 0; tmp_extruder < EXTRUDERS; tmp_extruder++)
1679
          SERIAL_ECHO(extruder_offset[X_AXIS][tmp_extruder]);
1732
          SERIAL_ECHO(extruder_offset[X_AXIS][tmp_extruder]);
1680
          SERIAL_ECHO(",");
1733
          SERIAL_ECHO(",");
1681
          SERIAL_ECHO(extruder_offset[Y_AXIS][tmp_extruder]);
1734
          SERIAL_ECHO(extruder_offset[Y_AXIS][tmp_extruder]);
1735
+      #ifdef DUAL_X_CARRIAGE
1736
+         SERIAL_ECHO(",");
1737
+         SERIAL_ECHO(extruder_offset[Z_AXIS][tmp_extruder]);
1738
+      #endif
1682
       }
1739
       }
1683
       SERIAL_ECHOLN("");
1740
       SERIAL_ECHOLN("");
1684
     }break;
1741
     }break;
2013
     }
2070
     }
2014
     break;
2071
     break;
2015
     #endif //FILAMENTCHANGEENABLE
2072
     #endif //FILAMENTCHANGEENABLE
2073
+    #ifdef DUAL_X_CARRIAGE
2074
+    case 605: // Set dual x-carriage movement mode:
2075
+              //    M605 S0: Full control mode. The slicer has full control over x-carriage movement
2076
+              //    M605 S1: Auto-park mode. The inactive head will auto park/unpark without slicer involvement
2077
+              //    M605 S2 [Xnnn] [Rmmm]: Duplication mode. The second extruder will duplicate the first with nnn
2078
+              //                         millimeters x-offset and an optional differential hotend temperature of 
2079
+              //                         mmm degrees. E.g., with "M605 S2 X100 R2" the second extruder will duplicate
2080
+              //                         the first with a spacing of 100mm in the x direction and 2 degrees hotter.
2081
+              //
2082
+              //    Note: the X axis should be homed after changing dual x-carriage mode.
2083
+    {
2084
+        st_synchronize();
2085
+        
2086
+        if (code_seen('S'))
2087
+          dual_x_carriage_mode = code_value();
2088
+
2089
+        if (dual_x_carriage_mode == DXC_DUPLICATION_MODE)
2090
+        {
2091
+          if (code_seen('X'))
2092
+            duplicate_extruder_x_offset = max(code_value(),X2_MIN_POS - x_home_pos(0));
2093
+
2094
+          if (code_seen('R'))
2095
+            duplicate_extruder_temp_offset = code_value();
2096
+            
2097
+          SERIAL_ECHO_START;
2098
+          SERIAL_ECHOPGM(MSG_HOTEND_OFFSET);
2099
+          SERIAL_ECHO(" ");
2100
+          SERIAL_ECHO(extruder_offset[X_AXIS][0]);
2101
+          SERIAL_ECHO(",");
2102
+          SERIAL_ECHO(extruder_offset[Y_AXIS][0]);
2103
+          SERIAL_ECHO(" ");
2104
+          SERIAL_ECHO(duplicate_extruder_x_offset);
2105
+          SERIAL_ECHO(",");
2106
+          SERIAL_ECHOLN(extruder_offset[Y_AXIS][1]);
2107
+        }
2108
+        else if (dual_x_carriage_mode != DXC_FULL_CONTROL_MODE && dual_x_carriage_mode != DXC_AUTO_PARK_MODE)
2109
+        {
2110
+          dual_x_carriage_mode = DEFAULT_DUAL_X_CARRIAGE_MODE;
2111
+        }
2112
+        
2113
+        active_extruder_parked = false;
2114
+        extruder_duplication_enabled = false;
2115
+        delayed_move_time = 0;
2116
+    }
2117
+    break;
2118
+    #endif //DUAL_X_CARRIAGE         
2119
+
2016
     case 907: // M907 Set digital trimpot motor current using axis codes.
2120
     case 907: // M907 Set digital trimpot motor current using axis codes.
2017
     {
2121
     {
2018
       #if defined(DIGIPOTSS_PIN) && DIGIPOTSS_PIN > -1
2122
       #if defined(DIGIPOTSS_PIN) && DIGIPOTSS_PIN > -1
2092
         // Save current position to return to after applying extruder offset
2196
         // Save current position to return to after applying extruder offset
2093
         memcpy(destination, current_position, sizeof(destination));
2197
         memcpy(destination, current_position, sizeof(destination));
2094
       #ifdef DUAL_X_CARRIAGE
2198
       #ifdef DUAL_X_CARRIAGE
2095
-        // only apply Y extruder offset in dual x carriage mode (x offset is already used in determining home pos)
2199
+        if (dual_x_carriage_mode == DXC_AUTO_PARK_MODE && Stopped == false && 
2200
+            (delayed_move_time != 0 || current_position[X_AXIS] != x_home_pos(active_extruder)))
2201
+        {
2202
+          // Park old head: 1) raise 2) move to park position 3) lower
2203
+          plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS] + TOOLCHANGE_PARK_ZLIFT, 
2204
+                current_position[E_AXIS], max_feedrate[Z_AXIS], active_extruder);
2205
+          plan_buffer_line(x_home_pos(active_extruder), current_position[Y_AXIS], current_position[Z_AXIS] + TOOLCHANGE_PARK_ZLIFT, 
2206
+                current_position[E_AXIS], max_feedrate[X_AXIS], active_extruder);
2207
+          plan_buffer_line(x_home_pos(active_extruder), current_position[Y_AXIS], current_position[Z_AXIS], 
2208
+                current_position[E_AXIS], max_feedrate[Z_AXIS], active_extruder);
2209
+          st_synchronize();
2210
+        }
2211
+        
2212
+        // apply Y & Z extruder offset (x offset is already used in determining home pos)
2096
         current_position[Y_AXIS] = current_position[Y_AXIS] -
2213
         current_position[Y_AXIS] = current_position[Y_AXIS] -
2097
                      extruder_offset[Y_AXIS][active_extruder] +
2214
                      extruder_offset[Y_AXIS][active_extruder] +
2098
                      extruder_offset[Y_AXIS][tmp_extruder];
2215
                      extruder_offset[Y_AXIS][tmp_extruder];
2216
+        current_position[Z_AXIS] = current_position[Z_AXIS] -
2217
+                     extruder_offset[Z_AXIS][active_extruder] +
2218
+                     extruder_offset[Z_AXIS][tmp_extruder];
2219
+                     
2220
+        active_extruder = tmp_extruder;
2099
 
2221
 
2100
-        float tmp_x_pos = current_position[X_AXIS];
2222
+        // This function resets the max/min values - the current position may be overwritten below.
2223
+        axis_is_at_home(X_AXIS);
2101
 
2224
 
2102
-        // Set the new active extruder and position
2103
-        active_extruder = tmp_extruder;
2104
-        axis_is_at_home(X_AXIS); //this function updates X min/max values.
2105
-        current_position[X_AXIS] = inactive_x_carriage_pos;
2106
-        inactive_x_carriage_pos = tmp_x_pos;
2107
-      #else
2225
+        if (dual_x_carriage_mode == DXC_FULL_CONTROL_MODE)
2226
+        {
2227
+          current_position[X_AXIS] = inactive_extruder_x_pos; 
2228
+          inactive_extruder_x_pos = destination[X_AXIS];
2229
+        }
2230
+        else if (dual_x_carriage_mode == DXC_DUPLICATION_MODE)
2231
+        {
2232
+          active_extruder_parked = (active_extruder == 0); // this triggers the second extruder to move into the duplication position
2233
+          if (active_extruder == 0 || active_extruder_parked)
2234
+            current_position[X_AXIS] = inactive_extruder_x_pos; 
2235
+          else
2236
+            current_position[X_AXIS] = destination[X_AXIS] + duplicate_extruder_x_offset; 
2237
+          inactive_extruder_x_pos = destination[X_AXIS];
2238
+          extruder_duplication_enabled = false; 
2239
+        }
2240
+        else
2241
+        {
2242
+          // record raised toolhead position for use by unpark
2243
+          memcpy(raised_parked_position, current_position, sizeof(raised_parked_position));
2244
+          raised_parked_position[Z_AXIS] += TOOLCHANGE_UNPARK_ZLIFT;
2245
+          active_extruder_parked = true;
2246
+          delayed_move_time = 0;
2247
+        }
2248
+      #else    
2108
         // Offset extruder (only by XY)
2249
         // Offset extruder (only by XY)
2109
         int i;
2250
         int i;
2110
         for(i = 0; i < 2; i++) {
2251
         for(i = 0; i < 2; i++) {
2309
                      active_extruder);
2450
                      active_extruder);
2310
   }
2451
   }
2311
 #else
2452
 #else
2453
+
2454
+#ifdef DUAL_X_CARRIAGE
2455
+  if (active_extruder_parked)
2456
+  {
2457
+    if (dual_x_carriage_mode == DXC_DUPLICATION_MODE && active_extruder == 0)
2458
+    {
2459
+      // move duplicate extruder into correct duplication position.
2460
+      plan_set_position(inactive_extruder_x_pos, current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
2461
+      plan_buffer_line(current_position[X_AXIS] + duplicate_extruder_x_offset, current_position[Y_AXIS], current_position[Z_AXIS], 
2462
+          current_position[E_AXIS], max_feedrate[X_AXIS], 1);
2463
+      plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
2464
+      st_synchronize();
2465
+      extruder_duplication_enabled = true;
2466
+      active_extruder_parked = false;
2467
+    }  
2468
+    else if (dual_x_carriage_mode == DXC_AUTO_PARK_MODE) // handle unparking of head
2469
+    {
2470
+      if (current_position[E_AXIS] == destination[E_AXIS])
2471
+      {
2472
+        // this is a travel move - skit it but keep track of current position (so that it can later
2473
+        // be used as start of first non-travel move)
2474
+        if (delayed_move_time != 0xFFFFFFFFUL)
2475
+        {
2476
+          memcpy(current_position, destination, sizeof(current_position)); 
2477
+          if (destination[Z_AXIS] > raised_parked_position[Z_AXIS])
2478
+            raised_parked_position[Z_AXIS] = destination[Z_AXIS];
2479
+          delayed_move_time = millis();
2480
+          return;
2481
+        }
2482
+      }
2483
+      delayed_move_time = 0;
2484
+      // unpark extruder: 1) raise, 2) move into starting XY position, 3) lower
2485
+      plan_buffer_line(raised_parked_position[X_AXIS], raised_parked_position[Y_AXIS], raised_parked_position[Z_AXIS],    current_position[E_AXIS], max_feedrate[Z_AXIS], active_extruder);
2486
+      plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], raised_parked_position[Z_AXIS], 
2487
+          current_position[E_AXIS], min(max_feedrate[X_AXIS],max_feedrate[Y_AXIS]), active_extruder);
2488
+      plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], 
2489
+          current_position[E_AXIS], max_feedrate[Z_AXIS], active_extruder);
2490
+      active_extruder_parked = false;
2491
+    }
2492
+  }
2493
+#endif //DUAL_X_CARRIAGE
2494
+
2312
   // Do not use feedmultiply for E or Z only moves
2495
   // Do not use feedmultiply for E or Z only moves
2313
   if( (current_position[X_AXIS] == destination [X_AXIS]) && (current_position[Y_AXIS] == destination [Y_AXIS])) {
2496
   if( (current_position[X_AXIS] == destination [X_AXIS]) && (current_position[Y_AXIS] == destination [Y_AXIS])) {
2314
       plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder);
2497
       plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder);
2316
   else {
2499
   else {
2317
     plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate*feedmultiply/60/100.0, active_extruder);
2500
     plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate*feedmultiply/60/100.0, active_extruder);
2318
   }
2501
   }
2319
-#endif
2502
+#endif //else DELTA
2320
   for(int8_t i=0; i < NUM_AXIS; i++) {
2503
   for(int8_t i=0; i < NUM_AXIS; i++) {
2321
     current_position[i] = destination[i];
2504
     current_position[i] = destination[i];
2322
   }
2505
   }
2428
      WRITE(E0_ENABLE_PIN,oldstatus);
2611
      WRITE(E0_ENABLE_PIN,oldstatus);
2429
     }
2612
     }
2430
   #endif
2613
   #endif
2614
+  #if defined(DUAL_X_CARRIAGE)
2615
+    // handle delayed move timeout
2616
+    if (delayed_move_time != 0 && (millis() - delayed_move_time) > 1000 && Stopped == false)
2617
+    {
2618
+      // travel moves have been received so enact them
2619
+      delayed_move_time = 0xFFFFFFFFUL; // force moves to be done
2620
+      memcpy(destination,current_position,sizeof(destination));
2621
+      prepare_move(); 
2622
+    }
2623
+  #endif  
2431
   check_axes_activity();
2624
   check_axes_activity();
2432
 }
2625
 }
2433
 
2626
 

+ 64
- 30
Marlin/stepper.cpp View File

349
     // Set the direction bits (X_AXIS=A_AXIS and Y_AXIS=B_AXIS for COREXY)
349
     // Set the direction bits (X_AXIS=A_AXIS and Y_AXIS=B_AXIS for COREXY)
350
     if((out_bits & (1<<X_AXIS))!=0){
350
     if((out_bits & (1<<X_AXIS))!=0){
351
       #ifdef DUAL_X_CARRIAGE
351
       #ifdef DUAL_X_CARRIAGE
352
-      if (active_extruder != 0)
353
-        WRITE(X2_DIR_PIN,INVERT_X_DIR);
354
-      else
355
-      #endif
352
+        if (extruder_duplication_enabled){
353
+          WRITE(X_DIR_PIN, INVERT_X_DIR);
354
+          WRITE(X2_DIR_PIN, INVERT_X_DIR);
355
+        }
356
+        else{
357
+          if (current_block->active_extruder != 0)
358
+            WRITE(X2_DIR_PIN, INVERT_X_DIR);
359
+          else
360
+            WRITE(X_DIR_PIN, INVERT_X_DIR);
361
+        }
362
+      #else
356
         WRITE(X_DIR_PIN, INVERT_X_DIR);
363
         WRITE(X_DIR_PIN, INVERT_X_DIR);
364
+      #endif        
357
       count_direction[X_AXIS]=-1;
365
       count_direction[X_AXIS]=-1;
358
     }
366
     }
359
     else{
367
     else{
360
       #ifdef DUAL_X_CARRIAGE
368
       #ifdef DUAL_X_CARRIAGE
361
-      if (active_extruder != 0)
362
-        WRITE(X2_DIR_PIN,!INVERT_X_DIR);
363
-      else
364
-      #endif
369
+        if (extruder_duplication_enabled){
370
+          WRITE(X_DIR_PIN, !INVERT_X_DIR);
371
+          WRITE(X2_DIR_PIN, !INVERT_X_DIR);
372
+        }
373
+        else{
374
+          if (current_block->active_extruder != 0)
375
+            WRITE(X2_DIR_PIN, !INVERT_X_DIR);
376
+          else
377
+            WRITE(X_DIR_PIN, !INVERT_X_DIR);
378
+        }
379
+      #else
365
         WRITE(X_DIR_PIN, !INVERT_X_DIR);
380
         WRITE(X_DIR_PIN, !INVERT_X_DIR);
381
+      #endif        
366
       count_direction[X_AXIS]=1;
382
       count_direction[X_AXIS]=1;
367
     }
383
     }
368
     if((out_bits & (1<<Y_AXIS))!=0){
384
     if((out_bits & (1<<Y_AXIS))!=0){
384
       {
400
       {
385
         #ifdef DUAL_X_CARRIAGE
401
         #ifdef DUAL_X_CARRIAGE
386
         // with 2 x-carriages, endstops are only checked in the homing direction for the active extruder
402
         // with 2 x-carriages, endstops are only checked in the homing direction for the active extruder
387
-        if ((active_extruder == 0 && X_HOME_DIR == -1) || (active_extruder != 0 && X2_HOME_DIR == -1))
388
-        #endif
403
+        if ((current_block->active_extruder == 0 && X_HOME_DIR == -1) 
404
+            || (current_block->active_extruder != 0 && X2_HOME_DIR == -1))
405
+        #endif          
389
         {
406
         {
390
           #if defined(X_MIN_PIN) && X_MIN_PIN > -1
407
           #if defined(X_MIN_PIN) && X_MIN_PIN > -1
391
             bool x_min_endstop=(READ(X_MIN_PIN) != X_MIN_ENDSTOP_INVERTING);
408
             bool x_min_endstop=(READ(X_MIN_PIN) != X_MIN_ENDSTOP_INVERTING);
404
       {
421
       {
405
         #ifdef DUAL_X_CARRIAGE
422
         #ifdef DUAL_X_CARRIAGE
406
         // with 2 x-carriages, endstops are only checked in the homing direction for the active extruder
423
         // with 2 x-carriages, endstops are only checked in the homing direction for the active extruder
407
-        if ((active_extruder == 0 && X_HOME_DIR == 1) || (active_extruder != 0 && X2_HOME_DIR == 1))
408
-        #endif
424
+        if ((current_block->active_extruder == 0 && X_HOME_DIR == 1) 
425
+            || (current_block->active_extruder != 0 && X2_HOME_DIR == 1))
426
+        #endif          
409
         {
427
         {
410
           #if defined(X_MAX_PIN) && X_MAX_PIN > -1
428
           #if defined(X_MAX_PIN) && X_MAX_PIN > -1
411
             bool x_max_endstop=(READ(X_MAX_PIN) != X_MAX_ENDSTOP_INVERTING);
429
             bool x_max_endstop=(READ(X_MAX_PIN) != X_MAX_ENDSTOP_INVERTING);
455
 
473
 
456
     if ((out_bits & (1<<Z_AXIS)) != 0) {   // -direction
474
     if ((out_bits & (1<<Z_AXIS)) != 0) {   // -direction
457
       WRITE(Z_DIR_PIN,INVERT_Z_DIR);
475
       WRITE(Z_DIR_PIN,INVERT_Z_DIR);
458
-
459
-	  #ifdef Z_DUAL_STEPPER_DRIVERS
476
+      
477
+      #ifdef Z_DUAL_STEPPER_DRIVERS
460
         WRITE(Z2_DIR_PIN,INVERT_Z_DIR);
478
         WRITE(Z2_DIR_PIN,INVERT_Z_DIR);
461
       #endif
479
       #endif
462
 
480
 
477
     else { // +direction
495
     else { // +direction
478
       WRITE(Z_DIR_PIN,!INVERT_Z_DIR);
496
       WRITE(Z_DIR_PIN,!INVERT_Z_DIR);
479
 
497
 
480
-	  #ifdef Z_DUAL_STEPPER_DRIVERS
498
+      #ifdef Z_DUAL_STEPPER_DRIVERS
481
         WRITE(Z2_DIR_PIN,!INVERT_Z_DIR);
499
         WRITE(Z2_DIR_PIN,!INVERT_Z_DIR);
482
       #endif
500
       #endif
483
 
501
 
529
 
547
 
530
         counter_x += current_block->steps_x;
548
         counter_x += current_block->steps_x;
531
         if (counter_x > 0) {
549
         if (counter_x > 0) {
532
-          #ifdef DUAL_X_CARRIAGE
533
-          if (active_extruder != 0)
534
-            WRITE(X2_STEP_PIN,!INVERT_X_STEP_PIN);
535
-          else
536
-          #endif
550
+        #ifdef DUAL_X_CARRIAGE
551
+          if (extruder_duplication_enabled){
537
             WRITE(X_STEP_PIN, !INVERT_X_STEP_PIN);
552
             WRITE(X_STEP_PIN, !INVERT_X_STEP_PIN);
553
+            WRITE(X2_STEP_PIN, !INVERT_X_STEP_PIN);
554
+          }
555
+          else {
556
+            if (current_block->active_extruder != 0)
557
+              WRITE(X2_STEP_PIN, !INVERT_X_STEP_PIN);
558
+            else
559
+              WRITE(X_STEP_PIN, !INVERT_X_STEP_PIN);
560
+          }
561
+        #else
562
+          WRITE(X_STEP_PIN, !INVERT_X_STEP_PIN);
563
+        #endif        
538
           counter_x -= current_block->step_event_count;
564
           counter_x -= current_block->step_event_count;
539
-          count_position[X_AXIS]+=count_direction[X_AXIS];
540
-          #ifdef DUAL_X_CARRIAGE
541
-          if (active_extruder != 0)
542
-            WRITE(X2_STEP_PIN,INVERT_X_STEP_PIN);
543
-          else
544
-          #endif
565
+          count_position[X_AXIS]+=count_direction[X_AXIS];   
566
+        #ifdef DUAL_X_CARRIAGE
567
+          if (extruder_duplication_enabled){
545
             WRITE(X_STEP_PIN, INVERT_X_STEP_PIN);
568
             WRITE(X_STEP_PIN, INVERT_X_STEP_PIN);
569
+            WRITE(X2_STEP_PIN, INVERT_X_STEP_PIN);
570
+          }
571
+          else {
572
+            if (current_block->active_extruder != 0)
573
+              WRITE(X2_STEP_PIN, INVERT_X_STEP_PIN);
574
+            else
575
+              WRITE(X_STEP_PIN, INVERT_X_STEP_PIN);
576
+          }
577
+        #else
578
+          WRITE(X_STEP_PIN, INVERT_X_STEP_PIN);
579
+        #endif
546
         }
580
         }
547
 
581
 
548
         counter_y += current_block->steps_y;
582
         counter_y += current_block->steps_y;
556
       counter_z += current_block->steps_z;
590
       counter_z += current_block->steps_z;
557
       if (counter_z > 0) {
591
       if (counter_z > 0) {
558
         WRITE(Z_STEP_PIN, !INVERT_Z_STEP_PIN);
592
         WRITE(Z_STEP_PIN, !INVERT_Z_STEP_PIN);
559
-
560
-		#ifdef Z_DUAL_STEPPER_DRIVERS
593
+        
594
+        #ifdef Z_DUAL_STEPPER_DRIVERS
561
           WRITE(Z2_STEP_PIN, !INVERT_Z_STEP_PIN);
595
           WRITE(Z2_STEP_PIN, !INVERT_Z_STEP_PIN);
562
         #endif
596
         #endif
563
 
597
 
564
         counter_z -= current_block->step_event_count;
598
         counter_z -= current_block->step_event_count;
565
         count_position[Z_AXIS]+=count_direction[Z_AXIS];
599
         count_position[Z_AXIS]+=count_direction[Z_AXIS];
566
         WRITE(Z_STEP_PIN, INVERT_Z_STEP_PIN);
600
         WRITE(Z_STEP_PIN, INVERT_Z_STEP_PIN);
567
-
568
-		#ifdef Z_DUAL_STEPPER_DRIVERS
601
+        
602
+        #ifdef Z_DUAL_STEPPER_DRIVERS
569
           WRITE(Z2_STEP_PIN, INVERT_Z_STEP_PIN);
603
           WRITE(Z2_STEP_PIN, INVERT_Z_STEP_PIN);
570
         #endif
604
         #endif
571
       }
605
       }

+ 10
- 3
Marlin/stepper.h View File

28
   #define NORM_E_DIR() { if(current_block->active_extruder == 2) { WRITE(E2_DIR_PIN, !INVERT_E2_DIR); } else { if(current_block->active_extruder == 1) { WRITE(E1_DIR_PIN, !INVERT_E1_DIR); } else { WRITE(E0_DIR_PIN, !INVERT_E0_DIR); }}}
28
   #define NORM_E_DIR() { if(current_block->active_extruder == 2) { WRITE(E2_DIR_PIN, !INVERT_E2_DIR); } else { if(current_block->active_extruder == 1) { WRITE(E1_DIR_PIN, !INVERT_E1_DIR); } else { WRITE(E0_DIR_PIN, !INVERT_E0_DIR); }}}
29
   #define REV_E_DIR() { if(current_block->active_extruder == 2) { WRITE(E2_DIR_PIN, INVERT_E2_DIR); } else { if(current_block->active_extruder == 1) { WRITE(E1_DIR_PIN, INVERT_E1_DIR); } else { WRITE(E0_DIR_PIN, INVERT_E0_DIR); }}}
29
   #define REV_E_DIR() { if(current_block->active_extruder == 2) { WRITE(E2_DIR_PIN, INVERT_E2_DIR); } else { if(current_block->active_extruder == 1) { WRITE(E1_DIR_PIN, INVERT_E1_DIR); } else { WRITE(E0_DIR_PIN, INVERT_E0_DIR); }}}
30
 #elif EXTRUDERS > 1
30
 #elif EXTRUDERS > 1
31
-  #define WRITE_E_STEP(v) { if(current_block->active_extruder == 1) { WRITE(E1_STEP_PIN, v); } else { WRITE(E0_STEP_PIN, v); }}
32
-  #define NORM_E_DIR() { if(current_block->active_extruder == 1) { WRITE(E1_DIR_PIN, !INVERT_E1_DIR); } else { WRITE(E0_DIR_PIN, !INVERT_E0_DIR); }}
33
-  #define REV_E_DIR() { if(current_block->active_extruder == 1) { WRITE(E1_DIR_PIN, INVERT_E1_DIR); } else { WRITE(E0_DIR_PIN, INVERT_E0_DIR); }}
31
+  #ifndef DUAL_X_CARRIAGE
32
+    #define WRITE_E_STEP(v) { if(current_block->active_extruder == 1) { WRITE(E1_STEP_PIN, v); } else { WRITE(E0_STEP_PIN, v); }}
33
+    #define NORM_E_DIR() { if(current_block->active_extruder == 1) { WRITE(E1_DIR_PIN, !INVERT_E1_DIR); } else { WRITE(E0_DIR_PIN, !INVERT_E0_DIR); }}
34
+    #define REV_E_DIR() { if(current_block->active_extruder == 1) { WRITE(E1_DIR_PIN, INVERT_E1_DIR); } else { WRITE(E0_DIR_PIN, INVERT_E0_DIR); }}
35
+  #else
36
+    extern bool extruder_duplication_enabled;
37
+    #define WRITE_E_STEP(v) { if(extruder_duplication_enabled) { WRITE(E0_STEP_PIN, v); WRITE(E1_STEP_PIN, v); } else if(current_block->active_extruder == 1) { WRITE(E1_STEP_PIN, v); } else { WRITE(E0_STEP_PIN, v); }}
38
+    #define NORM_E_DIR() { if(extruder_duplication_enabled) { WRITE(E0_DIR_PIN, !INVERT_E0_DIR); WRITE(E1_DIR_PIN, !INVERT_E1_DIR); } else if(current_block->active_extruder == 1) { WRITE(E1_DIR_PIN, !INVERT_E1_DIR); } else { WRITE(E0_DIR_PIN, !INVERT_E0_DIR); }}
39
+    #define REV_E_DIR() { if(extruder_duplication_enabled) { WRITE(E0_DIR_PIN, INVERT_E0_DIR); WRITE(E1_DIR_PIN, INVERT_E1_DIR); } else if(current_block->active_extruder == 1) { WRITE(E1_DIR_PIN, INVERT_E1_DIR); } else { WRITE(E0_DIR_PIN, INVERT_E0_DIR); }}
40
+  #endif  
34
 #else
41
 #else
35
   #define WRITE_E_STEP(v) WRITE(E0_STEP_PIN, v)
42
   #define WRITE_E_STEP(v) WRITE(E0_STEP_PIN, v)
36
   #define NORM_E_DIR() WRITE(E0_DIR_PIN, !INVERT_E0_DIR)
43
   #define NORM_E_DIR() WRITE(E0_DIR_PIN, !INVERT_E0_DIR)

Loading…
Cancel
Save