瀏覽代碼

Merge G2/G3 for Delta (PR#2469)

Richard Wackerbarth 10 年之前
父節點
當前提交
adfcfcba95
共有 1 個文件被更改,包括 156 次插入136 次删除
  1. 156
    136
      Marlin/Marlin_main.cpp

+ 156
- 136
Marlin/Marlin_main.cpp 查看文件

@@ -410,6 +410,8 @@ bool target_direction;
410 410
 
411 411
 void process_next_command();
412 412
 
413
+void plan_arc(float target[NUM_AXIS], float *offset, uint8_t clockwise);
414
+
413 415
 bool setTargetedHotend(int code);
414 416
 
415 417
 void serial_echopair_P(const char *s_P, float v)         { serialprintPGM(s_P); SERIAL_ECHO(v); }
@@ -1886,130 +1888,6 @@ inline void gcode_G0_G1() {
1886 1888
 }
1887 1889
 
1888 1890
 /**
1889
- * Plan an arc in 2 dimensions
1890
- *
1891
- * The arc is approximated by generating many small linear segments.
1892
- * The length of each segment is configured in MM_PER_ARC_SEGMENT (Default 1mm)
1893
- * Arcs should only be made relatively large (over 5mm), as larger arcs with
1894
- * larger segments will tend to be more efficient. Your slicer should have
1895
- * options for G2/G3 arc generation. In future these options may be GCode tunable.
1896
- */
1897
-void plan_arc(
1898
-  float *target,    // Destination position
1899
-  float *offset,    // Center of rotation relative to current_position
1900
-  uint8_t clockwise // Clockwise?
1901
-) {
1902
-
1903
-  float radius = hypot(offset[X_AXIS], offset[Y_AXIS]),
1904
-        center_axis0 = current_position[X_AXIS] + offset[X_AXIS],
1905
-        center_axis1 = current_position[Y_AXIS] + offset[Y_AXIS],
1906
-        linear_travel = target[Z_AXIS] - current_position[Z_AXIS],
1907
-        extruder_travel = target[E_AXIS] - current_position[E_AXIS],
1908
-        r_axis0 = -offset[X_AXIS],  // Radius vector from center to current location
1909
-        r_axis1 = -offset[Y_AXIS],
1910
-        rt_axis0 = target[X_AXIS] - center_axis0,
1911
-        rt_axis1 = target[Y_AXIS] - center_axis1;
1912
-  
1913
-  // CCW angle of rotation between position and target from the circle center. Only one atan2() trig computation required.
1914
-  float angular_travel = atan2(r_axis0*rt_axis1-r_axis1*rt_axis0, r_axis0*rt_axis0+r_axis1*rt_axis1);
1915
-  if (angular_travel < 0) { angular_travel += RADIANS(360); }
1916
-  if (clockwise) { angular_travel -= RADIANS(360); }
1917
-  
1918
-  // Make a circle if the angular rotation is 0
1919
-  if (current_position[X_AXIS] == target[X_AXIS] && current_position[Y_AXIS] == target[Y_AXIS] && angular_travel == 0)
1920
-    angular_travel += RADIANS(360);
1921
-  
1922
-  float mm_of_travel = hypot(angular_travel*radius, fabs(linear_travel));
1923
-  if (mm_of_travel < 0.001) { return; }
1924
-  uint16_t segments = floor(mm_of_travel / MM_PER_ARC_SEGMENT);
1925
-  if (segments == 0) segments = 1;
1926
-  
1927
-  float theta_per_segment = angular_travel/segments;
1928
-  float linear_per_segment = linear_travel/segments;
1929
-  float extruder_per_segment = extruder_travel/segments;
1930
-  
1931
-  /* Vector rotation by transformation matrix: r is the original vector, r_T is the rotated vector,
1932
-     and phi is the angle of rotation. Based on the solution approach by Jens Geisler.
1933
-         r_T = [cos(phi) -sin(phi);
1934
-                sin(phi)  cos(phi] * r ;
1935
-     
1936
-     For arc generation, the center of the circle is the axis of rotation and the radius vector is 
1937
-     defined from the circle center to the initial position. Each line segment is formed by successive
1938
-     vector rotations. This requires only two cos() and sin() computations to form the rotation
1939
-     matrix for the duration of the entire arc. Error may accumulate from numerical round-off, since
1940
-     all double numbers are single precision on the Arduino. (True double precision will not have
1941
-     round off issues for CNC applications.) Single precision error can accumulate to be greater than
1942
-     tool precision in some cases. Therefore, arc path correction is implemented. 
1943
-
1944
-     Small angle approximation may be used to reduce computation overhead further. This approximation
1945
-     holds for everything, but very small circles and large MM_PER_ARC_SEGMENT values. In other words,
1946
-     theta_per_segment would need to be greater than 0.1 rad and N_ARC_CORRECTION would need to be large
1947
-     to cause an appreciable drift error. N_ARC_CORRECTION~=25 is more than small enough to correct for 
1948
-     numerical drift error. N_ARC_CORRECTION may be on the order a hundred(s) before error becomes an
1949
-     issue for CNC machines with the single precision Arduino calculations.
1950
-     
1951
-     This approximation also allows plan_arc to immediately insert a line segment into the planner 
1952
-     without the initial overhead of computing cos() or sin(). By the time the arc needs to be applied
1953
-     a correction, the planner should have caught up to the lag caused by the initial plan_arc overhead. 
1954
-     This is important when there are successive arc motions. 
1955
-  */
1956
-  // Vector rotation matrix values
1957
-  float cos_T = 1-0.5*theta_per_segment*theta_per_segment; // Small angle approximation
1958
-  float sin_T = theta_per_segment;
1959
-  
1960
-  float arc_target[4];
1961
-  float sin_Ti;
1962
-  float cos_Ti;
1963
-  float r_axisi;
1964
-  uint16_t i;
1965
-  int8_t count = 0;
1966
-
1967
-  // Initialize the linear axis
1968
-  arc_target[Z_AXIS] = current_position[Z_AXIS];
1969
-  
1970
-  // Initialize the extruder axis
1971
-  arc_target[E_AXIS] = current_position[E_AXIS];
1972
-
1973
-  float feed_rate = feedrate*feedrate_multiplier/60/100.0;
1974
-
1975
-  for (i = 1; i < segments; i++) { // Increment (segments-1)
1976
-
1977
-    if (count < N_ARC_CORRECTION) {
1978
-      // Apply vector rotation matrix to previous r_axis0 / 1
1979
-      r_axisi = r_axis0*sin_T + r_axis1*cos_T;
1980
-      r_axis0 = r_axis0*cos_T - r_axis1*sin_T;
1981
-      r_axis1 = r_axisi;
1982
-      count++;
1983
-    }
1984
-    else {
1985
-      // Arc correction to radius vector. Computed only every N_ARC_CORRECTION increments.
1986
-      // Compute exact location by applying transformation matrix from initial radius vector(=-offset).
1987
-      cos_Ti = cos(i*theta_per_segment);
1988
-      sin_Ti = sin(i*theta_per_segment);
1989
-      r_axis0 = -offset[X_AXIS]*cos_Ti + offset[Y_AXIS]*sin_Ti;
1990
-      r_axis1 = -offset[X_AXIS]*sin_Ti - offset[Y_AXIS]*cos_Ti;
1991
-      count = 0;
1992
-    }
1993
-
1994
-    // Update arc_target location
1995
-    arc_target[X_AXIS] = center_axis0 + r_axis0;
1996
-    arc_target[Y_AXIS] = center_axis1 + r_axis1;
1997
-    arc_target[Z_AXIS] += linear_per_segment;
1998
-    arc_target[E_AXIS] += extruder_per_segment;
1999
-
2000
-    clamp_to_software_endstops(arc_target);
2001
-    plan_buffer_line(arc_target[X_AXIS], arc_target[Y_AXIS], arc_target[Z_AXIS], arc_target[E_AXIS], feed_rate, active_extruder);
2002
-  }
2003
-  // Ensure last segment arrives at target location.
2004
-  plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], feed_rate, active_extruder);
2005
-
2006
-  // As far as the parser is concerned, the position is now == target. In reality the
2007
-  // motion control system might still be processing the action and the real tool position
2008
-  // in any intermediate location.
2009
-  set_current_to_destination();
2010
-}
2011
-
2012
-/**
2013 1891
  * G2: Clockwise Arc
2014 1892
  * G3: Counterclockwise Arc
2015 1893
  */
