mirror of
https://github.com/MarlinFirmware/Marlin.git
synced 2025-07-07 06:57:27 -06:00
⚡️ Optimize Smooth Linear Advance (via fixed-point) (#27818)
This commit is contained in:
parent
4de6d655ac
commit
12fdde24d8
16 changed files with 265 additions and 201 deletions
|
@ -2366,11 +2366,11 @@
|
||||||
* Higher k and higher XY acceleration may require larger ADVANCE_TAU to avoid skipping steps.
|
* Higher k and higher XY acceleration may require larger ADVANCE_TAU to avoid skipping steps.
|
||||||
*/
|
*/
|
||||||
#if ENABLED(DISTINCT_E_FACTORS)
|
#if ENABLED(DISTINCT_E_FACTORS)
|
||||||
#define ADVANCE_TAU { 0.01 } // (s) Smoothing time to reduce extruder acceleration, per extruder
|
#define ADVANCE_TAU { 0.02 } // (s) Smoothing time to reduce extruder acceleration, per extruder
|
||||||
#else
|
#else
|
||||||
#define ADVANCE_TAU 0.01 // (s) Smoothing time to reduce extruder acceleration
|
#define ADVANCE_TAU 0.02 // (s) Smoothing time to reduce extruder acceleration
|
||||||
#endif
|
#endif
|
||||||
#define SMOOTH_LIN_ADV_HZ 5000 // (Hz) How often to update extruder speed
|
#define SMOOTH_LIN_ADV_HZ 1000 // (Hz) How often to update extruder speed
|
||||||
#define INPUT_SHAPING_E_SYNC // Synchronize the extruder-shaped XY axes (to increase precision)
|
#define INPUT_SHAPING_E_SYNC // Synchronize the extruder-shaped XY axes (to increase precision)
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
#include "../../../module/stepper.h"
|
#include "../../../module/stepper.h"
|
||||||
|
|
||||||
#if ENABLED(ADVANCE_K_EXTRA)
|
#if ENABLED(ADVANCE_K_EXTRA)
|
||||||
float other_extruder_advance_K[DISTINCT_E];
|
float other_extruder_advance_K[EXTRUDERS];
|
||||||
uint8_t lin_adv_slot = 0;
|
uint8_t lin_adv_slot = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -62,17 +62,17 @@ void GcodeSuite::M900() {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
float &kref = planner.extruder_advance_K[E_INDEX_N(tool_index)], newK = kref;
|
const float oldK = planner.get_advance_k(tool_index);
|
||||||
const float oldK = newK;
|
float newK = oldK;
|
||||||
|
|
||||||
#if ENABLED(SMOOTH_LIN_ADVANCE)
|
#if ENABLED(SMOOTH_LIN_ADVANCE)
|
||||||
const float oldU = stepper.get_advance_tau(E_INDEX_N(tool_index));
|
const float oldU = stepper.get_advance_tau(tool_index);
|
||||||
float newU = oldU;
|
float newU = oldU;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if ENABLED(ADVANCE_K_EXTRA)
|
#if ENABLED(ADVANCE_K_EXTRA)
|
||||||
|
|
||||||
float &lref = other_extruder_advance_K[E_INDEX_N(tool_index)];
|
float &lref = other_extruder_advance_K[tool_index];
|
||||||
|
|
||||||
const bool old_slot = TEST(lin_adv_slot, tool_index), // Each tool uses 1 bit to store its current slot (0 or 1)
|
const bool old_slot = TEST(lin_adv_slot, tool_index), // Each tool uses 1 bit to store its current slot (0 or 1)
|
||||||
new_slot = parser.boolval('S', old_slot); // The new slot (0 or 1) to set for the tool (default = no change)
|
new_slot = parser.boolval('S', old_slot); // The new slot (0 or 1) to set for the tool (default = no change)
|
||||||
|
@ -125,9 +125,9 @@ void GcodeSuite::M900() {
|
||||||
|
|
||||||
if (newK != oldK || TERN0(SMOOTH_LIN_ADVANCE, newU != oldU)) {
|
if (newK != oldK || TERN0(SMOOTH_LIN_ADVANCE, newU != oldU)) {
|
||||||
planner.synchronize();
|
planner.synchronize();
|
||||||
if (newK != oldK) kref = newK;
|
if (newK != oldK) planner.set_advance_k(newK, tool_index);
|
||||||
#if ENABLED(SMOOTH_LIN_ADVANCE)
|
#if ENABLED(SMOOTH_LIN_ADVANCE)
|
||||||
if (newU != oldU) stepper.set_advance_tau(newU);
|
if (newU != oldU) stepper.set_advance_tau(newU, tool_index);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,11 +136,11 @@ void GcodeSuite::M900() {
|
||||||
#if ENABLED(ADVANCE_K_EXTRA)
|
#if ENABLED(ADVANCE_K_EXTRA)
|
||||||
|
|
||||||
#if DISABLED(DISTINCT_E_FACTORS)
|
#if DISABLED(DISTINCT_E_FACTORS)
|
||||||
SERIAL_ECHOLNPGM("Advance S", new_slot, " K", kref, "(S", !new_slot, " K", lref, ")");
|
SERIAL_ECHOLNPGM("Advance S", new_slot, " K", newK, "(S", !new_slot, " K", lref, ")");
|
||||||
#else
|
#else
|
||||||
EXTRUDER_LOOP() {
|
EXTRUDER_LOOP() {
|
||||||
const bool slot = TEST(lin_adv_slot, e);
|
const bool slot = TEST(lin_adv_slot, e);
|
||||||
SERIAL_ECHOLNPGM("Advance T", e, " S", slot, " K", planner.extruder_advance_K[e],
|
SERIAL_ECHOLNPGM("Advance T", e, " S", slot, " K", planner.get_advance_k(e),
|
||||||
"(S", !slot, " K", other_extruder_advance_K[e], ")");
|
"(S", !slot, " K", other_extruder_advance_K[e], ")");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -149,14 +149,14 @@ void GcodeSuite::M900() {
|
||||||
|
|
||||||
SERIAL_ECHO_START();
|
SERIAL_ECHO_START();
|
||||||
#if DISABLED(DISTINCT_E_FACTORS)
|
#if DISABLED(DISTINCT_E_FACTORS)
|
||||||
SERIAL_ECHOPGM("Advance K=", planner.extruder_advance_K[0]);
|
SERIAL_ECHOPGM("Advance K=", planner.get_advance_k());
|
||||||
#if ENABLED(SMOOTH_LIN_ADVANCE)
|
#if ENABLED(SMOOTH_LIN_ADVANCE)
|
||||||
SERIAL_ECHOPGM(" TAU=", stepper.get_advance_tau());
|
SERIAL_ECHOPGM(" TAU=", stepper.get_advance_tau());
|
||||||
#endif
|
#endif
|
||||||
SERIAL_EOL();
|
SERIAL_EOL();
|
||||||
#else
|
#else
|
||||||
SERIAL_ECHOPGM("Advance K");
|
SERIAL_ECHOPGM("Advance K");
|
||||||
EXTRUDER_LOOP() SERIAL_ECHO(C(' '), C('0' + e), C(':'), planner.extruder_advance_K[e]);
|
EXTRUDER_LOOP() SERIAL_ECHO(C(' '), C('0' + e), C(':'), planner.get_advance_k(e));
|
||||||
SERIAL_EOL();
|
SERIAL_EOL();
|
||||||
#if ENABLED(SMOOTH_LIN_ADVANCE)
|
#if ENABLED(SMOOTH_LIN_ADVANCE)
|
||||||
SERIAL_ECHOPGM("Advance TAU");
|
SERIAL_ECHOPGM("Advance TAU");
|
||||||
|
@ -174,23 +174,21 @@ void GcodeSuite::M900_report(const bool forReplay/*=true*/) {
|
||||||
TERN_(MARLIN_SMALL_BUILD, return);
|
TERN_(MARLIN_SMALL_BUILD, return);
|
||||||
|
|
||||||
report_heading(forReplay, F(STR_LINEAR_ADVANCE));
|
report_heading(forReplay, F(STR_LINEAR_ADVANCE));
|
||||||
#if DISABLED(DISTINCT_E_FACTORS)
|
DISTINCT_E_LOOP() {
|
||||||
report_echo_start(forReplay);
|
report_echo_start(forReplay);
|
||||||
SERIAL_ECHOPGM(" M900 K", planner.extruder_advance_K[0]);
|
SERIAL_ECHOPGM(
|
||||||
#if ENABLED(SMOOTH_LIN_ADVANCE)
|
#if ENABLED(DISTINCT_E_FACTORS)
|
||||||
SERIAL_ECHOPGM(" M900 U", stepper.get_advance_tau());
|
" M900 T", e, " K"
|
||||||
#endif
|
|
||||||
SERIAL_EOL();
|
|
||||||
#else
|
#else
|
||||||
EXTRUDER_LOOP() {
|
" M900 K"
|
||||||
report_echo_start(forReplay);
|
#endif
|
||||||
SERIAL_ECHOPGM(" M900 T", e, " K", planner.extruder_advance_K[e]);
|
);
|
||||||
|
SERIAL_ECHO(planner.get_advance_k(e));
|
||||||
#if ENABLED(SMOOTH_LIN_ADVANCE)
|
#if ENABLED(SMOOTH_LIN_ADVANCE)
|
||||||
SERIAL_ECHOPGM(" U", stepper.get_advance_tau(e));
|
SERIAL_ECHOPGM(" U", stepper.get_advance_tau(e));
|
||||||
#endif
|
#endif
|
||||||
SERIAL_EOL();
|
SERIAL_EOL();
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // LIN_ADVANCE
|
#endif // LIN_ADVANCE
|
||||||
|
|
|
@ -3725,7 +3725,7 @@ static_assert(NUM_SERVOS <= NUM_SERVO_PLUGS, "NUM_SERVOS (or some servo index) i
|
||||||
* Check per-axis initializers for errors
|
* Check per-axis initializers for errors
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define __PLUS_TEST(I,A) && (sanity_arr_##A[_MIN(I,signed(COUNT(sanity_arr_##A)-1))] > 0)
|
#define __PLUS_TEST(I,A) && (sanity_arr_##A[ALIM(I,sanity_arr_##A)] > 0)
|
||||||
#define _PLUS_TEST(A) (1 REPEAT2(14,__PLUS_TEST,A))
|
#define _PLUS_TEST(A) (1 REPEAT2(14,__PLUS_TEST,A))
|
||||||
#if HAS_MULTI_EXTRUDER
|
#if HAS_MULTI_EXTRUDER
|
||||||
#define _EXTRA_NOTE " (Did you forget to enable DISTINCT_E_FACTORS?)"
|
#define _EXTRA_NOTE " (Did you forget to enable DISTINCT_E_FACTORS?)"
|
||||||
|
|
|
@ -2398,10 +2398,13 @@ void JyersDWIN::menuItemHandler(const uint8_t menu, const uint8_t item, bool dra
|
||||||
case MOTION_LA:
|
case MOTION_LA:
|
||||||
if (draw) {
|
if (draw) {
|
||||||
drawMenuItem(row, ICON_MaxAccelerated, GET_TEXT_F(MSG_ADVANCE_K));
|
drawMenuItem(row, ICON_MaxAccelerated, GET_TEXT_F(MSG_ADVANCE_K));
|
||||||
drawFloat(planner.extruder_advance_K[0], row, false, 100);
|
drawFloat(planner.get_advance_k(), row, false, 100);
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
modifyValue(planner.extruder_advance_K[0], 0, 10, 100);
|
static float k = planner.get_advance_k();
|
||||||
|
modifyValue(k, 0, 10, 100, []{ planner.set_advance_k(k); });
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -2914,10 +2917,12 @@ void JyersDWIN::menuItemHandler(const uint8_t menu, const uint8_t item, bool dra
|
||||||
case ADVANCED_LA:
|
case ADVANCED_LA:
|
||||||
if (draw) {
|
if (draw) {
|
||||||
drawMenuItem(row, ICON_MaxAccelerated, GET_TEXT_F(MSG_ADVANCE_K));
|
drawMenuItem(row, ICON_MaxAccelerated, GET_TEXT_F(MSG_ADVANCE_K));
|
||||||
drawFloat(planner.extruder_advance_K[0], row, false, 100);
|
drawFloat(planner.get_advance_k(), row, false, 100);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
static float k = planner.get_advance_k();
|
||||||
|
modifyValue(k, 0, 10, 100, []{ planner.set_advance_k(k); });
|
||||||
}
|
}
|
||||||
else
|
|
||||||
modifyValue(planner.extruder_advance_K[0], 0, 10, 100);
|
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -3925,10 +3930,12 @@ void JyersDWIN::menuItemHandler(const uint8_t menu, const uint8_t item, bool dra
|
||||||
case TUNE_LA:
|
case TUNE_LA:
|
||||||
if (draw) {
|
if (draw) {
|
||||||
drawMenuItem(row, ICON_MaxAccelerated, GET_TEXT_F(MSG_ADVANCE_K));
|
drawMenuItem(row, ICON_MaxAccelerated, GET_TEXT_F(MSG_ADVANCE_K));
|
||||||
drawFloat(planner.extruder_advance_K[0], row, false, 100);
|
drawFloat(planner.get_advance_k(), row, false, 100);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
static float k = planner.get_advance_k();
|
||||||
|
modifyValue(k, 0, 10, 100, []{ planner.set_advance_k(k); });
|
||||||
}
|
}
|
||||||
else
|
|
||||||
modifyValue(planner.extruder_advance_K[0], 0, 10, 100);
|
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -2686,7 +2686,8 @@ void applyMaxAccel() { planner.set_max_acceleration(hmiValue.axis, menuData.valu
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if ENABLED(LIN_ADVANCE)
|
#if ENABLED(LIN_ADVANCE)
|
||||||
void setLA_K() { setPFloatOnClick(0, 10, 3); }
|
void applyLA_K() { planner.set_advance_k(menuData.value / MINUNITMULT); }
|
||||||
|
void setLA_K() { setPFloatOnClick(0, 10, 3, applyLA_K); }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if HAS_X_AXIS
|
#if HAS_X_AXIS
|
||||||
|
@ -3545,7 +3546,7 @@ void drawTuneMenu() {
|
||||||
EDIT_ITEM(ICON_JDmm, MSG_JUNCTION_DEVIATION, onDrawPFloat3Menu, setJDmm, &planner.junction_deviation_mm);
|
EDIT_ITEM(ICON_JDmm, MSG_JUNCTION_DEVIATION, onDrawPFloat3Menu, setJDmm, &planner.junction_deviation_mm);
|
||||||
#endif
|
#endif
|
||||||
#if ENABLED(PROUI_ITEM_ADVK)
|
#if ENABLED(PROUI_ITEM_ADVK)
|
||||||
EDIT_ITEM(ICON_MaxAccelerated, MSG_ADVANCE_K, onDrawPFloat3Menu, setLA_K, &planner.extruder_advance_K[0]);
|
EDIT_ITEM(ICON_MaxAccelerated, MSG_ADVANCE_K, onDrawPFloat3Menu, setLA_K, &planner.get_advance_k());
|
||||||
#endif
|
#endif
|
||||||
#if HAS_LOCKSCREEN
|
#if HAS_LOCKSCREEN
|
||||||
MENU_ITEM(ICON_Lock, MSG_LOCKSCREEN, onDrawMenuItem, dwinLockScreen);
|
MENU_ITEM(ICON_Lock, MSG_LOCKSCREEN, onDrawMenuItem, dwinLockScreen);
|
||||||
|
@ -3683,7 +3684,7 @@ void drawMotionMenu() {
|
||||||
MENU_ITEM(ICON_Homing, MSG_HOMING_FEEDRATE, onDrawSubMenu, drawHomingFRMenu);
|
MENU_ITEM(ICON_Homing, MSG_HOMING_FEEDRATE, onDrawSubMenu, drawHomingFRMenu);
|
||||||
#endif
|
#endif
|
||||||
#if ENABLED(LIN_ADVANCE)
|
#if ENABLED(LIN_ADVANCE)
|
||||||
EDIT_ITEM(ICON_MaxAccelerated, MSG_ADVANCE_K, onDrawPFloat3Menu, setLA_K, &planner.extruder_advance_K[0]);
|
EDIT_ITEM(ICON_MaxAccelerated, MSG_ADVANCE_K, onDrawPFloat3Menu, setLA_K, &planner.get_advance_k());
|
||||||
#endif
|
#endif
|
||||||
#if ENABLED(SHAPING_MENU)
|
#if ENABLED(SHAPING_MENU)
|
||||||
MENU_ITEM(ICON_InputShaping, MSG_INPUT_SHAPING, onDrawSubMenu, drawInputShaping_menu);
|
MENU_ITEM(ICON_InputShaping, MSG_INPUT_SHAPING, onDrawSubMenu, drawInputShaping_menu);
|
||||||
|
|
|
@ -643,12 +643,12 @@ namespace ExtUI {
|
||||||
|
|
||||||
#if ENABLED(LIN_ADVANCE)
|
#if ENABLED(LIN_ADVANCE)
|
||||||
float getLinearAdvance_mm_mm_s(const extruder_t extruder) {
|
float getLinearAdvance_mm_mm_s(const extruder_t extruder) {
|
||||||
return (extruder < EXTRUDERS) ? planner.extruder_advance_K[E_INDEX_N(extruder - E0)] : 0;
|
return (extruder < EXTRUDERS) ? planner.get_advance_k(E_INDEX_N(extruder - E0)) : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setLinearAdvance_mm_mm_s(const_float_t value, const extruder_t extruder) {
|
void setLinearAdvance_mm_mm_s(const_float_t value, const extruder_t extruder) {
|
||||||
if (extruder < EXTRUDERS)
|
if (extruder < EXTRUDERS)
|
||||||
planner.extruder_advance_K[E_INDEX_N(extruder - E0)] = constrain(value, 0, 10);
|
planner.set_advance_k(constrain(value, 0, 10), E_INDEX_N(extruder - E0));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -117,10 +117,13 @@ void menu_backlash();
|
||||||
|
|
||||||
#if ENABLED(LIN_ADVANCE)
|
#if ENABLED(LIN_ADVANCE)
|
||||||
#if DISABLED(DISTINCT_E_FACTORS)
|
#if DISABLED(DISTINCT_E_FACTORS)
|
||||||
EDIT_ITEM(float42_52, MSG_ADVANCE_K, &planner.extruder_advance_K[0], 0, 10);
|
editable.decimal = planner.get_advance_k();
|
||||||
|
EDIT_ITEM(float42_52, MSG_ADVANCE_K, &editable.decimal, 0.0f, 10.0f, []{ planner.set_advance_k(editable.decimal); });
|
||||||
#else
|
#else
|
||||||
EXTRUDER_LOOP()
|
EXTRUDER_LOOP() {
|
||||||
EDIT_ITEM_N(float42_52, e, MSG_ADVANCE_K_E, &planner.extruder_advance_K[e], 0, 10);
|
editable.decimal = planner.get_advance_k(e);
|
||||||
|
EDIT_ITEM_N(float42_52, e, MSG_ADVANCE_K_E, &editable.decimal, 0.0f, 10.0f, []{ planner.set_advance_k(editable.decimal, MenuItemBase::itemIndex); });
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
#if ENABLED(SMOOTH_LIN_ADVANCE)
|
#if ENABLED(SMOOTH_LIN_ADVANCE)
|
||||||
#if DISABLED(DISTINCT_E_FACTORS)
|
#if DISABLED(DISTINCT_E_FACTORS)
|
||||||
|
@ -745,15 +748,19 @@ void menu_advanced_settings() {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if HAS_ADV_FILAMENT_MENU
|
#if HAS_ADV_FILAMENT_MENU
|
||||||
SUBMENU(MSG_FILAMENT, menu_advanced_filament);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if ENABLED(LIN_ADVANCE) && DISABLED(HAS_ADV_FILAMENT_MENU)
|
SUBMENU(MSG_FILAMENT, menu_advanced_filament);
|
||||||
|
|
||||||
|
#elif ENABLED(LIN_ADVANCE)
|
||||||
|
|
||||||
#if DISABLED(DISTINCT_E_FACTORS)
|
#if DISABLED(DISTINCT_E_FACTORS)
|
||||||
EDIT_ITEM(float42_52, MSG_ADVANCE_K, &planner.extruder_advance_K[0], 0, 10);
|
editable.decimal = planner.get_advance_k();
|
||||||
|
EDIT_ITEM(float42_52, MSG_ADVANCE_K, &editable.decimal, 0.0f, 10.0f, []{ planner.set_advance_k(editable.decimal); });
|
||||||
#else
|
#else
|
||||||
EXTRUDER_LOOP()
|
EXTRUDER_LOOP() {
|
||||||
EDIT_ITEM_N(float42_52, e, MSG_ADVANCE_K_E, &planner.extruder_advance_K[e], 0, 10);
|
editable.decimal = planner.get_advance_k(e);
|
||||||
|
EDIT_ITEM_N(float42_52, e, MSG_ADVANCE_K_E, &editable.decimal, 0.0f, 10.0f, []{ planner.set_advance_k(editable.decimal, MenuItemBase::itemIndex); });
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
#if ENABLED(SMOOTH_LIN_ADVANCE)
|
#if ENABLED(SMOOTH_LIN_ADVANCE)
|
||||||
#if DISABLED(DISTINCT_E_FACTORS)
|
#if DISABLED(DISTINCT_E_FACTORS)
|
||||||
|
@ -766,7 +773,8 @@ void menu_advanced_settings() {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#endif
|
|
||||||
|
#endif // LIN_ADVANCE && !HAS_ADV_FILAMENT_MENU
|
||||||
|
|
||||||
// M540 S - Abort on endstop hit when SD printing
|
// M540 S - Abort on endstop hit when SD printing
|
||||||
#if ENABLED(SD_ABORT_ON_ENDSTOP_HIT)
|
#if ENABLED(SD_ABORT_ON_ENDSTOP_HIT)
|
||||||
|
|
|
@ -216,10 +216,13 @@ void menu_tune() {
|
||||||
//
|
//
|
||||||
#if ENABLED(LIN_ADVANCE) && DISABLED(SLIM_LCD_MENUS)
|
#if ENABLED(LIN_ADVANCE) && DISABLED(SLIM_LCD_MENUS)
|
||||||
#if DISABLED(DISTINCT_E_FACTORS)
|
#if DISABLED(DISTINCT_E_FACTORS)
|
||||||
EDIT_ITEM(float42_52, MSG_ADVANCE_K, &planner.extruder_advance_K[0], 0, 10);
|
editable.decimal = planner.get_advance_k();
|
||||||
|
EDIT_ITEM(float42_52, MSG_ADVANCE_K, &editable.decimal, 0.0f, 10.0f, []{ planner.set_advance_k(editable.decimal); });
|
||||||
#else
|
#else
|
||||||
EXTRUDER_LOOP()
|
EXTRUDER_LOOP() {
|
||||||
EDIT_ITEM_N(float42_52, e, MSG_ADVANCE_K_E, &planner.extruder_advance_K[e], 0, 10);
|
editable.decimal = planner.get_advance_k(e);
|
||||||
|
EDIT_ITEM_N(float42_52, e, MSG_ADVANCE_K_E, &editable.decimal, 0.0f, 10.0f, []{ planner.set_advance_k(editable.decimal, MenuItemBase::itemIndex); });
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
#if ENABLED(SMOOTH_LIN_ADVANCE)
|
#if ENABLED(SMOOTH_LIN_ADVANCE)
|
||||||
#if DISABLED(DISTINCT_E_FACTORS)
|
#if DISABLED(DISTINCT_E_FACTORS)
|
||||||
|
|
|
@ -894,7 +894,7 @@ void RTS::handleData() {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 4: // Go to Advanced Settings
|
case 4: // Go to Advanced Settings
|
||||||
TERN_(LIN_ADVANCE, sendData(planner.extruder_advance_K[0] * 100, Advance_K_VP));
|
TERN_(LIN_ADVANCE, sendData(planner.get_advance_k() * 100, Advance_K_VP));
|
||||||
gotoPage(ID_AdvWarn_L, ID_AdvWarn_D);
|
gotoPage(ID_AdvWarn_L, ID_AdvWarn_D);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -1292,7 +1292,7 @@ void RTS::handleData() {
|
||||||
|
|
||||||
#if ENABLED(LIN_ADVANCE)
|
#if ENABLED(LIN_ADVANCE)
|
||||||
case 7: // Confirm
|
case 7: // Confirm
|
||||||
sendData(planner.extruder_advance_K[0] * 100, Advance_K_VP);
|
sendData(planner.get_advance_k() * 100, Advance_K_VP);
|
||||||
gotoPage(ID_Advanced_L, ID_Advanced_D);
|
gotoPage(ID_Advanced_L, ID_Advanced_D);
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
@ -1350,7 +1350,7 @@ void RTS::handleData() {
|
||||||
#endif
|
#endif
|
||||||
case A_Retract: planner.settings.retract_acceleration = recdat.data[0]; break;
|
case A_Retract: planner.settings.retract_acceleration = recdat.data[0]; break;
|
||||||
#if ENABLED(LIN_ADVANCE)
|
#if ENABLED(LIN_ADVANCE)
|
||||||
case Advance_K: planner.extruder_advance_K[0] = float(recdat.data[0]) / 100.0f; break;
|
case Advance_K: planner.set_advance_k(float(recdat.data[0]) / 100.0f); break;
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
case Accel: planner.settings.acceleration = recdat.data[0]; break;
|
case Accel: planner.settings.acceleration = recdat.data[0]; break;
|
||||||
|
|
|
@ -181,44 +181,51 @@ void Touch::touch(touch_control_t *control) {
|
||||||
case SLIDER: hold(control); ui.encoderPosition = (x - control->x) * control->data / control->width; break;
|
case SLIDER: hold(control); ui.encoderPosition = (x - control->x) * control->data / control->width; break;
|
||||||
case INCREASE: hold(control, repeat_delay - 5); TERN(AUTO_BED_LEVELING_UBL, ui.external_control ? bedlevel.encoder_diff++ : ui.encoderPosition++, ui.encoderPosition++); break;
|
case INCREASE: hold(control, repeat_delay - 5); TERN(AUTO_BED_LEVELING_UBL, ui.external_control ? bedlevel.encoder_diff++ : ui.encoderPosition++, ui.encoderPosition++); break;
|
||||||
case DECREASE: hold(control, repeat_delay - 5); TERN(AUTO_BED_LEVELING_UBL, ui.external_control ? bedlevel.encoder_diff-- : ui.encoderPosition--, ui.encoderPosition--); break;
|
case DECREASE: hold(control, repeat_delay - 5); TERN(AUTO_BED_LEVELING_UBL, ui.external_control ? bedlevel.encoder_diff-- : ui.encoderPosition--, ui.encoderPosition--); break;
|
||||||
case HEATER:
|
case HEATER: {
|
||||||
int8_t heater;
|
|
||||||
heater = control->data;
|
|
||||||
ui.clear_for_drawing();
|
ui.clear_for_drawing();
|
||||||
|
const int8_t heater = control->data;
|
||||||
|
switch (heater) {
|
||||||
|
default: // Hotend
|
||||||
#if HAS_HOTEND
|
#if HAS_HOTEND
|
||||||
if (heater >= 0) { // HotEnd
|
#define HOTEND_HEATER(N) TERN0(HAS_MULTI_HOTEND, N)
|
||||||
#if HOTENDS == 1
|
TERN_(HAS_MULTI_HOTEND, MenuItemBase::itemIndex = heater);
|
||||||
MenuItem_int3::action(GET_TEXT_F(MSG_NOZZLE), &thermalManager.temp_hotend[0].target, 0, thermalManager.hotend_max_target(0), []{ thermalManager.start_watching_hotend(0); });
|
MenuItem_int3::action(GET_TEXT_F(TERN(HAS_MULTI_HOTEND, MSG_NOZZLE_N, MSG_NOZZLE)),
|
||||||
#else
|
&thermalManager.temp_hotend[HOTEND_HEATER(heater)].target, 0, thermalManager.hotend_max_target(HOTEND_HEATER(heater)),
|
||||||
MenuItemBase::itemIndex = heater;
|
[]{ thermalManager.start_watching_hotend(HOTEND_HEATER(MenuItemBase::itemIndex)); }
|
||||||
MenuItem_int3::action(GET_TEXT_F(MSG_NOZZLE_N), &thermalManager.temp_hotend[heater].target, 0, thermalManager.hotend_max_target(heater), []{ thermalManager.start_watching_hotend(MenuItemBase::itemIndex); });
|
);
|
||||||
#endif
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
break;
|
||||||
|
|
||||||
#if HAS_HEATED_BED
|
#if HAS_HEATED_BED
|
||||||
else if (heater == H_BED) {
|
case H_BED:
|
||||||
MenuItem_int3::action(GET_TEXT_F(MSG_BED), &thermalManager.temp_bed.target, 0, BED_MAX_TARGET, thermalManager.start_watching_bed);
|
MenuItem_int3::action(GET_TEXT_F(MSG_BED), &thermalManager.temp_bed.target, 0, BED_MAX_TARGET, thermalManager.start_watching_bed);
|
||||||
}
|
break;
|
||||||
#endif
|
|
||||||
#if HAS_HEATED_CHAMBER
|
|
||||||
else if (heater == H_CHAMBER) {
|
|
||||||
MenuItem_int3::action(GET_TEXT_F(MSG_CHAMBER), &thermalManager.temp_chamber.target, 0, CHAMBER_MAX_TARGET, thermalManager.start_watching_chamber);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#if HAS_COOLER
|
|
||||||
else if (heater == H_COOLER) {
|
|
||||||
MenuItem_int3::action(GET_TEXT_F(MSG_COOLER), &thermalManager.temp_cooler.target, 0, COOLER_MAX_TARGET, thermalManager.start_watching_cooler);
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if HAS_HEATED_CHAMBER
|
||||||
|
case H_CHAMBER:
|
||||||
|
MenuItem_int3::action(GET_TEXT_F(MSG_CHAMBER), &thermalManager.temp_chamber.target, 0, CHAMBER_MAX_TARGET, thermalManager.start_watching_chamber);
|
||||||
break;
|
break;
|
||||||
case FAN:
|
#endif
|
||||||
|
|
||||||
|
#if HAS_COOLER
|
||||||
|
case H_COOLER:
|
||||||
|
MenuItem_int3::action(GET_TEXT_F(MSG_COOLER), &thermalManager.temp_cooler.target, 0, COOLER_MAX_TARGET, thermalManager.start_watching_cooler);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // switch
|
||||||
|
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case FAN: {
|
||||||
ui.clear_for_drawing();
|
ui.clear_for_drawing();
|
||||||
static uint8_t fan, fan_speed;
|
static uint8_t fan, fan_speed;
|
||||||
fan = 0;
|
fan = 0;
|
||||||
fan_speed = thermalManager.fan_speed[fan];
|
fan_speed = thermalManager.fan_speed[fan];
|
||||||
MenuItem_percent::action(GET_TEXT_F(MSG_FIRST_FAN_SPEED), &fan_speed, 0, 255, []{ thermalManager.set_fan_speed(fan, fan_speed); TERN_(LASER_SYNCHRONOUS_M106_M107, planner.buffer_sync_block(BLOCK_BIT_SYNC_FANS));});
|
MenuItem_percent::action(GET_TEXT_F(MSG_FIRST_FAN_SPEED), &fan_speed, 0, 255, []{ thermalManager.set_fan_speed(fan, fan_speed); TERN_(LASER_SYNCHRONOUS_M106_M107, planner.buffer_sync_block(BLOCK_BIT_SYNC_FANS));});
|
||||||
break;
|
} break;
|
||||||
|
|
||||||
case FEEDRATE:
|
case FEEDRATE:
|
||||||
ui.clear_for_drawing();
|
ui.clear_for_drawing();
|
||||||
MenuItem_int3::action(GET_TEXT_F(MSG_SPEED), &feedrate_percentage, SPEED_EDIT_MIN, SPEED_EDIT_MAX);
|
MenuItem_int3::action(GET_TEXT_F(MSG_SPEED), &feedrate_percentage, SPEED_EDIT_MIN, SPEED_EDIT_MAX);
|
||||||
|
@ -228,11 +235,10 @@ void Touch::touch(touch_control_t *control) {
|
||||||
case FLOWRATE:
|
case FLOWRATE:
|
||||||
ui.clear_for_drawing();
|
ui.clear_for_drawing();
|
||||||
MenuItemBase::itemIndex = control->data;
|
MenuItemBase::itemIndex = control->data;
|
||||||
#if EXTRUDERS == 1
|
MenuItem_int3::action(GET_TEXT_F(TERN(HAS_MULTI_EXTRUDER, MSG_FLOW_N, MSG_FLOW)),
|
||||||
MenuItem_int3::action(GET_TEXT_F(MSG_FLOW), &planner.flow_percentage[MenuItemBase::itemIndex], FLOW_EDIT_MIN, FLOW_EDIT_MAX, []{ planner.refresh_e_factor(MenuItemBase::itemIndex); });
|
&planner.flow_percentage[MenuItemBase::itemIndex], FLOW_EDIT_MIN, FLOW_EDIT_MAX,
|
||||||
#else
|
[]{ planner.refresh_e_factor(MenuItemBase::itemIndex); }
|
||||||
MenuItem_int3::action(GET_TEXT_F(MSG_FLOW_N), &planner.flow_percentage[MenuItemBase::itemIndex], FLOW_EDIT_MIN, FLOW_EDIT_MAX, []{ planner.refresh_e_factor(MenuItemBase::itemIndex); });
|
);
|
||||||
#endif
|
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -236,6 +236,9 @@ float Planner::previous_nominal_speed;
|
||||||
|
|
||||||
#if ENABLED(LIN_ADVANCE)
|
#if ENABLED(LIN_ADVANCE)
|
||||||
float Planner::extruder_advance_K[DISTINCT_E]; // Initialized by settings.load
|
float Planner::extruder_advance_K[DISTINCT_E]; // Initialized by settings.load
|
||||||
|
#if ENABLED(SMOOTH_LIN_ADVANCE)
|
||||||
|
uint32_t Planner::extruder_advance_K_q27[DISTINCT_E];
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if HAS_POSITION_FLOAT
|
#if HAS_POSITION_FLOAT
|
||||||
|
@ -2457,7 +2460,7 @@ bool Planner::_populate_block(
|
||||||
block->acceleration_steps_per_s2 = accel;
|
block->acceleration_steps_per_s2 = accel;
|
||||||
block->acceleration = accel / steps_per_mm;
|
block->acceleration = accel / steps_per_mm;
|
||||||
#if DISABLED(S_CURVE_ACCELERATION)
|
#if DISABLED(S_CURVE_ACCELERATION)
|
||||||
block->acceleration_rate = uint32_t(accel * (float(1UL << 24) / (STEPPER_TIMER_RATE)));
|
block->acceleration_rate = uint32_t(accel * (float(_BV32(24)) / (STEPPER_TIMER_RATE)));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if HAS_ROUGH_LIN_ADVANCE
|
#if HAS_ROUGH_LIN_ADVANCE
|
||||||
|
@ -2478,7 +2481,13 @@ bool Planner::_populate_block(
|
||||||
}
|
}
|
||||||
#elif ENABLED(SMOOTH_LIN_ADVANCE)
|
#elif ENABLED(SMOOTH_LIN_ADVANCE)
|
||||||
block->use_advance_lead = use_advance_lead;
|
block->use_advance_lead = use_advance_lead;
|
||||||
block->e_step_ratio = (block->direction_bits.e ? 1 : -1) * float(block->steps.e) / block->step_event_count;
|
const uint32_t ratio = (uint64_t(block->steps.e) * _BV32(30)) / block->step_event_count;
|
||||||
|
block->e_step_ratio_q30 = block->direction_bits.e ? ratio : -ratio;
|
||||||
|
|
||||||
|
#if ENABLED(INPUT_SHAPING_E_SYNC)
|
||||||
|
const uint32_t xy_steps = TERN0(INPUT_SHAPING_X, block->steps.x) + TERN0(INPUT_SHAPING_Y, block->steps.y);
|
||||||
|
block->xy_length_inv_q30 = xy_steps ? (_BV32(30) / xy_steps) : 0;
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Formula for the average speed over a 1 step worth of distance if starting from zero and
|
// Formula for the average speed over a 1 step worth of distance if starting from zero and
|
||||||
|
|
|
@ -247,7 +247,10 @@ typedef struct PlannerBlock {
|
||||||
|
|
||||||
#if ENABLED(SMOOTH_LIN_ADVANCE)
|
#if ENABLED(SMOOTH_LIN_ADVANCE)
|
||||||
uint32_t cruise_time; // Cruise time in STEP timer counts
|
uint32_t cruise_time; // Cruise time in STEP timer counts
|
||||||
float e_step_ratio;
|
int32_t e_step_ratio_q30; // Ratio of e steps to block steps.
|
||||||
|
#if ENABLED(INPUT_SHAPING_E_SYNC)
|
||||||
|
uint32_t xy_length_inv_q30; // inverse of block->steps.x + block.steps.y
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#if ANY(S_CURVE_ACCELERATION, SMOOTH_LIN_ADVANCE)
|
#if ANY(S_CURVE_ACCELERATION, SMOOTH_LIN_ADVANCE)
|
||||||
uint32_t cruise_rate, // The actual cruise rate to use, between end of the acceleration phase and start of deceleration phase
|
uint32_t cruise_rate, // The actual cruise rate to use, between end of the acceleration phase and start of deceleration phase
|
||||||
|
@ -359,9 +362,8 @@ typedef struct PlannerSettings {
|
||||||
#if ENABLED(EDITABLE_STEPS_PER_UNIT)
|
#if ENABLED(EDITABLE_STEPS_PER_UNIT)
|
||||||
float axis_steps_per_mm[DISTINCT_AXES];
|
float axis_steps_per_mm[DISTINCT_AXES];
|
||||||
#else
|
#else
|
||||||
#define _DLIM(I) ALIM(I, _dasu)
|
#define _DASU(N) _dasu[ALIM(N, _dasu)],
|
||||||
#define _DASU(N) _dasu[_DLIM(N)],
|
#define _EASU(N) _dasu[ALIM(E_AXIS + N, _dasu)],
|
||||||
#define _EASU(N) _dasu[_DLIM(E_AXIS + N)],
|
|
||||||
static constexpr float axis_steps_per_mm[DISTINCT_AXES] = {
|
static constexpr float axis_steps_per_mm[DISTINCT_AXES] = {
|
||||||
REPEAT(NUM_AXES, _DASU)
|
REPEAT(NUM_AXES, _DASU)
|
||||||
TERN_(HAS_EXTRUDERS, REPEAT(DISTINCT_E, _EASU))
|
TERN_(HAS_EXTRUDERS, REPEAT(DISTINCT_E, _EASU))
|
||||||
|
@ -526,6 +528,23 @@ class Planner {
|
||||||
|
|
||||||
#if ENABLED(LIN_ADVANCE)
|
#if ENABLED(LIN_ADVANCE)
|
||||||
static float extruder_advance_K[DISTINCT_E];
|
static float extruder_advance_K[DISTINCT_E];
|
||||||
|
static void set_advance_k(const_float_t k, const uint8_t e=active_extruder) {
|
||||||
|
UNUSED(e);
|
||||||
|
extruder_advance_K[E_INDEX_N(e)] = k;
|
||||||
|
#if ENABLED(SMOOTH_LIN_ADVANCE)
|
||||||
|
extruder_advance_K_q27[E_INDEX_N(e)] = k * (1UL << 27);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
static float get_advance_k(const uint8_t e=active_extruder) {
|
||||||
|
UNUSED(e);
|
||||||
|
return extruder_advance_K[E_INDEX_N(e)];
|
||||||
|
}
|
||||||
|
#if ENABLED(SMOOTH_LIN_ADVANCE)
|
||||||
|
static uint32_t get_advance_k_q27(const uint8_t e=active_extruder) {
|
||||||
|
UNUSED(e);
|
||||||
|
return extruder_advance_K_q27[E_INDEX_N(e)];
|
||||||
|
}
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -602,6 +621,10 @@ class Planner {
|
||||||
volatile static uint32_t block_buffer_runtime_us; // Theoretical block buffer runtime in µs
|
volatile static uint32_t block_buffer_runtime_us; // Theoretical block buffer runtime in µs
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if ENABLED(SMOOTH_LIN_ADVANCE)
|
||||||
|
static uint32_t extruder_advance_K_q27[DISTINCT_E];
|
||||||
|
#endif
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -126,7 +126,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if ENABLED(ADVANCE_K_EXTRA)
|
#if ENABLED(ADVANCE_K_EXTRA)
|
||||||
extern float other_extruder_advance_K[DISTINCT_E];
|
extern float other_extruder_advance_K[EXTRUDERS];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if HAS_MULTI_EXTRUDER
|
#if HAS_MULTI_EXTRUDER
|
||||||
|
@ -2641,18 +2641,14 @@ void MarlinSettings::postprocess() {
|
||||||
_FIELD_TEST(planner_extruder_advance_K);
|
_FIELD_TEST(planner_extruder_advance_K);
|
||||||
EEPROM_READ(extruder_advance_K);
|
EEPROM_READ(extruder_advance_K);
|
||||||
if (!validating)
|
if (!validating)
|
||||||
COPY(planner.extruder_advance_K, extruder_advance_K);
|
DISTINCT_E_LOOP() planner.set_advance_k(extruder_advance_K[e], e);
|
||||||
|
|
||||||
#if ENABLED(SMOOTH_LIN_ADVANCE)
|
#if ENABLED(SMOOTH_LIN_ADVANCE)
|
||||||
_FIELD_TEST(stepper_extruder_advance_tau);
|
_FIELD_TEST(stepper_extruder_advance_tau);
|
||||||
float tau[DISTINCT_E];
|
float tau[DISTINCT_E];
|
||||||
EEPROM_READ(tau);
|
EEPROM_READ(tau);
|
||||||
if (!validating) {
|
if (!validating)
|
||||||
#if ENABLED(DISTINCT_E_FACTORS)
|
DISTINCT_E_LOOP() stepper.set_advance_tau(tau[e], e);
|
||||||
EXTRUDER_LOOP() stepper.set_advance_tau(tau[e], e);
|
|
||||||
#else
|
|
||||||
stepper.set_advance_tau(tau[0]);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -3615,21 +3611,23 @@ void MarlinSettings::reset() {
|
||||||
#if ENABLED(DISTINCT_E_FACTORS)
|
#if ENABLED(DISTINCT_E_FACTORS)
|
||||||
|
|
||||||
constexpr float linAdvanceK[] = ADVANCE_K;
|
constexpr float linAdvanceK[] = ADVANCE_K;
|
||||||
EXTRUDER_LOOP() {
|
|
||||||
const float a = linAdvanceK[ALIM(e, linAdvanceK)];
|
|
||||||
planner.extruder_advance_K[e] = a;
|
|
||||||
TERN_(ADVANCE_K_EXTRA, other_extruder_advance_K[e] = a);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
planner.extruder_advance_K[0] = ADVANCE_K;
|
|
||||||
#endif
|
|
||||||
#if ENABLED(SMOOTH_LIN_ADVANCE)
|
#if ENABLED(SMOOTH_LIN_ADVANCE)
|
||||||
#if ENABLED(DISTINCT_E_FACTORS)
|
|
||||||
constexpr float linAdvanceTau[] = ADVANCE_TAU;
|
constexpr float linAdvanceTau[] = ADVANCE_TAU;
|
||||||
EXTRUDER_LOOP()
|
#endif
|
||||||
stepper.set_advance_tau(linAdvanceTau[ALIM(e, linAdvanceTau)], e);
|
|
||||||
#else
|
EXTRUDER_LOOP() {
|
||||||
stepper.set_advance_tau(ADVANCE_TAU);
|
const float k = linAdvanceK[ALIM(e, linAdvanceK)];
|
||||||
|
planner.set_advance_k(k, e);
|
||||||
|
TERN_(SMOOTH_LIN_ADVANCE, stepper.set_advance_tau(linAdvanceTau[ALIM(e, linAdvanceTau)], e));
|
||||||
|
TERN_(ADVANCE_K_EXTRA, other_extruder_advance_K[e] = k);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else // !DISTINCT_E_FACTORS
|
||||||
|
|
||||||
|
planner.set_advance_k(ADVANCE_K);
|
||||||
|
TERN_(SMOOTH_LIN_ADVANCE, stepper.set_advance_tau(ADVANCE_TAU));
|
||||||
|
#if ENABLED(ADVANCE_K_EXTRA)
|
||||||
|
EXTRUDER_LOOP() other_extruder_advance_K[e] = ADVANCE_K;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1510,6 +1510,10 @@ HAL_STEP_TIMER_ISR() {
|
||||||
#define STEP_MULTIPLY(A,B) MultiU24X32toH16(A, B)
|
#define STEP_MULTIPLY(A,B) MultiU24X32toH16(A, B)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if ENABLED(SMOOTH_LIN_ADVANCE)
|
||||||
|
FORCE_INLINE static constexpr int32_t MULT_Q(uint8_t q, int32_t x, int32_t y) { return (int64_t(x) * y) >> q; }
|
||||||
|
#endif
|
||||||
|
|
||||||
void Stepper::isr() {
|
void Stepper::isr() {
|
||||||
|
|
||||||
static hal_timer_t nextMainISR = 0; // Interval until the next main Stepper Pulse phase (0 = Now)
|
static hal_timer_t nextMainISR = 0; // Interval until the next main Stepper Pulse phase (0 = Now)
|
||||||
|
@ -2877,9 +2881,9 @@ hal_timer_t Stepper::block_phase_isr() {
|
||||||
|
|
||||||
#if ENABLED(SMOOTH_LIN_ADVANCE)
|
#if ENABLED(SMOOTH_LIN_ADVANCE)
|
||||||
|
|
||||||
float Stepper::extruder_advance_tau[DISTINCT_E],
|
float Stepper::extruder_advance_tau[DISTINCT_E];
|
||||||
Stepper::extruder_advance_tau_ticks[DISTINCT_E],
|
uint32_t Stepper::extruder_advance_tau_ticks[DISTINCT_E],
|
||||||
Stepper::extruder_advance_alpha[DISTINCT_E];
|
Stepper::extruder_advance_alpha_q30[DISTINCT_E];
|
||||||
|
|
||||||
void Stepper::set_la_interval(const int32_t rate) {
|
void Stepper::set_la_interval(const int32_t rate) {
|
||||||
if (rate == 0) {
|
if (rate == 0) {
|
||||||
|
@ -2904,116 +2908,118 @@ hal_timer_t Stepper::block_phase_isr() {
|
||||||
constexpr uint16_t IS_COMPENSATION_BUFFER_SIZE = uint16_t(float(SMOOTH_LIN_ADV_HZ) / float(SHAPING_MIN_FREQ) / 2.0f + 0.5f);
|
constexpr uint16_t IS_COMPENSATION_BUFFER_SIZE = uint16_t(float(SMOOTH_LIN_ADV_HZ) / float(SHAPING_MIN_FREQ) / 2.0f + 0.5f);
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
xy_float_t buffer[IS_COMPENSATION_BUFFER_SIZE];
|
xy_long_t buffer[IS_COMPENSATION_BUFFER_SIZE];
|
||||||
uint16_t index;
|
uint16_t index;
|
||||||
|
FORCE_INLINE void add(const xy_long_t &input) {
|
||||||
|
buffer[index] = input;
|
||||||
|
if (++index == IS_COMPENSATION_BUFFER_SIZE) index = 0;
|
||||||
|
}
|
||||||
|
FORCE_INLINE xy_long_t past_item(const uint16_t n) {
|
||||||
|
const int16_t i = int16_t(index) - n;
|
||||||
|
return buffer[i >= 0 ? i : i + IS_COMPENSATION_BUFFER_SIZE];
|
||||||
|
}
|
||||||
} DelayBuffer;
|
} DelayBuffer;
|
||||||
|
|
||||||
DelayBuffer delayBuffer;
|
DelayBuffer delayBuffer;
|
||||||
|
|
||||||
void add_to_buffer(xy_float_t input) {
|
xy_long_t smooth_lin_adv_lookback(const shaping_time_t stepper_ticks) {
|
||||||
delayBuffer.buffer[delayBuffer.index++] = input;
|
constexpr uint32_t ADV_TICKS_PER_STEPPER_TICKS_Q30 = (uint64_t(SMOOTH_LIN_ADV_HZ) * _BV32(30)) / STEPPER_TIMER_RATE;
|
||||||
if (delayBuffer.index == IS_COMPENSATION_BUFFER_SIZE)
|
const uint16_t delay_steps = MULT_Q(30, stepper_ticks, ADV_TICKS_PER_STEPPER_TICKS_Q30);
|
||||||
delayBuffer.index = 0;
|
return delayBuffer.past_item(delay_steps);
|
||||||
}
|
|
||||||
|
|
||||||
xy_float_t lookback(shaping_time_t t /* in stepper timer ticks */) {
|
|
||||||
constexpr float ADV_TICKS_PER_STEPPER_TICKS = float(SMOOTH_LIN_ADV_HZ) / (STEPPER_TIMER_RATE);
|
|
||||||
uint32_t delay_steps = t * ADV_TICKS_PER_STEPPER_TICKS + 0.5f; // Convert time to steps
|
|
||||||
uint16_t past_i;
|
|
||||||
if (delay_steps>= IS_COMPENSATION_BUFFER_SIZE) {
|
|
||||||
// this means the buffer is too small. TODO: how to inform user?
|
|
||||||
past_i = delayBuffer.index;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
past_i = (delayBuffer.index + IS_COMPENSATION_BUFFER_SIZE - delay_steps) % IS_COMPENSATION_BUFFER_SIZE;
|
|
||||||
}
|
|
||||||
return delayBuffer.buffer[past_i];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // INPUT_SHAPING_E_SYNC
|
#endif // INPUT_SHAPING_E_SYNC
|
||||||
|
|
||||||
float lookahead(uint32_t t) {
|
int32_t smooth_lin_adv_lookahead(uint32_t stepper_ticks) {
|
||||||
for (uint8_t i = 0; block_t *block = planner.get_future_block(i); i++) {
|
for (uint8_t i = 0; block_t *block = planner.get_future_block(i); i++) {
|
||||||
if (block->is_sync()) continue;
|
if (block->is_sync()) continue;
|
||||||
if (t <= block->acceleration_time) {
|
if (stepper_ticks <= block->acceleration_time) {
|
||||||
if (!block->use_advance_lead) return 0.0f;
|
if (!block->use_advance_lead) return 0;
|
||||||
uint32_t rate = STEP_MULTIPLY(t, block->acceleration_rate) + block->initial_rate;
|
uint32_t rate = STEP_MULTIPLY(stepper_ticks, block->acceleration_rate) + block->initial_rate;
|
||||||
NOMORE(rate, block->nominal_rate);
|
NOMORE(rate, block->nominal_rate);
|
||||||
return rate * block->e_step_ratio;
|
return MULT_Q(30, rate, block->e_step_ratio_q30);
|
||||||
}
|
}
|
||||||
t -= block->acceleration_time;
|
stepper_ticks -= block->acceleration_time;
|
||||||
|
|
||||||
if (t <= block->cruise_time) {
|
if (stepper_ticks <= block->cruise_time) {
|
||||||
if (!block->use_advance_lead) return 0.0f;
|
if (!block->use_advance_lead) return 0;
|
||||||
return block->cruise_rate * block->e_step_ratio;
|
return MULT_Q(30, block->cruise_rate, block->e_step_ratio_q30);
|
||||||
}
|
}
|
||||||
t -= block->cruise_time;
|
stepper_ticks -= block->cruise_time;
|
||||||
|
|
||||||
if (t <= block->deceleration_time) {
|
if (stepper_ticks <= block->deceleration_time) {
|
||||||
if (!block->use_advance_lead) return 0.0f;
|
if (!block->use_advance_lead) return 0;
|
||||||
uint32_t rate = STEP_MULTIPLY(t, block->acceleration_rate);
|
uint32_t rate = STEP_MULTIPLY(stepper_ticks, block->acceleration_rate);
|
||||||
if (rate < block->cruise_rate) {
|
if (rate < block->cruise_rate) {
|
||||||
rate = block->cruise_rate - rate;
|
rate = block->cruise_rate - rate;
|
||||||
NOLESS(rate, block->final_rate);
|
NOLESS(rate, block->final_rate);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
rate = block->final_rate;
|
rate = block->final_rate;
|
||||||
return rate * block->e_step_ratio;
|
return MULT_Q(30, rate, block->e_step_ratio_q30);
|
||||||
}
|
}
|
||||||
t -= block->deceleration_time;
|
stepper_ticks -= block->deceleration_time;
|
||||||
}
|
}
|
||||||
return 0.0f;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
hal_timer_t Stepper::smooth_lin_adv_isr() {
|
hal_timer_t Stepper::smooth_lin_adv_isr() {
|
||||||
float target_adv_steps = 0;
|
int32_t target_adv_steps = 0;
|
||||||
if (current_block) {
|
if (current_block) {
|
||||||
const uint32_t t = extruder_advance_tau_ticks[0] + curr_timer_tick;
|
const uint32_t stepper_ticks = extruder_advance_tau_ticks[E_INDEX_N(active_extruder)] + curr_timer_tick;
|
||||||
target_adv_steps = lookahead(t) * planner.extruder_advance_K[0];
|
target_adv_steps = MULT_Q(27, smooth_lin_adv_lookahead(stepper_ticks), planner.get_advance_k_q27());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
curr_step_rate = 0;
|
curr_step_rate = 0;
|
||||||
}
|
}
|
||||||
static float last_target_adv_steps = 0;
|
static int32_t last_target_adv_steps = 0;
|
||||||
constexpr float dt_inv = SMOOTH_LIN_ADV_HZ;
|
constexpr uint16_t dt_inv = SMOOTH_LIN_ADV_HZ;
|
||||||
float la_step_rate = (target_adv_steps - last_target_adv_steps) * dt_inv;
|
int32_t la_step_rate = (target_adv_steps - last_target_adv_steps) * dt_inv;
|
||||||
last_target_adv_steps = target_adv_steps;
|
last_target_adv_steps = target_adv_steps;
|
||||||
|
|
||||||
static float smoothed_vals[SMOOTH_LIN_ADV_EXP_ORDER] = {0};
|
static int32_t smoothed_vals[SMOOTH_LIN_ADV_EXP_ORDER] = {0};
|
||||||
|
|
||||||
for (uint8_t i = 0; i < SMOOTH_LIN_ADV_EXP_ORDER; i++) {
|
for (uint8_t i = 0; i < SMOOTH_LIN_ADV_EXP_ORDER; i++) {
|
||||||
// Approximate gaussian smoothing via higher order exponential smoothing
|
// Approximate gaussian smoothing via higher order exponential smoothing
|
||||||
la_step_rate = extruder_advance_alpha[0] * la_step_rate + (1 - extruder_advance_alpha[0]) * smoothed_vals[i];
|
smoothed_vals[i] += MULT_Q(30, la_step_rate - smoothed_vals[i], extruder_advance_alpha_q30[E_INDEX_N(active_extruder)]);
|
||||||
smoothed_vals[i] = la_step_rate;
|
la_step_rate = smoothed_vals[i];
|
||||||
}
|
}
|
||||||
const float planned_step_rate = current_block ? curr_step_rate * current_block->e_step_ratio : 0;
|
|
||||||
float total_step_rate = la_step_rate + planned_step_rate;
|
const int32_t planned_step_rate = current_block
|
||||||
|
? MULT_Q(30, curr_step_rate, current_block->e_step_ratio_q30)
|
||||||
|
: 0;
|
||||||
|
|
||||||
|
int32_t total_step_rate = la_step_rate + planned_step_rate;
|
||||||
|
|
||||||
#if ENABLED(INPUT_SHAPING_E_SYNC)
|
#if ENABLED(INPUT_SHAPING_E_SYNC)
|
||||||
|
|
||||||
xy_float_t pre_shaping_rate = xy_float_t({0, 0}),
|
xy_long_t pre_shaping_rate = xy_long_t({0, 0}),
|
||||||
first_pulse_rate = xy_float_t({0, 0});
|
first_pulse_rate = xy_long_t({0, 0});
|
||||||
float unshaped_rate_e = total_step_rate;
|
int32_t unshaped_rate_e = total_step_rate;
|
||||||
if (current_block) {
|
if (current_block) {
|
||||||
const float xy_length = TERN0(INPUT_SHAPING_X, current_block->steps.x) + TERN0(INPUT_SHAPING_Y, current_block->steps.y);
|
if (current_block->xy_length_inv_q30 > 0) {
|
||||||
if (xy_length > 0) {
|
|
||||||
unshaped_rate_e = 0;
|
unshaped_rate_e = 0;
|
||||||
pre_shaping_rate = xy_float_t({
|
|
||||||
TERN0(INPUT_SHAPING_X, total_step_rate * current_block->steps.x / xy_length),
|
|
||||||
TERN0(INPUT_SHAPING_Y, total_step_rate * current_block->steps.y / xy_length)
|
|
||||||
});
|
|
||||||
first_pulse_rate = xy_float_t({
|
|
||||||
TERN0(INPUT_SHAPING_X, pre_shaping_rate.x * Stepper::shaping_x.factor1 / 128.0f),
|
|
||||||
TERN0(INPUT_SHAPING_Y, pre_shaping_rate.y * Stepper::shaping_y.factor1 / 128.0f)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const xy_float_t second_pulse_rate = {
|
|
||||||
TERN0(INPUT_SHAPING_X, lookback(ShapingQueue::get_delay_x()).x * Stepper::shaping_x.factor2 / 128.0f),
|
|
||||||
TERN0(INPUT_SHAPING_Y, lookback(ShapingQueue::get_delay_y()).y * Stepper::shaping_y.factor2 / 128.0f)
|
|
||||||
};
|
|
||||||
add_to_buffer(pre_shaping_rate);
|
|
||||||
|
|
||||||
const float x = TERN0(INPUT_SHAPING_X, first_pulse_rate.x + second_pulse_rate.x),
|
pre_shaping_rate = xy_long_t({
|
||||||
|
TERN0(INPUT_SHAPING_X, MULT_Q(30, total_step_rate * current_block->steps.x, current_block->xy_length_inv_q30)),
|
||||||
|
TERN0(INPUT_SHAPING_Y, MULT_Q(30, total_step_rate * current_block->steps.y, current_block->xy_length_inv_q30))
|
||||||
|
});
|
||||||
|
|
||||||
|
first_pulse_rate = xy_long_t({
|
||||||
|
TERN0(INPUT_SHAPING_X, (pre_shaping_rate.x * Stepper::shaping_x.factor1) >> 7),
|
||||||
|
TERN0(INPUT_SHAPING_Y, (pre_shaping_rate.y * Stepper::shaping_y.factor1) >> 7)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const xy_long_t second_pulse_rate = {
|
||||||
|
TERN0(INPUT_SHAPING_X, (smooth_lin_adv_lookback(ShapingQueue::get_delay_x()).x * Stepper::shaping_x.factor2)) >> 7,
|
||||||
|
TERN0(INPUT_SHAPING_Y, (smooth_lin_adv_lookback(ShapingQueue::get_delay_y()).y * Stepper::shaping_y.factor2)) >> 7
|
||||||
|
};
|
||||||
|
|
||||||
|
delayBuffer.add(pre_shaping_rate);
|
||||||
|
|
||||||
|
const int32_t x = TERN0(INPUT_SHAPING_X, first_pulse_rate.x + second_pulse_rate.x),
|
||||||
y = TERN0(INPUT_SHAPING_Y, first_pulse_rate.y + second_pulse_rate.y);
|
y = TERN0(INPUT_SHAPING_Y, first_pulse_rate.y + second_pulse_rate.y);
|
||||||
|
|
||||||
total_step_rate = unshaped_rate_e + x + y;
|
total_step_rate = unshaped_rate_e + x + y;
|
||||||
|
@ -3025,6 +3031,7 @@ hal_timer_t Stepper::block_phase_isr() {
|
||||||
curr_timer_tick += SMOOTH_LIN_ADV_INTERVAL;
|
curr_timer_tick += SMOOTH_LIN_ADV_INTERVAL;
|
||||||
return SMOOTH_LIN_ADV_INTERVAL;
|
return SMOOTH_LIN_ADV_INTERVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // SMOOTH_LIN_ADVANCE
|
#endif // SMOOTH_LIN_ADVANCE
|
||||||
|
|
||||||
// Timer interrupt for E. LA_steps is set in the main routine
|
// Timer interrupt for E. LA_steps is set in the main routine
|
||||||
|
|
|
@ -352,13 +352,18 @@ class Stepper {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if ENABLED(SMOOTH_LIN_ADVANCE)
|
#if ENABLED(SMOOTH_LIN_ADVANCE)
|
||||||
static void set_advance_tau(const_float_t tau, const uint8_t e=E_INDEX_N(active_extruder)) {
|
static float extruder_advance_tau[DISTINCT_E]; // Smoothing time; also the lookahead time of the smoother
|
||||||
extruder_advance_tau[e] = tau;
|
static void set_advance_tau(const_float_t tau, const uint8_t e=active_extruder) {
|
||||||
extruder_advance_tau_ticks[e] = tau * (STEPPER_TIMER_RATE); // i.e., <= STEPPER_TIMER_RATE / 2
|
const uint8_t i = E_INDEX_N(e);
|
||||||
|
extruder_advance_tau[i] = tau;
|
||||||
|
extruder_advance_tau_ticks[i] = tau * STEPPER_TIMER_RATE;
|
||||||
// α=1−exp(−dt/τ)
|
// α=1−exp(−dt/τ)
|
||||||
extruder_advance_alpha[e] = 1.0f - expf(-(SMOOTH_LIN_ADV_INTERVAL) * (SMOOTH_LIN_ADV_EXP_ORDER) / extruder_advance_tau_ticks[e]);
|
const float alpha_float = 1.0f - expf(-float(SMOOTH_LIN_ADV_INTERVAL) * (SMOOTH_LIN_ADV_EXP_ORDER) / extruder_advance_tau_ticks[i]);
|
||||||
|
extruder_advance_alpha_q30[i] = int32_t(alpha_float * _BV32(30));
|
||||||
|
}
|
||||||
|
static float get_advance_tau(const uint8_t e=active_extruder) {
|
||||||
|
return extruder_advance_tau[E_INDEX_N(e)];
|
||||||
}
|
}
|
||||||
static float get_advance_tau(const uint8_t e=E_INDEX_N(active_extruder)) { return extruder_advance_tau[e]; }
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -451,9 +456,8 @@ class Stepper {
|
||||||
#if ENABLED(SMOOTH_LIN_ADVANCE)
|
#if ENABLED(SMOOTH_LIN_ADVANCE)
|
||||||
static uint32_t curr_timer_tick, // Current tick relative to block start
|
static uint32_t curr_timer_tick, // Current tick relative to block start
|
||||||
curr_step_rate; // Current motion step rate
|
curr_step_rate; // Current motion step rate
|
||||||
static float extruder_advance_tau[DISTINCT_E], // Smoothing time; also the lookahead time of the smoother
|
static uint32_t extruder_advance_tau_ticks[DISTINCT_E], // Same as extruder_advance_tau but in in stepper timer ticks
|
||||||
extruder_advance_tau_ticks[DISTINCT_E], // Same as extruder_advance_tau but in in stepper timer ticks
|
extruder_advance_alpha_q30[DISTINCT_E]; // The smoothing factor of each stage of the high-order exponential
|
||||||
extruder_advance_alpha[DISTINCT_E]; // The smoothing factor of each stage of the high-order exponential
|
|
||||||
// smoothing filter (calculated from tau)
|
// smoothing filter (calculated from tau)
|
||||||
#else
|
#else
|
||||||
static int32_t la_delta_error, // Analogue of delta_error.e for E steps in LA ISR
|
static int32_t la_delta_error, // Analogue of delta_error.e for E steps in LA ISR
|
||||||
|
|
|
@ -1587,7 +1587,7 @@ void tool_change(const uint8_t new_tool, bool no_move/*=false*/) {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Migrate Linear Advance K factor to the new extruder
|
// Migrate Linear Advance K factor to the new extruder
|
||||||
TERN_(LIN_ADVANCE, planner.extruder_advance_K[active_extruder] = planner.extruder_advance_K[migration_extruder]);
|
TERN_(LIN_ADVANCE, planner.set_advance_k(planner.get_advance_k(migration_extruder), active_extruder));
|
||||||
|
|
||||||
// Temporary migration toolchange_settings restored on exit. i.e., before next tool_change().
|
// Temporary migration toolchange_settings restored on exit. i.e., before next tool_change().
|
||||||
#if defined(MIGRATION_FS_EXTRA_PRIME) \
|
#if defined(MIGRATION_FS_EXTRA_PRIME) \
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue