Browse Source

IDEX Improvements (#11848)

Roxy-3D 6 years ago
parent
commit
0780913848

+ 1
- 1
Marlin/src/config/examples/Formbot/T-Rex_2+/Configuration.h View File

22
 
22
 
23
 //#define TREX3              // Turn this on for T-Rex 3 features like dual filament run out sensors
23
 //#define TREX3              // Turn this on for T-Rex 3 features like dual filament run out sensors
24
 
24
 
25
-#define ROXYs_TRex           // Turn this on to get customizations only available on Roxy's T-Rex 2+
25
+//#define ROXYs_TRex         // Turn this on to get customizations only available on Roxy's T-Rex 2+
26
                              // Marlin controlled heat bed, Max7219 debug LED's, less bright LED light level
26
                              // Marlin controlled heat bed, Max7219 debug LED's, less bright LED light level
27
                              // More aggressive PID numbers for hotends (due to double fans)
27
                              // More aggressive PID numbers for hotends (due to double fans)
28
 /**
28
 /**

+ 1
- 3
Marlin/src/config/examples/Formbot/T_Rex_3/Configuration_adv.h View File

385
   //    Mode 2 (DXC_DUPLICATION_MODE) :           Duplication mode. The firmware will transparently make the second x-carriage and extruder copy all
385
   //    Mode 2 (DXC_DUPLICATION_MODE) :           Duplication mode. The firmware will transparently make the second x-carriage and extruder copy all
386
   //                                              actions of the first x-carriage. This allows the printer to print 2 arbitrary items at
386
   //                                              actions of the first x-carriage. This allows the printer to print 2 arbitrary items at
387
   //                                              once. (2nd extruder x offset and temp offset are set using: M605 S2 [Xnnn] [Rmmm])
387
   //                                              once. (2nd extruder x offset and temp offset are set using: M605 S2 [Xnnn] [Rmmm])
388
-  //    Mode 3 (DXC_SYMMETRIC_DUPLICATION_MODE) : Symmetric Duplication mode. The firmware will perform similarly to DXC_DUPLICATION_MODE except in a mirror
389
-  //                                              image of the first x-carriage.  ie. If you are printing a right hand shoe on the 1st extruder, you will
390
-  //                                              get a left hand shoe on the 2nd extruder.
388
+  //    Mode 3 (DXC_SCALED_DUPLICATION_MODE) :    Not working yet, but support routines in place
391
 
389
 
392
   // This is the default power-up mode which can be later using M605.
390
   // This is the default power-up mode which can be later using M605.
393
   #define DEFAULT_DUAL_X_CARRIAGE_MODE DXC_AUTO_PARK_MODE
391
   #define DEFAULT_DUAL_X_CARRIAGE_MODE DXC_AUTO_PARK_MODE

+ 2
- 0
Marlin/src/feature/Max7219_Debug_LEDs.cpp View File

56
 #if _ROT == 0 || _ROT == 270
56
 #if _ROT == 0 || _ROT == 270
57
   #define _LED_BIT(Q)   (7 - ((Q) & 0x7))
57
   #define _LED_BIT(Q)   (7 - ((Q) & 0x7))
58
   #define _LED_UNIT(Q)  ((Q) & ~0x7)
58
   #define _LED_UNIT(Q)  ((Q) & ~0x7)
59
+  //#define _LED_UNIT(Q)  ((MAX7219_NUMBER_UNITS - 1 - ((Q) >> 3)) << 3)  // some Max7219 boards have rotated the matrix
60
+                                                                          // this line can be substituted to correct orientation
59
 #else
61
 #else
60
   #define _LED_BIT(Q)   ((Q) & 0x7)
62
   #define _LED_BIT(Q)   ((Q) & 0x7)
61
   #define _LED_UNIT(Q)  ((MAX7219_NUMBER_UNITS - 1 - ((Q) >> 3)) << 3)
63
   #define _LED_UNIT(Q)  ((MAX7219_NUMBER_UNITS - 1 - ((Q) >> 3)) << 3)

+ 55
- 11
Marlin/src/feature/pause.cpp View File

140
 bool load_filament(const float &slow_load_length/*=0*/, const float &fast_load_length/*=0*/, const float &purge_length/*=0*/, const int8_t max_beep_count/*=0*/,
140
 bool load_filament(const float &slow_load_length/*=0*/, const float &fast_load_length/*=0*/, const float &purge_length/*=0*/, const int8_t max_beep_count/*=0*/,
141
                    const bool show_lcd/*=false*/, const bool pause_for_user/*=false*/,
141
                    const bool show_lcd/*=false*/, const bool pause_for_user/*=false*/,
142
                    const AdvancedPauseMode mode/*=ADVANCED_PAUSE_MODE_PAUSE_PRINT*/
142
                    const AdvancedPauseMode mode/*=ADVANCED_PAUSE_MODE_PAUSE_PRINT*/
143
+                   DXC_ARGS
143
 ) {
144
 ) {
144
   #if DISABLED(ULTIPANEL)
145
   #if DISABLED(ULTIPANEL)
145
     UNUSED(show_lcd);
146
     UNUSED(show_lcd);
184
       lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_LOAD, mode);
185
       lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_LOAD, mode);
185
   #endif
186
   #endif
186
 
187
 
188
+  #if ENABLED(DUAL_X_CARRIAGE)
189
+    const int8_t saved_ext        = active_extruder;
190
+    const bool saved_ext_dup_mode = extruder_duplication_enabled;
191
+    active_extruder = DXC_ext;
192
+    extruder_duplication_enabled = false;
193
+  #endif
194
+
187
   // Slow Load filament
195
   // Slow Load filament
188
   if (slow_load_length) do_pause_e_move(slow_load_length, FILAMENT_CHANGE_SLOW_LOAD_FEEDRATE);
196
   if (slow_load_length) do_pause_e_move(slow_load_length, FILAMENT_CHANGE_SLOW_LOAD_FEEDRATE);
189
 
197
 
201
     #endif
209
     #endif
202
   }
210
   }
203
 
211
 
212
+  #if ENABLED(DUAL_X_CARRIAGE)      // Tie the two extruders movement back together.
213
+    active_extruder = saved_ext;
214
+    extruder_duplication_enabled = saved_ext_dup_mode;
215
+    stepper.set_directions();
216
+  #endif
217
+
204
   #if ENABLED(ADVANCED_PAUSE_CONTINUOUS_PURGE)
218
   #if ENABLED(ADVANCED_PAUSE_CONTINUOUS_PURGE)
205
 
219
 
206
     #if ENABLED(ULTIPANEL)
220
     #if ENABLED(ULTIPANEL)
328
  */
342
  */
329
 uint8_t did_pause_print = 0;
343
 uint8_t did_pause_print = 0;
330
 
344
 
331
-bool pause_print(const float &retract, const point_t &park_point, const float &unload_length/*=0*/, const bool show_lcd/*=false*/) {
345
+bool pause_print(const float &retract, const point_t &park_point, const float &unload_length/*=0*/, const bool show_lcd/*=false*/ DXC_ARGS) {
346
+
332
   if (did_pause_print) return false; // already paused
347
   if (did_pause_print) return false; // already paused
333
 
348
 
334
   #ifdef ACTION_ON_PAUSE
349
   #ifdef ACTION_ON_PAUSE
380
   if (!axis_unhomed_error())
395
   if (!axis_unhomed_error())
381
     Nozzle::park(2, park_point);
396
     Nozzle::park(2, park_point);
382
 
397
 
383
-  // Unload the filament
384
-  if (unload_length)
398
+  #if ENABLED(DUAL_X_CARRIAGE)
399
+    const int8_t saved_ext        = active_extruder;
400
+    const bool saved_ext_dup_mode = extruder_duplication_enabled;
401
+    active_extruder = DXC_ext;
402
+    extruder_duplication_enabled = false;
403
+  #endif
404
+
405
+  if (unload_length)   // Unload the filament
385
     unload_filament(unload_length, show_lcd);
406
     unload_filament(unload_length, show_lcd);
386
 
407
 
408
+  #if ENABLED(DUAL_X_CARRIAGE)
409
+    active_extruder = saved_ext;
410
+    extruder_duplication_enabled = saved_ext_dup_mode;
411
+    stepper.set_directions();
412
+  #endif
413
+
387
   return true;
414
   return true;
388
 }
415
 }
389
 
416
 
394
  *
421
  *
395
  * Used by M125 and M600
422
  * Used by M125 and M600
396
  */
423
  */
