Add duplication and auto-park mode for dual x-carriage support.
This commit is contained in:
parent
62aab66299
commit
9547fb9dfb
1
.gitignore
vendored
1
.gitignore
vendored
@ -3,3 +3,4 @@ applet/
|
|||||||
*~
|
*~
|
||||||
*.orig
|
*.orig
|
||||||
*.rej
|
*.rej
|
||||||
|
*.bak
|
@ -155,8 +155,8 @@
|
|||||||
// Configuration for second X-carriage
|
// Configuration for second X-carriage
|
||||||
// Note: the first x-carriage is defined as the x-carriage which homes to the minimum endstop;
|
// Note: the first x-carriage is defined as the x-carriage which homes to the minimum endstop;
|
||||||
// the second x-carriage always homes to the maximum endstop.
|
// the second x-carriage always homes to the maximum endstop.
|
||||||
#define X2_MIN_POS 88 // set minimum to ensure second x-carriage doesn't hit the parked first X-carriage
|
#define X2_MIN_POS 80 // set minimum to ensure second x-carriage doesn't hit the parked first X-carriage
|
||||||
#define X2_MAX_POS 350.45 // set maximum to the distance between toolheads when both heads are homed
|
#define X2_MAX_POS 353 // set maximum to the distance between toolheads when both heads are homed
|
||||||
#define X2_HOME_DIR 1 // the second X-carriage always homes to the maximum endstop position
|
#define X2_HOME_DIR 1 // the second X-carriage always homes to the maximum endstop position
|
||||||
#define X2_HOME_POS X2_MAX_POS // default home position is the maximum carriage position
|
#define X2_HOME_POS X2_MAX_POS // default home position is the maximum carriage position
|
||||||
// However: In this mode the EXTRUDER_OFFSET_X value for the second extruder provides a software
|
// However: In this mode the EXTRUDER_OFFSET_X value for the second extruder provides a software
|
||||||
@ -169,6 +169,28 @@
|
|||||||
#define X2_STEP_PIN 25
|
#define X2_STEP_PIN 25
|
||||||
#define X2_DIR_PIN 23
|
#define X2_DIR_PIN 23
|
||||||
|
|
||||||
|
// There are a few selectable movement modes for dual x-carriages using M605 S<mode>
|
||||||
|
// Mode 0: Full control. The slicer has full control over both x-carriages and can achieve optimal travel results
|
||||||
|
// as long as it supports dual x-carriages. (M605 S0)
|
||||||
|
// Mode 1: Auto-park mode. The firmware will automatically park and unpark the x-carriages on tool changes so
|
||||||
|
// that additional slicer support is not required. (M605 S1)
|
||||||
|
// Mode 2: Duplication mode. The firmware will transparently make the second x-carriage and extruder copy all
|
||||||
|
// actions of the first x-carriage. This allows the printer to print 2 arbitrary items at
|
||||||
|
// once. (2nd extruder x offset and temp offset are set using: M605 S2 [Xnnn] [Rmmm])
|
||||||
|
|
||||||
|
// This is the default power-up mode which can be later using M605.
|
||||||
|
#define DEFAULT_DUAL_X_CARRIAGE_MODE 0
|
||||||
|
|
||||||
|
// As the x-carriages are independent we can now account for any relative Z offset
|
||||||
|
#define EXTRUDER1_Z_OFFSET 0.0 // z offset relative to extruder 0
|
||||||
|
|
||||||
|
// Default settings in "Auto-park Mode"
|
||||||
|
#define TOOLCHANGE_PARK_ZLIFT 0.2 // the distance to raise Z axis when parking an extruder
|
||||||
|
#define TOOLCHANGE_UNPARK_ZLIFT 1 // the distance to raise Z axis when unparking an extruder
|
||||||
|
|
||||||
|
// Default x offset in duplication mode (typically set to half print bed width)
|
||||||
|
#define DEFAULT_DUPLICATION_X_OFFSET 100
|
||||||
|
|
||||||
#endif //DUAL_X_CARRIAGE
|
#endif //DUAL_X_CARRIAGE
|
||||||
|
|
||||||
//homing hits the endstop, then retracts by this distance, before it tries to slowly bump again:
|
//homing hits the endstop, then retracts by this distance, before it tries to slowly bump again:
|
||||||
|
@ -139,6 +139,7 @@
|
|||||||
// M503 - print the current settings (from memory not from eeprom)
|
// M503 - print the current settings (from memory not from eeprom)
|
||||||
// M540 - Use S[0|1] to enable or disable the stop SD card print on endstop hit (requires ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED)
|
// M540 - Use S[0|1] to enable or disable the stop SD card print on endstop hit (requires ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED)
|
||||||
// M600 - Pause for filament change X[pos] Y[pos] Z[relative lift] E[initial retract] L[later retract distance for removal]
|
// M600 - Pause for filament change X[pos] Y[pos] Z[relative lift] E[initial retract] L[later retract distance for removal]
|
||||||
|
// M605 - Set dual x-carriage movement mode: S<mode> [ X<duplication x-offset> R<duplication temp offset> ]
|
||||||
// M907 - Set digital trimpot motor current using axis codes.
|
// M907 - Set digital trimpot motor current using axis codes.
|
||||||
// M908 - Control digital trimpot directly.
|
// M908 - Control digital trimpot directly.
|
||||||
// M350 - Set microstepping mode.
|
// M350 - Set microstepping mode.
|
||||||
@ -168,9 +169,15 @@ float current_position[NUM_AXIS] = { 0.0, 0.0, 0.0, 0.0 };
|
|||||||
float add_homeing[3]={0,0,0};
|
float add_homeing[3]={0,0,0};
|
||||||
float min_pos[3] = { X_MIN_POS, Y_MIN_POS, Z_MIN_POS };
|
float min_pos[3] = { X_MIN_POS, Y_MIN_POS, Z_MIN_POS };
|
||||||
float max_pos[3] = { X_MAX_POS, Y_MAX_POS, Z_MAX_POS };
|
float max_pos[3] = { X_MAX_POS, Y_MAX_POS, Z_MAX_POS };
|
||||||
// Extruder offset, only in XY plane
|
|
||||||
|
// Extruder offset
|
||||||
#if EXTRUDERS > 1
|
#if EXTRUDERS > 1
|
||||||
float extruder_offset[2][EXTRUDERS] = {
|
#ifndef DUAL_X_CARRIAGE
|
||||||
|
#define NUM_EXTRUDER_OFFSETS 2 // only in XY plane
|
||||||
|
#else
|
||||||
|
#define NUM_EXTRUDER_OFFSETS 3 // supports offsets in XYZ plane
|
||||||
|
#endif
|
||||||
|
float extruder_offset[NUM_EXTRUDER_OFFSETS][EXTRUDERS] = {
|
||||||
#if defined(EXTRUDER_OFFSET_X) && defined(EXTRUDER_OFFSET_Y)
|
#if defined(EXTRUDER_OFFSET_X) && defined(EXTRUDER_OFFSET_Y)
|
||||||
EXTRUDER_OFFSET_X, EXTRUDER_OFFSET_Y
|
EXTRUDER_OFFSET_X, EXTRUDER_OFFSET_Y
|
||||||
#endif
|
#endif
|
||||||
@ -693,6 +700,11 @@ XYZ_CONSTS_FROM_CONFIG(signed char, home_dir, HOME_DIR);
|
|||||||
#error "Please use canonical x-carriage assignment" // the x-carriages are defined by their homing directions
|
#error "Please use canonical x-carriage assignment" // the x-carriages are defined by their homing directions
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define DXC_FULL_CONTROL_MODE 0
|
||||||
|
#define DXC_AUTO_PARK_MODE 1
|
||||||
|
#define DXC_DUPLICATION_MODE 2
|
||||||
|
static int dual_x_carriage_mode = DEFAULT_DUAL_X_CARRIAGE_MODE;
|
||||||
|
|
||||||
static float x_home_pos(int extruder) {
|
static float x_home_pos(int extruder) {
|
||||||
if (extruder == 0)
|
if (extruder == 0)
|
||||||
return base_home_pos(X_AXIS) + add_homeing[X_AXIS];
|
return base_home_pos(X_AXIS) + add_homeing[X_AXIS];
|
||||||
@ -708,17 +720,32 @@ static int x_home_dir(int extruder) {
|
|||||||
return (extruder == 0) ? X_HOME_DIR : X2_HOME_DIR;
|
return (extruder == 0) ? X_HOME_DIR : X2_HOME_DIR;
|
||||||
}
|
}
|
||||||
|
|
||||||
static float inactive_x_carriage_pos = X2_MAX_POS;
|
static float inactive_extruder_x_pos = X2_MAX_POS; // used in mode 0 & 1
|
||||||
#endif
|
static bool active_extruder_parked = false; // used in mode 1 & 2
|
||||||
|
static float raised_parked_position[NUM_AXIS]; // used in mode 1
|
||||||
|
static unsigned long delayed_move_time = 0; // used in mode 1
|
||||||
|
static float duplicate_extruder_x_offset = DEFAULT_DUPLICATION_X_OFFSET; // used in mode 2
|
||||||
|
static float duplicate_extruder_temp_offset = 0; // used in mode 2
|
||||||
|
bool extruder_duplication_enabled = false; // used in mode 2
|
||||||
|
#endif //DUAL_X_CARRIAGE
|
||||||
|
|
||||||
static void axis_is_at_home(int axis) {
|
static void axis_is_at_home(int axis) {
|
||||||
#ifdef DUAL_X_CARRIAGE
|
#ifdef DUAL_X_CARRIAGE
|
||||||
if (axis == X_AXIS && active_extruder != 0) {
|
if (axis == X_AXIS) {
|
||||||
|
if (active_extruder != 0) {
|
||||||
current_position[X_AXIS] = x_home_pos(active_extruder);
|
current_position[X_AXIS] = x_home_pos(active_extruder);
|
||||||
min_pos[X_AXIS] = X2_MIN_POS;
|
min_pos[X_AXIS] = X2_MIN_POS;
|
||||||
max_pos[X_AXIS] = max(extruder_offset[X_AXIS][1], X2_MAX_POS);
|
max_pos[X_AXIS] = max(extruder_offset[X_AXIS][1], X2_MAX_POS);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
else if (dual_x_carriage_mode == DXC_DUPLICATION_MODE && active_extruder == 0) {
|
||||||
|
current_position[X_AXIS] = base_home_pos(X_AXIS) + add_homeing[X_AXIS];
|
||||||
|
min_pos[X_AXIS] = base_min_pos(X_AXIS) + add_homeing[X_AXIS];
|
||||||
|
max_pos[X_AXIS] = min(base_max_pos(X_AXIS) + add_homeing[X_AXIS],
|
||||||
|
max(extruder_offset[X_AXIS][1], X2_MAX_POS) - duplicate_extruder_x_offset);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
current_position[axis] = base_home_pos(axis) + add_homeing[axis];
|
current_position[axis] = base_home_pos(axis) + add_homeing[axis];
|
||||||
min_pos[axis] = base_min_pos(axis) + add_homeing[axis];
|
min_pos[axis] = base_min_pos(axis) + add_homeing[axis];
|
||||||
@ -920,6 +947,7 @@ void process_commands()
|
|||||||
int x_axis_home_dir = home_dir(X_AXIS);
|
int x_axis_home_dir = home_dir(X_AXIS);
|
||||||
#else
|
#else
|
||||||
int x_axis_home_dir = x_home_dir(active_extruder);
|
int x_axis_home_dir = x_home_dir(active_extruder);
|
||||||
|
extruder_duplication_enabled = false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
|
plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
|
||||||
@ -950,12 +978,19 @@ void process_commands()
|
|||||||
{
|
{
|
||||||
#ifdef DUAL_X_CARRIAGE
|
#ifdef DUAL_X_CARRIAGE
|
||||||
int tmp_extruder = active_extruder;
|
int tmp_extruder = active_extruder;
|
||||||
|
extruder_duplication_enabled = false;
|
||||||
active_extruder = !active_extruder;
|
active_extruder = !active_extruder;
|
||||||
HOMEAXIS(X);
|
HOMEAXIS(X);
|
||||||
inactive_x_carriage_pos = current_position[X_AXIS];
|
inactive_extruder_x_pos = current_position[X_AXIS];
|
||||||
active_extruder = tmp_extruder;
|
active_extruder = tmp_extruder;
|
||||||
#endif
|
|
||||||
HOMEAXIS(X);
|
HOMEAXIS(X);
|
||||||
|
// reset state used by the different modes
|
||||||
|
memcpy(raised_parked_position, current_position, sizeof(raised_parked_position));
|
||||||
|
delayed_move_time = 0;
|
||||||
|
active_extruder_parked = true;
|
||||||
|
#else
|
||||||
|
HOMEAXIS(X);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if((home_all_axis) || (code_seen(axis_codes[Y_AXIS]))) {
|
if((home_all_axis) || (code_seen(axis_codes[Y_AXIS]))) {
|
||||||
@ -1199,6 +1234,10 @@ void process_commands()
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (code_seen('S')) setTargetHotend(code_value(), tmp_extruder);
|
if (code_seen('S')) setTargetHotend(code_value(), tmp_extruder);
|
||||||
|
#ifdef DUAL_X_CARRIAGE
|
||||||
|
if (dual_x_carriage_mode == DXC_DUPLICATION_MODE && tmp_extruder == 0)
|
||||||
|
setTargetHotend1(code_value() == 0.0 ? 0.0 : code_value() + duplicate_extruder_temp_offset);
|
||||||
|
#endif
|
||||||
setWatch();
|
setWatch();
|
||||||
break;
|
break;
|
||||||
case 140: // M140 set bed temp
|
case 140: // M140 set bed temp
|
||||||
@ -1252,9 +1291,17 @@ void process_commands()
|
|||||||
#endif
|
#endif
|
||||||
if (code_seen('S')) {
|
if (code_seen('S')) {
|
||||||
setTargetHotend(code_value(), tmp_extruder);
|
setTargetHotend(code_value(), tmp_extruder);
|
||||||
|
#ifdef DUAL_X_CARRIAGE
|
||||||
|
if (dual_x_carriage_mode == DXC_DUPLICATION_MODE && tmp_extruder == 0)
|
||||||
|
setTargetHotend1(code_value() == 0.0 ? 0.0 : code_value() + duplicate_extruder_temp_offset);
|
||||||
|
#endif
|
||||||
CooldownNoWait = true;
|
CooldownNoWait = true;
|
||||||
} else if (code_seen('R')) {
|
} else if (code_seen('R')) {
|
||||||
setTargetHotend(code_value(), tmp_extruder);
|
setTargetHotend(code_value(), tmp_extruder);
|
||||||
|
#ifdef DUAL_X_CARRIAGE
|
||||||
|
if (dual_x_carriage_mode == DXC_DUPLICATION_MODE && tmp_extruder == 0)
|
||||||
|
setTargetHotend1(code_value() == 0.0 ? 0.0 : code_value() + duplicate_extruder_temp_offset);
|
||||||
|
#endif
|
||||||
CooldownNoWait = false;
|
CooldownNoWait = false;
|
||||||
}
|
}
|
||||||
#ifdef AUTOTEMP
|
#ifdef AUTOTEMP
|
||||||
@ -1671,6 +1718,12 @@ void process_commands()
|
|||||||
{
|
{
|
||||||
extruder_offset[Y_AXIS][tmp_extruder] = code_value();
|
extruder_offset[Y_AXIS][tmp_extruder] = code_value();
|
||||||
}
|
}
|
||||||
|
#ifdef DUAL_X_CARRIAGE
|
||||||
|
if(code_seen('Z'))
|
||||||
|
{
|
||||||
|
extruder_offset[Z_AXIS][tmp_extruder] = code_value();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
SERIAL_ECHO_START;
|
SERIAL_ECHO_START;
|
||||||
SERIAL_ECHOPGM(MSG_HOTEND_OFFSET);
|
SERIAL_ECHOPGM(MSG_HOTEND_OFFSET);
|
||||||
for(tmp_extruder = 0; tmp_extruder < EXTRUDERS; tmp_extruder++)
|
for(tmp_extruder = 0; tmp_extruder < EXTRUDERS; tmp_extruder++)
|
||||||
@ -1679,6 +1732,10 @@ void process_commands()
|
|||||||
SERIAL_ECHO(extruder_offset[X_AXIS][tmp_extruder]);
|
SERIAL_ECHO(extruder_offset[X_AXIS][tmp_extruder]);
|
||||||
SERIAL_ECHO(",");
|
SERIAL_ECHO(",");
|
||||||
SERIAL_ECHO(extruder_offset[Y_AXIS][tmp_extruder]);
|
SERIAL_ECHO(extruder_offset[Y_AXIS][tmp_extruder]);
|
||||||
|
#ifdef DUAL_X_CARRIAGE
|
||||||
|
SERIAL_ECHO(",");
|
||||||
|
SERIAL_ECHO(extruder_offset[Z_AXIS][tmp_extruder]);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
SERIAL_ECHOLN("");
|
SERIAL_ECHOLN("");
|
||||||
}break;
|
}break;
|
||||||
@ -2013,6 +2070,53 @@ void process_commands()
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
#endif //FILAMENTCHANGEENABLE
|
#endif //FILAMENTCHANGEENABLE
|
||||||
|
#ifdef DUAL_X_CARRIAGE
|
||||||
|
case 605: // Set dual x-carriage movement mode:
|
||||||
|
// M605 S0: Full control mode. The slicer has full control over x-carriage movement
|
||||||
|
// M605 S1: Auto-park mode. The inactive head will auto park/unpark without slicer involvement
|
||||||
|
// M605 S2 [Xnnn] [Rmmm]: Duplication mode. The second extruder will duplicate the first with nnn
|
||||||
|
// millimeters x-offset and an optional differential hotend temperature of
|
||||||
|
// mmm degrees. E.g., with "M605 S2 X100 R2" the second extruder will duplicate
|
||||||
|
// the first with a spacing of 100mm in the x direction and 2 degrees hotter.
|
||||||
|
//
|
||||||
|
// Note: the X axis should be homed after changing dual x-carriage mode.
|
||||||
|
{
|
||||||
|
st_synchronize();
|
||||||
|
|
||||||
|
if (code_seen('S'))
|
||||||
|
dual_x_carriage_mode = code_value();
|
||||||
|
|
||||||
|
if (dual_x_carriage_mode == DXC_DUPLICATION_MODE)
|
||||||
|
{
|
||||||
|
if (code_seen('X'))
|
||||||
|
duplicate_extruder_x_offset = max(code_value(),X2_MIN_POS - x_home_pos(0));
|
||||||
|
|
||||||
|
if (code_seen('R'))
|
||||||
|
duplicate_extruder_temp_offset = code_value();
|
||||||
|
|
||||||
|
SERIAL_ECHO_START;
|
||||||
|
SERIAL_ECHOPGM(MSG_HOTEND_OFFSET);
|
||||||
|
SERIAL_ECHO(" ");
|
||||||
|
SERIAL_ECHO(extruder_offset[X_AXIS][0]);
|
||||||
|
SERIAL_ECHO(",");
|
||||||
|
SERIAL_ECHO(extruder_offset[Y_AXIS][0]);
|
||||||
|
SERIAL_ECHO(" ");
|
||||||
|
SERIAL_ECHO(duplicate_extruder_x_offset);
|
||||||
|
SERIAL_ECHO(",");
|
||||||
|
SERIAL_ECHOLN(extruder_offset[Y_AXIS][1]);
|
||||||
|
}
|
||||||
|
else if (dual_x_carriage_mode != DXC_FULL_CONTROL_MODE && dual_x_carriage_mode != DXC_AUTO_PARK_MODE)
|
||||||
|
{
|
||||||
|
dual_x_carriage_mode = DEFAULT_DUAL_X_CARRIAGE_MODE;
|
||||||
|
}
|
||||||
|
|
||||||
|
active_extruder_parked = false;
|
||||||
|
extruder_duplication_enabled = false;
|
||||||
|
delayed_move_time = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#endif //DUAL_X_CARRIAGE
|
||||||
|
|
||||||
case 907: // M907 Set digital trimpot motor current using axis codes.
|
case 907: // M907 Set digital trimpot motor current using axis codes.
|
||||||
{
|
{
|
||||||
#if defined(DIGIPOTSS_PIN) && DIGIPOTSS_PIN > -1
|
#if defined(DIGIPOTSS_PIN) && DIGIPOTSS_PIN > -1
|
||||||
@ -2092,18 +2196,55 @@ void process_commands()
|
|||||||
// Save current position to return to after applying extruder offset
|
// Save current position to return to after applying extruder offset
|
||||||
memcpy(destination, current_position, sizeof(destination));
|
memcpy(destination, current_position, sizeof(destination));
|
||||||
#ifdef DUAL_X_CARRIAGE
|
#ifdef DUAL_X_CARRIAGE
|
||||||
// only apply Y extruder offset in dual x carriage mode (x offset is already used in determining home pos)
|
if (dual_x_carriage_mode == DXC_AUTO_PARK_MODE && Stopped == false &&
|
||||||
|
(delayed_move_time != 0 || current_position[X_AXIS] != x_home_pos(active_extruder)))
|
||||||
|
{
|
||||||
|
// Park old head: 1) raise 2) move to park position 3) lower
|
||||||
|
plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS] + TOOLCHANGE_PARK_ZLIFT,
|
||||||
|
current_position[E_AXIS], max_feedrate[Z_AXIS], active_extruder);
|
||||||
|
plan_buffer_line(x_home_pos(active_extruder), current_position[Y_AXIS], current_position[Z_AXIS] + TOOLCHANGE_PARK_ZLIFT,
|
||||||
|
current_position[E_AXIS], max_feedrate[X_AXIS], active_extruder);
|
||||||
|
plan_buffer_line(x_home_pos(active_extruder), current_position[Y_AXIS], current_position[Z_AXIS],
|
||||||
|
current_position[E_AXIS], max_feedrate[Z_AXIS], active_extruder);
|
||||||
|
st_synchronize();
|
||||||
|
}
|
||||||
|
|
||||||
|
// apply Y & Z extruder offset (x offset is already used in determining home pos)
|
||||||
current_position[Y_AXIS] = current_position[Y_AXIS] -
|
current_position[Y_AXIS] = current_position[Y_AXIS] -
|
||||||
extruder_offset[Y_AXIS][active_extruder] +
|
extruder_offset[Y_AXIS][active_extruder] +
|
||||||
extruder_offset[Y_AXIS][tmp_extruder];
|
extruder_offset[Y_AXIS][tmp_extruder];
|
||||||
|
current_position[Z_AXIS] = current_position[Z_AXIS] -
|
||||||
|
extruder_offset[Z_AXIS][active_extruder] +
|
||||||
|
extruder_offset[Z_AXIS][tmp_extruder];
|
||||||
|
|
||||||
float tmp_x_pos = current_position[X_AXIS];
|
|
||||||
|
|
||||||
// Set the new active extruder and position
|
|
||||||
active_extruder = tmp_extruder;
|
active_extruder = tmp_extruder;
|
||||||
axis_is_at_home(X_AXIS); //this function updates X min/max values.
|
|
||||||
current_position[X_AXIS] = inactive_x_carriage_pos;
|
// This function resets the max/min values - the current position may be overwritten below.
|
||||||
inactive_x_carriage_pos = tmp_x_pos;
|
axis_is_at_home(X_AXIS);
|
||||||
|
|
||||||
|
if (dual_x_carriage_mode == DXC_FULL_CONTROL_MODE)
|
||||||
|
{
|
||||||
|
current_position[X_AXIS] = inactive_extruder_x_pos;
|
||||||
|
inactive_extruder_x_pos = destination[X_AXIS];
|
||||||
|
}
|
||||||
|
else if (dual_x_carriage_mode == DXC_DUPLICATION_MODE)
|
||||||
|
{
|
||||||
|
active_extruder_parked = (active_extruder == 0); // this triggers the second extruder to move into the duplication position
|
||||||
|
if (active_extruder == 0 || active_extruder_parked)
|
||||||
|
current_position[X_AXIS] = inactive_extruder_x_pos;
|
||||||
|
else
|
||||||
|
current_position[X_AXIS] = destination[X_AXIS] + duplicate_extruder_x_offset;
|
||||||
|
inactive_extruder_x_pos = destination[X_AXIS];
|
||||||
|
extruder_duplication_enabled = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// record raised toolhead position for use by unpark
|
||||||
|
memcpy(raised_parked_position, current_position, sizeof(raised_parked_position));
|
||||||
|
raised_parked_position[Z_AXIS] += TOOLCHANGE_UNPARK_ZLIFT;
|
||||||
|
active_extruder_parked = true;
|
||||||
|
delayed_move_time = 0;
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
// Offset extruder (only by XY)
|
// Offset extruder (only by XY)
|
||||||
int i;
|
int i;
|
||||||
@ -2309,6 +2450,48 @@ void prepare_move()
|
|||||||
active_extruder);
|
active_extruder);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
#ifdef DUAL_X_CARRIAGE
|
||||||
|
if (active_extruder_parked)
|
||||||
|
{
|
||||||
|
if (dual_x_carriage_mode == DXC_DUPLICATION_MODE && active_extruder == 0)
|
||||||
|
{
|
||||||
|
// move duplicate extruder into correct duplication position.
|
||||||
|
plan_set_position(inactive_extruder_x_pos, current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
|
||||||
|
plan_buffer_line(current_position[X_AXIS] + duplicate_extruder_x_offset, current_position[Y_AXIS], current_position[Z_AXIS],
|
||||||
|
current_position[E_AXIS], max_feedrate[X_AXIS], 1);
|
||||||
|
plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
|
||||||
|
st_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 - skit it but keep track of current position (so that it can later
|
||||||
|
// be used as start of first non-travel move)
|
||||||
|
if (delayed_move_time != 0xFFFFFFFFUL)
|
||||||
|
{
|
||||||
|
memcpy(current_position, destination, sizeof(current_position));
|
||||||
|
if (destination[Z_AXIS] > raised_parked_position[Z_AXIS])
|
||||||
|
raised_parked_position[Z_AXIS] = destination[Z_AXIS];
|
||||||
|
delayed_move_time = millis();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delayed_move_time = 0;
|
||||||
|
// unpark extruder: 1) raise, 2) move into starting XY position, 3) lower
|
||||||
|
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);
|
||||||
|
plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], raised_parked_position[Z_AXIS],
|
||||||
|
current_position[E_AXIS], min(max_feedrate[X_AXIS],max_feedrate[Y_AXIS]), active_extruder);
|
||||||
|
plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS],
|
||||||
|
current_position[E_AXIS], max_feedrate[Z_AXIS], active_extruder);
|
||||||
|
active_extruder_parked = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif //DUAL_X_CARRIAGE
|
||||||
|
|
||||||
// Do not use feedmultiply for E or Z only moves
|
// Do not use feedmultiply for E or Z only moves
|
||||||
if( (current_position[X_AXIS] == destination [X_AXIS]) && (current_position[Y_AXIS] == destination [Y_AXIS])) {
|
if( (current_position[X_AXIS] == destination [X_AXIS]) && (current_position[Y_AXIS] == destination [Y_AXIS])) {
|
||||||
plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder);
|
plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder);
|
||||||
@ -2316,7 +2499,7 @@ void prepare_move()
|
|||||||
else {
|
else {
|
||||||
plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate*feedmultiply/60/100.0, active_extruder);
|
plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate*feedmultiply/60/100.0, active_extruder);
|
||||||
}
|
}
|
||||||
#endif
|
#endif //else DELTA
|
||||||
for(int8_t i=0; i < NUM_AXIS; i++) {
|
for(int8_t i=0; i < NUM_AXIS; i++) {
|
||||||
current_position[i] = destination[i];
|
current_position[i] = destination[i];
|
||||||
}
|
}
|
||||||
@ -2428,6 +2611,16 @@ void manage_inactivity()
|
|||||||
WRITE(E0_ENABLE_PIN,oldstatus);
|
WRITE(E0_ENABLE_PIN,oldstatus);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(DUAL_X_CARRIAGE)
|
||||||
|
// handle delayed move timeout
|
||||||
|
if (delayed_move_time != 0 && (millis() - delayed_move_time) > 1000 && Stopped == false)
|
||||||
|
{
|
||||||
|
// travel moves have been received so enact them
|
||||||
|
delayed_move_time = 0xFFFFFFFFUL; // force moves to be done
|
||||||
|
memcpy(destination,current_position,sizeof(destination));
|
||||||
|
prepare_move();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
check_axes_activity();
|
check_axes_activity();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -349,20 +349,36 @@ ISR(TIMER1_COMPA_vect)
|
|||||||
// Set the direction bits (X_AXIS=A_AXIS and Y_AXIS=B_AXIS for COREXY)
|
// Set the direction bits (X_AXIS=A_AXIS and Y_AXIS=B_AXIS for COREXY)
|
||||||
if((out_bits & (1<<X_AXIS))!=0){
|
if((out_bits & (1<<X_AXIS))!=0){
|
||||||
#ifdef DUAL_X_CARRIAGE
|
#ifdef DUAL_X_CARRIAGE
|
||||||
if (active_extruder != 0)
|
if (extruder_duplication_enabled){
|
||||||
|
WRITE(X_DIR_PIN, INVERT_X_DIR);
|
||||||
|
WRITE(X2_DIR_PIN, INVERT_X_DIR);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
if (current_block->active_extruder != 0)
|
||||||
WRITE(X2_DIR_PIN, INVERT_X_DIR);
|
WRITE(X2_DIR_PIN, INVERT_X_DIR);
|
||||||
else
|
else
|
||||||
#endif
|
|
||||||
WRITE(X_DIR_PIN, INVERT_X_DIR);
|
WRITE(X_DIR_PIN, INVERT_X_DIR);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
WRITE(X_DIR_PIN, INVERT_X_DIR);
|
||||||
|
#endif
|
||||||
count_direction[X_AXIS]=-1;
|
count_direction[X_AXIS]=-1;
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
#ifdef DUAL_X_CARRIAGE
|
#ifdef DUAL_X_CARRIAGE
|
||||||
if (active_extruder != 0)
|
if (extruder_duplication_enabled){
|
||||||
|
WRITE(X_DIR_PIN, !INVERT_X_DIR);
|
||||||
|
WRITE(X2_DIR_PIN, !INVERT_X_DIR);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
if (current_block->active_extruder != 0)
|
||||||
WRITE(X2_DIR_PIN, !INVERT_X_DIR);
|
WRITE(X2_DIR_PIN, !INVERT_X_DIR);
|
||||||
else
|
else
|
||||||
#endif
|
|
||||||
WRITE(X_DIR_PIN, !INVERT_X_DIR);
|
WRITE(X_DIR_PIN, !INVERT_X_DIR);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
WRITE(X_DIR_PIN, !INVERT_X_DIR);
|
||||||
|
#endif
|
||||||
count_direction[X_AXIS]=1;
|
count_direction[X_AXIS]=1;
|
||||||
}
|
}
|
||||||
if((out_bits & (1<<Y_AXIS))!=0){
|
if((out_bits & (1<<Y_AXIS))!=0){
|
||||||
@ -384,7 +400,8 @@ ISR(TIMER1_COMPA_vect)
|
|||||||
{
|
{
|
||||||
#ifdef DUAL_X_CARRIAGE
|
#ifdef DUAL_X_CARRIAGE
|
||||||
// with 2 x-carriages, endstops are only checked in the homing direction for the active extruder
|
// with 2 x-carriages, endstops are only checked in the homing direction for the active extruder
|
||||||
if ((active_extruder == 0 && X_HOME_DIR == -1) || (active_extruder != 0 && X2_HOME_DIR == -1))
|
if ((current_block->active_extruder == 0 && X_HOME_DIR == -1)
|
||||||
|
|| (current_block->active_extruder != 0 && X2_HOME_DIR == -1))
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
#if defined(X_MIN_PIN) && X_MIN_PIN > -1
|
#if defined(X_MIN_PIN) && X_MIN_PIN > -1
|
||||||
@ -404,7 +421,8 @@ ISR(TIMER1_COMPA_vect)
|
|||||||
{
|
{
|
||||||
#ifdef DUAL_X_CARRIAGE
|
#ifdef DUAL_X_CARRIAGE
|
||||||
// with 2 x-carriages, endstops are only checked in the homing direction for the active extruder
|
// with 2 x-carriages, endstops are only checked in the homing direction for the active extruder
|
||||||
if ((active_extruder == 0 && X_HOME_DIR == 1) || (active_extruder != 0 && X2_HOME_DIR == 1))
|
if ((current_block->active_extruder == 0 && X_HOME_DIR == 1)
|
||||||
|
|| (current_block->active_extruder != 0 && X2_HOME_DIR == 1))
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
#if defined(X_MAX_PIN) && X_MAX_PIN > -1
|
#if defined(X_MAX_PIN) && X_MAX_PIN > -1
|
||||||
@ -530,20 +548,36 @@ ISR(TIMER1_COMPA_vect)
|
|||||||
counter_x += current_block->steps_x;
|
counter_x += current_block->steps_x;
|
||||||
if (counter_x > 0) {
|
if (counter_x > 0) {
|
||||||
#ifdef DUAL_X_CARRIAGE
|
#ifdef DUAL_X_CARRIAGE
|
||||||
if (active_extruder != 0)
|
if (extruder_duplication_enabled){
|
||||||
|
WRITE(X_STEP_PIN, !INVERT_X_STEP_PIN);
|
||||||
|
WRITE(X2_STEP_PIN, !INVERT_X_STEP_PIN);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (current_block->active_extruder != 0)
|
||||||
WRITE(X2_STEP_PIN, !INVERT_X_STEP_PIN);
|
WRITE(X2_STEP_PIN, !INVERT_X_STEP_PIN);
|
||||||
else
|
else
|
||||||
#endif
|
|
||||||
WRITE(X_STEP_PIN, !INVERT_X_STEP_PIN);
|
WRITE(X_STEP_PIN, !INVERT_X_STEP_PIN);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
WRITE(X_STEP_PIN, !INVERT_X_STEP_PIN);
|
||||||
|
#endif
|
||||||
counter_x -= current_block->step_event_count;
|
counter_x -= current_block->step_event_count;
|
||||||
count_position[X_AXIS]+=count_direction[X_AXIS];
|
count_position[X_AXIS]+=count_direction[X_AXIS];
|
||||||
#ifdef DUAL_X_CARRIAGE
|
#ifdef DUAL_X_CARRIAGE
|
||||||
if (active_extruder != 0)
|
if (extruder_duplication_enabled){
|
||||||
|
WRITE(X_STEP_PIN, INVERT_X_STEP_PIN);
|
||||||
|
WRITE(X2_STEP_PIN, INVERT_X_STEP_PIN);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (current_block->active_extruder != 0)
|
||||||
WRITE(X2_STEP_PIN, INVERT_X_STEP_PIN);
|
WRITE(X2_STEP_PIN, INVERT_X_STEP_PIN);
|
||||||
else
|
else
|
||||||
#endif
|
|
||||||
WRITE(X_STEP_PIN, INVERT_X_STEP_PIN);
|
WRITE(X_STEP_PIN, INVERT_X_STEP_PIN);
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
WRITE(X_STEP_PIN, INVERT_X_STEP_PIN);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
counter_y += current_block->steps_y;
|
counter_y += current_block->steps_y;
|
||||||
if (counter_y > 0) {
|
if (counter_y > 0) {
|
||||||
|
@ -28,9 +28,16 @@
|
|||||||
#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); }}}
|
#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); }}}
|
||||||
#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); }}}
|
#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); }}}
|
||||||
#elif EXTRUDERS > 1
|
#elif EXTRUDERS > 1
|
||||||
|
#ifndef DUAL_X_CARRIAGE
|
||||||
#define WRITE_E_STEP(v) { if(current_block->active_extruder == 1) { WRITE(E1_STEP_PIN, v); } else { WRITE(E0_STEP_PIN, v); }}
|
#define WRITE_E_STEP(v) { if(current_block->active_extruder == 1) { WRITE(E1_STEP_PIN, v); } else { WRITE(E0_STEP_PIN, v); }}
|
||||||
#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); }}
|
#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); }}
|
||||||
#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); }}
|
#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); }}
|
||||||
|
#else
|
||||||
|
extern bool extruder_duplication_enabled;
|
||||||
|
#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); }}
|
||||||
|
#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); }}
|
||||||
|
#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); }}
|
||||||
|
#endif
|
||||||
#else
|
#else
|
||||||
#define WRITE_E_STEP(v) WRITE(E0_STEP_PIN, v)
|
#define WRITE_E_STEP(v) WRITE(E0_STEP_PIN, v)
|
||||||
#define NORM_E_DIR() WRITE(E0_DIR_PIN, !INVERT_E0_DIR)
|
#define NORM_E_DIR() WRITE(E0_DIR_PIN, !INVERT_E0_DIR)
|
||||||
|
Loading…
Reference in New Issue
Block a user