@@ -6074,9 +5952,9 @@ void mesh_plan_buffer_line(float x, float y, float z, const float e, float feed_
6074 5952
 
6075 5953
 #if defined(DELTA) || defined(SCARA)
6076 5954
 
6077
-  inline bool prepare_move_delta() {
5955
+  inline bool prepare_move_delta(float target[NUM_AXIS]) {
6078 5956
     float difference[NUM_AXIS];
6079
-    for (int8_t i=0; i < NUM_AXIS; i++) difference[i] = destination[i] - current_position[i];
5957
+    for (int8_t i=0; i < NUM_AXIS; i++) difference[i] = target[i] - current_position[i];
6080 5958
 
6081 5959
     float cartesian_mm = sqrt(sq(difference[X_AXIS]) + sq(difference[Y_AXIS]) + sq(difference[Z_AXIS]));
6082 5960
     if (cartesian_mm < 0.000001) cartesian_mm = abs(difference[E_AXIS]);
@@ -6093,22 +5971,22 @@ void mesh_plan_buffer_line(float x, float y, float z, const float e, float feed_
6093 5971
       float fraction = float(s) / float(steps);
6094 5972
 
6095 5973
       for (int8_t i = 0; i < NUM_AXIS; i++)
6096
-        destination[i] = current_position[i] + difference[i] * fraction;
5974
+        target[i] = current_position[i] + difference[i] * fraction;
6097 5975
 
6098
-      calculate_delta(destination);
5976
+      calculate_delta(target);
6099 5977
 
6100 5978
       #ifdef ENABLE_AUTO_BED_LEVELING
6101
-        adjust_delta(destination);
5979
+        adjust_delta(target);
6102 5980
       #endif
6103 5981
 
6104
-      //SERIAL_ECHOPGM("destination[X_AXIS]="); SERIAL_ECHOLN(destination[X_AXIS]);
6105
-      //SERIAL_ECHOPGM("destination[Y_AXIS]="); SERIAL_ECHOLN(destination[Y_AXIS]);
6106
-      //SERIAL_ECHOPGM("destination[Z_AXIS]="); SERIAL_ECHOLN(destination[Z_AXIS]);
5982
+      //SERIAL_ECHOPGM("target[X_AXIS]="); SERIAL_ECHOLN(target[X_AXIS]);
5983
+      //SERIAL_ECHOPGM("target[Y_AXIS]="); SERIAL_ECHOLN(target[Y_AXIS]);
5984
+      //SERIAL_ECHOPGM("target[Z_AXIS]="); SERIAL_ECHOLN(target[Z_AXIS]);
6107 5985
       //SERIAL_ECHOPGM("delta[X_AXIS]="); SERIAL_ECHOLN(delta[X_AXIS]);
6108 5986
       //SERIAL_ECHOPGM("delta[Y_AXIS]="); SERIAL_ECHOLN(delta[Y_AXIS]);
6109 5987
       //SERIAL_ECHOPGM("delta[Z_AXIS]="); SERIAL_ECHOLN(delta[Z_AXIS]);
6110 5988
 
6111
-      plan_buffer_line(delta[X_AXIS], delta[Y_AXIS], delta[Z_AXIS], destination[E_AXIS], feedrate/60*feedrate_multiplier/100.0, active_extruder);
5989
+      plan_buffer_line(delta[X_AXIS], delta[Y_AXIS], delta[Z_AXIS], target[E_AXIS], feedrate/60*feedrate_multiplier/100.0, active_extruder);
6112 5990
     }
6113 5991
     return true;
6114 5992
   }
@@ -6116,7 +5994,7 @@ void mesh_plan_buffer_line(float x, float y, float z, const float e, float feed_
6116 5994
 #endif // DELTA || SCARA
6117 5995
 
6118 5996
 #ifdef SCARA
6119
-  inline bool prepare_move_scara() { return prepare_move_delta(); }
5997
+  inline bool prepare_move_scara(float target[NUM_AXIS]) { return prepare_move_delta(target); }
6120 5998
 #endif
6121 5999
 
6122 6000
 #ifdef DUAL_X_CARRIAGE
@@ -6193,9 +6071,9 @@ void prepare_move() {
6193 6071
   #endif
6194 6072
 
6195 6073
   #ifdef SCARA
6196
-    if (!prepare_move_scara()) return;
6074
+    if (!prepare_move_scara(destination)) return;
6197 6075
   #elif defined(DELTA)
6198
-    if (!prepare_move_delta()) return;
6076
+    if (!prepare_move_delta(destination)) return;
6199 6077
   #endif
6200 6078
 
6201 6079
   #ifdef DUAL_X_CARRIAGE
@@ -6209,6 +6087,148 @@ void prepare_move() {
6209 6087
   set_current_to_destination();
6210 6088
 }
6211 6089
 
6090
+/**
6091
+ * Plan an arc in 2 dimensions
6092
+ *
6093
+ * The arc is approximated by generating many small linear segments.
6094
+ * The length of each segment is configured in MM_PER_ARC_SEGMENT (Default 1mm)
6095
+ * Arcs should only be made relatively large (over 5mm), as larger arcs with
6096
+ * larger segments will tend to be more efficient. Your slicer should have
6097
+ * options for G2/G3 arc generation. In future these options may be GCode tunable.
6098
+ */
6099
+void plan_arc(
6100
+  float target[NUM_AXIS], // Destination position
6101
+  float *offset,          // Center of rotation relative to current_position
6102
+  uint8_t clockwise       // Clockwise?
6103
+) {
6104
+
6105
+  float radius = hypot(offset[X_AXIS], offset[Y_AXIS]),
6106
+        center_axis0 = current_position[X_AXIS] + offset[X_AXIS],
6107
+        center_axis1 = current_position[Y_AXIS] + offset[Y_AXIS],
6108
+        linear_travel = target[Z_AXIS] - current_position[Z_AXIS],
6109
+        extruder_travel = target[E_AXIS] - current_position[E_AXIS],
6110
+        r_axis0 = -offset[X_AXIS],  // Radius vector from center to current location
6111
+        r_axis1 = -offset[Y_AXIS],
6112
+        rt_axis0 = target[X_AXIS] - center_axis0,
6113
+        rt_axis1 = target[Y_AXIS] - center_axis1;
6114
+  
6115
+  // CCW angle of rotation between position and target from the circle center. Only one atan2() trig computation required.
6116
+  float angular_travel = atan2(r_axis0*rt_axis1-r_axis1*rt_axis0, r_axis0*rt_axis0+r_axis1*rt_axis1);
6117
+  if (angular_travel < 0) { angular_travel += RADIANS(360); }
6118
+  if (clockwise) { angular_travel -= RADIANS(360); }
6119
+  
6120
+  // Make a circle if the angular rotation is 0
6121
+  if (current_position[X_AXIS] == target[X_AXIS] && current_position[Y_AXIS] == target[Y_AXIS] && angular_travel == 0)
6122
+    angular_travel += RADIANS(360);
6123
+  
6124
+  float mm_of_travel = hypot(angular_travel*radius, fabs(linear_travel));
6125
+  if (mm_of_travel < 0.001) { return; }
6126
+  uint16_t segments = floor(mm_of_travel / MM_PER_ARC_SEGMENT);
6127
+  if (segments == 0) segments = 1;
6128
+  
6129
+  float theta_per_segment = angular_travel/segments;
6130
+  float linear_per_segment = linear_travel/segments;
6131
+  float extruder_per_segment = extruder_travel/segments;
6132
+  
6133
+  /* Vector rotation by transformation matrix: r is the original vector, r_T is the rotated vector,
6134
+     and phi is the angle of rotation. Based on the solution approach by Jens Geisler.
6135
+         r_T = [cos(phi) -sin(phi);
6136
+                sin(phi)  cos(phi] * r ;
6137
+     
6138
+     For arc generation, the center of the circle is the axis of rotation and the radius vector is 
6139
+     defined from the circle center to the initial position. Each line segment is formed by successive
6140
+     vector rotations. This requires only two cos() and sin() computations to form the rotation
6141
+     matrix for the duration of the entire arc. Error may accumulate from numerical round-off, since
6142
+     all double numbers are single precision on the Arduino. (True double precision will not have
6143
+     round off issues for CNC applications.) Single precision error can accumulate to be greater than
6144
+     tool precision in some cases. Therefore, arc path correction is implemented. 
6145
+
6146
+     Small angle approximation may be used to reduce computation overhead further. This approximation
6147
+     holds for everything, but very small circles and large MM_PER_ARC_SEGMENT values. In other words,
6148
+     theta_per_segment would need to be greater than 0.1 rad and N_ARC_CORRECTION would need to be large
6149
+     to cause an appreciable drift error. N_ARC_CORRECTION~=25 is more than small enough to correct for 
6150
+     numerical drift error. N_ARC_CORRECTION may be on the order a hundred(s) before error becomes an
6151
+     issue for CNC machines with the single precision Arduino calculations.
6152
+     
6153
+     This approximation also allows plan_arc to immediately insert a line segment into the planner 
6154
+     without the initial overhead of computing cos() or sin(). By the time the arc needs to be applied
6155
+     a correction, the planner should have caught up to the lag caused by the initial plan_arc overhead. 
6156
+     This is important when there are successive arc motions. 
6157
+  */
6158
+  // Vector rotation matrix values
6159
+  float cos_T = 1-0.5*theta_per_segment*theta_per_segment; // Small angle approximation
6160
+  float sin_T = theta_per_segment;
6161
+  
6162
+  float arc_target[NUM_AXIS];
6163
+  float sin_Ti;
6164
+  float cos_Ti;
6165
+  float r_axisi;
6166
+  uint16_t i;
6167
+  int8_t count = 0;
6168
+
6169
+  // Initialize the linear axis
6170
+  arc_target[Z_AXIS] = current_position[Z_AXIS];
6171
+  
6172
+  // Initialize the extruder axis
6173
+  arc_target[E_AXIS] = current_position[E_AXIS];
6174
+
6175
+  float feed_rate = feedrate*feedrate_multiplier/60/100.0;
6176
+
6177
+  for (i = 1; i < segments; i++) { // Increment (segments-1)
6178
+
6179
+    if (count < N_ARC_CORRECTION) {
6180
+      // Apply vector rotation matrix to previous r_axis0 / 1
6181
+      r_axisi = r_axis0*sin_T + r_axis1*cos_T;
6182
+      r_axis0 = r_axis0*cos_T - r_axis1*sin_T;
6183
+      r_axis1 = r_axisi;
6184
+      count++;
6185
+    }
6186
+    else {
6187
+      // Arc correction to radius vector. Computed only every N_ARC_CORRECTION increments.
6188
+      // Compute exact location by applying transformation matrix from initial radius vector(=-offset).
6189
+      cos_Ti = cos(i*theta_per_segment);
6190
+      sin_Ti = sin(i*theta_per_segment);
6191
+      r_axis0 = -offset[X_AXIS]*cos_Ti + offset[Y_AXIS]*sin_Ti;
6192
+      r_axis1 = -offset[X_AXIS]*sin_Ti - offset[Y_AXIS]*cos_Ti;
6193
+      count = 0;
6194
+    }
6195
+
6196
+    // Update arc_target location
6197
+    arc_target[X_AXIS] = center_axis0 + r_axis0;
6198
+    arc_target[Y_AXIS] = center_axis1 + r_axis1;
6199
+    arc_target[Z_AXIS] += linear_per_segment;
6200
+    arc_target[E_AXIS] += extruder_per_segment;
6201
+
6202
+    clamp_to_software_endstops(arc_target);
6203
+
6204
+    #if defined(DELTA) || defined(SCARA)
6205
+      calculate_delta(arc_target);
6206
+      #ifdef ENABLE_AUTO_BED_LEVELING
6207
+        adjust_delta(arc_target);
6208
+      #endif
6209
+      plan_buffer_line(delta[X_AXIS], delta[Y_AXIS], delta[Z_AXIS], arc_target[E_AXIS], feed_rate, active_extruder);
6210
+    #else
6211
+      plan_buffer_line(arc_target[X_AXIS], arc_target[Y_AXIS], arc_target[Z_AXIS], arc_target[E_AXIS], feed_rate, active_extruder);
6212
+    #endif
6213
+  }
6214
+
6215
+  // Ensure last segment arrives at target location.
6216
+  #if defined(DELTA) || defined(SCARA)
6217
+    calculate_delta(target);
6218
+    #ifdef ENABLE_AUTO_BED_LEVELING
6219
+      adjust_delta(target);
6220
+    #endif
6221
+    plan_buffer_line(delta[X_AXIS], delta[Y_AXIS], delta[Z_AXIS], target[E_AXIS], feed_rate, active_extruder);
6222
+  #else
6223
+    plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], feed_rate, active_extruder);
6224
+  #endif
6225
+
6226
+  // As far as the parser is concerned, the position is now == target. In reality the
6227
+  // motion control system might still be processing the action and the real tool position
6228
+  // in any intermediate location.
6229
+  set_current_to_destination();
6230
+}
6231
+
6212 6232
 #if HAS_CONTROLLERFAN
6213 6233
 
6214 6234
   void controllerFan() {

Loading…
取消
儲存