397
-void wait_for_filament_reload(const int8_t max_beep_count/*=0*/) {
424
+void wait_for_filament_reload(const int8_t max_beep_count/*=0*/ DXC_ARGS) {
398
   bool nozzle_timed_out = false;
425
   bool nozzle_timed_out = false;
399
 
426
 
400
   #if ENABLED(ULTIPANEL)
427
   #if ENABLED(ULTIPANEL)
413
   HOTEND_LOOP()
440
   HOTEND_LOOP()
414
     thermalManager.start_heater_idle_timer(e, nozzle_timeout);
441
     thermalManager.start_heater_idle_timer(e, nozzle_timeout);
415
 
442
 
443
+  #if ENABLED(DUAL_X_CARRIAGE)
444
+    const int8_t saved_ext        = active_extruder;
445
+    const bool saved_ext_dup_mode = extruder_duplication_enabled;
446
+    active_extruder = DXC_ext;
447
+    extruder_duplication_enabled = false;
448
+  #endif
449
+
416
   // Wait for filament insert by user and press button
450
   // Wait for filament insert by user and press button
417
   KEEPALIVE_STATE(PAUSED_FOR_USER);
451
   KEEPALIVE_STATE(PAUSED_FOR_USER);
418
   wait_for_user = true;    // LCD click or M108 will clear this
452
   wait_for_user = true;    // LCD click or M108 will clear this
477
 
511
 
478
     idle(true);
512
     idle(true);
479
   }
513
   }
514
+  #if ENABLED(DUAL_X_CARRIAGE)
515
+    active_extruder = saved_ext;
516
+    extruder_duplication_enabled = saved_ext_dup_mode;
517
+    stepper.set_directions();
518
+  #endif
480
   KEEPALIVE_STATE(IN_HANDLER);
519
   KEEPALIVE_STATE(IN_HANDLER);
481
 }
520
 }
482
 
521
 
498
  * - Send host action for resume, if configured
537
  * - Send host action for resume, if configured
499
  * - Resume the current SD print job, if any
538
  * - Resume the current SD print job, if any
500
  */
539
  */
501
-void resume_print(const float &slow_load_length/*=0*/, const float &fast_load_length/*=0*/, const float &purge_length/*=ADVANCED_PAUSE_PURGE_LENGTH*/, const int8_t max_beep_count/*=0*/) {
540
+void resume_print(const float &slow_load_length/*=0*/, const float &fast_load_length/*=0*/, const float &purge_length/*=ADVANCED_PAUSE_PURGE_LENGTH*/, const int8_t max_beep_count/*=0*/ DXC_ARGS) {
541
+  /*
542
+  SERIAL_ECHOPGM("start of resume_print()\n");
543
+  SERIAL_ECHOPAIR("\ndual_x_carriage_mode:", dual_x_carriage_mode);
544
+  SERIAL_ECHOPAIR("\nextruder_duplication_enabled:", extruder_duplication_enabled);
545
+  SERIAL_ECHOPAIR("\nactive_extruder:", active_extruder);
546
+  SERIAL_ECHOPGM("\n\n");
547
+  */
548
+
502
   if (!did_pause_print) return;
549
   if (!did_pause_print) return;
503
 
550
 
504
   // Re-enable the heaters if they timed out
551
   // Re-enable the heaters if they timed out
508
     thermalManager.reset_heater_idle_timer(e);
555
     thermalManager.reset_heater_idle_timer(e);
509
   }
556
   }
510
 
557
 
511
-  if (nozzle_timed_out || thermalManager.hotEnoughToExtrude(active_extruder)) {
512
-    // Load the new filament
513
-    load_filament(slow_load_length, fast_load_length, purge_length, max_beep_count, true, nozzle_timed_out);
514
-  }
558
+  if (nozzle_timed_out || thermalManager.hotEnoughToExtrude(active_extruder)) // Load the new filament
559
+    load_filament(slow_load_length, fast_load_length, purge_length, max_beep_count, true, nozzle_timed_out, ADVANCED_PAUSE_MODE_PAUSE_PRINT DXC_PASS);
515
 
560
 
516
   #if ENABLED(ULTIPANEL)
561
   #if ENABLED(ULTIPANEL)
517
-    // "Wait for print to resume"
518
-    lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_RESUME);
562
+    lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_RESUME); // "Wait for print to resume"
519
   #endif
563
   #endif
520
 
564
 
521
   // Intelligent resuming
565
   // Intelligent resuming

+ 14
- 4
Marlin/src/feature/pause.h View File

67
 
67
 
68
 extern uint8_t did_pause_print;
68
 extern uint8_t did_pause_print;
69
 
69
 
70
-bool pause_print(const float &retract, const point_t &park_point, const float &unload_length=0, const bool show_lcd=false);
70
+#if ENABLED(DUAL_X_CARRIAGE)
71
+  #define DXC_PARAMS , const int8_t DXC_ext=-1
72
+  #define DXC_ARGS   , const int8_t DXC_ext
73
+  #define DXC_PASS   , DXC_ext
74
+#else
75
+  #define DXC_PARAMS
76
+  #define DXC_ARGS
77
+  #define DXC_PASS
78
+#endif
71
 
79
 
72
-void wait_for_filament_reload(const int8_t max_beep_count=0);
80
+bool pause_print(const float &retract, const point_t &park_point, const float &unload_length=0, const bool show_lcd=false DXC_PARAMS);
73
 
81
 
74
-void resume_print(const float &slow_load_length=0, const float &fast_load_length=0, const float &extrude_length=ADVANCED_PAUSE_PURGE_LENGTH, const int8_t max_beep_count=0);
82
+void wait_for_filament_reload(const int8_t max_beep_count=0 DXC_PARAMS);
83
+
84
+void resume_print(const float &slow_load_length=0, const float &fast_load_length=0, const float &extrude_length=ADVANCED_PAUSE_PURGE_LENGTH, const int8_t max_beep_count=0 DXC_PARAMS);
75
 
85
 
76
 bool load_filament(const float &slow_load_length=0, const float &fast_load_length=0, const float &extrude_length=0, const int8_t max_beep_count=0, const bool show_lcd=false,
86
 bool load_filament(const float &slow_load_length=0, const float &fast_load_length=0, const float &extrude_length=0, const int8_t max_beep_count=0, const bool show_lcd=false,
77
-                          const bool pause_for_user=false, const AdvancedPauseMode mode=ADVANCED_PAUSE_MODE_PAUSE_PRINT);
87
+                          const bool pause_for_user=false, const AdvancedPauseMode mode=ADVANCED_PAUSE_MODE_PAUSE_PRINT DXC_PARAMS);
78
 
88
 
79
 bool unload_filament(const float &unload_length, const bool show_lcd=false, const AdvancedPauseMode mode=ADVANCED_PAUSE_MODE_PAUSE_PRINT);
89
 bool unload_filament(const float &unload_length, const bool show_lcd=false, const AdvancedPauseMode mode=ADVANCED_PAUSE_MODE_PAUSE_PRINT);
80
 
90
 

+ 24
- 15
Marlin/src/feature/runout.h View File

62
       #else
62
       #else
63
         // Read the sensor for the active extruder
63
         // Read the sensor for the active extruder
64
         bool is_out;
64
         bool is_out;
65
-        switch (active_extruder) {
66
-          case 0: is_out = READ(FIL_RUNOUT_PIN) == FIL_RUNOUT_INVERTING; break;
67
-          case 1: is_out = READ(FIL_RUNOUT2_PIN) == FIL_RUNOUT_INVERTING; break;
68
-          #if NUM_RUNOUT_SENSORS > 2
69
-            case 2: is_out = READ(FIL_RUNOUT3_PIN) == FIL_RUNOUT_INVERTING; break;
70
-            #if NUM_RUNOUT_SENSORS > 3
71
-              case 3: is_out = READ(FIL_RUNOUT4_PIN) == FIL_RUNOUT_INVERTING; break;
72
-              #if NUM_RUNOUT_SENSORS > 4
73
-                case 4: is_out = READ(FIL_RUNOUT5_PIN) == FIL_RUNOUT_INVERTING; break;
74
-                #if NUM_RUNOUT_SENSORS > 5
75
-                  case 5: is_out = READ(FIL_RUNOUT6_PIN) == FIL_RUNOUT_INVERTING; break;
76
-                #endif
77
-              #endif
78
-            #endif
79
-          #endif
65
+        #if ENABLED(DUAL_X_CARRIAGE)
66
+          const bool out1 = READ(FIL_RUNOUT_PIN ) == FIL_RUNOUT_INVERTING,
67
+                     out2 = READ(FIL_RUNOUT2_PIN) == FIL_RUNOUT_INVERTING;
68
+          if (extruder_duplication_enabled)
69
+            is_out = out1 || out2;
70
+          else
71
+            is_out = active_extruder ? out2 : out1;
72
+        #else
73
+          switch (active_extruder) {
74
+            case 0: is_out = READ(FIL_RUNOUT_PIN) == FIL_RUNOUT_INVERTING; break;
75
+            case 1: is_out = READ(FIL_RUNOUT2_PIN) == FIL_RUNOUT_INVERTING; break;
76
+            #if NUM_RUNOUT_SENSORS > 2
77
+              case 2: is_out = READ(FIL_RUNOUT3_PIN) == FIL_RUNOUT_INVERTING; break;
78
+              #if NUM_RUNOUT_SENSORS > 3
79
+                case 3: is_out = READ(FIL_RUNOUT4_PIN) == FIL_RUNOUT_INVERTING; break;
80
+                #if NUM_RUNOUT_SENSORS > 4
81
+                  case 4: is_out = READ(FIL_RUNOUT5_PIN) == FIL_RUNOUT_INVERTING; break;
82
+                  #if NUM_RUNOUT_SENSORS > 5
83
+                    case 5: is_out = READ(FIL_RUNOUT6_PIN) == FIL_RUNOUT_INVERTING; break;
84
+                  #endif // > 5
85
+                #endif // > 4
86
+              #endif // > 3
87
+            #endif // > 2
80
         }
88
         }
89
+        #endif
81
       #endif
90
       #endif
82
       return (is_out ? ++runout_count : (runout_count = 0)) > FIL_RUNOUT_THRESHOLD;
91
       return (is_out ? ++runout_count : (runout_count = 0)) > FIL_RUNOUT_THRESHOLD;
83
     }
92
     }

+ 4
- 1
Marlin/src/gcode/calibrate/G28.cpp View File

369
    */
369
    */
370
   #if ENABLED(DUAL_X_CARRIAGE)
370
   #if ENABLED(DUAL_X_CARRIAGE)
371
 
371
 
372
-    if (dual_x_carriage_mode == DXC_DUPLICATION_MODE) {
372
+    if (dxc_is_duplicating()) {
373
 
373
 
374
       // Always home the 2nd (right) extruder first
374
       // Always home the 2nd (right) extruder first
375
       active_extruder = 1;
375
       active_extruder = 1;
387
       delayed_move_time = 0;
387
       delayed_move_time = 0;
388
       active_extruder_parked = true;
388
       active_extruder_parked = true;
389
       extruder_duplication_enabled = IDEX_saved_duplication_state;
389
       extruder_duplication_enabled = IDEX_saved_duplication_state;
390
+      extruder_duplication_enabled = false;
391
+
390
       dual_x_carriage_mode         = IDEX_saved_mode;
392
       dual_x_carriage_mode         = IDEX_saved_mode;
393
+      stepper.set_directions();
391
     }
394
     }
392
 
395
 
393
   #endif // DUAL_X_CARRIAGE
396
   #endif // DUAL_X_CARRIAGE

+ 55
- 10
Marlin/src/gcode/control/M605.cpp View File

44
    *                         units x-offset and an optional differential hotend temperature of
44
    *                         units x-offset and an optional differential hotend temperature of
45
    *                         mmm degrees. E.g., with "M605 S2 X100 R2" the second extruder will duplicate
45
    *                         mmm degrees. E.g., with "M605 S2 X100 R2" the second extruder will duplicate
46
    *                         the first with a spacing of 100mm in the x direction and 2 degrees hotter.
46
    *                         the first with a spacing of 100mm in the x direction and 2 degrees hotter.
47
-   *    M605 S3 : Enable Symmetric Duplication mode.  The second extruder will duplicate the first extruder's
47
+   *    M605 S3 : Enable Scaled Duplication mode.  The second extruder will duplicate the first extruder's
48
    *              movement similar to the M605 S2 mode.   However, the second extruder will be producing
48
    *              movement similar to the M605 S2 mode.   However, the second extruder will be producing
49
-   *              a mirror image of the first extruder.  The initial x-offset and temperature differential are
49
+   *              a scaled image of the first extruder.  The initial x-offset and temperature differential are
50
    *              set with M605 S2 [Xnnn] [Rmmm] and then followed with a M605 S3 to start the mirrored movement.
50
    *              set with M605 S2 [Xnnn] [Rmmm] and then followed with a M605 S3 to start the mirrored movement.
51
    *    M605 W  : IDEX What? command.
51
    *    M605 W  : IDEX What? command.
52
    *
52
    *
56
     planner.synchronize();
56
     planner.synchronize();
57
 
57
 
58
     if (parser.seen('S')) {
58
     if (parser.seen('S')) {
59
+      const DualXMode previous_mode = dual_x_carriage_mode;
60
+
59
       dual_x_carriage_mode = (DualXMode)parser.value_byte();
61
       dual_x_carriage_mode = (DualXMode)parser.value_byte();
62
+      scaled_duplication_mode = false;
63
+
64
+      if (dual_x_carriage_mode == DXC_SCALED_DUPLICATION_MODE) {
65
+        if (previous_mode != DXC_DUPLICATION_MODE) {
66
+          SERIAL_ECHOPGM("Printer must be in DXC_DUPLICATION_MODE prior to \n");
67
+          SERIAL_ECHOPGM("specifying DXC_SCALED_DUPLICATION_MODE.\n");
68
+          dual_x_carriage_mode = DEFAULT_DUAL_X_CARRIAGE_MODE;
69
+          return;
70
+        }
71
+        scaled_duplication_mode = true;
72
+        stepper.set_directions();
73
+        float x_jog = current_position[X_AXIS] - .1;
74
+        for (uint8_t i = 2; --i;) {
75
+          planner.buffer_line(x_jog, current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], feedrate_mm_s, 0);
76
+          x_jog += .1;
77
+        }
78
+        return;
79
+      }
60
 
80
 
61
       switch (dual_x_carriage_mode) {
81
       switch (dual_x_carriage_mode) {
62
         case DXC_FULL_CONTROL_MODE:
82
         case DXC_FULL_CONTROL_MODE:
73
       }
93
       }
74
       active_extruder_parked = false;
94
       active_extruder_parked = false;
75
       extruder_duplication_enabled = false;
95
       extruder_duplication_enabled = false;
96
+      stepper.set_directions();
76
       delayed_move_time = 0;
97
       delayed_move_time = 0;
77
     }
98
     }
78
     else if (!parser.seen('W'))  // if no S or W parameter, the DXC mode gets reset to the user's default
99
     else if (!parser.seen('W'))  // if no S or W parameter, the DXC mode gets reset to the user's default
82
       SERIAL_ECHO_START();
103
       SERIAL_ECHO_START();
83
       SERIAL_ECHOPGM("IDEX mode: ");
104
       SERIAL_ECHOPGM("IDEX mode: ");
84
       switch (dual_x_carriage_mode) {
105
       switch (dual_x_carriage_mode) {
85
-        case DXC_FULL_CONTROL_MODE: SERIAL_ECHOPGM("DXC_FULL_CONTROL_MODE"); break;
86
-        case DXC_AUTO_PARK_MODE:    SERIAL_ECHOPGM("DXC_AUTO_PARK_MODE");    break;
87
-        case DXC_DUPLICATION_MODE:  SERIAL_ECHOPGM("DXC_DUPLICATION_MODE");  break;
106
+        case DXC_FULL_CONTROL_MODE:       SERIAL_ECHOPGM("DXC_FULL_CONTROL_MODE");       break;
107
+        case DXC_AUTO_PARK_MODE:          SERIAL_ECHOPGM("DXC_AUTO_PARK_MODE");          break;
108
+        case DXC_DUPLICATION_MODE:        SERIAL_ECHOPGM("DXC_DUPLICATION_MODE");        break;
109
+        case DXC_SCALED_DUPLICATION_MODE: SERIAL_ECHOPGM("DXC_SCALED_DUPLICATION_MODE"); break;
88
       }
110
       }
89
       SERIAL_ECHOPAIR("\nActive Ext: ", int(active_extruder));
111
       SERIAL_ECHOPAIR("\nActive Ext: ", int(active_extruder));
90
       if (!active_extruder_parked) SERIAL_ECHOPGM(" NOT ");
112
       if (!active_extruder_parked) SERIAL_ECHOPGM(" NOT ");
91
-      SERIAL_ECHOLNPGM(" parked.");
92
-      SERIAL_ECHOPAIR("active_extruder_x_pos: ", current_position[X_AXIS]);
93
-      SERIAL_ECHOPAIR("   inactive_extruder_x_pos: ", inactive_extruder_x_pos);
94
-      SERIAL_ECHOPAIR("\nT0 Home X: ", x_home_pos(0));
95
-      SERIAL_ECHOPAIR("\nT1 Home X: ", x_home_pos(1));
113
+      SERIAL_ECHOPGM(" parked.");
114
+      SERIAL_ECHOPAIR("\nactive_extruder_x_pos: ", current_position[X_AXIS]);
115
+      SERIAL_ECHOPAIR("\ninactive_extruder_x_pos: ", inactive_extruder_x_pos);
96
       SERIAL_ECHOPAIR("\nextruder_duplication_enabled: ", int(extruder_duplication_enabled));
116
       SERIAL_ECHOPAIR("\nextruder_duplication_enabled: ", int(extruder_duplication_enabled));
97
       SERIAL_ECHOPAIR("\nduplicate_extruder_x_offset: ", duplicate_extruder_x_offset);
117
       SERIAL_ECHOPAIR("\nduplicate_extruder_x_offset: ", duplicate_extruder_x_offset);
98
       SERIAL_ECHOPAIR("\nduplicate_extruder_temp_offset: ", duplicate_extruder_temp_offset);
118
       SERIAL_ECHOPAIR("\nduplicate_extruder_temp_offset: ", duplicate_extruder_temp_offset);
99
       SERIAL_ECHOPAIR("\ndelayed_move_time: ", delayed_move_time);
119
       SERIAL_ECHOPAIR("\ndelayed_move_time: ", delayed_move_time);
120
+      SERIAL_ECHOPAIR("\nX1 Home X: ", x_home_pos(0));
121
+      SERIAL_ECHOPAIR("\nX1_MIN_POS=", int(X1_MIN_POS));
122
+      SERIAL_ECHOPAIR("\nX1_MAX_POS=", int(X1_MAX_POS));
123
+      SERIAL_ECHOPAIR("\nX2 Home X: ", x_home_pos(1));
124
+      SERIAL_ECHOPAIR("\nX2_MIN_POS=", int(X2_MIN_POS));
125
+      SERIAL_ECHOPAIR("\nX2_MAX_POS=", int(X2_MAX_POS));
126
+      SERIAL_ECHOPAIR("\nX2_HOME_DIR=", int(X2_HOME_DIR));
127
+      SERIAL_ECHOPAIR("\nX2_HOME_POS=", int(X2_HOME_POS));
128
+      SERIAL_ECHOPAIR("\nDEFAULT_DUAL_X_CARRIAGE_MODE=", STRINGIFY(DEFAULT_DUAL_X_CARRIAGE_MODE));
129
+      SERIAL_ECHOPAIR("\nTOOLCHANGE_PARK_ZLIFT=", float(TOOLCHANGE_PARK_ZLIFT));
130
+      SERIAL_ECHOPAIR("\nTOOLCHANGE_UNPARK_ZLIFT=", float(TOOLCHANGE_UNPARK_ZLIFT));
131
+      SERIAL_ECHOPAIR("\nDEFAULT_DUPLICATION_X_OFFSET=", int(DEFAULT_DUPLICATION_X_OFFSET));
132
+
133
+      SERIAL_EOL();
134
+      for (uint8_t i = 0; i < 2; i++) {
135
+        SERIAL_ECHOPAIR(" nozzle:", int(i));
136
+        LOOP_XYZ(j) {
137
+          SERIAL_ECHOPGM("    hotend_offset[");
138
+          SERIAL_CHAR(axis_codes[j]);
139
+          SERIAL_ECHOPAIR("_AXIS][", int(i));
140
+          SERIAL_ECHOPAIR("]=", hotend_offset[j][i]);
141
+        }
142
+        SERIAL_EOL();
143
+      }
144
+      SERIAL_EOL();
100
     }
145
     }
101
   }
146
   }
102
 
147
 

+ 1
- 1
Marlin/src/gcode/feature/leds/M7219.cpp View File

79
       SERIAL_ECHOPGM("led_line[");
79
       SERIAL_ECHOPGM("led_line[");
80
       if (r < 10) SERIAL_CHAR(' ');
80
       if (r < 10) SERIAL_CHAR(' ');
81
       SERIAL_ECHO(int(r));
81
       SERIAL_ECHO(int(r));
82
-      SERIAL_ECHO("]=");
82
+      SERIAL_ECHOPGM("]=");
83
       for (uint8_t b = 8; b--;) SERIAL_CHAR('0' + TEST(max7219.led_line[r], b));
83
       for (uint8_t b = 8; b--;) SERIAL_CHAR('0' + TEST(max7219.led_line[r], b));
84
       SERIAL_EOL();
84
       SERIAL_EOL();
85
     }
85
     }

+ 24
- 7
Marlin/src/gcode/feature/pause/M600.cpp View File

56
 
56
 
57
   if (get_target_extruder_from_command()) return;
57
   if (get_target_extruder_from_command()) return;
58
 
58
 
59
+  #if ENABLED(DUAL_X_CARRIAGE)
60
+    int8_t DXC_ext = target_extruder;
61
+    if (!parser.seen('T')) {  // If no tool index is specified, M600 was (probably) sent in response to filament runout.
62
+                              // In this case, for duplicating modes set DXC_ext to the extruder that ran out.
63
+      #if ENABLED(FILAMENT_RUNOUT_SENSOR)
64
+        if (dxc_is_duplicating())
65
+          DXC_ext = (READ(FIL_RUNOUT2_PIN) == FIL_RUNOUT_INVERTING) ? 1 : 0;
66
+      #else
67
+        DXC_ext = active_extruder;
68
+      #endif
69
+    }
70
+  #endif
71
+
59
   // Show initial "wait for start" message
72
   // Show initial "wait for start" message
60
   #if ENABLED(ULTIPANEL)
73
   #if ENABLED(ULTIPANEL)
61
     lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_INIT, ADVANCED_PAUSE_MODE_PAUSE_PRINT, target_extruder);
74
     lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_INIT, ADVANCED_PAUSE_MODE_PAUSE_PRINT, target_extruder);
63
 
76
 
64
   #if ENABLED(HOME_BEFORE_FILAMENT_CHANGE)
77
   #if ENABLED(HOME_BEFORE_FILAMENT_CHANGE)
65
     // Don't allow filament change without homing first
78
     // Don't allow filament change without homing first
66
-    if (axis_unhomed_error()) home_all_axes();
79
+    if (axis_unhomed_error()) gcode.home_all_axes();
67
   #endif
80
   #endif
68
 
81
 
69
   #if EXTRUDERS > 1
82
   #if EXTRUDERS > 1
70
     // Change toolhead if specified
83
     // Change toolhead if specified
71
-    uint8_t active_extruder_before_filament_change = active_extruder;
72
-    if (active_extruder != target_extruder)
73
-      tool_change(target_extruder, 0, true);
84
+    const uint8_t active_extruder_before_filament_change = active_extruder;
85
+    if (
86
+      active_extruder != target_extruder
87
+      #if ENABLED(DUAL_X_CARRIAGE)
88
+        && dual_x_carriage_mode != DXC_DUPLICATION_MODE && dual_x_carriage_mode != DXC_SCALED_DUPLICATION_MODE
89
+      #endif
90
+    ) tool_change(target_extruder, 0, true);
74
   #endif
91
   #endif
75
 
92
 
76
   // Initial retract before move to filament change position
93
   // Initial retract before move to filament change position
113
 
130
 
114
   const bool job_running = print_job_timer.isRunning();
131
   const bool job_running = print_job_timer.isRunning();
115
 
132
 
116
-  if (pause_print(retract, park_point, unload_length, true)) {
117
-    wait_for_filament_reload(beep_count);
118
-    resume_print(slow_load_length, fast_load_length, ADVANCED_PAUSE_PURGE_LENGTH, beep_count);
133
+  if (pause_print(retract, park_point, unload_length, true DXC_PASS)) {
134
+    wait_for_filament_reload(beep_count DXC_PASS);
135
+    resume_print(slow_load_length, fast_load_length, ADVANCED_PAUSE_PURGE_LENGTH, beep_count DXC_PASS);
119
   }
136
   }
120
 
137
 
121
   #if EXTRUDERS > 1
