Browse Source

Merge pull request #4997 from thinkyhead/rc_jerk_from_mk2

Adapt Jerk / Speed code from Prusa MK2
Scott Lahteine 8 years ago
parent
commit
0921c7da84
2 changed files with 201 additions and 116 deletions
  1. 175
    102
      Marlin/planner.cpp
  2. 26
    14
      Marlin/planner.h

+ 175
- 102
Marlin/planner.cpp View File

85
       Planner::axis_steps_per_mm[NUM_AXIS],
85
       Planner::axis_steps_per_mm[NUM_AXIS],
86
       Planner::steps_to_mm[NUM_AXIS];
86
       Planner::steps_to_mm[NUM_AXIS];
87
 
87
 
88
-unsigned long Planner::max_acceleration_steps_per_s2[NUM_AXIS],
89
-              Planner::max_acceleration_mm_per_s2[NUM_AXIS]; // Use M201 to override by software
88
+uint32_t Planner::max_acceleration_steps_per_s2[NUM_AXIS],
89
+         Planner::max_acceleration_mm_per_s2[NUM_AXIS]; // Use M201 to override by software
90
 
90
 
91
 millis_t Planner::min_segment_time;
91
 millis_t Planner::min_segment_time;
92
 float Planner::min_feedrate_mm_s,
92
 float Planner::min_feedrate_mm_s,
145
   #endif
145
   #endif
146
 }
146
 }
147
 
147
 
148
+#define MINIMAL_STEP_RATE 120
149
+
148
 /**
150
 /**
149
  * Calculate trapezoid parameters, multiplying the entry- and exit-speeds
151
  * Calculate trapezoid parameters, multiplying the entry- and exit-speeds
150
  * by the provided factors.
152
  * by the provided factors.
151
  */
153
  */
152
-void Planner::calculate_trapezoid_for_block(block_t* block, float entry_factor, float exit_factor) {
154
+void Planner::calculate_trapezoid_for_block(block_t* const block, const float &entry_factor, const float &exit_factor) {
153
   uint32_t initial_rate = ceil(block->nominal_rate * entry_factor),
155
   uint32_t initial_rate = ceil(block->nominal_rate * entry_factor),
154
            final_rate = ceil(block->nominal_rate * exit_factor); // (steps per second)
156
            final_rate = ceil(block->nominal_rate * exit_factor); // (steps per second)
155
 
157
 
156
   // Limit minimal step rate (Otherwise the timer will overflow.)
158
   // Limit minimal step rate (Otherwise the timer will overflow.)
157
-  NOLESS(initial_rate, 120);
158
-  NOLESS(final_rate, 120);
159
+  NOLESS(initial_rate, MINIMAL_STEP_RATE);
160
+  NOLESS(final_rate, MINIMAL_STEP_RATE);
159
 
161
 
160
   int32_t accel = block->acceleration_steps_per_s2,
162
   int32_t accel = block->acceleration_steps_per_s2,
161
           accelerate_steps = ceil(estimate_acceleration_distance(initial_rate, block->nominal_rate, accel)),
163
           accelerate_steps = ceil(estimate_acceleration_distance(initial_rate, block->nominal_rate, accel)),
172
     plateau_steps = 0;
174
     plateau_steps = 0;
173
   }
175
   }
174
 
176
 
175
-  #if ENABLED(ADVANCE)
176
-    volatile int32_t initial_advance = block->advance * sq(entry_factor),
177
-                       final_advance = block->advance * sq(exit_factor);
178
-  #endif // ADVANCE
179
-
180
   // block->accelerate_until = accelerate_steps;
177
   // block->accelerate_until = accelerate_steps;
181
   // block->decelerate_after = accelerate_steps+plateau_steps;
178
   // block->decelerate_after = accelerate_steps+plateau_steps;
179
+
182
   CRITICAL_SECTION_START;  // Fill variables used by the stepper in a critical section
180
   CRITICAL_SECTION_START;  // Fill variables used by the stepper in a critical section
183
   if (!block->busy) { // Don't update variables if block is busy.
181
   if (!block->busy) { // Don't update variables if block is busy.
184
     block->accelerate_until = accelerate_steps;
182
     block->accelerate_until = accelerate_steps;
186
     block->initial_rate = initial_rate;
184
     block->initial_rate = initial_rate;
187
     block->final_rate = final_rate;
185
     block->final_rate = final_rate;
188
     #if ENABLED(ADVANCE)
186
     #if ENABLED(ADVANCE)
189
-      block->initial_advance = initial_advance;
190
-      block->final_advance = final_advance;
187
+      block->initial_advance = block->advance * sq(entry_factor);
188
+      block->final_advance = block->advance * sq(exit_factor);
191
     #endif
189
     #endif
192
   }
190
   }
