mirror of
https://github.com/MarlinFirmware/Marlin.git
synced 2025-01-31 14:12:52 +00:00
Add an option to segment leveled moves
This commit is contained in:
parent
a0fc5f7b52
commit
d786fb99e2
4 changed files with 106 additions and 20 deletions
|
@ -890,7 +890,7 @@
|
||||||
/**
|
/**
|
||||||
* Set granular options based on the specific type of leveling
|
* Set granular options based on the specific type of leveling
|
||||||
*/
|
*/
|
||||||
#define UBL_DELTA (ENABLED(AUTO_BED_LEVELING_UBL) && (ENABLED(DELTA) || ENABLED(UBL_GRANULAR_SEGMENTATION_FOR_CARTESIAN)))
|
#define UBL_DELTA (ENABLED(AUTO_BED_LEVELING_UBL) && (ENABLED(DELTA) || ENABLED(SEGMENT_LEVELED_MOVES)))
|
||||||
#define ABL_PLANAR (ENABLED(AUTO_BED_LEVELING_LINEAR) || ENABLED(AUTO_BED_LEVELING_3POINT))
|
#define ABL_PLANAR (ENABLED(AUTO_BED_LEVELING_LINEAR) || ENABLED(AUTO_BED_LEVELING_3POINT))
|
||||||
#define ABL_GRID (ENABLED(AUTO_BED_LEVELING_LINEAR) || ENABLED(AUTO_BED_LEVELING_BILINEAR))
|
#define ABL_GRID (ENABLED(AUTO_BED_LEVELING_LINEAR) || ENABLED(AUTO_BED_LEVELING_BILINEAR))
|
||||||
#define OLDSCHOOL_ABL (ABL_PLANAR || ABL_GRID)
|
#define OLDSCHOOL_ABL (ABL_PLANAR || ABL_GRID)
|
||||||
|
@ -905,6 +905,10 @@
|
||||||
#define PROBE_BED_HEIGHT abs(BACK_PROBE_BED_POSITION - (FRONT_PROBE_BED_POSITION))
|
#define PROBE_BED_HEIGHT abs(BACK_PROBE_BED_POSITION - (FRONT_PROBE_BED_POSITION))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if ENABLED(SEGMENT_LEVELED_MOVES) && !defined(LEVELED_SEGMENT_LENGTH)
|
||||||
|
#define LEVELED_SEGMENT_LENGTH 5
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bed Probing rectangular bounds
|
* Bed Probing rectangular bounds
|
||||||
* These can be further constrained in code for Delta and SCARA
|
* These can be further constrained in code for Delta and SCARA
|
||||||
|
|
|
@ -891,6 +891,11 @@
|
||||||
// The height can be set with M420 Z<height>
|
// The height can be set with M420 Z<height>
|
||||||
#define ENABLE_LEVELING_FADE_HEIGHT
|
#define ENABLE_LEVELING_FADE_HEIGHT
|
||||||
|
|
||||||
|
// For Cartesian machines, instead of dividing moves on mesh boundaries,
|
||||||
|
// split up moves into short segments like a Delta.
|
||||||
|
#define SEGMENT_LEVELED_MOVES
|
||||||
|
#define LEVELED_SEGMENT_LENGTH 5.0 // (mm) Length of all segments (except the last one)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enable the G26 Mesh Validation Pattern tool.
|
* Enable the G26 Mesh Validation Pattern tool.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -12531,7 +12531,81 @@ void set_current_from_steppers_for_axis(const AxisEnum axis) {
|
||||||
current_position[axis] = cartes[axis];
|
current_position[axis] = cartes[axis];
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ENABLED(MESH_BED_LEVELING)
|
#if IS_CARTESIAN
|
||||||
|
#if ENABLED(SEGMENT_LEVELED_MOVES)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepare a segmented move on a CARTESIAN setup.
|
||||||
|
*
|
||||||
|
* This calls planner.buffer_line several times, adding
|
||||||
|
* small incremental moves. This allows the planner to
|
||||||
|
* apply more detailed bed leveling to the full move.
|
||||||
|
*/
|
||||||
|
inline void segmented_line_to_destination(const float fr_mm_s, const float segment_size=LEVELED_SEGMENT_LENGTH) {
|
||||||
|
|
||||||
|
const float xdiff = destination[X_AXIS] - current_position[X_AXIS],
|
||||||
|
ydiff = destination[Y_AXIS] - current_position[Y_AXIS];
|
||||||
|
|
||||||
|
// If the move is only in Z/E don't split up the move
|
||||||
|
if (!xdiff && !ydiff) {
|
||||||
|
planner.buffer_line_kinematic(destination, fr_mm_s, active_extruder);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remaining cartesian distances
|
||||||
|
const float zdiff = destination[Z_AXIS] - current_position[Z_AXIS],
|
||||||
|
ediff = destination[E_AXIS] - current_position[E_AXIS];
|
||||||
|
|
||||||
|
// Get the linear distance in XYZ
|
||||||
|
// If the move is very short, check the E move distance
|
||||||
|
// No E move either? Game over.
|
||||||
|
float cartesian_mm = SQRT(sq(xdiff) + sq(ydiff) + sq(zdiff));
|
||||||
|
if (UNEAR_ZERO(cartesian_mm)) cartesian_mm = FABS(ediff);
|
||||||
|
if (UNEAR_ZERO(cartesian_mm)) return;
|
||||||
|
|
||||||
|
// The length divided by the segment size
|
||||||
|
// At least one segment is required
|
||||||
|
uint16_t segments = cartesian_mm / segment_size;
|
||||||
|
NOLESS(segments, 1);
|
||||||
|
|
||||||
|
// The approximate length of each segment
|
||||||
|
const float inv_segments = 1.0 / float(segments),
|
||||||
|
segment_distance[XYZE] = {
|
||||||
|
xdiff * inv_segments,
|
||||||
|
ydiff * inv_segments,
|
||||||
|
zdiff * inv_segments,
|
||||||
|
ediff * inv_segments
|
||||||
|
};
|
||||||
|
|
||||||
|
// SERIAL_ECHOPAIR("mm=", cartesian_mm);
|
||||||
|
// SERIAL_ECHOLNPAIR(" segments=", segments);
|
||||||
|
|
||||||
|
// Drop one segment so the last move is to the exact target.
|
||||||
|
// If there's only 1 segment, loops will be skipped entirely.
|
||||||
|
--segments;
|
||||||
|
|
||||||
|
// Get the raw current position as starting point
|
||||||
|
float raw[XYZE];
|
||||||
|
COPY(raw, current_position);
|
||||||
|
|
||||||
|
// Calculate and execute the segments
|
||||||
|
for (uint16_t s = segments + 1; --s;) {
|
||||||
|
static millis_t next_idle_ms = millis() + 200UL;
|
||||||
|
thermalManager.manage_heater(); // This returns immediately if not really needed.
|
||||||
|
if (ELAPSED(millis(), next_idle_ms)) {
|
||||||
|
next_idle_ms = millis() + 200UL;
|
||||||
|
idle();
|
||||||
|
}
|
||||||
|
LOOP_XYZE(i) raw[i] += segment_distance[i];
|
||||||
|
planner.buffer_line_kinematic(raw, fr_mm_s, active_extruder);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Since segment_distance is only approximate,
|
||||||
|
// the final move must be to the exact destination.
|
||||||
|
planner.buffer_line_kinematic(destination, fr_mm_s, active_extruder);
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif ENABLED(MESH_BED_LEVELING)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prepare a mesh-leveled linear move in a Cartesian setup,
|
* Prepare a mesh-leveled linear move in a Cartesian setup,
|
||||||
|
@ -12592,7 +12666,7 @@ void set_current_from_steppers_for_axis(const AxisEnum axis) {
|
||||||
mesh_line_to_destination(fr_mm_s, x_splits, y_splits);
|
mesh_line_to_destination(fr_mm_s, x_splits, y_splits);
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif ENABLED(AUTO_BED_LEVELING_BILINEAR) && !IS_KINEMATIC
|
#elif ENABLED(AUTO_BED_LEVELING_BILINEAR)
|
||||||
|
|
||||||
#define CELL_INDEX(A,V) ((V - bilinear_start[A##_AXIS]) * ABL_BG_FACTOR(A##_AXIS))
|
#define CELL_INDEX(A,V) ((V - bilinear_start[A##_AXIS]) * ABL_BG_FACTOR(A##_AXIS))
|
||||||
|
|
||||||
|
@ -12656,6 +12730,7 @@ void set_current_from_steppers_for_axis(const AxisEnum axis) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // AUTO_BED_LEVELING_BILINEAR
|
#endif // AUTO_BED_LEVELING_BILINEAR
|
||||||
|
#endif // IS_CARTESIAN
|
||||||
|
|
||||||
#if !UBL_DELTA
|
#if !UBL_DELTA
|
||||||
#if IS_KINEMATIC
|
#if IS_KINEMATIC
|
||||||
|
@ -12674,8 +12749,11 @@ void set_current_from_steppers_for_axis(const AxisEnum axis) {
|
||||||
// Get the top feedrate of the move in the XY plane
|
// Get the top feedrate of the move in the XY plane
|
||||||
const float _feedrate_mm_s = MMS_SCALED(feedrate_mm_s);
|
const float _feedrate_mm_s = MMS_SCALED(feedrate_mm_s);
|
||||||
|
|
||||||
|
const float xdiff = rtarget[X_AXIS] - current_position[X_AXIS],
|
||||||
|
ydiff = rtarget[Y_AXIS] - current_position[Y_AXIS];
|
||||||
|
|
||||||
// If the move is only in Z/E don't split up the move
|
// If the move is only in Z/E don't split up the move
|
||||||
if (rtarget[X_AXIS] == current_position[X_AXIS] && rtarget[Y_AXIS] == current_position[Y_AXIS]) {
|
if (!xdiff && !ydiff) {
|
||||||
planner.buffer_line_kinematic(rtarget, _feedrate_mm_s, active_extruder);
|
planner.buffer_line_kinematic(rtarget, _feedrate_mm_s, active_extruder);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -12683,21 +12761,15 @@ void set_current_from_steppers_for_axis(const AxisEnum axis) {
|
||||||
// Fail if attempting move outside printable radius
|
// Fail if attempting move outside printable radius
|
||||||
if (!position_is_reachable(rtarget[X_AXIS], rtarget[Y_AXIS])) return true;
|
if (!position_is_reachable(rtarget[X_AXIS], rtarget[Y_AXIS])) return true;
|
||||||
|
|
||||||
// Get the cartesian distances moved in XYZE
|
// Remaining cartesian distances
|
||||||
const float difference[XYZE] = {
|
const float zdiff = rtarget[Z_AXIS] - current_position[Z_AXIS],
|
||||||
rtarget[X_AXIS] - current_position[X_AXIS],
|
ediff = rtarget[E_AXIS] - current_position[E_AXIS];
|
||||||
rtarget[Y_AXIS] - current_position[Y_AXIS],
|
|
||||||
rtarget[Z_AXIS] - current_position[Z_AXIS],
|
|
||||||
rtarget[E_AXIS] - current_position[E_AXIS]
|
|
||||||
};
|
|
||||||
|
|
||||||
// Get the linear distance in XYZ
|
// Get the linear distance in XYZ
|
||||||
float cartesian_mm = SQRT(sq(difference[X_AXIS]) + sq(difference[Y_AXIS]) + sq(difference[Z_AXIS]));
|
|
||||||
|
|
||||||
// If the move is very short, check the E move distance
|
// If the move is very short, check the E move distance
|
||||||
if (UNEAR_ZERO(cartesian_mm)) cartesian_mm = FABS(difference[E_AXIS]);
|
|
||||||
|
|
||||||
// No E move either? Game over.
|
// No E move either? Game over.
|
||||||
|
float cartesian_mm = SQRT(sq(xdiff) + sq(ydiff) + sq(zdiff));
|
||||||
|
if (UNEAR_ZERO(cartesian_mm)) cartesian_mm = FABS(ediff);
|
||||||
if (UNEAR_ZERO(cartesian_mm)) return true;
|
if (UNEAR_ZERO(cartesian_mm)) return true;
|
||||||
|
|
||||||
// Minimum number of seconds to move the given distance
|
// Minimum number of seconds to move the given distance
|
||||||
|
@ -12718,10 +12790,10 @@ void set_current_from_steppers_for_axis(const AxisEnum axis) {
|
||||||
// The approximate length of each segment
|
// The approximate length of each segment
|
||||||
const float inv_segments = 1.0 / float(segments),
|
const float inv_segments = 1.0 / float(segments),
|
||||||
segment_distance[XYZE] = {
|
segment_distance[XYZE] = {
|
||||||
difference[X_AXIS] * inv_segments,
|
xdiff * inv_segments,
|
||||||
difference[Y_AXIS] * inv_segments,
|
ydiff * inv_segments,
|
||||||
difference[Z_AXIS] * inv_segments,
|
zdiff * inv_segments,
|
||||||
difference[E_AXIS] * inv_segments
|
ediff * inv_segments
|
||||||
};
|
};
|
||||||
|
|
||||||
// SERIAL_ECHOPAIR("mm=", cartesian_mm);
|
// SERIAL_ECHOPAIR("mm=", cartesian_mm);
|
||||||
|
@ -12806,10 +12878,13 @@ void set_current_from_steppers_for_axis(const AxisEnum axis) {
|
||||||
*/
|
*/
|
||||||
inline bool prepare_move_to_destination_cartesian() {
|
inline bool prepare_move_to_destination_cartesian() {
|
||||||
#if HAS_MESH
|
#if HAS_MESH
|
||||||
if (planner.leveling_active) {
|
if (planner.leveling_active && planner.leveling_active_at_z(destination[Z_AXIS])) {
|
||||||
#if ENABLED(AUTO_BED_LEVELING_UBL)
|
#if ENABLED(AUTO_BED_LEVELING_UBL)
|
||||||
ubl.line_to_destination_cartesian(MMS_SCALED(feedrate_mm_s), active_extruder); // UBL's motion routine needs to know about
|
ubl.line_to_destination_cartesian(MMS_SCALED(feedrate_mm_s), active_extruder); // UBL's motion routine needs to know about
|
||||||
return true; // all moves, including Z-only moves.
|
return true; // all moves, including Z-only moves.
|
||||||
|
#elif ENABLED(SEGMENT_LEVELED_MOVES)
|
||||||
|
segmented_line_to_destination(MMS_SCALED(feedrate_mm_s));
|
||||||
|
return false;
|
||||||
#else
|
#else
|
||||||
/**
|
/**
|
||||||
* For MBL and ABL-BILINEAR only segment moves when X or Y are involved.
|
* For MBL and ABL-BILINEAR only segment moves when X or Y are involved.
|
||||||
|
|
|
@ -220,6 +220,8 @@
|
||||||
#error "ENABLE_MESH_EDIT_GFX_OVERLAY is now MESH_EDIT_GFX_OVERLAY. Please update your configuration."
|
#error "ENABLE_MESH_EDIT_GFX_OVERLAY is now MESH_EDIT_GFX_OVERLAY. Please update your configuration."
|
||||||
#elif defined(BABYSTEP_ZPROBE_GFX_REVERSE)
|
#elif defined(BABYSTEP_ZPROBE_GFX_REVERSE)
|
||||||
#error "BABYSTEP_ZPROBE_GFX_REVERSE is now set by OVERLAY_GFX_REVERSE. Please update your configurations."
|
#error "BABYSTEP_ZPROBE_GFX_REVERSE is now set by OVERLAY_GFX_REVERSE. Please update your configurations."
|
||||||
|
#elif defined(UBL_GRANULAR_SEGMENTATION_FOR_CARTESIAN)
|
||||||
|
#error "UBL_GRANULAR_SEGMENTATION_FOR_CARTESIAN is now SEGMENT_LEVELED_MOVES. Please update your configuration."
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in a new issue