138
   #if EXTRUDERS > 1

+ 5
- 1
Marlin/src/gcode/feature/pause/M701_M702.cpp View File

81
   const float fast_load_length = ABS(parser.seen('L') ? parser.value_axis_units(E_AXIS)
81
   const float fast_load_length = ABS(parser.seen('L') ? parser.value_axis_units(E_AXIS)
82
                                                        : filament_change_load_length[active_extruder]);
82
                                                        : filament_change_load_length[active_extruder]);
83
   load_filament(slow_load_length, fast_load_length, ADVANCED_PAUSE_PURGE_LENGTH, FILAMENT_CHANGE_ALERT_BEEPS,
83
   load_filament(slow_load_length, fast_load_length, ADVANCED_PAUSE_PURGE_LENGTH, FILAMENT_CHANGE_ALERT_BEEPS,
84
-                true, thermalManager.wait_for_heating(target_extruder), ADVANCED_PAUSE_MODE_LOAD_FILAMENT);
84
+                true, thermalManager.wait_for_heating(target_extruder), ADVANCED_PAUSE_MODE_LOAD_FILAMENT
85
+                #if ENABLED(DUAL_X_CARRIAGE)
86
+                  , target_extruder
87
+                #endif
88
+              );
85
 
89
 
86
   // Restore Z axis
90
   // Restore Z axis
87
   if (park_point.z > 0)
91
   if (park_point.z > 0)

+ 3
- 3
Marlin/src/gcode/queue.cpp View File

139
  */
139
  */
140
 bool enqueue_and_echo_command(const char* cmd) {
140
 bool enqueue_and_echo_command(const char* cmd) {
141
 
141
 
142
-  //SERIAL_ECHO("enqueue_and_echo_command(\"");
142
+  //SERIAL_ECHOPGM("enqueue_and_echo_command(\"");
143
   //SERIAL_ECHO(cmd);
143
   //SERIAL_ECHO(cmd);
144
-  //SERIAL_ECHO("\") \n");
144
+  //SERIAL_ECHOPGM("\") \n");
145
 
145
 
146
   if (*cmd == 0 || *cmd == '\n' || *cmd == '\r') {
146
   if (*cmd == 0 || *cmd == '\n' || *cmd == '\r') {
147
-    //SERIAL_ECHO("Null command found...   Did not queue!\n");
147
+    //SERIAL_ECHOPGM("Null command found...   Did not queue!\n");
148
     return true;
148
     return true;
149
   }
149
   }
150
 
150
 

+ 2
- 2
Marlin/src/gcode/temperature/M104_M109.cpp View File

53
     thermalManager.setTargetHotend(temp, e);
53
     thermalManager.setTargetHotend(temp, e);
54
 
54
 
55
     #if ENABLED(DUAL_X_CARRIAGE)
55
     #if ENABLED(DUAL_X_CARRIAGE)
56
-      if (dual_x_carriage_mode == DXC_DUPLICATION_MODE && e == 0)
56
+      if (dxc_is_duplicating() && e == 0)
57
         thermalManager.setTargetHotend(temp ? temp + duplicate_extruder_temp_offset : 0, 1);
57
         thermalManager.setTargetHotend(temp ? temp + duplicate_extruder_temp_offset : 0, 1);
58
     #endif
58
     #endif
59
 
59
 
103
     thermalManager.setTargetHotend(temp, target_extruder);
103
     thermalManager.setTargetHotend(temp, target_extruder);
104
 
104
 
105
     #if ENABLED(DUAL_X_CARRIAGE)
105
     #if ENABLED(DUAL_X_CARRIAGE)
106
-      if (dual_x_carriage_mode == DXC_DUPLICATION_MODE && target_extruder == 0)
106
+      if (dxc_is_duplicating() && target_extruder == 0)
107
         thermalManager.setTargetHotend(temp ? temp + duplicate_extruder_temp_offset : 0, 1);
107
         thermalManager.setTargetHotend(temp ? temp + duplicate_extruder_temp_offset : 0, 1);
108
     #endif
108
     #endif
109
 
109
 

+ 15
- 0
Marlin/src/lcd/language/language_en.h View File

214
 #ifndef MSG_IDEX_MODE_DUPLICATE
214
 #ifndef MSG_IDEX_MODE_DUPLICATE
215
   #define MSG_IDEX_MODE_DUPLICATE             _UxGT("Duplication")
215
   #define MSG_IDEX_MODE_DUPLICATE             _UxGT("Duplication")
216
 #endif
216
 #endif
217
+#ifndef MSG_IDEX_MODE_SCALED_COPY
218
+  #define MSG_IDEX_MODE_SCALED_COPY           _UxGT("Scaled copy")
219
+#endif
217
 #ifndef MSG_IDEX_MODE_FULL_CTRL
220
 #ifndef MSG_IDEX_MODE_FULL_CTRL
218
   #define MSG_IDEX_MODE_FULL_CTRL             _UxGT("Full control")
221
   #define MSG_IDEX_MODE_FULL_CTRL             _UxGT("Full control")
219
 #endif
222
 #endif
223
+#ifndef MSG_IDEX_X_OFFSET
224
+  #define MSG_IDEX_X_OFFSET                   _UxGT("2nd nozzle X")
225
+#endif
226
+#ifndef MSG_IDEX_Y_OFFSET
227
+  #define MSG_IDEX_Y_OFFSET                   _UxGT("2nd nozzle Y")
228
+#endif
229
+#ifndef MSG_IDEX_Z_OFFSET
230
+  #define MSG_IDEX_Z_OFFSET                   _UxGT("2nd nozzle Z")
231
+#endif
232
+#ifndef MSG_IDEX_SAVE_OFFSETS
233
+  #define MSG_IDEX_SAVE_OFFSETS               _UxGT("Save Offsets")
234
+#endif
220
 #ifndef MSG_UBL_MANUAL_MESH
235
 #ifndef MSG_UBL_MANUAL_MESH
221
   #define MSG_UBL_MANUAL_MESH                 _UxGT("Manually Build Mesh")
236
   #define MSG_UBL_MANUAL_MESH                 _UxGT("Manually Build Mesh")
222
 #endif
237
 #endif

+ 24
- 6
Marlin/src/lcd/ultralcd.cpp View File

38
 #include "../gcode/gcode.h"
38
 #include "../gcode/gcode.h"
39
 #include "../gcode/queue.h"
39
 #include "../gcode/queue.h"
40
 #include "../module/configuration_store.h"
40
 #include "../module/configuration_store.h"
41
+#include "../module/tool_change.h"
42
+
41
 
43
 
42
 #include "../Marlin.h"
44
 #include "../Marlin.h"
43
 
45
 
521
           if (currentScreen == lcd_status_screen)
523
           if (currentScreen == lcd_status_screen)
522
             doubleclick_expire_ms = millis() + DOUBLECLICK_MAX_INTERVAL;
524
             doubleclick_expire_ms = millis() + DOUBLECLICK_MAX_INTERVAL;
523
         }
525
         }
524
-        else if (screen == lcd_status_screen && currentScreen == lcd_main_menu && PENDING(millis(), doubleclick_expire_ms) && (planner.movesplanned() || IS_SD_PRINTING))
526
+        else if (screen == lcd_status_screen && currentScreen == lcd_main_menu && PENDING(millis(), doubleclick_expire_ms)/* && (planner.movesplanned() || IS_SD_PRINTING)*/)
525
           screen =
527
           screen =
526
             #if ENABLED(BABYSTEP_ZPROBE_OFFSET)
528
             #if ENABLED(BABYSTEP_ZPROBE_OFFSET)
527
               lcd_babystep_zoffset
529
               lcd_babystep_zoffset
1038
    * IDEX submenu
1040
    * IDEX submenu
1039
    */
1041
    */
1040
   #if ENABLED(DUAL_X_CARRIAGE)
1042
   #if ENABLED(DUAL_X_CARRIAGE)
