Browse Source

Add an option to segment leveled moves

Scott Lahteine 6 years ago
parent
commit
ef2531558c

+ 5
- 0
Marlin/Configuration.h View File

886
   // The height can be set with M420 Z<height>
886
   // The height can be set with M420 Z<height>
887
   #define ENABLE_LEVELING_FADE_HEIGHT
887
   #define ENABLE_LEVELING_FADE_HEIGHT
888
 
888
 
889
+  // For Cartesian machines, instead of dividing moves on mesh boundaries,
890
+  // split up moves into short segments like a Delta.
891
+  #define SEGMENT_LEVELED_MOVES
892
+  #define LEVELED_SEGMENT_LENGTH 5.0 // (mm) Length of all segments (except the last one)
893
+
889
   /**
894
   /**
890
    * Enable the G26 Mesh Validation Pattern tool.
895
    * Enable the G26 Mesh Validation Pattern tool.
891
    */
896
    */

+ 2
- 2
Marlin/src/feature/bedlevel/abl/abl.cpp View File

357
   return offset;
357
   return offset;
358
 }
358
 }
359
 
359
 
360
-#if !IS_KINEMATIC
360
+#if IS_CARTESIAN && DISABLED(SEGMENT_LEVELED_MOVES)
361
 
361
 
362
   #define CELL_INDEX(A,V) ((V - bilinear_start[A##_AXIS]) * ABL_BG_FACTOR(A##_AXIS))
362
   #define CELL_INDEX(A,V) ((V - bilinear_start[A##_AXIS]) * ABL_BG_FACTOR(A##_AXIS))
363
 
363
 
420
     bilinear_line_to_destination(fr_mm_s, x_splits, y_splits);
420
     bilinear_line_to_destination(fr_mm_s, x_splits, y_splits);
421
   }
421
   }
422
 
422
 
423
-#endif // !IS_KINEMATIC
423
+#endif // IS_CARTESIAN && !SEGMENT_LEVELED_MOVES
424
 
424
 
425
 #endif // AUTO_BED_LEVELING_BILINEAR
425
 #endif // AUTO_BED_LEVELING_BILINEAR

+ 1
- 1
Marlin/src/feature/bedlevel/abl/abl.h View File

42
     void bed_level_virt_interpolate();
42
     void bed_level_virt_interpolate();
43
   #endif
43
   #endif
44
 
44
 
45
-  #if !IS_KINEMATIC
45
+  #if IS_CARTESIAN && DISABLED(SEGMENT_LEVELED_MOVES)
46
     void bilinear_line_to_destination(const float fr_mm_s, uint16_t x_splits=0xFFFF, uint16_t y_splits=0xFFFF);
46
     void bilinear_line_to_destination(const float fr_mm_s, uint16_t x_splits=0xFFFF, uint16_t y_splits=0xFFFF);
47
   #endif
47
   #endif
48
 
48
 

+ 60
- 56
Marlin/src/feature/bedlevel/mbl/mesh_bed_leveling.cpp View File

52
     ZERO(z_values);
52
     ZERO(z_values);
53
   }
53
   }
54
 
54
 
