Allow Zero Endstops (e.g., for CNC) (#21120)

Co-authored-by: Scott Lahteine <thinkyhead@users.noreply.github.com>
This commit is contained in:
deirdreobyrne 2021-02-25 10:49:34 +00:00 committed by GitHub
parent d167af4c38
commit 468e437390
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 778 additions and 739 deletions

View file

@ -1118,8 +1118,8 @@ bool unified_bed_leveling::g29_parameter_parsing() {
} }
// If X or Y are not valid, use center of the bed values // If X or Y are not valid, use center of the bed values
if (!WITHIN(sx, X_MIN_BED, X_MAX_BED)) sx = X_CENTER; if (!COORDINATE_OKAY(sx, X_MIN_BED, X_MAX_BED)) sx = X_CENTER;
if (!WITHIN(sy, Y_MIN_BED, Y_MAX_BED)) sy = Y_CENTER; if (!COORDINATE_OKAY(sy, Y_MIN_BED, Y_MAX_BED)) sy = Y_CENTER;
if (err_flag) return UBL_ERR; if (err_flag) return UBL_ERR;

View file

@ -319,9 +319,13 @@ inline bool look_for_lines_to_connect() {
s.x = _GET_MESH_X( i ) + (INTERSECTION_CIRCLE_RADIUS - (CROSSHAIRS_SIZE)); // right edge s.x = _GET_MESH_X( i ) + (INTERSECTION_CIRCLE_RADIUS - (CROSSHAIRS_SIZE)); // right edge
e.x = _GET_MESH_X(i + 1) - (INTERSECTION_CIRCLE_RADIUS - (CROSSHAIRS_SIZE)); // left edge e.x = _GET_MESH_X(i + 1) - (INTERSECTION_CIRCLE_RADIUS - (CROSSHAIRS_SIZE)); // left edge
#if HAS_ENDSTOPS
LIMIT(s.x, X_MIN_POS + 1, X_MAX_POS - 1); LIMIT(s.x, X_MIN_POS + 1, X_MAX_POS - 1);
s.y = e.y = constrain(_GET_MESH_Y(j), Y_MIN_POS + 1, Y_MAX_POS - 1); s.y = e.y = constrain(_GET_MESH_Y(j), Y_MIN_POS + 1, Y_MAX_POS - 1);
LIMIT(e.x, X_MIN_POS + 1, X_MAX_POS - 1); LIMIT(e.x, X_MIN_POS + 1, X_MAX_POS - 1);
#else
s.y = e.y = _GET_MESH_Y(j);
#endif
if (position_is_reachable(s.x, s.y) && position_is_reachable(e.x, e.y)) if (position_is_reachable(s.x, s.y) && position_is_reachable(e.x, e.y))
print_line_from_here_to_there(s, e); print_line_from_here_to_there(s, e);
@ -339,9 +343,13 @@ inline bool look_for_lines_to_connect() {
s.y = _GET_MESH_Y( j ) + (INTERSECTION_CIRCLE_RADIUS - (CROSSHAIRS_SIZE)); // top edge s.y = _GET_MESH_Y( j ) + (INTERSECTION_CIRCLE_RADIUS - (CROSSHAIRS_SIZE)); // top edge
e.y = _GET_MESH_Y(j + 1) - (INTERSECTION_CIRCLE_RADIUS - (CROSSHAIRS_SIZE)); // bottom edge e.y = _GET_MESH_Y(j + 1) - (INTERSECTION_CIRCLE_RADIUS - (CROSSHAIRS_SIZE)); // bottom edge
#if HAS_ENDSTOPS
s.x = e.x = constrain(_GET_MESH_X(i), X_MIN_POS + 1, X_MAX_POS - 1); s.x = e.x = constrain(_GET_MESH_X(i), X_MIN_POS + 1, X_MAX_POS - 1);
LIMIT(s.y, Y_MIN_POS + 1, Y_MAX_POS - 1); LIMIT(s.y, Y_MIN_POS + 1, Y_MAX_POS - 1);
LIMIT(e.y, Y_MIN_POS + 1, Y_MAX_POS - 1); LIMIT(e.y, Y_MIN_POS + 1, Y_MAX_POS - 1);
#else
s.x = e.x = _GET_MESH_X(i);
#endif
if (position_is_reachable(s.x, s.y) && position_is_reachable(e.x, e.y)) if (position_is_reachable(s.x, s.y) && position_is_reachable(e.x, e.y))
print_line_from_here_to_there(s, e); print_line_from_here_to_there(s, e);
@ -826,7 +834,7 @@ void GcodeSuite::G26() {
#if IS_KINEMATIC #if IS_KINEMATIC
// Check to make sure this segment is entirely on the bed, skip if not. // Check to make sure this segment is entirely on the bed, skip if not.
if (!position_is_reachable(p) || !position_is_reachable(q)) continue; if (!position_is_reachable(p) || !position_is_reachable(q)) continue;
#else #elif HAS_ENDSTOPS
LIMIT(p.x, X_MIN_POS + 1, X_MAX_POS - 1); // Prevent hitting the endstops LIMIT(p.x, X_MIN_POS + 1, X_MAX_POS - 1); // Prevent hitting the endstops
LIMIT(p.y, Y_MIN_POS + 1, Y_MAX_POS - 1); LIMIT(p.y, Y_MIN_POS + 1, Y_MAX_POS - 1);
LIMIT(q.x, X_MIN_POS + 1, X_MAX_POS - 1); LIMIT(q.x, X_MIN_POS + 1, X_MAX_POS - 1);

View file

@ -202,7 +202,7 @@ void GcodeSuite::M48() {
if (verbose_level > 3) if (verbose_level > 3)
SERIAL_ECHOLNPAIR_P(PSTR("Moving inward: X"), next_pos.x, SP_Y_STR, next_pos.y); SERIAL_ECHOLNPAIR_P(PSTR("Moving inward: X"), next_pos.x, SP_Y_STR, next_pos.y);
} }
#else #elif HAS_ENDSTOPS
// For a rectangular bed just keep the probe in bounds // For a rectangular bed just keep the probe in bounds
LIMIT(next_pos.x, X_MIN_POS, X_MAX_POS); LIMIT(next_pos.x, X_MIN_POS, X_MAX_POS);
LIMIT(next_pos.y, Y_MIN_POS, Y_MAX_POS); LIMIT(next_pos.y, Y_MIN_POS, Y_MAX_POS);

View file

@ -1195,3 +1195,10 @@
#define TOUCH_ORIENTATION TOUCH_LANDSCAPE #define TOUCH_ORIENTATION TOUCH_LANDSCAPE
#endif #endif
#endif #endif
#if ANY(USE_XMIN_PLUG, USE_YMIN_PLUG, USE_ZMIN_PLUG, USE_XMAX_PLUG, USE_YMAX_PLUG, USE_ZMAX_PLUG)
#define HAS_ENDSTOPS 1
#define COORDINATE_OKAY(N,L,H) WITHIN(N,L,H)
#else
#define COORDINATE_OKAY(N,L,H) true
#endif

View file

@ -2016,19 +2016,20 @@ static_assert(hbm[Z_AXIS] >= 0, "HOMING_BUMP_MM.Z must be greater than or equal
&& !(ENABLED(A##_MULTI_ENDSTOPS) && WITHIN(A##2_USE_ENDSTOP, _##P##MAX_, _##P##MIN_)) ) && !(ENABLED(A##_MULTI_ENDSTOPS) && WITHIN(A##2_USE_ENDSTOP, _##P##MAX_, _##P##MIN_)) )
#define _AXIS_PLUG_UNUSED_TEST(A) (_PLUG_UNUSED_TEST(A,X) && _PLUG_UNUSED_TEST(A,Y) && _PLUG_UNUSED_TEST(A,Z)) #define _AXIS_PLUG_UNUSED_TEST(A) (_PLUG_UNUSED_TEST(A,X) && _PLUG_UNUSED_TEST(A,Y) && _PLUG_UNUSED_TEST(A,Z))
// At least 3 endstop plugs must be used // A machine with endstops must have a minimum of 3
#if _AXIS_PLUG_UNUSED_TEST(X) #if HAS_ENDSTOPS
#if _AXIS_PLUG_UNUSED_TEST(X)
#error "You must enable USE_XMIN_PLUG or USE_XMAX_PLUG." #error "You must enable USE_XMIN_PLUG or USE_XMAX_PLUG."
#endif #endif
#if _AXIS_PLUG_UNUSED_TEST(Y) #if _AXIS_PLUG_UNUSED_TEST(Y)
#error "You must enable USE_YMIN_PLUG or USE_YMAX_PLUG." #error "You must enable USE_YMIN_PLUG or USE_YMAX_PLUG."
#endif #endif
#if _AXIS_PLUG_UNUSED_TEST(Z) #if _AXIS_PLUG_UNUSED_TEST(Z)
#error "You must enable USE_ZMIN_PLUG or USE_ZMAX_PLUG." #error "You must enable USE_ZMIN_PLUG or USE_ZMAX_PLUG."
#endif #endif
// Delta and Cartesian use 3 homing endstops // Delta and Cartesian use 3 homing endstops
#if NONE(IS_SCARA, SPI_ENDSTOPS) #if NONE(IS_SCARA, SPI_ENDSTOPS)
#if X_HOME_DIR < 0 && DISABLED(USE_XMIN_PLUG) #if X_HOME_DIR < 0 && DISABLED(USE_XMIN_PLUG)
#error "Enable USE_XMIN_PLUG when homing X to MIN." #error "Enable USE_XMIN_PLUG when homing X to MIN."
#elif X_HOME_DIR > 0 && DISABLED(USE_XMAX_PLUG) #elif X_HOME_DIR > 0 && DISABLED(USE_XMAX_PLUG)
@ -2038,17 +2039,18 @@ static_assert(hbm[Z_AXIS] >= 0, "HOMING_BUMP_MM.Z must be greater than or equal
#elif Y_HOME_DIR > 0 && DISABLED(USE_YMAX_PLUG) #elif Y_HOME_DIR > 0 && DISABLED(USE_YMAX_PLUG)
#error "Enable USE_YMAX_PLUG when homing Y to MAX." #error "Enable USE_YMAX_PLUG when homing Y to MAX."
#endif #endif
#endif #endif
// Z homing direction and plug usage flags // Z homing direction and plug usage flags
#if Z_HOME_DIR < 0 && NONE(USE_ZMIN_PLUG, HOMING_Z_WITH_PROBE) #if Z_HOME_DIR < 0 && NONE(USE_ZMIN_PLUG, HOMING_Z_WITH_PROBE)
#error "Enable USE_ZMIN_PLUG when homing Z to MIN." #error "Enable USE_ZMIN_PLUG when homing Z to MIN."
#elif Z_HOME_DIR > 0 && ENABLED(USE_PROBE_FOR_Z_HOMING) #elif Z_HOME_DIR > 0 && ENABLED(USE_PROBE_FOR_Z_HOMING)
#error "Z_HOME_DIR must be -1 when homing Z with the probe." #error "Z_HOME_DIR must be -1 when homing Z with the probe."
#elif BOTH(HOMING_Z_WITH_PROBE, Z_MULTI_ENDSTOPS) #elif BOTH(HOMING_Z_WITH_PROBE, Z_MULTI_ENDSTOPS)
#error "Z_MULTI_ENDSTOPS is incompatible with USE_PROBE_FOR_Z_HOMING." #error "Z_MULTI_ENDSTOPS is incompatible with USE_PROBE_FOR_Z_HOMING."
#elif Z_HOME_DIR > 0 && DISABLED(USE_ZMAX_PLUG) #elif Z_HOME_DIR > 0 && DISABLED(USE_ZMAX_PLUG)
#error "Enable USE_ZMAX_PLUG when homing Z to MAX." #error "Enable USE_ZMAX_PLUG when homing Z to MAX."
#endif
#endif #endif
#if BOTH(HOME_Z_FIRST, USE_PROBE_FOR_Z_HOMING) #if BOTH(HOME_Z_FIRST, USE_PROBE_FOR_Z_HOMING)

View file

@ -446,10 +446,8 @@ uint8_t L64XX_Marlin::get_user_input(uint8_t &driver_count, L64XX_axis_t axis_in
position_max = X_center + displacement; position_max = X_center + displacement;
echo_min_max('X', position_min, position_max); echo_min_max('X', position_min, position_max);
if (false if (false
#ifdef X_MIN_POS #if HAS_ENDSTOPS
|| position_min < (X_MIN_POS) || position_min < (X_MIN_POS)
#endif
#ifdef X_MAX_POS
|| position_max > (X_MAX_POS) || position_max > (X_MAX_POS)
#endif #endif
) { ) {
@ -463,10 +461,8 @@ uint8_t L64XX_Marlin::get_user_input(uint8_t &driver_count, L64XX_axis_t axis_in
position_max = Y_center + displacement; position_max = Y_center + displacement;
echo_min_max('Y', position_min, position_max); echo_min_max('Y', position_min, position_max);
if (false if (false
#ifdef Y_MIN_POS #if HAS_ENDSTOPS
|| position_min < (Y_MIN_POS) || position_min < (Y_MIN_POS)
#endif
#ifdef Y_MAX_POS
|| position_max > (Y_MAX_POS) || position_max > (Y_MAX_POS)
#endif #endif
) { ) {
@ -480,10 +476,8 @@ uint8_t L64XX_Marlin::get_user_input(uint8_t &driver_count, L64XX_axis_t axis_in
position_max = Z_center + displacement; position_max = Z_center + displacement;
echo_min_max('Z', position_min, position_max); echo_min_max('Z', position_min, position_max);
if (false if (false
#ifdef Z_MIN_POS #if HAS_ENDSTOPS
|| position_min < (Z_MIN_POS) || position_min < (Z_MIN_POS)
#endif
#ifdef Z_MAX_POS
|| position_max > (Z_MAX_POS) || position_max > (Z_MAX_POS)
#endif #endif
) { ) {

View file

@ -74,17 +74,6 @@
#define DEBUG_OUT ENABLED(DEBUG_LEVELING_FEATURE) #define DEBUG_OUT ENABLED(DEBUG_LEVELING_FEATURE)
#include "../core/debug_out.h" #include "../core/debug_out.h"
/**
* axis_homed
* Flags that each linear axis was homed.
* XYZ on cartesian, ABC on delta, ABZ on SCARA.
*
* axis_trusted
* Flags that the position is trusted in each linear axis. Set when homed.
* Cleared whenever a stepper powers off, potentially losing its position.
*/
uint8_t axis_homed, axis_trusted; // = 0
// Relative Mode. Enable with G91, disable with G90. // Relative Mode. Enable with G91, disable with G90.
bool relative_mode; // = false; bool relative_mode; // = false;
@ -1122,16 +1111,20 @@ void prepare_line_to_destination() {
current_position = destination; current_position = destination;
} }
uint8_t axes_should_home(uint8_t axis_bits/*=0x07*/) { #if HAS_ENDSTOPS
uint8_t axis_homed, axis_trusted; // = 0
uint8_t axes_should_home(uint8_t axis_bits/*=0x07*/) {
#define SHOULD_HOME(A) TERN(HOME_AFTER_DEACTIVATE, axis_is_trusted, axis_was_homed)(A) #define SHOULD_HOME(A) TERN(HOME_AFTER_DEACTIVATE, axis_is_trusted, axis_was_homed)(A)
// Clear test bits that are trusted // Clear test bits that are trusted
if (TEST(axis_bits, X_AXIS) && SHOULD_HOME(X_AXIS)) CBI(axis_bits, X_AXIS); if (TEST(axis_bits, X_AXIS) && SHOULD_HOME(X_AXIS)) CBI(axis_bits, X_AXIS);
if (TEST(axis_bits, Y_AXIS) && SHOULD_HOME(Y_AXIS)) CBI(axis_bits, Y_AXIS); if (TEST(axis_bits, Y_AXIS) && SHOULD_HOME(Y_AXIS)) CBI(axis_bits, Y_AXIS);
if (TEST(axis_bits, Z_AXIS) && SHOULD_HOME(Z_AXIS)) CBI(axis_bits, Z_AXIS); if (TEST(axis_bits, Z_AXIS) && SHOULD_HOME(Z_AXIS)) CBI(axis_bits, Z_AXIS);
return axis_bits; return axis_bits;
} }
bool homing_needed_error(uint8_t axis_bits/*=0x07*/) { bool homing_needed_error(uint8_t axis_bits/*=0x07*/) {
if ((axis_bits = axes_should_home(axis_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);
char msg[strlen_P(home_first)+1]; char msg[strlen_P(home_first)+1];
@ -1146,12 +1139,12 @@ bool homing_needed_error(uint8_t axis_bits/*=0x07*/) {
return true; return true;
} }
return false; return false;
} }
/** /**
* Homing bump feedrate (mm/s) * Homing bump feedrate (mm/s)
*/ */
feedRate_t get_homing_bump_feedrate(const AxisEnum axis) { feedRate_t get_homing_bump_feedrate(const AxisEnum axis) {
#if HOMING_Z_WITH_PROBE #if HOMING_Z_WITH_PROBE
if (axis == Z_AXIS) return MMM_TO_MMS(Z_PROBE_SPEED_SLOW); if (axis == Z_AXIS) return MMM_TO_MMS(Z_PROBE_SPEED_SLOW);
#endif #endif
@ -1162,9 +1155,9 @@ feedRate_t get_homing_bump_feedrate(const AxisEnum axis) {
SERIAL_ECHO_MSG("Warning: Homing Bump Divisor < 1"); SERIAL_ECHO_MSG("Warning: Homing Bump Divisor < 1");
} }
return homing_feedrate(axis) / float(hbd); return homing_feedrate(axis) / float(hbd);
} }
#if ENABLED(SENSORLESS_HOMING) #if ENABLED(SENSORLESS_HOMING)
/** /**
* Set sensorless homing if the axis has it, accounting for Core Kinematics. * Set sensorless homing if the axis has it, accounting for Core Kinematics.
*/ */
@ -1294,12 +1287,12 @@ feedRate_t get_homing_bump_feedrate(const AxisEnum axis) {
#endif #endif
} }
#endif // SENSORLESS_HOMING #endif // SENSORLESS_HOMING
/** /**
* Home an individual linear axis * Home an individual linear axis
*/ */
void do_homing_move(const AxisEnum axis, const float distance, const feedRate_t fr_mm_s=0.0, const bool final_approach=true) { void do_homing_move(const AxisEnum axis, const float distance, const feedRate_t fr_mm_s=0.0, const bool final_approach=true) {
DEBUG_SECTION(log_move, "do_homing_move", DEBUGGING(LEVELING)); DEBUG_SECTION(log_move, "do_homing_move", DEBUGGING(LEVELING));
const feedRate_t home_fr_mm_s = fr_mm_s ?: homing_feedrate(axis); const feedRate_t home_fr_mm_s = fr_mm_s ?: homing_feedrate(axis);
@ -1377,88 +1370,14 @@ void do_homing_move(const AxisEnum axis, const float distance, const feedRate_t
// Re-enable stealthChop if used. Disable diag1 pin on driver. // Re-enable stealthChop if used. Disable diag1 pin on driver.
TERN_(SENSORLESS_HOMING, end_sensorless_homing_per_axis(axis, stealth_states)); TERN_(SENSORLESS_HOMING, end_sensorless_homing_per_axis(axis, stealth_states));
} }
}
/**
* Set an axis' current position to its home position (after homing).
*
* For Core and Cartesian robots this applies one-to-one when an
* individual axis has been homed.
*
* DELTA should wait until all homing is done before setting the XYZ
* current_position to home, because homing is a single operation.
* In the case where the axis positions are trusted and previously
* homed, DELTA could home to X or Y individually by moving either one
* to the center. However, homing Z always homes XY and Z.
*
* SCARA should wait until all XY homing is done before setting the XY
* current_position to home, because neither X nor Y is at home until
* both are at home. Z can however be homed individually.
*
* Callers must sync the planner position after calling this!
*/
void set_axis_is_at_home(const AxisEnum axis) {
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPAIR(">>> set_axis_is_at_home(", AS_CHAR(axis_codes[axis]), ")");
set_axis_trusted(axis);
set_axis_homed(axis);
#if ENABLED(DUAL_X_CARRIAGE)
if (axis == X_AXIS && (active_extruder == 1 || dual_x_carriage_mode == DXC_DUPLICATION_MODE)) {
current_position.x = x_home_pos(active_extruder);
return;
} }
#endif
#if ENABLED(MORGAN_SCARA)
scara_set_axis_is_at_home(axis);
#elif ENABLED(DELTA)
current_position[axis] = (axis == Z_AXIS) ? delta_height - TERN0(HAS_BED_PROBE, probe.offset.z) : base_home_pos(axis);
#else
current_position[axis] = base_home_pos(axis);
#endif
/** /**
* Z Probe Z Homing? Account for the probe's Z offset. * Set an axis to be unhomed. (Unless we are on a machine - e.g. a cheap Chinese CNC machine -
* that has no endstops. Such machines should always be considered to be in a "known" and
* "trusted" position).
*/ */
#if HAS_BED_PROBE && Z_HOME_DIR < 0 void set_axis_never_homed(const AxisEnum axis) {
if (axis == Z_AXIS) {
#if HOMING_Z_WITH_PROBE
current_position.z -= probe.offset.z;
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPAIR("*** Z HOMED WITH PROBE (Z_MIN_PROBE_USES_Z_MIN_ENDSTOP_PIN) ***\n> probe.offset.z = ", probe.offset.z);
#else
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("*** Z HOMED TO ENDSTOP ***");
#endif
}
#endif
TERN_(I2C_POSITION_ENCODERS, I2CPEM.homed(axis));
TERN_(BABYSTEP_DISPLAY_TOTAL, babystep.reset_total(axis));
#if HAS_POSITION_SHIFT
position_shift[axis] = 0;
update_workspace_offset(axis);
#endif
if (DEBUGGING(LEVELING)) {
#if HAS_HOME_OFFSET
DEBUG_ECHOLNPAIR("> home_offset[", AS_CHAR(axis_codes[axis]), "] = ", home_offset[axis]);
#endif
DEBUG_POS("", current_position);
DEBUG_ECHOLNPAIR("<<< set_axis_is_at_home(", axis_codes[axis], ")");
}
}
/**
* Set an axis to be unhomed.
*/
void set_axis_never_homed(const AxisEnum axis) {
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPAIR(">>> set_axis_never_homed(", axis_codes[axis], ")"); if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPAIR(">>> set_axis_never_homed(", axis_codes[axis], ")");
set_axis_untrusted(axis); set_axis_untrusted(axis);
@ -1467,9 +1386,9 @@ void set_axis_never_homed(const AxisEnum axis) {
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPAIR("<<< set_axis_never_homed(", axis_codes[axis], ")"); if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPAIR("<<< set_axis_never_homed(", axis_codes[axis], ")");
TERN_(I2C_POSITION_ENCODERS, I2CPEM.unhomed(axis)); TERN_(I2C_POSITION_ENCODERS, I2CPEM.unhomed(axis));
} }
#ifdef TMC_HOME_PHASE #if ENABLED(TMC_HOME_PHASE)
/** /**
* Move the axis back to its home_phase if set and driver is capable (TMC) * Move the axis back to its home_phase if set and driver is capable (TMC)
* *
@ -1546,9 +1465,9 @@ void set_axis_never_homed(const AxisEnum axis) {
do_homing_move(axis, mmDelta, get_homing_bump_feedrate(axis)); do_homing_move(axis, mmDelta, get_homing_bump_feedrate(axis));
} }
} }
#endif #endif
/** /**
* Home an individual "raw axis" to its endstop. * Home an individual "raw axis" to its endstop.
* This applies to XYZ on Cartesian and Core robots, and * This applies to XYZ on Cartesian and Core robots, and
* to the individual ABC steppers on DELTA and SCARA. * to the individual ABC steppers on DELTA and SCARA.
@ -1559,7 +1478,7 @@ void set_axis_never_homed(const AxisEnum axis) {
* before updating the current position. * before updating the current position.
*/ */
void homeaxis(const AxisEnum axis) { void homeaxis(const AxisEnum axis) {
#if IS_SCARA #if IS_SCARA
// Only Z homing (with probe) is permitted // Only Z homing (with probe) is permitted
@ -1875,7 +1794,85 @@ void homeaxis(const AxisEnum axis) {
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPAIR("<<< homeaxis(", axis_codes[axis], ")"); if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPAIR("<<< homeaxis(", axis_codes[axis], ")");
} // homeaxis() } // homeaxis()
#endif // HAS_ENDSTOPS
/**
* Set an axis' current position to its home position (after homing).
*
* For Core and Cartesian robots this applies one-to-one when an
* individual axis has been homed.
*
* DELTA should wait until all homing is done before setting the XYZ
* current_position to home, because homing is a single operation.
* In the case where the axis positions are trusted and previously
* homed, DELTA could home to X or Y individually by moving either one
* to the center. However, homing Z always homes XY and Z.
*
* SCARA should wait until all XY homing is done before setting the XY
* current_position to home, because neither X nor Y is at home until
* both are at home. Z can however be homed individually.
*
* Callers must sync the planner position after calling this!
*/
void set_axis_is_at_home(const AxisEnum axis) {
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPAIR(">>> set_axis_is_at_home(", AS_CHAR(axis_codes[axis]), ")");
set_axis_trusted(axis);
set_axis_homed(axis);
#if ENABLED(DUAL_X_CARRIAGE)
if (axis == X_AXIS && (active_extruder == 1 || dual_x_carriage_mode == DXC_DUPLICATION_MODE)) {
current_position.x = x_home_pos(active_extruder);
return;
}
#endif
#if ENABLED(MORGAN_SCARA)
scara_set_axis_is_at_home(axis);
#elif ENABLED(DELTA)
current_position[axis] = (axis == Z_AXIS) ? delta_height - TERN0(HAS_BED_PROBE, probe.offset.z) : base_home_pos(axis);
#else
current_position[axis] = base_home_pos(axis);
#endif
/**
* Z Probe Z Homing? Account for the probe's Z offset.
*/
#if HAS_BED_PROBE && Z_HOME_DIR < 0
if (axis == Z_AXIS) {
#if HOMING_Z_WITH_PROBE
current_position.z -= probe.offset.z;
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPAIR("*** Z HOMED WITH PROBE (Z_MIN_PROBE_USES_Z_MIN_ENDSTOP_PIN) ***\n> probe.offset.z = ", probe.offset.z);
#else
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("*** Z HOMED TO ENDSTOP ***");
#endif
}
#endif
TERN_(I2C_POSITION_ENCODERS, I2CPEM.homed(axis));
TERN_(BABYSTEP_DISPLAY_TOTAL, babystep.reset_total(axis));
#if HAS_POSITION_SHIFT
position_shift[axis] = 0;
update_workspace_offset(axis);
#endif
if (DEBUGGING(LEVELING)) {
#if HAS_HOME_OFFSET
DEBUG_ECHOLNPAIR("> home_offset[", AS_CHAR(axis_codes[axis]), "] = ", home_offset[axis]);
#endif
DEBUG_POS("", current_position);
DEBUG_ECHOLNPAIR("<<< set_axis_is_at_home(", axis_codes[axis], ")");
}
}
#if HAS_WORKSPACE_OFFSET #if HAS_WORKSPACE_OFFSET
void update_workspace_offset(const AxisEnum axis) { void update_workspace_offset(const AxisEnum axis) {
@ -1893,4 +1890,4 @@ void homeaxis(const AxisEnum axis) {
home_offset[axis] = v; home_offset[axis] = v;
update_workspace_offset(axis); update_workspace_offset(axis);
} }
#endif // HAS_M206_COMMAND #endif

View file

@ -284,13 +284,43 @@ void do_z_clearance(const float &zclear, const bool z_trusted=true, const bool r
* Homing and Trusted Axes * Homing and Trusted Axes
*/ */
constexpr uint8_t xyz_bits = _BV(X_AXIS) | _BV(Y_AXIS) | _BV(Z_AXIS); constexpr uint8_t xyz_bits = _BV(X_AXIS) | _BV(Y_AXIS) | _BV(Z_AXIS);
extern uint8_t axis_homed, axis_trusted;
void homeaxis(const AxisEnum axis);
void set_axis_is_at_home(const AxisEnum axis); void set_axis_is_at_home(const AxisEnum axis);
void set_axis_never_homed(const AxisEnum axis);
uint8_t axes_should_home(uint8_t axis_bits=0x07); #if HAS_ENDSTOPS
bool homing_needed_error(uint8_t axis_bits=0x07); /**
* axis_homed
* Flags that each linear axis was homed.
* XYZ on cartesian, ABC on delta, ABZ on SCARA.
*
* axis_trusted
* Flags that the position is trusted in each linear axis. Set when homed.
* Cleared whenever a stepper powers off, potentially losing its position.
*/
extern uint8_t axis_homed, axis_trusted;
void homeaxis(const AxisEnum axis);
void set_axis_never_homed(const AxisEnum axis);
uint8_t axes_should_home(uint8_t axis_bits=0x07);
bool homing_needed_error(uint8_t axis_bits=0x07);
FORCE_INLINE void set_axis_unhomed(const AxisEnum axis) { CBI(axis_homed, axis); }
FORCE_INLINE void set_axis_untrusted(const AxisEnum axis) { CBI(axis_trusted, axis); }
FORCE_INLINE void set_all_unhomed() { axis_homed = axis_trusted = 0; }
FORCE_INLINE void set_axis_homed(const AxisEnum axis) { SBI(axis_homed, axis); }
FORCE_INLINE void set_axis_trusted(const AxisEnum axis) { SBI(axis_trusted, axis); }
FORCE_INLINE void set_all_homed() { axis_homed = axis_trusted = xyz_bits; }
#else
constexpr uint8_t axis_homed = xyz_bits, axis_trusted = xyz_bits; // Zero-endstop machines are always homed and trusted
FORCE_INLINE void homeaxis(const AxisEnum axis) {}
FORCE_INLINE void set_axis_never_homed(const AxisEnum) {}
FORCE_INLINE uint8_t axes_should_home(uint8_t=0x07) { return false; }
FORCE_INLINE bool homing_needed_error(uint8_t=0x07) { return false; }
FORCE_INLINE void set_axis_unhomed(const AxisEnum axis) {}
FORCE_INLINE void set_axis_untrusted(const AxisEnum axis) {}
FORCE_INLINE void set_all_unhomed() {}
FORCE_INLINE void set_axis_homed(const AxisEnum axis) {}
FORCE_INLINE void set_axis_trusted(const AxisEnum axis) {}
FORCE_INLINE void set_all_homed() {}
#endif
FORCE_INLINE bool axis_was_homed(const AxisEnum axis) { return TEST(axis_homed, axis); } FORCE_INLINE bool axis_was_homed(const AxisEnum axis) { return TEST(axis_homed, axis); }
FORCE_INLINE bool axis_is_trusted(const AxisEnum axis) { return TEST(axis_trusted, axis); } FORCE_INLINE bool axis_is_trusted(const AxisEnum axis) { return TEST(axis_trusted, axis); }
@ -299,12 +329,6 @@ FORCE_INLINE bool no_axes_homed() { return !axis_homed;
FORCE_INLINE bool all_axes_homed() { return xyz_bits == (axis_homed & xyz_bits); } FORCE_INLINE bool all_axes_homed() { return xyz_bits == (axis_homed & xyz_bits); }
FORCE_INLINE bool homing_needed() { return !all_axes_homed(); } FORCE_INLINE bool homing_needed() { return !all_axes_homed(); }
FORCE_INLINE bool all_axes_trusted() { return xyz_bits == (axis_trusted & xyz_bits); } FORCE_INLINE bool all_axes_trusted() { return xyz_bits == (axis_trusted & xyz_bits); }
FORCE_INLINE void set_axis_homed(const AxisEnum axis) { SBI(axis_homed, axis); }
FORCE_INLINE void set_axis_unhomed(const AxisEnum axis) { CBI(axis_homed, axis); }
FORCE_INLINE void set_axis_trusted(const AxisEnum axis) { SBI(axis_trusted, axis); }
FORCE_INLINE void set_axis_untrusted(const AxisEnum axis) { CBI(axis_trusted, axis); }
FORCE_INLINE void set_all_homed() { axis_homed = axis_trusted = xyz_bits; }
FORCE_INLINE void set_all_unhomed() { axis_homed = axis_trusted = 0; }
#if ENABLED(NO_MOTION_BEFORE_HOMING) #if ENABLED(NO_MOTION_BEFORE_HOMING)
#define MOTION_CONDITIONS (IsRunning() && !homing_needed_error()) #define MOTION_CONDITIONS (IsRunning() && !homing_needed_error())
@ -360,7 +384,6 @@ FORCE_INLINE void set_all_unhomed() { axis_homed = axis_tr
/** /**
* position_is_reachable family of functions * position_is_reachable family of functions
*/ */
#if IS_KINEMATIC // (DELTA or SCARA) #if IS_KINEMATIC // (DELTA or SCARA)
#if HAS_SCARA_OFFSET #if HAS_SCARA_OFFSET
@ -390,14 +413,14 @@ FORCE_INLINE void set_all_unhomed() { axis_homed = axis_tr
// Return true if the given position is within the machine bounds. // Return true if the given position is within the machine bounds.
inline bool position_is_reachable(const float &rx, const float &ry) { inline bool position_is_reachable(const float &rx, const float &ry) {
if (!WITHIN(ry, Y_MIN_POS - fslop, Y_MAX_POS + fslop)) return false; if (!COORDINATE_OKAY(ry, Y_MIN_POS - fslop, Y_MAX_POS + fslop)) return false;
#if ENABLED(DUAL_X_CARRIAGE) #if ENABLED(DUAL_X_CARRIAGE)
if (active_extruder) if (active_extruder)
return WITHIN(rx, X2_MIN_POS - fslop, X2_MAX_POS + fslop); return COORDINATE_OKAY(rx, X2_MIN_POS - fslop, X2_MAX_POS + fslop);
else else
return WITHIN(rx, X1_MIN_POS - fslop, X1_MAX_POS + fslop); return COORDINATE_OKAY(rx, X1_MIN_POS - fslop, X1_MAX_POS + fslop);
#else #else
return WITHIN(rx, X_MIN_POS - fslop, X_MAX_POS + fslop); return COORDINATE_OKAY(rx, X_MIN_POS - fslop, X_MAX_POS + fslop);
#endif #endif
} }
inline bool position_is_reachable(const xy_pos_t &pos) { return position_is_reachable(pos.x, pos.y); } inline bool position_is_reachable(const xy_pos_t &pos) { return position_is_reachable(pos.x, pos.y); }

View file

@ -564,10 +564,10 @@ class Planner {
#if ENABLED(SKEW_CORRECTION) #if ENABLED(SKEW_CORRECTION)
FORCE_INLINE static void skew(float &cx, float &cy, const float &cz) { FORCE_INLINE static void skew(float &cx, float &cy, const float &cz) {
if (WITHIN(cx, X_MIN_POS + 1, X_MAX_POS) && WITHIN(cy, Y_MIN_POS + 1, Y_MAX_POS)) { if (COORDINATE_OKAY(cx, X_MIN_POS + 1, X_MAX_POS) && COORDINATE_OKAY(cy, Y_MIN_POS + 1, Y_MAX_POS)) {
const float sx = cx - cy * skew_factor.xy - cz * (skew_factor.xz - (skew_factor.xy * skew_factor.yz)), const float sx = cx - cy * skew_factor.xy - cz * (skew_factor.xz - (skew_factor.xy * skew_factor.yz)),
sy = cy - cz * skew_factor.yz; sy = cy - cz * skew_factor.yz;
if (WITHIN(sx, X_MIN_POS, X_MAX_POS) && WITHIN(sy, Y_MIN_POS, Y_MAX_POS)) { if (COORDINATE_OKAY(sx, X_MIN_POS, X_MAX_POS) && COORDINATE_OKAY(sy, Y_MIN_POS, Y_MAX_POS)) {
cx = sx; cy = sy; cx = sx; cy = sy;
} }
} }
@ -575,10 +575,10 @@ class Planner {
FORCE_INLINE static void skew(xyz_pos_t &raw) { skew(raw.x, raw.y, raw.z); } FORCE_INLINE static void skew(xyz_pos_t &raw) { skew(raw.x, raw.y, raw.z); }
FORCE_INLINE static void unskew(float &cx, float &cy, const float &cz) { FORCE_INLINE static void unskew(float &cx, float &cy, const float &cz) {
if (WITHIN(cx, X_MIN_POS, X_MAX_POS) && WITHIN(cy, Y_MIN_POS, Y_MAX_POS)) { if (COORDINATE_OKAY(cx, X_MIN_POS, X_MAX_POS) && COORDINATE_OKAY(cy, Y_MIN_POS, Y_MAX_POS)) {
const float sx = cx + cy * skew_factor.xy + cz * skew_factor.xz, const float sx = cx + cy * skew_factor.xy + cz * skew_factor.xz,
sy = cy + cz * skew_factor.yz; sy = cy + cz * skew_factor.yz;
if (WITHIN(sx, X_MIN_POS, X_MAX_POS) && WITHIN(sy, Y_MIN_POS, Y_MAX_POS)) { if (COORDINATE_OKAY(sx, X_MIN_POS, X_MAX_POS) && COORDINATE_OKAY(sy, Y_MIN_POS, Y_MAX_POS)) {
cx = sx; cy = sy; cx = sx; cy = sy;
} }
} }

View file

@ -92,8 +92,8 @@ public:
*/ */
static bool can_reach(const float &rx, const float &ry) { static bool can_reach(const float &rx, const float &ry) {
return position_is_reachable(rx - offset_xy.x, ry - offset_xy.y) return position_is_reachable(rx - offset_xy.x, ry - offset_xy.y)
&& WITHIN(rx, min_x() - fslop, max_x() + fslop) && COORDINATE_OKAY(rx, min_x() - fslop, max_x() + fslop)
&& WITHIN(ry, min_y() - fslop, max_y() + fslop); && COORDINATE_OKAY(ry, min_y() - fslop, max_y() + fslop);
} }
#endif #endif
@ -206,8 +206,8 @@ public:
#if IS_KINEMATIC #if IS_KINEMATIC
return HYPOT2(x, y) <= sq(probe_radius(default_probe_xy_offset)); return HYPOT2(x, y) <= sq(probe_radius(default_probe_xy_offset));
#else #else
return WITHIN(x, _min_x(default_probe_xy_offset) - fslop, _max_x(default_probe_xy_offset) + fslop) return COORDINATE_OKAY(x, _min_x(default_probe_xy_offset) - fslop, _max_x(default_probe_xy_offset) + fslop)
&& WITHIN(y, _min_y(default_probe_xy_offset) - fslop, _max_y(default_probe_xy_offset) + fslop); && COORDINATE_OKAY(y, _min_y(default_probe_xy_offset) - fslop, _max_y(default_probe_xy_offset) + fslop);
#endif #endif
} }

View file

@ -10,6 +10,14 @@ restore_configs
opt_set MOTHERBOARD BOARD_TEENSY31_32 opt_set MOTHERBOARD BOARD_TEENSY31_32
exec_test $1 $2 "Teensy3.1 with default config" "$3" exec_test $1 $2 "Teensy3.1 with default config" "$3"
#
# Zero endstops, as with a CNC
#
restore_configs
opt_set MOTHERBOARD BOARD_TEENSY31_32
opt_disable USE_XMIN_PLUG USE_YMIN_PLUG USE_ZMIN_PLUG
exec_test $1 $2 "Teensy3.1 with Zero Endstops" "$3"
# #
# Test many features together # Test many features together
# #