1043
+    static void _recalc_IDEX_settings() {
1044
+      if (active_extruder) {                      // For the 2nd extruder re-home so the next tool-change gets the new offsets.
1045
+        enqueue_and_echo_commands_P(PSTR("G28")); // In future, we can babystep the 2nd extruder (if active), making homing unnecessary.
1046
+        active_extruder = 0;
1047
+      }
1048
+    }
1049
+
1041
     static void IDEX_menu() {
1050
     static void IDEX_menu() {
1042
       START_MENU();
1051
       START_MENU();
1043
       MENU_BACK(MSG_MAIN);
1052
       MENU_BACK(MSG_MAIN);
1044
-      MENU_ITEM(gcode, MSG_IDEX_MODE_AUTOPARK, PSTR("M605 S1\nG28 X\nG1 X100"));
1045
-      if (!TEST(axis_known_position, Y_AXIS) || !TEST(axis_known_position, Z_AXIS))
1046
-        MENU_ITEM(gcode, MSG_IDEX_MODE_DUPLICATE, PSTR("T0\nG28\nM605 S2 X200\nG28 X\nG1 X100"));  // If Y or Z is not homed, a full G28 is done first.
1047
-      else
1048
-        MENU_ITEM(gcode, MSG_IDEX_MODE_DUPLICATE, PSTR("T0\nM605 S2 X200\nG28 X\nG1 X100"));       // If Y and Z is homed, a full G28 is not needed first.
1053
+      MENU_ITEM(gcode, MSG_IDEX_MODE_AUTOPARK,  PSTR("M605 S1\nG28 X\nG1 X100"));
1054
+      const bool need_g28 = !(TEST(axis_known_position, Y_AXIS) && TEST(axis_known_position, Z_AXIS));
1055
+      MENU_ITEM(gcode, MSG_IDEX_MODE_DUPLICATE, need_g28
1056
+        ? PSTR("M605 S1\nT0\nG28\nM605 S2 X200\nG28 X\nG1 X100")                // If Y or Z is not homed, do a full G28 first
1057
+        : PSTR("M605 S1\nT0\nM605 S2 X200\nG28 X\nG1 X100")
1058
+      );
1059
+      MENU_ITEM(gcode, MSG_IDEX_MODE_SCALED_COPY, need_g28
1060
+        ? PSTR("M605 S1\nT0\nG28\nM605 S2 X200\nG28 X\nG1 X100\nM605 S3 X200")  // If Y or Z is not homed, do a full G28 first
1061
+        : PSTR("M605 S1\nT0\nM605 S2 X200\nG28 X\nG1 X100\nM605 S3 X200")
1062
+      );
1049
       MENU_ITEM(gcode, MSG_IDEX_MODE_FULL_CTRL, PSTR("M605 S0\nG28 X"));
1063
       MENU_ITEM(gcode, MSG_IDEX_MODE_FULL_CTRL, PSTR("M605 S0\nG28 X"));
1064
+      MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float52, MSG_IDEX_X_OFFSET , &hotend_offset[X_AXIS][1], MIN(X2_HOME_POS, X2_MAX_POS) - 25.0, MAX(X2_HOME_POS, X2_MAX_POS) + 25.0, _recalc_IDEX_settings);
1065
+      MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float52, MSG_IDEX_Y_OFFSET , &hotend_offset[Y_AXIS][1], -10.0, 10.0, _recalc_IDEX_settings);
1066
+      MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float52, MSG_IDEX_Z_OFFSET , &hotend_offset[Z_AXIS][1], -10.0, 10.0, _recalc_IDEX_settings);
1067
+      MENU_ITEM(gcode, MSG_IDEX_SAVE_OFFSETS, PSTR("M500"));
1050
       END_MENU();
1068
       END_MENU();
1051
     }
1069
     }
1052
   #endif // DUAL_X_CARRIAGE
1070
   #endif // DUAL_X_CARRIAGE

+ 3
- 0
Marlin/src/module/configuration_store.cpp View File

1886
       "Offsets for the first hotend must be 0.0."
1886
       "Offsets for the first hotend must be 0.0."
1887
     );
1887
     );
1888
     LOOP_XYZ(i) HOTEND_LOOP() hotend_offset[i][e] = tmp4[i][e];
1888
     LOOP_XYZ(i) HOTEND_LOOP() hotend_offset[i][e] = tmp4[i][e];
1889
+    #if ENABLED(DUAL_X_CARRIAGE)
1890
+      hotend_offset[X_AXIS][1] = MAX(X2_HOME_POS, X2_MAX_POS);
1891
+    #endif
1889
   #endif
1892
   #endif
1890
 
1893
 
1891
   //
1894
   //

+ 12
- 10
Marlin/src/module/motion.cpp View File

760
 
760
 
761
 #if ENABLED(DUAL_X_CARRIAGE) || ENABLED(DUAL_NOZZLE_DUPLICATION_MODE)
761
 #if ENABLED(DUAL_X_CARRIAGE) || ENABLED(DUAL_NOZZLE_DUPLICATION_MODE)
762
   bool extruder_duplication_enabled = false,                              // Used in Dual X mode 2 & 3
762
   bool extruder_duplication_enabled = false,                              // Used in Dual X mode 2 & 3
763
-       symmetric_duplication_mode   = false;                              // Used in Dual X mode 2 & 3
763
+       scaled_duplication_mode      = false;                              // Used in Dual X mode 2 & 3
764
 #endif
764
 #endif
765
 
765
 
766
 #if ENABLED(DUAL_X_CARRIAGE)
766
 #if ENABLED(DUAL_X_CARRIAGE)
818
             #define RAISED_Y raised_parked_position[Y_AXIS]
818
             #define RAISED_Y raised_parked_position[Y_AXIS]
819
             #define RAISED_Z raised_parked_position[Z_AXIS]
819
             #define RAISED_Z raised_parked_position[Z_AXIS]
820
 
820
 
821
-            //SERIAL_ECHOLNPGM("dual_x_carriage_unpark()\n");
822
-
823
             if (  planner.buffer_line(RAISED_X, RAISED_Y, RAISED_Z, CUR_E, planner.max_feedrate_mm_s[Z_AXIS], active_extruder))
821
             if (  planner.buffer_line(RAISED_X, RAISED_Y, RAISED_Z, CUR_E, planner.max_feedrate_mm_s[Z_AXIS], active_extruder))
824
               if (planner.buffer_line(   CUR_X,    CUR_Y, RAISED_Z, CUR_E, PLANNER_XY_FEEDRATE(),             active_extruder))
822
               if (planner.buffer_line(   CUR_X,    CUR_Y, RAISED_Z, CUR_E, PLANNER_XY_FEEDRATE(),             active_extruder))
825
                   planner.buffer_line(   CUR_X,    CUR_Y,    CUR_Z, CUR_E, planner.max_feedrate_mm_s[Z_AXIS], active_extruder);
823
                   planner.buffer_line(   CUR_X,    CUR_Y,    CUR_Z, CUR_E, planner.max_feedrate_mm_s[Z_AXIS], active_extruder);
829
             if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("Clear active_extruder_parked");
827
             if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("Clear active_extruder_parked");
830
           #endif
828
           #endif
831
           break;
829
           break;
830
+        case DXC_SCALED_DUPLICATION_MODE:
832
         case DXC_DUPLICATION_MODE:
831
         case DXC_DUPLICATION_MODE:
833
           if (active_extruder == 0) {
832
           if (active_extruder == 0) {
834
             #if ENABLED(DEBUG_LEVELING_FEATURE)
833
             #if ENABLED(DEBUG_LEVELING_FEATURE)
839
             #endif
838
             #endif
840
             // move duplicate extruder into correct duplication position.
839
             // move duplicate extruder into correct duplication position.
841
             planner.set_position_mm(inactive_extruder_x_pos, current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
840
             planner.set_position_mm(inactive_extruder_x_pos, current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
841
+
842
             if (!planner.buffer_line(
842
             if (!planner.buffer_line(
843
-              current_position[X_AXIS] + duplicate_extruder_x_offset,
844
-              current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS],
845
-              planner.max_feedrate_mm_s[X_AXIS], 1)
843
+                dual_x_carriage_mode == DXC_DUPLICATION_MODE ? duplicate_extruder_x_offset + current_position[X_AXIS] : inactive_extruder_x_pos,
844
+                current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS],
845
+                planner.max_feedrate_mm_s[X_AXIS], 1
846
+              )
846
             ) break;
847
             ) break;
847
             planner.synchronize();
848
             planner.synchronize();
848
             sync_plan_position();
849
             sync_plan_position();
860
           break;
861
           break;
861
       }
862
       }
862
     }
863
     }
864
+    stepper.set_directions();
863
     return false;
865
     return false;
864
   }
866
   }
865
 
867
 
906
 
908
 
907
   if (
909
   if (
908
     #if UBL_SEGMENTED
910
     #if UBL_SEGMENTED
909
-//    ubl.prepare_segmented_line_to(destination, MMS_SCALED(feedrate_mm_s))   // This does not seem to work correctly on UBL.
910
-      #if ENABLED(DELTA)                                                      // A Delta case and a Cartesian case can work
911
-        ubl.prepare_segmented_line_to(destination, MMS_SCALED(feedrate_mm_s)) // around the problem until it is fixed.
911
+      //ubl.prepare_segmented_line_to(destination, MMS_SCALED(feedrate_mm_s))   // This doesn't seem to work correctly on UBL.
912
+      #if IS_KINEMATIC                                                          // Use Kinematic / Cartesian cases as a workaround for now.
913
+        ubl.prepare_segmented_line_to(destination, MMS_SCALED(feedrate_mm_s))
912
       #else
914
       #else
913
         prepare_move_to_destination_cartesian()
915
         prepare_move_to_destination_cartesian()
914
       #endif
916
       #endif
1499
           soft_endstop_min[X_AXIS] = X2_MIN_POS;
1501
           soft_endstop_min[X_AXIS] = X2_MIN_POS;
1500
           soft_endstop_max[X_AXIS] = dual_max_x;
1502
           soft_endstop_max[X_AXIS] = dual_max_x;
1501
         }
1503
         }