55
-  /**
56
-   * Prepare a mesh-leveled linear move in a Cartesian setup,
57
-   * splitting the move where it crosses mesh borders.
58
-   */
59
-  void mesh_line_to_destination(const float fr_mm_s, uint8_t x_splits, uint8_t y_splits) {
60
-    int cx1 = mbl.cell_index_x(current_position[X_AXIS]),
61
-        cy1 = mbl.cell_index_y(current_position[Y_AXIS]),
62
-        cx2 = mbl.cell_index_x(destination[X_AXIS]),
63
-        cy2 = mbl.cell_index_y(destination[Y_AXIS]);
64
-    NOMORE(cx1, GRID_MAX_POINTS_X - 2);
65
-    NOMORE(cy1, GRID_MAX_POINTS_Y - 2);
66
-    NOMORE(cx2, GRID_MAX_POINTS_X - 2);
67
-    NOMORE(cy2, GRID_MAX_POINTS_Y - 2);
68
-
69
-    if (cx1 == cx2 && cy1 == cy2) {
70
-      // Start and end on same mesh square
71
-      buffer_line_to_destination(fr_mm_s);
72
-      set_current_from_destination();
73
-      return;
55
+  #if IS_CARTESIAN && DISABLED(SEGMENT_LEVELED_MOVES)
56
+
57
+    /**
58
+     * Prepare a mesh-leveled linear move in a Cartesian setup,
59
+     * splitting the move where it crosses mesh borders.
60
+     */
61
+    void mesh_line_to_destination(const float fr_mm_s, uint8_t x_splits, uint8_t y_splits) {
62
+      int cx1 = mbl.cell_index_x(current_position[X_AXIS]),
63
+          cy1 = mbl.cell_index_y(current_position[Y_AXIS]),
64
+          cx2 = mbl.cell_index_x(destination[X_AXIS]),
65
+          cy2 = mbl.cell_index_y(destination[Y_AXIS]);
66
+      NOMORE(cx1, GRID_MAX_POINTS_X - 2);
67
+      NOMORE(cy1, GRID_MAX_POINTS_Y - 2);
68
+      NOMORE(cx2, GRID_MAX_POINTS_X - 2);
69
+      NOMORE(cy2, GRID_MAX_POINTS_Y - 2);
70
+
71
+      if (cx1 == cx2 && cy1 == cy2) {
72
+        // Start and end on same mesh square
73
+        buffer_line_to_destination(fr_mm_s);
74
+        set_current_from_destination();
75
+        return;
76
+      }
77
+
78
+      #define MBL_SEGMENT_END(A) (current_position[A ##_AXIS] + (destination[A ##_AXIS] - current_position[A ##_AXIS]) * normalized_dist)
79
+
80
+      float normalized_dist, end[XYZE];
81
+
82
+      // Split at the left/front border of the right/top square
83
+      const int8_t gcx = max(cx1, cx2), gcy = max(cy1, cy2);
84
+      if (cx2 != cx1 && TEST(x_splits, gcx)) {
85
+        COPY(end, destination);
86
+        destination[X_AXIS] = mbl.index_to_xpos[gcx];
87
+        normalized_dist = (destination[X_AXIS] - current_position[X_AXIS]) / (end[X_AXIS] - current_position[X_AXIS]);
88
+        destination[Y_AXIS] = MBL_SEGMENT_END(Y);
89
+        CBI(x_splits, gcx);
90
+      }
91
+      else if (cy2 != cy1 && TEST(y_splits, gcy)) {
92
+        COPY(end, destination);
93
+        destination[Y_AXIS] = mbl.index_to_ypos[gcy];
94
+        normalized_dist = (destination[Y_AXIS] - current_position[Y_AXIS]) / (end[Y_AXIS] - current_position[Y_AXIS]);
95
+        destination[X_AXIS] = MBL_SEGMENT_END(X);
96
+        CBI(y_splits, gcy);
97
+      }
98
+      else {
99
+        // Already split on a border
100
+        buffer_line_to_destination(fr_mm_s);
101
+        set_current_from_destination();
102
+        return;
103
+      }
104
+
105
+      destination[Z_AXIS] = MBL_SEGMENT_END(Z);
106
+      destination[E_AXIS] = MBL_SEGMENT_END(E);
107
+
108
+      // Do the split and look for more borders
109
+      mesh_line_to_destination(fr_mm_s, x_splits, y_splits);
110
+
111
+      // Restore destination from stack
112
+      COPY(destination, end);
113
+      mesh_line_to_destination(fr_mm_s, x_splits, y_splits);
74
     }
114
     }
75
 
115
 
76
-    #define MBL_SEGMENT_END(A) (current_position[A ##_AXIS] + (destination[A ##_AXIS] - current_position[A ##_AXIS]) * normalized_dist)
77
-
78
-    float normalized_dist, end[XYZE];
79
-
80
-    // Split at the left/front border of the right/top square
81
-    const int8_t gcx = max(cx1, cx2), gcy = max(cy1, cy2);
82
-    if (cx2 != cx1 && TEST(x_splits, gcx)) {
83
-      COPY(end, destination);
84
-      destination[X_AXIS] = mbl.index_to_xpos[gcx];
85
-      normalized_dist = (destination[X_AXIS] - current_position[X_AXIS]) / (end[X_AXIS] - current_position[X_AXIS]);
86
-      destination[Y_AXIS] = MBL_SEGMENT_END(Y);
87
-      CBI(x_splits, gcx);
88
-    }
89
-    else if (cy2 != cy1 && TEST(y_splits, gcy)) {
90
-      COPY(end, destination);
91
-      destination[Y_AXIS] = mbl.index_to_ypos[gcy];
92
-      normalized_dist = (destination[Y_AXIS] - current_position[Y_AXIS]) / (end[Y_AXIS] - current_position[Y_AXIS]);
93
-      destination[X_AXIS] = MBL_SEGMENT_END(X);
94
-      CBI(y_splits, gcy);
95
-    }
96
-    else {
97
-      // Already split on a border
98
-      buffer_line_to_destination(fr_mm_s);
99
-      set_current_from_destination();
100
-      return;
101
-    }
102
-
103
-    destination[Z_AXIS] = MBL_SEGMENT_END(Z);
104
-    destination[E_AXIS] = MBL_SEGMENT_END(E);
105
-
106
-    // Do the split and look for more borders
107
-    mesh_line_to_destination(fr_mm_s, x_splits, y_splits);
108
-
109
-    // Restore destination from stack
110
-    COPY(destination, end);
111
-    mesh_line_to_destination(fr_mm_s, x_splits, y_splits);
112
-  }
116
+  #endif // IS_CARTESIAN && !SEGMENT_LEVELED_MOVES
113
 
