🚸🌡️ Refactor AUTOTEMP, apply to LCD temp change (#28155)

Fixes #28154
This commit is contained in:
Scott Lahteine
2025-11-02 21:48:24 -06:00
committed by GitHub
parent 0c4beea9be
commit 29ad078fda
14 changed files with 170 additions and 109 deletions
+1
View File
@@ -296,6 +296,7 @@
#define STR_TOOL_CHANGING "Tool-changing"
#define STR_HOTEND_OFFSETS "Hotend offsets"
#define STR_SERVO_ANGLES "Servo Angles"
#define STR_AUTOTEMP "Auto Temp Control"
#define STR_HOTEND_PID "Hotend PID"
#define STR_BED_PID "Bed PID"
#define STR_CHAMBER_PID "Chamber PID"
+3
View File
@@ -766,6 +766,9 @@ private:
static void M104_M109(const bool isM109);
FORCE_INLINE static void M104() { M104_M109(false); }
FORCE_INLINE static void M109() { M104_M109(true); }
#if ENABLED(AUTOTEMP)
static void M104_report(const bool forReplay=true);
#endif
#endif
static void M105();
+19 -1
View File
@@ -70,6 +70,9 @@
* (used by printingIsActive, etc.) and turning off heaters will stop the timer.
*/
void GcodeSuite::M104_M109(const bool isM109) {
#if ENABLED(AUTOTEMP)
if (!isM109 && !parser.seen_any()) return M104_report();
#endif
if (DEBUGGING(DRYRUN)) return;
@@ -125,10 +128,25 @@ void GcodeSuite::M104_M109(const bool isM109) {
thermalManager.set_heating_message(target_extruder, !isM109 && got_temp);
}
TERN_(AUTOTEMP, planner.autotemp_M104_M109());
TERN_(AUTOTEMP, thermalManager.autotemp_M104_M109());
if (isM109 && got_temp)
(void)thermalManager.wait_for_hotend(target_extruder, no_wait_for_cooling);
}
#if ENABLED(AUTOTEMP)
//
// Report AUTOTEMP settings saved to EEPROM
//
void GcodeSuite::M104_report(const bool forReplay/*=true*/) {
TERN_(MARLIN_SMALL_BUILD, return);
report_heading_etc(forReplay, F(STR_AUTOTEMP));
SERIAL_ECHOLNPGM(" M104"
" S", thermalManager.autotemp.cfg.min,
" B", thermalManager.autotemp.cfg.max,
" F", thermalManager.autotemp.cfg.factor
);
}
#endif
#endif // HAS_HOTEND
+3 -3
View File
@@ -325,9 +325,9 @@ void menu_backlash();
// Autotemp, Min, Max, Fact
//
#if ALL(AUTOTEMP, HAS_TEMP_HOTEND)
EDIT_ITEM(int3, MSG_MIN, &planner.autotemp.min, 0, thermalManager.hotend_max_target(0));
EDIT_ITEM(int3, MSG_MAX, &planner.autotemp.max, 0, thermalManager.hotend_max_target(0));
EDIT_ITEM(float42_52, MSG_FACTOR, &planner.autotemp.factor, 0, 10);
EDIT_ITEM(int3, MSG_MIN, &thermalManager.autotemp.cfg.min, 0, thermalManager.hotend_max_target(0));
EDIT_ITEM(int3, MSG_MAX, &thermalManager.autotemp.cfg.max, 0, thermalManager.hotend_max_target(0));
EDIT_ITEM(float42_52, MSG_FACTOR, &thermalManager.autotemp.cfg.factor, 0, 10);
#endif
//
+1 -1
View File
@@ -154,7 +154,7 @@ void menu_temperature() {
EDIT_ITEM_FAST(int3, MSG_NOZZLE, &editable.celsius, 0, thermalManager.hotend_max_target(0), []{ thermalManager.setTargetHotend(editable.celsius, 0); });
#elif HAS_MULTI_HOTEND
HOTEND_LOOP() {
editable.celsius = thermalManager.temp_hotend[e].target;
editable.celsius = thermalManager.degTargetHotend(e);
EDIT_ITEM_FAST_N(int3, e, MSG_NOZZLE_N, &editable.celsius, 0, thermalManager.hotend_max_target(e), []{ thermalManager.setTargetHotend(editable.celsius, MenuItemBase::itemIndex); });
}
#endif
+6 -3
View File
@@ -125,10 +125,13 @@ void menu_tune() {
// Nozzle [1-4]:
//
#if HOTENDS == 1
EDIT_ITEM_FAST(int3, MSG_NOZZLE, &thermalManager.temp_hotend[0].target, 0, thermalManager.hotend_max_target(0), []{ thermalManager.start_watching_hotend(0); });
editable.celsius = thermalManager.degTargetHotend(0);
EDIT_ITEM_FAST(int3, MSG_NOZZLE, &editable.celsius, 0, thermalManager.hotend_max_target(0), []{ thermalManager.setTargetHotend(editable.celsius, 0); });
#elif HAS_MULTI_HOTEND
HOTEND_LOOP()
EDIT_ITEM_FAST_N(int3, e, MSG_NOZZLE_N, &thermalManager.temp_hotend[e].target, 0, thermalManager.hotend_max_target(e), []{ thermalManager.start_watching_hotend(MenuItemBase::itemIndex); });
HOTEND_LOOP() {
editable.celsius = thermalManager.degTargetHotend(e);
EDIT_ITEM_FAST_N(int3, e, MSG_NOZZLE_N, &editable.celsius, 0, thermalManager.hotend_max_target(e), []{ thermalManager.setTargetHotend(editable.celsius, MenuItemBase::itemIndex); });
}
#endif
#if ENABLED(SINGLENOZZLE_STANDBY_TEMP)
+3 -2
View File
@@ -236,9 +236,10 @@ void Touch::touch(touch_control_t * const control) {
#if HAS_HOTEND
#define HOTEND_HEATER(N) TERN0(HAS_MULTI_HOTEND, N)
TERN_(HAS_MULTI_HOTEND, MenuItemBase::itemIndex = heater);
editable.celsius = thermalManager.degTargetHotend(HOTEND_HEATER(heater));
MenuItem_int3::action(GET_TEXT_F(TERN(HAS_MULTI_HOTEND, MSG_NOZZLE_N, MSG_NOZZLE)),
&thermalManager.temp_hotend[HOTEND_HEATER(heater)].target, 0, thermalManager.hotend_max_target(HOTEND_HEATER(heater)),
[]{ thermalManager.start_watching_hotend(HOTEND_HEATER(MenuItemBase::itemIndex)); }
&editable.celsius, 0, thermalManager.hotend_max_target(HOTEND_HEATER(heater)),
[]{ thermalManager.setTargetHotend(editable.celsius, HOTEND_HEATER(MenuItemBase::itemIndex)); }
);
#endif
break;
+4 -56
View File
@@ -211,10 +211,6 @@ uint32_t Planner::max_acceleration_steps_per_s2[DISTINCT_AXES]; // (steps/s^2) D
skew_factor_t Planner::skew_factor; // Initialized by settings.load
#endif
#if ENABLED(AUTOTEMP)
autotemp_t Planner::autotemp = { AUTOTEMP_MIN, AUTOTEMP_MAX, AUTOTEMP_FACTOR, false };
#endif
// private:
xyze_long_t Planner::position{0};
@@ -1339,7 +1335,8 @@ void Planner::check_axes_activity() {
//
TERN_(HAS_TAIL_FAN_SPEED, if (fans_need_update) sync_fan_speeds(tail_fan_speed));
TERN_(AUTOTEMP, autotemp_task());
// Update hotend temperature based on extruder speed
TERN_(AUTOTEMP, thermalManager.autotemp_task());
#if ENABLED(BARICUDA)
TERN_(HAS_HEATER_1, hal.set_pwm_duty(pin_t(HEATER_1_PIN), tail_valve_pressure));
@@ -1349,51 +1346,7 @@ void Planner::check_axes_activity() {
#if ENABLED(AUTOTEMP)
#if ENABLED(AUTOTEMP_PROPORTIONAL)
void Planner::_autotemp_update_from_hotend() {
const celsius_t target = thermalManager.degTargetHotend(active_extruder);
autotemp.min = target + AUTOTEMP_MIN_P;
autotemp.max = target + AUTOTEMP_MAX_P;
}
#endif
/**
* Called after changing tools to:
* - Reset or re-apply the default proportional autotemp factor.
* - Enable autotemp if the factor is non-zero.
*/
void Planner::autotemp_update() {
_autotemp_update_from_hotend();
autotemp.factor = TERN0(AUTOTEMP_PROPORTIONAL, AUTOTEMP_FACTOR_P);
autotemp.enabled = autotemp.factor != 0;
}
/**
* Called by the M104/M109 commands after setting Hotend Temperature
*/
void Planner::autotemp_M104_M109() {
_autotemp_update_from_hotend();
if (parser.seenval('S')) autotemp.min = parser.value_celsius();
if (parser.seenval('B')) autotemp.max = parser.value_celsius();
// When AUTOTEMP_PROPORTIONAL is enabled, F0 disables autotemp.
// Normally, leaving off F also disables autotemp.
autotemp.factor = parser.seen('F') ? parser.value_float() : TERN0(AUTOTEMP_PROPORTIONAL, AUTOTEMP_FACTOR_P);
autotemp.enabled = autotemp.factor != 0;
}
/**
* Called every so often to adjust the hotend target temperature
* based on the extrusion speed, which is calculated from the blocks
* currently in the planner.
*/
void Planner::autotemp_task() {
static float oldt = 0.0f;
if (!autotemp.enabled) return;
if (thermalManager.degTargetHotend(active_extruder) < autotemp.min - 2) return; // Below the min?
float Planner::get_high_e_speed() {
float high = 0.0f;
for (uint8_t b = block_buffer_tail; b != block_buffer_head; b = next_block_index(b)) {
const block_t * const block = &block_buffer[b];
@@ -1402,12 +1355,7 @@ void Planner::check_axes_activity() {
NOLESS(high, se);
}
}
float t = autotemp.min + high * autotemp.factor;
LIMIT(t, autotemp.min, autotemp.max);
if (t < oldt) t = t * (1.0f - (AUTOTEMP_OLDWEIGHT)) + oldt * (AUTOTEMP_OLDWEIGHT);
oldt = t;
thermalManager.setTargetHotend(t, active_extruder);
return high;
}
#endif // AUTOTEMP
+6 -23
View File
@@ -32,6 +32,8 @@
#include "../MarlinCore.h"
#include "temperature.h"
#if ENABLED(JD_HANDLE_SMALL_SEGMENTS)
// Enable this option for perfect accuracy but maximum
// computation. Should be fine on ARM processors.
@@ -165,14 +167,6 @@ typedef struct {
} block_flags_t;
#if ENABLED(AUTOTEMP)
typedef struct {
celsius_t min, max;
float factor;
bool enabled;
} autotemp_t;
#endif
#if ENABLED(LASER_FEATURE)
typedef struct {
@@ -679,6 +673,10 @@ class Planner {
// Manage fans, paste pressure, etc.
static void check_axes_activity();
#if ENABLED(AUTOTEMP)
static float get_high_e_speed();
#endif
// Apply fan speeds
#if HAS_FAN
static void sync_fan_speeds(uint8_t (&fan_speed)[FAN_COUNT]);
@@ -1104,13 +1102,6 @@ class Planner {
static void clear_block_buffer_runtime();
#endif
#if ENABLED(AUTOTEMP)
static autotemp_t autotemp;
static void autotemp_update();
static void autotemp_M104_M109();
static void autotemp_task();
#endif
#if HAS_LINEAR_E_JERK
FORCE_INLINE static void recalculate_max_e_jerk() {
const float prop = junction_deviation_mm * SQRT(0.5) / (1.0f - SQRT(0.5));
@@ -1121,14 +1112,6 @@ class Planner {
private:
#if ENABLED(AUTOTEMP)
#if ENABLED(AUTOTEMP_PROPORTIONAL)
static void _autotemp_update_from_hotend();
#else
static void _autotemp_update_from_hotend() {}
#endif
#endif
/**
* Get the index of the next / previous block in the ring buffer
*/
+11 -14
View File
@@ -271,8 +271,7 @@ typedef struct SettingsDataStruct {
// AUTOTEMP
//
#if ENABLED(AUTOTEMP)
celsius_t planner_autotemp_max, planner_autotemp_min;
float planner_autotemp_factor;
autotemp_cfg_t planner_autotemp_cfg; // M104 S B F
#endif
//
@@ -1012,10 +1011,8 @@ void MarlinSettings::postprocess() {
// AUTOTEMP
//
#if ENABLED(AUTOTEMP)
_FIELD_TEST(planner_autotemp_max);
EEPROM_WRITE(planner.autotemp.max);
EEPROM_WRITE(planner.autotemp.min);
EEPROM_WRITE(planner.autotemp.factor);
_FIELD_TEST(planner_autotemp_cfg);
EEPROM_WRITE(thermalManager.autotemp.cfg);
#endif
//
@@ -2066,9 +2063,8 @@ void MarlinSettings::postprocess() {
// AUTOTEMP
//
#if ENABLED(AUTOTEMP)
EEPROM_READ(planner.autotemp.max);
EEPROM_READ(planner.autotemp.min);
EEPROM_READ(planner.autotemp.factor);
_FIELD_TEST(planner_autotemp_cfg);
EEPROM_READ(thermalManager.autotemp.cfg);
#endif
//
@@ -3450,11 +3446,7 @@ void MarlinSettings::reset() {
//
// AUTOTEMP
//
#if ENABLED(AUTOTEMP)
planner.autotemp.max = AUTOTEMP_MAX;
planner.autotemp.min = AUTOTEMP_MIN;
planner.autotemp.factor = AUTOTEMP_FACTOR;
#endif
TERN_(AUTOTEMP, thermalManager.autotemp.reset());
//
// X Axis Twist Compensation
@@ -3853,6 +3845,11 @@ void MarlinSettings::reset() {
#endif
gcode.say_units(); // " (in/mm)"
//
// M104 settings for AUTOTEMP
//
TERN_(AUTOTEMP, gcode.M104_report());
//
// M149 Temperature units
//
+59 -3
View File
@@ -389,6 +389,10 @@ PGMSTR(str_t_heating_failed, STR_T_HEATING_FAILED);
#endif // HAS_HOTEND
#if ENABLED(AUTOTEMP)
autotemp_t Temperature::autotemp; // Initialized by settings.load
#endif
#if HAS_TEMP_REDUNDANT
redundant_info_t Temperature::temp_redundant;
#endif
@@ -3552,7 +3556,7 @@ void Temperature::init() {
void Temperature::disable_all_heaters() {
// Disable autotemp, unpause and reset everything
TERN_(AUTOTEMP, planner.autotemp.enabled = false);
TERN_(AUTOTEMP, autotemp.enabled = false);
TERN_(PROBING_HEATERS_OFF, pause_heaters(false));
#if HAS_HOTEND
@@ -3637,7 +3641,7 @@ void Temperature::disable_all_heaters() {
singlenozzle_temp[old_tool] = temp_hotend[0].target;
if (singlenozzle_temp[new_tool] && singlenozzle_temp[new_tool] != singlenozzle_temp[old_tool]) {
setTargetHotend(singlenozzle_temp[new_tool], 0);
TERN_(AUTOTEMP, planner.autotemp_update());
TERN_(AUTOTEMP, autotemp_update());
set_heating_message(0);
(void)wait_for_hotend(0, false); // Wait for heating or cooling
}
@@ -4778,7 +4782,7 @@ void Temperature::isr() {
OPTARG(G26_CLICK_CAN_CANCEL, const bool click_to_cancel/*=false*/)
) {
#if ENABLED(AUTOTEMP)
REMEMBER(1, planner.autotemp.enabled, false);
REMEMBER(1, autotemp.enabled, false);
#endif
#if TEMP_RESIDENCY_TIME > 0
@@ -4911,6 +4915,58 @@ void Temperature::isr() {
#endif // HAS_TEMP_HOTEND
#if ENABLED(AUTOTEMP)
void Temperature::_autotemp_update_from_hotend() {
TERN_(AUTOTEMP_PROPORTIONAL, autotemp.update(degTargetHotend(active_extruder)));
}
/**
* Called after changing tools to:
* - Reset or re-apply the default proportional autotemp factor.
* - Enable autotemp if the factor is non-zero.
*/
void Temperature::autotemp_update() {
_autotemp_update_from_hotend();
autotemp.cfg.factor = TERN0(AUTOTEMP_PROPORTIONAL, AUTOTEMP_FACTOR_P);
autotemp.enabled = autotemp.cfg.factor != 0;
}
/**
* Called by the M104/M109 commands after setting Hotend Temperature
*/
void Temperature::autotemp_M104_M109() {
_autotemp_update_from_hotend();
if (parser.seenval('S')) autotemp.cfg.min = parser.value_celsius();
if (parser.seenval('B')) autotemp.cfg.max = parser.value_celsius();
// When AUTOTEMP_PROPORTIONAL is enabled, F0 disables autotemp.
// Normally, leaving off F also disables autotemp.
autotemp.cfg.factor = parser.seen('F') ? parser.value_float() : TERN0(AUTOTEMP_PROPORTIONAL, AUTOTEMP_FACTOR_P);
autotemp.enabled = autotemp.cfg.factor != 0;
}
/**
* Called every so often to adjust the hotend target temperature
* based on the extrusion speed, which is calculated from the blocks
* currently in the planner.
*/
void Temperature::autotemp_task() {
if (!autotemp.enabled) return;
if (degTargetHotend(active_extruder) < autotemp.cfg.min - 2) return; // Below the min?
// Get a highest target proportion greater than zero
float high = planner.get_high_e_speed();
// Calculate a new target, with weighted correction for a drop
float t = autotemp.calculate(high);
_setTargetHotend(t, active_extruder);
}
#endif // AUTOTEMP
#if HAS_HEATED_BED
#ifndef MIN_COOLING_SLOPE_DEG_BED
+52 -1
View File
@@ -603,6 +603,41 @@ typedef struct { raw_adc_t raw_min, raw_max; celsius_t mintemp, maxtemp; } temp_
#define HAS_FAN_LOGIC 1
#endif
#if ENABLED(AUTOTEMP)
typedef struct {
celsius_t min, max;
float factor;
} autotemp_cfg_t;
typedef struct {
autotemp_cfg_t cfg;
bool enabled;
void reset() {
cfg.min = AUTOTEMP_MIN;
cfg.max = AUTOTEMP_MAX;
cfg.factor = AUTOTEMP_FACTOR;
enabled = false;
}
#if ENABLED(AUTOTEMP_PROPORTIONAL)
void update(const celsius_t t) {
cfg.min = t + AUTOTEMP_MIN_P;
cfg.max = t + AUTOTEMP_MAX_P;
}
#endif
float calculate(const celsius_t high) {
static float oldt = 0;
float t = cfg.min + high * cfg.factor;
NOMORE(t, cfg.max);
if (t < oldt) t = t * (1.0f - (AUTOTEMP_OLDWEIGHT)) + oldt * (AUTOTEMP_OLDWEIGHT);
oldt = t;
return t;
}
} autotemp_t;
#endif // AUTOTEMP
class Temperature {
public:
@@ -1001,6 +1036,10 @@ class Temperature {
#if HAS_HOTEND
static void _setTargetHotend(const celsius_t celsius, const uint8_t E_NAME) {
temp_hotend[HOTEND_INDEX].target = _MIN(celsius, hotend_max_target(HOTEND_INDEX));
}
static void setTargetHotend(const celsius_t celsius, const uint8_t E_NAME) {
const uint8_t ee = HOTEND_INDEX;
#if PREHEAT_TIME_HOTEND_MS > 0
@@ -1010,7 +1049,8 @@ class Temperature {
start_hotend_preheat_time(ee);
#endif
TERN_(AUTO_POWER_CONTROL, if (celsius) powerManager.power_on());
temp_hotend[ee].target = _MIN(celsius, hotend_max_target(ee));
_setTargetHotend(celsius, ee);
TERN_(AUTOTEMP, autotemp.enabled = false);
start_watching_hotend(ee);
}
@@ -1052,6 +1092,13 @@ class Temperature {
#endif // HAS_HOTEND
#if ENABLED(AUTOTEMP)
static autotemp_t autotemp;
static void autotemp_update();
static void autotemp_M104_M109();
static void autotemp_task();
#endif
#if HAS_HEATED_BED
#if ENABLED(SHOW_TEMP_ADC_VALUES)
@@ -1349,6 +1396,10 @@ class Temperature {
return true;
}
#if ENABLED(AUTOTEMP)
static void _autotemp_update_from_hotend();
#endif
// MAX Thermocouples
#if HAS_MAX_TC
#define MAX_TC_COUNT TEMP_SENSOR_IS_MAX_TC(0) + TEMP_SENSOR_IS_MAX_TC(1) + TEMP_SENSOR_IS_MAX_TC(2) + TEMP_SENSOR_IS_MAX_TC(REDUNDANT)
+1 -1
View File
@@ -1581,7 +1581,7 @@ void tool_change(const uint8_t new_tool, bool no_move/*=false*/) {
// Migrate the temperature to the new hotend
#if HAS_MULTI_HOTEND
thermalManager.setTargetHotend(thermalManager.degTargetHotend(active_extruder), migration_extruder);
TERN_(AUTOTEMP, planner.autotemp_update());
TERN_(AUTOTEMP, thermalManager.autotemp_update());
thermalManager.set_heating_message(0);
thermalManager.wait_for_hotend(active_extruder);
#endif
+1 -1
View File
@@ -82,7 +82,7 @@ opt_set DEFAULT_AXIS_STEPS_PER_UNIT '{ 4000 }' \
MANUAL_FEEDRATE '{ 4*60 }' \
AXIS_RELATIVE_MODES '{ false }' \
HOMING_BUMP_MM '{}' HOMING_BUMP_DIVISOR '{}' HOMING_FEEDRATE_MM_M '{}'
opt_enable REPRAP_DISCOUNT_FULL_GRAPHIC_SMART_CONTROLLER
opt_enable REPRAP_DISCOUNT_FULL_GRAPHIC_SMART_CONTROLLER AUTOTEMP AUTOTEMP_PROPORTIONAL
opt_disable X_DRIVER_TYPE Y_DRIVER_TYPE Z_DRIVER_TYPE
exec_test $1 $2 "E Axis Only | DOGM MarlinUI" "$3"