Fix IDEX layer shift and DIR states (#19756)
Co-authored-by: Scott Lahteine <thinkyhead@users.noreply.github.com>
This commit is contained in:
@ -569,7 +569,7 @@ void restore_feedrate_and_scaling() {
|
||||
soft_endstop.min.x = X2_MIN_POS;
|
||||
soft_endstop.max.x = dual_max_x;
|
||||
}
|
||||
else if (dxc_is_duplicating()) {
|
||||
else if (idex_is_duplicating()) {
|
||||
// In Duplication Mode, T0 can move as far left as X1_MIN_POS
|
||||
// but not so far to the right that T1 would move past the end
|
||||
soft_endstop.min.x = X1_MIN_POS;
|
||||
@ -932,8 +932,7 @@ FORCE_INLINE void segment_idle(millis_t &next_idle_ms) {
|
||||
#endif // !UBL_SEGMENTED
|
||||
|
||||
#if HAS_DUPLICATION_MODE
|
||||
bool extruder_duplication_enabled,
|
||||
mirrored_duplication_mode;
|
||||
bool extruder_duplication_enabled;
|
||||
#if ENABLED(MULTI_NOZZLE_DUPLICATION)
|
||||
uint8_t duplication_e_mask; // = 0
|
||||
#endif
|
||||
@ -942,12 +941,13 @@ FORCE_INLINE void segment_idle(millis_t &next_idle_ms) {
|
||||
#if ENABLED(DUAL_X_CARRIAGE)
|
||||
|
||||
DualXMode dual_x_carriage_mode = DEFAULT_DUAL_X_CARRIAGE_MODE;
|
||||
float inactive_extruder_x_pos = X2_MAX_POS, // used in mode 0 & 1
|
||||
duplicate_extruder_x_offset = DEFAULT_DUPLICATION_X_OFFSET; // used in mode 2
|
||||
xyz_pos_t raised_parked_position; // used in mode 1
|
||||
bool active_extruder_parked = false; // used in mode 1 & 2
|
||||
millis_t delayed_move_time = 0; // used in mode 1
|
||||
int16_t duplicate_extruder_temp_offset = 0; // used in mode 2
|
||||
float inactive_extruder_x = X2_MAX_POS, // Used in mode 0 & 1
|
||||
duplicate_extruder_x_offset = DEFAULT_DUPLICATION_X_OFFSET; // Used in mode 2
|
||||
xyz_pos_t raised_parked_position; // Used in mode 1
|
||||
bool active_extruder_parked = false; // Used in mode 1 & 2
|
||||
millis_t delayed_move_time = 0; // Used in mode 1
|
||||
int16_t duplicate_extruder_temp_offset = 0; // Used in mode 2
|
||||
bool idex_mirrored_mode = false; // Used in mode 3
|
||||
|
||||
float x_home_pos(const uint8_t extruder) {
|
||||
if (extruder == 0)
|
||||
@ -962,6 +962,23 @@ FORCE_INLINE void segment_idle(millis_t &next_idle_ms) {
|
||||
return hotend_offset[1].x > 0 ? hotend_offset[1].x : X2_HOME_POS;
|
||||
}
|
||||
|
||||
void idex_set_mirrored_mode(const bool mirr) {
|
||||
idex_mirrored_mode = mirr;
|
||||
stepper.set_directions();
|
||||
}
|
||||
|
||||
void set_duplication_enabled(const bool dupe, const int8_t tool_index/*=-1*/) {
|
||||
extruder_duplication_enabled = dupe;
|
||||
if (tool_index >= 0) active_extruder = tool_index;
|
||||
stepper.set_directions();
|
||||
}
|
||||
|
||||
void idex_set_parked(const bool park/*=true*/) {
|
||||
delayed_move_time = 0;
|
||||
active_extruder_parked = park;
|
||||
if (park) raised_parked_position = current_position; // Remember current raised toolhead position for use by unpark
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare a linear move in a dual X axis setup
|
||||
*
|
||||
@ -970,9 +987,10 @@ FORCE_INLINE void segment_idle(millis_t &next_idle_ms) {
|
||||
inline bool dual_x_carriage_unpark() {
|
||||
if (active_extruder_parked) {
|
||||
switch (dual_x_carriage_mode) {
|
||||
case DXC_FULL_CONTROL_MODE:
|
||||
break;
|
||||
case DXC_AUTO_PARK_MODE:
|
||||
|
||||
case DXC_FULL_CONTROL_MODE: break;
|
||||
|
||||
case DXC_AUTO_PARK_MODE: {
|
||||
if (current_position.e == destination.e) {
|
||||
// This is a travel move (with no extrusion)
|
||||
// Skip it, but keep track of the current position
|
||||
@ -984,23 +1002,27 @@ FORCE_INLINE void segment_idle(millis_t &next_idle_ms) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// unpark extruder: 1) raise, 2) move into starting XY position, 3) lower
|
||||
//
|
||||
// Un-park the active extruder
|
||||
//
|
||||
const feedRate_t fr_zfast = planner.settings.max_feedrate_mm_s[Z_AXIS];
|
||||
#define CURPOS current_position
|
||||
#define RAISED raised_parked_position
|
||||
// 1. Move to the raised parked XYZ. Presumably the tool is already at XY.
|
||||
if (planner.buffer_line(RAISED.x, RAISED.y, RAISED.z, CURPOS.e, fr_zfast, active_extruder)) {
|
||||
// 2. Move to the current native XY and raised Z. Presumably this is a null move.
|
||||
if (planner.buffer_line(CURPOS.x, CURPOS.y, RAISED.z, CURPOS.e, PLANNER_XY_FEEDRATE(), active_extruder)) {
|
||||
// 3. Lower Z back down
|
||||
line_to_current_position(fr_zfast);
|
||||
}
|
||||
}
|
||||
planner.synchronize(); // paranoia
|
||||
stepper.set_directions();
|
||||
|
||||
#define CUR_X current_position.x
|
||||
#define CUR_Y current_position.y
|
||||
#define CUR_Z current_position.z
|
||||
#define CUR_E current_position.e
|
||||
#define RAISED_X raised_parked_position.x
|
||||
#define RAISED_Y raised_parked_position.y
|
||||
#define RAISED_Z raised_parked_position.z
|
||||
idex_set_parked(false);
|
||||
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("idex_set_parked(false)");
|
||||
} break;
|
||||
|
||||
if ( planner.buffer_line(RAISED_X, RAISED_Y, RAISED_Z, CUR_E, planner.settings.max_feedrate_mm_s[Z_AXIS], active_extruder))
|
||||
if (planner.buffer_line( CUR_X, CUR_Y, RAISED_Z, CUR_E, PLANNER_XY_FEEDRATE(), active_extruder))
|
||||
line_to_current_position(planner.settings.max_feedrate_mm_s[Z_AXIS]);
|
||||
delayed_move_time = 0;
|
||||
active_extruder_parked = false;
|
||||
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("Clear active_extruder_parked");
|
||||
break;
|
||||
case DXC_MIRRORED_MODE:
|
||||
case DXC_DUPLICATION_MODE:
|
||||
if (active_extruder == 0) {
|
||||
@ -1008,22 +1030,23 @@ FORCE_INLINE void segment_idle(millis_t &next_idle_ms) {
|
||||
if (dual_x_carriage_mode == DXC_DUPLICATION_MODE)
|
||||
new_pos.x += duplicate_extruder_x_offset;
|
||||
else
|
||||
new_pos.x = inactive_extruder_x_pos;
|
||||
// move duplicate extruder into correct duplication position.
|
||||
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPAIR("Set planner X", inactive_extruder_x_pos, " ... Line to X", new_pos.x);
|
||||
planner.set_position_mm(inactive_extruder_x_pos, current_position.y, current_position.z, current_position.e);
|
||||
new_pos.x = inactive_extruder_x;
|
||||
// Move duplicate extruder into correct duplication position.
|
||||
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPAIR("Set planner X", inactive_extruder_x, " ... Line to X", new_pos.x);
|
||||
planner.set_position_mm(inactive_extruder_x, current_position.y, current_position.z, current_position.e);
|
||||
if (!planner.buffer_line(new_pos, planner.settings.max_feedrate_mm_s[X_AXIS], 1)) break;
|
||||
|
||||
planner.synchronize();
|
||||
sync_plan_position();
|
||||
extruder_duplication_enabled = true;
|
||||
active_extruder_parked = false;
|
||||
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("Set extruder_duplication_enabled\nClear active_extruder_parked");
|
||||
|
||||
set_duplication_enabled(true);
|
||||
idex_set_parked(false);
|
||||
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("set_duplication_enabled(true)\nidex_set_parked(false)");
|
||||
}
|
||||
else if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("Active extruder not 0");
|
||||
break;
|
||||
}
|
||||
}
|
||||
stepper.set_directions();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -384,8 +384,7 @@ bool homing_needed_error(uint8_t axis_bits=0x07);
|
||||
* Duplication mode
|
||||
*/
|
||||
#if HAS_DUPLICATION_MODE
|
||||
extern bool extruder_duplication_enabled, // Used in Dual X mode 2
|
||||
mirrored_duplication_mode; // Used in Dual X mode 3
|
||||
extern bool extruder_duplication_enabled; // Used in Dual X mode 2
|
||||
#if ENABLED(MULTI_NOZZLE_DUPLICATION)
|
||||
extern uint8_t duplication_e_mask;
|
||||
#endif
|
||||
@ -404,23 +403,29 @@ bool homing_needed_error(uint8_t axis_bits=0x07);
|
||||
};
|
||||
|
||||
extern DualXMode dual_x_carriage_mode;
|
||||
extern float inactive_extruder_x_pos, // Used in mode 0 & 1
|
||||
extern float inactive_extruder_x, // Used in mode 0 & 1
|
||||
duplicate_extruder_x_offset; // Used in mode 2 & 3
|
||||
extern xyz_pos_t raised_parked_position; // Used in mode 1
|
||||
extern bool active_extruder_parked; // Used in mode 1, 2 & 3
|
||||
extern millis_t delayed_move_time; // Used in mode 1
|
||||
extern int16_t duplicate_extruder_temp_offset; // Used in mode 2 & 3
|
||||
extern bool idex_mirrored_mode; // Used in mode 3
|
||||
|
||||
FORCE_INLINE bool dxc_is_duplicating() { return dual_x_carriage_mode >= DXC_DUPLICATION_MODE; }
|
||||
FORCE_INLINE bool idex_is_duplicating() { return dual_x_carriage_mode >= DXC_DUPLICATION_MODE; }
|
||||
|
||||
float x_home_pos(const uint8_t extruder);
|
||||
|
||||
FORCE_INLINE int x_home_dir(const uint8_t extruder) { return extruder ? X2_HOME_DIR : X_HOME_DIR; }
|
||||
|
||||
void set_duplication_enabled(const bool dupe, const int8_t tool_index=-1);
|
||||
void idex_set_mirrored_mode(const bool mirr);
|
||||
void idex_set_parked(const bool park=true);
|
||||
|
||||
#else
|
||||
|
||||
#if ENABLED(MULTI_NOZZLE_DUPLICATION)
|
||||
enum DualXMode : char { DXC_DUPLICATION_MODE = 2 };
|
||||
FORCE_INLINE void set_duplication_enabled(const bool dupe) { extruder_duplication_enabled = dupe; }
|
||||
#endif
|
||||
|
||||
FORCE_INLINE int x_home_dir(const uint8_t) { return home_dir(X_AXIS); }
|
||||
|
@ -348,7 +348,7 @@ xyze_int8_t Stepper::count_direction{0};
|
||||
}
|
||||
|
||||
#if ENABLED(X_DUAL_STEPPER_DRIVERS)
|
||||
#define X_APPLY_DIR(v,Q) do{ X_DIR_WRITE(v); X2_DIR_WRITE((v) != INVERT_X2_VS_X_DIR); }while(0)
|
||||
#define X_APPLY_DIR(v,Q) do{ X_DIR_WRITE(v); X2_DIR_WRITE((v) ^ ENABLED(INVERT_X2_VS_X_DIR)); }while(0)
|
||||
#if ENABLED(X_DUAL_ENDSTOPS)
|
||||
#define X_APPLY_STEP(v,Q) DUAL_ENDSTOP_APPLY_STEP(X,v)
|
||||
#else
|
||||
@ -356,7 +356,7 @@ xyze_int8_t Stepper::count_direction{0};
|
||||
#endif
|
||||
#elif ENABLED(DUAL_X_CARRIAGE)
|
||||
#define X_APPLY_DIR(v,ALWAYS) do{ \
|
||||
if (extruder_duplication_enabled || ALWAYS) { X_DIR_WRITE(v); X2_DIR_WRITE(mirrored_duplication_mode ? !(v) : v); } \
|
||||
if (extruder_duplication_enabled || ALWAYS) { X_DIR_WRITE(v); X2_DIR_WRITE((v) ^ idex_mirrored_mode); } \
|
||||
else if (last_moved_extruder) X2_DIR_WRITE(v); else X_DIR_WRITE(v); \
|
||||
}while(0)
|
||||
#define X_APPLY_STEP(v,ALWAYS) do{ \
|
||||
@ -369,7 +369,7 @@ xyze_int8_t Stepper::count_direction{0};
|
||||
#endif
|
||||
|
||||
#if ENABLED(Y_DUAL_STEPPER_DRIVERS)
|
||||
#define Y_APPLY_DIR(v,Q) do{ Y_DIR_WRITE(v); Y2_DIR_WRITE((v) != INVERT_Y2_VS_Y_DIR); }while(0)
|
||||
#define Y_APPLY_DIR(v,Q) do{ Y_DIR_WRITE(v); Y2_DIR_WRITE((v) ^ ENABLED(INVERT_Y2_VS_Y_DIR)); }while(0)
|
||||
#if ENABLED(Y_DUAL_ENDSTOPS)
|
||||
#define Y_APPLY_STEP(v,Q) DUAL_ENDSTOP_APPLY_STEP(Y,v)
|
||||
#else
|
||||
@ -1605,10 +1605,9 @@ void Stepper::pulse_phase_isr() {
|
||||
PAGE_SEGMENT_UPDATE(Z, high >> 4);
|
||||
PAGE_SEGMENT_UPDATE(E, high & 0xF);
|
||||
|
||||
if (dm != last_direction_bits) {
|
||||
last_direction_bits = dm;
|
||||
set_directions();
|
||||
}
|
||||
if (dm != last_direction_bits)
|
||||
set_directions(dm);
|
||||
|
||||
} break;
|
||||
|
||||
default: break;
|
||||
@ -2131,9 +2130,7 @@ uint32_t Stepper::block_phase_isr() {
|
||||
MIXER_STEPPER_SETUP();
|
||||
#endif
|
||||
|
||||
#if HAS_MULTI_EXTRUDER
|
||||
stepper_extruder = current_block->extruder;
|
||||
#endif
|
||||
TERN_(HAS_MULTI_EXTRUDER, stepper_extruder = current_block->extruder);
|
||||
|
||||
// Initialize the trapezoid generator from the current block.
|
||||
#if ENABLED(LIN_ADVANCE)
|
||||
@ -2151,17 +2148,14 @@ uint32_t Stepper::block_phase_isr() {
|
||||
else LA_isr_rate = LA_ADV_NEVER;
|
||||
#endif
|
||||
|
||||
if ( ENABLED(HAS_L64XX) // Always set direction for L64xx (Also enables the chips)
|
||||
if ( ENABLED(HAS_L64XX) // Always set direction for L64xx (Also enables the chips)
|
||||
|| ENABLED(DUAL_X_CARRIAGE) // TODO: Find out why this fixes "jittery" small circles
|
||||
|| current_block->direction_bits != last_direction_bits
|
||||
|| TERN(MIXING_EXTRUDER, false, stepper_extruder != last_moved_extruder)
|
||||
) {
|
||||
last_direction_bits = current_block->direction_bits;
|
||||
#if HAS_MULTI_EXTRUDER
|
||||
last_moved_extruder = stepper_extruder;
|
||||
#endif
|
||||
|
||||
TERN_(HAS_MULTI_EXTRUDER, last_moved_extruder = stepper_extruder);
|
||||
TERN_(HAS_L64XX, L64XX_OK_to_power_up = true);
|
||||
set_directions();
|
||||
set_directions(current_block->direction_bits);
|
||||
}
|
||||
|
||||
#if ENABLED(LASER_POWER_INLINE)
|
||||
@ -2583,12 +2577,9 @@ void Stepper::init() {
|
||||
#endif
|
||||
|
||||
// Init direction bits for first moves
|
||||
last_direction_bits = 0
|
||||
| (INVERT_X_DIR ? _BV(X_AXIS) : 0)
|
||||
| (INVERT_Y_DIR ? _BV(Y_AXIS) : 0)
|
||||
| (INVERT_Z_DIR ? _BV(Z_AXIS) : 0);
|
||||
|
||||
set_directions();
|
||||
set_directions((INVERT_X_DIR ? _BV(X_AXIS) : 0)
|
||||
| (INVERT_Y_DIR ? _BV(Y_AXIS) : 0)
|
||||
| (INVERT_Z_DIR ? _BV(Z_AXIS) : 0));
|
||||
|
||||
#if HAS_MOTOR_CURRENT_SPI || HAS_MOTOR_CURRENT_PWM
|
||||
initialized = true;
|
||||
|
@ -514,9 +514,15 @@ class Stepper {
|
||||
static void refresh_motor_power();
|
||||
#endif
|
||||
|
||||
// Set direction bits for all steppers
|
||||
// Update direction states for all steppers
|
||||
static void set_directions();
|
||||
|
||||
// Set direction bits and update all stepper DIR states
|
||||
static void set_directions(const uint8_t bits) {
|
||||
last_direction_bits = bits;
|
||||
set_directions();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
// Set the current position in steps
|
||||
|
@ -61,6 +61,10 @@
|
||||
#include "../gcode/gcode.h"
|
||||
#endif
|
||||
|
||||
#if ENABLED(DUAL_X_CARRIAGE)
|
||||
#include "stepper.h"
|
||||
#endif
|
||||
|
||||
#if ANY(SWITCHING_EXTRUDER, SWITCHING_NOZZLE, SWITCHING_TOOLHEAD)
|
||||
#include "servo.h"
|
||||
#endif
|
||||
@ -701,6 +705,13 @@ inline void fast_line_to_current(const AxisEnum fr_axis) { _line_to_current(fr_a
|
||||
|
||||
#if ENABLED(DUAL_X_CARRIAGE)
|
||||
|
||||
/**
|
||||
* @brief Dual X Tool Change
|
||||
* @details Change tools, with extra behavior based on current mode
|
||||
*
|
||||
* @param new_tool Tool index to activate
|
||||
* @param no_move Flag indicating no moves should take place
|
||||
*/
|
||||
inline void dualx_tool_change(const uint8_t new_tool, bool &no_move) {
|
||||
|
||||
DEBUG_ECHOPGM("Dual X Carriage Mode ");
|
||||
@ -711,17 +722,16 @@ inline void fast_line_to_current(const AxisEnum fr_axis) { _line_to_current(fr_a
|
||||
case DXC_MIRRORED_MODE: DEBUG_ECHOLNPGM("MIRRORED"); break;
|
||||
}
|
||||
|
||||
// Get the home position of the currently-active tool
|
||||
const float xhome = x_home_pos(active_extruder);
|
||||
if (dual_x_carriage_mode == DXC_AUTO_PARK_MODE
|
||||
&& IsRunning() && !no_move
|
||||
&& (delayed_move_time || current_position.x != xhome)
|
||||
|
||||
if (dual_x_carriage_mode == DXC_AUTO_PARK_MODE // If Auto-Park mode is enabled
|
||||
&& IsRunning() && !no_move // ...and movement is permitted
|
||||
&& (delayed_move_time || current_position.x != xhome) // ...and delayed_move_time is set OR not "already parked"...
|
||||
) {
|
||||
|
||||
DEBUG_ECHOLNPAIR("MoveX to ", xhome);
|
||||
|
||||
// Park old head
|
||||
current_position.x = xhome;
|
||||
line_to_current_position(planner.settings.max_feedrate_mm_s[X_AXIS]);
|
||||
line_to_current_position(planner.settings.max_feedrate_mm_s[X_AXIS]); // Park the current head
|
||||
planner.synchronize();
|
||||
}
|
||||
|
||||
@ -736,20 +746,21 @@ inline void fast_line_to_current(const AxisEnum fr_axis) { _line_to_current(fr_a
|
||||
switch (dual_x_carriage_mode) {
|
||||
case DXC_FULL_CONTROL_MODE:
|
||||
// New current position is the position of the activated extruder
|
||||
current_position.x = inactive_extruder_x_pos;
|
||||
current_position.x = inactive_extruder_x;
|
||||
// Save the inactive extruder's position (from the old current_position)
|
||||
inactive_extruder_x_pos = destination.x;
|
||||
inactive_extruder_x = destination.x;
|
||||
DEBUG_ECHOLNPAIR("DXC Full Control curr.x=", current_position.x, " dest.x=", destination.x);
|
||||
break;
|
||||
case DXC_AUTO_PARK_MODE:
|
||||
// record current raised toolhead position for use by unpark
|
||||
raised_parked_position = current_position;
|
||||
active_extruder_parked = true;
|
||||
delayed_move_time = 0;
|
||||
idex_set_parked();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Ensure X axis DIR pertains to the correct carriage
|
||||
stepper.set_directions();
|
||||
|
||||
DEBUG_ECHOLNPAIR("Active extruder parked: ", active_extruder_parked ? "yes" : "no");
|
||||
DEBUG_POS("New extruder (parked)", current_position);
|
||||
}
|
||||
@ -875,7 +886,7 @@ void tool_change(const uint8_t new_tool, bool no_move/*=false*/) {
|
||||
planner.synchronize();
|
||||
|
||||
#if ENABLED(DUAL_X_CARRIAGE) // Only T0 allowed if the Printer is in DXC_DUPLICATION_MODE or DXC_MIRRORED_MODE
|
||||
if (new_tool != 0 && dxc_is_duplicating())
|
||||
if (new_tool != 0 && idex_is_duplicating())
|
||||
return invalid_extruder_error(new_tool);
|
||||
#endif
|
||||
|
||||
@ -1151,7 +1162,7 @@ void tool_change(const uint8_t new_tool, bool no_move/*=false*/) {
|
||||
}
|
||||
#endif
|
||||
|
||||
TERN_(DUAL_X_CARRIAGE, active_extruder_parked = false);
|
||||
TERN_(DUAL_X_CARRIAGE, idex_set_parked(false));
|
||||
}
|
||||
|
||||
#if ENABLED(SWITCHING_NOZZLE)
|
||||
|
Reference in New Issue
Block a user