Skip to content

Commit

Permalink
⚡️ Input Shaping improvements (MarlinFirmware#24951)
Browse files Browse the repository at this point in the history
  • Loading branch information
tombrazier authored and Andy-Big committed Jul 2, 2023
1 parent 5e7905d commit eb4f2eb
Show file tree
Hide file tree
Showing 15 changed files with 472 additions and 371 deletions.
31 changes: 19 additions & 12 deletions Marlin/Configuration_adv.h
Original file line number Diff line number Diff line change
Expand Up @@ -1064,12 +1064,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 @@ -1079,13 +1081,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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
Expand Up @@ -995,7 +995,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
Original file line number Diff line number Diff line change
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 @@ -1086,7 +1086,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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
Expand Up @@ -404,10 +404,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
Original file line number Diff line number Diff line change
Expand Up @@ -667,24 +667,28 @@ void menu_bedlevel_points();
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
Original file line number Diff line number Diff line change
Expand Up @@ -1723,6 +1723,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 @@ -2488,14 +2495,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
Original file line number Diff line number Diff line change
Expand Up @@ -943,11 +943,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
Original file line number Diff line number Diff line change
Expand Up @@ -585,11 +585,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 @@ -1655,12 +1655,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 @@ -2673,7 +2673,7 @@ void MarlinSettings::postprocess() {
//
// Input Shaping
//
#if HAS_SHAPING_X
#if ENABLED(INPUT_SHAPING_X)
{
float _data[2];
EEPROM_READ(_data);
Expand All @@ -2682,7 +2682,7 @@ void MarlinSettings::postprocess() {
}
#endif

#if HAS_SHAPING_Y
#if ENABLED(INPUT_SHAPING_Y)
{
float _data[2];
EEPROM_READ(_data);
Expand Down Expand Up @@ -3566,12 +3566,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 @@ -3830,7 +3830,7 @@ void MarlinSettings::reset() {
//
// Input Shaping
//
TERN_(INPUT_SHAPING, gcode.M593_report(forReplay));
TERN_(HAS_SHAPING, gcode.M593_report(forReplay));

//
// Linear Advance
Expand Down
Loading

0 comments on commit eb4f2eb

Please sign in to comment.