klipper
klipper copied to clipboard
[input_shaping] Native dual carriage support
Unfortunately, I have no hardware to test the change. So I could only run some sanity-checking using Klipper batch mode and looking at the generated serial logs. Anyone with the actual hardware, whether it is a cartesian IDEX or Hybrid CoreX? setup, who is willing to test the change is very welcome!
Thanks. What's the advantage of implementing this code as opposed to the user calling SET_INPUT_SHAPER in their T0 and T1 macros?
-Kevin
Thanks. What's the advantage of implementing this code as opposed to the user calling SET_INPUT_SHAPER in their
T0andT1macros?-Kevin
COPY and MIRROR IDEX modes that will, hopefully, eventually be merged into Klipper cannot be supported with Input Shaping using that approach, because both toolheads are active at the same time. Additionally, it is easier to override input shaping parameters of the toolheads at runtime when the toolheads are switched back and forth during printing (to be fair, this is possible today, but requires fiddling with the macro variables).
Separately, 638fa8532c91101b6b3b927ab46aa041a5e69a7f commit fixes a bug in hybrid_corex? implementation that resets the stepper alloc on a toolhead change, which disables input shaping completely.
COPY and MIRROR IDEX modes that will, hopefully, eventually be merged into Klipper cannot be supported with Input Shaping using that approach, because both toolheads are active at the same time.
Could the idex code be changed so that it can work? For example, SET_DUAL_CARRIAGE CARRIAGE=0, SET_INPUT_SHAPER ..., SET_DUAL_CARRIAGE CARRIAGE=1, SET_INPUT_SHAPER ..., SET_DUAL_CARRIAGE MODE=mirror, ... ? Perhaps @Tircown has some thoughts on this.
As a high-level comment, there are a lot of different "multi-filament" systems - idex, y-splitters, mmu/ercf, pallette2, tool changers, dual nozzle with servo activation, etc. . I fear trying to teach input_shaper (and pressure_advance) about them (or even some of them) is going to get very complex. Might be better to look at adding code/complexity to the idex code than to add that code/complexity to the input_shaper (and pressure_advance) code.
-Kevin
There are two considerations at hand here.
First, AFAICT, there is presently a bug in hybrid_corex? implementation that makes input_shaper defunct on a toolhead change. And I saw some users complaining about this issue. I think it should be fixed. The commit 638fa8532c91101b6b3b927ab46aa041a5e69a7f fixes that (pending testing), but there could be other ways to fix it. If you or @Tircown have any alternative suggestions, I'm happy to consider them. However, one nice outcome of that commit is that it also adds a Python API to transparently configure an input shaper on a per-stepper basis independently (and such C API already exists).
Then, there is a case currently not covered by the existing Klipper user API: dual carriages working together at the same time. In that case, it is presently not possible to configure the input shaper for both of them: while C API exists, Python code in input_shaper.py does not provide such an option.
However, I'm not sure about other cases like
different "multi-filament" systems - idex, y-splitters, mmu/ercf, pallette2, tool changers, dual nozzle with servo activation, etc.
AFAICT, they do not have multiple toolheads working together at the same time. But any other configuration, e.g., quad carriage

