|
@@ -677,7 +677,46 @@ XYZ_CONSTS_FROM_CONFIG(float, max_length, MAX_LENGTH);
|
677
|
677
|
XYZ_CONSTS_FROM_CONFIG(float, home_retract_mm, HOME_RETRACT_MM);
|
678
|
678
|
XYZ_CONSTS_FROM_CONFIG(signed char, home_dir, HOME_DIR);
|
679
|
679
|
|
|
680
|
+#ifdef DUAL_X_CARRIAGE
|
|
681
|
+ #if EXTRUDERS == 1 || defined(COREXY) \
|
|
682
|
+ || !defined(X2_ENABLE_PIN) || !defined(X2_STEP_PIN) || !defined(X2_DIR_PIN) \
|
|
683
|
+ || !defined(X2_HOME_POS) || !defined(X2_MIN_POS) || !defined(X2_MAX_POS) \
|
|
684
|
+ || !defined(X_MAX_PIN) || X_MAX_PIN < 0
|
|
685
|
+ #error "Missing or invalid definitions for DUAL_X_CARRIAGE mode."
|
|
686
|
+ #endif
|
|
687
|
+ #if X_HOME_DIR != -1 || X2_HOME_DIR != 1
|
|
688
|
+ #error "Please use canonical x-carriage assignment" // the x-carriages are defined by their homing directions
|
|
689
|
+ #endif
|
|
690
|
+
|
|
691
|
+static float x_home_pos(int extruder) {
|
|
692
|
+ if (extruder == 0)
|
|
693
|
+ return base_home_pos(X_AXIS) + add_homeing[X_AXIS];
|
|
694
|
+ else
|
|
695
|
+ // In dual carriage mode the extruder offset provides an override of the
|
|
696
|
+ // second X-carriage offset when homed - otherwise X2_HOME_POS is used.
|
|
697
|
+ // This allow soft recalibration of the second extruder offset position without firmware reflash
|
|
698
|
+ // (through the M218 command).
|
|
699
|
+ return (extruder_offset[X_AXIS][1] != 0) ? extruder_offset[X_AXIS][1] : X2_HOME_POS;
|
|
700
|
+}
|
|
701
|
+
|
|
702
|
+static int x_home_dir(int extruder) {
|
|
703
|
+ return (extruder == 0) ? X_HOME_DIR : X2_HOME_DIR;
|
|
704
|
+}
|
|
705
|
+
|
|
706
|
+static bool active_extruder_parked = false;
|
|
707
|
+static float raised_parked_position[NUM_AXIS];
|
|
708
|
+static unsigned long delayed_move_time = 0;
|
|
709
|
+#endif
|
|
710
|
+
|
680
|
711
|
static void axis_is_at_home(int axis) {
|
|
712
|
+#ifdef DUAL_X_CARRIAGE
|
|
713
|
+ if (axis == X_AXIS && active_extruder != 0) {
|
|
714
|
+ current_position[X_AXIS] = x_home_pos(active_extruder);
|
|
715
|
+ min_pos[X_AXIS] = X2_MIN_POS;
|
|
716
|
+ max_pos[X_AXIS] = X2_MAX_POS;
|
|
717
|
+ return;
|
|
718
|
+ }
|
|
719
|
+#endif
|
681
|
720
|
current_position[axis] = base_home_pos(axis) + add_homeing[axis];
|
682
|
721
|
min_pos[axis] = base_min_pos(axis) + add_homeing[axis];
|
683
|
722
|
max_pos[axis] = base_max_pos(axis) + add_homeing[axis];
|
|
@@ -686,10 +725,16 @@ static void axis_is_at_home(int axis) {
|
686
|
725
|
static void homeaxis(int axis) {
|
687
|
726
|
#define HOMEAXIS_DO(LETTER) \
|
688
|
727
|
((LETTER##_MIN_PIN > -1 && LETTER##_HOME_DIR==-1) || (LETTER##_MAX_PIN > -1 && LETTER##_HOME_DIR==1))
|
|
728
|
+
|
689
|
729
|
if (axis==X_AXIS ? HOMEAXIS_DO(X) :
|
690
|
730
|
axis==Y_AXIS ? HOMEAXIS_DO(Y) :
|
691
|
731
|
axis==Z_AXIS ? HOMEAXIS_DO(Z) :
|
692
|
732
|
0) {
|
|
733
|
+ int axis_home_dir = home_dir(axis);
|
|
734
|
+#ifdef DUAL_X_CARRIAGE
|
|
735
|
+ if (axis == X_AXIS)
|
|
736
|
+ axis_home_dir = x_home_dir(active_extruder);
|
|
737
|
+#endif
|
693
|
738
|
|
694
|
739
|
// Engage Servo endstop if enabled
|
695
|
740
|
#ifdef SERVO_ENDSTOPS
|
|
@@ -864,8 +909,14 @@ void process_commands()
|
864
|
909
|
{
|
865
|
910
|
current_position[X_AXIS] = 0;current_position[Y_AXIS] = 0;
|
866
|
911
|
|
|
912
|
+ #ifdef DUAL_X_CARRIAGE
|
|
913
|
+ int x_axis_home_dir = home_dir(X_AXIS);
|
|
914
|
+ #else
|
|
915
|
+ int x_axis_home_dir = x_home_dir(active_extruder);
|
|
916
|
+ #endif
|
|
917
|
+
|
867
|
918
|
plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
|
868
|
|
- destination[X_AXIS] = 1.5 * X_MAX_LENGTH * X_HOME_DIR;destination[Y_AXIS] = 1.5 * Y_MAX_LENGTH * Y_HOME_DIR;
|
|
919
|
+ destination[X_AXIS] = 1.5 * max_length(X_AXIS) * x_axis_home_dir;destination[Y_AXIS] = 1.5 * max_length(Y_AXIS) * home_dir(Y_AXIS);
|
869
|
920
|
feedrate = homing_feedrate[X_AXIS];
|
870
|
921
|
if(homing_feedrate[Y_AXIS]<feedrate)
|
871
|
922
|
feedrate =homing_feedrate[Y_AXIS];
|
|
@@ -890,6 +941,14 @@ void process_commands()
|
890
|
941
|
|
891
|
942
|
if((home_all_axis) || (code_seen(axis_codes[X_AXIS])))
|
892
|
943
|
{
|
|
944
|
+ #ifdef DUAL_X_CARRIAGE
|
|
945
|
+ int tmp_extruder = active_extruder;
|
|
946
|
+ active_extruder = !active_extruder;
|
|
947
|
+ HOMEAXIS(X);
|
|
948
|
+ active_extruder = tmp_extruder;
|
|
949
|
+ active_extruder_parked = false;
|
|
950
|
+ delayed_move_time = 0;
|
|
951
|
+ #endif
|
893
|
952
|
HOMEAXIS(X);
|
894
|
953
|
}
|
895
|
954
|
|
|
@@ -922,7 +981,7 @@ void process_commands()
|
922
|
981
|
}
|
923
|
982
|
}
|
924
|
983
|
plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
|
925
|
|
-#endif // DELTA
|
|
984
|
+#endif // else DELTA
|
926
|
985
|
|
927
|
986
|
#ifdef ENDSTOPS_ONLY_FOR_HOMING
|
928
|
987
|
enable_endstops(false);
|
|
@@ -2001,6 +2060,36 @@ void process_commands()
|
2001
|
2060
|
if(tmp_extruder != active_extruder) {
|
2002
|
2061
|
// Save current position to return to after applying extruder offset
|
2003
|
2062
|
memcpy(destination, current_position, sizeof(destination));
|
|
2063
|
+ #ifdef DUAL_X_CARRIAGE
|
|
2064
|
+ if (Stopped == false && delayed_move_time == 0 && current_position[X_AXIS] != x_home_pos(active_extruder))
|
|
2065
|
+ {
|
|
2066
|
+ // Park old head: 1) raise 2) move to park position 3) lower
|
|
2067
|
+ plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS] + TOOLCHANGE_PARK_ZLIFT,
|
|
2068
|
+ current_position[E_AXIS], max_feedrate[Z_AXIS], active_extruder);
|
|
2069
|
+ plan_buffer_line(x_home_pos(active_extruder), current_position[Y_AXIS], current_position[Z_AXIS] + TOOLCHANGE_PARK_ZLIFT,
|
|
2070
|
+ current_position[E_AXIS], max_feedrate[X_AXIS], active_extruder);
|
|
2071
|
+ plan_buffer_line(x_home_pos(active_extruder), current_position[Y_AXIS], current_position[Z_AXIS],
|
|
2072
|
+ current_position[E_AXIS], max_feedrate[Z_AXIS], active_extruder);
|
|
2073
|
+ st_synchronize();
|
|
2074
|
+ }
|
|
2075
|
+
|
|
2076
|
+ // only apply Y extruder offset in dual x carriage mode (x offset is already used in determining home pos)
|
|
2077
|
+ current_position[Y_AXIS] = current_position[Y_AXIS] -
|
|
2078
|
+ extruder_offset[Y_AXIS][active_extruder] +
|
|
2079
|
+ extruder_offset[Y_AXIS][tmp_extruder];
|
|
2080
|
+
|
|
2081
|
+ active_extruder = tmp_extruder;
|
|
2082
|
+
|
|
2083
|
+ // Inactive head always starts at its parked position.
|
|
2084
|
+ axis_is_at_home(X_AXIS);
|
|
2085
|
+
|
|
2086
|
+ // record raised toolhead position for use by unpark
|
|
2087
|
+ memcpy(raised_parked_position, current_position, sizeof(raised_parked_position));
|
|
2088
|
+ raised_parked_position[Z_AXIS] += TOOLCHANGE_UNPARK_ZLIFT;
|
|
2089
|
+
|
|
2090
|
+ active_extruder_parked = true;
|
|
2091
|
+ delayed_move_time = 0;
|
|
2092
|
+ #else
|
2004
|
2093
|
// Offset extruder (only by XY)
|
2005
|
2094
|
int i;
|
2006
|
2095
|
for(i = 0; i < 2; i++) {
|
|
@@ -2010,6 +2099,7 @@ void process_commands()
|
2010
|
2099
|
}
|
2011
|
2100
|
// Set the new active extruder and position
|
2012
|
2101
|
active_extruder = tmp_extruder;
|
|
2102
|
+ #endif //else DUAL_X_CARRIAGE
|
2013
|
2103
|
plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
|
2014
|
2104
|
// Move to the old position if 'F' was in the parameters
|
2015
|
2105
|
if(make_move && Stopped == false) {
|
|
@@ -2204,6 +2294,40 @@ void prepare_move()
|
2204
|
2294
|
active_extruder);
|
2205
|
2295
|
}
|
2206
|
2296
|
#else
|
|
2297
|
+
|
|
2298
|
+#if defined(DUAL_X_CARRIAGE)
|
|
2299
|
+ if (active_extruder_parked)
|
|
2300
|
+ {
|
|
2301
|
+ if (current_position[E_AXIS] == destination[E_AXIS])
|
|
2302
|
+ {
|
|
2303
|
+ // this is a travel move
|
|
2304
|
+#ifdef TOOLCHANGE_UNPARK_SKIP_TRAVEL_MOVES
|
|
2305
|
+ if (delayed_move_time != 0xFFFFFFFFUL)
|
|
2306
|
+ {
|
|
2307
|
+ // skip this move but still update current_position in main so that it can
|
|
2308
|
+ // be used as starting position before extrusion (but not in planner)
|
|
2309
|
+ memcpy(current_position, destination, sizeof(current_position));
|
|
2310
|
+ if (destination[Z_AXIS] > raised_parked_position[Z_AXIS])
|
|
2311
|
+ raised_parked_position[Z_AXIS] = destination[Z_AXIS];
|
|
2312
|
+ delayed_move_time = millis();
|
|
2313
|
+ return;
|
|
2314
|
+ }
|
|
2315
|
+ delayed_move_time = 0;
|
|
2316
|
+#else
|
|
2317
|
+ // this will cause the unpark code below to execute the specified lift in moving to the initial (travel move) position.
|
|
2318
|
+ memcpy(current_position, destination, sizeof(current_position));
|
|
2319
|
+#endif
|
|
2320
|
+ }
|
|
2321
|
+ // unpark extruder: 1) raise, 2) move into starting XY position, 3) lower
|
|
2322
|
+ 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);
|
|
2323
|
+ plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], raised_parked_position[Z_AXIS],
|
|
2324
|
+ current_position[E_AXIS], min(max_feedrate[X_AXIS],max_feedrate[Y_AXIS]), active_extruder);
|
|
2325
|
+ plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS],
|
|
2326
|
+ current_position[E_AXIS], max_feedrate[Z_AXIS], active_extruder);
|
|
2327
|
+ active_extruder_parked = false;
|
|
2328
|
+ }
|
|
2329
|
+#endif //DUAL_X_CARRIAGE
|
|
2330
|
+
|
2207
|
2331
|
// Do not use feedmultiply for E or Z only moves
|
2208
|
2332
|
if( (current_position[X_AXIS] == destination [X_AXIS]) && (current_position[Y_AXIS] == destination [Y_AXIS])) {
|
2209
|
2333
|
plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder);
|
|
@@ -2254,6 +2378,9 @@ void controllerFan()
|
2254
|
2378
|
|| !READ(E2_ENABLE_PIN)
|
2255
|
2379
|
#endif
|
2256
|
2380
|
#if EXTRUDER > 1
|
|
2381
|
+ #if defined(X2_ENABLE_PIN) && X2_ENABLE_PIN > -1
|
|
2382
|
+ || !READ(X2_ENABLE_PIN)
|
|
2383
|
+ #endif
|
2257
|
2384
|
|| !READ(E1_ENABLE_PIN)
|
2258
|
2385
|
#endif
|
2259
|
2386
|
|| !READ(E0_ENABLE_PIN)) //If any of the drivers are enabled...
|
|
@@ -2320,6 +2447,16 @@ void manage_inactivity()
|
2320
|
2447
|
WRITE(E0_ENABLE_PIN,oldstatus);
|
2321
|
2448
|
}
|
2322
|
2449
|
#endif
|
|
2450
|
+ #if defined(DUAL_X_CARRIAGE) && defined(TOOLCHANGE_UNPARK_SKIP_TRAVEL_MOVES)
|
|
2451
|
+ // handle delayed move timeout
|
|
2452
|
+ if (delayed_move_time != 0 && (millis() - delayed_move_time) > 1000)
|
|
2453
|
+ {
|
|
2454
|
+ // travel moves have been received so enact them
|
|
2455
|
+ delayed_move_time = 0xFFFFFFFFUL; // force moves to be done
|
|
2456
|
+ memcpy(destination,current_position,sizeof(destination));
|
|
2457
|
+ prepare_move();
|
|
2458
|
+ }
|
|
2459
|
+ #endif
|
2323
|
2460
|
check_axes_activity();
|
2324
|
2461
|
}
|
2325
|
2462
|
|