|
|
@ -6304,131 +6304,134 @@ inline void gcode_T(uint8_t tmp_extruder) {
|
|
|
|
SERIAL_CHAR('T');
|
|
|
|
SERIAL_CHAR('T');
|
|
|
|
SERIAL_PROTOCOL_F(tmp_extruder, DEC);
|
|
|
|
SERIAL_PROTOCOL_F(tmp_extruder, DEC);
|
|
|
|
SERIAL_ECHOLN(MSG_INVALID_EXTRUDER);
|
|
|
|
SERIAL_ECHOLN(MSG_INVALID_EXTRUDER);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
|
|
|
|
target_extruder = tmp_extruder;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if EXTRUDERS > 1
|
|
|
|
float stored_feedrate = feedrate;
|
|
|
|
bool make_move = false;
|
|
|
|
|
|
|
|
|
|
|
|
if (code_seen('F')) {
|
|
|
|
|
|
|
|
float next_feedrate = code_value();
|
|
|
|
|
|
|
|
if (next_feedrate > 0.0) stored_feedrate = feedrate = next_feedrate;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
else {
|
|
|
|
|
|
|
|
#ifdef XY_TRAVEL_SPEED
|
|
|
|
|
|
|
|
feedrate = XY_TRAVEL_SPEED;
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
feedrate = min(max_feedrate[X_AXIS], max_feedrate[Y_AXIS]);
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (code_seen('F')) {
|
|
|
|
#if EXTRUDERS > 1
|
|
|
|
|
|
|
|
if (tmp_extruder != active_extruder) {
|
|
|
|
|
|
|
|
// Save current position to return to after applying extruder offset
|
|
|
|
|
|
|
|
set_destination_to_current();
|
|
|
|
|
|
|
|
#if ENABLED(DUAL_X_CARRIAGE)
|
|
|
|
|
|
|
|
if (dual_x_carriage_mode == DXC_AUTO_PARK_MODE && IsRunning() &&
|
|
|
|
|
|
|
|
(delayed_move_time || 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();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#if EXTRUDERS > 1
|
|
|
|
// apply Y & Z extruder offset (x offset is already used in determining home pos)
|
|
|
|
make_move = true;
|
|
|
|
current_position[Y_AXIS] -= extruder_offset[Y_AXIS][active_extruder] - extruder_offset[Y_AXIS][tmp_extruder];
|
|
|
|
#endif
|
|
|
|
current_position[Z_AXIS] -= extruder_offset[Z_AXIS][active_extruder] - extruder_offset[Z_AXIS][tmp_extruder];
|
|
|
|
|
|
|
|
active_extruder = tmp_extruder;
|
|
|
|
|
|
|
|
|
|
|
|
float next_feedrate = code_value();
|
|
|
|
// This function resets the max/min values - the current position may be overwritten below.
|
|
|
|
if (next_feedrate > 0.0) feedrate = next_feedrate;
|
|
|
|
set_axis_is_at_home(X_AXIS);
|
|
|
|
}
|
|
|
|
|
|
|
|
#if EXTRUDERS > 1
|
|
|
|
|
|
|
|
if (tmp_extruder != active_extruder) {
|
|
|
|
|
|
|
|
// Save current position to return to after applying extruder offset
|
|
|
|
|
|
|
|
set_destination_to_current();
|
|
|
|
|
|
|
|
#if ENABLED(DUAL_X_CARRIAGE)
|
|
|
|
|
|
|
|
if (dual_x_carriage_mode == DXC_AUTO_PARK_MODE && IsRunning() &&
|
|
|
|
|
|
|
|
(delayed_move_time || 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)
|
|
|
|
if (dual_x_carriage_mode == DXC_FULL_CONTROL_MODE) {
|
|
|
|
current_position[Y_AXIS] -= extruder_offset[Y_AXIS][active_extruder] - extruder_offset[Y_AXIS][tmp_extruder];
|
|
|
|
current_position[X_AXIS] = inactive_extruder_x_pos;
|
|
|
|
current_position[Z_AXIS] -= extruder_offset[Z_AXIS][active_extruder] - extruder_offset[Z_AXIS][tmp_extruder];
|
|
|
|
inactive_extruder_x_pos = destination[X_AXIS];
|
|
|
|
active_extruder = tmp_extruder;
|
|
|
|
}
|
|
|
|
|
|
|
|
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_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;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// No extra case for AUTO_BED_LEVELING_FEATURE in DUAL_X_CARRIAGE. Does that mean they don't work together?
|
|
|
|
|
|
|
|
#else // !DUAL_X_CARRIAGE
|
|
|
|
|
|
|
|
#if ENABLED(AUTO_BED_LEVELING_FEATURE)
|
|
|
|
|
|
|
|
// Offset extruder, make sure to apply the bed level rotation matrix
|
|
|
|
|
|
|
|
vector_3 tmp_offset_vec = vector_3(extruder_offset[X_AXIS][tmp_extruder],
|
|
|
|
|
|
|
|
extruder_offset[Y_AXIS][tmp_extruder],
|
|
|
|
|
|
|
|
0),
|
|
|
|
|
|
|
|
act_offset_vec = vector_3(extruder_offset[X_AXIS][active_extruder],
|
|
|
|
|
|
|
|
extruder_offset[Y_AXIS][active_extruder],
|
|
|
|
|
|
|
|
0),
|
|
|
|
|
|
|
|
offset_vec = tmp_offset_vec - act_offset_vec;
|
|
|
|
|
|
|
|
|
|
|
|
// This function resets the max/min values - the current position may be overwritten below.
|
|
|
|
#if ENABLED(DEBUG_LEVELING_FEATURE)
|
|
|
|
set_axis_is_at_home(X_AXIS);
|
|
|
|
if (DEBUGGING(LEVELING)) {
|
|
|
|
|
|
|
|
SERIAL_ECHOLNPGM(">>> gcode_T");
|
|
|
|
|
|
|
|
tmp_offset_vec.debug("tmp_offset_vec");
|
|
|
|
|
|
|
|
act_offset_vec.debug("act_offset_vec");
|
|
|
|
|
|
|
|
offset_vec.debug("offset_vec (BEFORE)");
|
|
|
|
|
|
|
|
DEBUG_POS("BEFORE rotation", current_position);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
if (dual_x_carriage_mode == DXC_FULL_CONTROL_MODE) {
|
|
|
|
offset_vec.apply_rotation(plan_bed_level_matrix.transpose(plan_bed_level_matrix));
|
|
|
|
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 // !DUAL_X_CARRIAGE
|
|
|
|
|
|
|
|
#if ENABLED(AUTO_BED_LEVELING_FEATURE)
|
|
|
|
|
|
|
|
// Offset extruder, make sure to apply the bed level rotation matrix
|
|
|
|
|
|
|
|
vector_3 tmp_offset_vec = vector_3(extruder_offset[X_AXIS][tmp_extruder],
|
|
|
|
|
|
|
|
extruder_offset[Y_AXIS][tmp_extruder],
|
|
|
|
|
|
|
|
0),
|
|
|
|
|
|
|
|
act_offset_vec = vector_3(extruder_offset[X_AXIS][active_extruder],
|
|
|
|
|
|
|
|
extruder_offset[Y_AXIS][active_extruder],
|
|
|
|
|
|
|
|
0),
|
|
|
|
|
|
|
|
offset_vec = tmp_offset_vec - act_offset_vec;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if ENABLED(DEBUG_LEVELING_FEATURE)
|
|
|
|
current_position[X_AXIS] += offset_vec.x;
|
|
|
|
if (DEBUGGING(LEVELING)) {
|
|
|
|
current_position[Y_AXIS] += offset_vec.y;
|
|
|
|
SERIAL_ECHOLNPGM(">>> gcode_T");
|
|
|
|
current_position[Z_AXIS] += offset_vec.z;
|
|
|
|
tmp_offset_vec.debug("tmp_offset_vec");
|
|
|
|
|
|
|
|
act_offset_vec.debug("act_offset_vec");
|
|
|
|
|
|
|
|
offset_vec.debug("offset_vec (BEFORE)");
|
|
|
|
|
|
|
|
DEBUG_POS("BEFORE rotation", current_position);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
offset_vec.apply_rotation(plan_bed_level_matrix.transpose(plan_bed_level_matrix));
|
|
|
|
#if ENABLED(DEBUG_LEVELING_FEATURE)
|
|
|
|
|
|
|
|
if (DEBUGGING(LEVELING)) {
|
|
|
|
|
|
|
|
offset_vec.debug("offset_vec (AFTER)");
|
|
|
|
|
|
|
|
DEBUG_POS("AFTER rotation", current_position);
|
|
|
|
|
|
|
|
SERIAL_ECHOLNPGM("<<< gcode_T");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
current_position[X_AXIS] += offset_vec.x;
|
|
|
|
#else // !AUTO_BED_LEVELING_FEATURE
|
|
|
|
current_position[Y_AXIS] += offset_vec.y;
|
|
|
|
// Offset extruder (only by XY)
|
|
|
|
current_position[Z_AXIS] += offset_vec.z;
|
|
|
|
for (int i=X_AXIS; i<=Y_AXIS; i++)
|
|
|
|
|
|
|
|
current_position[i] += extruder_offset[i][tmp_extruder] - extruder_offset[i][active_extruder];
|
|
|
|
|
|
|
|
#endif // !AUTO_BED_LEVELING_FEATURE
|
|
|
|
|
|
|
|
// Set the new active extruder and position
|
|
|
|
|
|
|
|
active_extruder = tmp_extruder;
|
|
|
|
|
|
|
|
#endif // !DUAL_X_CARRIAGE
|
|
|
|
|
|
|
|
#if ENABLED(DELTA)
|
|
|
|
|
|
|
|
sync_plan_position_delta();
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
sync_plan_position();
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Move to the old position
|
|
|
|
|
|
|
|
if (IsRunning()) prepare_move();
|
|
|
|
|
|
|
|
} // (tmp_extruder != active_extruder)
|
|
|
|
|
|
|
|
|
|
|
|
#if ENABLED(DEBUG_LEVELING_FEATURE)
|
|
|
|
#if ENABLED(EXT_SOLENOID)
|
|
|
|
if (DEBUGGING(LEVELING)) {
|
|
|
|
st_synchronize();
|
|
|
|
offset_vec.debug("offset_vec (AFTER)");
|
|
|
|
disable_all_solenoids();
|
|
|
|
DEBUG_POS("AFTER rotation", current_position);
|
|
|
|
enable_solenoid_on_active_extruder();
|
|
|
|
SERIAL_ECHOLNPGM("<<< gcode_T");
|
|
|
|
#endif // EXT_SOLENOID
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#else // !AUTO_BED_LEVELING_FEATURE
|
|
|
|
#endif // EXTRUDERS > 1
|
|
|
|
// Offset extruder (only by XY)
|
|
|
|
|
|
|
|
for (int i=X_AXIS; i<=Y_AXIS; i++)
|
|
|
|
|
|
|
|
current_position[i] += extruder_offset[i][tmp_extruder] - extruder_offset[i][active_extruder];
|
|
|
|
|
|
|
|
#endif // !AUTO_BED_LEVELING_FEATURE
|
|
|
|
|
|
|
|
// Set the new active extruder and position
|
|
|
|
|
|
|
|
active_extruder = tmp_extruder;
|
|
|
|
|
|
|
|
#endif // !DUAL_X_CARRIAGE
|
|
|
|
|
|
|
|
#if ENABLED(DELTA)
|
|
|
|
|
|
|
|
sync_plan_position_delta();
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
sync_plan_position();
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Move to the old position if 'F' was in the parameters
|
|
|
|
|
|
|
|
if (make_move && IsRunning()) prepare_move();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if ENABLED(EXT_SOLENOID)
|
|
|
|
feedrate = stored_feedrate;
|
|
|
|
st_synchronize();
|
|
|
|
|
|
|
|
disable_all_solenoids();
|
|
|
|
|
|
|
|
enable_solenoid_on_active_extruder();
|
|
|
|
|
|
|
|
#endif // EXT_SOLENOID
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#endif // EXTRUDERS > 1
|
|
|
|
SERIAL_ECHO_START;
|
|
|
|
SERIAL_ECHO_START;
|
|
|
|
SERIAL_ECHO(MSG_ACTIVE_EXTRUDER);
|
|
|
|
SERIAL_ECHO(MSG_ACTIVE_EXTRUDER);
|
|
|
|
SERIAL_PROTOCOLLN((int)active_extruder);
|
|
|
|
SERIAL_PROTOCOLLN((int)active_extruder);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|