|
|
@ -73,7 +73,7 @@ bool relative_mode = false; |
|
|
|
|
|
|
|
/**
|
|
|
|
* Cartesian Current Position |
|
|
|
* Used to track the logical position as moves are queued. |
|
|
|
* Used to track the native machine position as moves are queued. |
|
|
|
* Used by 'line_to_current_position' to do a move after changing it. |
|
|
|
* Used by 'SYNC_PLAN_POSITION_KINEMATIC' to update 'planner.position'. |
|
|
|
*/ |
|
|
@ -197,20 +197,16 @@ void get_cartesian_from_steppers() { |
|
|
|
stepper.get_axis_position_mm(B_AXIS), |
|
|
|
stepper.get_axis_position_mm(C_AXIS) |
|
|
|
); |
|
|
|
cartes[X_AXIS] += LOGICAL_X_POSITION(0); |
|
|
|
cartes[Y_AXIS] += LOGICAL_Y_POSITION(0); |
|
|
|
cartes[Z_AXIS] += LOGICAL_Z_POSITION(0); |
|
|
|
#elif IS_SCARA |
|
|
|
#else |
|
|
|
#if IS_SCARA |
|
|
|
forward_kinematics_SCARA( |
|
|
|
stepper.get_axis_position_degrees(A_AXIS), |
|
|
|
stepper.get_axis_position_degrees(B_AXIS) |
|
|
|
); |
|
|
|
cartes[X_AXIS] += LOGICAL_X_POSITION(0); |
|
|
|
cartes[Y_AXIS] += LOGICAL_Y_POSITION(0); |
|
|
|
cartes[Z_AXIS] = stepper.get_axis_position_mm(Z_AXIS); |
|
|
|
#else |
|
|
|
cartes[X_AXIS] = stepper.get_axis_position_mm(X_AXIS); |
|
|
|
cartes[Y_AXIS] = stepper.get_axis_position_mm(Y_AXIS); |
|
|
|
#endif |
|
|
|
cartes[Z_AXIS] = stepper.get_axis_position_mm(Z_AXIS); |
|
|
|
#endif |
|
|
|
} |
|
|
@ -288,16 +284,16 @@ void line_to_destination(const float fr_mm_s) { |
|
|
|
* Plan a move to (X, Y, Z) and set the current_position |
|
|
|
* The final current_position may not be the one that was requested |
|
|
|
*/ |
|
|
|
void do_blocking_move_to(const float &lx, const float &ly, const float &lz, const float &fr_mm_s/*=0.0*/) { |
|
|
|
void do_blocking_move_to(const float &rx, const float &ry, const float &rz, const float &fr_mm_s/*=0.0*/) { |
|
|
|
const float old_feedrate_mm_s = feedrate_mm_s; |
|
|
|
|
|
|
|
#if ENABLED(DEBUG_LEVELING_FEATURE) |
|
|
|
if (DEBUGGING(LEVELING)) print_xyz(PSTR(">>> do_blocking_move_to"), NULL, lx, ly, lz); |
|
|
|
if (DEBUGGING(LEVELING)) print_xyz(PSTR(">>> do_blocking_move_to"), NULL, rx, ry, rz); |
|
|
|
#endif |
|
|
|
|
|
|
|
#if ENABLED(DELTA) |
|
|
|
|
|
|
|
if (!position_is_reachable_xy(lx, ly)) return; |
|
|
|
if (!position_is_reachable(rx, ry)) return; |
|
|
|
|
|
|
|
feedrate_mm_s = fr_mm_s ? fr_mm_s : XY_PROBE_FEEDRATE_MM_S; |
|
|
|
|
|
|
@ -309,10 +305,10 @@ void do_blocking_move_to(const float &lx, const float &ly, const float &lz, cons |
|
|
|
|
|
|
|
// when in the danger zone
|
|
|
|
if (current_position[Z_AXIS] > delta_clip_start_height) { |
|
|
|
if (lz > delta_clip_start_height) { // staying in the danger zone
|
|
|
|
destination[X_AXIS] = lx; // move directly (uninterpolated)
|
|
|
|
destination[Y_AXIS] = ly; |
|
|
|
destination[Z_AXIS] = lz; |
|
|
|
if (rz > delta_clip_start_height) { // staying in the danger zone
|
|
|
|
destination[X_AXIS] = rx; // move directly (uninterpolated)
|
|
|
|
destination[Y_AXIS] = ry; |
|
|
|
destination[Z_AXIS] = rz; |
|
|
|
prepare_uninterpolated_move_to_destination(); // set_current_from_destination()
|
|
|
|
#if ENABLED(DEBUG_LEVELING_FEATURE) |
|
|
|
if (DEBUGGING(LEVELING)) DEBUG_POS("danger zone move", current_position); |
|
|
@ -328,23 +324,23 @@ void do_blocking_move_to(const float &lx, const float &ly, const float &lz, cons |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (lz > current_position[Z_AXIS]) { // raising?
|
|
|
|
destination[Z_AXIS] = lz; |
|
|
|
if (rz > current_position[Z_AXIS]) { // raising?
|
|
|
|
destination[Z_AXIS] = rz; |
|
|
|
prepare_uninterpolated_move_to_destination(); // set_current_from_destination()
|
|
|
|
#if ENABLED(DEBUG_LEVELING_FEATURE) |
|
|
|
if (DEBUGGING(LEVELING)) DEBUG_POS("z raise move", current_position); |
|
|
|
#endif |
|
|
|
} |
|
|
|
|
|
|
|
destination[X_AXIS] = lx; |
|
|
|
destination[Y_AXIS] = ly; |
|
|
|
destination[X_AXIS] = rx; |
|
|
|
destination[Y_AXIS] = ry; |
|
|
|
prepare_move_to_destination(); // set_current_from_destination()
|
|
|
|
#if ENABLED(DEBUG_LEVELING_FEATURE) |
|
|
|
if (DEBUGGING(LEVELING)) DEBUG_POS("xy move", current_position); |
|
|
|
#endif |
|
|
|
|
|
|
|
if (lz < current_position[Z_AXIS]) { // lowering?
|
|
|
|
destination[Z_AXIS] = lz; |
|
|
|
if (rz < current_position[Z_AXIS]) { // lowering?
|
|
|
|
destination[Z_AXIS] = rz; |
|
|
|
prepare_uninterpolated_move_to_destination(); // set_current_from_destination()
|
|
|
|
#if ENABLED(DEBUG_LEVELING_FEATURE) |
|
|
|
if (DEBUGGING(LEVELING)) DEBUG_POS("z lower move", current_position); |
|
|
@ -353,44 +349,44 @@ void do_blocking_move_to(const float &lx, const float &ly, const float &lz, cons |
|
|
|
|
|
|
|
#elif IS_SCARA |
|
|
|
|
|
|
|
if (!position_is_reachable_xy(lx, ly)) return; |
|
|
|
if (!position_is_reachable(rx, ry)) return; |
|
|
|
|
|
|
|
set_destination_from_current(); |
|
|
|
|
|
|
|
// If Z needs to raise, do it before moving XY
|
|
|
|
if (destination[Z_AXIS] < lz) { |
|
|
|
destination[Z_AXIS] = lz; |
|
|
|
if (destination[Z_AXIS] < rz) { |
|
|
|
destination[Z_AXIS] = rz; |
|
|
|
prepare_uninterpolated_move_to_destination(fr_mm_s ? fr_mm_s : homing_feedrate(Z_AXIS)); |
|
|
|
} |
|
|
|
|
|
|
|
destination[X_AXIS] = lx; |
|
|
|
destination[Y_AXIS] = ly; |
|
|
|
destination[X_AXIS] = rx; |
|
|
|
destination[Y_AXIS] = ry; |
|
|
|
prepare_uninterpolated_move_to_destination(fr_mm_s ? fr_mm_s : XY_PROBE_FEEDRATE_MM_S); |
|
|
|
|
|
|
|
// If Z needs to lower, do it after moving XY
|
|
|
|
if (destination[Z_AXIS] > lz) { |
|
|
|
destination[Z_AXIS] = lz; |
|
|
|
if (destination[Z_AXIS] > rz) { |
|
|
|
destination[Z_AXIS] = rz; |
|
|
|
prepare_uninterpolated_move_to_destination(fr_mm_s ? fr_mm_s : homing_feedrate(Z_AXIS)); |
|
|
|
} |
|
|
|
|
|
|
|
#else |
|
|
|
|
|
|
|
// If Z needs to raise, do it before moving XY
|
|
|
|
if (current_position[Z_AXIS] < lz) { |
|
|
|
if (current_position[Z_AXIS] < rz) { |
|
|
|
feedrate_mm_s = fr_mm_s ? fr_mm_s : homing_feedrate(Z_AXIS); |
|
|
|
current_position[Z_AXIS] = lz; |
|
|
|
current_position[Z_AXIS] = rz; |
|
|
|
line_to_current_position(); |
|
|
|
} |
|
|
|
|
|
|
|
feedrate_mm_s = fr_mm_s ? fr_mm_s : XY_PROBE_FEEDRATE_MM_S; |
|
|
|
current_position[X_AXIS] = lx; |
|
|
|
current_position[Y_AXIS] = ly; |
|
|
|
current_position[X_AXIS] = rx; |
|
|
|
current_position[Y_AXIS] = ry; |
|
|
|
line_to_current_position(); |
|
|
|
|
|
|
|
// If Z needs to lower, do it after moving XY
|
|
|
|
if (current_position[Z_AXIS] > lz) { |
|
|
|
if (current_position[Z_AXIS] > rz) { |
|
|
|
feedrate_mm_s = fr_mm_s ? fr_mm_s : homing_feedrate(Z_AXIS); |
|
|
|
current_position[Z_AXIS] = lz; |
|
|
|
current_position[Z_AXIS] = rz; |
|
|
|
line_to_current_position(); |
|
|
|
} |
|
|
|
|
|
|
@ -404,14 +400,14 @@ void do_blocking_move_to(const float &lx, const float &ly, const float &lz, cons |
|
|
|
if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("<<< do_blocking_move_to"); |
|
|
|
#endif |
|
|
|
} |
|
|
|
void do_blocking_move_to_x(const float &lx, const float &fr_mm_s/*=0.0*/) { |
|
|
|
do_blocking_move_to(lx, current_position[Y_AXIS], current_position[Z_AXIS], fr_mm_s); |
|
|
|
void do_blocking_move_to_x(const float &rx, const float &fr_mm_s/*=0.0*/) { |
|
|
|
do_blocking_move_to(rx, current_position[Y_AXIS], current_position[Z_AXIS], fr_mm_s); |
|
|
|
} |
|
|
|
void do_blocking_move_to_z(const float &lz, const float &fr_mm_s/*=0.0*/) { |
|
|
|
do_blocking_move_to(current_position[X_AXIS], current_position[Y_AXIS], lz, fr_mm_s); |
|
|
|
void do_blocking_move_to_z(const float &rz, const float &fr_mm_s/*=0.0*/) { |
|
|
|
do_blocking_move_to(current_position[X_AXIS], current_position[Y_AXIS], rz, fr_mm_s); |
|
|
|
} |
|
|
|
void do_blocking_move_to_xy(const float &lx, const float &ly, const float &fr_mm_s/*=0.0*/) { |
|
|
|
do_blocking_move_to(lx, ly, current_position[Z_AXIS], fr_mm_s); |
|
|
|
void do_blocking_move_to_xy(const float &rx, const float &ry, const float &fr_mm_s/*=0.0*/) { |
|
|
|
do_blocking_move_to(rx, ry, current_position[Z_AXIS], fr_mm_s); |
|
|
|
} |
|
|
|
|
|
|
|
//
|
|
|
@ -521,26 +517,26 @@ float soft_endstop_min[XYZ] = { X_MIN_BED, Y_MIN_BED, Z_MIN_POS }, |
|
|
|
* This calls planner.buffer_line several times, adding |
|
|
|
* small incremental moves for DELTA or SCARA. |
|
|
|
*/ |
|
|
|
inline bool prepare_kinematic_move_to(float ltarget[XYZE]) { |
|
|
|
inline bool prepare_kinematic_move_to(float rtarget[XYZE]) { |
|
|
|
|
|
|
|
// Get the top feedrate of the move in the XY plane
|
|
|
|
const float _feedrate_mm_s = MMS_SCALED(feedrate_mm_s); |
|
|
|
|
|
|
|
// If the move is only in Z/E don't split up the move
|
|
|
|
if (ltarget[X_AXIS] == current_position[X_AXIS] && ltarget[Y_AXIS] == current_position[Y_AXIS]) { |
|
|
|
planner.buffer_line_kinematic(ltarget, _feedrate_mm_s, active_extruder); |
|
|
|
if (rtarget[X_AXIS] == current_position[X_AXIS] && rtarget[Y_AXIS] == current_position[Y_AXIS]) { |
|
|
|
planner.buffer_line_kinematic(rtarget, _feedrate_mm_s, active_extruder); |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
// Fail if attempting move outside printable radius
|
|
|
|
if (!position_is_reachable_xy(ltarget[X_AXIS], ltarget[Y_AXIS])) return true; |
|
|
|
if (!position_is_reachable(rtarget[X_AXIS], rtarget[Y_AXIS])) return true; |
|
|
|
|
|
|
|
// Get the cartesian distances moved in XYZE
|
|
|
|
const float difference[XYZE] = { |
|
|
|
ltarget[X_AXIS] - current_position[X_AXIS], |
|
|
|
ltarget[Y_AXIS] - current_position[Y_AXIS], |
|
|
|
ltarget[Z_AXIS] - current_position[Z_AXIS], |
|
|
|
ltarget[E_AXIS] - current_position[E_AXIS] |
|
|
|
rtarget[X_AXIS] - current_position[X_AXIS], |
|
|
|
rtarget[Y_AXIS] - current_position[Y_AXIS], |
|
|
|
rtarget[Z_AXIS] - current_position[Z_AXIS], |
|
|
|
rtarget[E_AXIS] - current_position[E_AXIS] |
|
|
|
}; |
|
|
|
|
|
|
|
// Get the linear distance in XYZ
|
|
|
@ -588,9 +584,9 @@ float soft_endstop_min[XYZ] = { X_MIN_BED, Y_MIN_BED, Z_MIN_POS }, |
|
|
|
oldB = stepper.get_axis_position_degrees(B_AXIS); |
|
|
|
#endif |
|
|
|
|
|
|
|
// Get the logical current position as starting point
|
|
|
|
float logical[XYZE]; |
|
|
|
COPY(logical, current_position); |
|
|
|
// Get the current position as starting point
|
|
|
|
float raw[XYZE]; |
|
|
|
COPY(raw, current_position); |
|
|
|
|
|
|
|
// Drop one segment so the last move is to the exact target.
|
|
|
|
// If there's only 1 segment, loops will be skipped entirely.
|
|
|
@ -598,25 +594,25 @@ float soft_endstop_min[XYZ] = { X_MIN_BED, Y_MIN_BED, Z_MIN_POS }, |
|
|
|
|
|
|
|
// Calculate and execute the segments
|
|
|
|
for (uint16_t s = segments + 1; --s;) { |
|
|
|
LOOP_XYZE(i) logical[i] += segment_distance[i]; |
|
|
|
LOOP_XYZE(i) raw[i] += segment_distance[i]; |
|
|
|
#if ENABLED(DELTA) |
|
|
|
DELTA_LOGICAL_IK(); // Delta can inline its kinematics
|
|
|
|
DELTA_RAW_IK(); // Delta can inline its kinematics
|
|
|
|
#else |
|
|
|
inverse_kinematics(logical); |
|
|
|
inverse_kinematics(raw); |
|
|
|
#endif |
|
|
|
|
|
|
|
ADJUST_DELTA(logical); // Adjust Z if bed leveling is enabled
|
|
|
|
ADJUST_DELTA(raw); // Adjust Z if bed leveling is enabled
|
|
|
|
|
|
|
|
#if IS_SCARA && ENABLED(SCARA_FEEDRATE_SCALING) |
|
|
|
// For SCARA scale the feed rate from mm/s to degrees/s
|
|
|
|
// Use ratio between the length of the move and the larger angle change
|
|
|
|
const float adiff = abs(delta[A_AXIS] - oldA), |
|
|
|
bdiff = abs(delta[B_AXIS] - oldB); |
|
|
|
planner.buffer_line(delta[A_AXIS], delta[B_AXIS], delta[C_AXIS], logical[E_AXIS], max(adiff, bdiff) * feed_factor, active_extruder); |
|
|
|
planner.buffer_line(delta[A_AXIS], delta[B_AXIS], delta[C_AXIS], raw[E_AXIS], max(adiff, bdiff) * feed_factor, active_extruder); |
|
|
|
oldA = delta[A_AXIS]; |
|
|
|
oldB = delta[B_AXIS]; |
|
|
|
#else |
|
|
|
planner.buffer_line(delta[A_AXIS], delta[B_AXIS], delta[C_AXIS], logical[E_AXIS], _feedrate_mm_s, active_extruder); |
|
|
|
planner.buffer_line(delta[A_AXIS], delta[B_AXIS], delta[C_AXIS], raw[E_AXIS], _feedrate_mm_s, active_extruder); |
|
|
|
#endif |
|
|
|
} |
|
|
|
|
|
|
@ -626,13 +622,13 @@ float soft_endstop_min[XYZ] = { X_MIN_BED, Y_MIN_BED, Z_MIN_POS }, |
|
|
|
#if IS_SCARA && ENABLED(SCARA_FEEDRATE_SCALING) |
|
|
|
// For SCARA scale the feed rate from mm/s to degrees/s
|
|
|
|
// With segments > 1 length is 1 segment, otherwise total length
|
|
|
|
inverse_kinematics(ltarget); |
|
|
|
ADJUST_DELTA(ltarget); |
|
|
|
inverse_kinematics(rtarget); |
|
|
|
ADJUST_DELTA(rtarget); |
|
|
|
const float adiff = abs(delta[A_AXIS] - oldA), |
|
|
|
bdiff = abs(delta[B_AXIS] - oldB); |
|
|
|
planner.buffer_line(delta[A_AXIS], delta[B_AXIS], delta[C_AXIS], logical[E_AXIS], max(adiff, bdiff) * feed_factor, active_extruder); |
|
|
|
planner.buffer_line(delta[A_AXIS], delta[B_AXIS], delta[C_AXIS], raw[E_AXIS], max(adiff, bdiff) * feed_factor, active_extruder); |
|
|
|
#else |
|
|
|
planner.buffer_line_kinematic(ltarget, _feedrate_mm_s, active_extruder); |
|
|
|
planner.buffer_line_kinematic(rtarget, _feedrate_mm_s, active_extruder); |
|
|
|
#endif |
|
|
|
|
|
|
|
return false; |
|
|
@ -687,7 +683,7 @@ float soft_endstop_min[XYZ] = { X_MIN_BED, Y_MIN_BED, Z_MIN_POS }, |
|
|
|
|
|
|
|
float x_home_pos(const int extruder) { |
|
|
|
if (extruder == 0) |
|
|
|
return LOGICAL_X_POSITION(base_home_pos(X_AXIS)); |
|
|
|
return base_home_pos(X_AXIS); |
|
|
|
else |
|
|
|
/**
|
|
|
|
* In dual carriage mode the extruder offset provides an override of the |
|
|
@ -695,7 +691,7 @@ float soft_endstop_min[XYZ] = { X_MIN_BED, Y_MIN_BED, Z_MIN_POS }, |
|
|
|
* This allows soft recalibration of the second extruder home position |
|
|
|
* without firmware reflash (through the M218 command). |
|
|
|
*/ |
|
|
|
return LOGICAL_X_POSITION(hotend_offset[X_AXIS][1] > 0 ? hotend_offset[X_AXIS][1] : X2_HOME_POS); |
|
|
|
return hotend_offset[X_AXIS][1] > 0 ? hotend_offset[X_AXIS][1] : X2_HOME_POS; |
|
|
|
} |
|
|
|
|
|
|
|
/**
|
|
|
@ -740,13 +736,13 @@ float soft_endstop_min[XYZ] = { X_MIN_BED, Y_MIN_BED, Z_MIN_POS }, |
|
|
|
if (active_extruder == 0) { |
|
|
|
#if ENABLED(DEBUG_LEVELING_FEATURE) |
|
|
|
if (DEBUGGING(LEVELING)) { |
|
|
|
SERIAL_ECHOPAIR("Set planner X", LOGICAL_X_POSITION(inactive_extruder_x_pos)); |
|
|
|
SERIAL_ECHOPAIR("Set planner X", inactive_extruder_x_pos); |
|
|
|
SERIAL_ECHOLNPAIR(" ... Line to X", current_position[X_AXIS] + duplicate_extruder_x_offset); |
|
|
|
} |
|
|
|
#endif |
|
|
|
// move duplicate extruder into correct duplication position.
|
|
|
|
planner.set_position_mm( |
|
|
|
LOGICAL_X_POSITION(inactive_extruder_x_pos), |
|
|
|
inactive_extruder_x_pos, |
|
|
|
current_position[Y_AXIS], |
|
|
|
current_position[Z_AXIS], |
|
|
|
current_position[E_AXIS] |
|
|
@ -970,7 +966,7 @@ void set_axis_is_at_home(const AxisEnum axis) { |
|
|
|
#if ENABLED(MORGAN_SCARA) |
|
|
|
scara_set_axis_is_at_home(axis); |
|
|
|
#else |
|
|
|
current_position[axis] = LOGICAL_POSITION(base_home_pos(axis), axis); |
|
|
|
current_position[axis] = base_home_pos(axis); |
|
|
|
#endif |
|
|
|
|
|
|
|
/**
|
|
|
|