|
@ -3516,22 +3516,16 @@ inline void gcode_G28() { |
|
|
float measured_z, |
|
|
float measured_z, |
|
|
z_before = probePointCounter ? Z_RAISE_BETWEEN_PROBINGS + current_position[Z_AXIS] : Z_RAISE_BEFORE_PROBING + home_offset[Z_AXIS]; |
|
|
z_before = probePointCounter ? Z_RAISE_BETWEEN_PROBINGS + current_position[Z_AXIS] : Z_RAISE_BEFORE_PROBING + home_offset[Z_AXIS]; |
|
|
|
|
|
|
|
|
if (probePointCounter) { |
|
|
#if ENABLED(DEBUG_LEVELING_FEATURE) |
|
|
#if ENABLED(DEBUG_LEVELING_FEATURE) |
|
|
if (DEBUGGING(LEVELING)) { |
|
|
if (DEBUGGING(LEVELING)) { |
|
|
SERIAL_ECHOPGM("z_before = ("); |
|
|
SERIAL_ECHOPAIR("z_before = (between) ", (Z_RAISE_BETWEEN_PROBINGS + current_position[Z_AXIS])); |
|
|
if (probePointCounter) |
|
|
SERIAL_EOL; |
|
|
SERIAL_ECHOPGM("between) "); |
|
|
} |
|
|
else |
|
|
#endif |
|
|
SERIAL_ECHOPGM("before) "); |
|
|
} |
|
|
SERIAL_ECHOLN(z_before); |
|
|
else { |
|
|
} |
|
|
#if ENABLED(DEBUG_LEVELING_FEATURE) |
|
|
#endif |
|
|
if (DEBUGGING(LEVELING)) { |
|
|
|
|
|
SERIAL_ECHOPAIR("z_before = (before) ", Z_RAISE_BEFORE_PROBING + home_offset[Z_AXIS]); |
|
|
|
|
|
SERIAL_EOL; |
|
|
|
|
|
} |
|
|
|
|
|
#endif |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#if ENABLED(DELTA) |
|
|
#if ENABLED(DELTA) |
|
|
// Avoid probing the corners (outside the round or hexagon print surface) on a delta printer.
|
|
|
// Avoid probing the corners (outside the round or hexagon print surface) on a delta printer.
|
|
@ -4199,57 +4193,41 @@ inline void gcode_M42() { |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
double sum = 0.0, mean = 0.0, sigma = 0.0, sample_set[50]; |
|
|
int8_t verbose_level = code_seen('V') ? code_value_byte() : 1; |
|
|
int8_t verbose_level = 1, n_samples = 10, n_legs = 0, schizoid_flag = 0; |
|
|
if (verbose_level < 0 || verbose_level > 4) { |
|
|
|
|
|
SERIAL_PROTOCOLPGM("?Verbose Level not plausible (0-4).\n"); |
|
|
if (code_seen('V')) { |
|
|
return; |
|
|
verbose_level = code_value_byte(); |
|
|
|
|
|
if (verbose_level < 0 || verbose_level > 4) { |
|
|
|
|
|
SERIAL_PROTOCOLPGM("?Verbose Level not plausible (0-4).\n"); |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (verbose_level > 0) |
|
|
if (verbose_level > 0) |
|
|
SERIAL_PROTOCOLPGM("M48 Z-Probe Repeatability test\n"); |
|
|
SERIAL_PROTOCOLPGM("M48 Z-Probe Repeatability test\n"); |
|
|
|
|
|
|
|
|
if (code_seen('P')) { |
|
|
int8_t n_samples = code_seen('P') ? code_value_byte() : 10; |
|
|
n_samples = code_value_byte(); |
|
|
if (n_samples < 4 || n_samples > 50) { |
|
|
if (n_samples < 4 || n_samples > 50) { |
|
|
SERIAL_PROTOCOLPGM("?Sample size not plausible (4-50).\n"); |
|
|
SERIAL_PROTOCOLPGM("?Sample size not plausible (4-50).\n"); |
|
|
return; |
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
float X_current = current_position[X_AXIS], |
|
|
float X_current = current_position[X_AXIS], |
|
|
Y_current = current_position[Y_AXIS], |
|
|
Y_current = current_position[Y_AXIS], |
|
|
Z_current = current_position[Z_AXIS], |
|
|
Z_start_location = current_position[Z_AXIS] + Z_RAISE_BEFORE_PROBING; |
|
|
X_probe_location = X_current + X_PROBE_OFFSET_FROM_EXTRUDER, |
|
|
|
|
|
Y_probe_location = Y_current + Y_PROBE_OFFSET_FROM_EXTRUDER, |
|
|
|
|
|
Z_start_location = Z_current + Z_RAISE_BEFORE_PROBING; |
|
|
|
|
|
bool deploy_probe_for_each_reading = code_seen('E'); |
|
|
bool deploy_probe_for_each_reading = code_seen('E'); |
|
|
|
|
|
|
|
|
if (code_seen('X')) { |
|
|
float X_probe_location = code_seen('X') ? code_value_axis_units(X_AXIS) : X_current + X_PROBE_OFFSET_FROM_EXTRUDER; |
|
|
X_probe_location = code_value_axis_units(X_AXIS); |
|
|
#if DISABLED(DELTA) |
|
|
#if DISABLED(DELTA) |
|
|
if (X_probe_location < MIN_PROBE_X || X_probe_location > MAX_PROBE_X) { |
|
|
if (X_probe_location < MIN_PROBE_X || X_probe_location > MAX_PROBE_X) { |
|
|
out_of_range_error(PSTR("X")); |
|
|
out_of_range_error(PSTR("X")); |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
#endif |
|
|
#endif |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (code_seen('Y')) { |
|
|
|
|
|
Y_probe_location = code_value_axis_units(Y_AXIS); |
|
|
|
|
|
#if DISABLED(DELTA) |
|
|
|
|
|
if (Y_probe_location < MIN_PROBE_Y || Y_probe_location > MAX_PROBE_Y) { |
|
|
|
|
|
out_of_range_error(PSTR("Y")); |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
#endif |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#if ENABLED(DELTA) |
|
|
float Y_probe_location = code_seen('Y') ? code_value_axis_units(Y_AXIS) : Y_current + Y_PROBE_OFFSET_FROM_EXTRUDER; |
|
|
|
|
|
#if DISABLED(DELTA) |
|
|
|
|
|
if (Y_probe_location < MIN_PROBE_Y || Y_probe_location > MAX_PROBE_Y) { |
|
|
|
|
|
out_of_range_error(PSTR("Y")); |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
#else |
|
|
if (sqrt(X_probe_location * X_probe_location + Y_probe_location * Y_probe_location) > DELTA_PROBEABLE_RADIUS) { |
|
|
if (sqrt(X_probe_location * X_probe_location + Y_probe_location * Y_probe_location) > DELTA_PROBEABLE_RADIUS) { |
|
|
SERIAL_PROTOCOLPGM("? (X,Y) location outside of probeable radius.\n"); |
|
|
SERIAL_PROTOCOLPGM("? (X,Y) location outside of probeable radius.\n"); |
|
|
return; |
|
|
return; |
|
@ -4257,20 +4235,15 @@ inline void gcode_M42() { |
|
|
#endif |
|
|
#endif |
|
|
|
|
|
|
|
|
bool seen_L = code_seen('L'); |
|
|
bool seen_L = code_seen('L'); |
|
|
|
|
|
uint8_t n_legs = seen_L ? code_value_byte() : 0; |
|
|
if (seen_L) { |
|
|
if (n_legs < 0 || n_legs > 15) { |
|
|
n_legs = code_value_byte(); |
|
|
SERIAL_PROTOCOLPGM("?Number of legs in movement not plausible (0-15).\n"); |
|
|
if (n_legs < 0 || n_legs > 15) { |
|
|
return; |
|
|
SERIAL_PROTOCOLPGM("?Number of legs in movement not plausible (0-15).\n"); |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
if (n_legs == 1) n_legs = 2; |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
if (n_legs == 1) n_legs = 2; |
|
|
|
|
|
|
|
|
if (code_seen('S')) { |
|
|
bool schizoid_flag = code_seen('S'); |
|
|
schizoid_flag++; |
|
|
if (schizoid_flag && !seen_L) n_legs = 7; |
|
|
if (!seen_L) n_legs = 7; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
/**
|
|
|
* Now get everything to the specified probe point So we can safely do a |
|
|
* Now get everything to the specified probe point So we can safely do a |
|
@ -4299,26 +4272,29 @@ inline void gcode_M42() { |
|
|
*/ |
|
|
*/ |
|
|
setup_for_endstop_move(); |
|
|
setup_for_endstop_move(); |
|
|
|
|
|
|
|
|
probe_pt(X_probe_location, Y_probe_location, Z_RAISE_BEFORE_PROBING, |
|
|
// Height before each probe (except the first)
|
|
|
|
|
|
float z_between = home_offset[Z_AXIS] + (deploy_probe_for_each_reading ? Z_RAISE_BEFORE_PROBING : Z_RAISE_BETWEEN_PROBINGS); |
|
|
|
|
|
|
|
|
|
|
|
// Deploy the probe and probe the first point
|
|
|
|
|
|
probe_pt(X_probe_location, Y_probe_location, |
|
|
|
|
|
home_offset[Z_AXIS] + Z_RAISE_BEFORE_PROBING, |
|
|
deploy_probe_for_each_reading ? ProbeDeployAndStow : ProbeDeploy, |
|
|
deploy_probe_for_each_reading ? ProbeDeployAndStow : ProbeDeploy, |
|
|
verbose_level); |
|
|
verbose_level); |
|
|
|
|
|
|
|
|
raise_z_after_probing(); |
|
|
randomSeed(millis()); |
|
|
|
|
|
|
|
|
|
|
|
double mean, sigma, sample_set[n_samples]; |
|
|
for (uint8_t n = 0; n < n_samples; n++) { |
|
|
for (uint8_t n = 0; n < n_samples; n++) { |
|
|
randomSeed(millis()); |
|
|
|
|
|
delay(500); |
|
|
|
|
|
if (n_legs) { |
|
|
if (n_legs) { |
|
|
float radius, angle = random(0.0, 360.0); |
|
|
|
|
|
int dir = (random(0, 10) > 5.0) ? -1 : 1; // clockwise or counter clockwise
|
|
|
int dir = (random(0, 10) > 5.0) ? -1 : 1; // clockwise or counter clockwise
|
|
|
|
|
|
float angle = random(0.0, 360.0), |
|
|
radius = random( |
|
|
radius = random( |
|
|
#if ENABLED(DELTA) |
|
|
#if ENABLED(DELTA) |
|
|
DELTA_PROBEABLE_RADIUS / 8, DELTA_PROBEABLE_RADIUS / 3 |
|
|
DELTA_PROBEABLE_RADIUS / 8, DELTA_PROBEABLE_RADIUS / 3 |
|
|
#else |
|
|
#else |
|
|
5, X_MAX_LENGTH / 8 |
|
|
5, X_MAX_LENGTH / 8 |
|
|
#endif |
|
|
#endif |
|
|
); |
|
|
); |
|
|
|
|
|
|
|
|
if (verbose_level > 3) { |
|
|
if (verbose_level > 3) { |
|
|
SERIAL_ECHOPAIR("Starting radius: ", radius); |
|
|
SERIAL_ECHOPAIR("Starting radius: ", radius); |
|
@ -4383,26 +4359,21 @@ inline void gcode_M42() { |
|
|
} // n_legs loop
|
|
|
} // n_legs loop
|
|
|
} // n_legs
|
|
|
} // n_legs
|
|
|
|
|
|
|
|
|
/**
|
|
|
// The last probe will differ
|
|
|
* We don't really have to do this move, but if we don't we can see a |
|
|
bool last_probe = (n == n_samples - 1); |
|
|
* funny shift in the Z Height because the user might not have the |
|
|
|
|
|
* Z_RAISE_BEFORE_PROBING height identical to the Z_RAISE_BETWEEN_PROBING |
|
|
// Probe a single point
|
|
|
* height. This gets us back to the probe location at the same height that |
|
|
sample_set[n] = probe_pt( |
|
|
* we have been running around the circle at. |
|
|
X_probe_location, Y_probe_location, |
|
|
*/ |
|
|
z_between, |
|
|
do_blocking_move_to_xy(X_probe_location - (X_PROBE_OFFSET_FROM_EXTRUDER), Y_probe_location - (Y_PROBE_OFFSET_FROM_EXTRUDER)); |
|
|
deploy_probe_for_each_reading ? ProbeDeployAndStow : last_probe ? ProbeStow : ProbeStay, |
|
|
if (deploy_probe_for_each_reading) |
|
|
verbose_level |
|
|
sample_set[n] = probe_pt(X_probe_location, Y_probe_location, Z_RAISE_BEFORE_PROBING, ProbeDeployAndStow, verbose_level); |
|
|
); |
|
|
else { |
|
|
|
|
|
if (n == n_samples - 1) |
|
|
|
|
|
sample_set[n] = probe_pt(X_probe_location, Y_probe_location, Z_RAISE_BEFORE_PROBING, ProbeStow, verbose_level); else |
|
|
|
|
|
sample_set[n] = probe_pt(X_probe_location, Y_probe_location, Z_RAISE_BEFORE_PROBING, ProbeStay, verbose_level); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
/**
|
|
|
* Get the current mean for the data points we have so far |
|
|
* Get the current mean for the data points we have so far |
|
|
*/ |
|
|
*/ |
|
|
sum = 0.0; |
|
|
double sum = 0.0; |
|
|
for (uint8_t j = 0; j <= n; j++) sum += sample_set[j]; |
|
|
for (uint8_t j = 0; j <= n; j++) sum += sample_set[j]; |
|
|
mean = sum / (n + 1); |
|
|
mean = sum / (n + 1); |
|
|
|
|
|
|
|
@ -4416,38 +4387,42 @@ inline void gcode_M42() { |
|
|
sum += ss * ss; |
|
|
sum += ss * ss; |
|
|
} |
|
|
} |
|
|
sigma = sqrt(sum / (n + 1)); |
|
|
sigma = sqrt(sum / (n + 1)); |
|
|
if (verbose_level > 1) { |
|
|
if (verbose_level > 0) { |
|
|
SERIAL_PROTOCOL(n + 1); |
|
|
if (verbose_level > 1) { |
|
|
SERIAL_PROTOCOLPGM(" of "); |
|
|
SERIAL_PROTOCOL(n + 1); |
|
|
SERIAL_PROTOCOL((int)n_samples); |
|
|
SERIAL_PROTOCOLPGM(" of "); |
|
|
SERIAL_PROTOCOLPGM(" z: "); |
|
|
SERIAL_PROTOCOL((int)n_samples); |
|
|
SERIAL_PROTOCOL_F(current_position[Z_AXIS], 6); |
|
|
SERIAL_PROTOCOLPGM(" z: "); |
|
|
delay(50); |
|
|
SERIAL_PROTOCOL_F(current_position[Z_AXIS], 6); |
|
|
if (verbose_level > 2) { |
|
|
delay(50); |
|
|
SERIAL_PROTOCOLPGM(" mean: "); |
|
|
if (verbose_level > 2) { |
|
|
SERIAL_PROTOCOL_F(mean, 6); |
|
|
SERIAL_PROTOCOLPGM(" mean: "); |
|
|
SERIAL_PROTOCOLPGM(" sigma: "); |
|
|
SERIAL_PROTOCOL_F(mean, 6); |
|
|
SERIAL_PROTOCOL_F(sigma, 6); |
|
|
SERIAL_PROTOCOLPGM(" sigma: "); |
|
|
|
|
|
SERIAL_PROTOCOL_F(sigma, 6); |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
SERIAL_EOL; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Raise before the next loop for the legs,
|
|
|
|
|
|
// or do the final raise after the last probe
|
|
|
|
|
|
if (n_legs || last_probe) { |
|
|
|
|
|
do_blocking_move_to_z(last_probe ? home_offset[Z_AXIS] + Z_RAISE_AFTER_PROBING : z_between); |
|
|
|
|
|
if (!last_probe) delay(500); |
|
|
} |
|
|
} |
|
|
if (verbose_level > 0) SERIAL_EOL; |
|
|
|
|
|
delay(50); |
|
|
|
|
|
do_blocking_move_to_z(current_position[Z_AXIS] + Z_RAISE_BETWEEN_PROBINGS); |
|
|
|
|
|
} // End of probe loop code
|
|
|
|
|
|
|
|
|
|
|
|
// raise_z_after_probing();
|
|
|
} // End of probe loop
|
|
|
|
|
|
|
|
|
if (verbose_level > 0) { |
|
|
if (verbose_level > 0) { |
|
|
SERIAL_PROTOCOLPGM("Mean: "); |
|
|
SERIAL_PROTOCOLPGM("Mean: "); |
|
|
SERIAL_PROTOCOL_F(mean, 6); |
|
|
SERIAL_PROTOCOL_F(mean, 6); |
|
|
SERIAL_EOL; |
|
|
SERIAL_EOL; |
|
|
delay(25); |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
SERIAL_PROTOCOLPGM("Standard Deviation: "); |
|
|
SERIAL_PROTOCOLPGM("Standard Deviation: "); |
|
|
SERIAL_PROTOCOL_F(sigma, 6); |
|
|
SERIAL_PROTOCOL_F(sigma, 6); |
|
|
SERIAL_EOL; SERIAL_EOL; |
|
|
SERIAL_EOL; SERIAL_EOL; |
|
|
delay(25); |
|
|
|
|
|
|
|
|
|
|
|
clean_up_after_endstop_move(); |
|
|
clean_up_after_endstop_move(); |
|
|
|
|
|
|
|
|