Skip to content

Nonlinear extrusion #26127

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

Merged
merged 8 commits into from
Oct 11, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions Marlin/Configuration_adv.h
Original file line number Diff line number Diff line change
Expand Up @@ -2264,6 +2264,15 @@
//#define EXPERIMENTAL_I2S_LA // Allow I2S_STEPPER_STREAM to be used with LA. Performance degrades as the LA step rate reaches ~20kHz.
#endif

/**
* Nonlinear Extrusion Control
*
* Enables control over extrusion rate based on instantaneous extruder velocity. This can be used
* to correct for underextrusion at high extruder speeds that are otherwise well-behaved (e.g.
* not yet skipping).
*/
//#define NONLINEAR_EXTRUSION

// @section leveling

/**
Expand Down
54 changes: 54 additions & 0 deletions Marlin/src/gcode/feature/nonlinear/M592.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2023 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/

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

#if ENABLED(NONLINEAR_EXTRUSION)

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

/**
* M592: Get or set nonlinear extrusion parameters
* A<factor> Linear coefficient (default 0.0)
* B<factor> Quadratic coefficient (default 0.0)
* C<factor> Constant coefficient (default 1.0)
*
* Adjusts the amount of extrusion based on the instantaneous velocity of extrusion, as a multiplier.
* The amount of extrusion is multiplied by max(C, C + A*v + B*v^2) where v is extruder velocity in mm/s.
* Only adjusts forward extrusions, since those are the ones affected by backpressure.
*/
void GcodeSuite::M592() {
if (parser.seenval('A')) {
stepper.ne_A = parser.value_float();
}

if (parser.seenval('B')) {
stepper.ne_B = parser.value_float();
}

if (parser.seenval('C')) {
stepper.ne_C = parser.value_float();
}
}

#endif // NONLINEAR_EXTRUSION
4 changes: 4 additions & 0 deletions Marlin/src/gcode/gcode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -935,6 +935,10 @@ void GcodeSuite::process_parsed_command(const bool no_ok/*=false*/) {
case 575: M575(); break; // M575: Set serial baudrate
#endif

#if ENABLED(NONLINEAR_EXTRUSION)
case 592: M592(); break; // M592: Nonlinear Extrusion control
#endif

#if HAS_ZV_SHAPING
case 593: M593(); break; // M593: Input Shaping control
#endif
Expand Down
5 changes: 5 additions & 0 deletions Marlin/src/gcode/gcode.h
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +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)
* M592 - Get or set nonlinear extrusion parameters. (Requires NONLINEAR_EXTRUSION)
* 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)
Expand Down Expand Up @@ -1106,6 +1107,10 @@ class GcodeSuite {
static void M575();
#endif

#if ENABLED(NONLINEAR_EXTRUSION)
static void M592();
#endif

#if HAS_ZV_SHAPING
static void M593();
static void M593_report(const bool forReplay=true);
Expand Down
17 changes: 17 additions & 0 deletions Marlin/src/inc/SanityCheck.h
Original file line number Diff line number Diff line change
Expand Up @@ -852,6 +852,23 @@ static_assert(COUNT(arm) == LOGICAL_AXES, "AXIS_RELATIVE_MODES must contain " _L
#endif
#endif

/**
* Nonlinear Extrusion requirements
*/
#if ENABLED(NONLINEAR_EXTRUSION)
#if DISABLED(ADAPTIVE_STEP_SMOOTHING)
#error "ADAPTIVE_STEP_SMOOTHING is required for NONLINEAR_EXTRUSION"
#endif

#if EXTRUDERS > 1
#error "NONLINEAR_EXTRUSION doesn't currently support multi-extruder setups"
#endif

#if DISABLED(CPU_32_BIT)
#error "NONLINEAR_EXTRUSION requires 32-bit CPU"
#endif
#endif

/**
* Special tool-changing options
*/
Expand Down
2 changes: 1 addition & 1 deletion Marlin/src/module/planner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2005,7 +2005,7 @@ bool Planner::_populate_block(
#if HAS_EXTRUDERS
dm.e = (dist.e > 0);
const float esteps_float = dist.e * e_factor[extruder];
const uint32_t esteps = ABS(esteps_float) + 0.5f;
const uint32_t esteps = ABS(esteps_float);
#else
constexpr uint32_t esteps = 0;
#endif
Expand Down
27 changes: 26 additions & 1 deletion Marlin/src/module/settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
*/

// Change EEPROM version if the structure changes
#define EEPROM_VERSION "V88"
#define EEPROM_VERSION "V89"
#define EEPROM_OFFSET 100

// Check the integrity of data offsets.
Expand Down Expand Up @@ -634,6 +634,13 @@ typedef struct SettingsDataStruct {
hotend_idle_settings_t hotend_idle_config; // M86 S T E B
#endif

//
// NONLINEAR_EXTRUSION
//
#if ENABLED(NONLINEAR_EXTRUSION)
float ne_A, ne_B, ne_C; // M592 A B C
#endif

} SettingsData;

//static_assert(sizeof(SettingsData) <= MARLIN_EEPROM_SIZE, "EEPROM too small to contain SettingsData!");
Expand Down Expand Up @@ -1729,6 +1736,15 @@ void MarlinSettings::postprocess() {
EEPROM_WRITE(hotend_idle.cfg);
#endif

//
// NONLINEAR_EXTRUSION
//
#if ENABLED(NONLINEAR_EXTRUSION)
EEPROM_WRITE(stepper.ne_A);
EEPROM_WRITE(stepper.ne_B);
EEPROM_WRITE(stepper.ne_C);
#endif

//
// Report final CRC and Data Size
//
Expand Down Expand Up @@ -2803,6 +2819,15 @@ void MarlinSettings::postprocess() {
EEPROM_READ(hotend_idle.cfg);
#endif

//
// NONLINEAR_EXTRUSION
//
#if ENABLED(NONLINEAR_EXTRUSION)
EEPROM_READ(stepper.ne_A);
EEPROM_READ(stepper.ne_B);
EEPROM_READ(stepper.ne_C);
#endif

//
// Validate Final Size and CRC
//
Expand Down
51 changes: 43 additions & 8 deletions Marlin/src/module/stepper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,17 @@ uint32_t Stepper::advance_divisor = 0,
bool Stepper::la_active = false;
#endif

#if ENABLED(NONLINEAR_EXTRUSION)
int32_t Stepper::ne_edividend;
float Stepper::ne_A = 0;
float Stepper::ne_B = 0;
float Stepper::ne_C = 1;
int32_t Stepper::ne_Afix;
int32_t Stepper::ne_Bfix;
int32_t Stepper::ne_Cfix;
uint32_t Stepper::ne_scale;
#endif

#if HAS_ZV_SHAPING
shaping_time_t ShapingQueue::now = 0;
#if ANY(MCU_LPC1768, MCU_LPC1769) && DISABLED(NO_LPC_ETHERNET_BUFFER)
Expand Down Expand Up @@ -2194,6 +2205,14 @@ hal_timer_t Stepper::calc_timer_interval(uint32_t step_rate) {
// Get the timer interval and the number of loops to perform per tick
hal_timer_t Stepper::calc_multistep_timer_interval(uint32_t step_rate) {

#if ENABLED(NONLINEAR_EXTRUSION)
uint32_t velocity = ne_scale * step_rate; // scale step_rate first so all intermediate values stay in range of 8.24 fixed point math
int32_t vd = (((int64_t)ne_Afix * velocity) >> 24) + (((((int64_t)ne_Bfix * velocity) >> 24) * velocity) >> 24);
if (vd < 0) vd = 0;

advance_dividend.e = ((uint64_t)(ne_Cfix + vd) * ne_edividend) >> 24;
#endif

#if ENABLED(OLD_ADAPTIVE_MULTISTEPPING)

#if MULTISTEPPING_LIMIT == 1
Expand Down Expand Up @@ -2636,15 +2655,16 @@ hal_timer_t Stepper::block_phase_isr() {
acceleration_time = deceleration_time = 0;

#if ENABLED(ADAPTIVE_STEP_SMOOTHING)
oversampling_factor = 0; // Assume no axis smoothing (via oversampling)
oversampling_factor = 0; // Assume no axis smoothing (via oversampling)
#if ENABLED(NONLINEAR_EXTRUSION)
oversampling_factor = 1; // We need at least 2x oversampling to ensure we can increase extruder step rate
#endif
// Decide if axis smoothing is possible
uint32_t max_rate = current_block->nominal_rate; // Get the step event rate
if (TERN1(DWIN_LCD_PROUI, hmiData.adaptiveStepSmoothing)) {
while (max_rate < MIN_STEP_ISR_FREQUENCY) { // As long as more ISRs are possible...
max_rate <<= 1; // Try to double the rate
if (max_rate < MIN_STEP_ISR_FREQUENCY) // Don't exceed the estimated ISR limit
++oversampling_factor; // Increase the oversampling (used for left-shift)
}
uint32_t max_rate = current_block->nominal_rate; // Get the step event rate
while (max_rate < MIN_STEP_ISR_FREQUENCY) { // As long as more ISRs are possible...
max_rate <<= 1; // Try to double the rate
if (max_rate < MIN_STEP_ISR_FREQUENCY) // Don't exceed the estimated ISR limit
++oversampling_factor; // Increase the oversampling (used for left-shift)
}
#endif

Expand Down Expand Up @@ -2755,6 +2775,21 @@ hal_timer_t Stepper::block_phase_isr() {
acc_step_rate = current_block->initial_rate;
#endif

#if ENABLED(NONLINEAR_EXTRUSION)
ne_edividend = advance_dividend.e;
float scale = (float(ne_edividend) / advance_divisor) * planner.mm_per_step[E_AXIS_N(current_block->extruder)];
ne_scale = (1L << 24) * scale;
if (current_block->direction_bits.e) {
ne_Afix = (1L << 24) * ne_A;
ne_Bfix = (1L << 24) * ne_B;
ne_Cfix = (1L << 24) * ne_C;
} else {
ne_Afix = 0;
ne_Bfix = 0;
ne_Cfix = (1L << 24);
}
#endif

// Calculate the initial timer interval
interval = calc_multistep_timer_interval(current_block->initial_rate << oversampling_factor);
acceleration_time += interval;
Expand Down
14 changes: 14 additions & 0 deletions Marlin/src/module/stepper.h
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,12 @@ class Stepper {
static bool frozen; // Set this flag to instantly freeze motion
#endif

#if ENABLED(NONLINEAR_EXTRUSION)
static float ne_A;
static float ne_B;
static float ne_C;
#endif

private:

static block_t* current_block; // A pointer to the block currently being traced
Expand Down Expand Up @@ -416,6 +422,14 @@ class Stepper {
static bool la_active; // Whether linear advance is used on the present segment.
#endif

#if ENABLED(NONLINEAR_EXTRUSION)
static int32_t ne_edividend;
static int32_t ne_Afix;
static int32_t ne_Bfix;
static int32_t ne_Cfix;
static uint32_t ne_scale;
#endif

#if ENABLED(BABYSTEPPING)
static constexpr hal_timer_t BABYSTEP_NEVER = HAL_TIMER_TYPE_MAX;
static hal_timer_t nextBabystepISR;
Expand Down
1 change: 1 addition & 0 deletions ini/features.ini
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,7 @@ CONTROLLER_FAN_EDITABLE = build_src_filter=+<src/gcode/feature/co
HAS_ZV_SHAPING = build_src_filter=+<src/gcode/feature/input_shaping>
GCODE_MACROS = build_src_filter=+<src/gcode/feature/macro>
GRADIENT_MIX = build_src_filter=+<src/gcode/feature/mixing/M166.cpp>
NONLINEAR_EXTRUSION = build_src_filter=+<src/gcode/feature/nonlinear>
OTA_FIRMWARE_UPDATE = build_src_filter=+<src/gcode/feature/ota>
HAS_SAVED_POSITIONS = build_src_filter=+<src/gcode/feature/pause/G60.cpp> +<src/gcode/feature/pause/G61.cpp>
PARK_HEAD_ON_PAUSE = build_src_filter=+<src/gcode/feature/pause/M125.cpp>
Expand Down