Allow Zero Endstops (e.g., for CNC) (#21120)
Co-authored-by: Scott Lahteine <thinkyhead@users.noreply.github.com>
This commit is contained in:
		
							parent
							
								
									d167af4c38
								
							
						
					
					
						commit
						468e437390
					
				| @ -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 (!WITHIN(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(sx, X_MIN_BED, X_MAX_BED)) sx = X_CENTER; | ||||
|   if (!COORDINATE_OKAY(sy, Y_MIN_BED, Y_MAX_BED)) sy = Y_CENTER; | ||||
| 
 | ||||
|   if (err_flag) return UBL_ERR; | ||||
| 
 | ||||
|  | ||||
| @ -319,9 +319,13 @@ inline bool look_for_lines_to_connect() { | ||||
|           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
 | ||||
| 
 | ||||
|           #if HAS_ENDSTOPS | ||||
|             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); | ||||
|             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)) | ||||
|             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
 | ||||
|             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); | ||||
|               LIMIT(s.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)) | ||||
|               print_line_from_here_to_there(s, e); | ||||
| @ -826,7 +834,7 @@ void GcodeSuite::G26() { | ||||
|           #if IS_KINEMATIC | ||||
|             // Check to make sure this segment is entirely on the bed, skip if not.
 | ||||
|             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.y, Y_MIN_POS + 1, Y_MAX_POS - 1); | ||||
|             LIMIT(q.x, X_MIN_POS + 1, X_MAX_POS - 1); | ||||
|  | ||||
| @ -202,7 +202,7 @@ void GcodeSuite::M48() { | ||||
|               if (verbose_level > 3) | ||||
|                 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
 | ||||
|             LIMIT(next_pos.x, X_MIN_POS, X_MAX_POS); | ||||
|             LIMIT(next_pos.y, Y_MIN_POS, Y_MAX_POS); | ||||
|  | ||||
| @ -1195,3 +1195,10 @@ | ||||
|     #define TOUCH_ORIENTATION    TOUCH_LANDSCAPE | ||||
|   #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 | ||||
|  | ||||
| @ -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_)) ) | ||||
| #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
 | ||||
| #if _AXIS_PLUG_UNUSED_TEST(X) | ||||
| // A machine with endstops must have a minimum of 3
 | ||||
| #if HAS_ENDSTOPS | ||||
|   #if _AXIS_PLUG_UNUSED_TEST(X) | ||||
|     #error "You must enable USE_XMIN_PLUG or USE_XMAX_PLUG." | ||||
| #endif | ||||
| #if _AXIS_PLUG_UNUSED_TEST(Y) | ||||
|   #endif | ||||
|   #if _AXIS_PLUG_UNUSED_TEST(Y) | ||||
|     #error "You must enable USE_YMIN_PLUG or USE_YMAX_PLUG." | ||||
| #endif | ||||
| #if _AXIS_PLUG_UNUSED_TEST(Z) | ||||
|   #endif | ||||
|   #if _AXIS_PLUG_UNUSED_TEST(Z) | ||||
|     #error "You must enable USE_ZMIN_PLUG or USE_ZMAX_PLUG." | ||||
| #endif | ||||
|   #endif | ||||
| 
 | ||||
| // Delta and Cartesian use 3 homing endstops
 | ||||
| #if NONE(IS_SCARA, SPI_ENDSTOPS) | ||||
|   // Delta and Cartesian use 3 homing endstops
 | ||||
|   #if NONE(IS_SCARA, SPI_ENDSTOPS) | ||||
|     #if X_HOME_DIR < 0 && DISABLED(USE_XMIN_PLUG) | ||||
|       #error "Enable USE_XMIN_PLUG when homing X to MIN." | ||||
|     #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) | ||||
|       #error "Enable USE_YMAX_PLUG when homing Y to MAX." | ||||
|     #endif | ||||
| #endif | ||||
|   #endif | ||||
| 
 | ||||
| // Z homing direction and plug usage flags
 | ||||
| #if Z_HOME_DIR < 0 && NONE(USE_ZMIN_PLUG, HOMING_Z_WITH_PROBE) | ||||
|   // Z homing direction and plug usage flags
 | ||||
