@ -39,7 +39,6 @@
enum MeshPointType { INVALID , REAL , SET_IN_BITMAP } ;
bool axis_unhomed_error ( bool , bool , bool ) ;
void dump ( char * const str , const float & f ) ;
bool ubl_lcd_clicked ( ) ;
void probe_entire_mesh ( const float & , const float & , const bool , const bool , const bool ) ;
@ -78,275 +77,273 @@
enum MBLStatus { MBL_STATUS_NONE = 0 , MBL_STATUS_HAS_MESH_BIT = 0 , MBL_STATUS_ACTIVE_BIT = 1 } ;
# define MESH_X_DIST ( ( float(UBL_MESH_MAX_X) - float (UBL_MESH_MIN_X)) / ( float(UBL_MESH_NUM_X_POINTS) - 1.0 ))
# define MESH_Y_DIST ( ( float(UBL_MESH_MAX_Y) - float (UBL_MESH_MIN_Y)) / ( float(UBL_MESH_NUM_Y_POINTS) - 1.0 ))
# define MESH_X_DIST ( float(UBL_MESH_MAX_X - (UBL_MESH_MIN_X)) / float(UBL_MESH_NUM_X_POINTS - 1))
# define MESH_Y_DIST ( float(UBL_MESH_MAX_Y - (UBL_MESH_MIN_Y)) / float(UBL_MESH_NUM_Y_POINTS - 1))
extern float mesh_index_to_x_location [ UBL_MESH_NUM_X_POINTS + 1 ] ; // +1 just because of paranoia that we might end up on the
extern float mesh_index_to_y_location [ UBL_MESH_NUM_Y_POINTS + 1 ] ; // the last Mesh Line and that is the start of a whole new cell
typedef struct {
bool active = false ;
float z_offset = 0.0 ;
int8_t eeprom_storage_slot = - 1 ,
n_x = UBL_MESH_NUM_X_POINTS ,
n_y = UBL_MESH_NUM_Y_POINTS ;
float mesh_x_min = UBL_MESH_MIN_X ,
mesh_y_min = UBL_MESH_MIN_Y ,
mesh_x_max = UBL_MESH_MAX_X ,
mesh_y_max = UBL_MESH_MAX_Y ,
mesh_x_dist = MESH_X_DIST ,
mesh_y_dist = MESH_Y_DIST ;
# if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
float g29_correction_fade_height = 10.0 ,
g29_fade_height_multiplier = 1.0 / 10.0 ; // It's cheaper to do a floating point multiply than divide,
// so keep this value and its reciprocal.
# else
const float g29_correction_fade_height = 10.0 ,
g29_fade_height_multiplier = 1.0 / 10.0 ;
# endif
// If you change this struct, adjust TOTAL_STRUCT_SIZE
# define TOTAL_STRUCT_SIZE 40 // Total size of the above fields
// padding provides space to add state variables without
// changing the location of data structures in the EEPROM.
// This is for compatibility with future versions to keep
// users from having to regenerate their mesh data.
unsigned char padding [ 64 - TOTAL_STRUCT_SIZE ] ;
} ubl_state ;
class unified_bed_leveling {
private :
float last_specified_z ,
fade_scaling_factor_for_current_height ;
static float last_specified_z ,
fade_scaling_factor_for_current_height ;
public :
float z_values [ UBL_MESH_NUM_X_POINTS ] [ UBL_MESH_NUM_Y_POINTS ] ;
static ubl_state state , pre_initialized ;
bool g26_debug_flag = false ,
has_control_of_lcd_panel = false ;
static float z_values [ UBL_MESH_NUM_X_POINTS ] [ UBL_MESH_NUM_Y_POINTS ] ,
mesh_index_to_xpos [ UBL_MESH_NUM_X_POINTS + 1 ] , // +1 safety margin for now, until determinism prevails
mesh_index_to_ypos [ UBL_MESH_NUM_Y_POINTS + 1 ] ;
int8_t eeprom_start = - 1 ;
static bool g26_debug_flag ,
has_control_of_lcd_panel ;
volatile int encoder_diff ; // Volatile because it's changed at interrupt time.
static int8_t eeprom_start ;
struct ubl_state {
bool active = false ;
float z_offset = 0.0 ;
int8_t eeprom_storage_slot = - 1 ,
n_x = UBL_MESH_NUM_X_POINTS ,
n_y = UBL_MESH_NUM_Y_POINTS ;
static volatile int encoder_diff ; // Volatile because it's changed at interrupt time.
float mesh_x_min = UBL_MESH_MIN_X ,
mesh_y_min = UBL_MESH_MIN_Y ,
mesh_x_max = UBL_MESH_MAX_X ,
mesh_y_max = UBL_MESH_MAX_Y ,
mesh_x_dist = MESH_X_DIST ,
mesh_y_dist = MESH_Y_DIST ;
unified_bed_leveling ( ) ;
# if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
float g29_correction_fade_height = 10.0 ,
g29_fade_height_multiplier = 1.0 / 10.0 ; // It's cheaper to do a floating point multiply than divide,
// so keep this value and its reciprocal.
# else
const float g29_correction_fade_height = 10.0 ,
g29_fade_height_multiplier = 1.0 / 10.0 ;
# endif
static void display_map ( const int ) ;
// If you change this struct, adjust TOTAL_STRUCT_SIZE
# define TOTAL_STRUCT_SIZE 43 // Total size of the above fields
// padding provides space to add state variables without
// changing the location of data structures in the EEPROM.
// This is for compatibility with future versions to keep
// users from having to regenerate their mesh data.
unsigned char padding [ 64 - TOTAL_STRUCT_SIZE ] ;
} state , pre_initialized ;
unified_bed_leveling ( ) ;
void display_map ( const int ) ;
void reset ( ) ;
void invalidate ( ) ;
void store_state ( ) ;
void load_state ( ) ;
void store_mesh ( const int16_t ) ;
void load_mesh ( const int16_t ) ;
bool sanity_check ( ) ;
FORCE_INLINE static float map_x_index_to_bed_location ( const int8_t i ) { return ( ( float ) UBL_MESH_MIN_X ) + ( ( ( float ) MESH_X_DIST ) * ( float ) i ) ; } ;
FORCE_INLINE static float map_y_index_to_bed_location ( const int8_t i ) { return ( ( float ) UBL_MESH_MIN_Y ) + ( ( ( float ) MESH_Y_DIST ) * ( float ) i ) ; } ;
FORCE_INLINE void set_z ( const int8_t px , const int8_t py , const float & z ) { z_values [ px ] [ py ] = z ; }
static int8_t get_cell_index_x ( const float & x ) {
const int8_t cx = ( x - ( UBL_MESH_MIN_X ) ) * ( 1.0 / ( MESH_X_DIST ) ) ;
return constrain ( cx , 0 , ( UBL_MESH_NUM_X_POINTS ) - 1 ) ; // -1 is appropriate if we want all movement to the X_MAX
} // position. But with this defined this way, it is possible
// to extrapolate off of this point even further out. Probably
// that is OK because something else should be keeping that from
// happening and should not be worried about at this level.
static int8_t get_cell_index_y ( const float & y ) {
const int8_t cy = ( y - ( UBL_MESH_MIN_Y ) ) * ( 1.0 / ( MESH_Y_DIST ) ) ;
return constrain ( cy , 0 , ( UBL_MESH_NUM_Y_POINTS ) - 1 ) ; // -1 is appropriate if we want all movement to the Y_MAX
} // position. But with this defined this way, it is possible
// to extrapolate off of this point even further out. Probably
// that is OK because something else should be keeping that from
// happening and should not be worried about at this level.
static int8_t find_closest_x_index ( const float & x ) {
const int8_t px = ( x - ( UBL_MESH_MIN_X ) + ( MESH_X_DIST ) * 0.5 ) * ( 1.0 / ( MESH_X_DIST ) ) ;
return ( px > = 0 & & px < ( UBL_MESH_NUM_X_POINTS ) ) ? px : - 1 ;
}
static int8_t find_closest_y_index ( const float & y ) {
const int8_t py = ( y - ( UBL_MESH_MIN_Y ) + ( MESH_Y_DIST ) * 0.5 ) * ( 1.0 / ( MESH_Y_DIST ) ) ;
return ( py > = 0 & & py < ( UBL_MESH_NUM_Y_POINTS ) ) ? py : - 1 ;
}
/**
* z2 - - |
* z0 | |
* | | + ( z2 - z1 )
* z1 | | |
* - - - + - - - - - - - - - - - - - + - - - - - - - - + - - - - |
* a1 a0 a2
* | < - - - delta_a - - - - - - - - - - > |
*
* calc_z0 is the basis for all the Mesh Based correction . It is used to
* find the expected Z Height at a position between two known Z - Height locations .
*
* It is fairly expensive with its 4 floating point additions and 2 floating point
* multiplications .
*/
static FORCE_INLINE float calc_z0 ( const float & a0 , const float & a1 , const float & z1 , const float & a2 , const float & z2 ) {
const float delta_z = ( z2 - z1 ) ,
delta_a = ( a0 - a1 ) / ( a2 - a1 ) ;
return z1 + delta_a * delta_z ;
}
/**
* get_z_correction_at_Y_intercept ( float x0 , int x1_i , int yi ) only takes
* three parameters . It assumes the x0 point is on a Mesh line denoted by yi . In theory
* we could use get_cell_index_x ( float x ) to obtain the 2 nd parameter x1_i but any code calling
* the get_z_correction_along_vertical_mesh_line_at_specific_X routine will already have
* the X index of the x0 intersection available and we don ' t want to perform any extra floating
* point operations .
*/
inline float get_z_correction_along_horizontal_mesh_line_at_specific_X ( const float & x0 , const int x1_i , const int yi ) {
if ( x1_i < 0 | | yi < 0 | | x1_i > = UBL_MESH_NUM_X_POINTS | | yi > = UBL_MESH_NUM_Y_POINTS ) {
SERIAL_ECHOPAIR ( " ? in get_z_correction_along_horizontal_mesh_line_at_specific_X(x0= " , x0 ) ;
SERIAL_ECHOPAIR ( " ,x1_i= " , x1_i ) ;
SERIAL_ECHOPAIR ( " ,yi= " , yi ) ;
SERIAL_CHAR ( ' ) ' ) ;
SERIAL_EOL ;
return NAN ;
static void reset ( ) ;
static void invalidate ( ) ;
static void store_state ( ) ;
static void load_state ( ) ;
static void store_mesh ( const int16_t ) ;
static void load_mesh ( const int16_t ) ;
static bool sanity_check ( ) ;
static FORCE_INLINE void set_z ( const int8_t px , const int8_t py , const float & z ) { z_values [ px ] [ py ] = z ; }
static int8_t get_cell_index_x ( const float & x ) {
const int8_t cx = ( x - ( UBL_MESH_MIN_X ) ) * ( 1.0 / ( MESH_X_DIST ) ) ;
return constrain ( cx , 0 , ( UBL_MESH_NUM_X_POINTS ) - 1 ) ; // -1 is appropriate if we want all movement to the X_MAX
} // position. But with this defined this way, it is possible
// to extrapolate off of this point even further out. Probably
// that is OK because something else should be keeping that from
// happening and should not be worried about at this level.
static int8_t get_cell_index_y ( const float & y ) {
const int8_t cy = ( y - ( UBL_MESH_MIN_Y ) ) * ( 1.0 / ( MESH_Y_DIST ) ) ;
return constrain ( cy , 0 , ( UBL_MESH_NUM_Y_POINTS ) - 1 ) ; // -1 is appropriate if we want all movement to the Y_MAX
} // position. But with this defined this way, it is possible
// to extrapolate off of this point even further out. Probably
// that is OK because something else should be keeping that from
// happening and should not be worried about at this level.
static int8_t find_closest_x_index ( const float & x ) {
const int8_t px = ( x - ( UBL_MESH_MIN_X ) + ( MESH_X_DIST ) * 0.5 ) * ( 1.0 / ( MESH_X_DIST ) ) ;
return ( px > = 0 & & px < ( UBL_MESH_NUM_X_POINTS ) ) ? px : - 1 ;
}
const float xratio = ( RAW_X_POSITION ( x0 ) - mesh_index_to_x_location [ x1_i ] ) * ( 1.0 / ( MESH_X_DIST ) ) ,
z1 = z_values [ x1_i ] [ yi ] ,
z2 = z_values [ x1_i + 1 ] [ yi ] ,
dz = ( z2 - z1 ) ;
return z1 + xratio * dz ;
}
//
// See comments above for get_z_correction_along_horizontal_mesh_line_at_specific_X
//
inline float get_z_correction_along_vertical_mesh_line_at_specific_Y ( const float & y0 , const int xi , const int y1_i ) {
if ( xi < 0 | | y1_i < 0 | | xi > = UBL_MESH_NUM_X_POINTS | | y1_i > = UBL_MESH_NUM_Y_POINTS ) {
SERIAL_ECHOPAIR ( " ? in get_z_correction_along_vertical_mesh_line_at_specific_X(y0= " , y0 ) ;
SERIAL_ECHOPAIR ( " , x1_i= " , xi ) ;
SERIAL_ECHOPAIR ( " , yi= " , y1_i ) ;
SERIAL_CHAR ( ' ) ' ) ;
SERIAL_EOL ;
return NAN ;
static int8_t find_closest_y_index ( const float & y ) {
const int8_t py = ( y - ( UBL_MESH_MIN_Y ) + ( MESH_Y_DIST ) * 0.5 ) * ( 1.0 / ( MESH_Y_DIST ) ) ;
return ( py > = 0 & & py < ( UBL_MESH_NUM_Y_POINTS ) ) ? py : - 1 ;
}
const float yratio = ( RAW_Y_POSITION ( y0 ) - mesh_index_to_y_location [ y1_i ] ) * ( 1.0 / ( MESH_Y_DIST ) ) ,
z1 = z_values [ xi ] [ y1_i ] ,
z2 = z_values [ xi ] [ y1_i + 1 ] ,
dz = ( z2 - z1 ) ;
return z1 + yratio * dz ;
}
/**
* This is the generic Z - Correction . It works anywhere within a Mesh Cell . It first
* does a linear interpolation along both of the bounding X - Mesh - Lines to find the
* Z - Height at both ends . Then it does a linear interpolation of these heights based
* on the Y position within the cell .
*/
float get_z_correction ( const float & x0 , const float & y0 ) const {
const int8_t cx = get_cell_index_x ( RAW_X_POSITION ( x0 ) ) ,
cy = get_cell_index_y ( RAW_Y_POSITION ( y0 ) ) ;
if ( cx < 0 | | cy < 0 | | cx > = UBL_MESH_NUM_X_POINTS | | cy > = UBL_MESH_NUM_Y_POINTS ) {
SERIAL_ECHOPAIR ( " ? in get_z_correction(x0= " , x0 ) ;
SERIAL_ECHOPAIR ( " , y0= " , y0 ) ;
SERIAL_CHAR ( ' ) ' ) ;
SERIAL_EOL ;
# if ENABLED(ULTRA_LCD)
strcpy ( lcd_status_message , " get_z_correction() indexes out of range. " ) ;
lcd_quick_feedback ( ) ;
# endif
return 0.0 ; // this used to return state.z_offset
/**
* z2 - - |
* z0 | |
* | | + ( z2 - z1 )
* z1 | | |
* - - - + - - - - - - - - - - - - - + - - - - - - - - + - - - - |
* a1 a0 a2
* | < - - - delta_a - - - - - - - - - - > |
*
* calc_z0 is the basis for all the Mesh Based correction . It is used to
* find the expected Z Height at a position between two known Z - Height locations .
*
* It is fairly expensive with its 4 floating point additions and 2 floating point
* multiplications .
*/
static FORCE_INLINE float calc_z0 ( const float & a0 , const float & a1 , const float & z1 , const float & a2 , const float & z2 ) {
const float delta_z = ( z2 - z1 ) ,
delta_a = ( a0 - a1 ) / ( a2 - a1 ) ;
return z1 + delta_a * delta_z ;
}
const float z1 = calc_z0 ( RAW_X_POSITION ( x0 ) ,
map_x_index_to_bed_location ( cx ) , z_values [ cx ] [ cy ] ,
map_x_index_to_bed_location ( cx + 1 ) , z_values [ cx + 1 ] [ cy ] ) ,
z2 = calc_z0 ( RAW_X_POSITION ( x0 ) ,
map_x_index_to_bed_location ( cx ) , z_values [ cx ] [ cy + 1 ] ,
map_x_index_to_bed_location ( cx + 1 ) , z_values [ cx + 1 ] [ cy + 1 ] ) ;
float z0 = calc_z0 ( RAW_Y_POSITION ( y0 ) ,
map_y_index_to_bed_location ( cy ) , z1 ,
map_y_index_to_bed_location ( cy + 1 ) , z2 ) ;
# if ENABLED(DEBUG_LEVELING_FEATURE)
if ( DEBUGGING ( MESH_ADJUST ) ) {
SERIAL_ECHOPAIR ( " raw get_z_correction( " , x0 ) ;
SERIAL_CHAR ( ' , ' )
SERIAL_ECHO ( y0 ) ;
SERIAL_ECHOPGM ( " ) = " ) ;
SERIAL_ECHO_F ( z0 , 6 ) ;
/**
* get_z_correction_at_Y_intercept ( float x0 , int x1_i , int yi ) only takes
* three parameters . It assumes the x0 point is on a Mesh line denoted by yi . In theory
* we could use get_cell_index_x ( float x ) to obtain the 2 nd parameter x1_i but any code calling
* the get_z_correction_along_vertical_mesh_line_at_specific_X routine will already have
* the X index of the x0 intersection available and we don ' t want to perform any extra floating
* point operations .
*/
static inline float get_z_correction_along_horizontal_mesh_line_at_specific_X ( const float & x0 , const int x1_i , const int yi ) {
if ( x1_i < 0 | | yi < 0 | | x1_i > = UBL_MESH_NUM_X_POINTS | | yi > = UBL_MESH_NUM_Y_POINTS ) {
SERIAL_ECHOPAIR ( " ? in get_z_correction_along_horizontal_mesh_line_at_specific_X(x0= " , x0 ) ;
SERIAL_ECHOPAIR ( " ,x1_i= " , x1_i ) ;
SERIAL_ECHOPAIR ( " ,yi= " , yi ) ;
SERIAL_CHAR ( ' ) ' ) ;
SERIAL_EOL ;
return NAN ;
}
# endif
# if ENABLED(DEBUG_LEVELING_FEATURE)
if ( DEBUGGING ( MESH_ADJUST ) ) {
SERIAL_ECHOPGM ( " >>>---> " ) ;
SERIAL_ECHO_F ( z0 , 6 ) ;
const float xratio = ( RAW_X_POSITION ( x0 ) - mesh_index_to_xpos [ x1_i ] ) * ( 1.0 / ( MESH_X_DIST ) ) ,
z1 = z_values [ x1_i ] [ yi ] ,
z2 = z_values [ x1_i + 1 ] [ yi ] ,
dz = ( z2 - z1 ) ;
return z1 + xratio * dz ;
}
//
// See comments above for get_z_correction_along_horizontal_mesh_line_at_specific_X
//
static inline float get_z_correction_along_vertical_mesh_line_at_specific_Y ( const float & y0 , const int xi , const int y1_i ) {
if ( xi < 0 | | y1_i < 0 | | xi > = UBL_MESH_NUM_X_POINTS | | y1_i > = UBL_MESH_NUM_Y_POINTS ) {
SERIAL_ECHOPAIR ( " ? in get_z_correction_along_vertical_mesh_line_at_specific_X(y0= " , y0 ) ;
SERIAL_ECHOPAIR ( " , x1_i= " , xi ) ;
SERIAL_ECHOPAIR ( " , yi= " , y1_i ) ;
SERIAL_CHAR ( ' ) ' ) ;
SERIAL_EOL ;
return NAN ;
}
# endif
if ( isnan ( z0 ) ) { // if part of the Mesh is undefined, it will show up as NAN
z0 = 0.0 ; // in ubl.z_values[][] and propagate through the
// calculations. If our correction is NAN, we throw it out
// because part of the Mesh is undefined and we don't have the
// information we need to complete the height correction.
const float yratio = ( RAW_Y_POSITION ( y0 ) - mesh_index_to_ypos [ y1_i ] ) * ( 1.0 / ( MESH_Y_DIST ) ) ,
z1 = z_values [ xi ] [ y1_i ] ,
z2 = z_values [ xi ] [ y1_i + 1 ] ,
dz = ( z2 - z1 ) ;
return z1 + yratio * dz ;
}
/**
* This is the generic Z - Correction . It works anywhere within a Mesh Cell . It first
* does a linear interpolation along both of the bounding X - Mesh - Lines to find the
* Z - Height at both ends . Then it does a linear interpolation of these heights based
* on the Y position within the cell .
*/
static float get_z_correction ( const float & x0 , const float & y0 ) {
const int8_t cx = get_cell_index_x ( RAW_X_POSITION ( x0 ) ) ,
cy = get_cell_index_y ( RAW_Y_POSITION ( y0 ) ) ;
if ( cx < 0 | | cy < 0 | | cx > = UBL_MESH_NUM_X_POINTS | | cy > = UBL_MESH_NUM_Y_POINTS ) {
SERIAL_ECHOPAIR ( " ? in get_z_correction(x0= " , x0 ) ;
SERIAL_ECHOPAIR ( " , y0= " , y0 ) ;
SERIAL_CHAR ( ' ) ' ) ;
SERIAL_EOL ;
# if ENABLED(ULTRA_LCD)
strcpy ( lcd_status_message , " get_z_correction() indexes out of range. " ) ;
lcd_quick_feedback ( ) ;
# endif
return 0.0 ; // this used to return state.z_offset
}
const float z1 = calc_z0 ( RAW_X_POSITION ( x0 ) ,
mesh_index_to_xpos [ cx ] , z_values [ cx ] [ cy ] ,
mesh_index_to_xpos [ cx + 1 ] , z_values [ cx + 1 ] [ cy ] ) ,
z2 = calc_z0 ( RAW_X_POSITION ( x0 ) ,
mesh_index_to_xpos [ cx ] , z_values [ cx ] [ cy + 1 ] ,
mesh_index_to_xpos [ cx + 1 ] , z_values [ cx + 1 ] [ cy + 1 ] ) ;
float z0 = calc_z0 ( RAW_Y_POSITION ( y0 ) ,
mesh_index_to_ypos [ cy ] , z1 ,
mesh_index_to_ypos [ cy + 1 ] , z2 ) ;
# if ENABLED(DEBUG_LEVELING_FEATURE)
if ( DEBUGGING ( MESH_ADJUST ) ) {
SERIAL_ECHOPAIR ( " ??? Yikes! NAN in get_z_correction( " , x0 ) ;
SERIAL_CHAR ( ' , ' ) ;
SERIAL_ECHOPAIR ( " raw get_z_correction(" , x0 ) ;
SERIAL_CHAR ( ' , ' )
SERIAL_ECHO ( y0 ) ;
SERIAL_CHAR ( ' ) ' ) ;
SERIAL_ECHOPGM ( " ) = " ) ;
SERIAL_ECHO_F ( z0 , 6 ) ;
}
# endif
# if ENABLED(DEBUG_LEVELING_FEATURE)
if ( DEBUGGING ( MESH_ADJUST ) ) {
SERIAL_ECHOPGM ( " >>>---> " ) ;
SERIAL_ECHO_F ( z0 , 6 ) ;
SERIAL_EOL ;
}
# endif
}
return z0 ; // there used to be a +state.z_offset on this line
}
/**
* This routine is used to scale the Z correction depending upon the current nozzle height . It is
* optimized for speed . It avoids floating point operations by checking if the requested scaling
* factor is going to be the same as the last time the function calculated a value . If so , it just
* returns it .
*
* It returns a scaling factor of 1.0 if UBL is inactive .
* It returns a scaling factor of 0.0 if Z is past the specified ' Fade Height '
*/
# if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
FORCE_INLINE float fade_scaling_factor_for_z ( const float & lz ) {
const float rz = RAW_Z_POSITION ( lz ) ;
if ( last_specified_z ! = rz ) {
last_specified_z = rz ;
fade_scaling_factor_for_current_height =
state . active & & rz < state . g29_correction_fade_height
? 1.0 - ( rz * state . g29_fade_height_multiplier )
: 0.0 ;
if ( isnan ( z0 ) ) { // if part of the Mesh is undefined, it will show up as NAN
z0 = 0.0 ; // in ubl.z_values[][] and propagate through the
// calculations. If our correction is NAN, we throw it out
// because part of the Mesh is undefined and we don't have the
// information we need to complete the height correction.
# if ENABLED(DEBUG_LEVELING_FEATURE)
if ( DEBUGGING ( MESH_ADJUST ) ) {
SERIAL_ECHOPAIR ( " ??? Yikes! NAN in get_z_correction( " , x0 ) ;
SERIAL_CHAR ( ' , ' ) ;
SERIAL_ECHO ( y0 ) ;
SERIAL_CHAR ( ' ) ' ) ;
SERIAL_EOL ;
}
# endif
}
return fade_scaling_factor_for_current_height ;
return z0; // there used to be a +state.z_offset on this line
}
# else
/**
* This routine is used to scale the Z correction depending upon the current nozzle height . It is
* optimized for speed . It avoids floating point operations by checking if the requested scaling
* factor is going to be the same as the last time the function calculated a value . If so , it just
* returns it .
*
* It returns a scaling factor of 1.0 if UBL is inactive .
* It returns a scaling factor of 0.0 if Z is past the specified ' Fade Height '
*/
# if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
FORCE_INLINE float fade_scaling_factor_for_z ( const float & lz ) {
const float rz = RAW_Z_POSITION ( lz ) ;
if ( last_specified_z ! = rz ) {
last_specified_z = rz ;
fade_scaling_factor_for_current_height =
state . active & & rz < state . g29_correction_fade_height
? 1.0 - ( rz * state . g29_fade_height_multiplier )
: 0.0 ;
}
return fade_scaling_factor_for_current_height ;
}
static constexpr float fade_scaling_factor_for_z ( const float & lz ) { UNUSED ( lz ) ; return 1.0 ; }
# else
# endif
static constexpr float fade_scaling_factor_for_z ( const float & lz ) { UNUSED ( lz ) ; return 1.0 ; }
# endif
} ; // class unified_bed_leveling
@ -355,5 +352,4 @@
# define UBL_LAST_EEPROM_INDEX (E2END - sizeof(unified_bed_leveling::state))
# endif // AUTO_BED_LEVELING_UBL
# endif // UNIFIED_BED_LEVELING_H