Overhaul of the planner (#11578)
- Move FWRETRACT to the planner - Combine leveling, skew, etc. in a single modifier method - Have kinematic and non-kinematic moves call one planner method
This commit is contained in:
committed by
Scott Lahteine
parent
8323a08642
commit
c437bb08f1
@ -25,15 +25,12 @@
|
||||
#if HAS_LEVELING
|
||||
|
||||
#include "bedlevel.h"
|
||||
#include "../../module/planner.h"
|
||||
|
||||
#if ENABLED(MESH_BED_LEVELING) || ENABLED(PROBE_MANUALLY)
|
||||
#include "../../module/motion.h"
|
||||
#endif
|
||||
|
||||
#if PLANNER_LEVELING
|
||||
#include "../../module/planner.h"
|
||||
#endif
|
||||
|
||||
#if ENABLED(PROBE_MANUALLY)
|
||||
bool g29_in_progress = false;
|
||||
#endif
|
||||
@ -79,74 +76,24 @@ void set_bed_leveling_enabled(const bool enable/*=true*/) {
|
||||
|
||||
planner.synchronize();
|
||||
|
||||
#if ENABLED(MESH_BED_LEVELING)
|
||||
#if ENABLED(AUTO_BED_LEVELING_BILINEAR)
|
||||
// Force bilinear_z_offset to re-calculate next time
|
||||
const float reset[XYZ] = { -9999.999, -9999.999, 0 };
|
||||
(void)bilinear_z_offset(reset);
|
||||
#endif
|
||||
|
||||
if (!enable)
|
||||
planner.apply_leveling(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS]);
|
||||
if (planner.leveling_active) { // leveling from on to off
|
||||
// change unleveled current_position to physical current_position without moving steppers.
|
||||
planner.apply_leveling(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS]);
|
||||
planner.leveling_active = false; // disable only AFTER calling apply_leveling
|
||||
}
|
||||
else { // leveling from off to on
|
||||
planner.leveling_active = true; // enable BEFORE calling unapply_leveling, otherwise ignored
|
||||
// change physical current_position to unleveled current_position without moving steppers.
|
||||
planner.unapply_leveling(current_position);
|
||||
}
|
||||
|
||||
const bool enabling = enable && leveling_is_valid();
|
||||
planner.leveling_active = enabling;
|
||||
if (enabling) planner.unapply_leveling(current_position);
|
||||
|
||||
#elif ENABLED(AUTO_BED_LEVELING_UBL)
|
||||
#if PLANNER_LEVELING
|
||||
if (planner.leveling_active) { // leveling from on to off
|
||||
// change unleveled current_position to physical current_position without moving steppers.
|
||||
planner.apply_leveling(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS]);
|
||||
planner.leveling_active = false; // disable only AFTER calling apply_leveling
|
||||
}
|
||||
else { // leveling from off to on
|
||||
planner.leveling_active = true; // enable BEFORE calling unapply_leveling, otherwise ignored
|
||||
// change physical current_position to unleveled current_position without moving steppers.
|
||||
planner.unapply_leveling(current_position);
|
||||
}
|
||||
#else
|
||||
// UBL equivalents for apply/unapply_leveling
|
||||
#if ENABLED(SKEW_CORRECTION)
|
||||
float pos[XYZ] = { current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS] };
|
||||
planner.skew(pos[X_AXIS], pos[Y_AXIS], pos[Z_AXIS]);
|
||||
#else
|
||||
const float (&pos)[XYZE] = current_position;
|
||||
#endif
|
||||
if (planner.leveling_active) {
|
||||
current_position[Z_AXIS] += ubl.get_z_correction(pos[X_AXIS], pos[Y_AXIS]);
|
||||
planner.leveling_active = false;
|
||||
}
|
||||
else {
|
||||
planner.leveling_active = true;
|
||||
current_position[Z_AXIS] -= ubl.get_z_correction(pos[X_AXIS], pos[Y_AXIS]);
|
||||
}
|
||||
#endif
|
||||
|
||||
#else // OLDSCHOOL_ABL
|
||||
|
||||
#if ENABLED(AUTO_BED_LEVELING_BILINEAR)
|
||||
// Force bilinear_z_offset to re-calculate next time
|
||||
const float reset[XYZ] = { -9999.999, -9999.999, 0 };
|
||||
(void)bilinear_z_offset(reset);
|
||||
#endif
|
||||
|
||||
// Enable or disable leveling compensation in the planner
|
||||
planner.leveling_active = enable;
|
||||
|
||||
if (!enable)
|
||||
// When disabling just get the current position from the steppers.
|
||||
// This will yield the smallest error when first converted back to steps.
|
||||
set_current_from_steppers_for_axis(
|
||||
#if ABL_PLANAR
|
||||
ALL_AXES
|
||||
#else
|
||||
Z_AXIS
|
||||
#endif
|
||||
);
|
||||
else
|
||||
// When enabling, remove compensation from the current position,
|
||||
// so compensation will give the right stepper counts.
|
||||
planner.unapply_leveling(current_position);
|
||||
|
||||
SYNC_PLAN_POSITION_KINEMATIC();
|
||||
|
||||
#endif // OLDSCHOOL_ABL
|
||||
sync_plan_position();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -49,12 +49,11 @@
|
||||
* as possible to determine if this is the case. If this move is within the same cell, we will
|
||||
* just do the required Z-Height correction, call the Planner's buffer_line() routine, and leave
|
||||
*/
|
||||
#if ENABLED(SKEW_CORRECTION)
|
||||
// For skew correction just adjust the destination point and we're done
|
||||
#if HAS_POSITION_MODIFIERS
|
||||
float start[XYZE] = { current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS] },
|
||||
end[XYZE] = { destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS] };
|
||||
planner.skew(start[X_AXIS], start[Y_AXIS], start[Z_AXIS]);
|
||||
planner.skew(end[X_AXIS], end[Y_AXIS], end[Z_AXIS]);
|
||||
planner.apply_modifiers(start);
|
||||
planner.apply_modifiers(end);
|
||||
#else
|
||||
const float (&start)[XYZE] = current_position,
|
||||
(&end)[XYZE] = destination;
|
||||
@ -364,47 +363,6 @@
|
||||
|
||||
#else // UBL_SEGMENTED
|
||||
|
||||
#if IS_SCARA // scale the feed rate from mm/s to degrees/s
|
||||
static float scara_feed_factor, scara_oldA, scara_oldB;
|
||||
#endif
|
||||
|
||||
// We don't want additional apply_leveling() performed by regular buffer_line or buffer_line_kinematic,
|
||||
// so we call buffer_segment directly here. Per-segmented leveling and kinematics performed first.
|
||||
|
||||
inline void _O2 ubl_buffer_segment_raw(const float (&in_raw)[XYZE], const float &fr) {
|
||||
|
||||
#if ENABLED(SKEW_CORRECTION)
|
||||
float raw[XYZE] = { in_raw[X_AXIS], in_raw[Y_AXIS], in_raw[Z_AXIS] };
|
||||
planner.skew(raw[X_AXIS], raw[Y_AXIS], raw[Z_AXIS]);
|
||||
#else
|
||||
const float (&raw)[XYZE] = in_raw;
|
||||
#endif
|
||||
|
||||
#if ENABLED(DELTA) // apply delta inverse_kinematics
|
||||
|
||||
DELTA_IK(raw);
|
||||
planner.buffer_segment(delta[A_AXIS], delta[B_AXIS], delta[C_AXIS], in_raw[E_AXIS], fr, active_extruder);
|
||||
|
||||
#elif IS_SCARA // apply scara inverse_kinematics (should be changed to save raw->logical->raw)
|
||||
|
||||
inverse_kinematics(raw); // this writes delta[ABC] from raw[XYZE]
|
||||
// should move the feedrate scaling to scara inverse_kinematics
|
||||
|
||||
const float adiff = ABS(delta[A_AXIS] - scara_oldA),
|
||||
bdiff = ABS(delta[B_AXIS] - scara_oldB);
|
||||
scara_oldA = delta[A_AXIS];
|
||||
scara_oldB = delta[B_AXIS];
|
||||
float s_feedrate = MAX(adiff, bdiff) * scara_feed_factor;
|
||||
|
||||
planner.buffer_segment(delta[A_AXIS], delta[B_AXIS], delta[C_AXIS], in_raw[E_AXIS], s_feedrate, active_extruder);
|
||||
|
||||
#else // CARTESIAN
|
||||
|
||||
planner.buffer_segment(raw[X_AXIS], raw[Y_AXIS], raw[Z_AXIS], in_raw[E_AXIS], fr, active_extruder);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
#if IS_SCARA
|
||||
#define DELTA_SEGMENT_MIN_LENGTH 0.25 // SCARA minimum segment size is 0.25mm
|
||||
#elif ENABLED(DELTA)
|
||||
@ -449,10 +407,9 @@
|
||||
NOLESS(segments, 1U); // must have at least one segment
|
||||
const float inv_segments = 1.0f / segments; // divide once, multiply thereafter
|
||||
|
||||
#if IS_SCARA // scale the feed rate from mm/s to degrees/s
|
||||
scara_feed_factor = cartesian_xy_mm * inv_segments * feedrate;
|
||||
scara_oldA = planner.get_axis_position_degrees(A_AXIS);
|
||||
scara_oldB = planner.get_axis_position_degrees(B_AXIS);
|
||||
const float segment_xyz_mm = HYPOT(cartesian_xy_mm, total[Z_AXIS]) * inv_segments; // length of each segment
|
||||
#if ENABLED(SCARA_FEEDRATE_SCALING)
|
||||
const float inv_duration = feedrate / segment_xyz_mm;
|
||||
#endif
|
||||
|
||||
const float diff[XYZE] = {
|
||||
@ -476,9 +433,17 @@
|
||||
if (!planner.leveling_active || !planner.leveling_active_at_z(rtarget[Z_AXIS])) { // no mesh leveling
|
||||
while (--segments) {
|
||||
LOOP_XYZE(i) raw[i] += diff[i];
|
||||
ubl_buffer_segment_raw(raw, feedrate);
|
||||
planner.buffer_line(raw, feedrate, active_extruder, segment_xyz_mm
|
||||
#if ENABLED(SCARA_FEEDRATE_SCALING)
|
||||
, inv_duration
|
||||
#endif
|
||||
);
|
||||
}
|
||||
ubl_buffer_segment_raw(rtarget, feedrate);
|
||||
planner.buffer_line(rtarget, feedrate, active_extruder, segment_xyz_mm
|
||||
#if ENABLED(SCARA_FEEDRATE_SCALING)
|
||||
, inv_duration
|
||||
#endif
|
||||
);
|
||||
return false; // moved but did not set_current_from_destination();
|
||||
}
|
||||
|
||||
@ -554,7 +519,11 @@
|
||||
|
||||
const float z = raw[Z_AXIS];
|
||||
raw[Z_AXIS] += z_cxcy;
|
||||
ubl_buffer_segment_raw(raw, feedrate);
|
||||
planner.buffer_line(raw, feedrate, active_extruder, segment_xyz_mm
|
||||
#if ENABLED(SCARA_FEEDRATE_SCALING)
|
||||
, inv_duration
|
||||
#endif
|
||||
);
|
||||
raw[Z_AXIS] = z;
|
||||
|
||||
if (segments == 0) // done with last segment
|
||||
|
@ -54,6 +54,7 @@ float FWRetract::retract_length, // M207 S - G10 Retract len
|
||||
FWRetract::swap_retract_length, // M207 W - G10 Swap Retract length
|
||||
FWRetract::swap_retract_recover_length, // M208 W - G11 Swap Recover length
|
||||
FWRetract::swap_retract_recover_feedrate_mm_s, // M208 R - G11 Swap Recover feedrate
|
||||
FWRetract::current_retract[EXTRUDERS], // Retract value used by planner
|
||||
FWRetract::current_hop;
|
||||
|
||||
void FWRetract::reset() {
|
||||
@ -73,6 +74,7 @@ void FWRetract::reset() {
|
||||
#if EXTRUDERS > 1
|
||||
retracted_swap[i] = false;
|
||||
#endif
|
||||
current_retract[i] = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -84,9 +86,6 @@ void FWRetract::reset() {
|
||||
*
|
||||
* To simplify the logic, doubled retract/recover moves are ignored.
|
||||
*
|
||||
* Note: Z lift is done transparently to the planner. Aborting
|
||||
* a print between G10 and G11 may corrupt the Z position.
|
||||
*
|
||||
* Note: Auto-retract will apply the set Z hop in addition to any Z hop
|
||||
* included in the G-code. Use M207 Z0 to to prevent double hop.
|
||||
*/
|
||||
@ -95,9 +94,6 @@ void FWRetract::retract(const bool retracting
|
||||
, bool swapping /* =false */
|
||||
#endif
|
||||
) {
|
||||
|
||||
static float current_hop = 0.0; // Total amount lifted, for use in recover
|
||||
|
||||
// Prevent two retracts or recovers in a row
|
||||
if (retracted[active_extruder] == retracting) return;
|
||||
|
||||
@ -129,48 +125,50 @@ void FWRetract::retract(const bool retracting
|
||||
//*/
|
||||
|
||||
const float old_feedrate_mm_s = feedrate_mm_s,
|
||||
renormalize = RECIPROCAL(planner.e_factor[active_extruder]),
|
||||
base_retract = swapping ? swap_retract_length : retract_length,
|
||||
old_z = current_position[Z_AXIS],
|
||||
old_e = current_position[E_AXIS];
|
||||
unscale_e = RECIPROCAL(planner.e_factor[active_extruder]),
|
||||
unscale_fr = 100.0 / feedrate_percentage, // Disable feedrate scaling for retract moves
|
||||
base_retract = swapping ? swap_retract_length : retract_length;
|
||||
|
||||
// The current position will be the destination for E and Z moves
|
||||
set_destination_from_current();
|
||||
|
||||
if (retracting) {
|
||||
// Retract by moving from a faux E position back to the current E position
|
||||
feedrate_mm_s = retract_feedrate_mm_s;
|
||||
destination[E_AXIS] -= base_retract * renormalize;
|
||||
feedrate_mm_s = retract_feedrate_mm_s * unscale_fr;
|
||||
current_retract[active_extruder] = base_retract * unscale_e;
|
||||
prepare_move_to_destination(); // set_current_to_destination
|
||||
planner.synchronize(); // Wait for move to complete
|
||||
|
||||
// Is a Z hop set, and has the hop not yet been done?
|
||||
if (retract_zlift > 0.01 && !current_hop) { // Apply hop only once
|
||||
current_hop += retract_zlift; // Add to the hop total (again, only once)
|
||||
destination[Z_AXIS] += retract_zlift; // Raise Z by the zlift (M207 Z) amount
|
||||
feedrate_mm_s = planner.max_feedrate_mm_s[Z_AXIS]; // Maximum Z feedrate
|
||||
feedrate_mm_s = planner.max_feedrate_mm_s[Z_AXIS] * unscale_fr; // Maximum Z feedrate
|
||||
prepare_move_to_destination(); // Raise up, set_current_to_destination
|
||||
planner.synchronize(); // Wait for move to complete
|
||||
}
|
||||
}
|
||||
else {
|
||||
// If a hop was done and Z hasn't changed, undo the Z hop
|
||||
if (current_hop) {
|
||||
current_position[Z_AXIS] += current_hop; // Restore the actual Z position
|
||||
SYNC_PLAN_POSITION_KINEMATIC(); // Unspoof the position planner
|
||||
feedrate_mm_s = planner.max_feedrate_mm_s[Z_AXIS]; // Z feedrate to max
|
||||
current_hop = 0.0;
|
||||
feedrate_mm_s = planner.max_feedrate_mm_s[Z_AXIS] * unscale_fr; // Z feedrate to max
|
||||
prepare_move_to_destination(); // Lower Z, set_current_to_destination
|
||||
current_hop = 0.0; // Clear the hop amount
|
||||
planner.synchronize(); // Wait for move to complete
|
||||
}
|
||||
|
||||
destination[E_AXIS] += (base_retract + (swapping ? swap_retract_recover_length : retract_recover_length)) * renormalize;
|
||||
feedrate_mm_s = swapping ? swap_retract_recover_feedrate_mm_s : retract_recover_feedrate_mm_s;
|
||||
const float extra_recover = swapping ? swap_retract_recover_length : retract_recover_length;
|
||||
if (extra_recover != 0.0) {
|
||||
current_position[E_AXIS] -= extra_recover; // Adjust the current E position by the extra amount to recover
|
||||
sync_plan_position_e(); // Sync the planner position so the extra amount is recovered
|
||||
}
|
||||
|
||||
current_retract[active_extruder] = 0.0;
|
||||
feedrate_mm_s = (swapping ? swap_retract_recover_feedrate_mm_s : retract_recover_feedrate_mm_s) * unscale_fr;
|
||||
prepare_move_to_destination(); // Recover E, set_current_to_destination
|
||||
planner.synchronize(); // Wait for move to complete
|
||||
}
|
||||
|
||||
feedrate_mm_s = old_feedrate_mm_s; // Restore original feedrate
|
||||
current_position[Z_AXIS] = old_z; // Restore Z and E positions
|
||||
current_position[E_AXIS] = old_e;
|
||||
SYNC_PLAN_POSITION_KINEMATIC(); // As if the move never took place
|
||||
|
||||
retracted[active_extruder] = retracting; // Active extruder now retracted / recovered
|
||||
|
||||
// If swap retract/recover update the retracted_swap flag too
|
||||
@ -194,7 +192,6 @@ void FWRetract::retract(const bool retracting
|
||||
SERIAL_ECHOLNPAIR("current_position[e] ", current_position[E_AXIS]);
|
||||
SERIAL_ECHOLNPAIR("current_hop ", current_hop);
|
||||
//*/
|
||||
|
||||
}
|
||||
|
||||
#endif // FWRETRACT
|
||||
|
@ -46,7 +46,8 @@ public:
|
||||
swap_retract_length, // M207 W - G10 Swap Retract length
|
||||
swap_retract_recover_length, // M208 W - G11 Swap Recover length
|
||||
swap_retract_recover_feedrate_mm_s, // M208 R - G11 Swap Recover feedrate
|
||||
current_hop;
|
||||
current_retract[EXTRUDERS], // Retract value used by planner
|
||||
current_hop; // Hop value used by planner
|
||||
|
||||
FWRetract() { reset(); }
|
||||
|
||||
|
@ -120,7 +120,7 @@ static bool ensure_safe_temperature(const AdvancedPauseMode mode=ADVANCED_PAUSE_
|
||||
static void do_pause_e_move(const float &length, const float &fr) {
|
||||
set_destination_from_current();
|
||||
destination[E_AXIS] += length / planner.e_factor[active_extruder];
|
||||
planner.buffer_line_kinematic(destination, fr, active_extruder);
|
||||
planner.buffer_line(destination, fr, active_extruder);
|
||||
set_current_from_destination();
|
||||
planner.synchronize();
|
||||
}
|
||||
|
@ -39,6 +39,10 @@
|
||||
#include "../sd/cardreader.h"
|
||||
#include "../core/serial.h"
|
||||
|
||||
#if ENABLED(FWRETRACT)
|
||||
#include "fwretract.h"
|
||||
#endif
|
||||
|
||||
// Recovery data
|
||||
job_recovery_info_t job_recovery_info;
|
||||
JobRecoveryPhase job_recovery_phase = JOB_RECOVERY_IDLE;
|
||||
@ -90,6 +94,15 @@ extern uint8_t commands_in_queue, cmd_queue_index_r;
|
||||
SERIAL_PROTOCOLPAIR("leveling: ", int(job_recovery_info.leveling));
|
||||
SERIAL_PROTOCOLLNPAIR(" fade: ", int(job_recovery_info.fade));
|
||||
#endif
|
||||
#if ENABLED(FWRETRACT)
|
||||
SERIAL_PROTOCOLPGM("retract: ");
|
||||
for (int8_t e = 0; e < EXTRUDERS; e++) {
|
||||
SERIAL_PROTOCOL(job_recovery_info.retract[e]);
|
||||
if (e < EXTRUDERS - 1) SERIAL_CHAR(',');
|
||||
}
|
||||
SERIAL_EOL();
|
||||
SERIAL_PROTOCOLLNPAIR("retract_hop: ", job_recovery_info.retract_hop);
|
||||
#endif
|
||||
SERIAL_PROTOCOLLNPAIR("cmd_queue_index_r: ", int(job_recovery_info.cmd_queue_index_r));
|
||||
SERIAL_PROTOCOLLNPAIR("commands_in_queue: ", int(job_recovery_info.commands_in_queue));
|
||||
if (recovery)
|
||||
@ -160,6 +173,15 @@ void check_print_job_recovery() {
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ENABLED(FWRETRACT)
|
||||
for (uint8_t e = 0; e < EXTRUDERS; e++) {
|
||||
if (job_recovery_info.retract[e] != 0.0)
|
||||
fwretract.current_retract[e] = job_recovery_info.retract[e];
|
||||
fwretract.retracted[e] = true;
|
||||
}
|
||||
fwretract.current_hop = job_recovery_info.retract_hop;
|
||||
#endif
|
||||
|
||||
dtostrf(job_recovery_info.current_position[Z_AXIS] + 2, 1, 3, str_1);
|
||||
dtostrf(job_recovery_info.current_position[E_AXIS]
|
||||
#if ENABLED(SAVE_EACH_CMD_MODE)
|
||||
@ -256,6 +278,11 @@ void save_job_recovery_info() {
|
||||
);
|
||||
#endif
|
||||
|
||||
#if ENABLED(FWRETRACT)
|
||||
COPY(job_recovery_info.retract, fwretract.current_retract);
|
||||
job_recovery_info.retract_hop = fwretract.current_hop;
|
||||
#endif
|
||||
|
||||
// Commands in the queue
|
||||
job_recovery_info.cmd_queue_index_r = cmd_queue_index_r;
|
||||
job_recovery_info.commands_in_queue = commands_in_queue;
|
||||
|
@ -60,6 +60,10 @@ typedef struct {
|
||||
float fade;
|
||||
#endif
|
||||
|
||||
#if ENABLED(FWRETRACT)
|
||||
float retract[EXTRUDERS], retract_hop;
|
||||
#endif
|
||||
|
||||
// Command queue
|
||||
uint8_t cmd_queue_index_r, commands_in_queue;
|
||||
char command_queue[BUFSIZE][MAX_CMD_SIZE];
|
||||
|
Reference in New Issue
Block a user