|   #if Z_HOME_DIR < 0 && NONE(USE_ZMIN_PLUG, HOMING_Z_WITH_PROBE) | ||||
|     #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." | ||||
| #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." | ||||
| #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." | ||||
|   #endif | ||||
| #endif | ||||
| 
 | ||||
| #if BOTH(HOME_Z_FIRST, USE_PROBE_FOR_Z_HOMING) | ||||
|  | ||||
| @ -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; | ||||
|       echo_min_max('X', position_min, position_max); | ||||
|       if (false | ||||
|         #ifdef X_MIN_POS | ||||
|         #if HAS_ENDSTOPS | ||||
|           || position_min < (X_MIN_POS) | ||||
|         #endif | ||||
|         #ifdef X_MAX_POS | ||||
|           || position_max > (X_MAX_POS) | ||||
|         #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; | ||||
|       echo_min_max('Y', position_min, position_max); | ||||
|       if (false | ||||
|         #ifdef Y_MIN_POS | ||||
|         #if HAS_ENDSTOPS | ||||
|           || position_min < (Y_MIN_POS) | ||||
|         #endif | ||||
|         #ifdef Y_MAX_POS | ||||
|           || position_max > (Y_MAX_POS) | ||||
|         #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; | ||||
|       echo_min_max('Z', position_min, position_max); | ||||
|       if (false | ||||
|         #ifdef Z_MIN_POS | ||||
|         #if HAS_ENDSTOPS | ||||
|           || position_min < (Z_MIN_POS) | ||||
|         #endif | ||||
|         #ifdef Z_MAX_POS | ||||
|           || position_max > (Z_MAX_POS) | ||||
|         #endif | ||||
|       ) { | ||||
|  | ||||
| @ -74,17 +74,6 @@ | ||||
| #define DEBUG_OUT ENABLED(DEBUG_LEVELING_FEATURE) | ||||
| #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.
 | ||||
| bool relative_mode; // = false;
 | ||||
| 
 | ||||
| @ -1122,16 +1111,20 @@ void prepare_line_to_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) | ||||
|     // 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, 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); | ||||
|     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))) { | ||||
|       PGM_P home_first = GET_TEXT(MSG_HOME_FIRST); | ||||
|       char msg[strlen_P(home_first)+1]; | ||||
| @ -1146,12 +1139,12 @@ bool homing_needed_error(uint8_t axis_bits/*=0x07*/) { | ||||
|       return true; | ||||
|     } | ||||
|     return false; | ||||
| } | ||||
|   } | ||||
| 
 | ||||
| /**
 | ||||
|   /**
 | ||||
|    * 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 (axis == Z_AXIS) return MMM_TO_MMS(Z_PROBE_SPEED_SLOW); | ||||
|     #endif | ||||
| @ -1162,9 +1155,9 @@ feedRate_t get_homing_bump_feedrate(const AxisEnum axis) { | ||||
|       SERIAL_ECHO_MSG("Warning: Homing Bump Divisor < 1"); | ||||
|     } | ||||
|     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. | ||||
|      */ | ||||
| @ -1294,12 +1287,12 @@ feedRate_t get_homing_bump_feedrate(const AxisEnum axis) { | ||||
|       #endif | ||||
|     } | ||||
| 
 | ||||
| #endif // SENSORLESS_HOMING
 | ||||
|   #endif // SENSORLESS_HOMING
 | ||||
| 
 | ||||
| /**
 | ||||
|   /**
 | ||||
|    * 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)); | ||||
| 
 | ||||
|     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.
 | ||||
|       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 | ||||
|     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) { | ||||
|   void set_axis_never_homed(const AxisEnum axis) { | ||||
|     if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPAIR(">>> set_axis_never_homed(", axis_codes[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], ")"); | ||||
| 
 | ||||
|     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) | ||||
|      * | ||||
| @ -1546,9 +1465,9 @@ void set_axis_never_homed(const AxisEnum axis) { | ||||
|         do_homing_move(axis, mmDelta, get_homing_bump_feedrate(axis)); | ||||
|       } | ||||
|     } | ||||
| #endif | ||||
|   #endif | ||||
| 
 | ||||
| /**
 | ||||
|   /**
 | ||||
|    * Home an individual "raw axis" to its endstop. | ||||
|    * This applies to XYZ on Cartesian and Core robots, and | ||||
|    * 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. | ||||
|    */ | ||||
| 
 | ||||
| void homeaxis(const AxisEnum axis) { | ||||
|   void homeaxis(const AxisEnum axis) { | ||||
| 
 | ||||
|     #if IS_SCARA | ||||
|       // 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], ")"); | ||||
| 
 | ||||
| } // 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 | ||||
|   void update_workspace_offset(const AxisEnum axis) { | ||||
| @ -1893,4 +1890,4 @@ void homeaxis(const AxisEnum axis) { | ||||
|     home_offset[axis] = v; | ||||
|     update_workspace_offset(axis); | ||||
|   } | ||||
| #endif // HAS_M206_COMMAND
 | ||||
| #endif | ||||
|  | ||||
| @ -284,13 +284,43 @@ void do_z_clearance(const float &zclear, const bool z_trusted=true, const bool r | ||||
|  * Homing and Trusted Axes | ||||
|  */ | ||||
| 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_never_homed(const AxisEnum axis); | ||||
| uint8_t axes_should_home(uint8_t axis_bits=0x07); | ||||
| bool homing_needed_error(uint8_t axis_bits=0x07); | ||||
| 
 | ||||
| #if HAS_ENDSTOPS | ||||
|   /**
 | ||||
|    * 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_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 homing_needed()                           { return !all_axes_homed(); } | ||||
| 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) | ||||
|   #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 | ||||
|  */ | ||||
| 
 | ||||
| #if IS_KINEMATIC // (DELTA or SCARA)
 | ||||
| 
 | ||||
|   #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.
 | ||||
|   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 (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 | ||||
|         return WITHIN(rx, X1_MIN_POS - fslop, X1_MAX_POS + fslop); | ||||
|         return COORDINATE_OKAY(rx, X1_MIN_POS - fslop, X1_MAX_POS + fslop); | ||||
|     #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 | ||||
|   } | ||||
|   inline bool position_is_reachable(const xy_pos_t &pos) { return position_is_reachable(pos.x, pos.y); } | ||||
|  | ||||
| @ -564,10 +564,10 @@ class Planner { | ||||
|     #if ENABLED(SKEW_CORRECTION) | ||||
| 
 | ||||
|       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)), | ||||
|                       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; | ||||
|           } | ||||
|         } | ||||
| @ -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 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, | ||||
|                       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; | ||||
|           } | ||||
|         } | ||||
|  | ||||
| @ -92,8 +92,8 @@ public: | ||||
|        */ | ||||
|       static bool can_reach(const float &rx, const float &ry) { | ||||
|         return position_is_reachable(rx - offset_xy.x, ry - offset_xy.y) | ||||
|             && WITHIN(rx, min_x() - fslop, max_x() + fslop) | ||||
|             && WITHIN(ry, min_y() - fslop, max_y() + fslop); | ||||
|             && COORDINATE_OKAY(rx, min_x() - fslop, max_x() + fslop) | ||||
|             && COORDINATE_OKAY(ry, min_y() - fslop, max_y() + fslop); | ||||
|       } | ||||
| 
 | ||||
|     #endif | ||||
| @ -206,8 +206,8 @@ public: | ||||
|         #if IS_KINEMATIC | ||||
|           return HYPOT2(x, y) <= sq(probe_radius(default_probe_xy_offset)); | ||||
|         #else | ||||
|           return WITHIN(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); | ||||
|           return COORDINATE_OKAY(x, _min_x(default_probe_xy_offset) - fslop, _max_x(default_probe_xy_offset) + fslop) | ||||
|               && COORDINATE_OKAY(y, _min_y(default_probe_xy_offset) - fslop, _max_y(default_probe_xy_offset) + fslop); | ||||
|         #endif | ||||
|       } | ||||
| 
 | ||||
|  | ||||
| @ -10,6 +10,14 @@ restore_configs | ||||
| opt_set MOTHERBOARD BOARD_TEENSY31_32 | ||||
| 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 | ||||
| # | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user