🏗️ Support for up to 6 linear axes (#19112)

Co-authored-by: Scott Lahteine <github@thinkyhead.com>
This commit is contained in:
DerAndere
2021-06-05 09:18:47 +02:00
committed by Scott Lahteine
parent d3c56a76e7
commit c1fca91103
98 changed files with 5040 additions and 2256 deletions

View File

@ -89,7 +89,7 @@ bool relative_mode; // = false;
#define Z_INIT_POS Z_HOME_POS
#endif
xyze_pos_t current_position = LOGICAL_AXIS_ARRAY(0, X_HOME_POS, Y_HOME_POS, Z_INIT_POS);
xyze_pos_t current_position = LOGICAL_AXIS_ARRAY(0, X_HOME_POS, Y_HOME_POS, Z_INIT_POS, I_HOME_POS, J_HOME_POS, K_HOME_POS);
/**
* Cartesian Destination
@ -143,7 +143,7 @@ xyz_pos_t cartes;
#if IS_KINEMATIC
abc_pos_t delta;
abce_pos_t delta;
#if HAS_SCARA_OFFSET
abc_pos_t scara_home_offset;
@ -196,7 +196,14 @@ inline void report_more_positions() {
inline void report_logical_position(const xyze_pos_t &rpos) {
const xyze_pos_t lpos = rpos.asLogical();
SERIAL_ECHOPAIR_P(
LIST_N(DOUBLE(LINEAR_AXES), X_LBL, lpos.x, SP_Y_LBL, lpos.y, SP_Z_LBL, lpos.z)
LIST_N(DOUBLE(LINEAR_AXES),
X_LBL, lpos.x,
SP_Y_LBL, lpos.y,
SP_Z_LBL, lpos.z,
SP_I_LBL, lpos.i,
SP_J_LBL, lpos.j,
SP_K_LBL, lpos.k
)
#if HAS_EXTRUDERS
, SP_E_LBL, lpos.e
#endif
@ -209,7 +216,10 @@ void report_real_position() {
get_cartesian_from_steppers();
xyze_pos_t npos = LOGICAL_AXIS_ARRAY(
planner.get_axis_position_mm(E_AXIS),
cartes.x, cartes.y, cartes.z
cartes.x, cartes.y, cartes.z,
planner.get_axis_position_mm(I_AXIS),
planner.get_axis_position_mm(J_AXIS),
planner.get_axis_position_mm(K_AXIS)
);
TERN_(HAS_POSITION_MODIFIERS, planner.unapply_modifiers(npos, true));
@ -334,20 +344,21 @@ void sync_plan_position() {
void get_cartesian_from_steppers() {
#if ENABLED(DELTA)
forward_kinematics(planner.get_axis_positions_mm());
#else
#if IS_SCARA
forward_kinematics(
planner.get_axis_position_degrees(A_AXIS)
, planner.get_axis_position_degrees(B_AXIS)
#if ENABLED(AXEL_TPARA)
, planner.get_axis_position_degrees(C_AXIS)
#endif
);
#else
cartes.x = planner.get_axis_position_mm(X_AXIS);
cartes.y = planner.get_axis_position_mm(Y_AXIS);
#endif
#elif IS_SCARA
forward_kinematics(
planner.get_axis_position_degrees(A_AXIS), planner.get_axis_position_degrees(B_AXIS)
OPTARG(AXEL_TPARA, planner.get_axis_position_degrees(C_AXIS))
);
cartes.z = planner.get_axis_position_mm(Z_AXIS);
#else
LINEAR_AXIS_CODE(
cartes.x = planner.get_axis_position_mm(X_AXIS),
cartes.y = planner.get_axis_position_mm(Y_AXIS),
cartes.z = planner.get_axis_position_mm(Z_AXIS),
cartes.i = planner.get_axis_position_mm(I_AXIS),
cartes.j = planner.get_axis_position_mm(J_AXIS),
cartes.k = planner.get_axis_position_mm(K_AXIS)
);
#endif
}
@ -366,13 +377,9 @@ void set_current_from_steppers_for_axis(const AxisEnum axis) {
get_cartesian_from_steppers();
xyze_pos_t pos = cartes;
#if HAS_EXTRUDERS
pos.e = planner.get_axis_position_mm(E_AXIS);
#endif
TERN_(HAS_EXTRUDERS, pos.e = planner.get_axis_position_mm(E_AXIS));
#if HAS_POSITION_MODIFIERS
planner.unapply_modifiers(pos, true);
#endif
TERN_(HAS_POSITION_MODIFIERS, planner.unapply_modifiers(pos, true));
if (axis == ALL_AXES_ENUM)
current_position = pos;
@ -385,7 +392,7 @@ void set_current_from_steppers_for_axis(const AxisEnum axis) {
* (or from wherever it has been told it is located).
*/
void line_to_current_position(const_feedRate_t fr_mm_s/*=feedrate_mm_s*/) {
planner.buffer_line(current_position, fr_mm_s, active_extruder);
planner.buffer_line(current_position, fr_mm_s);
}
#if HAS_EXTRUDERS
@ -411,7 +418,7 @@ void line_to_current_position(const_feedRate_t fr_mm_s/*=feedrate_mm_s*/) {
#else
if (current_position == destination) return;
planner.buffer_line(destination, scaled_fr_mm_s, active_extruder);
planner.buffer_line(destination, scaled_fr_mm_s);
#endif
current_position = destination;
@ -449,25 +456,26 @@ void _internal_move_to_destination(const_feedRate_t fr_mm_s/*=0.0f*/
}
/**
* Plan a move to (X, Y, Z) with separation of the XY and Z components.
* Plan a move to (X, Y, Z, [I, [J, [K]]]) and set the current_position
* Plan a move to (X, Y, Z) with separation of Z from other components.
*
* - If Z is moving up, the Z move is done before XY.
* - If Z is moving down, the Z move is done after XY.
* - If Z is moving up, the Z move is done before XY, etc.
* - If Z is moving down, the Z move is done after XY, etc.
* - Delta may lower Z first to get into the free motion zone.
* - Before returning, wait for the planner buffer to empty.
*/
void do_blocking_move_to(
LINEAR_AXIS_LIST(const float rx, const float ry, const float rz),
const_feedRate_t fr_mm_s/*=0.0f*/
) {
void do_blocking_move_to(LINEAR_AXIS_ARGS(const float), const_feedRate_t fr_mm_s/*=0.0f*/) {
DEBUG_SECTION(log_move, "do_blocking_move_to", DEBUGGING(LEVELING));
if (DEBUGGING(LEVELING)) DEBUG_XYZ("> ", LINEAR_AXIS_LIST(rx, ry, rz));
if (DEBUGGING(LEVELING)) DEBUG_XYZ("> ", LINEAR_AXIS_ARGS());
const feedRate_t z_feedrate = fr_mm_s ?: homing_feedrate(Z_AXIS),
xy_feedrate = fr_mm_s ?: feedRate_t(XY_PROBE_FEEDRATE_MM_S);
const feedRate_t xy_feedrate = fr_mm_s ?: feedRate_t(XY_PROBE_FEEDRATE_MM_S);
#if HAS_Z_AXIS
const feedRate_t z_feedrate = fr_mm_s ?: homing_feedrate(Z_AXIS);
#endif
#if EITHER(DELTA, IS_SCARA)
if (!position_is_reachable(rx, ry)) return;
if (!position_is_reachable(x, y)) return;
destination = current_position; // sync destination at the start
#endif
@ -479,8 +487,8 @@ void do_blocking_move_to(
// when in the danger zone
if (current_position.z > delta_clip_start_height) {
if (rz > delta_clip_start_height) { // staying in the danger zone
destination.set(rx, ry, rz); // move directly (uninterpolated)
if (z > delta_clip_start_height) { // staying in the danger zone
destination.set(x, y, z); // move directly (uninterpolated)
prepare_internal_fast_move_to_destination(); // set current_position from destination
if (DEBUGGING(LEVELING)) DEBUG_POS("danger zone move", current_position);
return;
@ -490,18 +498,18 @@ void do_blocking_move_to(
if (DEBUGGING(LEVELING)) DEBUG_POS("zone border move", current_position);
}
if (rz > current_position.z) { // raising?
destination.z = rz;
if (z > current_position.z) { // raising?
destination.z = z;
prepare_internal_fast_move_to_destination(z_feedrate); // set current_position from destination
if (DEBUGGING(LEVELING)) DEBUG_POS("z raise move", current_position);
}
destination.set(rx, ry);
destination.set(x, y);
prepare_internal_move_to_destination(); // set current_position from destination
if (DEBUGGING(LEVELING)) DEBUG_POS("xy move", current_position);
if (rz < current_position.z) { // lowering?
destination.z = rz;
if (z < current_position.z) { // lowering?
destination.z = z;
prepare_internal_fast_move_to_destination(z_feedrate); // set current_position from destination
if (DEBUGGING(LEVELING)) DEBUG_POS("z lower move", current_position);
}
@ -509,36 +517,40 @@ void do_blocking_move_to(
#elif IS_SCARA
// If Z needs to raise, do it before moving XY
if (destination.z < rz) {
destination.z = rz;
if (destination.z < z) {
destination.z = z;
prepare_internal_fast_move_to_destination(z_feedrate);
}
destination.set(rx, ry);
destination.set(x, y);
prepare_internal_fast_move_to_destination(xy_feedrate);
// If Z needs to lower, do it after moving XY
if (destination.z > rz) {
destination.z = rz;
if (destination.z > z) {
destination.z = z;
prepare_internal_fast_move_to_destination(z_feedrate);
}
#else
// If Z needs to raise, do it before moving XY
if (current_position.z < rz) {
current_position.z = rz;
line_to_current_position(z_feedrate);
}
#if HAS_Z_AXIS
// If Z needs to raise, do it before moving XY
if (current_position.z < z) {
current_position.z = z;
line_to_current_position(z_feedrate);
}
#endif
current_position.set(rx, ry);
current_position.set(x, y);
line_to_current_position(xy_feedrate);
// If Z needs to lower, do it after moving XY
if (current_position.z > rz) {
current_position.z = rz;
line_to_current_position(z_feedrate);
}
#if HAS_Z_AXIS
// If Z needs to lower, do it after moving XY
if (current_position.z > z) {
current_position.z = z;
line_to_current_position(z_feedrate);
}
#endif
#endif
@ -546,53 +558,94 @@ void do_blocking_move_to(
}
void do_blocking_move_to(const xy_pos_t &raw, const_feedRate_t fr_mm_s/*=0.0f*/) {
do_blocking_move_to(LINEAR_AXIS_LIST(raw.x, raw.y, current_position.z, current_position.i), fr_mm_s);
do_blocking_move_to(LINEAR_AXIS_LIST(raw.x, raw.y, current_position.z, current_position.i, current_position.j, current_position.k), fr_mm_s);
}
void do_blocking_move_to(const xyz_pos_t &raw, const_feedRate_t fr_mm_s/*=0.0f*/) {
do_blocking_move_to(LINEAR_AXIS_LIST(raw.x, raw.y, raw.z), fr_mm_s);
do_blocking_move_to(LINEAR_AXIS_ELEM(raw), fr_mm_s);
}
void do_blocking_move_to(const xyze_pos_t &raw, const_feedRate_t fr_mm_s/*=0.0f*/) {
do_blocking_move_to(LINEAR_AXIS_LIST(raw.x, raw.y, raw.z), fr_mm_s);
do_blocking_move_to(LINEAR_AXIS_ELEM(raw), fr_mm_s);
}
void do_blocking_move_to_x(const_float_t rx, const_feedRate_t fr_mm_s/*=0.0*/) {
do_blocking_move_to(
LINEAR_AXIS_LIST(rx, current_position.y, current_position.z),
fr_mm_s
);
}
void do_blocking_move_to_y(const_float_t ry, const_feedRate_t fr_mm_s/*=0.0*/) {
do_blocking_move_to(
LINEAR_AXIS_LIST(current_position.x, ry, current_position.z),
fr_mm_s
);
}
void do_blocking_move_to_z(const_float_t rz, const_feedRate_t fr_mm_s/*=0.0*/) {
do_blocking_move_to_xy_z(current_position, rz, fr_mm_s);
}
void do_blocking_move_to_xy(const_float_t rx, const_float_t ry, const_feedRate_t fr_mm_s/*=0.0*/) {
do_blocking_move_to(
LINEAR_AXIS_LIST(rx, ry, current_position.z),
fr_mm_s
);
}
void do_blocking_move_to_xy(const xy_pos_t &raw, const_feedRate_t fr_mm_s/*=0.0f*/) {
do_blocking_move_to_xy(raw.x, raw.y, fr_mm_s);
}
void do_blocking_move_to_xy_z(const xy_pos_t &raw, const_float_t z, const_feedRate_t fr_mm_s/*=0.0f*/) {
do_blocking_move_to(
LINEAR_AXIS_LIST(raw.x, raw.y, z),
LINEAR_AXIS_LIST(rx, current_position.y, current_position.z, current_position.i, current_position.j, current_position.k),
fr_mm_s
);
}
void do_z_clearance(const_float_t zclear, const bool lower_allowed/*=false*/) {
float zdest = zclear;
if (!lower_allowed) NOLESS(zdest, current_position.z);
do_blocking_move_to_z(_MIN(zdest, Z_MAX_POS), TERN(HAS_BED_PROBE, z_probe_fast_mm_s, homing_feedrate(Z_AXIS)));
}
#if HAS_Y_AXIS
void do_blocking_move_to_y(const_float_t ry, const_feedRate_t fr_mm_s/*=0.0*/) {
do_blocking_move_to(
LINEAR_AXIS_LIST(current_position.x, ry, current_position.z, current_position.i, current_position.j, current_position.k),
fr_mm_s
);
}
#endif
#if HAS_Z_AXIS
void do_blocking_move_to_z(const_float_t rz, const_feedRate_t fr_mm_s/*=0.0*/) {
do_blocking_move_to_xy_z(current_position, rz, fr_mm_s);
}
#endif
#if LINEAR_AXES == 4
void do_blocking_move_to_i(const_float_t ri, const_feedRate_t fr_mm_s/*=0.0*/) {
do_blocking_move_to_xyz_i(current_position, ri, fr_mm_s);
}
void do_blocking_move_to_xyz_i(const xyze_pos_t &raw, const_float_t i, const_feedRate_t fr_mm_s/*=0.0f*/) {
do_blocking_move_to(raw.x, raw.y, raw.z, i, fr_mm_s);
}
#endif
#if LINEAR_AXES >= 5
void do_blocking_move_to_i(const_float_t ri, const_feedRate_t fr_mm_s/*=0.0*/) {
do_blocking_move_to_xyz_i(current_position, ri, fr_mm_s);
}
void do_blocking_move_to_xyz_i(const xyze_pos_t &raw, const_float_t i, const_feedRate_t fr_mm_s/*=0.0f*/) {
do_blocking_move_to(raw.x, raw.y, raw.z, i, raw.j, fr_mm_s);
}
void do_blocking_move_to_j(const_float_t rj, const_feedRate_t fr_mm_s/*=0.0*/) {
do_blocking_move_to_xyzi_j(current_position, rj, fr_mm_s);
}
void do_blocking_move_to_xyzi_j(const xyze_pos_t &raw, const_float_t j, const_feedRate_t fr_mm_s/*=0.0f*/) {
do_blocking_move_to(raw.x, raw.y, raw.z, raw.i, j, fr_mm_s);
}
#endif
#if LINEAR_AXES >= 6
void do_blocking_move_to_k(const_float_t rk, const_feedRate_t fr_mm_s/*=0.0*/) {
do_blocking_move_to_xyzij_k(current_position, rk, fr_mm_s);
}
void do_blocking_move_to_xyzij_k(const xyze_pos_t &raw, const_float_t k, const_feedRate_t fr_mm_s/*=0.0f*/) {
do_blocking_move_to(raw.x, raw.y, raw.z, raw.i, raw.j, k, fr_mm_s);
}
#endif
#if HAS_Y_AXIS
void do_blocking_move_to_xy(const_float_t rx, const_float_t ry, const_feedRate_t fr_mm_s/*=0.0*/) {
do_blocking_move_to(
LINEAR_AXIS_LIST(rx, ry, current_position.z, current_position.i, current_position.j, current_position.k),
fr_mm_s
);
}
void do_blocking_move_to_xy(const xy_pos_t &raw, const_feedRate_t fr_mm_s/*=0.0f*/) {
do_blocking_move_to_xy(raw.x, raw.y, fr_mm_s);
}
#endif
#if HAS_Z_AXIS
void do_blocking_move_to_xy_z(const xy_pos_t &raw, const_float_t z, const_feedRate_t fr_mm_s/*=0.0f*/) {
do_blocking_move_to(
LINEAR_AXIS_LIST(raw.x, raw.y, z, current_position.i, current_position.j, current_position.k),
fr_mm_s
);
}
void do_z_clearance(const_float_t zclear, const bool lower_allowed/*=false*/) {
float zdest = zclear;
if (!lower_allowed) NOLESS(zdest, current_position.z);
do_blocking_move_to_z(_MIN(zdest, Z_MAX_POS), TERN(HAS_BED_PROBE, z_probe_fast_mm_s, homing_feedrate(Z_AXIS)));
}
#endif
//
// Prepare to do endstop or probe moves with custom feedrates.
@ -618,8 +671,8 @@ void restore_feedrate_and_scaling() {
// Software Endstops are based on the configured limits.
soft_endstops_t soft_endstop = {
true, false,
LINEAR_AXIS_ARRAY(X_MIN_POS, Y_MIN_POS, Z_MIN_POS),
LINEAR_AXIS_ARRAY(X_MAX_BED, Y_MAX_BED, Z_MAX_POS)
LINEAR_AXIS_ARRAY(X_MIN_POS, Y_MIN_POS, Z_MIN_POS, I_MIN_POS, J_MIN_POS, K_MIN_POS),
LINEAR_AXIS_ARRAY(X_MAX_BED, Y_MAX_BED, Z_MAX_POS, I_MAX_POS, J_MAX_POS, K_MAX_POS)
};
/**
@ -746,25 +799,59 @@ void restore_feedrate_and_scaling() {
#endif
}
if (axis_was_homed(Y_AXIS)) {
#if !HAS_SOFTWARE_ENDSTOPS || ENABLED(MIN_SOFTWARE_ENDSTOP_Y)
NOLESS(target.y, soft_endstop.min.y);
#endif
#if !HAS_SOFTWARE_ENDSTOPS || ENABLED(MAX_SOFTWARE_ENDSTOP_Y)
NOMORE(target.y, soft_endstop.max.y);
#endif
}
#if HAS_Y_AXIS
if (axis_was_homed(Y_AXIS)) {
#if !HAS_SOFTWARE_ENDSTOPS || ENABLED(MIN_SOFTWARE_ENDSTOP_Y)
NOLESS(target.y, soft_endstop.min.y);
#endif
#if !HAS_SOFTWARE_ENDSTOPS || ENABLED(MAX_SOFTWARE_ENDSTOP_Y)
NOMORE(target.y, soft_endstop.max.y);
#endif
}
#endif
#endif
if (axis_was_homed(Z_AXIS)) {
#if !HAS_SOFTWARE_ENDSTOPS || ENABLED(MIN_SOFTWARE_ENDSTOP_Z)
NOLESS(target.z, soft_endstop.min.z);
#endif
#if !HAS_SOFTWARE_ENDSTOPS || ENABLED(MAX_SOFTWARE_ENDSTOP_Z)
NOMORE(target.z, soft_endstop.max.z);
#endif
}
#if HAS_Z_AXIS
if (axis_was_homed(Z_AXIS)) {
#if !HAS_SOFTWARE_ENDSTOPS || ENABLED(MIN_SOFTWARE_ENDSTOP_Z)
NOLESS(target.z, soft_endstop.min.z);
#endif
#if !HAS_SOFTWARE_ENDSTOPS || ENABLED(MAX_SOFTWARE_ENDSTOP_Z)
NOMORE(target.z, soft_endstop.max.z);
#endif
}
#endif
#if LINEAR_AXES >= 4 // TODO (DerAndere): Find out why this was missing / removed
if (axis_was_homed(I_AXIS)) {
#if !HAS_SOFTWARE_ENDSTOPS || ENABLED(MIN_SOFTWARE_ENDSTOP_I)
NOLESS(target.i, soft_endstop.min.i);
#endif
#if !HAS_SOFTWARE_ENDSTOPS || ENABLED(MAX_SOFTWARE_ENDSTOP_I)
NOMORE(target.i, soft_endstop.max.i);
#endif
}
#endif
#if LINEAR_AXES >= 5
if (axis_was_homed(J_AXIS)) {
#if !HAS_SOFTWARE_ENDSTOPS || ENABLED(MIN_SOFTWARE_ENDSTOP_J)
NOLESS(target.j, soft_endstop.min.j);
#endif
#if !HAS_SOFTWARE_ENDSTOPS || ENABLED(MAX_SOFTWARE_ENDSTOP_J)
NOMORE(target.j, soft_endstop.max.j);
#endif
}
#endif
#if LINEAR_AXES >= 6
if (axis_was_homed(K_AXIS)) {
#if !HAS_SOFTWARE_ENDSTOPS || ENABLED(MIN_SOFTWARE_ENDSTOP_K)
NOLESS(target.k, soft_endstop.min.k);
#endif
#if !HAS_SOFTWARE_ENDSTOPS || ENABLED(MAX_SOFTWARE_ENDSTOP_K)
NOMORE(target.k, soft_endstop.max.k);
#endif
}
#endif
}
#else // !HAS_SOFTWARE_ENDSTOPS
@ -824,7 +911,7 @@ FORCE_INLINE void segment_idle(millis_t &next_idle_ms) {
// If the move is only in Z/E don't split up the move
if (!diff.x && !diff.y) {
planner.buffer_line(destination, scaled_fr_mm_s, active_extruder);
planner.buffer_line(destination, scaled_fr_mm_s);
return false; // caller will update current_position
}
@ -880,15 +967,11 @@ FORCE_INLINE void segment_idle(millis_t &next_idle_ms) {
while (--segments) {
segment_idle(next_idle_ms);
raw += segment_distance;
if (!planner.buffer_line(raw, scaled_fr_mm_s, active_extruder, cartesian_segment_mm
OPTARG(SCARA_FEEDRATE_SCALING, inv_duration)
)) break;
if (!planner.buffer_line(raw, scaled_fr_mm_s, active_extruder, cartesian_segment_mm OPTARG(SCARA_FEEDRATE_SCALING, inv_duration))) break;
}
// Ensure last segment arrives at target location.
planner.buffer_line(destination, scaled_fr_mm_s, active_extruder, cartesian_segment_mm
OPTARG(SCARA_FEEDRATE_SCALING, inv_duration)
);
planner.buffer_line(destination, scaled_fr_mm_s, active_extruder, cartesian_segment_mm OPTARG(SCARA_FEEDRATE_SCALING, inv_duration));
return false; // caller will update current_position
}
@ -910,7 +993,7 @@ FORCE_INLINE void segment_idle(millis_t &next_idle_ms) {
// If the move is only in Z/E don't split up the move
if (!diff.x && !diff.y) {
planner.buffer_line(destination, fr_mm_s, active_extruder);
planner.buffer_line(destination, fr_mm_s);
return;
}
@ -947,18 +1030,12 @@ FORCE_INLINE void segment_idle(millis_t &next_idle_ms) {
while (--segments) {
segment_idle(next_idle_ms);
raw += segment_distance;
if (!planner.buffer_line(raw, fr_mm_s, active_extruder, cartesian_segment_mm
OPTARG(SCARA_FEEDRATE_SCALING, inv_duration)
)) break;
if (!planner.buffer_line(raw, fr_mm_s, active_extruder, cartesian_segment_mm OPTARG(SCARA_FEEDRATE_SCALING, inv_duration))) break;
}
// Since segment_distance is only approximate,
// the final move must be to the exact destination.
planner.buffer_line(destination, fr_mm_s, active_extruder, cartesian_segment_mm
#if ENABLED(SCARA_FEEDRATE_SCALING)
, inv_duration
#endif
);
planner.buffer_line(destination, fr_mm_s, active_extruder, cartesian_segment_mm OPTARG(SCARA_FEEDRATE_SCALING, inv_duration));
}
#endif // SEGMENT_LEVELED_MOVES
@ -998,7 +1075,7 @@ FORCE_INLINE void segment_idle(millis_t &next_idle_ms) {
}
#endif // HAS_MESH
planner.buffer_line(destination, scaled_fr_mm_s, active_extruder);
planner.buffer_line(destination, scaled_fr_mm_s);
return false; // caller will update current_position
}
@ -1080,12 +1157,12 @@ FORCE_INLINE void segment_idle(millis_t &next_idle_ms) {
// 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)) {
xyze_pos_t raised = raised_parked_position; raised.e = current_position.e;
if (planner.buffer_line(raised, fr_zfast)) {
// 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)) {
xyze_pos_t curpos = current_position; curpos.z = raised_parked_position.z;
if (planner.buffer_line(curpos, PLANNER_XY_FEEDRATE())) {
// 3. Lower Z back down
line_to_current_position(fr_zfast);
}
@ -1099,21 +1176,24 @@ FORCE_INLINE void segment_idle(millis_t &next_idle_ms) {
case DXC_MIRRORED_MODE:
case DXC_DUPLICATION_MODE:
if (active_extruder == 0) {
xyze_pos_t new_pos = current_position;
// Restore planner to parked head (T1) X position
xyze_pos_t pos_now = current_position;
pos_now.x = inactive_extruder_x;
planner.set_position_mm(pos_now);
// Keep the same X or add the duplication X offset
xyze_pos_t new_pos = pos_now;
if (dual_x_carriage_mode == DXC_DUPLICATION_MODE)
new_pos.x += duplicate_extruder_x_offset;
else
new_pos.x = inactive_extruder_x;
// Move duplicate extruder into correct duplication position.
// Move duplicate extruder into the correct 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();
set_duplication_enabled(true);
idex_set_parked(false);
sync_plan_position(); // Extra sync for good measure
set_duplication_enabled(true); // Enable Duplication
idex_set_parked(false); // No longer parked
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("set_duplication_enabled(true)\nidex_set_parked(false)");
}
else if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("Active extruder not 0");
@ -1207,22 +1287,24 @@ void prepare_line_to_destination() {
};
// Clear test bits that are trusted
LINEAR_AXIS_CODE(
set_should(axis_bits, X_AXIS),
set_should(axis_bits, Y_AXIS),
set_should(axis_bits, Z_AXIS)
set_should(axis_bits, X_AXIS), set_should(axis_bits, Y_AXIS), set_should(axis_bits, Z_AXIS),
set_should(axis_bits, I_AXIS), set_should(axis_bits, J_AXIS), set_should(axis_bits, K_AXIS)
);
return axis_bits;
}
bool homing_needed_error(linear_axis_bits_t axis_bits/*=linear_bits*/) {
if ((axis_bits = axes_should_home(axis_bits))) {
PGM_P home_first = GET_TEXT(MSG_HOME_FIRST);
PGM_P home_first = GET_TEXT(MSG_HOME_FIRST); // TODO: (DerAndere) Set this up for extra axes
char msg[strlen_P(home_first)+1];
sprintf_P(msg, home_first,
LINEAR_AXIS_LIST(
TEST(axis_bits, X_AXIS) ? "X" : "",
TEST(axis_bits, Y_AXIS) ? "Y" : "",
TEST(axis_bits, Z_AXIS) ? "Z" : ""
TEST(axis_bits, Z_AXIS) ? "Z" : "",
TEST(axis_bits, I_AXIS) ? AXIS4_STR : "",
TEST(axis_bits, J_AXIS) ? AXIS5_STR : "",
TEST(axis_bits, K_AXIS) ? AXIS6_STR : ""
)
);
SERIAL_ECHO_START();
@ -1374,6 +1456,9 @@ void prepare_line_to_destination() {
case X_AXIS: if (ENABLED(X_SPI_SENSORLESS)) endstops.tmc_spi_homing.x = false; break;
case Y_AXIS: if (ENABLED(Y_SPI_SENSORLESS)) endstops.tmc_spi_homing.y = false; break;
case Z_AXIS: if (ENABLED(Z_SPI_SENSORLESS)) endstops.tmc_spi_homing.z = false; break;
case I_AXIS: if (ENABLED(I_SPI_SENSORLESS)) endstops.tmc_spi_homing.i = false; break;
case J_AXIS: if (ENABLED(J_SPI_SENSORLESS)) endstops.tmc_spi_homing.j = false; break;
case K_AXIS: if (ENABLED(K_SPI_SENSORLESS)) endstops.tmc_spi_homing.k = false; break;
default: break;
}
#endif
@ -1446,12 +1531,7 @@ void prepare_line_to_destination() {
// Set delta/cartesian axes directly
target[axis] = distance; // The move will be towards the endstop
planner.buffer_segment(target
#if HAS_DIST_MM_ARG
, cart_dist_mm
#endif
, home_fr_mm_s, active_extruder
);
planner.buffer_segment(target OPTARG(HAS_DIST_MM_ARG, cart_dist_mm), home_fr_mm_s, active_extruder);
#endif
planner.synchronize();
@ -1531,6 +1611,30 @@ void prepare_line_to_destination() {
stepperBackoutDir = INVERT_Z_DIR ? effectorBackoutDir : -effectorBackoutDir;
break;
#endif
#ifdef I_MICROSTEPS
case I_AXIS:
phasePerUStep = PHASE_PER_MICROSTEP(I);
phaseCurrent = stepperI.get_microstep_counter();
effectorBackoutDir = -I_HOME_DIR;
stepperBackoutDir = INVERT_I_DIR ? effectorBackoutDir : -effectorBackoutDir;
break;
#endif
#ifdef J_MICROSTEPS
case J_AXIS:
phasePerUStep = PHASE_PER_MICROSTEP(J);
phaseCurrent = stepperJ.get_microstep_counter();
effectorBackoutDir = -J_HOME_DIR;
stepperBackoutDir = INVERT_J_DIR ? effectorBackoutDir : -effectorBackoutDir;
break;
#endif
#ifdef K_MICROSTEPS
case K_AXIS:
phasePerUStep = PHASE_PER_MICROSTEP(K);
phaseCurrent = stepperK.get_microstep_counter();
effectorBackoutDir = -K_HOME_DIR;
stepperBackoutDir = INVERT_K_DIR ? effectorBackoutDir : -effectorBackoutDir;
break;
#endif
default: return;
}
@ -1583,11 +1687,18 @@ void prepare_line_to_destination() {
#else
#define _CAN_HOME(A) (axis == _AXIS(A) && ( \
ENABLED(A##_SPI_SENSORLESS) \
|| (_AXIS(A) == Z_AXIS && ENABLED(HOMING_Z_WITH_PROBE)) \
|| TERN0(HAS_Z_AXIS, TERN0(HOMING_Z_WITH_PROBE, _AXIS(A) == Z_AXIS)) \
|| TERN0(A##_HOME_TO_MIN, A##_MIN_PIN > -1) \
|| TERN0(A##_HOME_TO_MAX, A##_MAX_PIN > -1) \
))
if (!_CAN_HOME(X) && !_CAN_HOME(Y) && !_CAN_HOME(Z)) return;
if (LINEAR_AXIS_GANG(
!_CAN_HOME(X),
&& !_CAN_HOME(Y),
&& !_CAN_HOME(Z),
&& !_CAN_HOME(I),
&& !_CAN_HOME(J),
&& !_CAN_HOME(K))
) return;
#endif
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPAIR(">>> homeaxis(", AS_CHAR(AXIS_CHAR(axis)), ")");
@ -1636,9 +1747,9 @@ void prepare_line_to_destination() {
// Determine if a homing bump will be done and the bumps distance
// When homing Z with probe respect probe clearance
const bool use_probe_bump = TERN0(HOMING_Z_WITH_PROBE, axis == Z_AXIS && home_bump_mm(Z_AXIS));
const bool use_probe_bump = TERN0(HOMING_Z_WITH_PROBE, axis == Z_AXIS && home_bump_mm(axis));
const float bump = axis_home_dir * (
use_probe_bump ? _MAX(TERN0(HOMING_Z_WITH_PROBE, Z_CLEARANCE_BETWEEN_PROBES), home_bump_mm(Z_AXIS)) : home_bump_mm(axis)
use_probe_bump ? _MAX(TERN0(HOMING_Z_WITH_PROBE, Z_CLEARANCE_BETWEEN_PROBES), home_bump_mm(axis)) : home_bump_mm(axis)
);
//