@ -158,7 +158,7 @@
* only done between probe points . You will need to press and hold the switch until the
* Phase 1 command can detect it . )
*
* P2 Phase 2 Probe areas of the Mesh that can no t be automatically handled . Phase 2 respects an H
* P2 Phase 2 Probe areas of the Mesh that can ' t be automatically handled . Phase 2 respects an H
* parameter to control the height between Mesh points . The default height for movement
* between Mesh points is 5 mm . A smaller number can be used to make this part of the
* calibration less time consuming . You will be running the nozzle down until it just barely
@ -303,25 +303,17 @@
volatile int8_t ubl_encoderDiff = 0 ; // Volatile because it's changed by Temperature ISR button update
// The simple parameter flags and values are 'static' so parameter parsing can be in a support routine.
static int g29_verbose_level = 0 , phase_value = - 1 , repetition_cnt = 1 ,
storage_slot = 0 , map_type = 0 , test_pattern = 0 , unlevel_value = - 1 ;
static bool repeat_flag = UBL_OK , c_flag = false , x_flag = UBL_OK , y_flag = UBL_OK , statistics_flag = UBL_OK , business_card_mode = false ;
static float x_pos = 0.0 , y_pos = 0.0 , height_value = 5.0 , measured_z , card_thickness = 0.0 , constant = 0.0 ;
static int g29_verbose_level , phase_value = - 1 , repetition_cnt ,
storage_slot = 0 , map_type ; //unlevel_value = -1;
static bool repeat_flag , c_flag , x_flag , y_flag ;
static float x_pos , y_pos , measured_z , card_thickness = 0.0 , ubl_ constant = 0.0 ;
# if ENABLED(ULTRA_LCD)
void lcd_setstatus ( const char * message , bool persist ) ;
# endif
void gcode_G29 ( ) {
float Z1 , Z2 , Z3 ;
g29_verbose_level = 0 ; // These may change, but let's get some reasonable values into them.
repeat_flag = UBL_OK ;
repetition_cnt = 1 ;
c_flag = false ;
SERIAL_PROTOCOLLNPAIR ( " ubl_eeprom_start= " , ubl_eeprom_start ) ;
if ( ubl_eeprom_start < 0 ) {
SERIAL_PROTOCOLLNPGM ( " ?You need to enable your EEPROM and initialize it " ) ;
SERIAL_PROTOCOLLNPGM ( " with M502, M500, M501 in that order. \n " ) ;
@ -350,53 +342,46 @@
if ( code_seen ( ' Q ' ) ) {
if ( code_has_value ( ) ) test_pattern = code_value_int ( ) ;
if ( test_pattern < 0 | | test_pattern > 4 ) {
SERIAL_PROTOCOLLNPGM ( " Invalid test_pattern value. (0-4) \n " ) ;
const int test_pattern = code_has_value ( ) ? code_value_int ( ) : - 1 ;
if ( test_pattern < 0 | | test_pattern > 2 ) {
SERIAL_PROTOCOLLNPGM ( " Invalid test_pattern value. (0-2) \n " ) ;
return ;
}
SERIAL_PROTOCOLLNPGM ( " Loading test_pattern values. \n " ) ;
switch ( test_pattern ) {
case 0 :
for ( uint8_t x = 0 ; x < UBL_MESH_NUM_X_POINTS ; x + + ) { // Create a bowl shape. This is
for ( uint8_t y = 0 ; y < UBL_MESH_NUM_Y_POINTS ; y + + ) { // similar to what a user would see with
Z 1 = 0.5 * ( UBL_MESH_NUM_X_POINTS ) - x ; // a poorly calibrated Delta.
Z 2 = 0.5 * ( UBL_MESH_NUM_Y_POINTS ) - y ;
z_values [ x ] [ y ] + = 2.0 * HYPOT ( Z1 , Z 2) ;
for ( uint8_t x = 0 ; x < UBL_MESH_NUM_X_POINTS ; x + + ) { // Create a bowl shape - similar to
for ( uint8_t y = 0 ; y < UBL_MESH_NUM_Y_POINTS ; y + + ) { // a poorly calibrated Delta.
const float p 1 = 0.5 * ( UBL_MESH_NUM_X_POINTS ) - x ,
p 2 = 0.5 * ( UBL_MESH_NUM_Y_POINTS ) - y ;
z_values [ x ] [ y ] + = 2.0 * HYPOT ( p1 , p 2) ;
}
}
break ;
break ;
case 1 :
for ( uint8_t x = 0 ; x < UBL_MESH_NUM_X_POINTS ; x + + ) { // Create a diagonal line several Mesh
z_values [ x ] [ x ] + = 9.999 ; // cells thick that is raised
if ( x < UBL_MESH_NUM_Y_POINTS - 1 )
z_values [ x ] [ x + 1 ] + = 9.999 ; // We want the altered line several mesh points thick
if ( x > 0 )
z_values [ x ] [ x - 1 ] + = 9.999 ; // We want the altered line several mesh points thick
for ( uint8_t x = 0 ; x < UBL_MESH_NUM_X_POINTS ; x + + ) { // Create a diagonal line several Mesh cells thick that is raised
z_values [ x ] [ x ] + = 9.999 ;
z_values [ x ] [ x + ( x < UBL_MESH_NUM_Y_POINTS - 1 ) ? 1 : - 1 ] + = 9.999 ; // We want the altered line several mesh points thick
}
break ;
case 2 :
// Allow the user to specify the height because 10mm is
// a little bit extreme in some cases.
// Allow the user to specify the height because 10mm is a little extreme in some cases.
for ( uint8_t x = ( UBL_MESH_NUM_X_POINTS ) / 3 ; x < 2 * ( UBL_MESH_NUM_X_POINTS ) / 3 ; x + + ) // Create a rectangular raised area in
for ( uint8_t y = ( UBL_MESH_NUM_Y_POINTS ) / 3 ; y < 2 * ( UBL_MESH_NUM_Y_POINTS ) / 3 ; y + + ) // the center of the bed
z_values [ x ] [ y ] + = code_seen ( ' C ' ) ? constant : 9.99 ;
break ;
case 3 :
z_values [ x ] [ y ] + = code_seen ( ' C ' ) ? ubl_constant : 9.99 ;
break ;
}
}
/*
/*
if ( code_seen ( ' U ' ) ) {
unlevel_value = code_value_int ( ) ;
// if (unlevel_value < 0 || unlevel_value > 7) {
// SERIAL_PROTOCOLLNPGM("Invalid Unlevel value. (0-4)\n");
// return;
// }
//if (unlevel_value < 0 || unlevel_value > 7) {
// SERIAL_PROTOCOLLNPGM("Invalid Unlevel value. (0-4)\n");
// return;
//}
}
*/
//*/
if ( code_seen ( ' P ' ) ) {
phase_value = code_value_int ( ) ;
@ -430,9 +415,9 @@
code_seen ( ' O ' ) | | code_seen ( ' M ' ) , code_seen ( ' E ' ) , code_seen ( ' U ' ) ) ;
break ;
//
// Manually Probe Mesh in areas that can no t be reached by the probe
// Manually Probe Mesh in areas that can' t be reached by the probe
//
case 2 :
case 2 : {
SERIAL_PROTOCOLLNPGM ( " Manually probing unreachable mesh locations. \n " ) ;
do_blocking_move_to_z ( Z_CLEARANCE_BETWEEN_PROBES ) ;
if ( ! x_flag & & ! y_flag ) { // use a good default location for the path
@ -451,32 +436,34 @@
y_pos = current_position [ Y_AXIS ] ;
}
height_value = code_seen ( ' H ' ) & & code_has_value ( ) ? code_value_float ( ) : Z_CLEARANCE_BETWEEN_PROBES ;
const float height = code_seen ( ' H ' ) & & code_has_value ( ) ? code_value_float ( ) : Z_CLEARANCE_BETWEEN_PROBES ;
if ( ( business_card_mode = code_seen ( ' B ' ) ) ) {
card_thickness = code_has_value ( ) ? code_value_float ( ) : measure_business_card_thickness ( height_value ) ;
if ( code_seen ( ' B ' ) ) {
card_thickness = code_has_value ( ) ? code_value_float ( ) : measure_business_card_thickness ( height ) ;
if ( fabs ( card_thickness ) > 1.5 ) {
SERIAL_PROTOCOLLNPGM ( " ?Error in Business Card measurment. \n " ) ;
SERIAL_PROTOCOLLNPGM ( " ?Error in Business Card measure ment. \n " ) ;
return ;
}
}
manually_probe_remaining_mesh ( x_pos , y_pos , height_value , card_thickness , code_seen ( ' O ' ) | | code_seen ( ' M ' ) ) ;
break ;
manually_probe_remaining_mesh ( x_pos , y_pos , height , card_thickness , code_seen ( ' O ' ) | | code_seen ( ' M ' ) ) ;
} break ;
//
// Populate invalid Mesh areas with a constant
//
case 3 :
height_value = 0.0 ; // Assume 0.0 until proven otherwise
if ( code_seen ( ' C ' ) ) height_value = constant ;
case 3 : {
const float height = code_seen ( ' C ' ) ? ubl_constant : 0.0 ;
// If no repetition is specified, do the whole Mesh
if ( ! repeat_flag ) repetition_cnt = 9999 ;
while ( repetition_cnt - - ) {
const mesh_index_pair location = find_closest_mesh_point_of_type ( INVALID , x_pos , y_pos , 0 , NULL , false ) ; // The '0' says we want to use the nozzle's position
if ( location . x_index < 0 ) break ; // No more invalid Mesh Points to populate
z_values [ location . x_index ] [ location . y_index ] = height_value ;
z_values [ location . x_index ] [ location . y_index ] = height ;
}
break ;
} break ;
//
// Fine Tune (Or Edit) the Mesh
//
@ -491,36 +478,56 @@
break ;
case 10 :
// Debug code... Pay no attention to this stuff
// it can be removed soon.
// [DEBUG] Pay no attention to this stuff. It can be removed soon.
SERIAL_ECHO_START ;
SERIAL_ECHOLNPGM ( " Checking G29 has control of LCD Panel: " ) ;
wait_for_user = true ;
KEEPALIVE_STATE ( PAUSED_FOR_USER ) ;
ubl_has_control_of_lcd_panel + + ;
while ( ! ubl_lcd_clicked ( ) ) {
safe_delay ( 250 ) ;
SERIAL_ECHO ( ( int ) ubl_encoderDiff ) ;
ubl_encoderDiff = 0 ;
SERIAL_EOL ;
if ( ubl_encoderDiff ) {
SERIAL_ECHOLN ( ( int ) ubl_encoderDiff ) ;
ubl_encoderDiff = 0 ;
}
}
SERIAL_ECHOLNPGM ( " G29 giving back control of LCD Panel. " ) ;
ubl_has_control_of_lcd_panel = false ;
KEEPALIVE_STATE ( IN_HANDLER ) ;
break ;
case 11 :
// [DEBUG] wait_for_user code. Pay no attention to this stuff. It can be removed soon.
SERIAL_ECHO_START ;
SERIAL_ECHOLNPGM ( " Checking G29 has control of LCD Panel: " ) ;
KEEPALIVE_STATE ( PAUSED_FOR_USER ) ;
wait_for_user = true ;
while ( wait_for_user ) {
safe_delay ( 250 ) ;
if ( ubl_encoderDiff ) {
SERIAL_ECHOLN ( ( int ) ubl_encoderDiff ) ;
ubl_encoderDiff = 0 ;
}
}
SERIAL_ECHOLNPGM ( " G29 giving back control of LCD Panel. " ) ;
KEEPALIVE_STATE ( IN_HANDLER ) ;
break ;
}
}
if ( code_seen ( ' T ' ) ) {
Z1 = probe_pt ( ubl_3_point_1_X , ubl_3_point_1_Y , false /*Stow Flag*/ , g29_verbose_level ) + zprobe_zoffset ;
Z2 = probe_pt ( ubl_3_point_2_X , ubl_3_point_2_Y , false /*Stow Flag*/ , g29_verbose_level ) + zprobe_zoffset ;
Z3 = probe_pt ( ubl_3_point_3_X , ubl_3_point_3_Y , true /*Stow Flag*/ , g29_verbose_level ) + zprobe_zoffset ;
float z 1 = probe_pt ( ubl_3_point_1_X , ubl_3_point_1_Y , false /*Stow Flag*/ , g29_verbose_level ) + zprobe_zoffset ,
z 2 = probe_pt ( ubl_3_point_2_X , ubl_3_point_2_Y , false /*Stow Flag*/ , g29_verbose_level ) + zprobe_zoffset ,
z 3 = probe_pt ( ubl_3_point_3_X , ubl_3_point_3_Y , true /*Stow Flag*/ , g29_verbose_level ) + zprobe_zoffset ;
// We need to adjust Z1, Z2, Z3 by the Mesh Height at these points. Just because they are non-zero doesn't mean
// We need to adjust z1, z2, z 3 by the Mesh Height at these points. Just because they are non-zero doesn't mean
// the Mesh is tilted! (We need to compensate each probe point by what the Mesh says that location's height is)
Z1 - = ubl . get_z_correction ( ubl_3_point_1_X , ubl_3_point_1_Y ) ;
Z2 - = ubl . get_z_correction ( ubl_3_point_2_X , ubl_3_point_2_Y ) ;
Z3 - = ubl . get_z_correction ( ubl_3_point_3_X , ubl_3_point_3_Y ) ;
z 1 - = ubl . get_z_correction ( ubl_3_point_1_X , ubl_3_point_1_Y ) ;
z 2 - = ubl . get_z_correction ( ubl_3_point_2_X , ubl_3_point_2_Y ) ;
z 3 - = ubl . get_z_correction ( ubl_3_point_3_X , ubl_3_point_3_Y ) ;
do_blocking_move_to_xy ( ( X_MAX_POS - ( X_MIN_POS ) ) / 2.0 , ( Y_MAX_POS - ( Y_MIN_POS ) ) / 2.0 ) ;
tilt_mesh_based_on_3pts ( Z1 , Z2 , Z 3) ;
tilt_mesh_based_on_3pts ( z1 , z2 , z 3) ;
}
//
@ -610,13 +617,16 @@
save_ubl_active_state_and_disable ( ) ;
//measured_z = probe_pt(x_pos + X_PROBE_OFFSET_FROM_EXTRUDER, y_pos + Y_PROBE_OFFSET_FROM_EXTRUDER, ProbeDeployAndStow, g29_verbose_level);
ubl_has_control_of_lcd_panel = true ; // Grab the LCD Hardware
ubl_has_control_of_lcd_panel + + ; // Grab the LCD Hardware
measured_z = 1.5 ;
do_blocking_move_to_z ( measured_z ) ; // Get close to the bed, but leave some space so we don't damage anything
// The user is not going to be locking in a new Z-Offset very often so
// it won't be that painful to spin the Encoder Wheel for 1.5mm
lcd_implementation_clear ( ) ;
lcd_z_offset_edit_setup ( measured_z ) ;
KEEPALIVE_STATE ( PAUSED_FOR_USER ) ;
do {
measured_z = lcd_z_offset_edit ( ) ;
idle ( ) ;
@ -628,6 +638,8 @@
// or here. So, until we are done looking for a long Encoder Wheel Press,
// we need to take control of the panel
KEEPALIVE_STATE ( IN_HANDLER ) ;
lcd_return_to_status ( ) ;
const millis_t nxt = millis ( ) + 1500UL ;
@ -637,7 +649,6 @@
SERIAL_PROTOCOLLNPGM ( " \n Z-Offset Adjustment Stopped. " ) ;
do_blocking_move_to_z ( Z_CLEARANCE_DEPLOY_PROBE ) ;
lcd_setstatus ( " Z-Offset Stopped " , true ) ;
ubl_has_control_of_lcd_panel = false ;
restore_ubl_active_state_and_leave ( ) ;
goto LEAVE ;
}
@ -702,14 +713,14 @@
for ( x = 0 ; x < UBL_MESH_NUM_X_POINTS ; x + + )
for ( y = 0 ; y < UBL_MESH_NUM_Y_POINTS ; y + + )
if ( ! isnan ( z_values [ x ] [ y ] ) )
z_values [ x ] [ y ] - = mean + constant ;
z_values [ x ] [ y ] - = mean + ubl_ constant;
}
void shift_mesh_height ( ) {
for ( uint8_t x = 0 ; x < UBL_MESH_NUM_X_POINTS ; x + + )
for ( uint8_t y = 0 ; y < UBL_MESH_NUM_Y_POINTS ; y + + )
if ( ! isnan ( z_values [ x ] [ y ] ) )
z_values [ x ] [ y ] + = constant ;
z_values [ x ] [ y ] + = ubl_ constant;
}
/**
@ -728,9 +739,7 @@
SERIAL_PROTOCOLLNPGM ( " \n Mesh only partially populated. \n " ) ;
lcd_quick_feedback ( ) ;
STOW_PROBE ( ) ;
while ( ubl_lcd_clicked ( ) ) {
idle ( ) ;
}
while ( ubl_lcd_clicked ( ) ) idle ( ) ;
ubl_has_control_of_lcd_panel = false ;
restore_ubl_active_state_and_leave ( ) ;
safe_delay ( 50 ) ; // Debounce the Encoder wheel
@ -739,14 +748,18 @@
location = find_closest_mesh_point_of_type ( INVALID , lx , ly , 1 , NULL , do_furthest ) ; // the '1' says we want the location to be relative to the probe
if ( location . x_index > = 0 & & location . y_index > = 0 ) {
const float xProbe = ubl . map_x_index_to_bed_location ( location . x_index ) ,
yProbe = ubl . map_y_index_to_bed_location ( location . y_index ) ;
if ( xProbe < MIN_PROBE_X | | xProbe > MAX_PROBE_X | | yProbe < MIN_PROBE_Y | | yProbe > MAX_PROBE_Y ) {
SERIAL_PROTOCOLLNPGM ( " ?Error: Attempt to probe off the bed. " ) ;
const float rawx = ubl . map_x_index_to_bed_location ( location . x_index ) ,
rawy = ubl . map_y_index_to_bed_location ( location . y_index ) ;
// TODO: Change to use `position_is_reachable` (for SCARA-compatibility)
if ( rawx < ( MIN_PROBE_X ) | | rawx > ( MAX_PROBE_X ) | | rawy < ( MIN_PROBE_Y ) | | rawy > ( MAX_PROBE_Y ) ) {
SERIAL_ERROR_START ;
SERIAL_ERRORLNPGM ( " Attempt to probe off the bed. " ) ;
ubl_has_control_of_lcd_panel = false ;
goto LEAVE ;
}
const float measured_z = probe_pt ( xProbe , yProbe , stow_probe , g29_verbose_level ) ;
const float measured_z = probe_pt ( LOGICAL_X_POSITION ( rawx ) , LOGICAL_Y_POSITION ( rawy ) , stow_probe , g29_verbose_level ) ;
z_values [ location . x_index ] [ location . y_index ] = measured_z + zprobe_zoffset ;
}
@ -831,6 +844,7 @@
}
float use_encoder_wheel_to_measure_point ( ) {
KEEPALIVE_STATE ( PAUSED_FOR_USER ) ;
while ( ! ubl_lcd_clicked ( ) ) { // we need the loop to move the nozzle based on the encoder wheel here!
idle ( ) ;
if ( ubl_encoderDiff ) {
@ -838,34 +852,35 @@
ubl_encoderDiff = 0 ;
}
}
KEEPALIVE_STATE ( IN_HANDLER ) ;
return current_position [ Z_AXIS ] ;
}
float measure_business_card_thickness ( const float & height_value ) {
float measure_business_card_thickness ( const float & in_ height) {
ubl_has_control_of_lcd_panel + + ;
save_ubl_active_state_and_disable ( ) ; // we don't do bed level correction because we want the raw data when we probe
SERIAL_PROTOCOLLNPGM ( " Place Shim Under Nozzle and Perform Measurement. " ) ;
do_blocking_move_to_z ( height_value ) ;
do_blocking_move_to_z ( in_ height) ;
do_blocking_move_to_xy ( ( float ( X_MAX_POS ) - float ( X_MIN_POS ) ) / 2.0 , ( float ( Y_MAX_POS ) - float ( Y_MIN_POS ) ) / 2.0 ) ;
//, min( planner.max_feedrate_mm_s[X_AXIS], planner.max_feedrate_mm_s[Y_AXIS])/2.0);
const float Z 1 = use_encoder_wheel_to_measure_point ( ) ;
const float z 1 = use_encoder_wheel_to_measure_point ( ) ;
do_blocking_move_to_z ( current_position [ Z_AXIS ] + SIZE_OF_LITTLE_RAISE ) ;
ubl_has_control_of_lcd_panel = false ;
SERIAL_PROTOCOLLNPGM ( " Remove Shim and Measure Bed Height. " ) ;
const float Z 2 = use_encoder_wheel_to_measure_point ( ) ;
const float z 2 = use_encoder_wheel_to_measure_point ( ) ;
do_blocking_move_to_z ( current_position [ Z_AXIS ] + SIZE_OF_LITTLE_RAISE ) ;
if ( g29_verbose_level > 1 ) {
SERIAL_PROTOCOLPGM ( " Business Card is: " ) ;
SERIAL_PROTOCOL_F ( abs ( Z1 - Z 2) , 6 ) ;
SERIAL_PROTOCOL_F ( abs ( z1 - z 2) , 6 ) ;
SERIAL_PROTOCOLLNPGM ( " mm thick. " ) ;
}
restore_ubl_active_state_and_leave ( ) ;
return abs ( Z1 - Z 2) ;
return abs ( z1 - z 2) ;
}
void manually_probe_remaining_mesh ( const float & lx , const float & ly , const float & z_clearance , const float & card_thickness , const bool do_ubl_mesh_map ) {
@ -881,21 +896,23 @@
if ( do_ubl_mesh_map ) ubl . display_map ( map_type ) ;
location = find_closest_mesh_point_of_type ( INVALID , lx , ly , 0 , NULL , false ) ; // The '0' says we want to use the nozzle's position
// It doesn't matter if the probe can not reach the
// NAN location. This is a manual probe.
// It doesn't matter if the probe can't reach the NAN location. This is a manual probe.
if ( location . x_index < 0 & & location . y_index < 0 ) continue ;
const float xProbe = ubl . map_x_index_to_bed_location ( location . x_index ) ,
yProbe = ubl . map_y_index_to_bed_location ( location . y_index ) ;
const float rawx = ubl . map_x_index_to_bed_location ( location . x_index ) ,
rawy = ubl . map_y_index_to_bed_location ( location . y_index ) ;
// Modify to use if (position_is_reachable(pos[XYZ]))
if ( xProbe < ( X_MIN_POS ) | | xProbe > ( X_MAX_POS ) | | yProbe < ( Y_MIN_POS ) | | yProbe > ( Y_MAX_POS ) ) {
SERIAL_PROTOCOLLNPGM ( " ?Error: Attempt to probe off the bed. " ) ;
// TODO: Change to use `position_is_reachable` (for SCARA-compatibility)
if ( rawx < ( X_MIN_POS ) | | rawx > ( X_MAX_POS ) | | rawy < ( Y_MIN_POS ) | | rawy > ( Y_MAX_POS ) ) {
SERIAL_ERROR_START ;
SERIAL_ERRORLNPGM ( " Attempt to probe off the bed. " ) ;
ubl_has_control_of_lcd_panel = false ;
goto LEAVE ;
}
const float dx = xProbe - last_x ,
const float xProbe = LOGICAL_X_POSITION ( rawx ) ,
yProbe = LOGICAL_Y_POSITION ( rawy ) ,
dx = xProbe - last_x ,
dy = yProbe - last_y ;
if ( HYPOT ( dx , dy ) < BIG_RAISE_NOT_NEEDED )
@ -908,8 +925,10 @@
last_x = xProbe ;
last_y = yProbe ;
KEEPALIVE_STATE ( PAUSED_FOR_USER ) ;
ubl_has_control_of_lcd_panel = true ;
while ( ! ubl_lcd_clicked ) { // we need the loop to move the nozzle based on the encoder wheel here!
while ( ! ubl_lcd_clicked ( ) ) { // we need the loop to move the nozzle based on the encoder wheel here!
idle ( ) ;
if ( ubl_encoderDiff ) {
do_blocking_move_to_z ( current_position [ Z_AXIS ] + float ( ubl_encoderDiff ) / 100.0 ) ;
@ -926,6 +945,7 @@
lcd_quick_feedback ( ) ;
while ( ubl_lcd_clicked ( ) ) idle ( ) ;
ubl_has_control_of_lcd_panel = false ;
KEEPALIVE_STATE ( IN_HANDLER ) ;
restore_ubl_active_state_and_leave ( ) ;
return ;
}
@ -933,7 +953,7 @@
z_values [ location . x_index ] [ location . y_index ] = current_position [ Z_AXIS ] - card_thickness ;
if ( g29_verbose_level > 2 ) {
SERIAL_PROTOCOL ( " Mesh Point Measured at: " ) ;
SERIAL_PROTOCOLPGM ( " Mesh Point Measured at: " ) ;
SERIAL_PROTOCOL_F ( z_values [ location . x_index ] [ location . y_index ] , 6 ) ;
SERIAL_EOL ;
}
@ -943,52 +963,40 @@
LEAVE :
restore_ubl_active_state_and_leave ( ) ;
KEEPALIVE_STATE ( IN_HANDLER ) ;
do_blocking_move_to_z ( Z_CLEARANCE_DEPLOY_PROBE ) ;
do_blocking_move_to_xy ( lx , ly ) ;
}
bool g29_parameter_parsing ( ) {
# if ENABLED(ULTRA_LCD)
lcd_setstatus ( " Doing G29 UBL ! " , true ) ;
lcd_quick_feedback ( ) ;
# endif
x_pos = current_position [ X_AXIS ] ;
y_pos = current_position [ Y_AXIS ] ;
x_flag = y_flag = repeat_flag = false ;
map_type = 0 ;
constant = 0.0 ;
repetition_cnt = 1 ;
if ( ( x_flag = code_seen ( ' X ' ) ) ) {
x_pos = code_value_float ( ) ;
if ( x_pos < X_MIN_POS | | x_pos > X_MAX_POS ) {
SERIAL_PROTOCOLLNPGM ( " Invalid X location specified. \n " ) ;
return UBL_ERR ;
}
g29_verbose_level = code_seen ( ' V ' ) ? code_value_int ( ) : 0 ;
if ( g29_verbose_level < 0 | | g29_verbose_level > 4 ) {
SERIAL_PROTOCOLLNPGM ( " Invalid Verbose Level specified. (0-4) \n " ) ;
return UBL_ERR ;
}
if ( ( y_flag = code_seen ( ' Y ' ) ) ) {
y_pos = code_value_float ( ) ;
if ( y_pos < Y_MIN_POS | | y_pos > Y_MAX_POS ) {
SERIAL_PROTOCOLLNPGM ( " Invalid Y location specified. \n " ) ;
return UBL_ERR ;
}
x_flag = code_seen ( ' X ' ) & & code_has_value ( ) ;
x_pos = x_flag ? code_value_float ( ) : current_position [ X_AXIS ] ;
if ( x_pos < LOGICAL_X_POSITION ( X_MIN_POS ) | | x_pos > LOGICAL_X_POSITION ( X_MAX_POS ) ) {
SERIAL_PROTOCOLLNPGM ( " Invalid X location specified. \n " ) ;
return UBL_ERR ;
}
if ( x_flag ! = y_flag ) {
SERIAL_PROTOCOLLNPGM ( " Both X & Y locations must be specified. \n " ) ;
y_flag = code_seen ( ' Y ' ) & & code_has_value ( ) ;
y_pos = y_flag ? code_value_float ( ) : current_position [ Y_AXIS ] ;
if ( y_pos < LOGICAL_Y_POSITION ( Y_MIN_POS ) | | y_pos > LOGICAL_Y_POSITION ( Y_MAX_POS ) ) {
SERIAL_PROTOCOLLNPGM ( " Invalid Y location specified. \n " ) ;
return UBL_ERR ;
}
g29_verbose_level = 0 ;
if ( code_seen ( ' V ' ) ) {
g29_verbose_level = code_value_int ( ) ;
if ( g29_verbose_level < 0 | | g29_verbose_level > 4 ) {
SERIAL_PROTOCOLLNPGM ( " Invalid Verbose Level specified. (0-4) \n " ) ;
return UBL_ERR ;
}
if ( x_flag ! = y_flag ) {
SERIAL_PROTOCOLLNPGM ( " Both X & Y locations must be specified. \n " ) ;
return UBL_ERR ;
}
if ( code_seen ( ' A ' ) ) { // Activate the Unified Bed Leveling System
@ -997,8 +1005,8 @@
ubl . store_state ( ) ;
}
if ( ( c_flag = code_seen ( ' C ' ) & & code_has_value ( ) ) )
constant = code_value_float ( ) ;
c_flag = code_seen ( ' C ' ) & & code_has_value ( ) ;
ubl_ constant = c_flag ? c ode_value_float ( ) : 0.0 ;
if ( code_seen ( ' D ' ) ) { // Disable the Unified Bed Leveling System
ubl . state . active = 0 ;
@ -1018,29 +1026,28 @@
}
# endif
if ( ( repeat_flag = code_seen ( ' R ' ) ) ) {
repetition_cnt = code_has_value ( ) ? code_value_int ( ) : 9999 ;
if ( repetition_cnt < 1 ) {
SERIAL_PROTOCOLLNPGM ( " Invalid Repetition count. \n " ) ;
return UBL_ERR ;
}
repeat_flag = code_seen ( ' R ' ) ;
repetition_cnt = repeat_flag ? ( code_has_value ( ) ? code_value_int ( ) : 9999 ) : 1 ;
if ( repetition_cnt < 1 ) {
SERIAL_PROTOCOLLNPGM ( " Invalid Repetition count. \n " ) ;
return UBL_ERR ;
}
if ( code_seen ( ' O ' ) ) { // Check if a map type was specified
map_type = code_value_int ( ) ? code_has_value ( ) : 0 ;
if ( map_type < 0 | | map_type > 1 ) {
SERIAL_PROTOCOLLNPGM ( " Invalid map type. \n " ) ;
return UBL_ERR ;
}
map_type = code_seen ( ' O ' ) & & code_has_value ( ) ? code_value_int ( ) : 0 ;
if ( map_type < 0 | | map_type > 1 ) {
SERIAL_PROTOCOLLNPGM ( " Invalid map type. \n " ) ;
return UBL_ERR ;
}
/*
if ( code_seen ( ' M ' ) ) { // Check if a map type was specified
map_type = code_value_int ( ) ? code_has_ value ( ) : 0 ;
if ( map_type < 0 | | map_type > 1 ) {
map_type = code_has_ value ( ) ? code_value_int ( ) : 0 ;
if ( map_type < 0 | | map_type > 1 ) {
SERIAL_PROTOCOLLNPGM ( " Invalid map type. \n " ) ;
return UBL_ERR ;
}
}
//*/
return UBL_OK ;
}
@ -1054,20 +1061,15 @@
SERIAL_PROTOCOL ( str ) ;
SERIAL_PROTOCOL_F ( f , 8 ) ;
SERIAL_PROTOCOL ( " " ) ;
SERIAL_PROTOCOLPGM ( " " ) ;
ptr = ( char * ) & f ;
for ( uint8_t i = 0 ; i < 4 ; i + + ) {
SERIAL_PROTOCOL ( " " ) ;
prt_hex_byte ( * ptr + + ) ;
}
SERIAL_PROTOCOL ( " isnan()= " ) ;
SERIAL_PROTOCOL ( isnan ( f ) ) ;
SERIAL_PROTOCOL ( " isinf()= " ) ;
SERIAL_PROTOCOL ( isinf ( f ) ) ;
for ( uint8_t i = 0 ; i < 4 ; i + + )
SERIAL_PROTOCOLPAIR ( " " , hex_byte ( * ptr + + ) ) ;
SERIAL_PROTOCOLPAIR ( " isnan()= " , isnan ( f ) ) ;
SERIAL_PROTOCOLPAIR ( " isinf()= " , isinf ( f ) ) ;
constexpr float g = INFINITY ;
if ( f = = - g )
SERIAL_PROTOCOL ( " Minus Infinity detected. " ) ;
if ( f = = - INFINITY )
SERIAL_PROTOCOLPGM ( " Minus Infinity detected. " ) ;
SERIAL_EOL ;
}
@ -1104,7 +1106,6 @@
*/
void g29_what_command ( ) {
const uint16_t k = E2END - ubl_eeprom_start ;
statistics_flag + + ;
SERIAL_PROTOCOLPGM ( " Unified Bed Leveling System Version 1.00 " ) ;
if ( ubl . state . active )
@ -1117,8 +1118,7 @@
if ( ubl . state . eeprom_storage_slot = = - 1 )
SERIAL_PROTOCOLPGM ( " No Mesh Loaded. " ) ;
else {
SERIAL_PROTOCOLPGM ( " Mesh: " ) ;
prt_hex_word ( ubl . state . eeprom_storage_slot ) ;
SERIAL_PROTOCOLPAIR ( " Mesh " , ubl . state . eeprom_storage_slot ) ;
SERIAL_PROTOCOLPGM ( " Loaded. " ) ;
}
SERIAL_EOL ;
@ -1136,7 +1136,7 @@
SERIAL_PROTOCOLPGM ( " X-Axis Mesh Points at: " ) ;
for ( uint8_t i = 0 ; i < UBL_MESH_NUM_X_POINTS ; i + + ) {
SERIAL_PROTOCOL_F ( ubl . map_x_index_to_bed_location ( i ) , 1 ) ;
SERIAL_PROTOCOL_F ( LOGICAL_X_POSITION ( ubl . map_x_index_to_bed_location ( i ) ) , 1 ) ;
SERIAL_PROTOCOLPGM ( " " ) ;
safe_delay ( 50 ) ;
}
@ -1144,7 +1144,7 @@
SERIAL_PROTOCOLPGM ( " Y-Axis Mesh Points at: " ) ;
for ( uint8_t i = 0 ; i < UBL_MESH_NUM_Y_POINTS ; i + + ) {
SERIAL_PROTOCOL_F ( ubl . map_y_index_to_bed_location ( i ) , 1 ) ;
SERIAL_PROTOCOL_F ( LOGICAL_Y_POSITION ( ubl . map_y_index_to_bed_location ( i ) ) , 1 ) ;
SERIAL_PROTOCOLPGM ( " " ) ;
safe_delay ( 50 ) ;
}
@ -1162,13 +1162,9 @@
SERIAL_PROTOCOLLNPAIR ( " ubl_state_recursion_chk : " , ubl_state_recursion_chk ) ;
SERIAL_EOL ;
safe_delay ( 50 ) ;
SERIAL_PROTOCOLPGM ( " Free EEPROM space starts at: 0x " ) ;
prt_hex_word ( ubl_eeprom_start ) ;
SERIAL_EOL ;
SERIAL_PROTOCOLLNPAIR ( " Free EEPROM space starts at: 0x " , hex_word ( ubl_eeprom_start ) ) ;
SERIAL_PROTOCOLPGM ( " end of EEPROM : " ) ;
prt_hex_word ( E2END ) ;
SERIAL_EOL ;
SERIAL_PROTOCOLLNPAIR ( " end of EEPROM : " , hex_word ( E2END ) ) ;
safe_delay ( 50 ) ;
SERIAL_PROTOCOLLNPAIR ( " sizeof(ubl) : " , ( int ) sizeof ( ubl ) ) ;
@ -1177,18 +1173,14 @@
SERIAL_EOL ;
safe_delay ( 50 ) ;
SERIAL_PROTOCOLPGM ( " EEPROM free for UBL: 0x " ) ;
prt_hex_word ( k ) ;
SERIAL_EOL ;
SERIAL_PROTOCOLLNPAIR ( " EEPROM free for UBL: 0x " , hex_word ( k ) ) ;
safe_delay ( 50 ) ;
SERIAL_PROTOCOLPGM ( " EEPROM can hold 0x " ) ;
prt_hex_word ( k / sizeof ( z_values ) ) ;
SERIAL_PROTOCOLPAIR ( " EEPROM can hold " , k / sizeof ( z_values ) ) ;
SERIAL_PROTOCOLLNPGM ( " meshes. \n " ) ;
safe_delay ( 50 ) ;
SERIAL_PROTOCOLPGM ( " sizeof(ubl.state) : " ) ;
prt_hex_word ( sizeof ( ubl . state ) ) ;
SERIAL_PROTOCOLPAIR ( " sizeof(ubl.state) : " , ( int ) sizeof ( ubl . state ) ) ;
SERIAL_PROTOCOLPAIR ( " \n UBL_MESH_NUM_X_POINTS " , UBL_MESH_NUM_X_POINTS ) ;
SERIAL_PROTOCOLPAIR ( " \n UBL_MESH_NUM_Y_POINTS " , UBL_MESH_NUM_Y_POINTS ) ;
@ -1222,12 +1214,12 @@
SERIAL_ECHOLNPGM ( " EEPROM Dump: " ) ;
for ( uint16_t i = 0 ; i < E2END + 1 ; i + = 16 ) {
if ( ! ( i & 0x3 ) ) idle ( ) ;
prt_hex_word ( i ) ;
prin t_hex_word ( i ) ;
SERIAL_ECHOPGM ( " : " ) ;
for ( uint16_t j = 0 ; j < 16 ; j + + ) {
kkkk = i + j ;
eeprom_read_block ( & cccc , ( void * ) kkkk , 1 ) ;
prt_hex_byte ( cccc ) ;
prin t_hex_byte ( cccc ) ;
SERIAL_ECHO ( ' ' ) ;
}
SERIAL_EOL ;
@ -1259,9 +1251,8 @@
eeprom_read_block ( ( void * ) & tmp_z_values , ( void * ) j , sizeof ( tmp_z_values ) ) ;
SERIAL_ECHOPAIR ( " Subtracting Mesh " , storage_slot ) ;
SERIAL_PROTOCOLPGM ( " loaded from EEPROM address " ) ; // Soon, we can remove the extra clutter of printing
prt_hex_word ( j ) ; // the address in the EEPROM where the Mesh is stored.
SERIAL_EOL ;
SERIAL_PROTOCOLLNPAIR ( " loaded from EEPROM address " , hex_word ( j ) ) ; // Soon, we can remove the extra clutter of printing
// the address in the EEPROM where the Mesh is stored.
for ( uint8_t x = 0 ; x < UBL_MESH_NUM_X_POINTS ; x + + )
for ( uint8_t y = 0 ; y < UBL_MESH_NUM_Y_POINTS ; y + + )
@ -1269,7 +1260,6 @@
}
mesh_index_pair find_closest_mesh_point_of_type ( const MeshPointType type , const float & lx , const float & ly , const bool probe_as_reference , unsigned int bits [ 16 ] , bool far_flag ) {
int i , j , k , l ;
float distance , closest = far_flag ? - 99999.99 : 99999.99 ;
mesh_index_pair return_val ;
@ -1282,8 +1272,8 @@
const float px = lx - ( probe_as_reference ? X_PROBE_OFFSET_FROM_EXTRUDER : 0 ) ,
py = ly - ( probe_as_reference ? Y_PROBE_OFFSET_FROM_EXTRUDER : 0 ) ;
for ( i = 0 ; i < UBL_MESH_NUM_X_POINTS ; i + + ) {
for ( j = 0 ; j < UBL_MESH_NUM_Y_POINTS ; j + + ) {
for ( uint8_t i = 0 ; i < UBL_MESH_NUM_X_POINTS ; i + + ) {
for ( uint8_t j = 0 ; j < UBL_MESH_NUM_Y_POINTS ; j + + ) {
if ( ( type = = INVALID & & isnan ( z_values [ i ] [ j ] ) ) // Check to see if this location holds the right thing
| | ( type = = REAL & & ! isnan ( z_values [ i ] [ j ] ) )
@ -1292,42 +1282,45 @@
// We only get here if we found a Mesh Point of the specified type
const float mx = LOGICAL_X_POSITION ( ubl . map_x_index_to_bed_location ( i ) ) , // Check if we can probe this mesh location
my = LOGICAL_Y_POSITION ( ubl . map_y_index_to_bed_location ( j ) ) ;
const float rawx = ubl . map_x_index_to_bed_location ( i ) , // Check if we can probe this mesh location
rawy = ubl . map_y_index_to_bed_location ( j ) ;
// If we are using the probe as the reference there are some locations we can't get to.
// We prune these out of the list and ignore them until the next Phase where we do the
// manual nozzle probing.
// If using the probe as the reference there are some unreachable locations.
// Prune them from the list and ignore them till the next Phase (manual nozzle probing).
if ( probe_as_reference & &
( m x < ( MIN_PROBE_X ) | | m x > ( MAX_PROBE_X ) | | m y < ( MIN_PROBE_Y ) | | m y > ( MAX_PROBE_Y ) )
( raw x < ( MIN_PROBE_X ) | | raw x > ( MAX_PROBE_X ) | | raw y < ( MIN_PROBE_Y ) | | raw y > ( MAX_PROBE_Y ) )
) continue ;
// We can get to it. Let's see if it i s the closest location to the nozzle.
// Unreachable. Check if it' s the closest location to the nozzle.
// Add in a weighting factor that considers the current location of the nozzle.
const float mx = LOGICAL_X_POSITION ( rawx ) , // Check if we can probe this mesh location
my = LOGICAL_Y_POSITION ( rawy ) ;
distance = HYPOT ( px - mx , py - my ) + HYPOT ( current_x - mx , current_y - my ) * 0.1 ;
if ( far_flag ) { // If doing the far_flag action, we want to be as far as possible
for ( k = 0 ; k < UBL_MESH_NUM_X_POINTS ; k + + ) { // from the starting point and from any other probed points. We
for ( l = 0 ; l < UBL_MESH_NUM_Y_POINTS ; l + + ) { // want the next point spread out and filling in any blank spaces
if ( ! isnan ( z_values [ k ] [ l ] ) ) { // in the mesh. So we add in some of the distance to every probed
distance + = ( i - k ) * ( i - k ) * MESH_X_DIST * .05 ; // point we can find.
distance + = ( j - l ) * ( j - l ) * MESH_Y_DIST * .05 ;
}
if ( far_flag ) { // If doing the far_flag action, we want to be as far as possible
for ( uint8_t k = 0 ; k < UBL_MESH_NUM_X_POINTS ; k + + ) { // from the starting point and from any other probed points. We
for ( uint8_t l = 0 ; l < UBL_MESH_NUM_Y_POINTS ; l + + ) { // want the next point spread out and filling in any blank spaces
if ( ! isnan ( z_values [ k ] [ l ] ) ) { // in the mesh. So we add in some of the distance to every probed
distance + = sq ( i - k ) * ( MESH_X_DIST ) * .05 // point we can find.
+ sq ( j - l ) * ( MESH_Y_DIST ) * .05 ;
}
}
}
}
}
}
if ( ( ! far_flag & & ( distance < closest ) ) | | ( far_flag & & ( distance > closest ) ) ) { // if far_flag, look for furthest away point
closest = distance ; // We found a closer location with
if ( far_flag = = ( distance > closest ) & & distance ! = closest ) { // if far_flag, look for farthest point
closest = distance ; // We found a closer/farther location with
return_val . x_index = i ; // the specified type of mesh value.
return_val . y_index = j ;
return_val . distance = closest ;
}
}
}
}
} // for j
} // for i
return return_val ;
}
@ -1356,27 +1349,30 @@
bit_clear ( not_done , location . x_index , location . y_index ) ; // Mark this location as 'adjusted' so we will find a
// different location the next time through the loop
const float xProbe = ubl . map_x_index_to_bed_location ( location . x_index ) ,
yProbe = ubl . map_y_index_to_bed_location ( location . y_index ) ;
if ( xProbe < X_MIN_POS | | xProbe > X_MAX_POS | | yProbe < Y_MIN_POS | | yProbe > Y_MAX_POS ) { // In theory, we don't need this check.
SERIAL_PROTOCOLLNPGM ( " ?Error: Attempt to edit off the bed. " ) ; // This really can't happen, but for now,
ubl_has_control_of_lcd_panel = false ; // Let's do the check.
const float rawx = ubl . map_x_index_to_bed_location ( location . x_index ) ,
rawy = ubl . map_y_index_to_bed_location ( location . y_index ) ;
// TODO: Change to use `position_is_reachable` (for SCARA-compatibility)
if ( rawx < ( X_MIN_POS ) | | rawx > ( X_MAX_POS ) | | rawy < ( Y_MIN_POS ) | | rawy > ( Y_MAX_POS ) ) { // In theory, we don't need this check.
SERIAL_ERROR_START ;
SERIAL_ERRORLNPGM ( " Attempt to edit off the bed. " ) ; // This really can't happen, but do the check for now
ubl_has_control_of_lcd_panel = false ;
goto FINE_TUNE_EXIT ;
}
do_blocking_move_to_z ( Z_CLEARANCE_DEPLOY_PROBE ) ; // Move the nozzle to where we are going to edit
do_blocking_move_to_xy ( xProbe , yProbe ) ;
do_blocking_move_to_xy ( LOGICAL_X_POSITION ( rawx ) , LOGICAL_Y_POSITION ( rawy ) ) ;
float new_z = z_values [ location . x_index ] [ location . y_index ] ;
round_off = ( int32_t ) ( new_z * 1000.0 ) ; // we chop off the last digits just to be clean. We are rounding to the
new_z = float ( round_off ) / 1000.0 ;
KEEPALIVE_STATE ( PAUSED_FOR_USER ) ;
ubl_has_control_of_lcd_panel = true ;
lcd_implementation_clear ( ) ;
lcd_mesh_edit_setup ( new_z ) ;
wait_for_user = true ;
do {
new_z = lcd_mesh_edit ( ) ;
idle ( ) ;
@ -1393,13 +1389,12 @@
idle ( ) ;
if ( ELAPSED ( millis ( ) , nxt ) ) {
lcd_return_to_status ( ) ;
// SERIAL_PROTOCOLLNPGM("\nFine Tuning of Mesh Stopped.");
//SERIAL_PROTOCOLLNPGM("\nFine Tuning of Mesh Stopped.");
do_blocking_move_to_z ( Z_CLEARANCE_DEPLOY_PROBE ) ;
lcd_setstatus ( " Mesh Editing Stopped " , true ) ;
while ( ubl_lcd_clicked ( ) ) idle ( ) ;
ubl_has_control_of_lcd_panel = false ;
goto FINE_TUNE_EXIT ;
}
}
@ -1415,6 +1410,7 @@
FINE_TUNE_EXIT :
ubl_has_control_of_lcd_panel = false ;
KEEPALIVE_STATE ( IN_HANDLER ) ;
if ( do_ubl_mesh_map ) ubl . display_map ( map_type ) ;
restore_ubl_active_state_and_leave ( ) ;