|
|
@ -739,7 +739,7 @@ block_t* Planner::get_current_block() { |
|
|
|
block_t * const block = &block_buffer[block_buffer_tail]; |
|
|
|
|
|
|
|
// No trapezoid calculated? Don't execute yet.
|
|
|
|
if (TEST(block->flag, BLOCK_BIT_RECALCULATE)) return nullptr; |
|
|
|
if (block->flag.recalculate) return nullptr; |
|
|
|
|
|
|
|
// We can't be sure how long an active block will take, so don't count it.
|
|
|
|
TERN_(HAS_WIRED_LCD, block_buffer_runtime_us -= block->segment_time_us); |
|
|
@ -948,7 +948,7 @@ void Planner::reverse_pass_kernel(block_t * const current, const block_t * const |
|
|
|
|
|
|
|
// Compute maximum entry speed decelerating over the current block from its exit speed.
|
|
|
|
// If not at the maximum entry speed, or the previous block entry speed changed
|
|
|
|
if (current->entry_speed_sqr != max_entry_speed_sqr || (next && TEST(next->flag, BLOCK_BIT_RECALCULATE))) { |
|
|
|
if (current->entry_speed_sqr != max_entry_speed_sqr || (next && next->flag.recalculate)) { |
|
|
|
|
|
|
|
// If nominal length true, max junction speed is guaranteed to be reached.
|
|
|
|
// If a block can de/ac-celerate from nominal speed to zero within the length of the block, then
|
|
|
@ -958,14 +958,14 @@ void Planner::reverse_pass_kernel(block_t * const current, const block_t * const |
|
|
|
// the reverse and forward planners, the corresponding block junction speed will always be at the
|
|
|
|
// the maximum junction speed and may always be ignored for any speed reduction checks.
|
|
|
|
|
|
|
|
const float new_entry_speed_sqr = TEST(current->flag, BLOCK_BIT_NOMINAL_LENGTH) |
|
|
|
const float new_entry_speed_sqr = current->flag.nominal_length |
|
|
|
? max_entry_speed_sqr |
|
|
|
: _MIN(max_entry_speed_sqr, max_allowable_speed_sqr(-current->acceleration, next ? next->entry_speed_sqr : sq(float(MINIMUM_PLANNER_SPEED)), current->millimeters)); |
|
|
|
if (current->entry_speed_sqr != new_entry_speed_sqr) { |
|
|
|
|
|
|
|
// Need to recalculate the block speed - Mark it now, so the stepper
|
|
|
|
// ISR does not consume the block before being recalculated
|
|
|
|
SBI(current->flag, BLOCK_BIT_RECALCULATE); |
|
|
|
current->flag.recalculate = true; |
|
|
|
|
|
|
|
// But there is an inherent race condition here, as the block may have
|
|
|
|
// become BUSY just before being marked RECALCULATE, so check for that!
|
|
|
@ -973,7 +973,7 @@ void Planner::reverse_pass_kernel(block_t * const current, const block_t * const |
|
|
|
// Block became busy. Clear the RECALCULATE flag (no point in
|
|
|
|
// recalculating BUSY blocks). And don't set its speed, as it can't
|
|
|
|
// be updated at this time.
|
|
|
|
CBI(current->flag, BLOCK_BIT_RECALCULATE); |
|
|
|
current->flag.recalculate = false; |
|
|
|
} |
|
|
|
else { |
|
|
|
// Block is not BUSY so this is ahead of the Stepper ISR:
|
|
|
@ -1011,8 +1011,8 @@ void Planner::reverse_pass() { |
|
|
|
// Perform the reverse pass
|
|
|
|
block_t *current = &block_buffer[block_index]; |
|
|
|
|
|
|
|
// Only consider non sync-and-page blocks
|
|
|
|
if (!(current->flag & BLOCK_MASK_SYNC) && !IS_PAGE(current)) { |
|
|
|
// Only process movement blocks
|
|
|
|
if (current->is_move()) { |
|
|
|
reverse_pass_kernel(current, next); |
|
|
|
next = current; |
|
|
|
} |
|
|
@ -1041,8 +1041,7 @@ void Planner::forward_pass_kernel(const block_t * const previous, block_t * cons |
|
|
|
// change, adjust the entry speed accordingly. Entry speeds have already been reset,
|
|
|
|
// maximized, and reverse-planned. If nominal length is set, max junction speed is
|
|
|
|
// guaranteed to be reached. No need to recheck.
|
|
|
|
if (!TEST(previous->flag, BLOCK_BIT_NOMINAL_LENGTH) && |
|
|
|
previous->entry_speed_sqr < current->entry_speed_sqr) { |
|
|
|
if (!previous->flag.nominal_length && previous->entry_speed_sqr < current->entry_speed_sqr) { |
|
|
|
|
|
|
|
// Compute the maximum allowable speed
|
|
|
|
const float new_entry_speed_sqr = max_allowable_speed_sqr(-previous->acceleration, previous->entry_speed_sqr, previous->millimeters); |
|
|
@ -1052,7 +1051,7 @@ void Planner::forward_pass_kernel(const block_t * const previous, block_t * cons |
|
|
|
|
|
|
|
// Mark we need to recompute the trapezoidal shape, and do it now,
|
|
|
|
// so the stepper ISR does not consume the block before being recalculated
|
|
|
|
SBI(current->flag, BLOCK_BIT_RECALCULATE); |
|
|
|
current->flag.recalculate = true; |
|
|
|
|
|
|
|
// But there is an inherent race condition here, as the block maybe
|
|
|
|
// became BUSY, just before it was marked as RECALCULATE, so check
|
|
|
@ -1061,7 +1060,7 @@ void Planner::forward_pass_kernel(const block_t * const previous, block_t * cons |
|
|
|
// Block became busy. Clear the RECALCULATE flag (no point in
|
|
|
|
// recalculating BUSY blocks and don't set its speed, as it can't
|
|
|
|
// be updated at this time.
|
|
|
|
CBI(current->flag, BLOCK_BIT_RECALCULATE); |
|
|
|
current->flag.recalculate = false; |
|
|
|
} |
|
|
|
else { |
|
|
|
// Block is not BUSY, we won the race against the Stepper ISR:
|
|
|
@ -1106,8 +1105,8 @@ void Planner::forward_pass() { |
|
|
|
// Perform the forward pass
|
|
|
|
block = &block_buffer[block_index]; |
|
|
|
|
|
|
|
// Skip SYNC and page blocks
|
|
|
|
if (!(block->flag & BLOCK_MASK_SYNC) && !IS_PAGE(block)) { |
|
|
|
// Only process movement blocks
|
|
|
|
if (block->is_move()) { |
|
|
|
// If there's no previous block or the previous block is not
|
|
|
|
// BUSY (thus, modifiable) run the forward_pass_kernel. Otherwise,
|
|
|
|
// the previous block became BUSY, so assume the current block's
|
|
|
@ -1131,9 +1130,10 @@ void Planner::recalculate_trapezoids() { |
|
|
|
// The tail may be changed by the ISR so get a local copy.
|
|
|
|
uint8_t block_index = block_buffer_tail, |
|
|
|
head_block_index = block_buffer_head; |
|
|
|
// Since there could be a sync block in the head of the queue, and the
|
|
|
|
|
|
|
|
// Since there could be non-move blocks in the head of the queue, and the
|
|
|
|
// next loop must not recalculate the head block (as it needs to be
|
|
|
|
// specially handled), scan backwards to the first non-SYNC block.
|
|
|
|
// specially handled), scan backwards to the first move block.
|
|
|
|
while (head_block_index != block_index) { |
|
|
|
|
|
|
|
// Go back (head always point to the first free block)
|
|
|
@ -1142,8 +1142,8 @@ void Planner::recalculate_trapezoids() { |
|
|
|
// Get the pointer to the block
|
|
|
|
block_t *prev = &block_buffer[prev_index]; |
|
|
|
|
|
|
|
// If not dealing with a sync block, we are done. The last block is not a SYNC block
|
|
|
|
if (!(prev->flag & BLOCK_MASK_SYNC)) break; |
|
|
|
// It the block is a move, we're done with this loop
|
|
|
|
if (prev->is_move()) break; |
|
|
|
|
|
|
|
// Examine the previous block. This and all following are SYNC blocks
|
|
|
|
head_block_index = prev_index; |
|
|
@ -1156,18 +1156,17 @@ void Planner::recalculate_trapezoids() { |
|
|
|
|
|
|
|
next = &block_buffer[block_index]; |
|
|
|
|
|
|
|
// Skip sync and page blocks
|
|
|
|
if (!(next->flag & BLOCK_MASK_SYNC) && !IS_PAGE(next)) { |
|
|
|
// Only process movement blocks
|
|
|
|
if (next->is_move()) { |
|
|
|
next_entry_speed = SQRT(next->entry_speed_sqr); |
|
|
|
|
|
|
|
if (block) { |
|
|
|
// Recalculate if current block entry or exit junction speed has changed.
|
|
|
|
if (TEST(block->flag, BLOCK_BIT_RECALCULATE) || TEST(next->flag, BLOCK_BIT_RECALCULATE)) { |
|
|
|
|
|
|
|
// Mark the current block as RECALCULATE, to protect it from the Stepper ISR running it.
|
|
|
|
// Note that due to the above condition, there's a chance the current block isn't marked as
|
|
|
|
// RECALCULATE yet, but the next one is. That's the reason for the following line.
|
|
|
|
SBI(block->flag, BLOCK_BIT_RECALCULATE); |
|
|
|
// If the next block is marked to RECALCULATE, also mark the previously-fetched one
|
|
|
|
if (next->flag.recalculate) block->flag.recalculate = true; |
|
|
|
|
|
|
|
// Recalculate if current block entry or exit junction speed has changed.
|
|
|
|
if (block->flag.recalculate) { |
|
|
|
|
|
|
|
// But there is an inherent race condition here, as the block maybe
|
|
|
|
// became BUSY, just before it was marked as RECALCULATE, so check
|
|
|
@ -1190,7 +1189,7 @@ void Planner::recalculate_trapezoids() { |
|
|
|
|
|
|
|
// Reset current only to ensure next trapezoid is computed - The
|
|
|
|
// stepper is free to use the block from now on.
|
|
|
|
CBI(block->flag, BLOCK_BIT_RECALCULATE); |
|
|
|
block->flag.recalculate = false; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
@ -1204,10 +1203,10 @@ void Planner::recalculate_trapezoids() { |
|
|
|
// Last/newest block in buffer. Exit speed is set with MINIMUM_PLANNER_SPEED. Always recalculated.
|
|
|
|
if (next) { |
|
|
|
|
|
|
|
// Mark the next(last) block as RECALCULATE, to prevent the Stepper ISR running it.
|
|
|
|
// Mark the last block as RECALCULATE, to prevent the Stepper ISR running it.
|
|
|
|
// As the last block is always recalculated here, there is a chance the block isn't
|
|
|
|
// marked as RECALCULATE yet. That's the reason for the following line.
|
|
|
|
SBI(next->flag, BLOCK_BIT_RECALCULATE); |
|
|
|
block->flag.recalculate = true; |
|
|
|
|
|
|
|
// But there is an inherent race condition here, as the block maybe
|
|
|
|
// became BUSY, just before it was marked as RECALCULATE, so check
|
|
|
@ -1229,7 +1228,7 @@ void Planner::recalculate_trapezoids() { |
|
|
|
|
|
|
|
// Reset next only to ensure its trapezoid is computed - The stepper is free to use
|
|
|
|
// the block from now on.
|
|
|
|
CBI(next->flag, BLOCK_BIT_RECALCULATE); |
|
|
|
next->flag.recalculate = false; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
@ -1460,7 +1459,7 @@ void Planner::check_axes_activity() { |
|
|
|
for (uint8_t b = block_buffer_tail; b != block_buffer_head; b = next_block_index(b)) { |
|
|
|
const block_t * const block = &block_buffer[b]; |
|
|
|
if (NUM_AXIS_GANG(block->steps.x, || block->steps.y, || block->steps.z, || block->steps.i, || block->steps.j, || block->steps.k, || block->steps.u, || block->steps.v, || block->steps.w)) { |
|
|
|
const float se = (float)block->steps.e / block->step_event_count * SQRT(block->nominal_speed_sqr); // mm/sec;
|
|
|
|
const float se = (float)block->steps.e / block->step_event_count * SQRT(block->nominal_speed_sqr); // mm/sec
|
|
|
|
NOLESS(high, se); |
|
|
|
} |
|
|
|
} |
|
|
@ -1782,7 +1781,7 @@ void Planner::synchronize() { while (busy()) idle(); } |
|
|
|
bool Planner::_buffer_steps(const xyze_long_t &target |
|
|
|
OPTARG(HAS_POSITION_FLOAT, const xyze_pos_t &target_float) |
|
|
|
OPTARG(HAS_DIST_MM_ARG, const xyze_float_t &cart_dist_mm) |
|
|
|
, feedRate_t fr_mm_s, const uint8_t extruder, const_float_t millimeters |
|
|
|
, feedRate_t fr_mm_s, const uint8_t extruder, const_float_t millimeters/*=0.0*/ |
|
|
|
) { |
|
|
|
|
|
|
|
// Wait for the next available block
|
|
|
@ -1796,10 +1795,11 @@ bool Planner::_buffer_steps(const xyze_long_t &target |
|
|
|
|
|
|
|
// Fill the block with the specified movement
|
|
|
|
if (!_populate_block(block, false, target |
|
|
|
OPTARG(HAS_POSITION_FLOAT, target_float) |
|
|
|
OPTARG(HAS_DIST_MM_ARG, cart_dist_mm) |
|
|
|
, fr_mm_s, extruder, millimeters |
|
|
|
)) { |
|
|
|
OPTARG(HAS_POSITION_FLOAT, target_float) |
|
|
|
OPTARG(HAS_DIST_MM_ARG, cart_dist_mm) |
|
|
|
, fr_mm_s, extruder, millimeters |
|
|
|
) |
|
|
|
) { |
|
|
|
// Movement was not queued, probably because it was too short.
|
|
|
|
// Simply accept that as movement queued and done
|
|
|
|
return true; |
|
|
@ -1856,36 +1856,8 @@ bool Planner::_populate_block(block_t * const block, bool split_move, |
|
|
|
); |
|
|
|
|
|
|
|
/* <-- add a slash to enable
|
|
|
|
SERIAL_ECHOLNPGM( |
|
|
|
" _populate_block FR:", fr_mm_s, |
|
|
|
" A:", target.a, " (", da, " steps)" |
|
|
|
#if HAS_Y_AXIS |
|
|
|
" B:", target.b, " (", db, " steps)" |
|
|
|
#endif |
|
|
|
#if HAS_Z_AXIS |
|
|
|
" C:", target.c, " (", dc, " steps)" |
|
|
|
#endif |
|
|
|
#if HAS_I_AXIS |
|
|
|
" " STR_I ":", target.i, " (", di, " steps)" |
|
|
|
#endif |
|
|
|
#if HAS_J_AXIS |
|
|
|
" " STR_J ":", target.j, " (", dj, " steps)" |
|
|
|
#endif |
|
|
|
#if HAS_K_AXIS |
|
|
|
" " STR_K ":", target.k, " (", dk, " steps)" |
|
|
|
#endif |
|
|
|
#if HAS_U_AXIS |
|
|
|
" " STR_U ":", target.u, " (", du, " steps)" |
|
|
|
#endif |
|
|
|
#if HAS_V_AXIS |
|
|
|
" " STR_V ":", target.v, " (", dv, " steps)" |
|
|
|
#endif |
|
|
|
#if HAS_W_AXIS |
|
|
|
" " STR_W ":", target.w, " (", dw, " steps)" |
|
|
|
#if HAS_EXTRUDERS |
|
|
|
" E:", target.e, " (", de, " steps)" |
|
|
|
#endif |
|
|
|
); |
|
|
|
#define _ALINE(A) " " STR_##A ":", target[_AXIS(A)], " (", int32_t(target[_AXIS(A)] - position[_AXIS(A)]), " steps)" |
|
|
|
SERIAL_ECHOLNPGM(" _populate_block FR:", fr_mm_s, LOGICAL_AXIS_MAP(_ALINE)); |
|
|
|
//*/
|
|
|
|
|
|
|
|
#if EITHER(PREVENT_COLD_EXTRUSION, PREVENT_LENGTHY_EXTRUDE) |
|
|
@ -1978,7 +1950,7 @@ bool Planner::_populate_block(block_t * const block, bool split_move, |
|
|
|
#endif |
|
|
|
|
|
|
|
// Clear all flags, including the "busy" bit
|
|
|
|
block->flag = 0x00; |
|
|
|
block->flag.clear(); |
|
|
|
|
|
|
|
// Set direction bits
|
|
|
|
block->direction_bits = dm; |
|
|
@ -2449,7 +2421,7 @@ bool Planner::_populate_block(block_t * const block, bool split_move, |
|
|
|
if (speed_factor < 1.0f) { |
|
|
|
current_speed *= speed_factor; |
|
|
|
block->nominal_rate *= speed_factor; |
|
|
|
block->nominal_speed_sqr = block->nominal_speed_sqr * sq(speed_factor); |
|
|
|
block->nominal_speed_sqr *= sq(speed_factor); |
|
|
|
} |
|
|
|
|
|
|
|
// Compute and limit the acceleration rate for the trapezoid generator.
|
|
|
@ -2651,14 +2623,15 @@ bool Planner::_populate_block(block_t * const block, bool split_move, |
|
|
|
vmax_junction_sqr = sq(float(MINIMUM_PLANNER_SPEED)); |
|
|
|
} |
|
|
|
else { |
|
|
|
NOLESS(junction_cos_theta, -0.999999f); // Check for numerical round-off to avoid divide by zero.
|
|
|
|
|
|
|
|
// Convert delta vector to unit vector
|
|
|
|
xyze_float_t junction_unit_vec = unit_vec - prev_unit_vec; |
|
|
|
normalize_junction_vector(junction_unit_vec); |
|
|
|
|
|
|
|
const float junction_acceleration = limit_value_by_axis_maximum(block->acceleration, junction_unit_vec), |
|
|
|
sin_theta_d2 = SQRT(0.5f * (1.0f - junction_cos_theta)); // Trig half angle identity. Always positive.
|
|
|
|
const float junction_acceleration = limit_value_by_axis_maximum(block->acceleration, junction_unit_vec); |
|
|
|
|
|
|
|
NOLESS(junction_cos_theta, -0.999999f); // Check for numerical round-off to avoid divide by zero.
|
|
|
|
|
|
|
|
const float sin_theta_d2 = SQRT(0.5f * (1.0f - junction_cos_theta)); // Trig half angle identity. Always positive.
|
|
|
|
|
|
|
|
vmax_junction_sqr = junction_acceleration * junction_deviation_mm * sin_theta_d2 / (1.0f - sin_theta_d2); |
|
|
|
|
|
|
@ -2888,7 +2861,7 @@ bool Planner::_populate_block(block_t * const block, bool split_move, |
|
|
|
// block nominal speed limits both the current and next maximum junction speeds. Hence, in both
|
|
|
|
// the reverse and forward planners, the corresponding block junction speed will always be at the
|
|
|
|
// the maximum junction speed and may always be ignored for any speed reduction checks.
|
|
|
|
block->flag |= block->nominal_speed_sqr <= v_allowable_sqr ? BLOCK_FLAG_RECALCULATE | BLOCK_FLAG_NOMINAL_LENGTH : BLOCK_FLAG_RECALCULATE; |
|
|
|
block->flag.set_nominal(block->nominal_speed_sqr <= v_allowable_sqr); |
|
|
|
|
|
|
|
// Update previous path unit_vector and nominal speed
|
|
|
|
previous_speed = current_speed; |
|
|
@ -2913,9 +2886,9 @@ bool Planner::_populate_block(block_t * const block, bool split_move, |
|
|
|
* Add a block to the buffer that just updates the position, |
|
|
|
* or in case of LASER_SYNCHRONOUS_M106_M107 the fan PWM |
|
|
|
*/ |
|
|
|
void Planner::buffer_sync_block(TERN_(LASER_SYNCHRONOUS_M106_M107, uint8_t sync_flag)) { |
|
|
|
void Planner::buffer_sync_block(TERN_(LASER_SYNCHRONOUS_M106_M107, const BlockFlagBit sync_flag/*=BLOCK_BIT_SYNC_POSITION*/)) { |
|
|
|
#if DISABLED(LASER_SYNCHRONOUS_M106_M107) |
|
|
|
constexpr uint8_t sync_flag = BLOCK_FLAG_SYNC_POSITION; |
|
|
|
constexpr BlockFlagBit sync_flag = BLOCK_BIT_SYNC_POSITION; |
|
|
|
#endif |
|
|
|
|
|
|
|
// Wait for the next available block
|
|
|
@ -2925,7 +2898,7 @@ void Planner::buffer_sync_block(TERN_(LASER_SYNCHRONOUS_M106_M107, uint8_t sync_ |
|
|
|
// Clear block
|
|
|
|
memset(block, 0, sizeof(block_t)); |
|
|
|
|
|
|
|
block->flag = sync_flag; |
|
|
|
block->flag.apply(sync_flag); |
|
|
|
|
|
|
|
block->position = position; |
|
|
|
#if ENABLED(BACKLASH_COMPENSATION) |
|
|
@ -3073,8 +3046,8 @@ bool Planner::buffer_segment(const abce_pos_t &abce |
|
|
|
if (!_buffer_steps(target |
|
|
|
OPTARG(HAS_POSITION_FLOAT, target_float) |
|
|
|
OPTARG(HAS_DIST_MM_ARG, cart_dist_mm) |
|
|
|
, fr_mm_s, extruder, millimeters) |
|
|
|
) return false; |
|
|
|
, fr_mm_s, extruder, millimeters |
|
|
|
)) return false; |
|
|
|
|
|
|
|
stepper.wake_up(); |
|
|
|
return true; |
|
|
@ -3141,6 +3114,14 @@ bool Planner::buffer_line(const xyze_pos_t &cart, const_feedRate_t fr_mm_s, cons |
|
|
|
|
|
|
|
#if ENABLED(DIRECT_STEPPING) |
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Add a direct stepping page block to the buffer |
|
|
|
* and wake up the Stepper ISR to process it. |
|
|
|
* |
|
|
|
* @param page_idx Page index provided by G6 I<index> |
|
|
|
* @param extruder The extruder to use in the move |
|
|
|
* @param num_steps Number of steps to process in the ISR |
|
|
|
*/ |
|
|
|
void Planner::buffer_page(const page_idx_t page_idx, const uint8_t extruder, const uint16_t num_steps) { |
|
|
|
if (!last_page_step_rate) { |
|
|
|
kill(GET_TEXT_F(MSG_BAD_PAGE_SPEED)); |
|
|
@ -3150,7 +3131,7 @@ bool Planner::buffer_line(const xyze_pos_t &cart, const_feedRate_t fr_mm_s, cons |
|
|
|
uint8_t next_buffer_head; |
|
|
|
block_t * const block = get_next_free_block(next_buffer_head); |
|
|
|
|
|
|
|
block->flag = BLOCK_FLAG_IS_PAGE; |
|
|
|
block->flag.reset(BLOCK_BIT_PAGE); |
|
|
|
|
|
|
|
#if HAS_FAN |
|
|
|
FANS_LOOP(i) block->fan_speed[i] = thermalManager.fan_speed[i]; |
|
|
@ -3238,6 +3219,12 @@ void Planner::set_machine_position_mm(const abce_pos_t &abce) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Set the Planner position in mm |
|
|
|
* @details Set the Planner position from a native machine position in mm |
|
|
|
* |
|
|
|
* @param xyze A native (Cartesian) machine position |
|
|
|
*/ |
|
|
|
void Planner::set_position_mm(const xyze_pos_t &xyze) { |
|
|
|
xyze_pos_t machine = xyze; |
|
|
|
TERN_(HAS_POSITION_MODIFIERS, apply_modifiers(machine, true)); |
|
|
@ -3273,7 +3260,13 @@ void Planner::set_position_mm(const xyze_pos_t &xyze) { |
|
|
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
// Recalculate the steps/s^2 acceleration rates, based on the mm/s^2
|
|
|
|
/**
|
|
|
|
* @brief Recalculate the steps/s^2 acceleration rates, based on the mm/s^2 |
|
|
|
* @details Update planner movement factors after a change to certain settings: |
|
|
|
* - max_acceleration_steps_per_s2 from settings max_acceleration_mm_per_s2 * axis_steps_per_mm (M201, M92) |
|
|
|
* - acceleration_long_cutoff based on the largest max_acceleration_steps_per_s2 (M201) |
|
|
|
* - max_e_jerk for all extruders based on junction_deviation_mm (M205 J) |
|
|
|
*/ |
|
|
|
void Planner::reset_acceleration_rates() { |
|
|
|
uint32_t highest_rate = 1; |
|
|
|
LOOP_DISTINCT_AXES(i) { |
|
|
@ -3286,8 +3279,8 @@ void Planner::reset_acceleration_rates() { |
|
|
|
} |
|
|
|
|
|
|
|
/**
|
|
|
|
* Recalculate 'position' and 'mm_per_step'. |
|
|
|
* Must be called whenever settings.axis_steps_per_mm changes! |
|
|
|
* @brief Recalculate 'position' and 'mm_per_step'. |
|
|
|
* @details Required whenever settings.axis_steps_per_mm changes! |
|
|
|
*/ |
|
|
|
void Planner::refresh_positioning() { |
|
|
|
LOOP_DISTINCT_AXES(i) mm_per_step[i] = 1.0f / settings.axis_steps_per_mm[i]; |
|
|
|