|
@@ -12,9 +12,18 @@ extern float home_retract_mm_ext(int axis);
|
|
|
float world2machine_rotation_and_skew[2][2];
|
|
|
float world2machine_shift[2];
|
|
|
|
|
|
+// Weight of the Y coordinate for the least squares fitting of the bed induction sensor targets.
|
|
|
+// Only used for the first row of the points, which may not befully in reach of the sensor.
|
|
|
+#define WEIGHT_FIRST_ROW (0.2f)
|
|
|
+
|
|
|
#define BED_ZERO_REF_X (- 22.f + X_PROBE_OFFSET_FROM_EXTRUDER)
|
|
|
#define BED_ZERO_REF_Y (- 0.6f + Y_PROBE_OFFSET_FROM_EXTRUDER)
|
|
|
|
|
|
+// Scaling of the real machine axes against the programmed dimensions in the firmware.
|
|
|
+// The correction is tiny, here around 0.5mm on 250mm length.
|
|
|
+#define MACHINE_AXIS_SCALE_X ((250.f + 0.5f) / 250.f)
|
|
|
+#define MACHINE_AXIS_SCALE_Y ((250.f + 0.5f) / 250.f)
|
|
|
+
|
|
|
// Positions of the bed reference points in the machine coordinates, referenced to the P.I.N.D.A sensor.
|
|
|
// The points are ordered in a zig-zag fashion to speed up the calibration.
|
|
|
const float bed_ref_points[] PROGMEM = {
|
|
@@ -45,6 +54,12 @@ const float bed_ref_points_4[] PROGMEM = {
|
|
|
|
|
|
static inline float sqr(float x) { return x * x; }
|
|
|
|
|
|
+
|
|
|
+#if 0
|
|
|
+// Linear Least Squares fitting of the bed to the measured induction points.
|
|
|
+// This method will not maintain a unity length of the machine axes.
|
|
|
+// This may be all right if the sensor points are measured precisely,
|
|
|
+// but it will stretch or shorten the machine axes if the measured data is not precise enough.
|
|
|
bool calculate_machine_skew_and_offset_LS(
|
|
|
// Matrix of maximum 9 2D points (18 floats)
|
|
|
const float *measured_pts,
|
|
@@ -136,13 +151,11 @@ bool calculate_machine_skew_and_offset_LS(
|
|
|
|
|
|
// Recalculate A and b for the y values.
|
|
|
// Note the weighting of the first row of values.
|
|
|
-// const float weight_1st_row = 0.5f;
|
|
|
- const float weight_1st_row = 0.2f;
|
|
|
for (uint8_t r = 0; r < 3; ++ r) {
|
|
|
for (uint8_t c = 0; c < 3; ++ c) {
|
|
|
acc = 0;
|
|
|
for (uint8_t i = 0; i < npts; ++ i) {
|
|
|
- float w = (i < 3) ? weight_1st_row : 1.f;
|
|
|
+ float w = (i < 3) ? WEIGHT_FIRST_ROW : 1.f;
|
|
|
float a = (r == 2) ? 1.f : measured_pts[2 * i + r];
|
|
|
float b = (c == 2) ? 1.f : measured_pts[2 * i + c];
|
|
|
acc += a * b * w;
|
|
@@ -151,7 +164,7 @@ bool calculate_machine_skew_and_offset_LS(
|
|
|
}
|
|
|
acc = 0.f;
|
|
|
for (uint8_t i = 0; i < npts; ++ i) {
|
|
|
- float w = (i < 3) ? weight_1st_row : 1.f;
|
|
|
+ float w = (i < 3) ? WEIGHT_FIRST_ROW : 1.f;
|
|
|
float a = (r == 2) ? 1.f : measured_pts[2 * i + r];
|
|
|
float b = pgm_read_float(true_pts+i*2+1);
|
|
|
acc += w * a * b;
|
|
@@ -333,6 +346,318 @@ bool calculate_machine_skew_and_offset_LS(
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
+#else
|
|
|
+
|
|
|
+// Non-Linear Least Squares fitting of the bed to the measured induction points
|
|
|
+// using the Gauss-Newton method.
|
|
|
+// This method will maintain a unity length of the machine axes,
|
|
|
+// which is the correct approach if the sensor points are not measured precisely.
|
|
|
+bool calculate_machine_skew_and_offset_LS(
|
|
|
+ // Matrix of maximum 9 2D points (18 floats)
|
|
|
+ const float *measured_pts,
|
|
|
+ uint8_t npts,
|
|
|
+ const float *true_pts,
|
|
|
+ // Resulting correction matrix.
|
|
|
+ float *vec_x,
|
|
|
+ float *vec_y,
|
|
|
+ float *cntr,
|
|
|
+ // Temporary values, 49-18-(2*3)=25 floats
|
|
|
+ // , float *temp
|
|
|
+ int8_t verbosity_level
|
|
|
+ )
|
|
|
+{
|
|
|
+ if (verbosity_level >= 10) {
|
|
|
+ // Show the initial state, before the fitting.
|
|
|
+ SERIAL_ECHOPGM("X vector, initial: ");
|
|
|
+ MYSERIAL.print(vec_x[0], 5);
|
|
|
+ SERIAL_ECHOPGM(", ");
|
|
|
+ MYSERIAL.print(vec_x[1], 5);
|
|
|
+ SERIAL_ECHOLNPGM("");
|
|
|
+
|
|
|
+ SERIAL_ECHOPGM("Y vector, initial: ");
|
|
|
+ MYSERIAL.print(vec_y[0], 5);
|
|
|
+ SERIAL_ECHOPGM(", ");
|
|
|
+ MYSERIAL.print(vec_y[1], 5);
|
|
|
+ SERIAL_ECHOLNPGM("");
|
|
|
+
|
|
|
+ SERIAL_ECHOPGM("center, initial: ");
|
|
|
+ MYSERIAL.print(cntr[0], 5);
|
|
|
+ SERIAL_ECHOPGM(", ");
|
|
|
+ MYSERIAL.print(cntr[1], 5);
|
|
|
+ SERIAL_ECHOLNPGM("");
|
|
|
+
|
|
|
+ for (uint8_t i = 0; i < npts; ++i) {
|
|
|
+ SERIAL_ECHOPGM("point #");
|
|
|
+ MYSERIAL.print(int(i));
|
|
|
+ SERIAL_ECHOPGM(" measured: (");
|
|
|
+ MYSERIAL.print(measured_pts[i * 2], 5);
|
|
|
+ SERIAL_ECHOPGM(", ");
|
|
|
+ MYSERIAL.print(measured_pts[i * 2 + 1], 5);
|
|
|
+ SERIAL_ECHOPGM("); target: (");
|
|
|
+ MYSERIAL.print(pgm_read_float(true_pts + i * 2), 5);
|
|
|
+ SERIAL_ECHOPGM(", ");
|
|
|
+ MYSERIAL.print(pgm_read_float(true_pts + i * 2 + 1), 5);
|
|
|
+ SERIAL_ECHOPGM("), error: ");
|
|
|
+ MYSERIAL.print(sqrt(
|
|
|
+ sqr(pgm_read_float(true_pts + i * 2) - measured_pts[i * 2]) +
|
|
|
+ sqr(pgm_read_float(true_pts + i * 2 + 1) - measured_pts[i * 2 + 1])), 5);
|
|
|
+ SERIAL_ECHOLNPGM("");
|
|
|
+ }
|
|
|
+ delay_keep_alive(100);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Run some iterations of the Gauss-Newton method of non-linear least squares.
|
|
|
+ // Initial set of parameters:
|
|
|
+ // X,Y offset
|
|
|
+ cntr[0] = 0.f;
|
|
|
+ cntr[1] = 0.f;
|
|
|
+ // Rotation of the machine X axis from the bed X axis.
|
|
|
+ float a1 = 0;
|
|
|
+ // Rotation of the machine Y axis from the bed Y axis.
|
|
|
+ float a2 = 0;
|
|
|
+ for (int8_t iter = 0; iter < 100; ++iter) {
|
|
|
+ float c1 = cos(a1) * MACHINE_AXIS_SCALE_X;
|
|
|
+ float s1 = sin(a1) * MACHINE_AXIS_SCALE_X;
|
|
|
+ float c2 = cos(a2) * MACHINE_AXIS_SCALE_Y;
|
|
|
+ float s2 = sin(a2) * MACHINE_AXIS_SCALE_Y;
|
|
|
+ // Prepare the Normal equation for the Gauss-Newton method.
|
|
|
+ float A[4][4] = { 0.f };
|
|
|
+ float b[4] = { 0.f };
|
|
|
+ float acc;
|
|
|
+ for (uint8_t r = 0; r < 4; ++r) {
|
|
|
+ for (uint8_t c = 0; c < 4; ++c) {
|
|
|
+ acc = 0;
|
|
|
+ // J^T times J
|
|
|
+ for (uint8_t i = 0; i < npts; ++i) {
|
|
|
+ // First for the residuum in the x axis:
|
|
|
+ if (r != 1 && c != 1) {
|
|
|
+ float a =
|
|
|
+ (r == 0) ? 1.f :
|
|
|
+ ((r == 2) ? (-s1 * measured_pts[2 * i]) :
|
|
|
+ (-c2 * measured_pts[2 * i + 1]));
|
|
|
+ float b =
|
|
|
+ (c == 0) ? 1.f :
|
|
|
+ ((c == 2) ? (-s1 * measured_pts[2 * i]) :
|
|
|
+ (-c2 * measured_pts[2 * i + 1]));
|
|
|
+ acc += a * b;
|
|
|
+ }
|
|
|
+ // Second for the residuum in the y axis.
|
|
|
+ // The first row of the points have a low weight, because their position may not be known
|
|
|
+ // with a sufficient accuracy.
|
|
|
+ if (r != 0 && c != 0) {
|
|
|
+ float a =
|
|
|
+ (r == 1) ? 1.f :
|
|
|
+ ((r == 2) ? ( c1 * measured_pts[2 * i]) :
|
|
|
+ (-s2 * measured_pts[2 * i + 1]));
|
|
|
+ float b =
|
|
|
+ (c == 1) ? 1.f :
|
|
|
+ ((c == 2) ? ( c1 * measured_pts[2 * i]) :
|
|
|
+ (-s2 * measured_pts[2 * i + 1]));
|
|
|
+ float w = (i < 3) ? WEIGHT_FIRST_ROW : 1.f;
|
|
|
+ acc += a * b * w;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ A[r][c] = acc;
|
|
|
+ }
|
|
|
+ // J^T times f(x)
|
|
|
+ acc = 0.f;
|
|
|
+ for (uint8_t i = 0; i < npts; ++i) {
|
|
|
+ {
|
|
|
+ float j =
|
|
|
+ (r == 0) ? 1.f :
|
|
|
+ ((r == 1) ? 0.f :
|
|
|
+ ((r == 2) ? (-s1 * measured_pts[2 * i]) :
|
|
|
+ (-c2 * measured_pts[2 * i + 1])));
|
|
|
+ float fx = c1 * measured_pts[2 * i] - s2 * measured_pts[2 * i + 1] + cntr[0] - pgm_read_float(true_pts + i * 2);
|
|
|
+ acc += j * fx;
|
|
|
+ }
|
|
|
+ {
|
|
|
+ float j =
|
|
|
+ (r == 0) ? 0.f :
|
|
|
+ ((r == 1) ? 1.f :
|
|
|
+ ((r == 2) ? ( c1 * measured_pts[2 * i]) :
|
|
|
+ (-s2 * measured_pts[2 * i + 1])));
|
|
|
+ float fy = s1 * measured_pts[2 * i] + c2 * measured_pts[2 * i + 1] + cntr[1] - pgm_read_float(true_pts + i * 2 + 1);
|
|
|
+ float w = (i < 3) ? WEIGHT_FIRST_ROW : 1.f;
|
|
|
+ acc += j * fy * w;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ b[r] = -acc;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Solve for h by a Gauss iteration method.
|
|
|
+ float h[4] = { 0.f };
|
|
|
+ for (uint8_t gauss_iter = 0; gauss_iter < 100; ++gauss_iter) {
|
|
|
+ h[0] = (b[0] - A[0][1] * h[1] - A[0][2] * h[2] - A[0][3] * h[3]) / A[0][0];
|
|
|
+ h[1] = (b[1] - A[1][0] * h[0] - A[1][2] * h[2] - A[1][3] * h[3]) / A[1][1];
|
|
|
+ h[2] = (b[2] - A[2][0] * h[0] - A[2][1] * h[1] - A[2][3] * h[3]) / A[2][2];
|
|
|
+ h[3] = (b[3] - A[3][0] * h[0] - A[3][1] * h[1] - A[3][2] * h[2]) / A[3][3];
|
|
|
+ }
|
|
|
+
|
|
|
+ // and update the current position with h.
|
|
|
+ // It may be better to use the Levenberg-Marquart method here,
|
|
|
+ // but because we are very close to the solution alread,
|
|
|
+ // the simple Gauss-Newton non-linear Least Squares method works well enough.
|
|
|
+ cntr[0] += h[0];
|
|
|
+ cntr[1] += h[1];
|
|
|
+ a1 += h[2];
|
|
|
+ a2 += h[3];
|
|
|
+
|
|
|
+ if (verbosity_level >= 20) {
|
|
|
+ SERIAL_ECHOPGM("iteration: ");
|
|
|
+ MYSERIAL.print(iter, 0);
|
|
|
+ SERIAL_ECHOPGM("correction vector: ");
|
|
|
+ MYSERIAL.print(h[0], 5);
|
|
|
+ SERIAL_ECHOPGM(", ");
|
|
|
+ MYSERIAL.print(h[1], 5);
|
|
|
+ SERIAL_ECHOPGM(", ");
|
|
|
+ MYSERIAL.print(h[2], 5);
|
|
|
+ SERIAL_ECHOPGM(", ");
|
|
|
+ MYSERIAL.print(h[3], 5);
|
|
|
+ SERIAL_ECHOLNPGM("");
|
|
|
+ SERIAL_ECHOPGM("corrected x/y: ");
|
|
|
+ MYSERIAL.print(cntr[0], 5);
|
|
|
+ SERIAL_ECHOPGM(", ");
|
|
|
+ MYSERIAL.print(cntr[0], 5);
|
|
|
+ SERIAL_ECHOLNPGM("");
|
|
|
+ SERIAL_ECHOPGM("corrected angles: ");
|
|
|
+ MYSERIAL.print(180.f * a1 / M_PI, 5);
|
|
|
+ SERIAL_ECHOPGM(", ");
|
|
|
+ MYSERIAL.print(180.f * a2 / M_PI, 5);
|
|
|
+ SERIAL_ECHOLNPGM("");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ vec_x[0] = cos(a1) * MACHINE_AXIS_SCALE_X;
|
|
|
+ vec_x[1] = sin(a1) * MACHINE_AXIS_SCALE_X;
|
|
|
+ vec_y[0] = -sin(a2) * MACHINE_AXIS_SCALE_Y;
|
|
|
+ vec_y[1] = cos(a2) * MACHINE_AXIS_SCALE_Y;
|
|
|
+
|
|
|
+ if (verbosity_level >= 1) {
|
|
|
+ SERIAL_ECHOPGM("correction angles: ");
|
|
|
+ MYSERIAL.print(180.f * a1 / M_PI, 5);
|
|
|
+ SERIAL_ECHOPGM(", ");
|
|
|
+ MYSERIAL.print(180.f * a2 / M_PI, 5);
|
|
|
+ SERIAL_ECHOLNPGM("");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (verbosity_level >= 10) {
|
|
|
+ // Show the adjusted state, before the fitting.
|
|
|
+ SERIAL_ECHOPGM("X vector new, inverted: ");
|
|
|
+ MYSERIAL.print(vec_x[0], 5);
|
|
|
+ SERIAL_ECHOPGM(", ");
|
|
|
+ MYSERIAL.print(vec_x[1], 5);
|
|
|
+ SERIAL_ECHOLNPGM("");
|
|
|
+
|
|
|
+ SERIAL_ECHOPGM("Y vector new, inverted: ");
|
|
|
+ MYSERIAL.print(vec_y[0], 5);
|
|
|
+ SERIAL_ECHOPGM(", ");
|
|
|
+ MYSERIAL.print(vec_y[1], 5);
|
|
|
+ SERIAL_ECHOLNPGM("");
|
|
|
+
|
|
|
+ SERIAL_ECHOPGM("center new, inverted: ");
|
|
|
+ MYSERIAL.print(cntr[0], 5);
|
|
|
+ SERIAL_ECHOPGM(", ");
|
|
|
+ MYSERIAL.print(cntr[1], 5);
|
|
|
+ SERIAL_ECHOLNPGM("");
|
|
|
+ delay_keep_alive(100);
|
|
|
+
|
|
|
+ SERIAL_ECHOLNPGM("Error after correction: ");
|
|
|
+ for (uint8_t i = 0; i < npts; ++i) {
|
|
|
+ float x = vec_x[0] * measured_pts[i * 2] + vec_y[0] * measured_pts[i * 2 + 1] + cntr[0];
|
|
|
+ float y = vec_x[1] * measured_pts[i * 2] + vec_y[1] * measured_pts[i * 2 + 1] + cntr[1];
|
|
|
+ SERIAL_ECHOPGM("point #");
|
|
|
+ MYSERIAL.print(int(i));
|
|
|
+ SERIAL_ECHOPGM(" measured: (");
|
|
|
+ MYSERIAL.print(measured_pts[i * 2], 5);
|
|
|
+ SERIAL_ECHOPGM(", ");
|
|
|
+ MYSERIAL.print(measured_pts[i * 2 + 1], 5);
|
|
|
+ SERIAL_ECHOPGM("); corrected: (");
|
|
|
+ MYSERIAL.print(x, 5);
|
|
|
+ SERIAL_ECHOPGM(", ");
|
|
|
+ MYSERIAL.print(y, 5);
|
|
|
+ SERIAL_ECHOPGM("); target: (");
|
|
|
+ MYSERIAL.print(pgm_read_float(true_pts + i * 2), 5);
|
|
|
+ SERIAL_ECHOPGM(", ");
|
|
|
+ MYSERIAL.print(pgm_read_float(true_pts + i * 2 + 1), 5);
|
|
|
+ SERIAL_ECHOPGM("), error: ");
|
|
|
+ MYSERIAL.print(sqrt(sqr(pgm_read_float(true_pts + i * 2) - x) + sqr(pgm_read_float(true_pts + i * 2 + 1) - y)));
|
|
|
+ SERIAL_ECHOLNPGM("");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Invert the transformation matrix made of vec_x, vec_y and cntr.
|
|
|
+ {
|
|
|
+ float d = vec_x[0] * vec_y[1] - vec_x[1] * vec_y[0];
|
|
|
+ float Ainv[2][2] = {
|
|
|
+ { vec_y[1] / d, -vec_y[0] / d },
|
|
|
+ { -vec_x[1] / d, vec_x[0] / d }
|
|
|
+ };
|
|
|
+ float cntrInv[2] = {
|
|
|
+ -Ainv[0][0] * cntr[0] - Ainv[0][1] * cntr[1],
|
|
|
+ -Ainv[1][0] * cntr[0] - Ainv[1][1] * cntr[1]
|
|
|
+ };
|
|
|
+ vec_x[0] = Ainv[0][0];
|
|
|
+ vec_x[1] = Ainv[1][0];
|
|
|
+ vec_y[0] = Ainv[0][1];
|
|
|
+ vec_y[1] = Ainv[1][1];
|
|
|
+ cntr[0] = cntrInv[0];
|
|
|
+ cntr[1] = cntrInv[1];
|
|
|
+ }
|
|
|
+
|
|
|
+ if (verbosity_level >= 1) {
|
|
|
+ // Show the adjusted state, before the fitting.
|
|
|
+ SERIAL_ECHOPGM("X vector, adjusted: ");
|
|
|
+ MYSERIAL.print(vec_x[0], 5);
|
|
|
+ SERIAL_ECHOPGM(", ");
|
|
|
+ MYSERIAL.print(vec_x[1], 5);
|
|
|
+ SERIAL_ECHOLNPGM("");
|
|
|
+
|
|
|
+ SERIAL_ECHOPGM("Y vector, adjusted: ");
|
|
|
+ MYSERIAL.print(vec_y[0], 5);
|
|
|
+ SERIAL_ECHOPGM(", ");
|
|
|
+ MYSERIAL.print(vec_y[1], 5);
|
|
|
+ SERIAL_ECHOLNPGM("");
|
|
|
+
|
|
|
+ SERIAL_ECHOPGM("center, adjusted: ");
|
|
|
+ MYSERIAL.print(cntr[0], 5);
|
|
|
+ SERIAL_ECHOPGM(", ");
|
|
|
+ MYSERIAL.print(cntr[1], 5);
|
|
|
+ SERIAL_ECHOLNPGM("");
|
|
|
+ delay_keep_alive(100);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (verbosity_level >= 2) {
|
|
|
+ SERIAL_ECHOLNPGM("Difference after correction: ");
|
|
|
+ for (uint8_t i = 0; i < npts; ++i) {
|
|
|
+ float x = vec_x[0] * pgm_read_float(true_pts + i * 2) + vec_y[0] * pgm_read_float(true_pts + i * 2 + 1) + cntr[0];
|
|
|
+ float y = vec_x[1] * pgm_read_float(true_pts + i * 2) + vec_y[1] * pgm_read_float(true_pts + i * 2 + 1) + cntr[1];
|
|
|
+ SERIAL_ECHOPGM("point #");
|
|
|
+ MYSERIAL.print(int(i));
|
|
|
+ SERIAL_ECHOPGM("measured: (");
|
|
|
+ MYSERIAL.print(measured_pts[i * 2], 5);
|
|
|
+ SERIAL_ECHOPGM(", ");
|
|
|
+ MYSERIAL.print(measured_pts[i * 2 + 1], 5);
|
|
|
+ SERIAL_ECHOPGM("); measured-corrected: (");
|
|
|
+ MYSERIAL.print(x, 5);
|
|
|
+ SERIAL_ECHOPGM(", ");
|
|
|
+ MYSERIAL.print(y, 5);
|
|
|
+ SERIAL_ECHOPGM("); target: (");
|
|
|
+ MYSERIAL.print(pgm_read_float(true_pts + i * 2), 5);
|
|
|
+ SERIAL_ECHOPGM(", ");
|
|
|
+ MYSERIAL.print(pgm_read_float(true_pts + i * 2 + 1), 5);
|
|
|
+ SERIAL_ECHOPGM("), error: ");
|
|
|
+ MYSERIAL.print(sqrt(sqr(measured_pts[i * 2] - x) + sqr(measured_pts[i * 2 + 1] - y)));
|
|
|
+ SERIAL_ECHOLNPGM("");
|
|
|
+ }
|
|
|
+ delay_keep_alive(100);
|
|
|
+ }
|
|
|
+
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+#endif
|
|
|
+
|
|
|
void reset_bed_offset_and_skew()
|
|
|
{
|
|
|
eeprom_update_dword((uint32_t*)(EEPROM_BED_CALIBRATION_CENTER+0), 0x0FFFFFFFF);
|
|
@@ -883,151 +1208,274 @@ canceled:
|
|
|
// Searching in a zig-zag movement in a plane for the maximum width of the response.
|
|
|
#define IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_RADIUS (4.f)
|
|
|
#define IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_STEP_FINE_Y (0.1f)
|
|
|
-inline bool improve_bed_induction_sensor_point3()
|
|
|
+inline bool improve_bed_induction_sensor_point3(int verbosity_level)
|
|
|
{
|
|
|
float center_old_x = current_position[X_AXIS];
|
|
|
float center_old_y = current_position[Y_AXIS];
|
|
|
- float x0 = center_old_x - IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_RADIUS;
|
|
|
- float x1 = center_old_x + IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_RADIUS;
|
|
|
- float y0 = center_old_y - IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_RADIUS;
|
|
|
- float y1 = center_old_y + IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_RADIUS;
|
|
|
- float y = y0;
|
|
|
float a, b;
|
|
|
+ {
|
|
|
+ float x0 = center_old_x - IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_RADIUS;
|
|
|
+ float x1 = center_old_x + IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_RADIUS;
|
|
|
+ float y0 = center_old_y - IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_RADIUS;
|
|
|
+ float y1 = center_old_y + IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_RADIUS;
|
|
|
+ float y = y0;
|
|
|
|
|
|
- if (x0 < X_MIN_POS)
|
|
|
- x0 = X_MIN_POS;
|
|
|
- if (x1 > X_MAX_POS)
|
|
|
- x1 = X_MAX_POS;
|
|
|
- if (y0 < Y_MIN_POS_FOR_BED_CALIBRATION)
|
|
|
- y0 = Y_MIN_POS_FOR_BED_CALIBRATION;
|
|
|
- if (y1 > Y_MAX_POS)
|
|
|
- y1 = Y_MAX_POS;
|
|
|
+ if (x0 < X_MIN_POS)
|
|
|
+ x0 = X_MIN_POS;
|
|
|
+ if (x1 > X_MAX_POS)
|
|
|
+ x1 = X_MAX_POS;
|
|
|
+ if (y0 < Y_MIN_POS_FOR_BED_CALIBRATION)
|
|
|
+ y0 = Y_MIN_POS_FOR_BED_CALIBRATION;
|
|
|
+ if (y1 > Y_MAX_POS)
|
|
|
+ y1 = Y_MAX_POS;
|
|
|
|
|
|
-#if 0
|
|
|
- SERIAL_ECHOPGM("Initial position: ");
|
|
|
- SERIAL_ECHO(center_old_x);
|
|
|
- SERIAL_ECHOPGM(", ");
|
|
|
- SERIAL_ECHO(center_old_y);
|
|
|
- SERIAL_ECHOLNPGM("");
|
|
|
-#endif
|
|
|
+ if (verbosity_level >= 20) {
|
|
|
+ SERIAL_ECHOPGM("Initial position: ");
|
|
|
+ SERIAL_ECHO(center_old_x);
|
|
|
+ SERIAL_ECHOPGM(", ");
|
|
|
+ SERIAL_ECHO(center_old_y);
|
|
|
+ SERIAL_ECHOLNPGM("");
|
|
|
+ }
|
|
|
|
|
|
- // Search in the X direction along a cross.
|
|
|
- float dmax = 0.;
|
|
|
- float xmax1 = 0.;
|
|
|
- float xmax2 = 0.;
|
|
|
- for (float y = y0; y < y1; y += IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_STEP_FINE_Y) {
|
|
|
+ // Search in the positive Y direction, until a maximum diameter is found.
|
|
|
+ float dmax = 0.f;
|
|
|
+ float xmax1 = 0.f;
|
|
|
+ float xmax2 = 0.f;
|
|
|
+ for (float y = y0; y < y1; y += IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_STEP_FINE_Y) {
|
|
|
+ enable_z_endstop(false);
|
|
|
+ go_xy(x0, y, homing_feedrate[X_AXIS] / 60.f);
|
|
|
+ enable_z_endstop(true);
|
|
|
+ go_xy(x1, y, homing_feedrate[X_AXIS] / 60.f);
|
|
|
+ update_current_position_xyz();
|
|
|
+ if (! endstop_z_hit_on_purpose()) {
|
|
|
+ continue;
|
|
|
+ // SERIAL_PROTOCOLPGM("Failed 1\n");
|
|
|
+ // current_position[X_AXIS] = center_old_x;
|
|
|
+ // goto canceled;
|
|
|
+ }
|
|
|
+ a = current_position[X_AXIS];
|
|
|
+ enable_z_endstop(false);
|
|
|
+ go_xy(x1, y, homing_feedrate[X_AXIS] / 60.f);
|
|
|
+ enable_z_endstop(true);
|
|
|
+ go_xy(x0, y, homing_feedrate[X_AXIS] / 60.f);
|
|
|
+ update_current_position_xyz();
|
|
|
+ if (! endstop_z_hit_on_purpose()) {
|
|
|
+ continue;
|
|
|
+ // SERIAL_PROTOCOLPGM("Failed 2\n");
|
|
|
+ // current_position[X_AXIS] = center_old_x;
|
|
|
+ // goto canceled;
|
|
|
+ }
|
|
|
+ b = current_position[X_AXIS];
|
|
|
+ if (verbosity_level > 20) {
|
|
|
+ SERIAL_ECHOPGM("Measured left ");
|
|
|
+ MYSERIAL.print(a, 5);
|
|
|
+ SERIAL_ECHOPGM("right ");
|
|
|
+ MYSERIAL.print(b, 5);
|
|
|
+ SERIAL_ECHOPGM(", ");
|
|
|
+ MYSERIAL.print(y, 5);
|
|
|
+ SERIAL_ECHOPGM(", ");
|
|
|
+ MYSERIAL.print(current_position[Z_AXIS], 5);
|
|
|
+ SERIAL_ECHOLNPGM("");
|
|
|
+ }
|
|
|
+ float d = b - a;
|
|
|
+ if (d > dmax) {
|
|
|
+ xmax1 = 0.5f * (a + b);
|
|
|
+ dmax = d;
|
|
|
+ } else if (dmax > 0.) {
|
|
|
+ y0 = y - IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_STEP_FINE_Y;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (dmax == 0.) {
|
|
|
+ SERIAL_PROTOCOLPGM("failed - not found\n");
|
|
|
+ goto canceled;
|
|
|
+ }
|
|
|
+
|
|
|
+ SERIAL_PROTOCOLPGM("ok 1\n");
|
|
|
+ // Search in the negative Y direction, until a maximum diameter is found.
|
|
|
+ dmax = 0.;
|
|
|
+ if (y0 + 1.f < y1)
|
|
|
+ y1 = y0 + 1.f;
|
|
|
+ for (float y = y1; y >= y0; y -= IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_STEP_FINE_Y) {
|
|
|
+ enable_z_endstop(false);
|
|
|
+ go_xy(x0, y, homing_feedrate[X_AXIS] / 60.f);
|
|
|
+ enable_z_endstop(true);
|
|
|
+ go_xy(x1, y, homing_feedrate[X_AXIS] / 60.f);
|
|
|
+ update_current_position_xyz();
|
|
|
+ if (! endstop_z_hit_on_purpose()) {
|
|
|
+ continue;
|
|
|
+ /*
|
|
|
+ current_position[X_AXIS] = center_old_x;
|
|
|
+ SERIAL_PROTOCOLPGM("Failed 3\n");
|
|
|
+ goto canceled;
|
|
|
+ */
|
|
|
+ }
|
|
|
+ a = current_position[X_AXIS];
|
|
|
+ enable_z_endstop(false);
|
|
|
+ go_xy(x1, y, homing_feedrate[X_AXIS] / 60.f);
|
|
|
+ enable_z_endstop(true);
|
|
|
+ go_xy(x0, y, homing_feedrate[X_AXIS] / 60.f);
|
|
|
+ update_current_position_xyz();
|
|
|
+ if (! endstop_z_hit_on_purpose()) {
|
|
|
+ continue;
|
|
|
+ /*
|
|
|
+ current_position[X_AXIS] = center_old_x;
|
|
|
+ SERIAL_PROTOCOLPGM("Failed 4\n");
|
|
|
+ goto canceled;
|
|
|
+ */
|
|
|
+ }
|
|
|
+ b = current_position[X_AXIS];
|
|
|
+ if (verbosity_level > 20) {
|
|
|
+ SERIAL_ECHOPGM("Measured left ");
|
|
|
+ MYSERIAL.print(a, 5);
|
|
|
+ SERIAL_ECHOPGM("right ");
|
|
|
+ MYSERIAL.print(b, 5);
|
|
|
+ SERIAL_ECHOPGM(", ");
|
|
|
+ MYSERIAL.print(y, 5);
|
|
|
+ SERIAL_ECHOPGM(", ");
|
|
|
+ MYSERIAL.print(current_position[Z_AXIS], 5);
|
|
|
+ SERIAL_ECHOLNPGM("");
|
|
|
+ }
|
|
|
+ float d = b - a;
|
|
|
+ if (d > dmax) {
|
|
|
+ xmax2 = 0.5f * (a + b);
|
|
|
+ dmax = d;
|
|
|
+ } else if (dmax > 0.) {
|
|
|
+ y1 = y + IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_STEP_FINE_Y;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // SERIAL_PROTOCOLPGM("ok 2\n");
|
|
|
+ // Go to the center.
|
|
|
enable_z_endstop(false);
|
|
|
- go_xy(x0, y, homing_feedrate[X_AXIS] / 60.f);
|
|
|
+ if (dmax == 0.f) {
|
|
|
+ // Found only the point going from ymin to ymax.
|
|
|
+ current_position[X_AXIS] = xmax1;
|
|
|
+ current_position[Y_AXIS] = y0;
|
|
|
+ } else {
|
|
|
+ // Both points found (from ymin to ymax and from ymax to ymin).
|
|
|
+ float p = 0.5f;
|
|
|
+ // If the first hit was on the machine boundary,
|
|
|
+ // give it a higher weight.
|
|
|
+ if (y0 == Y_MIN_POS_FOR_BED_CALIBRATION)
|
|
|
+ p = 0.75f;
|
|
|
+ current_position[X_AXIS] = p * xmax1 + (1.f - p) * xmax2;
|
|
|
+ current_position[Y_AXIS] = p * y0 + (1.f - p) * y1;
|
|
|
+ }
|
|
|
+ if (verbosity_level >= 20) {
|
|
|
+ SERIAL_ECHOPGM("Adjusted position: ");
|
|
|
+ SERIAL_ECHO(current_position[X_AXIS]);
|
|
|
+ SERIAL_ECHOPGM(", ");
|
|
|
+ SERIAL_ECHO(current_position[Y_AXIS]);
|
|
|
+ SERIAL_ECHOLNPGM("");
|
|
|
+ }
|
|
|
+ go_xy(current_position[X_AXIS], current_position[Y_AXIS], homing_feedrate[X_AXIS] / 60.f);
|
|
|
+ // delay_keep_alive(3000);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Try yet to improve the X position.
|
|
|
+ {
|
|
|
+ float x0 = current_position[X_AXIS] - IMPROVE_BED_INDUCTION_SENSOR_SEARCH_RADIUS;
|
|
|
+ float x1 = current_position[X_AXIS] + IMPROVE_BED_INDUCTION_SENSOR_SEARCH_RADIUS;
|
|
|
+ if (x0 < X_MIN_POS)
|
|
|
+ x0 = X_MIN_POS;
|
|
|
+ if (x1 > X_MAX_POS)
|
|
|
+ x1 = X_MAX_POS;
|
|
|
+
|
|
|
+ // Search in the X direction along a cross.
|
|
|
+ enable_z_endstop(false);
|
|
|
+ go_xy(x0, current_position[Y_AXIS], homing_feedrate[X_AXIS] / 60.f);
|
|
|
enable_z_endstop(true);
|
|
|
- go_xy(x1, y, homing_feedrate[X_AXIS] / 60.f);
|
|
|
+ go_xy(x1, current_position[Y_AXIS], homing_feedrate[X_AXIS] / 60.f);
|
|
|
update_current_position_xyz();
|
|
|
if (! endstop_z_hit_on_purpose()) {
|
|
|
- // SERIAL_PROTOCOLPGM("Failed 1\n");
|
|
|
current_position[X_AXIS] = center_old_x;
|
|
|
goto canceled;
|
|
|
}
|
|
|
a = current_position[X_AXIS];
|
|
|
enable_z_endstop(false);
|
|
|
- go_xy(x1, y, homing_feedrate[X_AXIS] / 60.f);
|
|
|
+ go_xy(x1, current_position[Y_AXIS], homing_feedrate[X_AXIS] / 60.f);
|
|
|
enable_z_endstop(true);
|
|
|
- go_xy(x0, y, homing_feedrate[X_AXIS] / 60.f);
|
|
|
+ go_xy(x0, current_position[Y_AXIS], homing_feedrate[X_AXIS] / 60.f);
|
|
|
update_current_position_xyz();
|
|
|
if (! endstop_z_hit_on_purpose()) {
|
|
|
- // SERIAL_PROTOCOLPGM("Failed 2\n");
|
|
|
current_position[X_AXIS] = center_old_x;
|
|
|
goto canceled;
|
|
|
}
|
|
|
b = current_position[X_AXIS];
|
|
|
- float d = b - a;
|
|
|
- if (d > dmax) {
|
|
|
- xmax1 = 0.5f * (a + b);
|
|
|
- dmax = d;
|
|
|
- } else {
|
|
|
- y0 = y - IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_STEP_FINE_Y;
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- if (dmax == 0.) {
|
|
|
- // SERIAL_PROTOCOLPGM("failed - not found\n");
|
|
|
- goto canceled;
|
|
|
+
|
|
|
+ // Go to the center.
|
|
|
+ enable_z_endstop(false);
|
|
|
+ current_position[X_AXIS] = 0.5f * (a + b);
|
|
|
+ go_xy(current_position[X_AXIS], current_position[Y_AXIS], homing_feedrate[X_AXIS] / 60.f);
|
|
|
}
|
|
|
|
|
|
- // SERIAL_PROTOCOLPGM("ok 1\n");
|
|
|
- // Search in the X direction along a cross.
|
|
|
- dmax = 0.;
|
|
|
- if (y0 + 1.f < y1)
|
|
|
- y1 = y0 + 1.f;
|
|
|
- for (float y = y1; y >= y0; y -= IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_STEP_FINE_Y) {
|
|
|
+ return true;
|
|
|
+
|
|
|
+canceled:
|
|
|
+ // Go back to the center.
|
|
|
+ enable_z_endstop(false);
|
|
|
+ go_xy(current_position[X_AXIS], current_position[Y_AXIS], homing_feedrate[X_AXIS] / 60.f);
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
+// Scan the mesh bed induction points one by one by a left-right zig-zag movement,
|
|
|
+// write the trigger coordinates to the serial line.
|
|
|
+// Useful for visualizing the behavior of the bed induction detector.
|
|
|
+inline void scan_bed_induction_sensor_point()
|
|
|
+{
|
|
|
+ float center_old_x = current_position[X_AXIS];
|
|
|
+ float center_old_y = current_position[Y_AXIS];
|
|
|
+ float x0 = center_old_x - IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_RADIUS;
|
|
|
+ float x1 = center_old_x + IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_RADIUS;
|
|
|
+ float y0 = center_old_y - IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_RADIUS;
|
|
|
+ float y1 = center_old_y + IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_RADIUS;
|
|
|
+ float y = y0;
|
|
|
+
|
|
|
+ if (x0 < X_MIN_POS)
|
|
|
+ x0 = X_MIN_POS;
|
|
|
+ if (x1 > X_MAX_POS)
|
|
|
+ x1 = X_MAX_POS;
|
|
|
+ if (y0 < Y_MIN_POS_FOR_BED_CALIBRATION)
|
|
|
+ y0 = Y_MIN_POS_FOR_BED_CALIBRATION;
|
|
|
+ if (y1 > Y_MAX_POS)
|
|
|
+ y1 = Y_MAX_POS;
|
|
|
+
|
|
|
+ for (float y = y0; y < y1; y += IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_STEP_FINE_Y) {
|
|
|
enable_z_endstop(false);
|
|
|
go_xy(x0, y, homing_feedrate[X_AXIS] / 60.f);
|
|
|
enable_z_endstop(true);
|
|
|
go_xy(x1, y, homing_feedrate[X_AXIS] / 60.f);
|
|
|
update_current_position_xyz();
|
|
|
- if (! endstop_z_hit_on_purpose()) {
|
|
|
- continue;
|
|
|
- /*
|
|
|
- current_position[X_AXIS] = center_old_x;
|
|
|
- SERIAL_PROTOCOLPGM("Failed 3\n");
|
|
|
- goto canceled;
|
|
|
- */
|
|
|
+ if (endstop_z_hit_on_purpose()) {
|
|
|
+ SERIAL_ECHOPGM("Measured left: ");
|
|
|
+ MYSERIAL.print(current_position[X_AXIS], 5);
|
|
|
+ SERIAL_ECHOPGM(", ");
|
|
|
+ MYSERIAL.print(y, 5);
|
|
|
+ SERIAL_ECHOPGM(", ");
|
|
|
+ MYSERIAL.print(current_position[Z_AXIS], 5);
|
|
|
+ SERIAL_ECHOLNPGM("");
|
|
|
}
|
|
|
- a = current_position[X_AXIS];
|
|
|
enable_z_endstop(false);
|
|
|
go_xy(x1, y, homing_feedrate[X_AXIS] / 60.f);
|
|
|
enable_z_endstop(true);
|
|
|
go_xy(x0, y, homing_feedrate[X_AXIS] / 60.f);
|
|
|
update_current_position_xyz();
|
|
|
- if (! endstop_z_hit_on_purpose()) {
|
|
|
- continue;
|
|
|
- /*
|
|
|
- current_position[X_AXIS] = center_old_x;
|
|
|
- SERIAL_PROTOCOLPGM("Failed 4\n");
|
|
|
- goto canceled;
|
|
|
- */
|
|
|
- }
|
|
|
- b = current_position[X_AXIS];
|
|
|
- float d = b - a;
|
|
|
- if (d > dmax) {
|
|
|
- xmax2 = 0.5f * (a + b);
|
|
|
- dmax = d;
|
|
|
- } else {
|
|
|
- y1 = y + IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_STEP_FINE_Y;
|
|
|
- break;
|
|
|
+ if (endstop_z_hit_on_purpose()) {
|
|
|
+ SERIAL_ECHOPGM("Measured right: ");
|
|
|
+ MYSERIAL.print(current_position[X_AXIS], 5);
|
|
|
+ SERIAL_ECHOPGM(", ");
|
|
|
+ MYSERIAL.print(y, 5);
|
|
|
+ SERIAL_ECHOPGM(", ");
|
|
|
+ MYSERIAL.print(current_position[Z_AXIS], 5);
|
|
|
+ SERIAL_ECHOLNPGM("");
|
|
|
}
|
|
|
}
|
|
|
- // SERIAL_PROTOCOLPGM("ok 2\n");
|
|
|
- // Go to the center.
|
|
|
- enable_z_endstop(false);
|
|
|
- if (dmax == 0.f) {
|
|
|
- // Found only the point going from ymin to ymax.
|
|
|
- current_position[X_AXIS] = xmax1;
|
|
|
- current_position[Y_AXIS] = y0;
|
|
|
- } else {
|
|
|
- // Both points found (from ymin to ymax and from ymax to ymin).
|
|
|
- float p = 0.5f;
|
|
|
- // If the first hit was on the machine boundary,
|
|
|
- // give it a higher weight.
|
|
|
- if (y0 == Y_MIN_POS_FOR_BED_CALIBRATION)
|
|
|
- p = 0.75f;
|
|
|
- current_position[X_AXIS] = p * xmax1 + (1.f - p) * xmax2;
|
|
|
- current_position[Y_AXIS] = p * y0 + (1.f - p) * y1;
|
|
|
- }
|
|
|
- /*
|
|
|
- SERIAL_ECHOPGM("Adjusted position: ");
|
|
|
- SERIAL_ECHO(current_position[X_AXIS]);
|
|
|
- SERIAL_ECHOPGM(", ");
|
|
|
- SERIAL_ECHO(current_position[Y_AXIS]);
|
|
|
- SERIAL_ECHOLNPGM("");
|
|
|
- */
|
|
|
- go_xy(current_position[X_AXIS], current_position[Y_AXIS], homing_feedrate[X_AXIS] / 60.f);
|
|
|
- // delay_keep_alive(3000);
|
|
|
- return true;
|
|
|
|
|
|
-canceled:
|
|
|
- // Go back to the center.
|
|
|
enable_z_endstop(false);
|
|
|
+ current_position[X_AXIS] = center_old_x;
|
|
|
+ current_position[Y_AXIS] = center_old_y;
|
|
|
go_xy(current_position[X_AXIS], current_position[Y_AXIS], homing_feedrate[X_AXIS] / 60.f);
|
|
|
- return false;
|
|
|
}
|
|
|
|
|
|
#define MESH_BED_CALIBRATION_SHOW_LCD
|
|
@@ -1089,9 +1537,10 @@ bool find_bed_offset_and_skew(int8_t verbosity_level)
|
|
|
find_bed_induction_sensor_point_z();
|
|
|
#if 1
|
|
|
if (k == 0) {
|
|
|
+ // Improve the position of the 1st row sensor points by a zig-zag movement.
|
|
|
int8_t i = 4;
|
|
|
for (;;) {
|
|
|
- if (improve_bed_induction_sensor_point3())
|
|
|
+ if (improve_bed_induction_sensor_point3(verbosity_level))
|
|
|
break;
|
|
|
if (-- i == 0)
|
|
|
return false;
|
|
@@ -1251,9 +1700,22 @@ bool improve_bed_offset_and_skew(int8_t method, int8_t verbosity_level)
|
|
|
// Improve the point position by searching its center in a current plane.
|
|
|
int8_t n_errors = 3;
|
|
|
for (int8_t iter = 0; iter < 8; ) {
|
|
|
+ if (verbosity_level > 20) {
|
|
|
+ SERIAL_ECHOPGM("Improving bed point ");
|
|
|
+ SERIAL_ECHO(mesh_point);
|
|
|
+ SERIAL_ECHOPGM(", iteration ");
|
|
|
+ SERIAL_ECHO(iter);
|
|
|
+ SERIAL_ECHOPGM(", z");
|
|
|
+ MYSERIAL.print(current_position[Z_AXIS], 5);
|
|
|
+ SERIAL_ECHOLNPGM("");
|
|
|
+ }
|
|
|
bool found = false;
|
|
|
if (mesh_point < 3) {
|
|
|
- found = improve_bed_induction_sensor_point3();
|
|
|
+ // Because the sensor cannot move in front of the first row
|
|
|
+ // of the sensor points, the y position cannot be measured
|
|
|
+ // by a cross center method.
|
|
|
+ // Use a zig-zag search for the first row of the points.
|
|
|
+ found = improve_bed_induction_sensor_point3(verbosity_level);
|
|
|
} else {
|
|
|
switch (method) {
|
|
|
case 0: found = improve_bed_induction_sensor_point(); break;
|
|
@@ -1277,6 +1739,15 @@ bool improve_bed_offset_and_skew(int8_t method, int8_t verbosity_level)
|
|
|
enable_endstops(false);
|
|
|
enable_z_endstop(false);
|
|
|
go_to_current(homing_feedrate[Z_AXIS]);
|
|
|
+ if (verbosity_level > 20) {
|
|
|
+ SERIAL_ECHOPGM("Improving bed point ");
|
|
|
+ SERIAL_ECHO(mesh_point);
|
|
|
+ SERIAL_ECHOPGM(", iteration ");
|
|
|
+ SERIAL_ECHO(iter);
|
|
|
+ SERIAL_ECHOPGM(" failed. Lowering z to ");
|
|
|
+ MYSERIAL.print(current_position[Z_AXIS], 5);
|
|
|
+ SERIAL_ECHOLNPGM("");
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
if (verbosity_level >= 10)
|
|
@@ -1303,6 +1774,17 @@ bool improve_bed_offset_and_skew(int8_t method, int8_t verbosity_level)
|
|
|
current_position[Y_AXIS] = pts[mesh_point*2+1];
|
|
|
go_to_current(homing_feedrate[X_AXIS]/60);
|
|
|
delay_keep_alive(3000);
|
|
|
+ #if 0
|
|
|
+ if (verbosity_level > 20) {
|
|
|
+ SERIAL_ECHOPGM("Final measured bed point ");
|
|
|
+ SERIAL_ECHO(mesh_point);
|
|
|
+ SERIAL_ECHOPGM(": ");
|
|
|
+ MYSERIAL.print(current_position[X_AXIS], 5);
|
|
|
+ SERIAL_ECHOPGM(", ");
|
|
|
+ MYSERIAL.print(current_position[Y_AXIS], 5);
|
|
|
+ SERIAL_ECHOLNPGM("");
|
|
|
+ }
|
|
|
+ #endif
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -1341,6 +1823,17 @@ bool improve_bed_offset_and_skew(int8_t method, int8_t verbosity_level)
|
|
|
current_position[Y_AXIS] = pgm_read_float(bed_ref_points+mesh_point*2+1);
|
|
|
go_to_current(homing_feedrate[X_AXIS]/60);
|
|
|
delay_keep_alive(3000);
|
|
|
+ #if 0
|
|
|
+ if (verbosity_level > 20) {
|
|
|
+ SERIAL_ECHOPGM("Final calculated bed point ");
|
|
|
+ SERIAL_ECHO(mesh_point);
|
|
|
+ SERIAL_ECHOPGM(": ");
|
|
|
+ MYSERIAL.print(st_get_position_mm(X_AXIS), 5);
|
|
|
+ SERIAL_ECHOPGM(", ");
|
|
|
+ MYSERIAL.print(st_get_position_mm(Y_AXIS), 5);
|
|
|
+ SERIAL_ECHOLNPGM("");
|
|
|
+ }
|
|
|
+ #endif
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -1360,3 +1853,65 @@ canceled:
|
|
|
enable_z_endstop(endstop_z_enabled);
|
|
|
return false;
|
|
|
}
|
|
|
+
|
|
|
+bool scan_bed_induction_points(int8_t verbosity_level)
|
|
|
+{
|
|
|
+ // Don't let the manage_inactivity() function remove power from the motors.
|
|
|
+ refresh_cmd_timeout();
|
|
|
+
|
|
|
+ // Reusing the z_values memory for the measurement cache.
|
|
|
+ // 7x7=49 floats, good for 16 (x,y,z) vectors.
|
|
|
+ float *pts = &mbl.z_values[0][0];
|
|
|
+ float *vec_x = pts + 2 * 9;
|
|
|
+ float *vec_y = vec_x + 2;
|
|
|
+ float *cntr = vec_y + 2;
|
|
|
+ memset(pts, 0, sizeof(float) * 7 * 7);
|
|
|
+
|
|
|
+ // Cache the current correction matrix.
|
|
|
+ world2machine_initialize();
|
|
|
+ vec_x[0] = world2machine_rotation_and_skew[0][0];
|
|
|
+ vec_x[1] = world2machine_rotation_and_skew[1][0];
|
|
|
+ vec_y[0] = world2machine_rotation_and_skew[0][1];
|
|
|
+ vec_y[1] = world2machine_rotation_and_skew[1][1];
|
|
|
+ cntr[0] = world2machine_shift[0];
|
|
|
+ cntr[1] = world2machine_shift[1];
|
|
|
+ // and reset the correction matrix, so the planner will not do anything.
|
|
|
+ world2machine_reset();
|
|
|
+
|
|
|
+ bool endstops_enabled = enable_endstops(false);
|
|
|
+ bool endstop_z_enabled = enable_z_endstop(false);
|
|
|
+
|
|
|
+ // Collect a matrix of 9x9 points.
|
|
|
+ for (int8_t mesh_point = 0; mesh_point < 9; ++ mesh_point) {
|
|
|
+ // Don't let the manage_inactivity() function remove power from the motors.
|
|
|
+ refresh_cmd_timeout();
|
|
|
+
|
|
|
+ // Move up.
|
|
|
+ current_position[Z_AXIS] = MESH_HOME_Z_SEARCH;
|
|
|
+ enable_endstops(false);
|
|
|
+ enable_z_endstop(false);
|
|
|
+ go_to_current(homing_feedrate[Z_AXIS]/60);
|
|
|
+ // Go to the measurement point.
|
|
|
+ // Use the coorrected coordinate, which is a result of find_bed_offset_and_skew().
|
|
|
+ current_position[X_AXIS] = vec_x[0] * pgm_read_float(bed_ref_points+mesh_point*2) + vec_y[0] * pgm_read_float(bed_ref_points+mesh_point*2+1) + cntr[0];
|
|
|
+ current_position[Y_AXIS] = vec_x[1] * pgm_read_float(bed_ref_points+mesh_point*2) + vec_y[1] * pgm_read_float(bed_ref_points+mesh_point*2+1) + cntr[1];
|
|
|
+ // The calibration points are very close to the min Y.
|
|
|
+ if (current_position[Y_AXIS] < Y_MIN_POS_FOR_BED_CALIBRATION)
|
|
|
+ current_position[Y_AXIS] = Y_MIN_POS_FOR_BED_CALIBRATION;
|
|
|
+ go_to_current(homing_feedrate[X_AXIS]/60);
|
|
|
+ find_bed_induction_sensor_point_z();
|
|
|
+ scan_bed_induction_sensor_point();
|
|
|
+ }
|
|
|
+ // Don't let the manage_inactivity() function remove power from the motors.
|
|
|
+ refresh_cmd_timeout();
|
|
|
+
|
|
|
+ enable_endstops(false);
|
|
|
+ enable_z_endstop(false);
|
|
|
+
|
|
|
+ // Don't let the manage_inactivity() function remove power from the motors.
|
|
|
+ refresh_cmd_timeout();
|
|
|
+
|
|
|
+ enable_endstops(endstops_enabled);
|
|
|
+ enable_z_endstop(endstop_z_enabled);
|
|
|
+ return true;
|
|
|
+}
|