193
   CRITICAL_SECTION_END;
191
   CRITICAL_SECTION_END;
203
 
201
 
204
 
202
 
205
 // The kernel called by recalculate() when scanning the plan from last to first entry.
203
 // The kernel called by recalculate() when scanning the plan from last to first entry.
206
-void Planner::reverse_pass_kernel(block_t* current, block_t* next) {
207
-  if (!current) return;
208
-
209
-  if (next) {
210
-    // If entry speed is already at the maximum entry speed, no need to recheck. Block is cruising.
211
-    // If not, block in state of acceleration or deceleration. Reset entry speed to maximum and
212
-    // check for maximum allowable speed reductions to ensure maximum possible planned speed.
213
-    float max_entry_speed = current->max_entry_speed;
214
-    if (current->entry_speed != max_entry_speed) {
215
-
216
-      // If nominal length true, max junction speed is guaranteed to be reached. Only compute
217
-      // for max allowable speed if block is decelerating and nominal length is false.
218
-      if (!current->nominal_length_flag && max_entry_speed > next->entry_speed) {
219
-        current->entry_speed = min(max_entry_speed,
220
-                                   max_allowable_speed(-current->acceleration, next->entry_speed, current->millimeters));
221
-      }
222
-      else {
223
-        current->entry_speed = max_entry_speed;
224
-      }
225
-      current->recalculate_flag = true;
226
-
227
-    }
228
-  } // Skip last block. Already initialized and set for recalculation.
204
+void Planner::reverse_pass_kernel(block_t* const current, const block_t *next) {
205
+  if (!current || !next) return;
206
+  // If entry speed is already at the maximum entry speed, no need to recheck. Block is cruising.
207
+  // If not, block in state of acceleration or deceleration. Reset entry speed to maximum and
208
+  // check for maximum allowable speed reductions to ensure maximum possible planned speed.
209
+  float max_entry_speed = current->max_entry_speed;
210
+  if (current->entry_speed != max_entry_speed) {
211
+    // If nominal length true, max junction speed is guaranteed to be reached. Only compute
212
+    // for max allowable speed if block is decelerating and nominal length is false.
213
+    current->entry_speed = ((current->flag & BLOCK_FLAG_NOMINAL_LENGTH) || max_entry_speed <= next->entry_speed)
214
+      ? max_entry_speed
215
+      : min(max_entry_speed, max_allowable_speed(-current->acceleration, next->entry_speed, current->millimeters));
216
+    current->flag |= BLOCK_FLAG_RECALCULATE;
217
+  }
229
 }
218
 }
230
 
219
 
231
 /**
220
 /**
239
     block_t* block[3] = { NULL, NULL, NULL };
228
     block_t* block[3] = { NULL, NULL, NULL };
240
 
229
 
241
     // Make a local copy of block_buffer_tail, because the interrupt can alter it
230
     // Make a local copy of block_buffer_tail, because the interrupt can alter it
242
-    CRITICAL_SECTION_START;
243
-      uint8_t tail = block_buffer_tail;
244
-    CRITICAL_SECTION_END
231
+    // Is a critical section REALLY needed for a single byte change?
232
+    //CRITICAL_SECTION_START;
233
+    uint8_t tail = block_buffer_tail;
234
+    //CRITICAL_SECTION_END
245
 
235
 
246
     uint8_t b = BLOCK_MOD(block_buffer_head - 3);
236
     uint8_t b = BLOCK_MOD(block_buffer_head - 3);
247
     while (b != tail) {
237
     while (b != tail) {
238
+      if (block[0] && (block[0]->flag & BLOCK_FLAG_START_FROM_FULL_HALT)) break;
248
       b = prev_block_index(b);
239
       b = prev_block_index(b);
249
       block[2] = block[1];
240
       block[2] = block[1];
250
       block[1] = block[0];
241
       block[1] = block[0];
255
 }
246
 }
256
 
247
 
257
 // The kernel called by recalculate() when scanning the plan from first to last entry.
248
 // The kernel called by recalculate() when scanning the plan from first to last entry.
258
-void Planner::forward_pass_kernel(block_t* previous, block_t* current) {
249
+void Planner::forward_pass_kernel(const block_t* previous, block_t* const current) {
259
   if (!previous) return;
250
   if (!previous) return;
260
 
251
 
261
   // If the previous block is an acceleration block, but it is not long enough to complete the
252
   // If the previous block is an acceleration block, but it is not long enough to complete the
262
   // full speed change within the block, we need to adjust the entry speed accordingly. Entry
253
   // full speed change within the block, we need to adjust the entry speed accordingly. Entry
263
   // speeds have already been reset, maximized, and reverse planned by reverse planner.
254
   // speeds have already been reset, maximized, and reverse planned by reverse planner.
264
   // If nominal length is true, max junction speed is guaranteed to be reached. No need to recheck.
255
   // If nominal length is true, max junction speed is guaranteed to be reached. No need to recheck.
265
-  if (!previous->nominal_length_flag) {
256
+  if (!(previous->flag & BLOCK_FLAG_NOMINAL_LENGTH)) {
266
     if (previous->entry_speed < current->entry_speed) {
257
     if (previous->entry_speed < current->entry_speed) {
267
       float entry_speed = min(current->entry_speed,
258
       float entry_speed = min(current->entry_speed,
268
                                max_allowable_speed(-previous->acceleration, previous->entry_speed, previous->millimeters));
259
                                max_allowable_speed(-previous->acceleration, previous->entry_speed, previous->millimeters));
269
       // Check for junction speed change
260
       // Check for junction speed change
270
       if (current->entry_speed != entry_speed) {
261
       if (current->entry_speed != entry_speed) {
271
         current->entry_speed = entry_speed;
262
         current->entry_speed = entry_speed;
272
-        current->recalculate_flag = true;
263
+        current->flag |= BLOCK_FLAG_RECALCULATE;
273
       }
264
       }
274
     }
265
     }
275
   }
266
   }
298
  */
289
  */
299
 void Planner::recalculate_trapezoids() {
290
 void Planner::recalculate_trapezoids() {
300
   int8_t block_index = block_buffer_tail;
291
   int8_t block_index = block_buffer_tail;
301
-  block_t* current;
302
-  block_t* next = NULL;
292
+  block_t *current, *next = NULL;
303
 
293
 
304
   while (block_index != block_buffer_head) {
294
   while (block_index != block_buffer_head) {
305
     current = next;
295
     current = next;
306
     next = &block_buffer[block_index];
296
     next = &block_buffer[block_index];
307
     if (current) {
297
     if (current) {
308
       // Recalculate if current block entry or exit junction speed has changed.
298
       // Recalculate if current block entry or exit junction speed has changed.
309
-      if (current->recalculate_flag || next->recalculate_flag) {
299
+      if ((current->flag & BLOCK_FLAG_RECALCULATE) || (next->flag & BLOCK_FLAG_RECALCULATE)) {
310
         // NOTE: Entry and exit factors always > 0 by all previous logic operations.
300
         // NOTE: Entry and exit factors always > 0 by all previous logic operations.
311
         float nom = current->nominal_speed;
301
         float nom = current->nominal_speed;
312
         calculate_trapezoid_for_block(current, current->entry_speed / nom, next->entry_speed / nom);
302
         calculate_trapezoid_for_block(current, current->entry_speed / nom, next->entry_speed / nom);
313
-        current->recalculate_flag = false; // Reset current only to ensure next trapezoid is computed
303
+        current->flag &= ~BLOCK_FLAG_RECALCULATE; // Reset current only to ensure next trapezoid is computed
314
       }
304
       }
315
     }
305
     }
316
     block_index = next_block_index(block_index);
306
     block_index = next_block_index(block_index);
319
   if (next) {
309
   if (next) {
320
     float nom = next->nominal_speed;
310
     float nom = next->nominal_speed;
321
     calculate_trapezoid_for_block(next, next->entry_speed / nom, (MINIMUM_PLANNER_SPEED) / nom);
311
     calculate_trapezoid_for_block(next, next->entry_speed / nom, (MINIMUM_PLANNER_SPEED) / nom);
322
-    next->recalculate_flag = false;
312
+    next->flag &= ~BLOCK_FLAG_RECALCULATE;
323
   }
313
   }
324
 }
314
 }
325
 
315
 
706
   // Bail if this is a zero-length block
696
   // Bail if this is a zero-length block
707
   if (block->step_event_count < MIN_STEPS_PER_SEGMENT) return;
697
   if (block->step_event_count < MIN_STEPS_PER_SEGMENT) return;
708
 
698
 
699
+  // Clear the block flags
700
+  block->flag = 0;
701
+
709
   // For a mixing extruder, get a magnified step_event_count for each
702
   // For a mixing extruder, get a magnified step_event_count for each
710
   #if ENABLED(MIXING_EXTRUDER)
703
   #if ENABLED(MIXING_EXTRUDER)
711
     for (uint8_t i = 0; i < MIXING_STEPPERS; i++)
704
     for (uint8_t i = 0; i < MIXING_STEPPERS; i++)
1021
 
1014
 
1022
   // Compute and limit the acceleration rate for the trapezoid generator.
1015
   // Compute and limit the acceleration rate for the trapezoid generator.
1023
   float steps_per_mm = block->step_event_count / block->millimeters;
1016
   float steps_per_mm = block->step_event_count / block->millimeters;
1017
+  uint32_t accel;
1024
   if (!block->steps[X_AXIS] && !block->steps[Y_AXIS] && !block->steps[Z_AXIS]) {
1018
   if (!block->steps[X_AXIS] && !block->steps[Y_AXIS] && !block->steps[Z_AXIS]) {
1025
-    block->acceleration_steps_per_s2 = ceil(retract_acceleration * steps_per_mm); // convert to: acceleration steps/sec^2
1019
+    // convert to: acceleration steps/sec^2
1020
+    accel = ceil(retract_acceleration * steps_per_mm);
1026
   }
1021
   }
1027
   else {
1022
   else {
1023
+    #define LIMIT_ACCEL(AXIS) do{ \
1024
+      const uint32_t comp = max_acceleration_steps_per_s2[AXIS] * block->step_event_count; \
1025
+      if (accel * block->steps[AXIS] > comp) accel = comp / block->steps[AXIS]; \
1026
+    }while(0)
1027
+
1028
+    // Start with print or travel acceleration
1029
+    accel = ceil((block->steps[E_AXIS] ? acceleration : travel_acceleration) * steps_per_mm);
1030
+
1028
     // Limit acceleration per axis
1031
     // Limit acceleration per axis
1029
-    block->acceleration_steps_per_s2 = ceil((block->steps[E_AXIS] ? acceleration : travel_acceleration) * steps_per_mm);
1030
-    if (max_acceleration_steps_per_s2[X_AXIS] < (block->acceleration_steps_per_s2 * block->steps[X_AXIS]) / block->step_event_count)
1031
-      block->acceleration_steps_per_s2 = (max_acceleration_steps_per_s2[X_AXIS] * block->step_event_count) / block->steps[X_AXIS];
1032
-    if (max_acceleration_steps_per_s2[Y_AXIS] < (block->acceleration_steps_per_s2 * block->steps[Y_AXIS]) / block->step_event_count)
1033
-      block->acceleration_steps_per_s2 = (max_acceleration_steps_per_s2[Y_AXIS] * block->step_event_count) / block->steps[Y_AXIS];
1034
-    if (max_acceleration_steps_per_s2[Z_AXIS] < (block->acceleration_steps_per_s2 * block->steps[Z_AXIS]) / block->step_event_count)
1035
-      block->acceleration_steps_per_s2 = (max_acceleration_steps_per_s2[Z_AXIS] * block->step_event_count) / block->steps[Z_AXIS];
1036
-    if (max_acceleration_steps_per_s2[E_AXIS] < (block->acceleration_steps_per_s2 * block->steps[E_AXIS]) / block->step_event_count)
1037
-      block->acceleration_steps_per_s2 = (max_acceleration_steps_per_s2[E_AXIS] * block->step_event_count) / block->steps[E_AXIS];
1032
+    LIMIT_ACCEL(X_AXIS);
1033
+    LIMIT_ACCEL(Y_AXIS);
1034
+    LIMIT_ACCEL(Z_AXIS);
1035
+    LIMIT_ACCEL(E_AXIS);
1038
   }
1036
   }
1039
-  block->acceleration = block->acceleration_steps_per_s2 / steps_per_mm;
1040
-  block->acceleration_rate = (long)(block->acceleration_steps_per_s2 * 16777216.0 / ((F_CPU) * 0.125));
1037
+  block->acceleration_steps_per_s2 = accel;
1038
+  block->acceleration = accel / steps_per_mm;
1039
+  block->acceleration_rate = (long)(accel * 16777216.0 / ((F_CPU) * 0.125)); // * 8.388608
1040
+
1041
+  // Initial limit on the segment entry velocity
1042
+  float vmax_junction;
1041
 
1043
 
1042
   #if 0  // Use old jerk for now
1044
   #if 0  // Use old jerk for now
1043
 
1045
 
1044
     float junction_deviation = 0.1;
1046
     float junction_deviation = 0.1;
1045
 
1047
 
1046
     // Compute path unit vector
1048
     // Compute path unit vector
1047
-    double unit_vec[XYZ];
1048
-
1049
-    unit_vec[X_AXIS] = delta_mm[X_AXIS] * inverse_millimeters;
1050
-    unit_vec[Y_AXIS] = delta_mm[Y_AXIS] * inverse_millimeters;
1051
-    unit_vec[Z_AXIS] = delta_mm[Z_AXIS] * inverse_millimeters;
1052
-
1053
-    // Compute maximum allowable entry speed at junction by centripetal acceleration approximation.
1054
-    // Let a circle be tangent to both previous and current path line segments, where the junction
1055
-    // deviation is defined as the distance from the junction to the closest edge of the circle,
1056
-    // collinear with the circle center. The circular segment joining the two paths represents the
1057
-    // path of centripetal acceleration. Solve for max velocity based on max acceleration about the
1058
-    // radius of the circle, defined indirectly by junction deviation. This may be also viewed as
1059
-    // path width or max_jerk in the previous grbl version. This approach does not actually deviate
1060
-    // from path, but used as a robust way to compute cornering speeds, as it takes into account the
1061
-    // nonlinearities of both the junction angle and junction velocity.
1062
-    double vmax_junction = MINIMUM_PLANNER_SPEED; // Set default max junction speed
1049
+    double unit_vec[XYZ] = {
1050
+      delta_mm[X_AXIS] * inverse_millimeters,
1051
+      delta_mm[Y_AXIS] * inverse_millimeters,
1052
+      delta_mm[Z_AXIS] * inverse_millimeters
1053
+    };
1054
+
1055
+    /*
1056
+       Compute maximum allowable entry speed at junction by centripetal acceleration approximation.
1057
+
1058
+       Let a circle be tangent to both previous and current path line segments, where the junction
1059
+       deviation is defined as the distance from the junction to the closest edge of the circle,
1060
+       collinear with the circle center.
1061
+
1062
+       The circular segment joining the two paths represents the path of centripetal acceleration.
1063
+       Solve for max velocity based on max acceleration about the radius of the circle, defined
1064
+       indirectly by junction deviation.
1065
+
1066
+       This may be also viewed as path width or max_jerk in the previous grbl version. This approach
1067
+       does not actually deviate from path, but used as a robust way to compute cornering speeds, as
1068
+       it takes into account the nonlinearities of both the junction angle and junction velocity.
1069
+     */
1070
+
1071
+    vmax_junction = MINIMUM_PLANNER_SPEED; // Set default max junction speed
1063
 
1072
 
1064
     // Skip first block or when previous_nominal_speed is used as a flag for homing and offset cycles.
1073
     // Skip first block or when previous_nominal_speed is used as a flag for homing and offset cycles.
1065
-    if ((block_buffer_head != block_buffer_tail) && (previous_nominal_speed > 0.0)) {
1074
+    if (block_buffer_head != block_buffer_tail && previous_nominal_speed > 0.0) {
1066
       // Compute cosine of angle between previous and current path. (prev_unit_vec is negative)
1075
       // Compute cosine of angle between previous and current path. (prev_unit_vec is negative)
1067
       // NOTE: Max junction velocity is computed without sin() or acos() by trig half angle identity.
1076
       // NOTE: Max junction velocity is computed without sin() or acos() by trig half angle identity.
1068
-      double cos_theta = - previous_unit_vec[X_AXIS] * unit_vec[X_AXIS]
1069
-                         - previous_unit_vec[Y_AXIS] * unit_vec[Y_AXIS]
1070
-                         - previous_unit_vec[Z_AXIS] * unit_vec[Z_AXIS] ;
1077
+      float cos_theta = - previous_unit_vec[X_AXIS] * unit_vec[X_AXIS]
1078
+                        - previous_unit_vec[Y_AXIS] * unit_vec[Y_AXIS]
1079
+                        - previous_unit_vec[Z_AXIS] * unit_vec[Z_AXIS] ;
1071
       // Skip and use default max junction speed for 0 degree acute junction.
1080
       // Skip and use default max junction speed for 0 degree acute junction.
1072
       if (cos_theta < 0.95) {
1081
       if (cos_theta < 0.95) {
1073
         vmax_junction = min(previous_nominal_speed, block->nominal_speed);
1082
         vmax_junction = min(previous_nominal_speed, block->nominal_speed);
1074
         // Skip and avoid divide by zero for straight junctions at 180 degrees. Limit to min() of nominal speeds.
1083
         // Skip and avoid divide by zero for straight junctions at 180 degrees. Limit to min() of nominal speeds.
1075
         if (cos_theta > -0.95) {
1084
         if (cos_theta > -0.95) {
1076
           // Compute maximum junction velocity based on maximum acceleration and junction deviation
1085
           // Compute maximum junction velocity based on maximum acceleration and junction deviation
1077
-          double sin_theta_d2 = sqrt(0.5 * (1.0 - cos_theta)); // Trig half angle identity. Always positive.
1086
+          float sin_theta_d2 = sqrt(0.5 * (1.0 - cos_theta)); // Trig half angle identity. Always positive.
1078
           NOMORE(vmax_junction, sqrt(block->acceleration * junction_deviation * sin_theta_d2 / (1.0 - sin_theta_d2)));
1087
           NOMORE(vmax_junction, sqrt(block->acceleration * junction_deviation * sin_theta_d2 / (1.0 - sin_theta_d2)));
1079
         }
1088
         }
1080
       }
1089
       }
1081
     }
1090
     }
1082
   #endif
1091
   #endif
1083
 
1092
 
1084
-  // Start with a safe speed
1085
-  float vmax_junction = max_jerk[X_AXIS] * 0.5, vmax_junction_factor = 1.0;
1086
-  if (max_jerk[Y_AXIS] * 0.5 < fabs(current_speed[Y_AXIS])) NOMORE(vmax_junction, max_jerk[Y_AXIS] * 0.5);
1087
-  if (max_jerk[Z_AXIS] * 0.5 < fabs(current_speed[Z_AXIS])) NOMORE(vmax_junction, max_jerk[Z_AXIS] * 0.5);
1088
-  if (max_jerk[E_AXIS] * 0.5 < fabs(current_speed[E_AXIS])) NOMORE(vmax_junction, max_jerk[E_AXIS] * 0.5);
1089
-  NOMORE(vmax_junction, block->nominal_speed);
1090
-  float safe_speed = vmax_junction;
1093
+  /**
1094
+   * Adapted from Prusa MKS firmware
1095
+   *
1096
+   * Start with a safe speed (from which the machine may halt to stop immediately).
1097
+   */
1098
+
1099
+  // Exit speed limited by a jerk to full halt of a previous last segment
1100
+  static float previous_safe_speed;
1101
+
1102
+  float safe_speed = block->nominal_speed;
1103
+  bool limited = false;
1104
+  LOOP_XYZE(i) {
1105
+    float jerk = fabs(current_speed[i]);
1106
+    if (jerk > max_jerk[i]) {
1107
+      // The actual jerk is lower if it has been limited by the XY jerk.
1108
+      if (limited) {
1109
+        // Spare one division by a following gymnastics:
1110
+        // Instead of jerk *= safe_speed / block->nominal_speed,
1111
+        // multiply max_jerk[i] by the divisor.
1112
+        jerk *= safe_speed;
1113
+        float mjerk = max_jerk[i] * block->nominal_speed;
1114
+        if (jerk > mjerk) safe_speed *= mjerk / jerk;
1115
+      }
1116
+      else {
1117
+        safe_speed = max_jerk[i];
1118
+        limited = true;
1119
+      }
1120
+    }
1121
+  }
1091
 
1122
 
1092
   if (moves_queued > 1 && previous_nominal_speed > 0.0001) {
1123
   if (moves_queued > 1 && previous_nominal_speed > 0.0001) {
1093
-    //if ((fabs(previous_speed[X_AXIS]) > 0.0001) || (fabs(previous_speed[Y_AXIS]) > 0.0001)) {
1094
-        vmax_junction = block->nominal_speed;
1095
-    //}
1096
-
1097
-    float dsx = fabs(current_speed[X_AXIS] - previous_speed[X_AXIS]),
1098
-          dsy = fabs(current_speed[Y_AXIS] - previous_speed[Y_AXIS]),
1099
-          dsz = fabs(current_speed[Z_AXIS] - previous_speed[Z_AXIS]),
1100
-          dse = fabs(current_speed[E_AXIS] - previous_speed[E_AXIS]);
1101
-    if (dsx > max_jerk[X_AXIS]) NOMORE(vmax_junction_factor, max_jerk[X_AXIS] / dsx);
1102
-    if (dsy > max_jerk[Y_AXIS]) NOMORE(vmax_junction_factor, max_jerk[Y_AXIS] / dsy);
1103
-    if (dsz > max_jerk[Z_AXIS]) NOMORE(vmax_junction_factor, max_jerk[Z_AXIS] / dsz);
1104
-    if (dse > max_jerk[E_AXIS]) NOMORE(vmax_junction_factor, max_jerk[E_AXIS] / dse);
1105
-
1106
-    vmax_junction = min(previous_nominal_speed, vmax_junction * vmax_junction_factor); // Limit speed to max previous speed
1124
+    // Estimate a maximum velocity allowed at a joint of two successive segments.
1125
+    // If this maximum velocity allowed is lower than the minimum of the entry / exit safe velocities,
1126
+    // then the machine is not coasting anymore and the safe entry / exit velocities shall be used.
1127
+
1128
+    // The junction velocity will be shared between successive segments. Limit the junction velocity to their minimum.
1129
+    bool prev_speed_larger = previous_nominal_speed > block->nominal_speed;
1130
+    float smaller_speed_factor = prev_speed_larger ? (block->nominal_speed / previous_nominal_speed) : (previous_nominal_speed / block->nominal_speed);
1131
+    // Pick the smaller of the nominal speeds. Higher speed shall not be achieved at the junction during coasting.
1132
+    vmax_junction = prev_speed_larger ? block->nominal_speed : previous_nominal_speed;
1133
+    // Factor to multiply the previous / current nominal velocities to get componentwise limited velocities.
1134
+    float v_factor = 1.f;
1135
+    limited = false;
1136
+    // Now limit the jerk in all axes.
1137
+    LOOP_XYZE(axis) {
1138
+      // Limit an axis. We have to differentiate: coasting, reversal of an axis, full stop.
1139
+      float v_exit = previous_speed[axis], v_entry = current_speed[axis];
1140
+      if (prev_speed_larger) v_exit *= smaller_speed_factor;
1141
+      if (limited) {
1142
+        v_exit *= v_factor;
1143
+        v_entry *= v_factor;
1144
+      }
1145
+      // Calculate jerk depending on whether the axis is coasting in the same direction or reversing.
1146
+      float jerk = 
1147
+        (v_exit > v_entry) ?
1148
+          ((v_entry > 0.f || v_exit < 0.f) ?
1149
+            // coasting
1150
+            (v_exit - v_entry) : 
1151
+            // axis reversal
1152
+            max(v_exit, -v_entry)) :
1153
+          // v_exit <= v_entry
1154
+          ((v_entry < 0.f || v_exit > 0.f) ?
1155
+            // coasting
1156
+            (v_entry - v_exit) :
1157
+            // axis reversal
1158
+            max(-v_exit, v_entry));
1159
+      if (jerk > max_jerk[axis]) {
1160
+        v_factor *= max_jerk[axis] / jerk;
1161
+        limited = true;
1162
+      }
1163
+    }
1164
+    if (limited) vmax_junction *= v_factor;
1165
+    // Now the transition velocity is known, which maximizes the shared exit / entry velocity while
1166
+    // respecting the jerk factors, it may be possible, that applying separate safe exit / entry velocities will achieve faster prints.
1167
+    float vmax_junction_threshold = vmax_junction * 0.99f;
1168
+    if (previous_safe_speed > vmax_junction_threshold && safe_speed > vmax_junction_threshold) {
1169
+      // Not coasting. The machine will stop and start the movements anyway,
1170
+      // better to start the segment from start.
1171
+      block->flag |= BLOCK_FLAG_START_FROM_FULL_HALT;
1172
+      vmax_junction = safe_speed;
1173
+    }
1174
+  }
1175
+  else {
1176
+    block->flag |= BLOCK_FLAG_START_FROM_FULL_HALT;
1177
+    vmax_junction = safe_speed;
1107
   }
1178
   }
1179
+
1180
+  // Max entry speed of this block equals the max exit speed of the previous block.
1108
   block->max_entry_speed = vmax_junction;
1181
   block->max_entry_speed = vmax_junction;
1109
 
1182
 
1110
   // Initialize block entry speed. Compute based on deceleration to user-defined MINIMUM_PLANNER_SPEED.
1183
   // Initialize block entry speed. Compute based on deceleration to user-defined MINIMUM_PLANNER_SPEED.
1119
   // block nominal speed limits both the current and next maximum junction speeds. Hence, in both
1192
   // block nominal speed limits both the current and next maximum junction speeds. Hence, in both
1120
   // the reverse and forward planners, the corresponding block junction speed will always be at the
1193
   // the reverse and forward planners, the corresponding block junction speed will always be at the
1121
   // the maximum junction speed and may always be ignored for any speed reduction checks.
1194
   // the maximum junction speed and may always be ignored for any speed reduction checks.
1122
-  block->nominal_length_flag = (block->nominal_speed <= v_allowable);
1123
-  block->recalculate_flag = true; // Always calculate trapezoid for new block
1195
+  block->flag |= BLOCK_FLAG_RECALCULATE | (block->nominal_speed <= v_allowable ? BLOCK_FLAG_NOMINAL_LENGTH : 0);
1124
 
1196
 
1125
   // Update previous path unit_vector and nominal speed
1197
   // Update previous path unit_vector and nominal speed
1126
   memcpy(previous_speed, current_speed, sizeof(previous_speed));
1198
   memcpy(previous_speed, current_speed, sizeof(previous_speed));
1127
   previous_nominal_speed = block->nominal_speed;
1199
   previous_nominal_speed = block->nominal_speed;
1200
+  previous_safe_speed = safe_speed;
1128
 
1201
 
1129
   #if ENABLED(LIN_ADVANCE)
1202
   #if ENABLED(LIN_ADVANCE)
1130
 
1203
 

+ 26
- 14
Marlin/planner.h View File

40
   #include "vector_3.h"
40
   #include "vector_3.h"
41
 #endif
41
 #endif
42
 
42
 
43
+enum BlockFlag {
44
+    // Recalculate trapezoids on entry junction. For optimization.
45
+    BLOCK_FLAG_RECALCULATE          = _BV(0),
46
+
47
+    // Nominal speed always reached.
48
+    // i.e., The segment is long enough, so the nominal speed is reachable if accelerating
49
+    // from a safe speed (in consideration of jerking from zero speed).
50
+    BLOCK_FLAG_NOMINAL_LENGTH       = _BV(1),
51
+
52
+    // Start from a halt at the start of this block, respecting the maximum allowed jerk.
53
+    BLOCK_FLAG_START_FROM_FULL_HALT = _BV(2)
54
+};
55
+
43
 /**
56
 /**
44
  * struct block_t
57
  * struct block_t
45
  *
58
  *
79
   #endif
92
   #endif
80
 
93
 
81
   // Fields used by the motion planner to manage acceleration
94
   // Fields used by the motion planner to manage acceleration
82
-  float nominal_speed,                               // The nominal speed for this block in mm/sec
83
-        entry_speed,                                 // Entry speed at previous-current junction in mm/sec
84
-        max_entry_speed,                             // Maximum allowable junction entry speed in mm/sec
85
-        millimeters,                                 // The total travel of this block in mm
86
-        acceleration;                                // acceleration mm/sec^2
87
-  unsigned char recalculate_flag,                    // Planner flag to recalculate trapezoids on entry junction
88
-                nominal_length_flag;                 // Planner flag for nominal speed always reached
95
+  float nominal_speed,                          // The nominal speed for this block in mm/sec
96
+        entry_speed,                            // Entry speed at previous-current junction in mm/sec
97
+        max_entry_speed,                        // Maximum allowable junction entry speed in mm/sec
98
+        millimeters,                            // The total travel of this block in mm
99
+        acceleration;                           // acceleration mm/sec^2
100
+  uint8_t flag;                                 // Block flags (See BlockFlag enum above)
89
 
101
 
90
   // Settings for the trapezoid generator
102
   // Settings for the trapezoid generator
91
-  unsigned long nominal_rate,                        // The nominal step rate for this block in step_events/sec
92
-                initial_rate,                        // The jerk-adjusted step rate at start of block
93
-                final_rate,                          // The minimal rate at exit
94
-                acceleration_steps_per_s2;           // acceleration steps/sec^2
103
+  uint32_t nominal_rate,                        // The nominal step rate for this block in step_events/sec
104
+           initial_rate,                        // The jerk-adjusted step rate at start of block
105
+           final_rate,                          // The minimal rate at exit
106
+           acceleration_steps_per_s2;           // acceleration steps/sec^2
95
 
107
 
96
   #if FAN_COUNT > 0
108
   #if FAN_COUNT > 0
97
     unsigned long fan_speed[FAN_COUNT];
109
     unsigned long fan_speed[FAN_COUNT];
379
       return sqrt(sq(target_velocity) - 2 * accel * distance);
391
       return sqrt(sq(target_velocity) - 2 * accel * distance);
380
     }
392
     }
381
 
393
 
382
-    static void calculate_trapezoid_for_block(block_t* block, float entry_factor, float exit_factor);
394
+    static void calculate_trapezoid_for_block(block_t* const block, const float &entry_factor, const float &exit_factor);
383
 
395
 
384
-    static void reverse_pass_kernel(block_t* current, block_t* next);
385
-    static void forward_pass_kernel(block_t* previous, block_t* current);
396
+    static void reverse_pass_kernel(block_t* const current, const block_t *next);
397
+    static void forward_pass_kernel(const block_t *previous, block_t* const current);
386
 
398
 
387
     static void reverse_pass();
399
     static void reverse_pass();
388
     static void forward_pass();
400
     static void forward_pass();

Loading…
Cancel
Save