Skip to content

Aborting bg swap, when different toolhead is picked up #172

Closed

Description

@docx-tech

How did you install multiACE?

Official release, SSH installer

Startup banner

[multiACE] Version 1.30b-pre1 build=f0d15d33 file=2026-10-15 16:52:49

Operating mode

head

ACE units

ACE PRO 2

What happened

Bg swap begins prime purge on TH0 which has the ACE Pro 2 connected. The other heads are attached to the stock feeders. The printer picks up TH4/TH3, the prime purge begins on T0. Then it picks up TH1, and TH0 stops the bg swap routine, heats up to print temperature, and waits. The printer picks up TH0 next and restarts the swap process.

Perhaps this is an instance. It happened numerous times through out the print.

Image

Time of the error

00:07.901

Logs

klippy.log

Before submitting

  • I am running the current release, or I have checked that the problem still exists on it.
  • This build was installed from this repository, not from a third-party firmware image.

Activity

  1. decay71 commented on Oct 16, 2026

    @decay71
    Owner

    This is expected behaviour, just confusingly logged. The background job is only aborted when its own head is picked: at 21:00:08 the printer picked T0 itself, 0.1 s after the unload half had finished, so there was no time left for the transport and the arrival loaded inline. Your pre-prime makes this more likely, with prime:40 plus the cool-down the unload half took 106 s instead of about 60 s. The “head 1” in those lines is the display number, i.e. your T0; i will change the messages to show both, e.g. “head 1 (T0)”.

    The log you sent ends at 17:26 on 10-15. Please send the klippy.log that covers the print from your screenshot (21:00). (if its still needed)

  2. docx-tech commented on Oct 19, 2026

    @docx-tech
    CollaboratorAuthor

    Here is the rest of the log that includes the 21:00:07.901 timestamp for 10/15/2026

    klippylog2.log

  3. decay71 commented on Oct 20, 2026

    @decay71
    Owner

    Thanks for the logs, they show it clearly. The background op is not aborted by the other heads loading. It is aborted when head 1 itself gets picked again for its next color: every "PICKED mid-sequence" line comes 2-3 seconds after head 1 is picked. Picks of heads 3 and 4 in between do not affect it.
    Up to about 17:03 UTC head 1 was parked for roughly 2 minutes between uses and every background op completed. From 17:05 on it was only parked for about 60 seconds, but your sequence needs about 80 seconds just for the cold pull (the 30 mm pre-prime at 250 runs first) and about 2 minutes for the full transport. So it runs out of time, and the normal inline swap takes over, as designed. No print was paused.
    If you want more of them to finish, try the PLA table without prime:30 and primetemp:250, that shortens the unload half. The "FAILED" wording sounds worse than it is

  4. docx-tech commented on Oct 20, 2026

    @docx-tech
    CollaboratorAuthor

    Thank you for taking the time to looking over the logs.

    Right, we are on the same page roughly about the sequence. The discussion is the following: Rather then Prioritizing the Picker being rdy, and aborting the swap, Prioritize the Unload and have the picker wait while it finishes, then the picker can attach the head.

    What happens now:
    It doesnt have time to do the full swap or the unload. H1 has enough time to finish the prime purge while Head 3 is printing, a different Head is picked up, lets say Head 2, which appears to triggers H1 to heat to print temp and wait for 30-60 seconds idle until Head 2 finishes. Once H1 is picked up, the swap sequence and prime purge that already happened is aborted and it starts from the beginning.

    So rather then what it does now

    Prioritize the Picker (Aborts swap & Restarts)

    • Starting over again, redoing the prime purge (more waste and loss of 20 seconds) plus the idle wait time at the print temp for 30-60 seconds (total loss time of ~50-80 seconds)

    Alternative | Prioritize the Unload (Finish the Unload & Make the Picker Wait)

    • Prioritize the background swap (i.e. finish the unload) and have the picker wait over the prime tower. Rather then head 1 waiting 30-60 seconds idle, use that time to do the tip forming, and have the picker wait while the old filament is being unloaded. Once that finishes, the picker can pick up Head 1 while the the new filament is being loaded.

    This could save over a minute per swap in this case, which for smaller prints with say 100 swaps could save roughly 1 hour and 40 minutes.

    What do you think?

  5. decay71 commented on Oct 20, 2026

    @decay71
    Owner

    Hi. . Part of what you see comes from a setting on my side: the preflight stamps a background swap as soon as a head is parked for at least one minute. I set that aggressively on purpose for testing. In practice a background swap needs about two minutes to get through the cold pull to the bulk retract, and your prime:30 at 250 adds to that. So many windows in your print were simply too short, the head was picked again during heating or tip forming, and the swap fell back to the normal inline swap.

    Some of your idea already exists: once the background swap has reached the bulk retract, picking the head does not abort it. The tool change waits for the rest of the retract and then continues. It only aborts while the filament is still in the hotend, because there the old filament cannot stay half pulled. Making the picker wait in those earlier phases would need a wait placed in the G-code before the tool change, since the stock tool change macro picks the head before multiACE gets control.

    You can try the larger window yourself: it is the constant BG_UNLOAD_MIN_WINDOW_MIN in post_process_virtual_toolheads.py (on your printer under printer_data/config/tools/, editable in Fluidd). Set it to 2, save, and run the preflight again on the original slicer file. The web backend picks up the change on the next preflight, no restart needed. A multiACE update will overwrite the file.

    If it helps, feel free to turn it into a proper setting as a PR, for example as an option in [ace_bg_swap] that the preflight reads. Same for the "picker waits" idea: if you want to try it, ask me first and we go through where the wait would have to sit.

  6. docx-tech commented on Oct 20, 2026

    @docx-tech
    CollaboratorAuthor
  7. decay71 commented on Oct 20, 2026

    @decay71
    Owner

    No, BG_UNLOAD_MIN_WINDOW_MIN = 2 does not make anything wait or extend anything. It is only a filter in the preflight: when the estimated parked time of a head (from the M73 times) is shorter than 2 minutes, that tool change gets no background swap at all and runs inline from the start. Longer windows still get one, with the same abort rules as now. So it removes the start-abort-redo cases, nothing more.
    Your step list, corrected from what the code does and what we measured:

    1. Heat, then (with prime: in your table) the pre-prime, then tip forming and the cold pull. In your log this took about 72-82 s.
    2. Bulk retract back to the ACE, decoder-verified. Roughly 15-20 s.
    3. Feed of the new filament to the toolhead sensor. Roughly 15-20 s. In transport mode it stops here and the head stays staged.
    4. Only in full mode: press, grip and prime/purge through the dock, then the anti-ooze retract. In transport mode this part runs inline when the head is picked.
      What happens on a pick today: during 1 it aborts (the old filament is still in the hotend), during 2 it does not abort and the tool change waits for the rest of the retract, during 3 it stops and keeps the filament staged, and the inline load continues from there.
      So your idea is about phase 1, and I agree it is where the time is: a 60 s window currently costs a full inline swap, while waiting 20 s for the cold pull to finish would save most of it, and the pre-prime is not wasted twice.

    Happy for you to try it. Some pointers:

    • The head is picked by the stock T macro before multiACE gets control, so the wait has to be stamped into the G-code before the arrival T. That happens in rewrite_head_mode_to_file in multiace/tools/post_process_virtual_toolheads.py, next to where the ACE_BG_SWAP lines are stamped and the M73 windows are computed.
    • The engine is multiace/klipper/extras/ace_bg_swap.py: the phases, is_busy(head) and _check_docked (where the abort is raised). ace.py has _wait_bg_op, which is the existing wait at the start of ACE_SWAP_HEAD.
    • Something like ACE_BG_WAIT HEAD=n that blocks until that head's background op has left the cold pull (or is not running at all), with a timeout that falls back to today's behaviour.
    • While it waits, the printing head stands still and hot. Park it over the discard chute first (the pick-check does that with MOVE_TO_DISCARD_FILAMENT_POSITION and restores the position afterwards), otherwise it oozes onto the part.
    • Background ops are serialized (one at a time), and the bulk retract must never be aborted. Please keep both.

    Please open a draft PR early, so I can look at the approach before you spend too much time on it.

  8. docx-tech commented on Oct 21, 2026

    @docx-tech
    CollaboratorAuthor

    No, BG_UNLOAD_MIN_WINDOW_MIN = 2 does not make anything wait or extend anything. It is only a filter in the preflight: when the estimated parked time of a head (from the M73 times) is shorter than 2 minutes, that tool change gets no background swap at all and runs inline from the start. Longer windows still get one, with the same abort rules as now. So it removes the start-abort-redo cases, nothing more. Your step list, corrected from what the code does and what we measured:

    Got it! So this would skip the bg swap for moves that are shorter then 2 minutes and avoid the extra priming waste that gets currently gets aborted and restarted with the inline swap.

    Updated the window to 2 in the py file, will reupload the gcode and give it a go.

  9. docx-tech commented on Oct 22, 2026

    @docx-tech
    CollaboratorAuthor

    Can confirm that changing BG_UNLOAD_MIN_WINDOW_MIN = 2, removed all those bg swaps that were too short without restarting the console. Just re-ran the gcode through the pre-flight.

  10. docx-tech commented on Oct 22, 2026

    @docx-tech
    CollaboratorAuthor

    Job results from successful prints

    (1) Transport BG Swaps mode w/BG_UNLOAD_MIN_WINDOW_MIN = 2
    (2) Normal BG Swaps mode

    Interesting to see the times and even the filament used; it kind of makes sense =)

    Image
  11. decay71 commented on Oct 23, 2026

    @decay71
    Owner

    Thanks for the numbers. Your runs also show the unload window matters (BG_UNLOAD_MIN_WINDOW_MIN 2 vs 1), and it could be refined. Some ideas, none of them settled, take what you find interesting:

    1. Count the swaps inside the window. The window is measured from the slicer's M73 remaining minutes, and the slicer knows nothing about the swaps of other heads in that time, each of which adds real minutes. So the real parked window is longer than computed and we stamp fewer swaps than we could. On the Razorback from MakerWorld (6 colours, about 1100 swaps (18 stops only, yay:) ) ) this made roughly 500 vs 700 eligible swaps. This would be preflight only, no Klipper change.

    2. Finer time base. M73 R is whole minutes, so a delta of 1 can be anything from a few seconds to almost two minutes. That is why 1 is a gamble and 2 is on the strict side. Interpolating seconds between M73 lines (for example over file position) would be more precise, but it is more work than idea 1 for less gain.

    3. Threshold per mode. What has to fit in the window differs: the full bg swap needs unload, load, grip and prime; transport only the unload half and the feed to the sensor, longer with a pre-prime in the tip-form table. One constant for all modes fits none of them well.

    Once #186 makes the arrival wait for the cold pull, a mis-sized window will cost real waiting time instead of just an abort, so this becomes more relevant then.

  12. docx-tech commented on Oct 23, 2026

    @docx-tech
    CollaboratorAuthor

    Thanks for the numbers. Your runs also show the unload window matters (BG_UNLOAD_MIN_WINDOW_MIN 2 vs 1)

    Exactly! About an 11% (57 mins) difference that came mostly from the swap window, since only a few full background swaps happen at the beginning of the print before the infill takes over.

    For this print, there is potentially 1-2 hrs of time savings by making the picker carriage wait for the tip forming to complete! If we have 2 ACE Pros I think we could save even more by placing the filament in an optimized fashion. Will be fun to see.

    Will dig into your comments soon. Thank you.

  13. decay71 commented on Oct 23, 2026

    @decay71
    Owner

    I can do a 4 Ace Print this weekend, did you send the gcode already? not sure, too much logs :)

  14. 6 remaining items

  15. added
    enhancementNew feature or request
    and removed
    bugSomething isn't working
    on Oct 23, 2026
  16. self-assigned this
    on Oct 23, 2026
  17. decay71 commented on Oct 24, 2026

    @decay71
    Owner

    Thanks for the link, will report back!

  18. docx-tech commented on Oct 24, 2026

    @docx-tech
    CollaboratorAuthor
    1. Finer time base. M73 R is whole minutes, so a delta of 1 can be anything from a few seconds to almost two minutes. That is why 1 is a gamble and 2 is on the strict side. Interpolating seconds between M73 lines (for example over file position) would be more precise, but it is more work than idea 1 for less gain.

    I am going to print my test file and it has stamped out the following in the gcode by changing the windows:

    Swap Breakdown Comparison

    Metric Stock Window (MIN_WINDOW = 1) Unconstrained Window (MIN_WINDOW = 0) Impact / Savings
    Total Toolchange Swaps 126 126 Identical layer & toolchange sequence
    Background Swaps (ACE_BG_SWAP) 77 122 +45 swaps converted to background (+58.4%)
    Arrival Holds (ACE_BG_WAIT) 77 122 122 / 122 (100% 1-to-1 parity)
    Short-Window Skips (Left Inline) 45 0 100% eliminated — all short windows captured

    With the ACE_BG_WAIT is the BG_UNLOAD_MIN_WINDOW_MIN=1 necessary (i.e. can we set it 0) since ACE_BG_WAIT should be able to handle this dynamically now? If not we would need to set this to something closer ~20-30 secs which is roughly the time it takes for the head to heat up to 215C but as I understand that isn't possible with the current integral M73 setup.

  19. docx-tech commented on Oct 25, 2026

    @docx-tech
    CollaboratorAuthor

    Wow! This is running much faster 🔥All those weird phantom restarts, when it would pause when a non-bg swap head was picked up, abort the bg swap, and then restart, have been resolved from my observations. I set min window = 0 and let ACE_BG_WAIT handle all the swaps. See log, the first few layers are able to complete full background swaps, once we hit the infill layers, you can see T0 is fired at different intervals of the ladder and ACE_BG_WAIT handles it correctly. It's very cool b/c the wait in discard position works well. Often you will see it pull the filament just above the tool head, pick up the bg swap tool head and then continue retracting and loading. I am curious how much time we will save!

    An inefficiency help request

    After it has swapped filament and purged, right before it goes to the prime tower, the printer goes IDLE drops to sub 200C then heats up to 250C which wastes some time, and then cools down to the print temp as it prints over the prime tower. Where is this value set? Here is the my current tip forming string for reference:
    unloadtemp:215, loadtemp:215, 20@600, waittemp:215, -15@1800, -22@2400, -6.2@1200, -3.2@720, 20@1200, -20@940, 41@1740, -43@2400, 20@680, -20@420, -21.1@2700

    Check out how things are going =)

    Only about 6% through but you can check it out. Example output

    Image

    klippy ACE_BG_WAIT BG WIN MIN0.log

    Live stream if you can catch it
    https://oe.ink/l/m3q53be4OE

  20. decay71 commented on Oct 25, 2026

    @decay71
    Owner

    Great progress, and nice to see the wait and the early abort working on hardware. I read the branch against current main (merges clean, ace.py untouched).
    My print stopped the moment i went to sleep of course, blob on toolhead 4.. so still a few hours left..

    Three things:
    :

    1. The ineligible branch of ACE_BG_WAIT aborts every busy op that is not wait-eligible, not only early HEAT. That includes RETRACT, BOOKKEEP and the load half (LD_FEED / LD_GRIP / LD_PRIME): the heater is set to 0 in the middle of the load, and the abort flag is only cleared in _check_docked, so if the op finishes without another check, the flag stays and the next bg op on that head aborts at its first check. From RETRACT on it should just pass through as today (the swap already waits for the bulk, and a pick during the feed stages the filament). Please also clear the flag when an op starts.

    2. Please don't set the heater to 0 on the abort. Today an abort during HEAT hands its preheat to the inline swap that follows, so the arrival does not reheat from scratch. Let the existing failure path decide the heater.

    3. Please drop the README line-ending commit (it rewrites 1420 lines), and bump PP_FORMAT_VERSION in the post-processor, since the generated gcode changes.

  21. docx-tech commented on Oct 25, 2026

    @docx-tech
    CollaboratorAuthor

    Don't want to lose this...

    Some ideas, none of them settled, take what you find interesting:

    1. Count the swaps inside the window. The window is measured from the slicer's M73 remaining minutes, and the slicer knows nothing about the swaps of other heads in that time, each of which adds real minutes. So the real parked window is longer than computed and we stamp fewer swaps than we could. On the Razorback from MakerWorld (6 colours, about 1100 swaps (18 stops only, yay:) ) ) this made roughly 500 vs 700 eligible swaps. This would be preflight only, no Klipper change.

    Given recent developments, does setting the min window to 0 resolve this, since all swaps are eligible and ACE_BG_WAIT can handle each situation dynamically? I could be missing a finer point here, so pls let me know =)

    1. Finer time base. M73 R is whole minutes, so a delta of 1 can be anything from a few seconds to almost two minutes. That is why 1 is a gamble and 2 is on the strict side. Interpolating seconds between M73 lines (for example over file position) would be more precise, but it is more work than idea 1 for less gain.

    I believe this is resolved by min window = 0

    1. Threshold per mode. What has to fit in the window differs: the full bg swap needs unload, load, grip and prime; transport only the unload half and the feed to the sensor, longer with a pre-prime in the tip-form table. One constant for all modes fits none of them well.>
      Once #186 makes the arrival wait for the cold pull, a mis-sized window will cost real waiting time instead of just an abort, so this becomes more relevant then.

    Currently ACE_BG_WAIT uses a dynamic temp check of the hotend (<25C of target temp) for pre PULL stages. Making the monotonic ladder allows everything else to pass to inline swaps. Does this satisfy the requirement?

  22. decay71 commented on Oct 25, 2026

    @decay71
    Owner

    Mostly yes. For deciding which swaps get stamped, 0 plus ACE_BG_WAIT makes 1-3 moot: a short window now costs at most what the inline swap would have cost (early HEAT aborts and keeps the heat, PULL waits for the rest, which inline would redo anyway). Two finer points remain:

    1. The same window also feeds the loadout optimizer and the preview. They score a swap on a bg head as 30 s when its window passes the threshold, else 210 s. With 0 every such swap scores 30 s, so the optimizer routes swap chains onto bg heads even where the head is parked for seconds, and the shown saving is too high. That is where 1 and 2 still matter: the cost of a bg swap should grow with the window instead of being a fixed 30 s.
    2. Serialization: your MIN0 log can't answer that yet, only T0 swaps in the background there, and a single bg head never waits for itself. It needs a print where several heads swap in the background. What the log does show: the holds were 0.0, 0.2 and 2.0 s, the arrival came right at the end of the cold pull, so 0 cost nothing there.
  23. docx-tech commented on Oct 26, 2026

    @docx-tech
    CollaboratorAuthor

    13. Job results from successful prints
    (1) Transport BG Swaps mode w/BG_UNLOAD_MIN_WINDOW_MIN = 2 | 9 H 49 M Print Time, 10 H 42 M of Total Time
    (2) Normal BG Swaps mode | 8 H 54 M Print Time, 10 H 2 M of Total Time
    Interesting to see the times and even the filament used; it kind of makes sense =)
    Image

    @decay71
    (3) ACE_BG_WAIT - 7 H 33 M of Print Time, 7 H 36 M of Total Time! I hit print and walked away. No jams or human intervention. Really nice time savings for 122 stamped Bg Swaps.

    I would also like to optimize the last know position (currently moves to prime tower then back to parked position) move to something more optimal (like the parked position?) as we are losing about 3 seconds per swap there.

    How long with no BG Swaps?

    When we set the min window = 2 and transport mode we saved 2 hours and 16 mins (23% time savings which I beleive was 44 stamped bg swaps). How much time do we save with no BG Swaps at all? Can we do a back of the envelope calculation or do we need to print the axolotl with BG Swaps disabled? This is what got me excited about your project in the first place 🤩

    Print Run Durations & Overhead

    Run Mode Print Time Total Time Overhead (Total − Print)
    (1) Transport BG Swaps (Min Win=2) 9h 49m 10h 42m 53m
    (2) Normal BG Swaps (Min Win=1) 8h 54m 10h 02m 1h 08m (68m)
    (3) ACE_BG_WAIT (Min Win=0) (Branch #186) 7h 33m 7h 36m 3m
    Time Savings Achieved by ACE_BG_WAIT (Run 3)
    Compared Against Print Time Saved Print % Saved Total Time Saved
    --- --- --- ---
    vs. (1) Transport Mode (WINDOW=2) 2h 16m 23.1% 3h 06m
    vs. (2) Normal BG Swaps 1h 21m 15.2% 2h 26m

    This was for 122 Bg Swaps out of 126 Swaps (Min Window = 0)

    Image
  24. docx-tech commented on Oct 26, 2026

    @docx-tech
    CollaboratorAuthor

    @decay71 I forgot to post that my earlier print failed due to a ghost print error. Granted, I was adjusting the tip-forming during a print and it wasn't taking the updates live, so I decided to pause the print and restart the printer. During the pause T0 was in a parked bg swap which was completed and just purging in the background.

    Unfortunately that aborted the print so I won't be able to finish the entire print at the commit point below, which was before the heater ownership fix #196 8c0bfe9

    I am going to run the print again with the latest fixes

    Image

    klippy GHOST Head.log

  25. decay71 commented on Oct 27, 2026

    @decay71
    Owner

    The ghost on your restart is on my side, not #186. Your restart came 12 s into the background feed of ACE 1 slot 4 (from 11:58:36 UTC). The ACE keeps feeding after a host restart, so the new filament reached T0's sensor at 11:58:49, while the old filament's mapping had already been cleared at the end of the unload half. After the power-loss restore T0 had filament and no mapping, and the ghost check refused the swap, rightly so, it can't know which slot that filament comes from. Fixed on my dev branch: the STAGED marker is now written before the feed starts, and after a restart multiACE stops that slot's feed once the ACE is back. comes with the next push to main.

    Tip-form edits apply live when you save them in the multiACE web editor. After an edit in Fluidd, run ACE_TIPFORM_RELOAD in the console, no restart needed

  26. docx-tech commented on Oct 27, 2026

    @docx-tech
    CollaboratorAuthor

    30. The ghost on your restart is on my side, not #186. Your restart came 12 s into the background feed of ACE 1 slot 4 (from 11:58:36 UTC). The ACE keeps feeding after a host restart, so the new filament reached T0's sensor at 11:58:49, while the old filament's mapping had already been cleared at the end of the unload half. After the power-loss restore T0 had filament and no mapping, and the ghost check refused the swap, rightly so, it can't know which slot that filament comes from. Fixed on my dev branch: the STAGED marker is now written before the feed starts, and after a restart multiACE stops that slot's feed once the ACE is back. comes with the next push to main.
    Tip-form edits apply live when you save them in the multiACE web editor. After an edit in Fluidd, run ACE_TIPFORM_RELOAD in the console, no restart needed

    Cool. Yeah, I figured out that the tip-forming tokens weren't being applied due to the mismatch of MultiACE versions (i.e., I was trying to use the 1.30b token strings on version 1.27b).

  27. docx-tech commented on Oct 29, 2026

    @docx-tech
    CollaboratorAuthor
    Image

    Final Benchmark & Results: ACE_BG_WAIT + Prime Tower Move Optimization

    Here are the finalized benchmark results across all test runs on the Axolotl multi-color print (axolt multicolor_PLA_3h57m.gcode / 3h58m.gcode).

    This dataset covers 122 background swaps out of 126 total tool changes (MIN_WINDOW = 0), testing the progression from stock background swap behaviors up through PR #186 and commit 658085c (RESTORE_POS=0).

    Status Update: The Run 5 configuration (ACE_BG_WAIT non-blocking wait + RESTORE_POS=0 prime tower skip) is now merged and set as the default behavior in main for background swaps.


    1. Full Benchmark Matrix

    Run # Configuration / Mode Print Duration Total Duration Overhead (Total − Print) Filament Used Notes
    (1) Transport BG Swaps (MIN_WIN=2) 9h 49m 06s 10h 42m 43s 53m 37s 40.66 m High carriage idle and large swap window latency
    (2) Normal BG Swaps (MIN_WIN=1) 8h 54m 13s 10h 02m 14s 1h 08m 01s 40.75 m Window=1 blocking arrival behavior
    (3) ACE_BG_WAIT (MIN_WIN=0, PR #186 initial) 7h 33m 00s 7h 36m 45s 3m 45s 48.56 m First async non-blocking implementation
    (4) BG Swaps OFF (Baseline Sequential) 9h 07m 16s 9h 10m 40s 3m 24s 37.92 m Stock sequential toolchange baseline
    (5) ACE_BG_WAIT + RESTORE_POS=0 (Default in main) 7h 16m 23s 7h 27m 56s 11m 33s 47.27 m Current default; zero redundant prime moves
    Ref Theoretical 6-Head Dedicated Toolchanger ~3h 58m ~3h 58m 0m ~30 m (est) Snorca estimate (zero filament swaps, 0s Bowden latency)

    (Note: Overhead in Run 5 accounts for brief manual mid-print pauses/restarts; Klipper's print duration reflects purely active macro and motion execution.)


    2. Cumulative Savings (Run 5 vs. All Previous Configurations)

    Baseline Compared Against Print Time Saved Print % Saved Total Duration Saved Total % Saved
    vs. (4) BG Swaps OFF (Sequential Baseline) 1h 50m 53s (~1h 51m) 20.3% 1h 42m 44s (~1h 43m) 18.7%
    vs. (1) Transport Mode (MIN_WIN=2) 2h 32m 43s (~2h 33m) 25.9% 3h 14m 47s (~3h 15m) 30.3%
    vs. (2) Normal BG Swaps (MIN_WIN=1) 1h 37m 50s (~1h 38m) 18.3% 2h 34m 18s (~2h 34m) 25.6%
    vs. (3) Initial ACE_BG_WAIT (Run 3) 16m 37s (~17m) 3.7% 8m 49s (~9m) 1.9%

    3. Technical Summary & Findings

    • 20.3% Print Time Reduction Over Sequential Baseline: By pipelining swaps in the background and eliminating carriage stalls on the bed, active print time dropped from 9h 07m down to 7h 16m—saving 1h 51m.
    • Closing the Gap to the 6-Head Ceiling: In Snorca slicer, an idealized 6-head toolchanger with zero filament swapping in parked heads estimates this print at 3h 58m.
      • Baseline sequential swapping (Run 4) added +5h 09m of swap overhead over that ideal limit.
      • Our optimized default (Run 5) cuts that overhead to +3h 18m.
      • This recovers over 35% of the total overhead gap between a single-feeder hybrid and a dedicated toolchanger purely through firmware and macro pipelining.
    • Impact of RESTORE_POS=0: Skipping the redundant repositioning travel to the prime tower saved an additional 16m 37s of active motion and 1.29 meters of filament over Run 3.
    • Carriage Stalls Resolved: Gantry arrival holds that previously cost over an hour of idle time in Runs 1 and 2 are fully resolved; the carriage now only holds when a short layer requires waiting for physical Bowden transit to finish.

    4. Next Step: Bridging Load Optimization and Concurrency (Issue #197)

    While PR #186 optimizes the pipelining between the active printing head and a single parked head, multiACE currently serializes toolchanges across multiple parked toolheads.

    This connects directly to decay's ongoing benchmark running this exact same Axolotl file across 4 ACE units with the multiACE load optimizer (Issue #86 Comment):

    • The Current Dynamic: The built-in load optimizer schedules filament assignments across toolheads to maximize available swap windows. However, because extruder motion execution shares a single serialized motion queue in Klipper, even a 4-ACE setup must execute unloads, Bowden feeding, and reloads in single file across parked heads.
    • The Missing Link — Issue #197 (Support concurrent background swaps across parked heads / per-head trapq): Implementing independent motion queues (trapq) per extruder/parked head will allow multiple ACE feeder units to run background swaps concurrently.
    • The Potential: Combining multiACE's load optimizer with true parallel background execution will eliminate the remaining arrival stalls on short layers where two parked heads need swaps in close succession, pushing the hybrid 4-head system even closer to the 3h 58m dedicated toolchanger floor.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions