Skip to content

RFC: Cooperative Heaters predictive control#6837

Open
nefelim4ag wants to merge 2 commits intoKlipper3d:masterfrom
nefelim4ag:heaters-predictive-control
Open

RFC: Cooperative Heaters predictive control#6837
nefelim4ag wants to merge 2 commits intoKlipper3d:masterfrom
nefelim4ag:heaters-predictive-control

Conversation

@nefelim4ag
Copy link
Copy Markdown
Collaborator

@nefelim4ag nefelim4ag commented Feb 25, 2025

Some time ago I dug heaters a little on the Discourse

I don't think PID is bad or needs to be replaced.
I tried to do some fun stuff, like train DNN or write my own algo to control the power.
In the end, everything looks the same.

There are historically various topics, that try to replace it or tune it differently.
I think the only practical reason is to handle something important for that human being.

So, there is an ultimate solution, I think.
Pid is still under the control of a heater and is able to drive it.
The end-user has the ability to adjust it freely, like in my doc example - drive PWM in a feedforward way if the fan is suddenly enabled, like for bridges.

If it is needed, it is definitely possible to get the current chamber temperature, adjust to the fan curve, try to parse the extruder moving queue (IDK) and drive PWM higher before the temperature falls and PID will reactively compensate for that.
I hope that will add enough flexibility to stop rituals like "how to do PID autotune properly".

Another example, for some reason people do not insulate the heating beds, adding thermistors inside a thick aluminum plate and then want sort of PID control by two thermistors, and feel that combined sensor is not good enough.

Well, now it is possible to literally query the sensors and decide what to do, like return the -N value and decrease bed heater power on demand.

I hope it is made in a way to is safe and acceptable, leaves all existing safety measures in place, and mostly does not touch safety-critical code.

Thanks.


Btw, I will try to add templates to temperature FANs in a similar way, to fit most of the wishes, like curves, formulas & etc.


cd ~/klipper
git fetch origin pull/6837/head
git checkout FETCH_HEAD
sudo systemctl restart klipper

@nefelim4ag nefelim4ag changed the title Cooperative Heaters predictive control RFC: Cooperative Heaters predictive control Feb 25, 2025
@nefelim4ag nefelim4ag force-pushed the heaters-predictive-control branch 5 times, most recently from 097a22c to 1b115b6 Compare February 26, 2025 01:42
@Sineos
Copy link
Copy Markdown
Collaborator

Sineos commented Feb 26, 2025

Nice!
It seems to follow the same logic as display templates. Maybe stick to the general wording and naming from there?

@nefelim4ag
Copy link
Copy Markdown
Collaborator Author

Maybe stick to the general wording and naming from there?

I imported some changes from there, and I hope, now it is a little better.

@Sineos
Copy link
Copy Markdown
Collaborator

Sineos commented Feb 27, 2025

From the eyes emoticon, I gather you found my comment confusing. What I tried to say:

The display template functions in Klipper for LEDs and fans (example) seem to be using the same overarching logic, albeit with a bit of different nomenclature.
Maybe I'm misunderstanding something?

@nefelim4ag
Copy link
Copy Markdown
Collaborator Author

nefelim4ag commented Feb 27, 2025

The display template functions in Klipper for LEDs and fans (example) seem to be using the same overarching logic, albeit with a bit of different nomenclature.

I got the idea of what you meant after your comment in the temperature_fan PR.
I'm looking for what can be done to make it similar to current integration with `[display_templates]'.
The current integration feels a little unintuitive from my perspective, but it is better to reuse it, of course.

Thanks for checking. I was totally unaware of that functionality, now I will try to wrap my head around it.

@nefelim4ag
Copy link
Copy Markdown
Collaborator Author

I don't know how I feel about adding a G-code command to reload the template or directly alter the PWM output.
I also think it is wrong to add custom value get/set/log functions to all templates by incorporating them in display_template.
So, I dropped them for now.

So, for now, I only leave here a bare config binding between template and heater.
If it is needed, technically, temperature and read time can be propagated in the template context.
But I think they are mostly useless without state management inside macro.

Thanks.

@KevinOConnor
Copy link
Copy Markdown
Collaborator

Interesting. I'm not sure this implementation is safe though, as the PID temperature_update() code is called from a background thread (serialhdl:_bg_thread()) and I don't know what would happen if one tried to render templates from that thread. Certainly if the template accessed any of the {printer.module.xxx} values it would result in get_status() calls from the background thread which would not be safe.

I suspect we could alter the target temperature from templates without thread issues (or set a temperature offset), but I'm not sure if that's what you are looking for.

Still interesting though.
-Kevin

@nefelim4ag
Copy link
Copy Markdown
Collaborator Author

code is called from a background thread (serialhdl:_bg_thread()) and I don't know what would happen if one tried to render templates from that thread

I will change it to run in a similar fashion to current fan/led templates in the main/reactor thread.
And pass shared value to offset PWM.
It seems simpler to do locks with one shared value.
The only tricky part would be to run it close before PWM calculation to make it semi-synchronized.
Maybe use the last PWM evaluation time and schedule the timer in <300ms after that.
Even though it will mostly retain the suggested functionality.

I suspect we could alter the target temperature from templates without thread issues (or set a temperature offset), but I'm not sure if that's what you are looking for.

AFAIK, it is only useful if the target is to use variable extrusion temperature based on the flow. AFAIK, there is at least one project for that: https://github.com/sb53systems/G-Code-Flow-Temperature-Controller

It can be made on the Klipper side, but I suspect it is requires different design to trigger temperature changes ahead and do other stuff like accounting for thermal inertia/slow down printing.
So, I suspect it is easier to do as an external extension/gcode preprocessor.

Thanks.

@github-actions
Copy link
Copy Markdown

Thank you for your contribution to Klipper. Unfortunately, a reviewer has not assigned themselves to this GitHub Pull Request. All Pull Requests are reviewed before merging, and a reviewer will need to volunteer. Further information is available at: https://www.klipper3d.org/CONTRIBUTING.html

There are some steps that you can take now:

  1. Perform a self-review of your Pull Request by following the steps at: https://www.klipper3d.org/CONTRIBUTING.html#what-to-expect-in-a-review
    If you have completed a self-review, be sure to state the results of that self-review explicitly in the Pull Request comments. A reviewer is more likely to participate if the bulk of a review has already been completed.
  2. Consider opening a topic on the Klipper Discourse server to discuss this work. The Discourse server is a good place to discuss development ideas and to engage users interested in testing. Reviewers are more likely to prioritize Pull Requests with an active community of users.
  3. Consider helping out reviewers by reviewing other Klipper Pull Requests. Taking the time to perform a careful and detailed review of others work is appreciated. Regular contributors are more likely to prioritize the contributions of other regular contributors.

Unfortunately, if a reviewer does not assign themselves to this GitHub Pull Request then it will be automatically closed. If this happens, then it is a good idea to move further discussion to the Klipper Discourse server. Reviewers can reach out on that forum to let you know if they are interested and when they are available.

Best regards,
~ Your friendly GitIssueBot

PS: I'm just an automated script, not a human being.

@nefelim4ag nefelim4ag force-pushed the heaters-predictive-control branch from 77f03eb to fbfecee Compare April 29, 2025 23:20
@nefelim4ag
Copy link
Copy Markdown
Collaborator Author

I realized there is no example, so this one is for the extruder heater with accounting for fan losses and the losses due to the volumetric flow.

[display_template extruder]
text:
  {% set pwr_adj = printer.fan.speed * 0.15 %}
  {% set flow = printer.motion_report.live_extruder_velocity * (1.75 / 2)**2 * 3.1415 %}
  # 25 is around max flow, a simple, linear equation
  # 25 mm^3/s requires at least +40% of PWM
  { pwr_adj + flow/25 * 0.4 }

[heater_pc extruder]
macro_template: extruder

@nefelim4ag
Copy link
Copy Markdown
Collaborator Author

nefelim4ag commented Oct 9, 2025

Example of 2 termistors bed control to limit the bed heater temperature.
https://klipper.discourse.group/t/thick-bed-temperature-controll/24940/48

[display_template bed_limiter]
text:
  {% set bed_heater_temp = printer['temperature_sensor bed_heater'].temperature | float %}
  {% set max_temp = 100 %}
  {% set range = 5 %}
  {% set proportional_damping = (bed_heater_temp - (max_temp - range / 2))/range %}
  {0 if proportional_damping < 0 else proportional_damping * -1 }

[heater_pc heater_bed]
macro_template: bed_limiter

This is my example of reducing the chamber heater power until the heater bed is done to heat, to limit the peak power.

[display_template chamber]
text:
  { -1.0 * printer["heater_bed"].power }

[heater_pc chamber]
macro_template: chamber

There is an error with how I rescheduled the timer before the PWM code, so the template runs several times before the next PWM arrives. I will fix that.
Fixed.

@nefelim4ag nefelim4ag force-pushed the heaters-predictive-control branch 4 times, most recently from 400fda4 to 3e5fc95 Compare October 10, 2025 02:18
@nefelim4ag nefelim4ag force-pushed the heaters-predictive-control branch from 3e5fc95 to bbfffa7 Compare October 22, 2025 21:20
@nefelim4ag nefelim4ag force-pushed the heaters-predictive-control branch 2 times, most recently from 15daf6d to 40054ce Compare January 9, 2026 05:44
@nefelim4ag nefelim4ag force-pushed the heaters-predictive-control branch from 40054ce to 04b7f25 Compare January 9, 2026 05:45
@nefelim4ag nefelim4ag force-pushed the heaters-predictive-control branch 2 times, most recently from 2909ce7 to c6937ee Compare January 26, 2026 12:52
@nefelim4ag nefelim4ag force-pushed the heaters-predictive-control branch from c6937ee to 2517b47 Compare February 7, 2026 22:15
@nefelim4ag nefelim4ag force-pushed the heaters-predictive-control branch from 2517b47 to aa4484e Compare February 28, 2026 15:38
@nefelim4ag
Copy link
Copy Markdown
Collaborator Author

nefelim4ag commented Feb 28, 2026

I had a long idea that my initial implementation with hooks into the PID loop is hacky.
After recent conversations around PID Calibration, Integer windups, & etc, I realized that actually, I can make it pluggable.
Also, there are temperature fans' control loops, which are mostly copy paste of heaters' control loops.

So, here is internal refactoring for the heaters' control, which now returns control output.
That way, without any hooks, I can amend the control with feed-forward with simple wrappers.

The same refactoring can be done for the fans, where the same control loop can be reused; the only difference is that temperature fans need to invert the control output, basically do -1 * co.

With that, it is possible to later reuse the existing PID_CALIBRATE for the fans.

Thanks,
-Timofey


Hmmm,
It is also possible to reuse the existing PrinterTemplateEvaluator. But I feel it would make sense to make templates less ambiguous, output_pin_template, led_template, and so on, and to validate the output during the connect phase.
Instead of "silently" logging the template errors.


Reused

This allows to chain the control later,
or reuse same control loops for the fan for example

Signed-off-by: Timofey Titovets <nefelim4ag@gmail.com>
Allows for the amendment of the real control loop
with feed-forward control

Feed-forward allows for the implementation of advanced control,
such as "dual loop", using data from several temperature sensors.
Increase/decrease power beforehand without PID reactive lag.

Signed-off-by: Timofey Titovets <nefelim4ag@gmail.com>
@nefelim4ag nefelim4ag force-pushed the heaters-predictive-control branch from aa4484e to 043bb12 Compare April 3, 2026 00:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants