✨ Nonlinear Extrusion Control (M592) (#26127)
This commit is contained in:
parent
6d301a282e
commit
e9b9d634c4
|
@ -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
|
||||
|
||||
/**
|
||||
|
|
|
@ -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>)"
|
||||
|
|
51
Marlin/src/gcode/feature/nonlinear/M592.cpp
Normal file
51
Marlin/src/gcode/feature/nonlinear/M592.cpp
Normal file
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
@ -1106,6 +1107,11 @@ private:
|
|||
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);
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
@ -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!");
|
||||
|
@ -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
|
||||
//
|
||||
|
@ -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
|
||||
//
|
||||
|
@ -3396,7 +3417,6 @@ void MarlinSettings::reset() {
|
|||
//
|
||||
// Heated Bed PID
|
||||
//
|
||||
|
||||
#if ENABLED(PIDTEMPBED)
|
||||
thermalManager.temp_bed.pid.set(DEFAULT_bedKp, DEFAULT_bedKi, DEFAULT_bedKd);
|
||||
#endif
|
||||
|
@ -3404,7 +3424,6 @@ void MarlinSettings::reset() {
|
|||
//
|
||||
// Heated Chamber PID
|
||||
//
|
||||
|
||||
#if ENABLED(PIDTEMPCHAMBER)
|
||||
thermalManager.temp_chamber.pid.set(DEFAULT_chamberKp, DEFAULT_chamberKi, DEFAULT_chamberKd);
|
||||
#endif
|
||||
|
@ -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)
|
||||
|
@ -3598,6 +3616,11 @@ void MarlinSettings::reset() {
|
|||
//
|
||||
TERN_(FT_MOTION, fxdTiCtrl.set_defaults());
|
||||
|
||||
//
|
||||
// Nonlinear Extrusion
|
||||
//
|
||||
TERN_(NONLINEAR_EXTRUSION, stepper.ne.reset());
|
||||
|
||||
//
|
||||
// Input Shaping
|
||||
//
|
||||
|
@ -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
|
||||
//
|
||||
|
|
|
@ -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)
|
||||
|
@ -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) {
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
//
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Reference in a new issue