|
@@ -843,20 +843,22 @@ void Planner::calculate_trapezoid_for_block(block_t * const block, const_float_t
|
843
|
843
|
/**
|
844
|
844
|
* Laser Trapezoid Calculations
|
845
|
845
|
*
|
846
|
|
- * Approximate the trapezoid with the laser, incrementing the power every `trap_ramp_entry_incr` steps while accelerating,
|
847
|
|
- * and decrementing the power every `trap_ramp_exit_decr` while decelerating, to keep power proportional to feedrate.
|
848
|
|
- * Laser power trap will reduce the initial power to no less than the laser_power_floor value. Based on the number
|
849
|
|
- * of calculated accel/decel steps the power is distributed over the trapezoid entry- and exit-ramp steps.
|
|
846
|
+ * Approximate the trapezoid with the laser, incrementing the power every `trap_ramp_entry_incr`
|
|
847
|
+ * steps while accelerating, and decrementing the power every `trap_ramp_exit_decr` while decelerating,
|
|
848
|
+ * to keep power proportional to feedrate. Laser power trap will reduce the initial power to no less
|
|
849
|
+ * than the laser_power_floor value. Based on the number of calculated accel/decel steps the power is
|
|
850
|
+ * distributed over the trapezoid entry- and exit-ramp steps.
|
850
|
851
|
*
|
851
|
|
- * trap_ramp_active_pwr - The active power is initially set at a reduced level factor of initial power / accel steps and
|
852
|
|
- * will be additively incremented using a trap_ramp_entry_incr value for each accel step processed later in the stepper code.
|
853
|
|
- * The trap_ramp_exit_decr value is calculated as power / decel steps and is also adjusted to no less than the power floor.
|
|
852
|
+ * trap_ramp_active_pwr - The active power is initially set at a reduced level factor of initial
|
|
853
|
+ * power / accel steps and will be additively incremented using a trap_ramp_entry_incr value for each
|
|
854
|
+ * accel step processed later in the stepper code. The trap_ramp_exit_decr value is calculated as
|
|
855
|
+ * power / decel steps and is also adjusted to no less than the power floor.
|
854
|
856
|
*
|
855
|
|
- * If the power == 0 the inline mode variables need to be set to zero to prevent stepper processing. The method allows
|
856
|
|
- * for simpler non-powered moves like G0 or G28.
|
|
857
|
+ * If the power == 0 the inline mode variables need to be set to zero to prevent stepper processing.
|
|
858
|
+ * The method allows for simpler non-powered moves like G0 or G28.
|
857
|
859
|
*
|
858
|
|
- * Laser Trap Power works for all Jerk and Curve modes; however Arc-based moves will have issues since the segments are
|
859
|
|
- * usually too small.
|
|
860
|
+ * Laser Trap Power works for all Jerk and Curve modes; however Arc-based moves will have issues since
|
|
861
|
+ * the segments are usually too small.
|
860
|
862
|
*/
|
861
|
863
|
if (cutter.cutter_mode == CUTTER_MODE_CONTINUOUS) {
|
862
|
864
|
if (planner.laser_inline.status.isPowered && planner.laser_inline.status.isEnabled) {
|
|
@@ -937,20 +939,30 @@ void Planner::calculate_trapezoid_for_block(block_t * const block, const_float_t
|
937
|
939
|
this block can never be less than block_buffer_tail and will always be pushed forward and maintain
|
938
|
940
|
this requirement when encountered by the Planner::release_current_block() routine during a cycle.
|
939
|
941
|
|
940
|
|
- NOTE: Since the planner only computes on what's in the planner buffer, some motions with lots of short
|
941
|
|
- line segments, like G2/3 arcs or complex curves, may seem to move slow. This is because there simply isn't
|
942
|
|
- enough combined distance traveled in the entire buffer to accelerate up to the nominal speed and then
|
943
|
|
- decelerate to a complete stop at the end of the buffer, as stated by the guidelines. If this happens and
|
944
|
|
- becomes an annoyance, there are a few simple solutions: (1) Maximize the machine acceleration. The planner
|
945
|
|
- will be able to compute higher velocity profiles within the same combined distance. (2) Maximize line
|
946
|
|
- motion(s) distance per block to a desired tolerance. The more combined distance the planner has to use,
|
947
|
|
- the faster it can go. (3) Maximize the planner buffer size. This also will increase the combined distance
|
948
|
|
- for the planner to compute over. It also increases the number of computations the planner has to perform
|
949
|
|
- to compute an optimal plan, so select carefully.
|
|
942
|
+ NOTE: Since the planner only computes on what's in the planner buffer, some motions with many short
|
|
943
|
+ segments (e.g., complex curves) may seem to move slowly. This is because there simply isn't
|
|
944
|
+ enough combined distance traveled in the entire buffer to accelerate up to the nominal speed and
|
|
945
|
+ then decelerate to a complete stop at the end of the buffer, as stated by the guidelines. If this
|
|
946
|
+ happens and becomes an annoyance, there are a few simple solutions:
|
|
947
|
+
|
|
948
|
+ - Maximize the machine acceleration. The planner will be able to compute higher velocity profiles
|
|
949
|
+ within the same combined distance.
|
|
950
|
+
|
|
951
|
+ - Maximize line motion(s) distance per block to a desired tolerance. The more combined distance the
|
|
952
|
+ planner has to use, the faster it can go.
|
|
953
|
+
|
|
954
|
+ - Maximize the planner buffer size. This also will increase the combined distance for the planner to
|
|
955
|
+ compute over. It also increases the number of computations the planner has to perform to compute an
|
|
956
|
+ optimal plan, so select carefully.
|
|
957
|
+
|
|
958
|
+ - Use G2/G3 arcs instead of many short segments. Arcs inform the planner of a safe exit speed at the
|
|
959
|
+ end of the last segment, which alleviates this problem.
|
950
|
960
|
*/
|
951
|
961
|
|
952
|
962
|
// The kernel called by recalculate() when scanning the plan from last to first entry.
|
953
|
|
-void Planner::reverse_pass_kernel(block_t * const current, const block_t * const next) {
|
|
963
|
+void Planner::reverse_pass_kernel(block_t * const current, const block_t * const next
|
|
964
|
+ OPTARG(HINTS_SAFE_EXIT_SPEED, const_float_t safe_exit_speed_sqr)
|
|
965
|
+) {
|
954
|
966
|
if (current) {
|
955
|
967
|
// If entry speed is already at the maximum entry speed, and there was no change of speed
|
956
|
968
|
// in the next block, there is no need to recheck. Block is cruising and there is no need to
|
|
@@ -970,9 +982,10 @@ void Planner::reverse_pass_kernel(block_t * const current, const block_t * const
|
970
|
982
|
// the reverse and forward planners, the corresponding block junction speed will always be at the
|
971
|
983
|
// the maximum junction speed and may always be ignored for any speed reduction checks.
|
972
|
984
|
|
973
|
|
- const float new_entry_speed_sqr = current->flag.nominal_length
|
974
|
|
- ? max_entry_speed_sqr
|
975
|
|
- : _MIN(max_entry_speed_sqr, max_allowable_speed_sqr(-current->acceleration, next ? next->entry_speed_sqr : sq(float(MINIMUM_PLANNER_SPEED)), current->millimeters));
|
|
985
|
+ const float next_entry_speed_sqr = next ? next->entry_speed_sqr : _MAX(TERN0(HINTS_SAFE_EXIT_SPEED, safe_exit_speed_sqr), sq(float(MINIMUM_PLANNER_SPEED))),
|
|
986
|
+ new_entry_speed_sqr = current->flag.nominal_length
|
|
987
|
+ ? max_entry_speed_sqr
|
|
988
|
+ : _MIN(max_entry_speed_sqr, max_allowable_speed_sqr(-current->acceleration, next_entry_speed_sqr, current->millimeters));
|
976
|
989
|
if (current->entry_speed_sqr != new_entry_speed_sqr) {
|
977
|
990
|
|
978
|
991
|
// Need to recalculate the block speed - Mark it now, so the stepper
|
|
@@ -1001,7 +1014,7 @@ void Planner::reverse_pass_kernel(block_t * const current, const block_t * const
|
1001
|
1014
|
* recalculate() needs to go over the current plan twice.
|
1002
|
1015
|
* Once in reverse and once forward. This implements the reverse pass.
|
1003
|
1016
|
*/
|
1004
|
|
-void Planner::reverse_pass() {
|
|
1017
|
+void Planner::reverse_pass(TERN_(HINTS_SAFE_EXIT_SPEED, const_float_t safe_exit_speed_sqr)) {
|
1005
|
1018
|
// Initialize block index to the last block in the planner buffer.
|
1006
|
1019
|
uint8_t block_index = prev_block_index(block_buffer_head);
|
1007
|
1020
|
|
|
@@ -1025,7 +1038,7 @@ void Planner::reverse_pass() {
|
1025
|
1038
|
|
1026
|
1039
|
// Only process movement blocks
|
1027
|
1040
|
if (current->is_move()) {
|
1028
|
|
- reverse_pass_kernel(current, next);
|
|
1041
|
+ reverse_pass_kernel(current, next OPTARG(HINTS_SAFE_EXIT_SPEED, safe_exit_speed_sqr));
|
1029
|
1042
|
next = current;
|
1030
|
1043
|
}
|
1031
|
1044
|
|
|
@@ -1138,7 +1151,7 @@ void Planner::forward_pass() {
|
1138
|
1151
|
* according to the entry_factor for each junction. Must be called by
|
1139
|
1152
|
* recalculate() after updating the blocks.
|
1140
|
1153
|
*/
|
1141
|
|
-void Planner::recalculate_trapezoids() {
|
|
1154
|
+void Planner::recalculate_trapezoids(TERN_(HINTS_SAFE_EXIT_SPEED, const_float_t safe_exit_speed_sqr)) {
|
1142
|
1155
|
// The tail may be changed by the ISR so get a local copy.
|
1143
|
1156
|
uint8_t block_index = block_buffer_tail,
|
1144
|
1157
|
head_block_index = block_buffer_head;
|
|
@@ -1211,8 +1224,10 @@ void Planner::recalculate_trapezoids() {
|
1211
|
1224
|
block_index = next_block_index(block_index);
|
1212
|
1225
|
}
|
1213
|
1226
|
|
1214
|
|
- // Last/newest block in buffer. Exit speed is set with MINIMUM_PLANNER_SPEED. Always recalculated.
|
1215
|
|
- if (next) {
|
|
1227
|
+ // Last/newest block in buffer. Always recalculated.
|
|
1228
|
+ if (block) {
|
|
1229
|
+ // Exit speed is set with MINIMUM_PLANNER_SPEED unless some code higher up knows better.
|
|
1230
|
+ next_entry_speed = _MAX(TERN0(HINTS_SAFE_EXIT_SPEED, SQRT(safe_exit_speed_sqr)), float(MINIMUM_PLANNER_SPEED));
|
1216
|
1231
|
|
1217
|
1232
|
// Mark the next(last) block as RECALCULATE, to prevent the Stepper ISR running it.
|
1218
|
1233
|
// As the last block is always recalculated here, there is a chance the block isn't
|
|
@@ -1225,33 +1240,33 @@ void Planner::recalculate_trapezoids() {
|
1225
|
1240
|
if (!stepper.is_block_busy(block)) {
|
1226
|
1241
|
// Block is not BUSY, we won the race against the Stepper ISR:
|
1227
|
1242
|
|
1228
|
|
- const float next_nominal_speed = SQRT(next->nominal_speed_sqr),
|
1229
|
|
- nomr = 1.0f / next_nominal_speed;
|
1230
|
|
- calculate_trapezoid_for_block(next, next_entry_speed * nomr, float(MINIMUM_PLANNER_SPEED) * nomr);
|
|
1243
|
+ const float current_nominal_speed = SQRT(block->nominal_speed_sqr),
|
|
1244
|
+ nomr = 1.0f / current_nominal_speed;
|
|
1245
|
+ calculate_trapezoid_for_block(block, current_entry_speed * nomr, next_entry_speed * nomr);
|
1231
|
1246
|
#if ENABLED(LIN_ADVANCE)
|
1232
|
|
- if (next->use_advance_lead) {
|
1233
|
|
- const float comp = next->e_D_ratio * extruder_advance_K[active_extruder] * settings.axis_steps_per_mm[E_AXIS];
|
1234
|
|
- next->max_adv_steps = next_nominal_speed * comp;
|
1235
|
|
- next->final_adv_steps = (MINIMUM_PLANNER_SPEED) * comp;
|
|
1247
|
+ if (block->use_advance_lead) {
|
|
1248
|
+ const float comp = block->e_D_ratio * extruder_advance_K[active_extruder] * settings.axis_steps_per_mm[E_AXIS];
|
|
1249
|
+ block->max_adv_steps = current_nominal_speed * comp;
|
|
1250
|
+ block->final_adv_steps = next_entry_speed * comp;
|
1236
|
1251
|
}
|
1237
|
1252
|
#endif
|
1238
|
1253
|
}
|
1239
|
1254
|
|
1240
|
|
- // Reset next only to ensure its trapezoid is computed - The stepper is free to use
|
|
1255
|
+ // Reset block to ensure its trapezoid is computed - The stepper is free to use
|
1241
|
1256
|
// the block from now on.
|
1242
|
|
- next->flag.recalculate = false;
|
|
1257
|
+ block->flag.recalculate = false;
|
1243
|
1258
|
}
|
1244
|
1259
|
}
|
1245
|
1260
|
|
1246
|
|
-void Planner::recalculate() {
|
|
1261
|
+void Planner::recalculate(TERN_(HINTS_SAFE_EXIT_SPEED, const_float_t safe_exit_speed_sqr)) {
|
1247
|
1262
|
// Initialize block index to the last block in the planner buffer.
|
1248
|
1263
|
const uint8_t block_index = prev_block_index(block_buffer_head);
|
1249
|
1264
|
// If there is just one block, no planning can be done. Avoid it!
|
1250
|
1265
|
if (block_index != block_buffer_planned) {
|
1251
|
|
- reverse_pass();
|
|
1266
|
+ reverse_pass(TERN_(HINTS_SAFE_EXIT_SPEED, safe_exit_speed_sqr));
|
1252
|
1267
|
forward_pass();
|
1253
|
1268
|
}
|
1254
|
|
- recalculate_trapezoids();
|
|
1269
|
+ recalculate_trapezoids(TERN_(HINTS_SAFE_EXIT_SPEED, safe_exit_speed_sqr));
|
1255
|
1270
|
}
|
1256
|
1271
|
|
1257
|
1272
|
/**
|
|
@@ -1777,22 +1792,21 @@ float Planner::get_axis_position_mm(const AxisEnum axis) {
|
1777
|
1792
|
void Planner::synchronize() { while (busy()) idle(); }
|
1778
|
1793
|
|
1779
|
1794
|
/**
|
1780
|
|
- * Planner::_buffer_steps
|
1781
|
|
- *
|
1782
|
|
- * Add a new linear movement to the planner queue (in terms of steps).
|
|
1795
|
+ * @brief Add a new linear movement to the planner queue (in terms of steps).
|
1783
|
1796
|
*
|
1784
|
|
- * target - target position in steps units
|
1785
|
|
- * target_float - target position in direct (mm, degrees) units. optional
|
1786
|
|
- * fr_mm_s - (target) speed of the move
|
1787
|
|
- * extruder - target extruder
|
1788
|
|
- * millimeters - the length of the movement, if known
|
|
1797
|
+ * @param target Target position in steps units
|
|
1798
|
+ * @param target_float Target position in direct (mm, degrees) units.
|
|
1799
|
+ * @param cart_dist_mm The pre-calculated move lengths for all axes, in mm
|
|
1800
|
+ * @param fr_mm_s (target) speed of the move
|
|
1801
|
+ * @param extruder target extruder
|
|
1802
|
+ * @param hints parameters to aid planner calculations
|
1789
|
1803
|
*
|
1790
|
|
- * Returns true if movement was properly queued, false otherwise (if cleaning)
|
|
1804
|
+ * @return true if movement was properly queued, false otherwise (if cleaning)
|
1791
|
1805
|
*/
|
1792
|
1806
|
bool Planner::_buffer_steps(const xyze_long_t &target
|
1793
|
1807
|
OPTARG(HAS_POSITION_FLOAT, const xyze_pos_t &target_float)
|
1794
|
1808
|
OPTARG(HAS_DIST_MM_ARG, const xyze_float_t &cart_dist_mm)
|
1795
|
|
- , feedRate_t fr_mm_s, const uint8_t extruder, const_float_t millimeters
|
|
1809
|
+ , feedRate_t fr_mm_s, const uint8_t extruder, const PlannerHints &hints
|
1796
|
1810
|
) {
|
1797
|
1811
|
|
1798
|
1812
|
// Wait for the next available block
|
|
@@ -1808,7 +1822,7 @@ bool Planner::_buffer_steps(const xyze_long_t &target
|
1808
|
1822
|
if (!_populate_block(block, target
|
1809
|
1823
|
OPTARG(HAS_POSITION_FLOAT, target_float)
|
1810
|
1824
|
OPTARG(HAS_DIST_MM_ARG, cart_dist_mm)
|
1811
|
|
- , fr_mm_s, extruder, millimeters
|
|
1825
|
+ , fr_mm_s, extruder, hints
|
1812
|
1826
|
)
|
1813
|
1827
|
) {
|
1814
|
1828
|
// Movement was not queued, probably because it was too short.
|
|
@@ -1830,7 +1844,7 @@ bool Planner::_buffer_steps(const xyze_long_t &target
|
1830
|
1844
|
block_buffer_head = next_buffer_head;
|
1831
|
1845
|
|
1832
|
1846
|
// Recalculate and optimize trapezoidal speed profiles
|
1833
|
|
- recalculate();
|
|
1847
|
+ recalculate(TERN_(HINTS_SAFE_EXIT_SPEED, hints.safe_exit_speed_sqr));
|
1834
|
1848
|
|
1835
|
1849
|
// Movement successfully queued!
|
1836
|
1850
|
return true;
|
|
@@ -1848,8 +1862,7 @@ bool Planner::_buffer_steps(const xyze_long_t &target
|
1848
|
1862
|
* @param cart_dist_mm The pre-calculated move lengths for all axes, in mm
|
1849
|
1863
|
* @param fr_mm_s (target) speed of the move
|
1850
|
1864
|
* @param extruder target extruder
|
1851
|
|
- * @param millimeters A pre-calculated linear distance for the move, in mm,
|
1852
|
|
- * or 0.0 to have the distance calculated here.
|
|
1865
|
+ * @param hints parameters to aid planner calculations
|
1853
|
1866
|
*
|
1854
|
1867
|
* @return true if movement is acceptable, false otherwise
|
1855
|
1868
|
*/
|
|
@@ -1858,7 +1871,7 @@ bool Planner::_populate_block(
|
1858
|
1871
|
const abce_long_t &target
|
1859
|
1872
|
OPTARG(HAS_POSITION_FLOAT, const xyze_pos_t &target_float)
|
1860
|
1873
|
OPTARG(HAS_DIST_MM_ARG, const xyze_float_t &cart_dist_mm)
|
1861
|
|
- , feedRate_t fr_mm_s, const uint8_t extruder, const_float_t millimeters/*=0.0*/
|
|
1874
|
+ , feedRate_t fr_mm_s, const uint8_t extruder, const PlannerHints &hints
|
1862
|
1875
|
) {
|
1863
|
1876
|
int32_t LOGICAL_AXIS_LIST(
|
1864
|
1877
|
de = target.e - position.e,
|
|
@@ -2134,8 +2147,8 @@ bool Planner::_populate_block(
|
2134
|
2147
|
block->millimeters = TERN0(HAS_EXTRUDERS, ABS(steps_dist_mm.e));
|
2135
|
2148
|
}
|
2136
|
2149
|
else {
|
2137
|
|
- if (millimeters)
|
2138
|
|
- block->millimeters = millimeters;
|
|
2150
|
+ if (hints.millimeters)
|
|
2151
|
+ block->millimeters = hints.millimeters;
|
2139
|
2152
|
else {
|
2140
|
2153
|
/**
|
2141
|
2154
|
* Distance for interpretation of feedrate in accordance with LinuxCNC (the successor of NIST
|
|
@@ -2243,15 +2256,9 @@ bool Planner::_populate_block(
|
2243
|
2256
|
|
2244
|
2257
|
#if ENABLED(AUTO_POWER_CONTROL)
|
2245
|
2258
|
if (NUM_AXIS_GANG(
|
2246
|
|
- block->steps.x,
|
2247
|
|
- || block->steps.y,
|
2248
|
|
- || block->steps.z,
|
2249
|
|
- || block->steps.i,
|
2250
|
|
- || block->steps.j,
|
2251
|
|
- || block->steps.k,
|
2252
|
|
- || block->steps.u,
|
2253
|
|
- || block->steps.v,
|
2254
|
|
- || block->steps.w
|
|
2259
|
+ block->steps.x, || block->steps.y, || block->steps.z,
|
|
2260
|
+ || block->steps.i, || block->steps.j, || block->steps.k,
|
|
2261
|
+ || block->steps.u, || block->steps.v, || block->steps.w
|
2255
|
2262
|
)) powerManager.power_on();
|
2256
|
2263
|
#endif
|
2257
|
2264
|
|
|
@@ -2562,29 +2569,17 @@ bool Planner::_populate_block(
|
2562
|
2569
|
if (block->step_event_count <= acceleration_long_cutoff) {
|
2563
|
2570
|
LOGICAL_AXIS_CODE(
|
2564
|
2571
|
LIMIT_ACCEL_LONG(E_AXIS, E_INDEX_N(extruder)),
|
2565
|
|
- LIMIT_ACCEL_LONG(A_AXIS, 0),
|
2566
|
|
- LIMIT_ACCEL_LONG(B_AXIS, 0),
|
2567
|
|
- LIMIT_ACCEL_LONG(C_AXIS, 0),
|
2568
|
|
- LIMIT_ACCEL_LONG(I_AXIS, 0),
|
2569
|
|
- LIMIT_ACCEL_LONG(J_AXIS, 0),
|
2570
|
|
- LIMIT_ACCEL_LONG(K_AXIS, 0),
|
2571
|
|
- LIMIT_ACCEL_LONG(U_AXIS, 0),
|
2572
|
|
- LIMIT_ACCEL_LONG(V_AXIS, 0),
|
2573
|
|
- LIMIT_ACCEL_LONG(W_AXIS, 0)
|
|
2572
|
+ LIMIT_ACCEL_LONG(A_AXIS, 0), LIMIT_ACCEL_LONG(B_AXIS, 0), LIMIT_ACCEL_LONG(C_AXIS, 0),
|
|
2573
|
+ LIMIT_ACCEL_LONG(I_AXIS, 0), LIMIT_ACCEL_LONG(J_AXIS, 0), LIMIT_ACCEL_LONG(K_AXIS, 0),
|
|
2574
|
+ LIMIT_ACCEL_LONG(U_AXIS, 0), LIMIT_ACCEL_LONG(V_AXIS, 0), LIMIT_ACCEL_LONG(W_AXIS, 0)
|
2574
|
2575
|
);
|
2575
|
2576
|
}
|
2576
|
2577
|
else {
|
2577
|
2578
|
LOGICAL_AXIS_CODE(
|
2578
|
2579
|
LIMIT_ACCEL_FLOAT(E_AXIS, E_INDEX_N(extruder)),
|
2579
|
|
- LIMIT_ACCEL_FLOAT(A_AXIS, 0),
|
2580
|
|
- LIMIT_ACCEL_FLOAT(B_AXIS, 0),
|
2581
|
|
- LIMIT_ACCEL_FLOAT(C_AXIS, 0),
|
2582
|
|
- LIMIT_ACCEL_FLOAT(I_AXIS, 0),
|
2583
|
|
- LIMIT_ACCEL_FLOAT(J_AXIS, 0),
|
2584
|
|
- LIMIT_ACCEL_FLOAT(K_AXIS, 0),
|
2585
|
|
- LIMIT_ACCEL_FLOAT(U_AXIS, 0),
|
2586
|
|
- LIMIT_ACCEL_FLOAT(V_AXIS, 0),
|
2587
|
|
- LIMIT_ACCEL_FLOAT(W_AXIS, 0)
|
|
2580
|
+ LIMIT_ACCEL_FLOAT(A_AXIS, 0), LIMIT_ACCEL_FLOAT(B_AXIS, 0), LIMIT_ACCEL_FLOAT(C_AXIS, 0),
|
|
2581
|
+ LIMIT_ACCEL_FLOAT(I_AXIS, 0), LIMIT_ACCEL_FLOAT(J_AXIS, 0), LIMIT_ACCEL_FLOAT(K_AXIS, 0),
|
|
2582
|
+ LIMIT_ACCEL_FLOAT(U_AXIS, 0), LIMIT_ACCEL_FLOAT(V_AXIS, 0), LIMIT_ACCEL_FLOAT(W_AXIS, 0)
|
2588
|
2583
|
);
|
2589
|
2584
|
}
|
2590
|
2585
|
}
|
|
@@ -2649,7 +2644,10 @@ bool Planner::_populate_block(
|
2649
|
2644
|
#if HAS_DIST_MM_ARG
|
2650
|
2645
|
cart_dist_mm
|
2651
|
2646
|
#else
|
2652
|
|
- LOGICAL_AXIS_ARRAY(steps_dist_mm.e, steps_dist_mm.x, steps_dist_mm.y, steps_dist_mm.z, steps_dist_mm.i, steps_dist_mm.j, steps_dist_mm.k, steps_dist_mm.u, steps_dist_mm.v, steps_dist_mm.w)
|
|
2647
|
+ LOGICAL_AXIS_ARRAY(steps_dist_mm.e,
|
|
2648
|
+ steps_dist_mm.x, steps_dist_mm.y, steps_dist_mm.z,
|
|
2649
|
+ steps_dist_mm.i, steps_dist_mm.j, steps_dist_mm.k,
|
|
2650
|
+ steps_dist_mm.u, steps_dist_mm.v, steps_dist_mm.w)
|
2653
|
2651
|
#endif
|
2654
|
2652
|
;
|
2655
|
2653
|
|
|
@@ -2670,7 +2668,7 @@ bool Planner::_populate_block(
|
2670
|
2668
|
// NOTE: Max junction velocity is computed without sin() or acos() by trig half angle identity.
|
2671
|
2669
|
float junction_cos_theta = LOGICAL_AXIS_GANG(
|
2672
|
2670
|
+ (-prev_unit_vec.e * unit_vec.e),
|
2673
|
|
- (-prev_unit_vec.x * unit_vec.x),
|
|
2671
|
+ + (-prev_unit_vec.x * unit_vec.x),
|
2674
|
2672
|
+ (-prev_unit_vec.y * unit_vec.y),
|
2675
|
2673
|
+ (-prev_unit_vec.z * unit_vec.z),
|
2676
|
2674
|
+ (-prev_unit_vec.i * unit_vec.i),
|
|
@@ -2687,104 +2685,110 @@ bool Planner::_populate_block(
|
2687
|
2685
|
vmax_junction_sqr = sq(float(MINIMUM_PLANNER_SPEED));
|
2688
|
2686
|
}
|
2689
|
2687
|
else {
|
2690
|
|
- NOLESS(junction_cos_theta, -0.999999f); // Check for numerical round-off to avoid divide by zero.
|
2691
|
|
-
|
2692
|
2688
|
// Convert delta vector to unit vector
|
2693
|
2689
|
xyze_float_t junction_unit_vec = unit_vec - prev_unit_vec;
|
2694
|
2690
|
normalize_junction_vector(junction_unit_vec);
|
2695
|
2691
|
|
2696
|
|
- const float junction_acceleration = limit_value_by_axis_maximum(block->acceleration, junction_unit_vec),
|
2697
|
|
- sin_theta_d2 = SQRT(0.5f * (1.0f - junction_cos_theta)); // Trig half angle identity. Always positive.
|
2698
|
|
-
|
2699
|
|
- vmax_junction_sqr = junction_acceleration * junction_deviation_mm * sin_theta_d2 / (1.0f - sin_theta_d2);
|
2700
|
|
-
|
2701
|
|
- #if ENABLED(JD_HANDLE_SMALL_SEGMENTS)
|
2702
|
|
-
|
2703
|
|
- // For small moves with >135° junction (octagon) find speed for approximate arc
|
2704
|
|
- if (block->millimeters < 1 && junction_cos_theta < -0.7071067812f) {
|
2705
|
|
-
|
2706
|
|
- #if ENABLED(JD_USE_MATH_ACOS)
|
2707
|
|
-
|
2708
|
|
- #error "TODO: Inline maths with the MCU / FPU."
|
2709
|
|
-
|
2710
|
|
- #elif ENABLED(JD_USE_LOOKUP_TABLE)
|
2711
|
|
-
|
2712
|
|
- // Fast acos approximation (max. error +-0.01 rads)
|
2713
|
|
- // Based on LUT table and linear interpolation
|
2714
|
|
-
|
2715
|
|
- /**
|
2716
|
|
- * // Generate the JD Lookup Table
|
2717
|
|
- * constexpr float c = 1.00751495f; // Correction factor to center error around 0
|
2718
|
|
- * for (int i = 0; i < jd_lut_count - 1; ++i) {
|
2719
|
|
- * const float x0 = (sq(i) - 1) / sq(i),
|
2720
|
|
- * y0 = acos(x0) * (i == 0 ? 1 : c),
|
2721
|
|
- * x1 = i < jd_lut_count - 1 ? 0.5 * x0 + 0.5 : 0.999999f,
|
2722
|
|
- * y1 = acos(x1) * (i < jd_lut_count - 1 ? c : 1);
|
2723
|
|
- * jd_lut_k[i] = (y0 - y1) / (x0 - x1);
|
2724
|
|
- * jd_lut_b[i] = (y1 * x0 - y0 * x1) / (x0 - x1);
|
2725
|
|
- * }
|
2726
|
|
- *
|
2727
|
|
- * // Compute correction factor (Set c to 1.0f first!)
|
2728
|
|
- * float min = INFINITY, max = -min;
|
2729
|
|
- * for (float t = 0; t <= 1; t += 0.0003f) {
|
2730
|
|
- * const float e = acos(t) / approx(t);
|
2731
|
|
- * if (isfinite(e)) {
|
2732
|
|
- * if (e < min) min = e;
|
2733
|
|
- * if (e > max) max = e;
|
2734
|
|
- * }
|
2735
|
|
- * }
|
2736
|
|
- * fprintf(stderr, "%.9gf, ", (min + max) / 2);
|
2737
|
|
- */
|
2738
|
|
- static constexpr int16_t jd_lut_count = 16;
|
2739
|
|
- static constexpr uint16_t jd_lut_tll = _BV(jd_lut_count - 1);
|
2740
|
|
- static constexpr int16_t jd_lut_tll0 = __builtin_clz(jd_lut_tll) + 1; // i.e., 16 - jd_lut_count + 1
|
2741
|
|
- static constexpr float jd_lut_k[jd_lut_count] PROGMEM = {
|
2742
|
|
- -1.03145837f, -1.30760646f, -1.75205851f, -2.41705704f,
|
2743
|
|
- -3.37769222f, -4.74888992f, -6.69649887f, -9.45661736f,
|
2744
|
|
- -13.3640480f, -18.8928222f, -26.7136841f, -37.7754593f,
|
2745
|
|
- -53.4201813f, -75.5458374f, -106.836761f, -218.532821f };
|
2746
|
|
- static constexpr float jd_lut_b[jd_lut_count] PROGMEM = {
|
2747
|
|
- 1.57079637f, 1.70887053f, 2.04220939f, 2.62408352f,
|
2748
|
|
- 3.52467871f, 4.85302639f, 6.77020454f, 9.50875854f,
|
2749
|
|
- 13.4009285f, 18.9188995f, 26.7321243f, 37.7885055f,
|
2750
|
|
- 53.4293975f, 75.5523529f, 106.841369f, 218.534011f };
|
2751
|
|
-
|
2752
|
|
- const float neg = junction_cos_theta < 0 ? -1 : 1,
|
2753
|
|
- t = neg * junction_cos_theta;
|
2754
|
|
-
|
2755
|
|
- const int16_t idx = (t < 0.00000003f) ? 0 : __builtin_clz(uint16_t((1.0f - t) * jd_lut_tll)) - jd_lut_tll0;
|
2756
|
|
-
|
2757
|
|
- float junction_theta = t * pgm_read_float(&jd_lut_k[idx]) + pgm_read_float(&jd_lut_b[idx]);
|
2758
|
|
- if (neg > 0) junction_theta = RADIANS(180) - junction_theta; // acos(-t)
|
2759
|
|
-
|
2760
|
|
- #else
|
2761
|
|
-
|
2762
|
|
- // Fast acos(-t) approximation (max. error +-0.033rad = 1.89°)
|
2763
|
|
- // Based on MinMax polynomial published by W. Randolph Franklin, see
|
2764
|
|
- // https://wrf.ecse.rpi.edu/Research/Short_Notes/arcsin/onlyelem.html
|
2765
|
|
- // acos( t) = pi / 2 - asin(x)
|
2766
|
|
- // acos(-t) = pi - acos(t) ... pi / 2 + asin(x)
|
2767
|
|
-
|
2768
|
|
- const float neg = junction_cos_theta < 0 ? -1 : 1,
|
2769
|
|
- t = neg * junction_cos_theta,
|
2770
|
|
- asinx = 0.032843707f
|
2771
|
|
- + t * (-1.451838349f
|
2772
|
|
- + t * ( 29.66153956f
|
2773
|
|
- + t * (-131.1123477f
|
2774
|
|
- + t * ( 262.8130562f
|
2775
|
|
- + t * (-242.7199627f
|
2776
|
|
- + t * ( 84.31466202f ) ))))),
|
2777
|
|
- junction_theta = RADIANS(90) + neg * asinx; // acos(-t)
|
2778
|
|
-
|
2779
|
|
- // NOTE: junction_theta bottoms out at 0.033 which avoids divide by 0.
|
2780
|
|
-
|
2781
|
|
- #endif
|
2782
|
|
-
|
2783
|
|
- const float limit_sqr = (block->millimeters * junction_acceleration) / junction_theta;
|
2784
|
|
- NOMORE(vmax_junction_sqr, limit_sqr);
|
2785
|
|
- }
|
|
2692
|
+ const float junction_acceleration = limit_value_by_axis_maximum(block->acceleration, junction_unit_vec);
|
2786
|
2693
|
|
2787
|
|
- #endif // JD_HANDLE_SMALL_SEGMENTS
|
|
2694
|
+ if (TERN0(HINTS_CURVE_RADIUS, hints.curve_radius)) {
|
|
2695
|
+ TERN_(HINTS_CURVE_RADIUS, vmax_junction_sqr = junction_acceleration * hints.curve_radius);
|
|
2696
|
+ }
|
|
2697
|
+ else {
|
|
2698
|
+ NOLESS(junction_cos_theta, -0.999999f); // Check for numerical round-off to avoid divide by zero.
|
|
2699
|
+
|
|
2700
|
+ const float sin_theta_d2 = SQRT(0.5f * (1.0f - junction_cos_theta)); // Trig half angle identity. Always positive.
|
|
2701
|
+
|
|
2702
|
+ vmax_junction_sqr = junction_acceleration * junction_deviation_mm * sin_theta_d2 / (1.0f - sin_theta_d2);
|
|
2703
|
+
|
|
2704
|
+ #if ENABLED(JD_HANDLE_SMALL_SEGMENTS)
|
|
2705
|
+
|
|
2706
|
+ // For small moves with >135° junction (octagon) find speed for approximate arc
|
|
2707
|
+ if (block->millimeters < 1 && junction_cos_theta < -0.7071067812f) {
|
|
2708
|
+
|
|
2709
|
+ #if ENABLED(JD_USE_MATH_ACOS)
|
|
2710
|
+
|
|
2711
|
+ #error "TODO: Inline maths with the MCU / FPU."
|
|
2712
|
+
|
|
2713
|
+ #elif ENABLED(JD_USE_LOOKUP_TABLE)
|
|
2714
|
+
|
|
2715
|
+ // Fast acos approximation (max. error +-0.01 rads)
|
|
2716
|
+ // Based on LUT table and linear interpolation
|
|
2717
|
+
|
|
2718
|
+ /**
|
|
2719
|
+ * // Generate the JD Lookup Table
|
|
2720
|
+ * constexpr float c = 1.00751495f; // Correction factor to center error around 0
|
|
2721
|
+ * for (int i = 0; i < jd_lut_count - 1; ++i) {
|
|
2722
|
+ * const float x0 = (sq(i) - 1) / sq(i),
|
|
2723
|
+ * y0 = acos(x0) * (i == 0 ? 1 : c),
|
|
2724
|
+ * x1 = i < jd_lut_count - 1 ? 0.5 * x0 + 0.5 : 0.999999f,
|
|
2725
|
+ * y1 = acos(x1) * (i < jd_lut_count - 1 ? c : 1);
|
|
2726
|
+ * jd_lut_k[i] = (y0 - y1) / (x0 - x1);
|
|
2727
|
+ * jd_lut_b[i] = (y1 * x0 - y0 * x1) / (x0 - x1);
|
|
2728
|
+ * }
|
|
2729
|
+ *
|
|
2730
|
+ * // Compute correction factor (Set c to 1.0f first!)
|
|
2731
|
+ * float min = INFINITY, max = -min;
|
|
2732
|
+ * for (float t = 0; t <= 1; t += 0.0003f) {
|
|
2733
|
+ * const float e = acos(t) / approx(t);
|
|
2734
|
+ * if (isfinite(e)) {
|
|
2735
|
+ * if (e < min) min = e;
|
|
2736
|
+ * if (e > max) max = e;
|
|
2737
|
+ * }
|
|
2738
|
+ * }
|
|
2739
|
+ * fprintf(stderr, "%.9gf, ", (min + max) / 2);
|
|
2740
|
+ */
|
|
2741
|
+ static constexpr int16_t jd_lut_count = 16;
|
|
2742
|
+ static constexpr uint16_t jd_lut_tll = _BV(jd_lut_count - 1);
|
|
2743
|
+ static constexpr int16_t jd_lut_tll0 = __builtin_clz(jd_lut_tll) + 1; // i.e., 16 - jd_lut_count + 1
|
|
2744
|
+ static constexpr float jd_lut_k[jd_lut_count] PROGMEM = {
|
|
2745
|
+ -1.03145837f, -1.30760646f, -1.75205851f, -2.41705704f,
|
|
2746
|
+ -3.37769222f, -4.74888992f, -6.69649887f, -9.45661736f,
|
|
2747
|
+ -13.3640480f, -18.8928222f, -26.7136841f, -37.7754593f,
|
|
2748
|
+ -53.4201813f, -75.5458374f, -106.836761f, -218.532821f };
|
|
2749
|
+ static constexpr float jd_lut_b[jd_lut_count] PROGMEM = {
|
|
2750
|
+ 1.57079637f, 1.70887053f, 2.04220939f, 2.62408352f,
|
|
2751
|
+ 3.52467871f, 4.85302639f, 6.77020454f, 9.50875854f,
|
|
2752
|
+ 13.4009285f, 18.9188995f, 26.7321243f, 37.7885055f,
|
|
2753
|
+ 53.4293975f, 75.5523529f, 106.841369f, 218.534011f };
|
|
2754
|
+
|
|
2755
|
+ const float neg = junction_cos_theta < 0 ? -1 : 1,
|
|
2756
|
+ t = neg * junction_cos_theta;
|
|
2757
|
+
|
|
2758
|
+ const int16_t idx = (t < 0.00000003f) ? 0 : __builtin_clz(uint16_t((1.0f - t) * jd_lut_tll)) - jd_lut_tll0;
|
|
2759
|
+
|
|
2760
|
+ float junction_theta = t * pgm_read_float(&jd_lut_k[idx]) + pgm_read_float(&jd_lut_b[idx]);
|
|
2761
|
+ if (neg > 0) junction_theta = RADIANS(180) - junction_theta; // acos(-t)
|
|
2762
|
+
|
|
2763
|
+ #else
|
|
2764
|
+
|
|
2765
|
+ // Fast acos(-t) approximation (max. error +-0.033rad = 1.89°)
|
|
2766
|
+ // Based on MinMax polynomial published by W. Randolph Franklin, see
|
|
2767
|
+ // https://wrf.ecse.rpi.edu/Research/Short_Notes/arcsin/onlyelem.html
|
|
2768
|
+ // acos( t) = pi / 2 - asin(x)
|
|
2769
|
+ // acos(-t) = pi - acos(t) ... pi / 2 + asin(x)
|
|
2770
|
+
|
|
2771
|
+ const float neg = junction_cos_theta < 0 ? -1 : 1,
|
|
2772
|
+ t = neg * junction_cos_theta,
|
|
2773
|
+ asinx = 0.032843707f
|
|
2774
|
+ + t * (-1.451838349f
|
|
2775
|
+ + t * ( 29.66153956f
|
|
2776
|
+ + t * (-131.1123477f
|
|
2777
|
+ + t * ( 262.8130562f
|
|
2778
|
+ + t * (-242.7199627f
|
|
2779
|
+ + t * ( 84.31466202f ) ))))),
|
|
2780
|
+ junction_theta = RADIANS(90) + neg * asinx; // acos(-t)
|
|
2781
|
+
|
|
2782
|
+ // NOTE: junction_theta bottoms out at 0.033 which avoids divide by 0.
|
|
2783
|
+
|
|
2784
|
+ #endif
|
|
2785
|
+
|
|
2786
|
+ const float limit_sqr = (block->millimeters * junction_acceleration) / junction_theta;
|
|
2787
|
+ NOMORE(vmax_junction_sqr, limit_sqr);
|
|
2788
|
+ }
|
|
2789
|
+
|
|
2790
|
+ #endif // JD_HANDLE_SMALL_SEGMENTS
|
|
2791
|
+ }
|
2788
|
2792
|
}
|
2789
|
2793
|
|
2790
|
2794
|
// Get the lowest speed
|
|
@@ -2944,12 +2948,11 @@ bool Planner::_populate_block(
|
2944
|
2948
|
} // _populate_block()
|
2945
|
2949
|
|
2946
|
2950
|
/**
|
2947
|
|
- * Planner::buffer_sync_block
|
2948
|
|
- * Add a block to the buffer that just updates the position
|
2949
|
|
- * @param sync_flag BLOCK_FLAG_SYNC_FANS & BLOCK_FLAG_LASER_PWR
|
2950
|
|
- * Supports LASER_SYNCHRONOUS_M106_M107 and LASER_POWER_SYNC power sync block buffer queueing.
|
|
2951
|
+ * @brief Add a block to the buffer that just updates the position
|
|
2952
|
+ * Supports LASER_SYNCHRONOUS_M106_M107 and LASER_POWER_SYNC power sync block buffer queueing.
|
|
2953
|
+ *
|
|
2954
|
+ * @param sync_flag The sync flag to set, determining the type of sync the block will do
|
2951
|
2955
|
*/
|
2952
|
|
-
|
2953
|
2956
|
void Planner::buffer_sync_block(const BlockFlagBit sync_flag/*=BLOCK_BIT_SYNC_POSITION*/) {
|
2954
|
2957
|
|
2955
|
2958
|
// Wait for the next available block
|
|
@@ -2957,14 +2960,13 @@ void Planner::buffer_sync_block(const BlockFlagBit sync_flag/*=BLOCK_BIT_SYNC_PO
|
2957
|
2960
|
block_t * const block = get_next_free_block(next_buffer_head);
|
2958
|
2961
|
|
2959
|
2962
|
// Clear block
|
2960
|
|
- memset(block, 0, sizeof(block_t));
|
|
2963
|
+ block->reset();
|
2961
|
2964
|
block->flag.apply(sync_flag);
|
2962
|
2965
|
|
2963
|
2966
|
block->position = position;
|
2964
|
2967
|
#if ENABLED(BACKLASH_COMPENSATION)
|
2965
|
2968
|
LOOP_NUM_AXES(axis) block->position[axis] += backlash.get_applied_steps((AxisEnum)axis);
|
2966
|
2969
|
#endif
|
2967
|
|
-
|
2968
|
2970
|
#if BOTH(HAS_FAN, LASER_SYNCHRONOUS_M106_M107)
|
2969
|
2971
|
FANS_LOOP(i) block->fan_speed[i] = thermalManager.fan_speed[i];
|
2970
|
2972
|
#endif
|
|
@@ -2991,22 +2993,24 @@ void Planner::buffer_sync_block(const BlockFlagBit sync_flag/*=BLOCK_BIT_SYNC_PO
|
2991
|
2993
|
} // buffer_sync_block()
|
2992
|
2994
|
|
2993
|
2995
|
/**
|
2994
|
|
- * Planner::buffer_segment
|
2995
|
|
- *
|
2996
|
|
- * Add a new linear movement to the buffer in axis units.
|
|
2996
|
+ * @brief Add a single linear movement
|
2997
|
2997
|
*
|
2998
|
|
- * Leveling and kinematics should be applied ahead of calling this.
|
|
2998
|
+ * @description Add a new linear movement to the buffer in axis units.
|
|
2999
|
+ * Leveling and kinematics should be applied before calling this.
|
2999
|
3000
|
*
|
3000
|
|
- * a,b,c,e - target positions in mm and/or degrees
|
3001
|
|
- * fr_mm_s - (target) speed of the move
|
3002
|
|
- * extruder - target extruder
|
3003
|
|
- * millimeters - the length of the movement, if known
|
|
3001
|
+ * @param abce Target position in mm and/or degrees
|
|
3002
|
+ * @param cart_dist_mm The pre-calculated move lengths for all axes, in mm
|
|
3003
|
+ * @param fr_mm_s (target) speed of the move
|
|
3004
|
+ * @param extruder optional target extruder (otherwise active_extruder)
|
|
3005
|
+ * @param hints optional parameters to aid planner calculations
|
3004
|
3006
|
*
|
3005
|
|
- * Return 'false' if no segment was queued due to cleaning, cold extrusion, full queue, etc.
|
|
3007
|
+ * @return false if no segment was queued due to cleaning, cold extrusion, full queue, etc.
|
3006
|
3008
|
*/
|
3007
|
3009
|
bool Planner::buffer_segment(const abce_pos_t &abce
|
3008
|
3010
|
OPTARG(HAS_DIST_MM_ARG, const xyze_float_t &cart_dist_mm)
|
3009
|
|
- , const_feedRate_t fr_mm_s, const uint8_t extruder/*=active_extruder*/, const_float_t millimeters/*=0.0*/
|
|
3011
|
+ , const_feedRate_t fr_mm_s
|
|
3012
|
+ , const uint8_t extruder/*=active_extruder*/
|
|
3013
|
+ , const PlannerHints &hints/*=PlannerHints()*/
|
3010
|
3014
|
) {
|
3011
|
3015
|
|
3012
|
3016
|
// If we are cleaning, do not accept queuing of movements
|
|
@@ -3112,8 +3116,8 @@ bool Planner::buffer_segment(const abce_pos_t &abce
|
3112
|
3116
|
if (!_buffer_steps(target
|
3113
|
3117
|
OPTARG(HAS_POSITION_FLOAT, target_float)
|
3114
|
3118
|
OPTARG(HAS_DIST_MM_ARG, cart_dist_mm)
|
3115
|
|
- , fr_mm_s, extruder, millimeters)
|
3116
|
|
- ) return false;
|
|
3119
|
+ , fr_mm_s, extruder, hints
|
|
3120
|
+ )) return false;
|
3117
|
3121
|
|
3118
|
3122
|
stepper.wake_up();
|
3119
|
3123
|
return true;
|
|
@@ -3126,12 +3130,12 @@ bool Planner::buffer_segment(const abce_pos_t &abce
|
3126
|
3130
|
*
|
3127
|
3131
|
* cart - target position in mm or degrees
|
3128
|
3132
|
* fr_mm_s - (target) speed of the move (mm/s)
|
3129
|
|
- * extruder - target extruder
|
3130
|
|
- * millimeters - the length of the movement, if known
|
3131
|
|
- * inv_duration - the reciprocal if the duration of the movement, if known (kinematic only if feeedrate scaling is enabled)
|
|
3133
|
+ * extruder - optional target extruder (otherwise active_extruder)
|
|
3134
|
+ * hints - optional parameters to aid planner calculations
|
3132
|
3135
|
*/
|
3133
|
|
-bool Planner::buffer_line(const xyze_pos_t &cart, const_feedRate_t fr_mm_s, const uint8_t extruder/*=active_extruder*/, const float millimeters/*=0.0*/
|
3134
|
|
- OPTARG(SCARA_FEEDRATE_SCALING, const_float_t inv_duration/*=0.0*/)
|
|
3136
|
+bool Planner::buffer_line(const xyze_pos_t &cart, const_feedRate_t fr_mm_s
|
|
3137
|
+ , const uint8_t extruder/*=active_extruder*/
|
|
3138
|
+ , const PlannerHints &hints/*=PlannerHints()*/
|
3135
|
3139
|
) {
|
3136
|
3140
|
xyze_pos_t machine = cart;
|
3137
|
3141
|
TERN_(HAS_POSITION_MODIFIERS, apply_modifiers(machine));
|
|
@@ -3153,28 +3157,30 @@ bool Planner::buffer_line(const xyze_pos_t &cart, const_feedRate_t fr_mm_s, cons
|
3153
|
3157
|
);
|
3154
|
3158
|
#endif
|
3155
|
3159
|
|
3156
|
|
- const float mm = millimeters ?: (cart_dist_mm.x || cart_dist_mm.y) ? cart_dist_mm.magnitude() : TERN0(HAS_Z_AXIS, ABS(cart_dist_mm.z));
|
3157
|
|
-
|
3158
|
3160
|
// Cartesian XYZ to kinematic ABC, stored in global 'delta'
|
3159
|
3161
|
inverse_kinematics(machine);
|
3160
|
3162
|
|
|
3163
|
+ PlannerHints ph = hints;
|
|
3164
|
+ if (!hints.millimeters)
|
|
3165
|
+ ph.millimeters = (cart_dist_mm.x || cart_dist_mm.y) ? cart_dist_mm.magnitude() : TERN0(HAS_Z_AXIS, ABS(cart_dist_mm.z));
|
|
3166
|
+
|
3161
|
3167
|
#if ENABLED(SCARA_FEEDRATE_SCALING)
|
3162
|
3168
|
// For SCARA scale the feedrate from mm/s to degrees/s
|
3163
|
3169
|
// i.e., Complete the angular vector in the given time.
|
3164
|
|
- const float duration_recip = inv_duration ?: fr_mm_s / mm;
|
|
3170
|
+ const float duration_recip = hints.inv_duration ?: fr_mm_s / ph.millimeters;
|
3165
|
3171
|
const xyz_pos_t diff = delta - position_float;
|
3166
|
3172
|
const feedRate_t feedrate = diff.magnitude() * duration_recip;
|
3167
|
3173
|
#else
|
3168
|
3174
|
const feedRate_t feedrate = fr_mm_s;
|
3169
|
3175
|
#endif
|
3170
|
3176
|
TERN_(HAS_EXTRUDERS, delta.e = machine.e);
|
3171
|
|
- if (buffer_segment(delta OPTARG(HAS_DIST_MM_ARG, cart_dist_mm), feedrate, extruder, mm)) {
|
|
3177
|
+ if (buffer_segment(delta OPTARG(HAS_DIST_MM_ARG, cart_dist_mm), feedrate, extruder, ph)) {
|
3172
|
3178
|
position_cart = cart;
|
3173
|
3179
|
return true;
|
3174
|
3180
|
}
|
3175
|
3181
|
return false;
|
3176
|
3182
|
#else
|
3177
|
|
- return buffer_segment(machine, fr_mm_s, extruder, millimeters);
|
|
3183
|
+ return buffer_segment(machine, fr_mm_s, extruder, hints);
|
3178
|
3184
|
#endif
|
3179
|
3185
|
} // buffer_line()
|
3180
|
3186
|
|