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

Nonlinear extrusion #26127

Merged
merged 8 commits into from
Oct 11, 2023
Merged
Show file tree
Hide file tree
Changes from all 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
8 changes: 8 additions & 0 deletions Marlin/Configuration_adv.h
Original file line number Diff line number Diff line change
Expand Up @@ -2275,6 +2275,14 @@
//#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
*
* Control extrusion rate based on instantaneous extruder velocity. Can be used to correct for
* underextrusion at high extruder speeds that are otherwise well-behaved (i.e., not skipping).
*/
//#define NONLINEAR_EXTRUSION

// @section leveling

/**
Expand Down
1 change: 1 addition & 0 deletions Marlin/src/core/language.h
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,7 @@
#define STR_CHAMBER_PID "Chamber PID"
#define STR_STEPS_PER_UNIT "Steps per unit"
#define STR_LINEAR_ADVANCE "Linear Advance"
#define STR_NONLINEAR_EXTRUSION "Nonlinear Extrusion"
#define STR_CONTROLLER_FAN "Controller Fan"
#define STR_STEPPER_MOTOR_CURRENTS "Stepper motor currents"
#define STR_RETRACT_S_F_Z "Retract (S<length> F<feedrate> Z<lift>)"
Expand Down
51 changes: 51 additions & 0 deletions Marlin/src/gcode/feature/nonlinear/M592.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/**
* 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"

void GcodeSuite::M592_report(const bool forReplay/*=true*/) {
report_heading(forReplay, F(STR_NONLINEAR_EXTRUSION));
SERIAL_ECHOLNPGM(" M593 A", stepper.ne.A, " B", stepper.ne.B, " C", stepper.ne.C);
}

/**
* 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
6 changes: 6 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,11 @@ class GcodeSuite {
static void M575();
#endif

#if ENABLED(NONLINEAR_EXTRUSION)
static void M592();
static void M592_report(const bool forReplay=true);
#endif

#if HAS_ZV_SHAPING
static void M593();
static void M593_report(const bool forReplay=true);
Expand Down
13 changes: 13 additions & 0 deletions Marlin/src/inc/SanityCheck.h
Original file line number Diff line number Diff line change
Expand Up @@ -858,6 +858,19 @@ 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."
#elif HAS_MULTI_EXTRUDER
#error "NONLINEAR_EXTRUSION doesn't currently support multi-extruder setups."
#elif DISABLED(CPU_32_BIT)
#error "NONLINEAR_EXTRUSION requires a 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);
thinkyhead marked this conversation as resolved.
Show resolved Hide resolved
#else
constexpr uint32_t esteps = 0;
#endif
Expand Down
36 changes: 32 additions & 4 deletions 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)
ne_coeff_t stepper_ne; // 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,13 @@ void MarlinSettings::postprocess() {
EEPROM_WRITE(hotend_idle.cfg);
#endif

//
// Nonlinear Extrusion
//
#if ENABLED(NONLINEAR_EXTRUSION)
EEPROM_WRITE(stepper.ne);
#endif

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

//
// Nonlinear Extrusion
//
#if ENABLED(NONLINEAR_EXTRUSION)
EEPROM_READ(stepper.ne);
#endif

//
// Validate Final Size and CRC
//
Expand Down Expand Up @@ -3396,15 +3417,13 @@ void MarlinSettings::reset() {
//
// Heated Bed PID
//

#if ENABLED(PIDTEMPBED)
thermalManager.temp_bed.pid.set(DEFAULT_bedKp, DEFAULT_bedKi, DEFAULT_bedKd);
#endif

//
// Heated Chamber PID
//

#if ENABLED(PIDTEMPCHAMBER)
thermalManager.temp_chamber.pid.set(DEFAULT_chamberKp, DEFAULT_chamberKi, DEFAULT_chamberKd);
#endif
Expand Down Expand Up @@ -3456,7 +3475,6 @@ void MarlinSettings::reset() {
//
// Volumetric & Filament Size
//

#if DISABLED(NO_VOLUMETRICS)
parser.volumetric_enabled = ENABLED(VOLUMETRIC_DEFAULT_ON);
for (uint8_t q = 0; q < COUNT(planner.filament_size); ++q)
Expand Down Expand Up @@ -3598,6 +3616,11 @@ void MarlinSettings::reset() {
//
TERN_(FT_MOTION, fxdTiCtrl.set_defaults());

//
// Nonlinear Extrusion
//
TERN_(NONLINEAR_EXTRUSION, stepper.ne.reset());

//
// Input Shaping
//
Expand Down Expand Up @@ -3867,6 +3890,11 @@ void MarlinSettings::reset() {
//
TERN_(FT_MOTION, gcode.M493_report(forReplay));

//
// Nonlinear Extrusion
//
TERN_(NONLINEAR_EXTRUSION, gcode.M592_report(forReplay));

//
// Input Shaping
//
Expand Down
55 changes: 53 additions & 2 deletions Marlin/src/module/stepper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,13 @@ uint32_t Stepper::advance_divisor = 0,
bool Stepper::la_active = false;
#endif

#if ENABLED(NONLINEAR_EXTRUSION)
ne_coeff_t Stepper::ne;
ne_fix_t Stepper::ne_fix;
int32_t Stepper::ne_edividend;
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 @@ -2191,6 +2198,16 @@ hal_timer_t Stepper::calc_timer_interval(uint32_t step_rate) {
#endif // !CPU_32_BIT
}

#if ENABLED(NONLINEAR_EXTRUSION)
void Stepper::calc_nonlinear_e(uint32_t step_rate) {
const 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_fix.A * velocity) >> 24) + (((((int64_t)ne_fix.B * velocity) >> 24) * velocity) >> 24);
NOLESS(vd, 0);

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

// 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) {

Expand Down Expand Up @@ -2318,6 +2335,10 @@ hal_timer_t Stepper::block_phase_isr() {
interval = calc_multistep_timer_interval(acc_step_rate << oversampling_factor);
acceleration_time += interval;

#if ENABLED(NONLINEAR_EXTRUSION)
calc_nonlinear_e(acc_step_rate << oversampling_factor);
#endif

#if ENABLED(LIN_ADVANCE)
if (la_active) {
const uint32_t la_step_rate = la_advance_steps < current_block->max_adv_steps ? current_block->la_advance_rate : 0;
Expand Down Expand Up @@ -2388,6 +2409,10 @@ hal_timer_t Stepper::block_phase_isr() {
interval = calc_multistep_timer_interval(step_rate << oversampling_factor);
deceleration_time += interval;

#if ENABLED(NONLINEAR_EXTRUSION)
calc_nonlinear_e(step_rate << oversampling_factor);
#endif

#if ENABLED(LIN_ADVANCE)
if (la_active) {
const uint32_t la_step_rate = la_advance_steps > current_block->final_adv_steps ? current_block->la_advance_rate : 0;
Expand Down Expand Up @@ -2436,6 +2461,10 @@ hal_timer_t Stepper::block_phase_isr() {
// step_rate to timer interval and loops for the nominal speed
ticks_nominal = calc_multistep_timer_interval(current_block->nominal_rate << oversampling_factor);

#if ENABLED(NONLINEAR_EXTRUSION)
calc_nonlinear_e(current_block->nominal_rate << oversampling_factor);
#endif

#if ENABLED(LIN_ADVANCE)
if (la_active)
la_interval = calc_timer_interval(current_block->nominal_rate >> current_block->la_scaling);
Expand Down Expand Up @@ -2636,10 +2665,13 @@ 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)
// Nonlinear Extrusion needs at least 2x oversampling to permit increase of E step rate
// Otherwise assume no axis smoothing (via oversampling)
oversampling_factor = TERN(NONLINEAR_EXTRUSION, 1, 0);

// 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)) {
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
Expand Down Expand Up @@ -2755,10 +2787,29 @@ hal_timer_t Stepper::block_phase_isr() {
acc_step_rate = current_block->initial_rate;
#endif

#if ENABLED(NONLINEAR_EXTRUSION)
ne_edividend = advance_dividend.e;
const 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_fix.A = (1L << 24) * ne.A;
ne_fix.B = (1L << 24) * ne.B;
ne_fix.C = (1L << 24) * ne.C;
}
else {
ne_fix.A = ne_fix.B = 0;
ne_fix.C = (1L << 24);
}
#endif

// Calculate the initial timer interval
interval = calc_multistep_timer_interval(current_block->initial_rate << oversampling_factor);
acceleration_time += interval;

#if ENABLED(NONLINEAR_EXTRUSION)
calc_nonlinear_e(current_block->initial_rate << oversampling_factor);
#endif

#if ENABLED(LIN_ADVANCE)
if (la_active) {
const uint32_t la_step_rate = la_advance_steps < current_block->max_adv_steps ? current_block->la_advance_rate : 0;
Expand Down
19 changes: 19 additions & 0 deletions Marlin/src/module/stepper.h
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,11 @@ constexpr ena_mask_t enable_overlap[] = {

#endif // HAS_ZV_SHAPING

#if ENABLED(NONLINEAR_EXTRUSION)
typedef struct { float A, B, C; void reset() { A = B = 0.0f; C = 1.0f; } } ne_coeff_t;
typedef struct { int32_t A, B, C; } ne_fix_t;
#endif

//
// Stepper class definition
//
Expand Down Expand Up @@ -326,6 +331,10 @@ class Stepper {
static bool frozen; // Set this flag to instantly freeze motion
#endif

#if ENABLED(NONLINEAR_EXTRUSION)
static ne_coeff_t ne;
#endif

private:

static block_t* current_block; // A pointer to the block currently being traced
Expand Down Expand Up @@ -416,6 +425,12 @@ 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 uint32_t ne_scale;
static ne_fix_t ne_fix;
#endif

#if ENABLED(BABYSTEPPING)
static constexpr hal_timer_t BABYSTEP_NEVER = HAL_TIMER_TYPE_MAX;
static hal_timer_t nextBabystepISR;
Expand Down Expand Up @@ -660,6 +675,10 @@ class Stepper {
// Calculate timing interval and steps-per-ISR for the given step rate
static hal_timer_t calc_multistep_timer_interval(uint32_t step_rate);

#if ENABLED(NONLINEAR_EXTRUSION)
static void calc_nonlinear_e(uint32_t step_rate);
#endif

#if ENABLED(S_CURVE_ACCELERATION)
static void _calc_bezier_curve_coeffs(const int32_t v0, const int32_t v1, const uint32_t av);
static int32_t _eval_bezier_curve(const uint32_t curr_step);
Expand Down
2 changes: 1 addition & 1 deletion buildroot/tests/STM32F103RC_btt
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ set -e
restore_configs
opt_set MOTHERBOARD BOARD_BTT_SKR_MINI_E3_V1_0 SERIAL_PORT 1 SERIAL_PORT_2 -1 \
X_DRIVER_TYPE TMC2209 Y_DRIVER_TYPE TMC2209 Z_DRIVER_TYPE TMC2209 E0_DRIVER_TYPE TMC2209
opt_enable CR10_STOCKDISPLAY PINS_DEBUGGING Z_IDLE_HEIGHT FT_MOTION FT_MOTION_MENU
opt_enable CR10_STOCKDISPLAY PINS_DEBUGGING Z_IDLE_HEIGHT FT_MOTION FT_MOTION_MENU ADAPTIVE_STEP_SMOOTHING NONLINEAR_EXTRUSION
exec_test $1 $2 "BigTreeTech SKR Mini E3 1.0 - TMC2209 HW Serial, FT_MOTION" "$3"

# clean up
Expand Down
Loading
Loading