|
|
@ -6948,6 +6948,9 @@ inline void gcode_M503() { |
|
|
|
stepper.synchronize(); |
|
|
|
if (code_seen('S')) dual_x_carriage_mode = (DualXMode)code_value_byte(); |
|
|
|
switch (dual_x_carriage_mode) { |
|
|
|
case DXC_FULL_CONTROL_MODE: |
|
|
|
case DXC_AUTO_PARK_MODE: |
|
|
|
break; |
|
|
|
case DXC_DUPLICATION_MODE: |
|
|
|
if (code_seen('X')) duplicate_extruder_x_offset = max(code_value_axis_units(X_AXIS), X2_MIN_POS - x_home_pos(0)); |
|
|
|
if (code_seen('R')) duplicate_extruder_temp_offset = code_value_temp_diff(); |
|
|
@ -6962,9 +6965,6 @@ inline void gcode_M503() { |
|
|
|
SERIAL_CHAR(','); |
|
|
|
SERIAL_ECHOLN(hotend_offset[Y_AXIS][1]); |
|
|
|
break; |
|
|
|
case DXC_FULL_CONTROL_MODE: |
|
|
|
case DXC_AUTO_PARK_MODE: |
|
|
|
break; |
|
|
|
default: |
|
|
|
dual_x_carriage_mode = DEFAULT_DUAL_X_CARRIAGE_MODE; |
|
|
|
break; |
|
|
@ -7254,9 +7254,9 @@ void tool_change(const uint8_t tmp_extruder, const float fr_mm_s/*=0.0*/, bool n |
|
|
|
if (DEBUGGING(LEVELING)) { |
|
|
|
SERIAL_ECHOPGM("Dual X Carriage Mode "); |
|
|
|
switch (dual_x_carriage_mode) { |
|
|
|
case DXC_DUPLICATION_MODE: SERIAL_ECHOLNPGM("DXC_DUPLICATION_MODE"); break; |
|
|
|
case DXC_AUTO_PARK_MODE: SERIAL_ECHOLNPGM("DXC_AUTO_PARK_MODE"); break; |
|
|
|
case DXC_FULL_CONTROL_MODE: SERIAL_ECHOLNPGM("DXC_FULL_CONTROL_MODE"); break; |
|
|
|
case DXC_AUTO_PARK_MODE: SERIAL_ECHOLNPGM("DXC_AUTO_PARK_MODE"); break; |
|
|
|
case DXC_DUPLICATION_MODE: SERIAL_ECHOLNPGM("DXC_DUPLICATION_MODE"); break; |
|
|
|
} |
|
|
|
} |
|
|
|
#endif |
|
|
@ -8974,39 +8974,45 @@ void set_current_from_steppers_for_axis(const AxisEnum axis) { |
|
|
|
*/ |
|
|
|
inline bool prepare_move_to_destination_dualx() { |
|
|
|
if (active_extruder_parked) { |
|
|
|
if (dual_x_carriage_mode == DXC_DUPLICATION_MODE && active_extruder == 0) { |
|
|
|
// move duplicate extruder into correct duplication position.
|
|
|
|
planner.set_position_mm( |
|
|
|
LOGICAL_X_POSITION(inactive_extruder_x_pos), |
|
|
|
current_position[Y_AXIS], |
|
|
|
current_position[Z_AXIS], |
|
|
|
current_position[E_AXIS] |
|
|
|
); |
|
|
|
planner.buffer_line(current_position[X_AXIS] + duplicate_extruder_x_offset, |
|
|
|
current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], planner.max_feedrate_mm_s[X_AXIS], 1); |
|
|
|
SYNC_PLAN_POSITION_KINEMATIC(); |
|
|
|
stepper.synchronize(); |
|
|
|
extruder_duplication_enabled = true; |
|
|
|
active_extruder_parked = false; |
|
|
|
} |
|
|
|
else if (dual_x_carriage_mode == DXC_AUTO_PARK_MODE) { // handle unparking of head
|
|
|
|
if (current_position[E_AXIS] == destination[E_AXIS]) { |
|
|
|
// This is a travel move (with no extrusion)
|
|
|
|
// Skip it, but keep track of the current position
|
|
|
|
// (so it can be used as the start of the next non-travel move)
|
|
|
|
if (delayed_move_time != 0xFFFFFFFFUL) { |
|
|
|
set_current_to_destination(); |
|
|
|
NOLESS(raised_parked_position[Z_AXIS], destination[Z_AXIS]); |
|
|
|
delayed_move_time = millis(); |
|
|
|
return false; |
|
|
|
switch (dual_x_carriage_mode) { |
|
|
|
case DXC_FULL_CONTROL_MODE: |
|
|
|
break; |
|
|
|
case DXC_DUPLICATION_MODE: |
|
|
|
if (active_extruder == 0) { |
|
|
|
// move duplicate extruder into correct duplication position.
|
|
|
|
planner.set_position_mm( |
|
|
|
LOGICAL_X_POSITION(inactive_extruder_x_pos), |
|
|
|
current_position[Y_AXIS], |
|
|
|
current_position[Z_AXIS], |
|
|
|
current_position[E_AXIS] |
|
|
|
); |
|
|
|
planner.buffer_line(current_position[X_AXIS] + duplicate_extruder_x_offset, |
|
|
|
current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], planner.max_feedrate_mm_s[X_AXIS], 1); |
|
|
|
SYNC_PLAN_POSITION_KINEMATIC(); |
|
|
|
stepper.synchronize(); |
|
|
|
extruder_duplication_enabled = true; |
|
|
|
active_extruder_parked = false; |
|
|
|
} |
|
|
|
} |
|
|
|
delayed_move_time = 0; |
|
|
|
// unpark extruder: 1) raise, 2) move into starting XY position, 3) lower
|
|
|
|
planner.buffer_line(raised_parked_position[X_AXIS], raised_parked_position[Y_AXIS], raised_parked_position[Z_AXIS], current_position[E_AXIS], planner.max_feedrate_mm_s[Z_AXIS], active_extruder); |
|
|
|
planner.buffer_line(current_position[X_AXIS], current_position[Y_AXIS], raised_parked_position[Z_AXIS], current_position[E_AXIS], PLANNER_XY_FEEDRATE(), active_extruder); |
|
|
|
planner.buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], planner.max_feedrate_mm_s[Z_AXIS], active_extruder); |
|
|
|
active_extruder_parked = false; |
|
|
|
break; |
|
|
|
case DXC_AUTO_PARK_MODE: |
|
|
|
if (current_position[E_AXIS] == destination[E_AXIS]) { |
|
|
|
// This is a travel move (with no extrusion)
|
|
|
|
// Skip it, but keep track of the current position
|
|
|
|
// (so it can be used as the start of the next non-travel move)
|
|
|
|
if (delayed_move_time != 0xFFFFFFFFUL) { |
|
|
|
set_current_to_destination(); |
|
|
|
NOLESS(raised_parked_position[Z_AXIS], destination[Z_AXIS]); |
|
|
|
delayed_move_time = millis(); |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
delayed_move_time = 0; |
|
|
|
// unpark extruder: 1) raise, 2) move into starting XY position, 3) lower
|
|
|
|
planner.buffer_line(raised_parked_position[X_AXIS], raised_parked_position[Y_AXIS], raised_parked_position[Z_AXIS], current_position[E_AXIS], planner.max_feedrate_mm_s[Z_AXIS], active_extruder); |
|
|
|
planner.buffer_line(current_position[X_AXIS], current_position[Y_AXIS], raised_parked_position[Z_AXIS], current_position[E_AXIS], PLANNER_XY_FEEDRATE(), active_extruder); |
|
|
|
planner.buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], planner.max_feedrate_mm_s[Z_AXIS], active_extruder); |
|
|
|
active_extruder_parked = false; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
return true; |
|
|
|