Marcio Teixeira
6 years ago
committed by
Scott Lahteine
77 changed files with 4334 additions and 3 deletions
@ -0,0 +1,639 @@ |
|||||
|
/**
|
||||
|
* Marlin 3D Printer Firmware |
||||
|
* Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
|
||||
|
* |
||||
|
* Based on Sprinter and grbl. |
||||
|
* Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm |
||||
|
* |
||||
|
* This program is free software: you can redistribute it and/or modify |
||||
|
* it under the terms of the GNU General Public License as published by |
||||
|
* the Free Software Foundation, either version 3 of the License, or |
||||
|
* (at your option) any later version. |
||||
|
* |
||||
|
* This program is distributed in the hope that it will be useful, |
||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
* GNU General Public License for more details. |
||||
|
* |
||||
|
* You should have received a copy of the GNU General Public License |
||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
* |
||||
|
*/ |
||||
|
|
||||
|
#include "../../Marlin.h" |
||||
|
|
||||
|
#if ENABLED(CALIBRATION_GCODE) |
||||
|
|
||||
|
#include "../gcode.h" |
||||
|
#include "../../lcd/ultralcd.h" |
||||
|
#include "../../module/motion.h" |
||||
|
#include "../../module/planner.h" |
||||
|
#include "../../module/tool_change.h" |
||||
|
#include "../../module/endstops.h" |
||||
|
|
||||
|
/**
|
||||
|
* G425 backs away from the calibration object by various distances |
||||
|
* depending on the confidence level: |
||||
|
* |
||||
|
* UNKNOWN - No real notion on where the calibration object is on the bed |
||||
|
* UNCERTAIN - Measurement may be uncertain due to backlash |
||||
|
* CERTAIN - Measurement obtained with backlash compensation |
||||
|
*/ |
||||
|
|
||||
|
#ifndef CALIBRATION_MEASUREMENT_UNKNOWN |
||||
|
#define CALIBRATION_MEASUREMENT_UNKNOWN 5.0 // mm
|
||||
|
#endif |
||||
|
#ifndef CALIBRATION_MEASUREMENT_UNCERTAIN |
||||
|
#define CALIBRATION_MEASUREMENT_UNCERTAIN 1.0 // mm
|
||||
|
#endif |
||||
|
#ifndef CALIBRATION_MEASUREMENT_CERTAIN |
||||
|
#define CALIBRATION_MEASUREMENT_CERTAIN 0.5 // mm
|
||||
|
#endif |
||||
|
|
||||
|
#define HAS_X_CENTER (ENABLED(CALIBRATION_MEASURE_LEFT) && ENABLED(CALIBRATION_MEASURE_RIGHT)) |
||||
|
#define HAS_Y_CENTER (ENABLED(CALIBRATION_MEASURE_FRONT) && ENABLED(CALIBRATION_MEASURE_BACK)) |
||||
|
|
||||
|
#if ENABLED(BACKLASH_GCODE) |
||||
|
extern float backlash_distance_mm[], backlash_correction, backlash_smoothing_mm; |
||||
|
#endif |
||||
|
|
||||
|
enum side_t : uint8_t { TOP, RIGHT, FRONT, LEFT, BACK, NUM_SIDES }; |
||||
|
|
||||
|
struct measurements_t { |
||||
|
static const float dimensions[XYZ]; |
||||
|
static const float true_center[XYZ]; // This cannot be constexpr since it is accessed by index in probe_side
|
||||
|
float obj_center[XYZ] = CALIBRATION_OBJECT_CENTER; |
||||
|
float obj_side[NUM_SIDES]; |
||||
|
|
||||
|
float backlash[NUM_SIDES]; |
||||
|
float pos_error[XYZ]; |
||||
|
|
||||
|
float nozzle_outer_dimension[2] = {CALIBRATION_NOZZLE_OUTER_DIAMETER, CALIBRATION_NOZZLE_OUTER_DIAMETER}; |
||||
|
}; |
||||
|
|
||||
|
const float measurements_t::true_center[XYZ] = CALIBRATION_OBJECT_CENTER; |
||||
|
|
||||
|
const float measurements_t::dimensions[] = CALIBRATION_OBJECT_DIMENSIONS; |
||||
|
|
||||
|
#define TEMPORARY_ENDSTOP_STATE(enable) REMEMBER(tes, soft_endstops_enabled, enable); TemporaryGlobalEndstopsState tges(enable) |
||||
|
|
||||
|
#if ENABLED(BACKLASH_GCODE) |
||||
|
#define TEMPORARY_BACKLASH_STATE(enable) REMEMBER(tbst, backlash_correction, enable) |
||||
|
#else |
||||
|
#define TEMPORARY_BACKLASH_STATE(enable) |
||||
|
#endif |
||||
|
|
||||
|
#if ENABLED(BACKLASH_GCODE) && defined(BACKLASH_SMOOTHING_MM) |
||||
|
#define TEMPORARY_BACKLASH_SMOOTHING(value) REMEMBER(tbsm, backlash_smoothing_mm, value) |
||||
|
#else |
||||
|
#define TEMPORARY_BACKLASH_SMOOTHING(value) |
||||
|
#endif |
||||
|
|
||||
|
/**
|
||||
|
* Move to a particular location. Up to three individual axes |
||||
|
* and their destinations can be specified, in any order. |
||||
|
*/ |
||||
|
inline void move_to( |
||||
|
const AxisEnum a1 = NO_AXIS, const float p1 = 0, |
||||
|
const AxisEnum a2 = NO_AXIS, const float p2 = 0, |
||||
|
const AxisEnum a3 = NO_AXIS, const float p3 = 0 |
||||
|
) { |
||||
|
set_destination_from_current(); |
||||
|
|
||||
|
// Note: The order of p1, p2, p3 may not correspond to X, Y, Z
|
||||
|
if (a1 != NO_AXIS) destination[a1] = p1; |
||||
|
if (a2 != NO_AXIS) destination[a2] = p2; |
||||
|
if (a3 != NO_AXIS) destination[a3] = p3; |
||||
|
|
||||
|
// Make sure coordinates are within bounds
|
||||
|
destination[X_AXIS] = MAX(MIN(destination[X_AXIS], X_MAX_POS), X_MIN_POS); |
||||
|
destination[Y_AXIS] = MAX(MIN(destination[Y_AXIS], Y_MAX_POS), Y_MIN_POS); |
||||
|
destination[Z_AXIS] = MAX(MIN(destination[Z_AXIS], Z_MAX_POS), Z_MIN_POS); |
||||
|
|
||||
|
// Move to position
|
||||
|
do_blocking_move_to(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], MMM_TO_MMS(CALIBRATION_FEEDRATE_TRAVEL)); |
||||
|
} |
||||
|
|
||||
|
/**
|
||||
|
* Move to the exact center above the calibration object |
||||
|
* |
||||
|
* m in - Measurement record |
||||
|
* uncertainty in - How far away from the object top to park |
||||
|
*/ |
||||
|
inline void park_above_object(measurements_t &m, const float uncertainty) { |
||||
|
/* Move to safe distance above calibration object */ |
||||
|
move_to(Z_AXIS, m.obj_center[Z_AXIS] + m.dimensions[Z_AXIS] / 2 + uncertainty); |
||||
|
|
||||
|
/* Move to center of calibration object in XY */ |
||||
|
move_to(X_AXIS, m.obj_center[X_AXIS], Y_AXIS, m.obj_center[Y_AXIS]); |
||||
|
} |
||||
|
|
||||
|
#if HOTENDS > 1 |
||||
|
|
||||
|
inline void set_nozzle(measurements_t &m, const uint8_t extruder) { |
||||
|
if (extruder != active_extruder) { |
||||
|
park_above_object(m, CALIBRATION_MEASUREMENT_UNKNOWN); |
||||
|
tool_change(extruder); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
inline void reset_nozzle_offsets() { |
||||
|
constexpr float tmp[XYZ][HOTENDS] = { HOTEND_OFFSET_X, HOTEND_OFFSET_Y, HOTEND_OFFSET_Z }; |
||||
|
LOOP_XYZ(i) HOTEND_LOOP() hotend_offset[i][e] = tmp[i][e]; |
||||
|
} |
||||
|
|
||||
|
inline void normalize_hotend_offsets() { |
||||
|
for (uint8_t e = 1; e < HOTENDS; e++) { |
||||
|
hotend_offset[X_AXIS][e] -= hotend_offset[X_AXIS][0]; |
||||
|
hotend_offset[Y_AXIS][e] -= hotend_offset[Y_AXIS][0]; |
||||
|
hotend_offset[Z_AXIS][e] -= hotend_offset[Z_AXIS][0]; |
||||
|
} |
||||
|
hotend_offset[X_AXIS][0] = 0; |
||||
|
hotend_offset[Y_AXIS][0] = 0; |
||||
|
hotend_offset[Z_AXIS][0] = 0; |
||||
|
} |
||||
|
|
||||
|
#endif // HOTENDS > 1
|
||||
|
|
||||
|
inline bool read_calibration_pin() { |
||||
|
#if HAS_CALIBRATION_PIN |
||||
|
return (READ(CALIBRATION_PIN) != CALIBRATION_PIN_INVERTING); |
||||
|
#elif ENABLED(Z_MIN_PROBE_USES_Z_MIN_ENDSTOP_PIN) |
||||
|
return (READ(Z_MIN_PIN) != Z_MIN_ENDSTOP_INVERTING); |
||||
|
#else |
||||
|
return (READ(Z_MIN_PROBE_PIN) != Z_MIN_PROBE_ENDSTOP_INVERTING); |
||||
|
#endif |
||||
|
} |
||||
|
|
||||
|
/**
|
||||
|
* Move along axis in the specified dir until the probe value becomes stop_state, |
||||
|
* then return the axis value. |
||||
|
* |
||||
|
* axis in - Axis along which the measurement will take place |
||||
|
* dir in - Direction along that axis (-1 or 1) |
||||
|
* stop_state in - Move until probe pin becomes this value |
||||
|
* fast in - Fast vs. precise measurement |
||||
|
*/ |
||||
|
float measuring_movement(const AxisEnum axis, const int dir, const bool stop_state, const bool fast) { |
||||
|
const float step = fast ? 0.25 : CALIBRATION_MEASUREMENT_RESOLUTION; |
||||
|
const float mms = MMM_TO_MMS(fast ? CALIBRATION_FEEDRATE_FAST : CALIBRATION_FEEDRATE_SLOW); |
||||
|
const float limit = fast ? 50 : 5; |
||||
|
|
||||
|
set_destination_from_current(); |
||||
|
for (float travel = 0; travel < limit; travel += step) { |
||||
|
destination[axis] += dir * step; |
||||
|
do_blocking_move_to(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], mms); |
||||
|
planner.synchronize(); |
||||
|
if (read_calibration_pin() == stop_state) |
||||
|
break; |
||||
|
} |
||||
|
return destination[axis]; |
||||
|
} |
||||
|
|
||||
|
/**
|
||||
|
* Move along axis until the probe is triggered. Move toolhead to its starting |
||||
|
* point and return the measured value. |
||||
|
* |
||||
|
* axis in - Axis along which the measurement will take place |
||||
|
* dir in - Direction along that axis (-1 or 1) |
||||
|
* stop_state in - Move until probe pin becomes this value |
||||
|
* backlash_ptr in/out - When not NULL, measure and record axis backlash |
||||
|
* uncertainty in - If uncertainty is CALIBRATION_MEASUREMENT_UNKNOWN, do a fast probe. |
||||
|
*/ |
||||
|
inline float measure(const AxisEnum axis, const int dir, const bool stop_state, float * const backlash_ptr, const float uncertainty) { |
||||
|
const bool fast = uncertainty == CALIBRATION_MEASUREMENT_UNKNOWN; |
||||
|
|
||||
|
// Save position
|
||||
|
set_destination_from_current(); |
||||
|
const float start_pos = destination[axis]; |
||||
|
const float measured_pos = measuring_movement(axis, dir, stop_state, fast); |
||||
|
// Measure backlash
|
||||
|
if (backlash_ptr && !fast) { |
||||
|
const float release_pos = measuring_movement(axis, -dir, !stop_state, fast); |
||||
|
*backlash_ptr = ABS(release_pos - measured_pos); |
||||
|
} |
||||
|
// Return to starting position
|
||||
|
destination[axis] = start_pos; |
||||
|
do_blocking_move_to(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], MMM_TO_MMS(CALIBRATION_FEEDRATE_TRAVEL)); |
||||
|
return measured_pos; |
||||
|
} |
||||
|
|
||||
|
/**
|
||||
|
* Probe one side of the calibration object |
||||
|
* |
||||
|
* m in/out - Measurement record, m.obj_center and m.obj_side will be updated. |
||||
|
* uncertainty in - How far away from the calibration object to begin probing |
||||
|
* side in - Side of probe where probe will occur |
||||
|
* probe_top_at_edge in - When probing sides, probe top of calibration object nearest edge |
||||
|
* to find out height of edge |
||||
|
*/ |
||||
|
inline void probe_side(measurements_t &m, const float uncertainty, const side_t side, const bool probe_top_at_edge=false) { |
||||
|
AxisEnum axis; |
||||
|
float dir; |
||||
|
|
||||
|
park_above_object(m, uncertainty); |
||||
|
|
||||
|
switch(side) { |
||||
|
case TOP: { |
||||
|
const float measurement = measure(Z_AXIS, -1, true, &m.backlash[TOP], uncertainty); |
||||
|
m.obj_center[Z_AXIS] = measurement - m.dimensions[Z_AXIS] / 2; |
||||
|
m.obj_side[TOP] = measurement; |
||||
|
return; |
||||
|
} |
||||
|
case RIGHT: axis = X_AXIS; dir = -1; break; |
||||
|
case FRONT: axis = Y_AXIS; dir = 1; break; |
||||
|
case LEFT: axis = X_AXIS; dir = 1; break; |
||||
|
case BACK: axis = Y_AXIS; dir = -1; break; |
||||
|
default: |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
if (probe_top_at_edge) { |
||||
|
// Probe top nearest the side we are probing
|
||||
|
move_to(axis, m.obj_center[axis] + (-dir) * (m.dimensions[axis] / 2 - m.nozzle_outer_dimension[axis])); |
||||
|
m.obj_side[TOP] = measure(Z_AXIS, -1, true, &m.backlash[TOP], uncertainty); |
||||
|
m.obj_center[Z_AXIS] = m.obj_side[TOP] - m.dimensions[Z_AXIS] / 2; |
||||
|
} |
||||
|
|
||||
|
// Move to safe distance to the side of the calibration object
|
||||
|
move_to(axis, m.obj_center[axis] + (-dir) * (m.dimensions[axis] / 2 + m.nozzle_outer_dimension[axis] / 2 + uncertainty)); |
||||
|
|
||||
|
// Plunge below the side of the calibration object and measure
|
||||
|
move_to(Z_AXIS, m.obj_side[TOP] - CALIBRATION_NOZZLE_TIP_HEIGHT * 0.7); |
||||
|
const float measurement = measure(axis, dir, true, &m.backlash[side], uncertainty); |
||||
|
m.obj_center[axis] = measurement + dir * (m.dimensions[axis] / 2 + m.nozzle_outer_dimension[axis] / 2); |
||||
|
m.obj_side[side] = measurement; |
||||
|
} |
||||
|
|
||||
|
/**
|
||||
|
* Probe all sides of the calibration calibration object |
||||
|
* |
||||
|
* m in/out - Measurement record: center, backlash and error values be updated. |
||||
|
* uncertainty in - How far away from the calibration object to begin probing |
||||
|
*/ |
||||
|
inline void probe_sides(measurements_t &m, const float uncertainty) { |
||||
|
TEMPORARY_ENDSTOP_STATE(false); |
||||
|
|
||||
|
#ifdef CALIBRATION_MEASURE_AT_TOP_EDGES |
||||
|
constexpr bool probe_top_at_edge = true; |
||||
|
#else |
||||
|
/* Probing at the exact center only works if the center is flat. Probing on a washer
|
||||
|
* or bolt will require probing the top near the side edges, away from the center. |
||||
|
*/ |
||||
|
constexpr bool probe_top_at_edge = false; |
||||
|
probe_side(m, uncertainty, TOP); |
||||
|
#endif |
||||
|
|
||||
|
#ifdef CALIBRATION_MEASURE_RIGHT |
||||
|
probe_side(m, uncertainty, RIGHT, probe_top_at_edge); |
||||
|
#endif |
||||
|
#ifdef CALIBRATION_MEASURE_FRONT |
||||
|
probe_side(m, uncertainty, FRONT, probe_top_at_edge); |
||||
|
#endif |
||||
|
#ifdef CALIBRATION_MEASURE_LEFT |
||||
|
probe_side(m, uncertainty, LEFT, probe_top_at_edge); |
||||
|
#endif |
||||
|
#ifdef CALIBRATION_MEASURE_BACK |
||||
|
probe_side(m, uncertainty, BACK, probe_top_at_edge); |
||||
|
#endif |
||||
|
|
||||
|
/* Compute the measured center of the calibration object. */ |
||||
|
#if HAS_X_CENTER |
||||
|
m.obj_center[X_AXIS] = (m.obj_side[LEFT] + m.obj_side[RIGHT]) / 2; |
||||
|
#endif |
||||
|
#if HAS_Y_CENTER |
||||
|
m.obj_center[Y_AXIS] = (m.obj_side[FRONT] + m.obj_side[BACK]) / 2; |
||||
|
#endif |
||||
|
|
||||
|
/* Compute the outside diameter of the nozzle at the height
|
||||
|
* at which it makes contact with the calibration object */ |
||||
|
#if HAS_X_CENTER |
||||
|
m.nozzle_outer_dimension[X_AXIS] = m.obj_side[RIGHT] - m.obj_side[LEFT] - m.dimensions[X_AXIS]; |
||||
|
#endif |
||||
|
#if HAS_Y_CENTER |
||||
|
m.nozzle_outer_dimension[Y_AXIS] = m.obj_side[BACK] - m.obj_side[FRONT] - m.dimensions[Y_AXIS]; |
||||
|
#endif |
||||
|
|
||||
|
park_above_object(m, uncertainty); |
||||
|
|
||||
|
/* The positional error is the difference between the known calibration
|
||||
|
* object location and the measured calibration object location */ |
||||
|
m.pos_error[X_AXIS] = |
||||
|
#if HAS_X_CENTER |
||||
|
m.true_center[X_AXIS] - m.obj_center[X_AXIS]; |
||||
|
#else |
||||
|
0; |
||||
|
#endif |
||||
|
m.pos_error[Y_AXIS] = |
||||
|
#if HAS_Y_CENTER |
||||
|
m.true_center[Y_AXIS] - m.obj_center[Y_AXIS]; |
||||
|
#else |
||||
|
0; |
||||
|
#endif |
||||
|
m.pos_error[Z_AXIS] = m.true_center[Z_AXIS] - m.obj_center[Z_AXIS]; |
||||
|
} |
||||
|
|
||||
|
#if ENABLED(CALIBRATION_REPORTING) |
||||
|
inline void report_measured_faces(const measurements_t &m) { |
||||
|
SERIAL_ECHOLNPGM("Sides:"); |
||||
|
SERIAL_ECHOLNPAIR(" Top: ", m.obj_side[TOP]); |
||||
|
#if ENABLED(CALIBRATION_MEASURE_LEFT) |
||||
|
SERIAL_ECHOLNPAIR(" Left: ", m.obj_side[LEFT]); |
||||
|
#endif |
||||
|
#if ENABLED(CALIBRATION_MEASURE_RIGHT) |
||||
|
SERIAL_ECHOLNPAIR(" Right: ", m.obj_side[RIGHT]); |
||||
|
#endif |
||||
|
#if ENABLED(CALIBRATION_MEASURE_FRONT) |
||||
|
SERIAL_ECHOLNPAIR(" Front: ", m.obj_side[FRONT]); |
||||
|
#endif |
||||
|
#if ENABLED(CALIBRATION_MEASURE_BACK) |
||||
|
SERIAL_ECHOLNPAIR(" Back: ", m.obj_side[BACK]); |
||||
|
#endif |
||||
|
SERIAL_EOL(); |
||||
|
} |
||||
|
|
||||
|
inline void report_measured_center(const measurements_t &m) { |
||||
|
SERIAL_ECHOLNPGM("Center:"); |
||||
|
#if HAS_X_CENTER |
||||
|
SERIAL_ECHOLNPAIR(" X", m.obj_center[X_AXIS]); |
||||
|
#endif |
||||
|
#if HAS_Y_CENTER |
||||
|
SERIAL_ECHOLNPAIR(" Y", m.obj_center[Y_AXIS]); |
||||
|
#endif |
||||
|
SERIAL_ECHOLNPAIR(" Z", m.obj_center[Z_AXIS]); |
||||
|
SERIAL_EOL(); |
||||
|
} |
||||
|
|
||||
|
inline void report_measured_backlash(const measurements_t &m) { |
||||
|
SERIAL_ECHOLNPGM("Backlash:"); |
||||
|
#if ENABLED(CALIBRATION_MEASURE_LEFT) |
||||
|
SERIAL_ECHOLNPAIR(" Left: ", m.backlash[LEFT]); |
||||
|
#endif |
||||
|
#if ENABLED(CALIBRATION_MEASURE_RIGHT) |
||||
|
SERIAL_ECHOLNPAIR(" Right: ", m.backlash[RIGHT]); |
||||
|
#endif |
||||
|
#if ENABLED(CALIBRATION_MEASURE_FRONT) |
||||
|
SERIAL_ECHOLNPAIR(" Front: ", m.backlash[FRONT]); |
||||
|
#endif |
||||
|
#if ENABLED(CALIBRATION_MEASURE_BACK) |
||||
|
SERIAL_ECHOLNPAIR(" Back: ", m.backlash[BACK]); |
||||
|
#endif |
||||
|
SERIAL_ECHOLNPAIR(" Top: ", m.backlash[TOP]); |
||||
|
SERIAL_EOL(); |
||||
|
} |
||||
|
|
||||
|
inline void report_measured_positional_error(const measurements_t &m) { |
||||
|
SERIAL_CHAR('T'); |
||||
|
SERIAL_ECHO(int(active_extruder)); |
||||
|
SERIAL_ECHOLNPGM(" Positional Error:"); |
||||
|
#if HAS_X_CENTER |
||||
|
SERIAL_ECHOLNPAIR(" X", m.pos_error[X_AXIS]); |
||||
|
#endif |
||||
|
#if HAS_Y_CENTER |
||||
|
SERIAL_ECHOLNPAIR(" Y", m.pos_error[Y_AXIS]); |
||||
|
#endif |
||||
|
SERIAL_ECHOLNPAIR(" Z", m.pos_error[Z_AXIS]); |
||||
|
SERIAL_EOL(); |
||||
|
} |
||||
|
|
||||
|
inline void report_measured_nozzle_dimensions(const measurements_t &m) { |
||||
|
SERIAL_ECHOLNPGM("Nozzle Tip Outer Dimensions:"); |
||||
|
#if HAS_X_CENTER |
||||
|
SERIAL_ECHOLNPAIR(" X", m.nozzle_outer_dimension[X_AXIS]); |
||||
|
#endif |
||||
|
#if HAS_Y_CENTER |
||||
|
SERIAL_ECHOLNPAIR(" Y", m.nozzle_outer_dimension[Y_AXIS]); |
||||
|
#endif |
||||
|
SERIAL_EOL(); |
||||
|
} |
||||
|
|
||||
|
#if HOTENDS > 1 |
||||
|
//
|
||||
|
// This function requires normalize_hotend_offsets() to be called
|
||||
|
//
|
||||
|
inline void report_hotend_offsets() { |
||||
|
for (uint8_t e = 1; e < HOTENDS; e++) { |
||||
|
SERIAL_ECHOPAIR("T", int(e)); |
||||
|
SERIAL_ECHOLNPGM(" Hotend Offset:"); |
||||
|
SERIAL_ECHOLNPAIR(" X: ", hotend_offset[X_AXIS][e]); |
||||
|
SERIAL_ECHOLNPAIR(" Y: ", hotend_offset[Y_AXIS][e]); |
||||
|
SERIAL_ECHOLNPAIR(" Z: ", hotend_offset[Z_AXIS][e]); |
||||
|
SERIAL_EOL(); |
||||
|
} |
||||
|
} |
||||
|
#endif |
||||
|
#endif // CALIBRATION_REPORTING
|
||||
|
|
||||
|
/**
|
||||
|
* Probe around the calibration object to measure backlash |
||||
|
* |
||||
|
* m in/out - Measurement record, updated with new readings |
||||
|
* uncertainty in - How far away from the object to begin probing |
||||
|
*/ |
||||
|
inline void calibrate_backlash(measurements_t &m, const float uncertainty) { |
||||
|
// Backlash compensation should be off while measuring backlash
|
||||
|
|
||||
|
{ |
||||
|
// New scope for TEMPORARY_BACKLASH_STATE
|
||||
|
TEMPORARY_BACKLASH_STATE(false); |
||||
|
TEMPORARY_BACKLASH_SMOOTHING(0); |
||||
|
|
||||
|
probe_sides(m, uncertainty); |
||||
|
|
||||
|
#if ENABLED(BACKLASH_GCODE) |
||||
|
#if HAS_X_CENTER |
||||
|
backlash_distance_mm[X_AXIS] = (m.backlash[LEFT] + m.backlash[RIGHT]) / 2; |
||||
|
#elif ENABLED(CALIBRATION_MEASURE_LEFT) |
||||
|
backlash_distance_mm[X_AXIS] = m.backlash[LEFT]; |
||||
|
#elif ENABLED(CALIBRATION_MEASURE_RIGHT) |
||||
|
backlash_distance_mm[X_AXIS] = m.backlash[RIGHT]; |
||||
|
#endif |
||||
|
|
||||
|
#if HAS_Y_CENTER |
||||
|
backlash_distance_mm[Y_AXIS] = (m.backlash[FRONT] + m.backlash[BACK]) / 2; |
||||
|
#elif ENABLED(CALIBRATION_MEASURE_FRONT) |
||||
|
backlash_distance_mm[Y_AXIS] = m.backlash[FRONT]; |
||||
|
#elif ENABLED(CALIBRATION_MEASURE_BACK) |
||||
|
backlash_distance_mm[Y_AXIS] = m.backlash[BACK]; |
||||
|
#endif |
||||
|
|
||||
|
backlash_distance_mm[Z_AXIS] = m.backlash[TOP]; |
||||
|
#endif |
||||
|
} |
||||
|
|
||||
|
#if ENABLED(BACKLASH_GCODE) |
||||
|
// Turn on backlash compensation and move in all
|
||||
|
// directions to take up any backlash
|
||||
|
|
||||
|
{ |
||||
|
// New scope for TEMPORARY_BACKLASH_STATE
|
||||
|
TEMPORARY_BACKLASH_STATE(true); |
||||
|
TEMPORARY_BACKLASH_SMOOTHING(0); |
||||
|
move_to( |
||||
|
X_AXIS, current_position[X_AXIS] + 3, |
||||
|
Y_AXIS, current_position[Y_AXIS] + 3, |
||||
|
Z_AXIS, current_position[Z_AXIS] + 3 |
||||
|
); |
||||
|
move_to( |
||||
|
X_AXIS, current_position[X_AXIS] - 3, |
||||
|
Y_AXIS, current_position[Y_AXIS] - 3, |
||||
|
Z_AXIS, current_position[Z_AXIS] - 3 |
||||
|
); |
||||
|
} |
||||
|
#endif |
||||
|
} |
||||
|
|
||||
|
inline void update_measurements(measurements_t &m, const AxisEnum axis) { |
||||
|
current_position[axis] += m.pos_error[axis]; |
||||
|
m.obj_center[axis] = m.true_center[axis]; |
||||
|
m.pos_error[axis] = 0; |
||||
|
} |
||||
|
|
||||
|
/**
|
||||
|
* Probe around the calibration object. Adjust the position and toolhead offset |
||||
|
* using the deviation from the known position of the calibration object. |
||||
|
* |
||||
|
* m in/out - Measurement record, updated with new readings |
||||
|
* uncertainty in - How far away from the object to begin probing |
||||
|
* extruder in - What extruder to probe |
||||
|
* |
||||
|
* Prerequisites: |
||||
|
* - Call calibrate_backlash() beforehand for best accuracy |
||||
|
*/ |
||||
|
inline void calibrate_toolhead(measurements_t &m, const float uncertainty, const uint8_t extruder) { |
||||
|
TEMPORARY_BACKLASH_STATE(true); |
||||
|
TEMPORARY_BACKLASH_SMOOTHING(0); |
||||
|
|
||||
|
#if HOTENDS > 1 |
||||
|
set_nozzle(m, extruder); |
||||
|
#endif |
||||
|
|
||||
|
probe_sides(m, uncertainty); |
||||
|
|
||||
|
/* Adjust the hotend offset */ |
||||
|
#if HOTENDS > 1 |
||||
|
#if HAS_X_CENTER |
||||
|
hotend_offset[X_AXIS][extruder] += m.pos_error[X_AXIS]; |
||||
|
#endif |
||||
|
#if HAS_Y_CENTER |
||||
|
hotend_offset[Y_AXIS][extruder] += m.pos_error[Y_AXIS]; |
||||
|
#endif |
||||
|
hotend_offset[Z_AXIS][extruder] += m.pos_error[Z_AXIS]; |
||||
|
|
||||
|
normalize_hotend_offsets(); |
||||
|
#endif |
||||
|
|
||||
|
// Correct for positional error, so the object
|
||||
|
// is at the known actual spot
|
||||
|
planner.synchronize(); |
||||
|
#if HAS_X_CENTER |
||||
|
update_measurements(m, X_AXIS); |
||||
|
#endif |
||||
|
#if HAS_Y_CENTER |
||||
|
update_measurements(m, Y_AXIS); |
||||
|
#endif |
||||
|
update_measurements(m, Z_AXIS); |
||||
|
|
||||
|
sync_plan_position(); |
||||
|
} |
||||
|
|
||||
|
/**
|
||||
|
* Probe around the calibration object for all toolheads, adjusting the coordinate |
||||
|
* system for the first nozzle and the nozzle offset for subsequent nozzles. |
||||
|
* |
||||
|
* m in/out - Measurement record, updated with new readings |
||||
|
* uncertainty in - How far away from the object to begin probing |
||||
|
*/ |
||||
|
inline void calibrate_all_toolheads(measurements_t &m, const float uncertainty) { |
||||
|
TEMPORARY_BACKLASH_STATE(true); |
||||
|
TEMPORARY_BACKLASH_SMOOTHING(0); |
||||
|
|
||||
|
HOTEND_LOOP() calibrate_toolhead(m, uncertainty, e); |
||||
|
|
||||
|
#if HOTENDS > 1 |
||||
|
normalize_hotend_offsets(); |
||||
|
set_nozzle(m, 0); |
||||
|
#endif |
||||
|
} |
||||
|
|
||||
|
/**
|
||||
|
* Perform a full auto-calibration routine: |
||||
|
* |
||||
|
* 1) For each nozzle, touch top and sides of object to determine object position and |
||||
|
* nozzle offsets. Do a fast but rough search over a wider area. |
||||
|
* 2) With the first nozzle, touch top and sides of object to determine backlash values |
||||
|
* for all axis (if BACKLASH_GCODE is enabled) |
||||
|
* 3) For each nozzle, touch top and sides of object slowly to determine precise |
||||
|
* position of object. Adjust coordinate system and nozzle offsets so probed object |
||||
|
* location corresponds to known object location with a high degree of precision. |
||||
|
*/ |
||||
|
inline void calibrate_all() { |
||||
|
measurements_t m; |
||||
|
|
||||
|
#if HOTENDS > 1 |
||||
|
reset_nozzle_offsets(); |
||||
|
#endif |
||||
|
|
||||
|
TEMPORARY_BACKLASH_STATE(true); |
||||
|
TEMPORARY_BACKLASH_SMOOTHING(0); |
||||
|
|
||||
|
|
||||
|
/* Do a fast and rough calibration of the toolheads */ |
||||
|
calibrate_all_toolheads(m, CALIBRATION_MEASUREMENT_UNKNOWN); |
||||
|
|
||||
|
#if ENABLED(BACKLASH_GCODE) |
||||
|
calibrate_backlash(m, CALIBRATION_MEASUREMENT_UNCERTAIN); |
||||
|
#endif |
||||
|
|
||||
|
/* Cycle the toolheads so the servos settle into their "natural" positions */ |
||||
|
#if HOTENDS > 1 |
||||
|
HOTEND_LOOP() set_nozzle(m, e); |
||||
|
#endif |
||||
|
|
||||
|
/* Do a slow and precise calibration of the toolheads */ |
||||
|
calibrate_all_toolheads(m, CALIBRATION_MEASUREMENT_UNCERTAIN); |
||||
|
|
||||
|
move_to(X_AXIS, 150); // Park nozzle away from calibration object
|
||||
|
} |
||||
|
|
||||
|
/**
|
||||
|
* G425: Perform calibration with calibration object. |
||||
|
* |
||||
|
* B - Perform calibration of backlash only. |
||||
|
* T<extruder> - Perform calibration of toolhead only. |
||||
|
* V - Probe object and print position, error, backlash and hotend offset. |
||||
|
* U - Uncertainty, how far to start probe away from the object (mm) |
||||
|
* |
||||
|
* no args - Perform entire calibration sequence (backlash + position on all toolheads) |
||||
|
*/ |
||||
|
void GcodeSuite::G425() { |
||||
|
if (axis_unhomed_error()) return; |
||||
|
|
||||
|
measurements_t m; |
||||
|
|
||||
|
float uncertainty = parser.seenval('U') ? parser.value_float() : CALIBRATION_MEASUREMENT_UNCERTAIN; |
||||
|
|
||||
|
if (parser.seen('B')) |
||||
|
calibrate_backlash(m, uncertainty); |
||||
|
else if (parser.seen('T')) |
||||
|
calibrate_toolhead(m, uncertainty, parser.has_value() ? parser.value_int() : active_extruder); |
||||
|
#if ENABLED(CALIBRATION_REPORTING) |
||||
|
else if (parser.seen('V')) { |
||||
|
probe_sides(m, uncertainty); |
||||
|
SERIAL_EOL(); |
||||
|
report_measured_faces(m); |
||||
|
report_measured_center(m); |
||||
|
report_measured_backlash(m); |
||||
|
report_measured_nozzle_dimensions(m); |
||||
|
report_measured_positional_error(m); |
||||
|
#if HOTENDS > 1 |
||||
|
normalize_hotend_offsets(); |
||||
|
report_hotend_offsets(); |
||||
|
#endif |
||||
|
} |
||||
|
#endif |
||||
|
else |
||||
|
calibrate_all(); |
||||
|
} |
||||
|
|
||||
|
#endif // CALIBRATION_GCODE
|
Loading…
Reference in new issue