|
@@ -522,8 +522,11 @@ float soft_endstop_min[XYZ] = { X_MIN_BED, Y_MIN_BED, Z_MIN_POS },
|
522
|
522
|
// Get the top feedrate of the move in the XY plane
|
523
|
523
|
const float _feedrate_mm_s = MMS_SCALED(feedrate_mm_s);
|
524
|
524
|
|
|
525
|
+ const float xdiff = rtarget[X_AXIS] - current_position[X_AXIS],
|
|
526
|
+ ydiff = rtarget[Y_AXIS] - current_position[Y_AXIS];
|
|
527
|
+
|
525
|
528
|
// If the move is only in Z/E don't split up the move
|
526
|
|
- if (rtarget[X_AXIS] == current_position[X_AXIS] && rtarget[Y_AXIS] == current_position[Y_AXIS]) {
|
|
529
|
+ if (!xdiff && !ydiff) {
|
527
|
530
|
planner.buffer_line_kinematic(rtarget, _feedrate_mm_s, active_extruder);
|
528
|
531
|
return false;
|
529
|
532
|
}
|
|
@@ -531,19 +534,15 @@ float soft_endstop_min[XYZ] = { X_MIN_BED, Y_MIN_BED, Z_MIN_POS },
|
531
|
534
|
// Fail if attempting move outside printable radius
|
532
|
535
|
if (!position_is_reachable(rtarget[X_AXIS], rtarget[Y_AXIS])) return true;
|
533
|
536
|
|
534
|
|
- // Get the cartesian distances moved in XYZE
|
535
|
|
- const float difference[XYZE] = {
|
536
|
|
- rtarget[X_AXIS] - current_position[X_AXIS],
|
537
|
|
- rtarget[Y_AXIS] - current_position[Y_AXIS],
|
538
|
|
- rtarget[Z_AXIS] - current_position[Z_AXIS],
|
539
|
|
- rtarget[E_AXIS] - current_position[E_AXIS]
|
540
|
|
- };
|
|
537
|
+ // Remaining cartesian distances
|
|
538
|
+ const float zdiff = rtarget[Z_AXIS] - current_position[Z_AXIS],
|
|
539
|
+ ediff = rtarget[E_AXIS] - current_position[E_AXIS];
|
541
|
540
|
|
542
|
541
|
// Get the linear distance in XYZ
|
543
|
|
- float cartesian_mm = SQRT(sq(difference[X_AXIS]) + sq(difference[Y_AXIS]) + sq(difference[Z_AXIS]));
|
|
542
|
+ float cartesian_mm = SQRT(sq(xdiff) + sq(ydiff) + sq(zdiff));
|
544
|
543
|
|
545
|
544
|
// If the move is very short, check the E move distance
|
546
|
|
- if (UNEAR_ZERO(cartesian_mm)) cartesian_mm = FABS(difference[E_AXIS]);
|
|
545
|
+ if (UNEAR_ZERO(cartesian_mm)) cartesian_mm = FABS(ediff);
|
547
|
546
|
|
548
|
547
|
// No E move either? Game over.
|
549
|
548
|
if (UNEAR_ZERO(cartesian_mm)) return true;
|
|
@@ -566,10 +565,10 @@ float soft_endstop_min[XYZ] = { X_MIN_BED, Y_MIN_BED, Z_MIN_POS },
|
566
|
565
|
// The approximate length of each segment
|
567
|
566
|
const float inv_segments = 1.0 / float(segments),
|
568
|
567
|
segment_distance[XYZE] = {
|
569
|
|
- difference[X_AXIS] * inv_segments,
|
570
|
|
- difference[Y_AXIS] * inv_segments,
|
571
|
|
- difference[Z_AXIS] * inv_segments,
|
572
|
|
- difference[E_AXIS] * inv_segments
|
|
568
|
+ xdiff * inv_segments,
|
|
569
|
+ ydiff * inv_segments,
|
|
570
|
+ zdiff * inv_segments,
|
|
571
|
+ ediff * inv_segments
|
573
|
572
|
};
|
574
|
573
|
|
575
|
574
|
// SERIAL_ECHOPAIR("mm=", cartesian_mm);
|
|
@@ -644,6 +643,81 @@ float soft_endstop_min[XYZ] = { X_MIN_BED, Y_MIN_BED, Z_MIN_POS },
|
644
|
643
|
|
645
|
644
|
#else // !IS_KINEMATIC
|
646
|
645
|
|
|
646
|
+ #if ENABLED(SEGMENT_LEVELED_MOVES)
|
|
647
|
+
|
|
648
|
+ /**
|
|
649
|
+ * Prepare a segmented move on a CARTESIAN setup.
|
|
650
|
+ *
|
|
651
|
+ * This calls planner.buffer_line several times, adding
|
|
652
|
+ * small incremental moves. This allows the planner to
|
|
653
|
+ * apply more detailed bed leveling to the full move.
|
|
654
|
+ */
|
|
655
|
+ inline void segmented_line_to_destination(const float &fr_mm_s, const float segment_size=LEVELED_SEGMENT_LENGTH) {
|
|
656
|
+
|
|
657
|
+ const float xdiff = destination[X_AXIS] - current_position[X_AXIS],
|
|
658
|
+ ydiff = destination[Y_AXIS] - current_position[Y_AXIS];
|
|
659
|
+
|
|
660
|
+ // If the move is only in Z/E don't split up the move
|
|
661
|
+ if (!xdiff && !ydiff) {
|
|
662
|
+ planner.buffer_line_kinematic(destination, fr_mm_s, active_extruder);
|
|
663
|
+ return;
|
|
664
|
+ }
|
|
665
|
+
|
|
666
|
+ // Remaining cartesian distances
|
|
667
|
+ const float zdiff = destination[Z_AXIS] - current_position[Z_AXIS],
|
|
668
|
+ ediff = destination[E_AXIS] - current_position[E_AXIS];
|
|
669
|
+
|
|
670
|
+ // Get the linear distance in XYZ
|
|
671
|
+ // If the move is very short, check the E move distance
|
|
672
|
+ // No E move either? Game over.
|
|
673
|
+ float cartesian_mm = SQRT(sq(xdiff) + sq(ydiff) + sq(zdiff));
|
|
674
|
+ if (UNEAR_ZERO(cartesian_mm)) cartesian_mm = FABS(ediff);
|
|
675
|
+ if (UNEAR_ZERO(cartesian_mm)) return;
|
|
676
|
+
|
|
677
|
+ // The length divided by the segment size
|
|
678
|
+ // At least one segment is required
|
|
679
|
+ uint16_t segments = cartesian_mm / segment_size;
|
|
680
|
+ NOLESS(segments, 1);
|
|
681
|
+
|
|
682
|
+ // The approximate length of each segment
|
|
683
|
+ const float inv_segments = 1.0 / float(segments),
|
|
684
|
+ segment_distance[XYZE] = {
|
|
685
|
+ xdiff * inv_segments,
|
|
686
|
+ ydiff * inv_segments,
|
|
687
|
+ zdiff * inv_segments,
|
|
688
|
+ ediff * inv_segments
|
|
689
|
+ };
|
|
690
|
+
|
|
691
|
+ // SERIAL_ECHOPAIR("mm=", cartesian_mm);
|
|
692
|
+ // SERIAL_ECHOLNPAIR(" segments=", segments);
|
|
693
|
+
|
|
694
|
+ // Drop one segment so the last move is to the exact target.
|
|
695
|
+ // If there's only 1 segment, loops will be skipped entirely.
|
|
696
|
+ --segments;
|
|
697
|
+
|
|
698
|
+ // Get the raw current position as starting point
|
|
699
|
+ float raw[XYZE];
|
|
700
|
+ COPY(raw, current_position);
|
|
701
|
+
|
|
702
|
+ // Calculate and execute the segments
|
|
703
|
+ for (uint16_t s = segments + 1; --s;) {
|
|
704
|
+ static millis_t next_idle_ms = millis() + 200UL;
|
|
705
|
+ thermalManager.manage_heater(); // This returns immediately if not really needed.
|
|
706
|
+ if (ELAPSED(millis(), next_idle_ms)) {
|
|
707
|
+ next_idle_ms = millis() + 200UL;
|
|
708
|
+ idle();
|
|
709
|
+ }
|
|
710
|
+ LOOP_XYZE(i) raw[i] += segment_distance[i];
|
|
711
|
+ planner.buffer_line_kinematic(raw, fr_mm_s, active_extruder);
|
|
712
|
+ }
|
|
713
|
+
|
|
714
|
+ // Since segment_distance is only approximate,
|
|
715
|
+ // the final move must be to the exact destination.
|
|
716
|
+ planner.buffer_line_kinematic(destination, fr_mm_s, active_extruder);
|
|
717
|
+ }
|
|
718
|
+
|
|
719
|
+ #endif // SEGMENT_LEVELED_MOVES
|
|
720
|
+
|
647
|
721
|
/**
|
648
|
722
|
* Prepare a linear move in a Cartesian setup.
|
649
|
723
|
*
|
|
@@ -654,10 +728,13 @@ float soft_endstop_min[XYZ] = { X_MIN_BED, Y_MIN_BED, Z_MIN_POS },
|
654
|
728
|
*/
|
655
|
729
|
inline bool prepare_move_to_destination_cartesian() {
|
656
|
730
|
#if HAS_MESH
|
657
|
|
- if (planner.leveling_active) {
|
|
731
|
+ if (planner.leveling_active && planner.leveling_active_at_z(destination[Z_AXIS])) {
|
658
|
732
|
#if ENABLED(AUTO_BED_LEVELING_UBL)
|
659
|
733
|
ubl.line_to_destination_cartesian(MMS_SCALED(feedrate_mm_s), active_extruder); // UBL's motion routine needs to know about
|
660
|
734
|
return true; // all moves, including Z-only moves.
|
|
735
|
+ #elif ENABLED(SEGMENT_LEVELED_MOVES)
|
|
736
|
+ segmented_line_to_destination(MMS_SCALED(feedrate_mm_s));
|
|
737
|
+ return false;
|
661
|
738
|
#else
|
662
|
739
|
/**
|
663
|
740
|
* For MBL and ABL-BILINEAR only segment moves when X or Y are involved.
|