1502
-        else if (dual_x_carriage_mode == DXC_DUPLICATION_MODE) {
1504
+        else if (dxc_is_duplicating()) {
1503
           // In Duplication Mode, T0 can move as far left as X_MIN_POS
1505
           // In Duplication Mode, T0 can move as far left as X_MIN_POS
1504
           // but not so far to the right that T1 would move past the end
1506
           // but not so far to the right that T1 would move past the end
1505
           soft_endstop_min[X_AXIS] = base_min_pos(X_AXIS);
1507
           soft_endstop_min[X_AXIS] = base_min_pos(X_AXIS);

+ 7
- 4
Marlin/src/module/motion.h View File

305
  */
305
  */
306
 #if ENABLED(DUAL_X_CARRIAGE) || ENABLED(DUAL_NOZZLE_DUPLICATION_MODE)
306
 #if ENABLED(DUAL_X_CARRIAGE) || ENABLED(DUAL_NOZZLE_DUPLICATION_MODE)
307
   extern bool extruder_duplication_enabled,       // Used in Dual X mode 2
307
   extern bool extruder_duplication_enabled,       // Used in Dual X mode 2
308
-              symmetric_duplication_mode;         // Used in Dual X mode 2
308
+              scaled_duplication_mode;            // Used in Dual X mode 3
309
 #endif
309
 #endif
310
 
310
 
311
 /**
311
 /**
314
 #if ENABLED(DUAL_X_CARRIAGE)
314
 #if ENABLED(DUAL_X_CARRIAGE)
315
 
315
 
316
   enum DualXMode : char {
316
   enum DualXMode : char {
317
-    DXC_FULL_CONTROL_MODE,  // DUAL_X_CARRIAGE only
318
-    DXC_AUTO_PARK_MODE,     // DUAL_X_CARRIAGE only
319
-    DXC_DUPLICATION_MODE
317
+    DXC_FULL_CONTROL_MODE,
318
+    DXC_AUTO_PARK_MODE,
319
+    DXC_DUPLICATION_MODE,
320
+    DXC_SCALED_DUPLICATION_MODE
320
   };
321
   };
321
 
322
 
322
   extern DualXMode dual_x_carriage_mode;
323
   extern DualXMode dual_x_carriage_mode;
327
   extern millis_t delayed_move_time;              // used in mode 1
328
   extern millis_t delayed_move_time;              // used in mode 1
328
   extern int16_t duplicate_extruder_temp_offset;  // used in mode 2 & 3
329
   extern int16_t duplicate_extruder_temp_offset;  // used in mode 2 & 3
329
 
330
 
331
+  FORCE_INLINE bool dxc_is_duplicating() { return dual_x_carriage_mode >= DXC_DUPLICATION_MODE; }
332
+
330
   float x_home_pos(const int extruder);
333
   float x_home_pos(const int extruder);
331
 
334
 
332
   FORCE_INLINE int x_home_dir(const uint8_t extruder) { return extruder ? X2_HOME_DIR : X_HOME_DIR; }
335
   FORCE_INLINE int x_home_dir(const uint8_t extruder) { return extruder ? X2_HOME_DIR : X_HOME_DIR; }

+ 1
- 1
Marlin/src/module/stepper.cpp View File

251
   #define X_APPLY_DIR(v,ALWAYS) \
251
   #define X_APPLY_DIR(v,ALWAYS) \
252
     if (extruder_duplication_enabled || ALWAYS) { \
252
     if (extruder_duplication_enabled || ALWAYS) { \
253
       X_DIR_WRITE(v); \
253
       X_DIR_WRITE(v); \
254
-      X2_DIR_WRITE(bool(v)); \
254
+      X2_DIR_WRITE(v); \
255
     } \
255
     } \
256
     else { \
256
     else { \
257
       if (movement_extruder()) X2_DIR_WRITE(v); else X_DIR_WRITE(v); \
257
       if (movement_extruder()) X2_DIR_WRITE(v); else X_DIR_WRITE(v); \

+ 1
- 4
Marlin/src/module/stepper.h View File

472
       #endif
472
       #endif
473
     }
473
     }
474
 
474
 
475
-  private:
476
-
477
     // Set direction bits for all steppers
475
     // Set direction bits for all steppers
478
     static void set_directions();
476
     static void set_directions();
479
 
477
 
480
-    // Allow reset_stepper_drivers to access private set_directions
481
-    friend void reset_stepper_drivers();
478
+  private:
482
 
479
 
483
     // Set the current position in steps
480
     // Set the current position in steps
484
     static void _set_position(const int32_t &a, const int32_t &b, const int32_t &c, const int32_t &e);
481
     static void _set_position(const int32_t &a, const int32_t &b, const int32_t &c, const int32_t &e);

+ 12
- 3
Marlin/src/module/stepper_indirection.h View File

562
   #define    REV_E_DIR(E)   do{ switch (E) { case 0: E0_DIR_WRITE( INVERT_E0_DIR); break; case 1: E1_DIR_WRITE( INVERT_E1_DIR); break; case 2: E2_DIR_WRITE( INVERT_E2_DIR); } }while(0)
562
   #define    REV_E_DIR(E)   do{ switch (E) { case 0: E0_DIR_WRITE( INVERT_E0_DIR); break; case 1: E1_DIR_WRITE( INVERT_E1_DIR); break; case 2: E2_DIR_WRITE( INVERT_E2_DIR); } }while(0)
563
 #elif E_STEPPERS > 1
563
 #elif E_STEPPERS > 1
564
   #if ENABLED(DUAL_X_CARRIAGE) || ENABLED(DUAL_NOZZLE_DUPLICATION_MODE)
564
   #if ENABLED(DUAL_X_CARRIAGE) || ENABLED(DUAL_NOZZLE_DUPLICATION_MODE)
565
-    #define E_STEP_WRITE(E,V) do{ if (extruder_duplication_enabled) { E0_STEP_WRITE(V); E1_STEP_WRITE(V); } else if (E == 0) { E0_STEP_WRITE(V); } else { E1_STEP_WRITE(V); } }while(0)
566
-    #define   NORM_E_DIR(E)   do{ if (extruder_duplication_enabled) { E0_DIR_WRITE(!INVERT_E0_DIR); E1_DIR_WRITE(!INVERT_E1_DIR); } else if (E == 0) { E0_DIR_WRITE(!INVERT_E0_DIR); } else { E1_DIR_WRITE(!INVERT_E1_DIR); } }while(0)
567
-    #define    REV_E_DIR(E)   do{ if (extruder_duplication_enabled) { E0_DIR_WRITE( INVERT_E0_DIR); E1_DIR_WRITE( INVERT_E1_DIR); } else if (E == 0) { E0_DIR_WRITE( INVERT_E0_DIR); } else { E1_DIR_WRITE( INVERT_E1_DIR); } }while(0)
565
+
566
+    #define E_STEP_WRITE(E,V) do{ if (extruder_duplication_enabled)  { E0_STEP_WRITE(V); E1_STEP_WRITE(V); } \
567
+                                                  else if ((E) == 0) { E0_STEP_WRITE(V); } \
568
+                                                  else               { E1_STEP_WRITE(V); } }while(0)
569
+
570
+    #define   NORM_E_DIR(E)   do{ if (extruder_duplication_enabled)  { E0_DIR_WRITE(!INVERT_E0_DIR); E1_DIR_WRITE(!INVERT_E1_DIR); } \
571
+                                                  else if ((E) == 0) { E0_DIR_WRITE(!INVERT_E0_DIR); } \
572
+                                                  else               { E1_DIR_WRITE(!INVERT_E1_DIR); } }while(0)
573
+
574
+    #define    REV_E_DIR(E)   do{ if (extruder_duplication_enabled)  { E0_DIR_WRITE( INVERT_E0_DIR); E1_DIR_WRITE( INVERT_E1_DIR); } \
575
+                                                  else if ((E) == 0) { E0_DIR_WRITE( INVERT_E0_DIR); } \
576
+                                                  else               { E1_DIR_WRITE( INVERT_E1_DIR); } }while(0)
568
   #else
577
   #else
569
     #define E_STEP_WRITE(E,V) do{ if (E == 0) { E0_STEP_WRITE(V); } else { E1_STEP_WRITE(V); } }while(0)
578
     #define E_STEP_WRITE(E,V) do{ if (E == 0) { E0_STEP_WRITE(V); } else { E1_STEP_WRITE(V); } }while(0)
570
     #define   NORM_E_DIR(E)   do{ if (E == 0) { E0_DIR_WRITE(!INVERT_E0_DIR); } else { E1_DIR_WRITE(!INVERT_E1_DIR); } }while(0)
579
     #define   NORM_E_DIR(E)   do{ if (E == 0) { E0_DIR_WRITE(!INVERT_E0_DIR); } else { E1_DIR_WRITE(!INVERT_E1_DIR); } }while(0)

+ 4
- 3
Marlin/src/module/tool_change.cpp View File

366
         switch (dual_x_carriage_mode) {
366
         switch (dual_x_carriage_mode) {
367
           case DXC_FULL_CONTROL_MODE: SERIAL_ECHOLNPGM("DXC_FULL_CONTROL_MODE"); break;
367
           case DXC_FULL_CONTROL_MODE: SERIAL_ECHOLNPGM("DXC_FULL_CONTROL_MODE"); break;
368
           case DXC_AUTO_PARK_MODE: SERIAL_ECHOLNPGM("DXC_AUTO_PARK_MODE"); break;
368
           case DXC_AUTO_PARK_MODE: SERIAL_ECHOLNPGM("DXC_AUTO_PARK_MODE"); break;
369
+          case DXC_DUPLICATION_MODE: SERIAL_ECHOLNPGM("DXC_DUPLICATION_MODE"); break;
370
+          case DXC_SCALED_DUPLICATION_MODE: SERIAL_ECHOLNPGM("DXC_SCALED_DUPLICATION_MODE"); break;
369
         }
371
         }
370
       }
372
       }
371
     #endif
373
     #endif
455
 void tool_change(const uint8_t tmp_extruder, const float fr_mm_s/*=0.0*/, bool no_move/*=false*/) {
457
 void tool_change(const uint8_t tmp_extruder, const float fr_mm_s/*=0.0*/, bool no_move/*=false*/) {
456
   planner.synchronize();
458
   planner.synchronize();
457
 
459
 
458
-  #if ENABLED(DUAL_X_CARRIAGE)
459
-    // Only T0 allowed in DXC_DUPLICATION_MODE
460
-    if (tmp_extruder != 0 && dual_x_carriage_mode == DXC_DUPLICATION_MODE)
460
+  #if ENABLED(DUAL_X_CARRIAGE)  // Only T0 allowed if the Printer is in DXC_DUPLICATION_MODE or DXC_SCALED_DUPLICATION_MODE
461
+    if (tmp_extruder != 0 && dxc_is_duplicating())
461
        return invalid_extruder_error(tmp_extruder);
462
        return invalid_extruder_error(tmp_extruder);
462
   #endif
463
   #endif
463
 
464
 

+ 10
- 12
Marlin/src/pins/pins_FORMBOT_TREX2.h View File

28
   #error "Oops!  Make sure you have 'Arduino Mega' selected from the 'Tools -> Boards' menu."
28
   #error "Oops!  Make sure you have 'Arduino Mega' selected from the 'Tools -> Boards' menu."
29
 #endif
29
 #endif
30
 
30
 
31
-#if E_STEPPERS > 3 || HOTENDS > 3
32
-  #error "Formbot supports up to 3 hotends / E-steppers. Comment this line to keep going."
31
+#if E_STEPPERS > 2 || HOTENDS > 2
32
+  #error "Formbot supports up to 2 hotends / E-steppers. Comment this line to keep going."
33
 #endif
33
 #endif
34
 
34
 
35
 #define DEFAULT_MACHINE_NAME "Formbot"
35
 #define DEFAULT_MACHINE_NAME "Formbot"
143
 #define HEATER_BED_PIN     58
143
 #define HEATER_BED_PIN     58
144
 
144
 
145
 #define FAN_PIN             9
145
 #define FAN_PIN             9
146
-#define FAN1_PIN            4
146
+//#define FAN1_PIN            4
147
 
147
 
148
 
148
 
149
 #if DISABLED(ICSP_PORT_SWITCHES)
149
 #if DISABLED(ICSP_PORT_SWITCHES)
150
-  #define FIL_RUNOUT_PIN    22
151
-  #define FIL_RUNOUT2_PIN   21
152
-#else
153
-  #if ENABLED(FILAMENT_RUNOUT_SENSOR)
154
-    #define FIL_RUNOUT_PIN  52
155
-    #define FIL_RUNOUT2_PIN 50
156
-  #endif
150
+  //#define FIL_RUNOUT_PIN    22
151
+  //#define FIL_RUNOUT2_PIN   21
152
+#elif ENABLED(FILAMENT_RUNOUT_SENSOR)
153
+  #define FIL_RUNOUT_PIN   52
154
+  #define FIL_RUNOUT2_PIN  50
157
 #endif
155
 #endif
158
 
156
 
159
 //
157
 //
162
 #define CASE_LIGHT_PIN      8
160
 #define CASE_LIGHT_PIN      8
163
 #define SDSS               53
161
 #define SDSS               53
164
 #ifndef ROXYs_TRex
162
 #ifndef ROXYs_TRex
165
-  #define LED_PIN          13
166
-#endif
163
+  #define LED_PIN          13   // The Formbot v 1 board has almost no unassigned pins on it.  The Board's LED
164
+#endif                          // is a good place to get a signal to control the Max7219 LED Matrix.
167
 
165
 
168
 // Use the RAMPS 1.4 Analog input 5 on the AUX2 connector
166
 // Use the RAMPS 1.4 Analog input 5 on the AUX2 connector
169
 #define FILWIDTH_PIN        5   // Analog Input
167
 #define FILWIDTH_PIN        5   // Analog Input

+ 5
- 13
Marlin/src/pins/pins_FORMBOT_TREX3.h View File

28
   #error "Oops!  Make sure you have 'Arduino Mega' selected from the 'Tools -> Boards' menu."
28
   #error "Oops!  Make sure you have 'Arduino Mega' selected from the 'Tools -> Boards' menu."
29
 #endif
29
 #endif
30
 
30
 
31
-#if E_STEPPERS > 3 || HOTENDS > 3
32
-  #error "Formbot supports up to 3 hotends / E-steppers. Comment this line to keep going."
31
+#if E_STEPPERS > 2 || HOTENDS > 2
32
+  #error "Formbot supports up to 2 hotends / E-steppers. Comment this line to keep going."
33
 #endif
33
 #endif
34
 
34
 
35
 #define DEFAULT_MACHINE_NAME "Formbot"
35
 #define DEFAULT_MACHINE_NAME "Formbot"
143
 #define HEATER_BED_PIN      8
143
 #define HEATER_BED_PIN      8
144
 
144
 
145
 #define FAN_PIN             9
145
 #define FAN_PIN             9
146
-#define FAN1_PIN            4
146
+//#define FAN1_PIN          4
147
 
147
 
148
-
149
-#if DISABLED(ICSP_PORT_SWITCHES)
150
-  #define FIL_RUNOUT_PIN    22
151
-  #define FIL_RUNOUT2_PIN   21
152
-#else
153
-  #if ENABLED(FILAMENT_RUNOUT_SENSOR)
154
-    #define FIL_RUNOUT_PIN  52
155
-    #define FIL_RUNOUT2_PIN 50
156
-  #endif
157
-#endif
148
+#define FIL_RUNOUT_PIN     23
149
+#define FIL_RUNOUT2_PIN    21
158
 
150
 
159
 //
151
 //
160
 // Misc. Functions
152
 // Misc. Functions

Loading…
Cancel
Save