[feature] Adaptive / Feedforward Temperature setpoint
-
Hi,
I remember this being mentioned somewhere before, maybe someone here can help where that was.It's about raising the temperature depending on the extrusion speed.
i first implemented the idea as a daemon script a few months ago https://forum.duet3d.com/post/338055The problem with increased temperature is, that the filament will burn while printing slow speed areas like top surface, outer perimeter, bridges and so on. This limits the ability to crank up the temperature e.g. for PLA you can start at 180 °C up you can not expect much performance unless you have a very long melt zone.
If you want to go fast with your normal setup you need to increase the temperature to compensate for the reduced time of the filament in the melt zone. But if you increase the temperature too much, you will burn your filament while printing slow, e.g. printing PLA at 280°C is totally fine if the time in the melt zone is below 2-3 sec.
I have found that feedforward temperature setpoint allows significantly higher extrusion rates without burning the filament.
For example, for PLA, with a 0.8mm nozzle and 220°C nozzle temperature, I achieve a maximum of 180 mm/min or 19.14 mm³/sec with 2.85mm² filament and a standard deviation of less than 0.01 -> 1%.; max F180.0 mm/min or 19.14mm³/s ; temp: 220 °C ; mean error: 0.0253076 -> 2.53076% ; min error: 0.0178955 -> 1.78955% ; max error: 0.0349438 -> 3.49438% ; standard deviation: 0.0014118 -> 0.14118%
With the dynamic temperature increase with a factor of feedforward = 8, I achieve a maximum of 330 mm/min or 35.09 mm³/sec. with a comparable standard deviation.
The formula is: new_target_temp = target_temp + avg_extrusion_speed * feedforward; max F330.0 mm/min or 35.09mm³/s ; temp: 220 °C ; mean error: 0.0090234 -> 0.90234 % ; min error: -0.0016260 -> -0.16260 % ; max error: 0.0218506 -> 2.18506 % ; standard deviation: 0.0038675 -> 0.38675%
as you can see, I've misused the heater feedforward for my implementaion.
What dou you think about it?
Surprisingly, I have found that a factor of 8 is suitable for different FIlaments e.g. PLA, PETG, PA6. Maybe someone with a deeper understanding can explain this? I am thinking of @dc42 ?
Btw. these are the non linear extrusion parameters
M592 D0 A-0.0039865 B0.0029572 L0.2
As you can see, this will also reduce the NLE values
-
@timschneider Interesting! There is a discussion in the OrcaSlicer community about this, see https://github.com/SoftFever/OrcaSlicer/discussions/5057, and an implementation as a post-slicing app here https://github.com/sb53systems/G-Code-Flow-Temperature-Controller
I think while it could be firmware controlled, a slicer implementation might be more desirable.
Ian
-
@timschneider interesting! This could be implemented as an extension to M309, https://docs.duet3d.com/User_manual/Reference/Gcodes#m309-set-or-report-heater-feedforward, perhaps by adding a T parameter to specify the temperature increase(s) per unit of extrusion speed.
-
@droftarts said in [feature] Adaptive / Feedforward Temperature setpoint:
@timschneider Interesting! There is a discussion in the OrcaSlicer community about this, see https://github.com/SoftFever/OrcaSlicer/discussions/5057, and an implementation as a post-slicing app here https://github.com/sb53systems/G-Code-Flow-Temperature-Controller
I think while it could be firmware controlled, a slicer implementation might be more desirable.
Ian
hey cool - yes i though that a slicer implementaion is even better, but the problem is the calibration of it, it takes ages to calibrate the PA and NLE for every setpoint and since we can automatically calculate the NLE in the printer as a macro, we can also tune the adaptive temp control with it, automatically.
-
@dc42
do you mean something like the following:From 83be8a6fac88110fc62f6e105f522ef601164b69 Mon Sep 17 00:00:00 2001 From: Tim Schneider <tim@schneider.engineering> Date: Wed, 21 Aug 2024 14:22:41 +0200 Subject: [PATCH] - M309: added T parameter to specify the temperature increase(s) per unit of extrusion speed --- src/Heating/Heat.cpp | 4 ++-- src/Heating/Heat.h | 2 +- src/Heating/Heater.h | 2 +- src/Heating/LocalHeater.cpp | 17 +++++++++++++---- src/Heating/LocalHeater.h | 4 +++- src/Heating/RemoteHeater.h | 2 +- src/Tools/Tool.cpp | 15 +++++++++++++-- src/Tools/Tool.h | 1 + 8 files changed, 35 insertions(+), 12 deletions(-) diff --git a/src/Heating/Heat.cpp b/src/Heating/Heat.cpp index 397c25bd..cd4cb7d0 100644 --- a/src/Heating/Heat.cpp +++ b/src/Heating/Heat.cpp @@ -876,14 +876,14 @@ void Heat::FeedForwardAdjustment(unsigned int heater, float fanPwmChange, float } // This one is called from an ISR so we must not get a lock -void Heat::SetExtrusionFeedForward(unsigned int heater, float pwm) const noexcept +void Heat::SetExtrusionFeedForward(unsigned int heater, float pwm, float degree) const noexcept { if (heater < MaxHeaters) { Heater * const h = heaters[heater]; if (h != nullptr) { - h->SetExtrusionFeedForward(pwm); + h->SetExtrusionFeedForward(pwm, degree); } } } diff --git a/src/Heating/Heat.h b/src/Heating/Heat.h index 7ca1e5e4..5e49680b 100644 --- a/src/Heating/Heat.h +++ b/src/Heating/Heat.h @@ -128,7 +128,7 @@ public: GCodeResult SetActiveOrStandby(int heater, const Tool *tool, bool active, const StringRef& reply) noexcept; // Turn a heater on void SwitchOff(int heater) noexcept; // Turn off a specific heater void FeedForwardAdjustment(unsigned int heater, float fanPwmChange, float extrusionChange) const noexcept; - void SetExtrusionFeedForward(unsigned int heater, float pwm) const noexcept; + void SetExtrusionFeedForward(unsigned int heater, float pwm, float degree) const noexcept; #if HAS_MASS_STORAGE || HAS_SBC_INTERFACE bool WriteModelParameters(FileStore *f) const noexcept; // Write heater model parameters to file returning true if no error diff --git a/src/Heating/Heater.h b/src/Heating/Heater.h index 64f61666..b71f3405 100644 --- a/src/Heating/Heater.h +++ b/src/Heating/Heater.h @@ -57,7 +57,7 @@ public: virtual void Suspend(bool sus) noexcept = 0; // Suspend the heater to conserve power or while doing Z probing virtual float GetAccumulator() const noexcept = 0; // Get the inertial term accumulator virtual void FeedForwardAdjustment(float fanPwmChange, float extrusionChange) noexcept = 0; - virtual void SetExtrusionFeedForward(float pwm) noexcept = 0; + virtual void SetExtrusionFeedForward(float pwm, float degree) noexcept = 0; #if SUPPORT_CAN_EXPANSION virtual bool IsLocal() const noexcept = 0; diff --git a/src/Heating/LocalHeater.cpp b/src/Heating/LocalHeater.cpp index 9059d7f2..eaff1314 100644 --- a/src/Heating/LocalHeater.cpp +++ b/src/Heating/LocalHeater.cpp @@ -86,7 +86,7 @@ void LocalHeater::ResetHeater() noexcept mode = HeaterMode::off; previousTemperaturesGood = 0; previousTemperatureIndex = 0; - iAccumulator = extrusionBoost = 0.0; + iAccumulator = extrusionBoost = extrusionTemperatureBoost = lastExtrusionTemperatureBoost = 0.0; badTemperatureCount = 0; averagePWM = lastPwm = 0.0; heatingFaultCount = 0; @@ -189,7 +189,7 @@ GCodeResult LocalHeater::SwitchOn(const StringRef& reply) noexcept return GCodeResult::error; } - const float target = GetTargetTemperature(); + const float target = min<float>(GetTargetTemperature() + extrusionTemperatureBoost, GetHighestTemperatureLimit()); const HeaterMode newMode = (temperature + TemperatureCloseEnough < target) ? HeaterMode::heating : (temperature > target + TemperatureCloseEnough) ? HeaterMode::cooling : HeaterMode::stable; @@ -282,9 +282,17 @@ void LocalHeater::Spin() noexcept if (GetModel().IsEnabled()) { // Get the target temperature and the error - const float targetTemperature = GetTargetTemperature(); + const float targetTemperature = min<float>(GetTargetTemperature() + extrusionTemperatureBoost, GetHighestTemperatureLimit()); const float error = targetTemperature - temperature; + if (extrusionTemperatureBoost != 0.0 || lastExtrusionTemperatureBoost != extrusionTemperatureBoost) + { + // calculate new heater mode to prevent heater fault due to exceededAllowedExcursion + String<1> dummy; + (void)SwitchOn(dummy.GetRef()); + } + lastExtrusionTemperatureBoost = extrusionTemperatureBoost; + // Do the heating checks switch(mode) { @@ -570,9 +578,10 @@ void LocalHeater::FeedForwardAdjustment(float fanPwmChange, float extrusionChang } // Set extrusion feedforward. This is called from an ISR. -void LocalHeater::SetExtrusionFeedForward(float pwm) noexcept +void LocalHeater::SetExtrusionFeedForward(float pwm, float degree) noexcept { extrusionBoost = pwm; + extrusionTemperatureBoost = degree; } /* Notes on the auto tune algorithm diff --git a/src/Heating/LocalHeater.h b/src/Heating/LocalHeater.h index cf0840c5..d5a18221 100644 --- a/src/Heating/LocalHeater.h +++ b/src/Heating/LocalHeater.h @@ -39,7 +39,7 @@ public: float GetAccumulator() const noexcept override; // Return the integral accumulator void Suspend(bool sus) noexcept override; // Suspend the heater to conserve power or while doing Z probing void FeedForwardAdjustment(float fanPwmChange, float extrusionChange) noexcept override; - void SetExtrusionFeedForward(float pwm) noexcept override; // Set extrusion feedforward + void SetExtrusionFeedForward(float pwm, float degree) noexcept override; // Set extrusion feedforward #if SUPPORT_CAN_EXPANSION bool IsLocal() const noexcept override { return true; } void UpdateRemoteStatus(CanAddress src, const CanHeaterReport& report) noexcept override { } @@ -76,6 +76,8 @@ private: float lastPwm; // The last PWM value set for this heater float averagePWM; // The running average of the PWM, after scaling. volatile float extrusionBoost; // The amount of extrusion feedforward to apply + volatile float extrusionTemperatureBoost; // The amount of extrusion feedforward to apply + float lastExtrusionTemperatureBoost; // The amount of extrusion feedforward to apply float lastTemperatureValue; // the last temperature we recorded while heating up uint32_t lastTemperatureMillis; // when we recorded the last temperature uint32_t timeSetHeating; // When we turned on the heater diff --git a/src/Heating/RemoteHeater.h b/src/Heating/RemoteHeater.h index a6c09029..a30872d7 100644 --- a/src/Heating/RemoteHeater.h +++ b/src/Heating/RemoteHeater.h @@ -30,7 +30,7 @@ public: float GetAccumulator() const noexcept override; // Return the integral accumulator void Suspend(bool sus) noexcept override; // Suspend the heater to conserve power or while doing Z probing void FeedForwardAdjustment(float fanPwmChange, float extrusionChange) noexcept override; - void SetExtrusionFeedForward(float pwm) noexcept override { } // We can't yet set feedforward on remote heaters because this is called from an ISR + void SetExtrusionFeedForward(float pwm, float degree) noexcept override { } // We can't yet set feedforward on remote heaters because this is called from an ISR bool IsLocal() const noexcept override { return false; } void UpdateRemoteStatus(CanAddress src, const CanHeaterReport& report) noexcept override; void UpdateHeaterTuning(CanAddress src, const CanMessageHeaterTuningReport& msg) noexcept override; diff --git a/src/Tools/Tool.cpp b/src/Tools/Tool.cpp index c0676b8f..b41174c9 100644 --- a/src/Tools/Tool.cpp +++ b/src/Tools/Tool.cpp @@ -946,6 +946,12 @@ GCodeResult Tool::GetSetFeedForward(GCodeBuffer& gb, const StringRef& reply) THR gb.GetFloatArray(heaterFeedForward, numValues, false); ToolUpdated(); } + else if (gb.Seen('T')) + { + size_t numValues = heaterCount; + gb.GetFloatArray(temperatureFeedForward, numValues, false); + ToolUpdated(); + } else { reply.printf("Tool %u heater feedforward:", myNumber); @@ -953,6 +959,11 @@ GCodeResult Tool::GetSetFeedForward(GCodeBuffer& gb, const StringRef& reply) THR { reply.catf(" %.3f", (double)heaterFeedForward[i]); } + reply.printf("Tool %u temperature feedforward:", myNumber); + for (size_t i = 0; i < heaterCount; ++i) + { + reply.catf(" %.3f", (double)temperatureFeedForward[i]); + } } return GCodeResult::ok; @@ -964,7 +975,7 @@ void Tool::ApplyFeedForward(float extrusionSpeed) const noexcept Heat& heat = reprap.GetHeat(); for (size_t i = 0; i < heaterCount; ++i) { - heat.SetExtrusionFeedForward(heaters[i], extrusionSpeed * heaterFeedForward[i]); + heat.SetExtrusionFeedForward(heaters[i], extrusionSpeed * heaterFeedForward[i], extrusionSpeed * temperatureFeedForward[i]); } } @@ -974,7 +985,7 @@ void Tool::StopFeedForward() const noexcept Heat& heat = reprap.GetHeat(); for (size_t i = 0; i < heaterCount; ++i) { - heat.SetExtrusionFeedForward(heaters[i], 0.0); + heat.SetExtrusionFeedForward(heaters[i], 0.0, 0.0); } } diff --git a/src/Tools/Tool.h b/src/Tools/Tool.h index 2c2e5afb..e071000b 100644 --- a/src/Tools/Tool.h +++ b/src/Tools/Tool.h @@ -188,6 +188,7 @@ private: float activeTemperatures[MaxHeatersPerTool]; float standbyTemperatures[MaxHeatersPerTool]; float heaterFeedForward[MaxHeatersPerTool]; + float temperatureFeedForward[MaxHeatersPerTool]; // Firmware retraction settings float retractLength, retractExtra; // retraction length and extra length to un-retract -- 2.39.2.windows.1
I'm not sure about the change of the method interface and so on but if it is heading in the right direction I can prepare a merge request.
Update
The implementation will not fit into Duet2 due to too less rom.
It will fit if the wifi is compiled without W5500 and the ethernet without WIFI
or both without FTP and Telnet support -
-
@droftarts I was just about to post a question regarding feed forward till I found this post.
I think the feedforwwar tool doesnt cover all the issue. As mentioned here, you can print perfectly PLA at 180 degrees with excelent quality, BUT you will be restricted on how fast you can print. On the other hand, you can print PLA at 150 mm/s on a 0.8 nozzle only if you go up in your temp to 230 degrees oir little more, but as soon as you slow down you quality goes to the trash bin because of that excesive temp.The feedforward config at least to me has not solved this in my prints, I have to either choose print really fast and hot or normal/slow and "cold". My question was going to be if the feedforward command could add some type of algorithm to take into account the cubic mms being extruded instead of the printing speed, in that way you would be covering all nozzle spectrum and printing speed at the same time.
And regarding where: I think the oposite. It should be the formware the one in charge of that because the slicer never knows the real speed of a path. Final real speed is decided by firmware, the slciewr never knows the real printing speed (and that is the reason why the time calculation on slicer are allways really off)
-
@Tinchus said in [feature] Adaptive / Feedforward Temperature setpoint:
And regarding where: I think the oposite. It should be the formware the one in charge of that because the slicer never knows the real speed of a path. Final real speed is decided by firmware, the slciewr never knows the real printing speed (and that is the reason why the time calculation on slicer are allways really off)
Thats a good point!
I made a PR for this https://github.com/Duet3D/RepRapFirmware/pull/1036
But due to memory contrains, it will not fit in the ROM of a regular Duet2 combined firmware. You need to disable other not important features to make it work e.g. Telnet and FTP.
-
@timschneider I wonder if temp increase VS speed will be ok when you change to a bigger noozle and you go slow; in that situation you would have a potential huge increment of mm3/s but a lower speed. Example: 100 MM/s speed with a 0.4 noozle . The you switch to a 0.8 nozzle and go to 80 mm/s
-
@Tinchus it is extruder speed e.g. movement of filament per sec, not travel speed so it is accounting for that. I print with 0.8mm to 1.2mm nozzles.
-
@timschneider that is what I meant. May be Im wrong so please clarify: the push request is using the new requested T parameter in terms of extrusion speed or volumentric speed? Because the firmeware actually never knows what size of nozzle you are using: if slicer request a 10 mm/s extrusion move and you are using a 0.8 nozzle volumen and needed temperature will be quite dfifferent if the slicer request the same speed but you are using a 0.4 nozzle. am I wrong?
-
@Tinchus, it's the extrusion speed. So I use 2.85 mm filament and if I use an extrusion speed of 1 mm/s, for example, it is about 6.38 mm³/s, regardless of the nozzle size. The only difference between extrusion speed and volume speed is the area of the filament, e.g. for 2.85 mm filament 6.38 mm² and thus only a factor.
-
@timschneider said in [feature] Adaptive / Feedforward Temperature setpoint:
So I use 2.85 mm filament
I thought it was just me using up everyone else's 2.85mm filament! If I ever get my Trident-ish machine finished, I've got a Titan extruder with volcano CHT nozzles (probably 1mm nozzle dia) tool earmarked for it, to get through all the old stock (after it's spent time in the filament dryer), and print big things fast! So some form of temperature feedforward would be good.
Ian