Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Input Shaping improvements #24951

Merged
merged 35 commits into from Nov 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
34fe801
Frequency = 0 now disables input shaping
tombrazier Oct 25, 2022
518a43e
Adjusted ADAPTIVE_STEP_SMOOTHING calculation to take input shaping in…
tombrazier Oct 28, 2022
aaacf79
Fixed synchronisation error between echo steps and changes in dividends
tombrazier Oct 29, 2022
58797c8
Laser seems to work okay with input shaping, so allow it
tombrazier Oct 29, 2022
2023140
Ensure the double pulse generated on direction change is slow enough …
tombrazier Oct 29, 2022
60966e2
Spread the tiny rounding errors caused by scaling over subsequent seg…
tombrazier Oct 29, 2022
c87be2e
Remember steps that have not yet happened because of echoes when proc…
tombrazier Oct 31, 2022
c5865da
Fixed some errors around IS being disabled for specific axes
tombrazier Nov 3, 2022
c9458cd
Handle multi-stepping in input shaping
tombrazier Nov 3, 2022
1c67a61
Allow disabling input shaping from the menu and make it clear in conf…
tombrazier Nov 5, 2022
8e6aae5
Cache the values for peek_x and peek_y which saves a lot of cycles in…
tombrazier Nov 9, 2022
b76a8df
Testing a bool for shaping being enabled is a lot cheaper than testin…
tombrazier Nov 9, 2022
3d094f1
shaping_isr() gets called a lot, so optimised it
tombrazier Nov 9, 2022
5d10dc5
Updated ASS calculations
tombrazier Nov 9, 2022
312b4c2
Fix DelayQueue
thinkyhead Nov 11, 2022
d8f5e26
misc. cleanup
thinkyhead Nov 11, 2022
e570e1c
Modify configuration
thinkyhead Nov 12, 2022
9ea21dd
Minor fixes
tombrazier Nov 12, 2022
9d6f98e
Cleaned up oversampling_factor vs oversampling
tombrazier Nov 14, 2022
c2a9c5f
Refined step frequency calculations for multi-stepping
tombrazier Nov 14, 2022
24b589b
Add a sufficient delay when changing direction to prevent confusing t…
tombrazier Nov 14, 2022
a1546cb
Take extra step rate from ADAPTIVE_STEP_SMOOTHING into account when s…
tombrazier Nov 16, 2022
24a1b4d
Remove remaining small hysteresis on direction change
tombrazier Nov 19, 2022
35904b3
Instead of changing existing bresenham logic, do IS with a secondary …
tombrazier Nov 19, 2022
62eb0c5
Cleanup
tombrazier Nov 20, 2022
badaab2
Alternative method of preventing buffer overflows: reduce shaping del…
tombrazier Nov 20, 2022
cca1b8e
Optimised free_count_[xy]() functions and updated cycle calculations
tombrazier Nov 20, 2022
d54efc1
Merge branch 'bugfix-2.1.x' into is_improvements
tombrazier Nov 20, 2022
d273909
More realistic default zetas
tombrazier Nov 20, 2022
8fe8a4f
shaping_isr() must now happen before pulse_phase_isr() to prevent buf…
tombrazier Nov 21, 2022
52664a0
Simpler, cleaner alternative buffer overflow logic
tombrazier Nov 21, 2022
35725a7
Updated timings
tombrazier Nov 21, 2022
583f249
Prevent TMC2208/TMC2225 bug using hysteresis
tombrazier Nov 23, 2022
c8c0f3a
Merge branch 'bugfix-2.1.x' into pr/24951
thinkyhead Nov 27, 2022
f2c06af
cleanup
thinkyhead Nov 27, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
31 changes: 19 additions & 12 deletions Marlin/Configuration_adv.h
Expand Up @@ -1062,12 +1062,14 @@
*
* Zero Vibration (ZV) Input Shaping for X and/or Y movements.
*
* This option uses a lot of SRAM for the step buffer, which is proportional
* to the largest step rate possible for any axis. If the build fails due to
* This option uses a lot of SRAM for the step buffer, which is related to the
* largest step rate possible for the shaped axes. If the build fails due to
* low SRAM the buffer size may be reduced by setting smaller values for
* DEFAULT_AXIS_STEPS_PER_UNIT and/or DEFAULT_MAX_FEEDRATE. Runtime editing
* of max feedrate (M203) or resonant frequency (M593) may result feedrate
* being capped to prevent buffer overruns.
* DEFAULT_AXIS_STEPS_PER_UNIT and/or DEFAULT_MAX_FEEDRATE. Disabling
* ADAPTIVE_STEP_SMOOTHING and reducing the step rate for non-shaped axes may
* also reduce the buffer sizes. Runtime editing of max feedrate (M203) or
* resonant frequency (M593) may result in input shaping losing effectiveness
* during high speed movements to prevent buffer overruns.
*
* Tune with M593 D<factor> F<frequency>:
*
Expand All @@ -1077,13 +1079,18 @@
* X<1> Set the given parameters only for the X axis.
* Y<1> Set the given parameters only for the Y axis.
*/
//#define INPUT_SHAPING
#if ENABLED(INPUT_SHAPING)
#define SHAPING_FREQ_X 40 // (Hz) The dominant resonant frequency of the X axis.
#define SHAPING_FREQ_Y 40 // (Hz) The dominant resonant frequency of the Y axis.
#define SHAPING_ZETA_X 0.3f // Damping ratio of the X axis (range: 0.0 = no damping to 1.0 = critical damping).
#define SHAPING_ZETA_Y 0.3f // Damping ratio of the Y axis (range: 0.0 = no damping to 1.0 = critical damping).
//#define SHAPING_MENU // Add a menu to the LCD to set shaping parameters.
//#define INPUT_SHAPING_X
//#define INPUT_SHAPING_Y
#if EITHER(INPUT_SHAPING_X, INPUT_SHAPING_Y)
#if ENABLED(INPUT_SHAPING_X)
#define SHAPING_FREQ_X 40 // (Hz) The default dominant resonant frequency on the X axis.
#define SHAPING_ZETA_X 0.15f // Damping ratio of the X axis (range: 0.0 = no damping to 1.0 = critical damping).
#endif
#if ENABLED(INPUT_SHAPING_Y)
#define SHAPING_FREQ_Y 40 // (Hz) The default dominant resonant frequency on the Y axis.
#define SHAPING_ZETA_Y 0.15f // Damping ratio of the Y axis (range: 0.0 = no damping to 1.0 = critical damping).
#endif
//#define SHAPING_MENU // Add a menu to the LCD to set shaping parameters.
#endif

#define AXIS_RELATIVE_MODES { false, false, false, false }
Expand Down
21 changes: 11 additions & 10 deletions Marlin/src/gcode/feature/input_shaping/M593.cpp
Expand Up @@ -22,21 +22,21 @@

#include "../../../inc/MarlinConfig.h"

#if ENABLED(INPUT_SHAPING)
#if HAS_SHAPING

#include "../../gcode.h"
#include "../../../module/stepper.h"

void GcodeSuite::M593_report(const bool forReplay/*=true*/) {
report_heading_etc(forReplay, F("Input Shaping"));
#if HAS_SHAPING_X
#if ENABLED(INPUT_SHAPING_X)
SERIAL_ECHOLNPGM(" M593 X"
" F", stepper.get_shaping_frequency(X_AXIS),
" D", stepper.get_shaping_damping_ratio(X_AXIS)
);
#endif
#if HAS_SHAPING_Y
TERN_(HAS_SHAPING_X, report_echo_start(forReplay));
#if ENABLED(INPUT_SHAPING_Y)
TERN_(INPUT_SHAPING_X, report_echo_start(forReplay));
SERIAL_ECHOLNPGM(" M593 Y"
" F", stepper.get_shaping_frequency(Y_AXIS),
" D", stepper.get_shaping_damping_ratio(Y_AXIS)
Expand All @@ -55,10 +55,10 @@ void GcodeSuite::M593_report(const bool forReplay/*=true*/) {
void GcodeSuite::M593() {
if (!parser.seen_any()) return M593_report();

const bool seen_X = TERN0(HAS_SHAPING_X, parser.seen_test('X')),
seen_Y = TERN0(HAS_SHAPING_Y, parser.seen_test('Y')),
for_X = seen_X || TERN0(HAS_SHAPING_X, (!seen_X && !seen_Y)),
for_Y = seen_Y || TERN0(HAS_SHAPING_Y, (!seen_X && !seen_Y));
const bool seen_X = TERN0(INPUT_SHAPING_X, parser.seen_test('X')),
seen_Y = TERN0(INPUT_SHAPING_Y, parser.seen_test('Y')),
for_X = seen_X || TERN0(INPUT_SHAPING_X, (!seen_X && !seen_Y)),
for_Y = seen_Y || TERN0(INPUT_SHAPING_Y, (!seen_X && !seen_Y));

if (parser.seen('D')) {
const float zeta = parser.value_float();
Expand All @@ -72,12 +72,13 @@ void GcodeSuite::M593() {

if (parser.seen('F')) {
const float freq = parser.value_float();
if (freq > 0) {
constexpr float max_freq = float(uint32_t(STEPPER_TIMER_RATE) / 2) / shaping_time_t(-2);
if (freq == 0.0f || freq > max_freq) {
if (for_X) stepper.set_shaping_frequency(X_AXIS, freq);
if (for_Y) stepper.set_shaping_frequency(Y_AXIS, freq);
}
else
SERIAL_ECHO_MSG("?Frequency (F) must be greater than 0");
SERIAL_ECHOLNPGM("?Frequency (F) must be greater than ", max_freq, " or 0 to disable");
}
}

Expand Down
2 changes: 1 addition & 1 deletion Marlin/src/gcode/gcode.cpp
Expand Up @@ -933,7 +933,7 @@ void GcodeSuite::process_parsed_command(const bool no_ok/*=false*/) {
case 575: M575(); break; // M575: Set serial baudrate
#endif

#if ENABLED(INPUT_SHAPING)
#if HAS_SHAPING
case 593: M593(); break; // M593: Set Input Shaping parameters
#endif

Expand Down
4 changes: 2 additions & 2 deletions Marlin/src/gcode/gcode.h
Expand Up @@ -259,7 +259,7 @@
* M554 - Get or set IP gateway. (Requires enabled Ethernet port)
* M569 - Enable stealthChop on an axis. (Requires at least one _DRIVER_TYPE to be TMC2130/2160/2208/2209/5130/5160)
* M575 - Change the serial baud rate. (Requires BAUD_RATE_GCODE)
* M593 - Get or set input shaping parameters. (Requires INPUT_SHAPING)
* M593 - Get or set input shaping parameters. (Requires INPUT_SHAPING_[XY])
* M600 - Pause for filament change: "M600 X<pos> Y<pos> Z<raise> E<first_retract> L<later_retract>". (Requires ADVANCED_PAUSE_FEATURE)
* M603 - Configure filament change: "M603 T<tool> U<unload_length> L<load_length>". (Requires ADVANCED_PAUSE_FEATURE)
* M605 - Set Dual X-Carriage movement mode: "M605 S<mode> [X<x_offset>] [R<temp_offset>]". (Requires DUAL_X_CARRIAGE)
Expand Down Expand Up @@ -1081,7 +1081,7 @@ class GcodeSuite {
static void M575();
#endif

#if ENABLED(INPUT_SHAPING)
#if HAS_SHAPING
static void M593();
static void M593_report(const bool forReplay=true);
#endif
Expand Down
18 changes: 7 additions & 11 deletions Marlin/src/inc/Conditionals_adv.h
Expand Up @@ -1120,15 +1120,11 @@
#endif

// Input shaping
#if ENABLED(INPUT_SHAPING)
#if !HAS_Y_AXIS
#undef SHAPING_FREQ_Y
#undef SHAPING_BUFFER_Y
#endif
#ifdef SHAPING_FREQ_X
#define HAS_SHAPING_X 1
#endif
#ifdef SHAPING_FREQ_Y
#define HAS_SHAPING_Y 1
#endif
#if !HAS_Y_AXIS
#undef INPUT_SHAPING_Y
#undef SHAPING_FREQ_Y
#undef SHAPING_BUFFER_Y
#endif
#if EITHER(INPUT_SHAPING_X, INPUT_SHAPING_Y)
#define HAS_SHAPING 1
#endif
14 changes: 5 additions & 9 deletions Marlin/src/inc/SanityCheck.h
Expand Up @@ -4271,14 +4271,14 @@ static_assert(_PLUS_TEST(4), "HOMING_FEEDRATE_MM_M values must be positive.");
#endif

// Check requirements for Input Shaping
#if ENABLED(INPUT_SHAPING) && defined(__AVR__)
#if HAS_SHAPING_X
#if HAS_SHAPING && defined(__AVR__)
#if ENABLED(INPUT_SHAPING_X)
#if F_CPU > 16000000
static_assert((SHAPING_FREQ_X) * 2 * 0x10000 >= (STEPPER_TIMER_RATE), "SHAPING_FREQ_X is below the minimum (20) for AVR 20MHz.");
#else
static_assert((SHAPING_FREQ_X) * 2 * 0x10000 >= (STEPPER_TIMER_RATE), "SHAPING_FREQ_X is below the minimum (16) for AVR 16MHz.");
#endif
#elif HAS_SHAPING_Y
#elif ENABLED(INPUT_SHAPING_Y)
#if F_CPU > 16000000
static_assert((SHAPING_FREQ_Y) * 2 * 0x10000 >= (STEPPER_TIMER_RATE), "SHAPING_FREQ_Y is below the minimum (20) for AVR 20MHz.");
#else
Expand All @@ -4287,12 +4287,8 @@ static_assert(_PLUS_TEST(4), "HOMING_FEEDRATE_MM_M values must be positive.");
#endif
#endif

#if ENABLED(INPUT_SHAPING)
#if ENABLED(DIRECT_STEPPING)
#error "INPUT_SHAPING cannot currently be used with DIRECT_STEPPING."
#elif ENABLED(LASER_FEATURE)
#error "INPUT_SHAPING cannot currently be used with LASER_FEATURE."
#endif
#if BOTH(HAS_SHAPING, DIRECT_STEPPING)
#error "INPUT_SHAPING_[XY] cannot currently be used with DIRECT_STEPPING."
#endif

// Misc. Cleanup
Expand Down
8 changes: 4 additions & 4 deletions Marlin/src/lcd/language/language_en.h
Expand Up @@ -403,10 +403,10 @@ namespace Language_en {
LSTR MSG_A_RETRACT = _UxGT("Retract Accel");
LSTR MSG_A_TRAVEL = _UxGT("Travel Accel");
LSTR MSG_INPUT_SHAPING = _UxGT("Input Shaping");
LSTR MSG_SHAPING_X_FREQ = STR_X _UxGT(" frequency");
LSTR MSG_SHAPING_Y_FREQ = STR_Y _UxGT(" frequency");
LSTR MSG_SHAPING_X_ZETA = STR_X _UxGT(" damping");
LSTR MSG_SHAPING_Y_ZETA = STR_Y _UxGT(" damping");
LSTR MSG_SHAPING_ENABLE = _UxGT("Enable @ shaping");
LSTR MSG_SHAPING_DISABLE = _UxGT("Disable @ shaping");
LSTR MSG_SHAPING_FREQ = _UxGT("@ frequency");
LSTR MSG_SHAPING_ZETA = _UxGT("@ damping");
LSTR MSG_XY_FREQUENCY_LIMIT = _UxGT("XY Freq Limit");
LSTR MSG_XY_FREQUENCY_FEEDRATE = _UxGT("Min FR Factor");
LSTR MSG_STEPS_PER_MM = _UxGT("Steps/mm");
Expand Down
34 changes: 19 additions & 15 deletions Marlin/src/lcd/menu/menu_advanced.cpp
Expand Up @@ -545,24 +545,28 @@ void menu_backlash();
START_MENU();
BACK_ITEM(MSG_ADVANCED_SETTINGS);

// M593 F Frequency
#if HAS_SHAPING_X
// M593 F Frequency and D Damping ratio
#if ENABLED(INPUT_SHAPING_X)
editable.decimal = stepper.get_shaping_frequency(X_AXIS);
EDIT_ITEM_FAST(float61, MSG_SHAPING_X_FREQ, &editable.decimal, min_frequency, 200.0f, []{ stepper.set_shaping_frequency(X_AXIS, editable.decimal); });
if (editable.decimal) {
ACTION_ITEM_N(X_AXIS, MSG_SHAPING_DISABLE, []{ stepper.set_shaping_frequency(X_AXIS, 0.0f); });
EDIT_ITEM_FAST_N(float61, X_AXIS, MSG_SHAPING_FREQ, &editable.decimal, min_frequency, 200.0f, []{ stepper.set_shaping_frequency(X_AXIS, editable.decimal); });
editable.decimal = stepper.get_shaping_damping_ratio(X_AXIS);
EDIT_ITEM_FAST_N(float42_52, X_AXIS, MSG_SHAPING_ZETA, &editable.decimal, 0.0f, 1.0f, []{ stepper.set_shaping_damping_ratio(X_AXIS, editable.decimal); });
}
else
ACTION_ITEM_N(X_AXIS, MSG_SHAPING_ENABLE, []{ stepper.set_shaping_frequency(X_AXIS, SHAPING_FREQ_X); });
#endif
#if HAS_SHAPING_Y
#if ENABLED(INPUT_SHAPING_Y)
editable.decimal = stepper.get_shaping_frequency(Y_AXIS);
EDIT_ITEM_FAST(float61, MSG_SHAPING_Y_FREQ, &editable.decimal, min_frequency, 200.0f, []{ stepper.set_shaping_frequency(Y_AXIS, editable.decimal); });
#endif

// M593 D Damping ratio
#if HAS_SHAPING_X
editable.decimal = stepper.get_shaping_damping_ratio(X_AXIS);
EDIT_ITEM_FAST(float42_52, MSG_SHAPING_X_ZETA, &editable.decimal, 0.0f, 1.0f, []{ stepper.set_shaping_damping_ratio(X_AXIS, editable.decimal); });
#endif
#if HAS_SHAPING_Y
editable.decimal = stepper.get_shaping_damping_ratio(Y_AXIS);
EDIT_ITEM_FAST(float42_52, MSG_SHAPING_Y_ZETA, &editable.decimal, 0.0f, 1.0f, []{ stepper.set_shaping_damping_ratio(Y_AXIS, editable.decimal); });
if (editable.decimal) {
ACTION_ITEM_N(Y_AXIS, MSG_SHAPING_DISABLE, []{ stepper.set_shaping_frequency(Y_AXIS, 0.0f); });
EDIT_ITEM_FAST_N(float61, Y_AXIS, MSG_SHAPING_FREQ, &editable.decimal, min_frequency, 200.0f, []{ stepper.set_shaping_frequency(Y_AXIS, editable.decimal); });
editable.decimal = stepper.get_shaping_damping_ratio(Y_AXIS);
EDIT_ITEM_FAST_N(float42_52, Y_AXIS, MSG_SHAPING_ZETA, &editable.decimal, 0.0f, 1.0f, []{ stepper.set_shaping_damping_ratio(Y_AXIS, editable.decimal); });
}
else
ACTION_ITEM_N(Y_AXIS, MSG_SHAPING_ENABLE, []{ stepper.set_shaping_frequency(Y_AXIS, SHAPING_FREQ_Y); });
#endif

END_MENU();
Expand Down
15 changes: 7 additions & 8 deletions Marlin/src/module/planner.cpp
Expand Up @@ -1724,6 +1724,13 @@ float Planner::triggered_position_mm(const AxisEnum axis) {
return result * mm_per_step[axis];
}

bool Planner::busy() {
return (has_blocks_queued() || cleaning_buffer_counter
|| TERN0(EXTERNAL_CLOSED_LOOP_CONTROLLER, CLOSED_LOOP_WAITING())
|| TERN0(HAS_SHAPING, stepper.input_shaping_busy())
);
}

void Planner::finish_and_disable() {
while (has_blocks_queued() || cleaning_buffer_counter) idle();
stepper.disable_all_steppers();
Expand Down Expand Up @@ -2483,14 +2490,6 @@ bool Planner::_populate_block(

#endif // XY_FREQUENCY_LIMIT

#if ENABLED(INPUT_SHAPING)
const float top_freq = _MIN(float(0x7FFFFFFFL)
OPTARG(HAS_SHAPING_X, stepper.get_shaping_frequency(X_AXIS))
OPTARG(HAS_SHAPING_Y, stepper.get_shaping_frequency(Y_AXIS))),
max_factor = (top_freq * float(shaping_dividends - 3) * 2.0f) / block->nominal_rate;
NOMORE(speed_factor, max_factor);
#endif

// Correct the speed
if (speed_factor < 1.0f) {
current_speed *= speed_factor;
Expand Down
6 changes: 1 addition & 5 deletions Marlin/src/module/planner.h
Expand Up @@ -930,11 +930,7 @@ class Planner {
static float triggered_position_mm(const AxisEnum axis);

// Blocks are queued, or we're running out moves, or the closed loop controller is waiting
static bool busy() {
return (has_blocks_queued() || cleaning_buffer_counter
|| TERN0(EXTERNAL_CLOSED_LOOP_CONTROLLER, CLOSED_LOOP_WAITING())
);
}
static bool busy();

// Block until all buffered steps are executed / cleaned
static void synchronize();
Expand Down
22 changes: 11 additions & 11 deletions Marlin/src/module/settings.cpp
Expand Up @@ -580,11 +580,11 @@ typedef struct SettingsDataStruct {
//
// Input Shaping
//
#if HAS_SHAPING_X
#if ENABLED(INPUT_SHAPING_X)
float shaping_x_frequency, // M593 X F
shaping_x_zeta; // M593 X D
#endif
#if HAS_SHAPING_Y
#if ENABLED(INPUT_SHAPING_Y)
float shaping_y_frequency, // M593 Y F
shaping_y_zeta; // M593 Y D
#endif
Expand Down Expand Up @@ -1617,12 +1617,12 @@ void MarlinSettings::postprocess() {
//
// Input Shaping
///
#if ENABLED(INPUT_SHAPING)
#if HAS_SHAPING_X
#if HAS_SHAPING
#if ENABLED(INPUT_SHAPING_X)
EEPROM_WRITE(stepper.get_shaping_frequency(X_AXIS));
EEPROM_WRITE(stepper.get_shaping_damping_ratio(X_AXIS));
#endif
#if HAS_SHAPING_Y
#if ENABLED(INPUT_SHAPING_Y)
EEPROM_WRITE(stepper.get_shaping_frequency(Y_AXIS));
EEPROM_WRITE(stepper.get_shaping_damping_ratio(Y_AXIS));
#endif
Expand Down Expand Up @@ -2602,7 +2602,7 @@ void MarlinSettings::postprocess() {
//
// Input Shaping
//
#if HAS_SHAPING_X
#if ENABLED(INPUT_SHAPING_X)
{
float _data[2];
EEPROM_READ(_data);
Expand All @@ -2611,7 +2611,7 @@ void MarlinSettings::postprocess() {
}
#endif

#if HAS_SHAPING_Y
#if ENABLED(INPUT_SHAPING_Y)
{
float _data[2];
EEPROM_READ(_data);
Expand Down Expand Up @@ -3389,12 +3389,12 @@ void MarlinSettings::reset() {
//
// Input Shaping
//
#if ENABLED(INPUT_SHAPING)
#if HAS_SHAPING_X
#if HAS_SHAPING
#if ENABLED(INPUT_SHAPING_X)
stepper.set_shaping_frequency(X_AXIS, SHAPING_FREQ_X);
stepper.set_shaping_damping_ratio(X_AXIS, SHAPING_ZETA_X);
#endif
#if HAS_SHAPING_Y
#if ENABLED(INPUT_SHAPING_Y)
stepper.set_shaping_frequency(Y_AXIS, SHAPING_FREQ_Y);
stepper.set_shaping_damping_ratio(Y_AXIS, SHAPING_ZETA_Y);
#endif
Expand Down Expand Up @@ -3650,7 +3650,7 @@ void MarlinSettings::reset() {
//
// Input Shaping
//
TERN_(INPUT_SHAPING, gcode.M593_report(forReplay));
TERN_(HAS_SHAPING, gcode.M593_report(forReplay));

//
// Linear Advance
Expand Down