would have a similar issue. However, the latter isn't supported in Klipper presently AFAICT, is it?
In any case, this PR adds an option to configure the input shaper for dual_carriage specifically. I'm open to other suggestions though. However,
Could the idex code be changed so that it can work? For example,
SET_DUAL_CARRIAGE CARRIAGE=0,SET_INPUT_SHAPER ...,SET_DUAL_CARRIAGE CARRIAGE=1,SET_INPUT_SHAPER ...,SET_DUAL_CARRIAGE MODE=mirror, ... ? Perhaps @Tircown has some thoughts on this.
I wouldn't say it is impossible. But it will require to add a complexity elsewhere - either the idex code (both in cartesian and hybrid_corex? kinematics) should expose which carriage and which steppers are currently active, or the Toolhead class. Let me know what you think about it.
To offer another alternative for discussion myself that I considered and rejected initially, we could let users configure the input shaper on per-stepper basis, as the C API totally allows it (I think it would be similar to PA now). However, I find this specific option fairly fragile and potentially dangerous: a user may configure an input shaper differently for steppers that should have the same shaping by mistake (e.g. on a multi-rail, or on a delta printer), and this may result in a physical damage of a printer because the steppers won't pull the same carriage (or an effector) in unison. Besides, 99% of the configurations don't need that kind of flexibility.
AFAICT, they do not have multiple toolheads working together at the same time. But any other configuration, e.g., quad carriage
Indeed, all of those cases would be just fine with SET_INPUT_SHAPER, except for the quad carriage (or whatever fun new setups people come up with in the future).
we could let users configure the input shaper on per-stepper basis,
This sounds like the perfect foot gun to me, it would certainly be cool to have for advanced usage, but for the regular user shaper_type_dc, shaper_freq_dc is much easier to understand and use. Maybe both? :)
I will test this out very soon, got a few things to print first. This would've been a feature request from me as soon as duplicate/mirror support was merged, so thanks for that!
First, AFAICT, there is presently a bug in hybrid_corex? implementation that makes input_shaper defunct on a toolhead change. And I saw some users complaining about this issue. I think it should be fixed. The commit https://github.com/Klipper3d/klipper/commit/638fa8532c91101b6b3b927ab46aa041a5e69a7f fixes that (pending testing), but there could be other ways to fix it. If you or @Tircown have any alternative suggestions, I'm happy to consider them.
I agree that should be fixed. However, I wonder if we can fix that in idex_modes.py / corexy.py instead of adding complexity to stepper.py and input_shaper.py. Specifically, I think it should be possible for idex_modes.py to call setup_itersolve() at startup instead of on each activation (as the cartesian.py code does).
It would also be good to look at unifying the cartesian.py idex code with the corexy.py idex code. However, I'd guess changes here are likely to conflict with @Tircown pending work.
As a high-level comment, the input_shaper system is widely used, while idex systems are still relatively rare. It seems to me that we would have more maintainable and scalable code if we tried to keep the input_shaper.py and stepper.py code focused on their tasks, even if it requires additional complexity in the idex code.
-Kevin
To offer another alternative for discussion myself that I considered and rejected initially, we could let users configure the input shaper on per-stepper basis
I agree that does not seem like a good plan. If @Tircown doesn't already have this figured out, I'll try to put together a proposal for refactoring idex/rails to make this work.
-Kevin
What about SHAPER_CALIBRATE? Shouldn't it support AXIS=dual_carriage or something similar?
@dmbutyugin Could you copy the details of this PR and put them into a new PR on this fork of klipper, a small group of guys is making a community maintained bleeding edge fork of klipper, you can join the discord about it here, but please if you could copy this over, we would like you to have credit for the PR and help us implement this.
I finally got this working properly, my Trident IDEX printer is finally ringing free :) this is such a massive improvement. Thanks @dmbutyugin

Sorry, didn't get to this in a long while. I did update the branch to the latest Klipper state, hopefully this shouldn't be breaking anything. I agree that in general the feature requires some reworking, maybe me or Tircown will get to that at some point. And users can at least try using it in the meanwhile. @Fisheiyy I do not mind you copying this to your fork, you can just cherry-pick the changes (git keeps the commits metadata and messages then) and fix merge conflicts if any (the branch doesn't have conflicts with the current Klipper mainline). But I am unsure about the future of this feature: maybe it will be reworked, and then the configuration will be done differently. Probably this is not a concern for your fork though, if it's bleeding edge.
@KevinOConnor @dmbutyugin
I wanted to bring this PR back up, since more people are building Tridex (Trident IDEX) printers now :) Basically--at this time, the only way to get input shaping functional is to switch to this PR. My testing where I set input shaping parameters during tool changes does not work, the ringing is still present; Switching to this PR and setting the input shaping parameters works properly (see the image above that I posted on Oct 15, 2022).
I realize there are a lot of nuances here I don't understand, but is it possible to maybe implement some of the changes and not others to get input shaping fixed? Ie, if the bug could be fixed, and then input shaper parameters were applied during a tool change? Thank you both for all the work you've put into this!
-Eddie
OK, I made another attempt to get back to it. I've created another branch, where I tried to incorporate the feedback from Kevin. Basically, now in order to setup an input shaper on a printer with a dual carriage, one should configure it in a start gcode along the lines of
[gcode_macro START_GCODE]
gcode:
; ....
; Configure Input Shaper
SET_DUAL_CARRIAGE CARRIAGE=1
SET_INPUT_SHAPER SHAPER_TYPE_X=MZV SHAPER_FREQ_X=70
SET_INPUT_SHAPER SHAPER_TYPE_Y=2HUMP_EI SHAPER_FREQ_Y=50
SET_DUAL_CARRIAGE CARRIAGE=0
SET_INPUT_SHAPER SHAPER_TYPE_X=EI SHAPER_FREQ_X=60
SET_INPUT_SHAPER SHAPER_TYPE_Y=2HUMP_EI SHAPER_FREQ_Y=50
; ....
G28
; ....
and the printer.cfg should typically only have and empty [input_shaper] section:
[input_shaper]
[dual_carriage]
...
Note that in the start script, it is important to issue the same SET_INPUT_SHAPER SHAPER_TYPE_Y=... SHAPER_FREQ_Y=... command twice for both carriages, at least on hybrid? kinematics, because it will fill the required input shaper parameters for the inactive stepper kinematics for the carriages (when a carriage is deactivated, its 'Y' stepper must still generate steps to let the carriage stay in the same place).
Then one can just issue SET_DUAL_CARRIAGE CARRIAGE=1 and SET_DUAL_CARRIAGE CARRIAGE=0 commands in the tool changing scripts, and the input shaper parameters will be preserved accordingly. Incidentally, SHAPER_CALIBRATE should now also work as expected - if one is to activate a given carriage and then run this command, the results of the calibration should be applied to the correct carriage.
To get that effect, I had to refactor how input shaper configures the input shaper parameters, and make sure that idex_modes do not spuriously reallocate the stepper allocs.
@eddietheengineer and others, maybe you could give this branch and try provide your feedback. And if everything works as expected and the feedback is positive, I can update the documentation for it as well and then update this PR to that code instead.
@Tircown, @KevinOConnor FYI. Idex copy/mirror modes should also work then, and this approach should be scalable to other potential future kinematics, e.g. quad gantry kinematics.
BTW, I updated the new branch, but this was mostly some code refactoring/improvements. This should not have changed the functionality, but since I have no idex printer, I cannot test this myself. Please report any problems should they be spotted.
Definitely sounds interesting. Alas, I haven't gotten a chance to look at it in detail. I also don't have the hardware.
-Kevin
Alas, I don't have the hardware to test this either. So, I can only rely on community testing.
I switched to this branch today and ran "shaper_calibrate" worked fine on T0, but crashes Klipper when run on T1. I am currently testing the values I got from my T0 calibration for both tool heads to see if other issues come up. I have attached the log file from the crash. Further testing shows estimates and filament in Mainsail are completely broken when using T1 when they are working fine in the main branch of Klipper. But it does do what it says on the tin, input shaping seems to reduce the ringing when using the same gcode with this branch vs Klipper main branch.
If this is not the correct place for this, then please let me know where to post this.

Also experienced crash when using TEST_RESONANCES on the second toolhead, but ACCELEROMETER_QUERY returns valid measurements without crashing.
Input shaper works for print using first toolhead (pics below). I will use main klipper to test resonances for second toolhead and then test other combinations of the toolheads.
EDIT: This is using hybrid_corexy kinematics. Using input shaper with these kinematics in the main klipper build results in much worse ringing than not using input shaper.

Got in some more testing. Input shaping on the dual-extruder-input-shaping build works on both toolheads when used individually or both are used in the same print. I have printed ringing towers with each toolhead individually and a pair of ringing towers in the same print with each one printed by a different toolhead. I did all the same prints using the master build with no input shaper as a control. Improvement across the board seems about the same as what is pictured in my last post. I am using EI shaping on T0 and EI/MZV on T1. I did not test the other shapers, hoping it isn't necessary.
I will continue to use this build on my IDEX and will also install it on my V2 to see if any issues come up there. I will continue to check this thread, but probably won't post again unless I come across an issue or something specific is requested of me.
Although the input shaper bug with hybrid corexy kinematics should be fixed (because it is a bug), what I really want is mirror and duplication modes. Printing two at a time is twice as fast. I've had a few overnight prints recently where it would have saved me an entire day.
EDIT: I forgot to mention that the time estimates worked fine for me in Fluidd.
Hi, I am also waiting for Mirror and Duplicate modes I built idex with 4 extruders with 2 nozzles I am using 2 in 1 out bigtreetech hotend (not mixing)
@joseph-greiner, @BadMouth75, thanks for giving it a test! I think I identified the bug that caused crashes on the new branch, now it should hopefully be fixed. Maybe you can give it a try and see if everything works well now.
Separately, I understand that there is an interest in the mirror and copy idex modes. It was @Tircown who implemented the initial support for them. Alas, it was and still is blocked for merging. Perhaps this could unblock it to some degree? FWIW, this PR kind of independent of the mirror/copy modes support. The thing is, I cannot realistically take another pass over Tircown implementation of those modes since that implementation was rather non-trivial and I have no hardware to test it.
Just to be clear, this crash happens when I try to run shaper_calibrate with T1 (dual_carraige) active. The command runs successfully when run on T0 (stepper_x). The crash is still happening.
Here is a picture of the commands I used to update the branch (I know just enough about git to be dangerous, not enough to be savvy):

Here is the current configuration on my printer:

Here is the latest klippy.log with today's crash: klippy.log
I would love to work with you as much as I can to get this implemented into mainline Klipper. I figure the other IDEX modes will get here eventually. This is all about input shaping right now. I wish I understood python more than I do, but I am learning.
Same results here with TEST_RESONANCES on T1(second toolhead). The toolhead moves to the specified location for the test, then klipper crashes. klippy.log attached.
Probably not relevant, but I am using the ADXL built into EBB42 CAN toolhead boards and I did rebuild and update the firmware on them before testing. EDIT: Tried with an ADXL attached to a raspberry pi Pico and it also crashes.
@joseph-greiner, @BadMouth75, thanks, I found another problem. Now I think (according to my testing at least) that it should be good now.
Separately, I realized that I previously got a bit ahead of myself with claiming that SHAPER_CALIBRATE will work. Well, it could kind of work, but if you have two accelerometers on the two toolheads, it wasn't possible to use both of them for calibration. Now I made a change to support CHIPS parameter, so you could do something like
T0
SHAPER_CALIBRATE CHIP='adxl345 tool_0'
T1
SHAPER_CALIBRATE CHIP='adxl345 tool_1'
Note that now in my branch the results of SHAPER_CALIBRATE take effect immediately (without the need to first do SAVE_CONFIG). FWIW, SAVE_CONFIG with SHAPER_CALIBRATE wouldn't do any good - as indicated previously, one need to configure the input shaper in some start gcode instead. Or using something like
[delayed_gcode init_shaper]
initial_duration: 0.001
gcode:
SET_DUAL_CARRIAGE CARRIAGE=1
SET_INPUT_SHAPER SHAPER_TYPE_X=MZV SHAPER_FREQ_X=70
SET_INPUT_SHAPER SHAPER_TYPE_Y=2HUMP_EI SHAPER_FREQ_Y=50
SET_DUAL_CARRIAGE CARRIAGE=0
SET_INPUT_SHAPER SHAPER_TYPE_X=EI SHAPER_FREQ_X=60
SET_INPUT_SHAPER SHAPER_TYPE_Y=2HUMP_EI SHAPER_FREQ_Y=50
I tested the latest update, works well. SHAPER_CALIBRATE no longer crashes Klipper. and running it by specifying the chip worked well. I will add this to my V2 and test how it works on a single tool head machine.
Found a little time to test the latest build. SHAPER_CALIBRATE and TEST_RESONANCES no longer cause Klipper to crash when the second toolhead is active. Input shaper still appears to still work on both toolheads (based on a single print containing a ringing tower printed by each toolhead). I am configuring input shaper in the start gcode per your earlier posts.
Using the CHIP parameter seems to work. The resonance charts of the centered active toolhead and inactive parked toolhead are more similar than I expected, but I guess that makes sense. The two ADXL chips are experiencing the same resonances from different locations on the same X rail.

@joseph-greiner mentioned an issue with the single toolhead time estimates in Mainsail with the initial build. I hadn't noticed any in Fluidd previously, but got this estimate when I started a print with the latest build. This is on the IDEX, but only using the first toolhead. The print should take around 9 hours. This is the first time I've noticed it, but have only done short prints and not paid the most attention to the time estimates. Also notice the language for the Finish time.
I've installed this build on my single toolhead V2, but haven't printed anything with it yet. I should be printing every day with both printers in the coming week and will try to pay close attention or maybe stop prints and revert to mainline Klipper to see if there are differences.
The file time is actually increasing as the print progresses. 44 minutes into the print it is up to 158 hours.
EDIT: 20% into the print and the File estimate has dropped to 10hrs. No idea if any of this information is useful or whether the issue is with Fluidd or Klipper.
@dmbutyugin I ran over a dozen prints and didn't experience any weird time estimates again. It must have been a fluke. The time estimates are off, but no more than I would expect from slicer settings. The only abnormality is an extra time descriptor in a different language anywhere time is displayed. This happened on both the IDEX and V2 after switching to dual-carriage-input-shaping. Switching back to mainline klipper did not correct it. On the V2 I restored a pi image from before installing dual-carriage-input-shaping then updated all packages to see if the problem was elsewhere. Everything was normal. Then I installed dual-carriage-input-shaping again and everything is still normal. No problem this time. I am not sure what to make of it or whether it is related to dual-carriage-input-shaping, but that is what I experienced. Maybe something was off with my system or update process. Hopefully I am not causing you to look for problems that aren't there. I am not a software person.