117
 
114
   void mbl_mesh_report() {
118
   void mbl_mesh_report() {
115
     SERIAL_PROTOCOLLNPGM("Num X,Y: " STRINGIFY(GRID_MAX_POINTS_X) "," STRINGIFY(GRID_MAX_POINTS_Y));
119
     SERIAL_PROTOCOLLNPGM("Num X,Y: " STRINGIFY(GRID_MAX_POINTS_X) "," STRINGIFY(GRID_MAX_POINTS_Y));

+ 3
- 2
Marlin/src/feature/bedlevel/mbl/mesh_bed_leveling.h View File

110
 extern mesh_bed_leveling mbl;
110
 extern mesh_bed_leveling mbl;
111
 
111
 
112
 // Support functions, which may be embedded in the class later
112
 // Support functions, which may be embedded in the class later
113
-
114
-void mesh_line_to_destination(const float fr_mm_s, uint8_t x_splits=0xFF, uint8_t y_splits=0xFF);
113
+#if IS_CARTESIAN && DISABLED(SEGMENT_LEVELED_MOVES)
114
+  void mesh_line_to_destination(const float fr_mm_s, uint8_t x_splits=0xFF, uint8_t y_splits=0xFF);
115
+#endif
115
 
116
 
116
 void mbl_mesh_report();
117
 void mbl_mesh_report();
117
 
118
 

+ 5
- 1
Marlin/src/inc/Conditionals_post.h View File

934
 /**
934
 /**
935
  * Set granular options based on the specific type of leveling
935
  * Set granular options based on the specific type of leveling
936
  */
936
  */
937
-#define UBL_DELTA  (ENABLED(AUTO_BED_LEVELING_UBL) && (ENABLED(DELTA) || ENABLED(UBL_GRANULAR_SEGMENTATION_FOR_CARTESIAN)))
937
+#define UBL_DELTA  (ENABLED(AUTO_BED_LEVELING_UBL) && (ENABLED(DELTA) || ENABLED(SEGMENT_LEVELED_MOVES)))
938
 #define ABL_PLANAR (ENABLED(AUTO_BED_LEVELING_LINEAR) || ENABLED(AUTO_BED_LEVELING_3POINT))
938
 #define ABL_PLANAR (ENABLED(AUTO_BED_LEVELING_LINEAR) || ENABLED(AUTO_BED_LEVELING_3POINT))
939
 #define ABL_GRID   (ENABLED(AUTO_BED_LEVELING_LINEAR) || ENABLED(AUTO_BED_LEVELING_BILINEAR))
939
 #define ABL_GRID   (ENABLED(AUTO_BED_LEVELING_LINEAR) || ENABLED(AUTO_BED_LEVELING_BILINEAR))
940
 #define OLDSCHOOL_ABL         (ABL_PLANAR || ABL_GRID)
940
 #define OLDSCHOOL_ABL         (ABL_PLANAR || ABL_GRID)
949
   #define PROBE_BED_HEIGHT abs(BACK_PROBE_BED_POSITION - (FRONT_PROBE_BED_POSITION))
949
   #define PROBE_BED_HEIGHT abs(BACK_PROBE_BED_POSITION - (FRONT_PROBE_BED_POSITION))
950
 #endif
950
 #endif
951
 
951
 
952
+#if ENABLED(SEGMENT_LEVELED_MOVES) && !defined(LEVELED_SEGMENT_LENGTH)
953
+  #define LEVELED_SEGMENT_LENGTH 5
954
+#endif
955
+
952
 /**
956
 /**
953
  * Bed Probing rectangular bounds
957
  * Bed Probing rectangular bounds
954
  * These can be further constrained in code for Delta and SCARA
958
  * These can be further constrained in code for Delta and SCARA

+ 2
- 0
Marlin/src/inc/SanityCheck.h View File

223
   #error "ENABLE_MESH_EDIT_GFX_OVERLAY is now MESH_EDIT_GFX_OVERLAY. Please update your configuration."
223
   #error "ENABLE_MESH_EDIT_GFX_OVERLAY is now MESH_EDIT_GFX_OVERLAY. Please update your configuration."
224
 #elif defined(BABYSTEP_ZPROBE_GFX_REVERSE)
224
 #elif defined(BABYSTEP_ZPROBE_GFX_REVERSE)
225
   #error "BABYSTEP_ZPROBE_GFX_REVERSE is now set by OVERLAY_GFX_REVERSE. Please update your configurations."
225
   #error "BABYSTEP_ZPROBE_GFX_REVERSE is now set by OVERLAY_GFX_REVERSE. Please update your configurations."
226
+#elif defined(UBL_GRANULAR_SEGMENTATION_FOR_CARTESIAN)
227
+  #error "UBL_GRANULAR_SEGMENTATION_FOR_CARTESIAN is now SEGMENT_LEVELED_MOVES. Please update your configuration."
226
 #endif
228
 #endif
227
 
229
 
228
 /**
230
 /**

+ 92
- 15
Marlin/src/module/motion.cpp View File

522
     // Get the top feedrate of the move in the XY plane
522
     // Get the top feedrate of the move in the XY plane
523
     const float _feedrate_mm_s = MMS_SCALED(feedrate_mm_s);
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
     // If the move is only in Z/E don't split up the move
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
       planner.buffer_line_kinematic(rtarget, _feedrate_mm_s, active_extruder);
530
       planner.buffer_line_kinematic(rtarget, _feedrate_mm_s, active_extruder);
528
       return false;
531
       return false;
529
     }
532
     }
531
     // Fail if attempting move outside printable radius
534
     // Fail if attempting move outside printable radius
532
     if (!position_is_reachable(rtarget[X_AXIS], rtarget[Y_AXIS])) return true;
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
     // Get the linear distance in XYZ
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
     // If the move is very short, check the E move distance
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
     // No E move either? Game over.
547
     // No E move either? Game over.
549
     if (UNEAR_ZERO(cartesian_mm)) return true;
548
     if (UNEAR_ZERO(cartesian_mm)) return true;
566
     // The approximate length of each segment
565
     // The approximate length of each segment
567
     const float inv_segments = 1.0 / float(segments),
566
     const float inv_segments = 1.0 / float(segments),
568
                 segment_distance[XYZE] = {
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
     // SERIAL_ECHOPAIR("mm=", cartesian_mm);
574
     // SERIAL_ECHOPAIR("mm=", cartesian_mm);
644
 
643
 
645
 #else // !IS_KINEMATIC
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
    * Prepare a linear move in a Cartesian setup.
722
    * Prepare a linear move in a Cartesian setup.
649
    *
723
    *
654
    */
728
    */
655
   inline bool prepare_move_to_destination_cartesian() {
729
   inline bool prepare_move_to_destination_cartesian() {
656
     #if HAS_MESH
730
     #if HAS_MESH
657
-      if (planner.leveling_active) {
731
+      if (planner.leveling_active && planner.leveling_active_at_z(destination[Z_AXIS])) {
658
         #if ENABLED(AUTO_BED_LEVELING_UBL)
732
         #if ENABLED(AUTO_BED_LEVELING_UBL)
659
           ubl.line_to_destination_cartesian(MMS_SCALED(feedrate_mm_s), active_extruder);  // UBL's motion routine needs to know about
733
           ubl.line_to_destination_cartesian(MMS_SCALED(feedrate_mm_s), active_extruder);  // UBL's motion routine needs to know about
660
           return true;                                                                    // all moves, including Z-only moves.
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
         #else
738
         #else
662
           /**
739
           /**
663
            * For MBL and ABL-BILINEAR only segment moves when X or Y are involved.
740
            * For MBL and ABL-BILINEAR only segment moves when X or Y are involved.

Loading…
Cancel
Save