yarf 0.1
Yet Another RepRap Firmware
|
00001 /* 00002 * planner_lookahead.c 00003 * 00004 * Copyright 2011 Pieter Agten 00005 * 00006 * This file is part of Yarf. 00007 * 00008 * Yarf is free software: you can redistribute it and/or modify 00009 * it under the terms of the GNU General Public License as published by 00010 * the Free Software Foundation, either version 3 of the License, or 00011 * (at your option) any later version. 00012 * 00013 * Yarf is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 * GNU General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU General Public License 00019 * along with Yarf. If not, see <http://www.gnu.org/licenses/>. 00020 */ 00021 00035 #include "planner_lookahead.h" 00036 00037 #include "yarf.h" 00038 #include "planner.h" 00039 #include "planner_queue.h" 00040 #include "util/math.h" 00041 00042 #include <stdint.h> 00043 #include <string.h> 00044 00045 00046 #if PLANNER_LOOKAHEAD 00047 00051 static struct { 00052 float direction[NUM_AXES]; 00053 float plateau_speed; 00054 } previous_block_info; 00055 00056 00057 00058 00059 00091 static speed_t 00092 max_allowable_speed(speed_t target_speed, float distance_mm) 00093 { 00094 return sqrt(lsquare(target_speed)+2*ACCELERATION*distance_mm); 00095 } 00096 00097 00098 00116 static void 00117 reverse_pass_kernel(block_t *current, block_t *next) 00118 { 00119 if (! current) { return; } 00120 00121 if (next) { 00122 // If entry speed is already at the maximum entry speed, no need to recheck. Block is cruising. 00123 // If not, block in state of acceleration or deceleration. Reset entry speed to maximum and 00124 // check for maximum allowable speed reductions to ensure maximum possible planned speed. 00125 if (current->entry_speed < current->max_entry_speed) { 00126 if (current->plateau_speed_always_reachable || current->max_entry_speed < next->entry_speed) { 00127 current->entry_speed = current->max_entry_speed; 00128 } else { 00129 current->entry_speed = MIN(current->max_entry_speed, max_allowable_speed(next->entry_speed,current->distance_mm)); 00130 } 00131 current->recalculate = true; 00132 } 00133 } // Skip last block. Already initialized and set for recalculation. 00134 } 00135 00136 00144 static void 00145 reverse_pass(void) 00146 { 00147 uint8_t block_index = plan_q_head_index(); 00148 block_t *block[2] = {NULL, NULL}; 00149 while(block_index != plan_q_tail_index()) { 00150 block_index = plan_q_prev_index(block_index); 00151 block[1] = block[0]; 00152 block[0] = plan_q_get(block_index); 00153 reverse_pass_kernel(block[0], block[1]); 00154 } 00155 } 00156 00157 00171 static void 00172 forward_pass_kernel(block_t *previous, block_t *current) 00173 { 00174 if (! previous) { return; } // Begin planning after buffer_tail 00175 00176 // If the previous block is an acceleration block, but it is not long enough to complete the 00177 // full speed change within the block, we need to adjust the entry speed accordingly. Entry 00178 // speeds have already been reset, maximized, and reverse planned by reverse planner. 00179 // If nominal length is true, max junction speed is guaranteed to be reached. No need to recheck. 00180 if (! previous->plateau_speed_always_reachable) { 00181 if (previous->entry_speed < current->entry_speed) { 00182 speed_t max_obtainable_speed = max_allowable_speed(previous->entry_speed,previous->distance_mm); 00183 00184 // Check for junction speed change 00185 if (max_obtainable_speed < current->entry_speed) { 00186 current->entry_speed = max_obtainable_speed; 00187 current->recalculate = true; 00188 } 00189 } 00190 } 00191 } 00192 00193 00194 00195 00203 static void 00204 forward_pass(void) 00205 { 00206 uint8_t block_index = plan_q_tail_index(); 00207 block_t *block[2] = {NULL, NULL}; 00208 while(block_index != plan_q_head_index()) { 00209 block[0] = block[1]; 00210 block[1] = plan_q_get(block_index); 00211 forward_pass_kernel(block[0],block[1]); 00212 block_index = plan_q_next_index(block_index); 00213 } 00214 } 00215 00216 00236 static void 00237 recalculate_trapezoids(void) 00238 { 00239 uint8_t block_index = plan_q_tail_index(); 00240 block_t *current; 00241 block_t *next = NULL; 00242 00243 while(block_index != plan_q_head_index()) { 00244 current = next; 00245 next = plan_q_get(block_index); 00246 if (current) { 00247 // Recalculate if current block entry or exit junction speed has changed. 00248 if (current->recalculate || next->recalculate) { 00249 plan_calculate_trapezoid(current, current->entry_speed, next->entry_speed); 00250 current->recalculate = false; 00251 } 00252 } 00253 block_index = plan_q_next_index(block_index); 00254 } 00255 // Last/newest block in buffer. Exit speed is set with START_FEED_RATE. Always recalculated. 00256 plan_calculate_trapezoid(next, next->entry_speed, MIN(next->plateau_speed, START_FEED_RATE)); 00257 next->recalculate = false; 00258 } 00259 00260 00268 static inline void 00269 recalculate_motion_plan(void) { 00270 reverse_pass(); 00271 forward_pass(); 00272 recalculate_trapezoids(); 00273 } 00274 00275 00276 void 00277 plan_lookahead_init() 00278 { 00279 previous_block_info.plateau_speed = 0; 00280 } 00281 00282 00283 void 00284 plan_lookahead() 00285 { 00286 block_t *b = plan_q_get(plan_q_prev_index(plan_q_head_index())); 00287 // Compute maximum allowable entry speed at junction by centripetal acceleration approximation. 00288 // Let a circle be tangent to both previous and current path line segments, where the junction 00289 // deviation is defined as the distance from the junction to the closest edge of the circle, 00290 // colinear with the circle center. The circular segment joining the two paths represents the 00291 // path of centripetal acceleration. Solve for max velocity based on max acceleration about the 00292 // radius of the circle, defined indirectly by junction deviation. This may be also viewed as 00293 // path width or max_jerk in the previous grbl version. This approach does not actually deviate 00294 // from path, but used as a robust way to compute cornering speeds, as it takes into account the 00295 // nonlinearities of both the junction angle and junction velocity. 00296 const speed_t start_feed_rate = MIN(b->plateau_speed, START_FEED_RATE); 00297 speed_t max_junction_speed = start_feed_rate; // Set default conservative max junction speed 00298 00299 // Skip first block 00300 if (plan_q_size() >= 2) { 00301 // Make sure the junction speed will not be higher than the previous plateau speed. 00302 max_junction_speed = MIN(max_junction_speed, previous_block_info.plateau_speed); 00303 // Compute cosine of angle between previous and current path. 00304 // NOTE: Max junction velocity is computed without sin() or acos() by trig half angle identity. 00305 float cos_theta = -(previous_block_info.direction[X_AXIS] * b->direction[X_AXIS] + 00306 previous_block_info.direction[Y_AXIS] * b->direction[Y_AXIS] + 00307 previous_block_info.direction[Z_AXIS] * b->direction[Z_AXIS] + 00308 previous_block_info.direction[E_AXIS] * b->direction[E_AXIS]) ; 00309 00310 // Skip and use default max junction speed for 0 degree acute junction. 00311 if (cos_theta < 0.95) { 00312 // Skip and avoid divide by zero for straight junctions at 180 degrees. 00313 if (cos_theta > -0.95) { // -0.95 < cos_theta < 0.95 00314 // Compute maximum junction velocity based on maximum acceleration and junction deviation 00315 float sin_theta_d2 = sqrt(0.5*(1.0-cos_theta)); // Trig half angle identity. Always positive. 00316 max_junction_speed = MIN(max_junction_speed, sqrt(ACCELERATION * JUNCTION_DEVIATION * sin_theta_d2/(1.0-sin_theta_d2)) ); 00317 } // else { very unsharp corner } 00318 } // else { very sharp corner } 00319 } 00320 b->max_entry_speed = max_junction_speed; 00321 00322 // Calculate the maximum allowable speed to still be able to decelerate to START_FEED_RATE over 00323 // the length of the block. 00324 speed_t max_allowable_speed_ = max_allowable_speed(start_feed_rate,b->distance_mm); 00325 b->entry_speed = MIN(max_junction_speed, max_allowable_speed_); 00326 00327 // Initialize planner efficiency flags 00328 // Set flag if block will always reach maximum junction speed regardless of entry/exit speeds. 00329 // If a block can decelerate from nominal speed to minimum speed within the length of the block, then 00330 // the current block and next block junction speeds are guaranteed to always be at their maximum 00331 // junction speeds in deceleration and acceleration, respectively. This is due to how the current 00332 // block nominal speed limits both the current and next maximum junction speeds. Hence, in both 00333 // the reverse and forward planners, the corresponding block junction speed will always be at the 00334 // the maximum junction speed and may always be ignored for any speed reduction checks. 00335 b->plateau_speed_always_reachable = (b->plateau_speed <= max_allowable_speed_); 00336 b->recalculate = true; // Always calculate trapezoid for new block 00337 00338 // Update previous path unit_vector and nominal speed 00339 memcpy(previous_block_info.direction, b->direction, sizeof(b->direction)); 00340 previous_block_info.plateau_speed = b->plateau_speed; 00341 00342 recalculate_motion_plan(); 00343 } 00344 00345 #endif //PLANNER_LOOKAHEAD 00346