Tag Archives: Voron

Adding a Second Toolhead to my Voron 2.4, Part II

Posted 08 November 2025.

In part I of this saga, I described my motivations for starting this project as follows:
Last May (2025) I started the process of building a Voron 2.4 300x300mm 3D printer, with the ultimate goal of constructing a dual extruder system capable (hopefully) of complex prints requiring soluble supports. Now that I have the printer running with a single ‘Stealthburner’ toolhead, it is time to move on toward my ultimate goal of a dual extruder system.

After a LOT of research into the many available toolchanger mods, I chose the MISSChanger (the ‘MISS’ stands for ‘Make It Simple, Stupid!’) mod because unlike all the other mods, this one does not require a ‘top hat’ addition to make room for the top-rail-mounted docking system, room that I do not have in my office. Instead, it uses up about 130 mm of print surface (almost half of my available Y-dimension space on my 300×300 plate at the front of the printer for the docking system. If necessary, however, the docking system can be easily removed to recover the print space, but only at the cost of going back to a single-extruder configuration.

08 November 2025 Update:

I now have tool changing working, and I was actually able to make a two-color print, as shown in the following short video and a photo of the 10mm two-color calibration cube.

Smooth toolchanges – who would have thought I would ever get this far!
My very first dual-color print on my Voron 2.4/MissChanger 3D Printer

Lots of work still to do. The above print isn’t very high quality, and the zero offset isn’t dialed in yet. In addition I noticed the toolhead logo/nozzle colors were off; the nozzle LEDs were a dark red during print instead of white – which made seeing print details very difficult. Either the STATUS_PRINTING nozzle color isn’t white like I thought, or PRINT_START isn’t changing to STATUS_PRINTING when needed.

I manually checked, and STATUS_PRINTING nozzle LEDs are full white – so that’s not the problem. Looking at PRINT_START I don’t see where the STATUS_xxx macros are used except at the end when STATUS_READY is called.

Side Note: When I started checking where (if anywhere) the stealthburner LED colors were being set at the beginning of a print, I found that they weren’t being set at all, which explains why I wasn’t seeing anything. Also in this process, I discovered that Vin’s MissChanger files contain their own, much more complex PRINT_START macro (among others). This macro is found in ‘misschanger_macros/print_time_default.cfg’, which is included at the very start of Vin’s example ‘printer.cfg’ file. I had blindly copied these include lines into my ‘printer.cfg’ file without ever realizing what was in them, as they didn’t seem to affect much. In particular I never realized there was another PRINT_START macro due to the way that Klipper parses includes – subsequent copies of any section or macro override any previous ones, so my PRINT_START macro always survived the process. I’m not going to worry about this right now – I’ll get to it when I get to it.

I went into PRINT_START and placed some STATUS_XXX macro calls and some STATUS_MSG debug prints, and will re-do the test print. I also took photos of each defined STATUS_XXX color sets so I can match what I’m seeing with a STATUS_XX call in PRINT_START. See below for the photos:

10 November 2025 Update:

Well, I’m not much smarter than I was yesterday regarding two-color prints, but I think I may have made some progress today. I couldn’t (and still can’t) figure out Vin’s instructions for setting up toolhead Z offsets for tools other than T0. Finally I remembered that Vin’s instructions had me add the following to printer.cfg in the SAVE_CONFIG section:

This led me to believe that I could probably just mount T1, tell Klipper to send the toolhead to Z-=0, and use the paper test to set the offset. As far as I can tell, this trick actually worked! So, now I am wondering what all the hooforah is for the Lube_Ball calibration tools and associated config files? Here’s a photo of my two-color calibration block, with no fine tuning done for either toolhead.

Two color print (T1 green, T0 white) with both z-offsets set manually, and no fine-tuning

In the above photo, it looks like the T1 z-offset of -1.750 is just a little too much, as the brim lines aren’t squeezed enough to connect to each other. I reduced the offset to -1.700 and ran the print again.

Reduced T1 z-offset from -1.750 to -1.700. Much nicer ‘squeeze on brim lines.

As the above photo shows, this offset produced a much nicer ‘squeeze’ on the brim lines. Now it remains to be seen if this method will hold up over time.

I decided to try Voxel3D_Nederland’s XYZ tuning print, shown here. It will be interesting to see if it confirms the z-offsets I have so far.

When I tried to print this job, I got an error message that said the extruder was too cool. Then I noticed that the T1 extruder temp was where it should be (240C), but the gcode was trying to print with T0 – oops. I hope this is actually a problem with the slicer, as my test prints with the two-color 10mm cal cube have worked correctly.

11 November 2025 Update:

I ran into yet another odd problem with the offsets. After getting the T1 z-offset nailed down I tried another print, and this on failed miserably, with the extruder starting out way too high. I ‘fine-tuned’ it back down again, but it took almost all (and then some) of the original -1.700mm offset back out again – which can’t be right. I re-ran PROBE_CALIBRATE on T1 and got close to the original -1.700mm, and when I tried the print again, it worked fine. However, when I tried to print the same job a second time without any changes, the same thing (extruder tip way too high) happened again. After thinking about this for a while, I began to think that the culprit was the ‘trigger_to_bottom = -1.896’ entry in the ‘[tools_calibrate]’ section of misschanger_settings.cfg. Maybe somehow this was being added to the T1 z-offset?

So, I set the ‘trigger_to_bottom’ value to zero and tried again, and saw that the 10mm two-color print was now consistently perfect. I am now in the process of making several prints in a row to verify that the z-offset is now consistently correct.

Not quite. I got a couple of prints where the extruder started out about 0.05mm too low. Not quite sure that’s all that bad, so I’m going to keep the offset at -1.700 for a few more prints.

I added 0.05mm to the z-offset to arrive at -1.750mm and restarted the firmware, and this time the extruder tip was too high by about 0.900mm – I have no idea why. The ‘trigger_to_bottom_z’ value in misschanger_settings.cfg is still zero. I restarted again and tried another print. This time the extruder tip was too high by about 0.6mm (could be the same as the 0.9 from before). Tried another print without accepting the 0.6 offset recommendation and without restarting. Same thing – extruder tip too high

Chose ‘apply offset’ Klipper restarted, and z_offset in [tool_probe T1 changed from -1.75 to -1.10mm. Did another print. Job went OK. Trying another print without changing anything. Good print.

Did a full Klipper reboot, selected test job without any other changes. This time the extruder tip was WAY too high; almost -2.0mm. At this point the printer.cfg tool_probe T1 offset is -1.10, so to get the extruder down another 1.9mm would put the extruder into positive territory – wow!.

Did a Home-All, then sent extruder to z=0; Had to RAISE the extruder by 0.60mm in order to get the proper ‘paper’ thickness. Did another PROBE_CALIBRATE; the result was _0.477. Accepted the result, and the T1 offset changed from -1.100 to … -1.100 – NO CHANGE! Did a save & restart from MainSail, and checked printer.cfg again. T1 offset is still -1.100 – unchanged. Did a HOME ALL, then checked extruder zero; had to raise the tip 0.5mm for a good ‘paper drag’.

Did another print without changing anything (T1 z_offset still at -1.1). Had to ‘fine-tune’ up 0.5mm, so this time I accepted the change. This time the T1 z_offset did not change with the restart – had to manually revise it – to -1.6000.

Did a ‘save & restart, HOME ALL, and sent extruder to z=0. This time I had to LOWER the extruder tip by 0.5mm for good paper drag. So I adjusted T1 z_offset by 0.5mm UP (minus), but this caused me to have to LOWER it by 0.5 after a HOME ALL.

Alright – there is certainly something rotten in Denmark. I changed to T0, sent the extruder to 150,200,0 and the paper check was fine – within 0.1mm. I did this because of this sentence in Vin’s instructions; “test the z-offset with the paper test. – If it is good then you set up the trigger_to_bottom_z value correctly. However, I had long since manually set the ‘trigger_to_bottom_z’ value to 0, so I really don’t undersdand how this works.

Next, I switched from T0 to T1, ran HOME ALL & QGL. Then tested offset by driving extruder to zero. This time it was pretty much spot-on – within 0.1mm. Tried another test print; good print.

Do ten test prints:

  • Print 1: OK.
  • Print 2: OK; a skosh low (brim was hard to scrape off, but not impossible)
  • Print 3: OK;
  • Print 4: Failed – extruder started out too high
  • Print 5: Failed – extruder started out too high
  • Print 6: Failed – extruder started out too high

I inspected the T1 mount on the carrier, and it seemed pretty tight. Also the screw-in extruder tip seemed secure, so those are probably not the culprit. At this point I noticed that starting when starting a print job, the printer skipped both the HOME ALL & QGL steps (not in PRINT_START?). Maybe that is what is causing the wandering z_offset?

  • Print 1: After HOME ALL & QGL. looks good – almost perfect first layer.
  • Print 2: After HOME ALL & QGL. looks good – almost perfect first layer.
  • Print 3: After HOME ALL & QGL. Good print, but extruder a little high.
  • Print 4: After HOME ALL & QGL. Poor print. Extruder started out too high
  • Print 5 After HA & QGL. Poor print. Extruder started out too high
  • Print 6 After HA & QGL. Poor print. Extruder started out too high
  • Print 7 After HA & QGL. Excellent print – almost perfect first layer

At this point, it looks like I can consistently get two-color prints that have a functional (if not pretty) first layer with T1, without requiring any ‘fine-tune’ adjustments (although smaller ‘fine tune’ adjustments might be advisable). And this is with the ‘trigger_to_bottom_z’ parameter in the ‘tools_calibrate’ section of misschanger_settings.cfg set to zero.

literally dozens of test prints of my 20x20x10mm high dual-color test print. Note that many successful prints were terminated early, as I was mostly interested in first layer quality.

12 November 2025 Update:

At this point, I think I can successfully do two-color/material prints, with maybe the need for some minor ‘fine-tuning’. However, it is clear that the PRINT_START macro needs to make certain that the HOME_ALL and QGL operations are performed before each print actually starts. Looking at the PRINT_START macro, I see:

So, at least in theory the PRINT_START macro does the HOME_ALL (G28) and QGL if it hasn’t already been done. However, I’m not certain it *ever* does this. I looked to see if there were any status messages emitted, but couldn’t find anything. In fact, there don’t appear to be *any* status messages in the Klippy log. I asked Grok about this, and apparently the only way to get user outputs to the Klippy.log is to put in RESPOND lines. So I put a RESPOND MSG=”In PRINT_START” in the PRINT_START macro. Also, I commented out the ‘if’ statement guarding the HOME_ALL (G28) and QGL commands in PRINT_START to see if that would actually happen, and started a new test print. Console output confirmed that the G28 & QGL commands were actually performed, so we’ll see. Yep, the print started OK (with the extruder tip maybe just a bit too far from the bed, but still very nice!).

The RESPOND message did not appear in Klippy.log – bummer.

I think I’m going to declare victory at this point, and start working on the status LED problem. The problem is that the STATUS_XX commands seem to be going to T0 instead of T1. From the console log I see:

From the above output, I can see that the ‘STATUS_MESHING’ command was executed at 12:48, but the subsequent call to _set_sb_leds_by_name was called with ‘led = t0_sb_leds’ instead of ‘t1_sb_leds’, but I didn’t see any actual status change messages other than the one ‘STATUS_MESHING’ output. I think I need to edit ALL the STATUS_XX messages to include a STATUS_MSG MSG=”[current status call]” so I can track progress.

Saved all relevant config files (and printer.cfg backups) to ‘config-20251112-131701.zip’, and then deleted all the backup files.

Opened 251103_shared_stealthburner_leds.cfg and edited all ‘gcode_macro status_xxx’ macros to include a STATUS_MSG MSG = “status_xxx” line. Then I restarted Klipper, cleared the console and started another test print.

I noted that the printer started out with T0 initialized and it did the initial HOME_ALL & QGL with T0. Then changed tools and did STATUS_MESHING (with led = t0_sb_leds). Then a full mesh calibration, then // T1: status_heating (led = t0_sb_leds). I noted that the T0 leds did, in fact, change to the ‘STATUS_HEATING’ color set.

I got some Grok help in debugging this situation, and now the LED action seems to be following the correct toolhead. The affected files were 251103_shared_stealthburner_leds.cfg and 251103_paynter_toolchanger.cfg.

I saved the entire configuration set in ‘config-20251112-143625.zip’ in the MissChanger/Config Files folder.

Not so fast! There were a few more bugs to work out, but with Grok’s help we seem to have exterminated them – at least so far. I again saved the configuration set in MissChanger/Config Files/config-20251112-173325.zip

At this point I can print a two-color model reasonably consistently, with toolhead LED colors changing through ‘status_cal_z’, ‘status_meshing’, ‘status_heating’, then ‘status_printing’ and finally to ‘status_ready’ after the print concludes – yay! Here is a photo of a two-color print I just did from a design I created some time ago with my old Flashforge Pro IDEX printer (before I threw it in the trash!)

Final exam: Two color print of a desk nameplate for my wife

30 November 2025 Update:

Well, it has certainly been an interesting adventure so far, but I think I may have actually gotten to the point where I can do dual-material prints with my Voron printer. The last set of hurdles to surmount were a series of infinite hangs during tool changes, caused by poorly formed macros that were way too picky about extruder temperatures. The macros wanted to wait until the extruder temperature was just right, and sometimes the extruder in question just didn’t want to be that exact. This caused long waits (on the order of 30 seconds) before picking up the next tool, and eventually the printer wouldn’t pick up the next tool at all. I got a lot of help from Grok running this down, and I am now a real fan of this AI. Its superpower is a combination of an in-depth understanding of Klipper (by reading the manual at about 10000x human speed, with perfect recall) combined with the ability to grind through huge mind-numbing klippy.log files and then use that information to pinpoint the place(s) in my macros where things weren’t working correctly. For instance, here is one of several macros that regulate the process of changing from one toolhead to another:

This is very tough stuff to get my head around due to all the variable referencing, but basically it controls the carriage movement that drops off the current tool into its docking station before the printer moves on to picking up the next one. The Grok realized that part of the problem may have been that the extruder temps weren’t being set at their ‘standby’ temps when they were dropped off, which allowed the extruder to cool all the way down to ambient, which then caused a long delay on pickup as the printer waited for the extruder temp to come back up (and as I said before, sometimes the wait became infinite). In any case, Grok wrote out a completely valid bit of Klipper code to add to the end of this macro to make sure the dropped-off extruder temp was set to ‘standby’ properly, as follows:

Then it went on to look at the companion ‘TOOL PICKUP’ macro and identified the real culprit, which was the use of the ‘M109’ gcode command, which sets the extruder temperature, and then waits for the extruder temperature to fall within a very narrow range. This can take 30 seconds or more – and sometimes the ‘more’ is ‘infinity. Grok’s solution was to use the M104 command, which also sets the temperature, but doesn’t wait – it is non-blocking. Then he followed this with a TEMPERATURE_WAIT command that does block – but only until the extruder temp rises to within 5C of the setpoint. Here’s the applicable part of this macro, with the original M109-based code commented out and the Grok code substituted.

These modifications worked extremely well. My test print went from an average of about 30-45sec between the time one tool finished printing to the time the next tool started printing (and as I noted before, it almost always died entirely at some point in the print) to an average of about 15sec inter-tool delay, with complete reliability – YAY!

Here’s a couple of photos of my test print. It is a box with cutouts for chassis-mounted USB-C female sockets; the body was printed in green PETG, and the supports were printed in black PLA.

Of course, my ultimate goal is still to be able to do prints that require water-soluble support material, but the above project at least demonstrated that the two-toolhead MissChanger mod – or at least my version of it, can handle dual-material prints.

03 December 2025 Update:

Made my first water-soluble support print today – yay! I printed the bottom part of one of my caplet dispensers, as shown in the screenshot below:

And here is the result:

07 December 2025 Update:

After running into yet more problems with getting a good ‘squish’ on T1 (and spending WAY too much time working with Grok to no real result), today I went back to Vin’s instructions and went through the entire thing again, carefully.

In preparation for this I changed out the PVA soluble filament for PETG to eliminate any issues associated with the rather flexible and sometimes cantankerous PVA. Then, starting with 4.3. Calibrate offsets .

The first step is PROBE_CALIBRATE. This is the normal ‘paper test’ z-offset calibration, a step I have become very familiar with.

4.3.2. Calibration probe setup: This describes the process of setting up the LUBE_BALLS calibration probe, which I had already done. The description is a bit confusing because Vin also talks about another type of physical offset probe called a ‘Nudge Probe’, so I had to keep working around that issue. Another confusing factor is the need to keep removing and replacing the calibration probe. It can’t be on the bed when doing a QGL, and a QGL is required before doing most steps – ugh!

The steps for validating the calibration probe and calibrating T0, which is then used as the reference for all other toolheads:

  1. Go to printer.cfg and record the z-offset for [tool_probe T0], which should be at (or near) the bottom of the file
  2. Mount tool-head T0 and make sure it’s nozzle is clean
  3. !!! MAKE SURE THE CALIBRATION PROBE IS NOT MOUNTED !!!
  4. Run G28 and QUAD_GANTRY_LEVEL
  5. Mount the calibration probe to the bed.
  6. Run CALIBRATE_TRIGGER_BOTTOM. If it is a fresh calibration probe, it is worth redoing this step until the suggested value is consistent at +/- 0.005mm.
  7. Copy the proposed offset on the console to the trigger_to_bottom_z: in [tools_calibrate].
  8. Save and restart
  9. Run CALIBRATE_OFFSETS TOOL=0 – But, DON’T RESTART
  10. Check if proposed z-offset to be +-0.01mm of the recorded z_offset in step 1.
  11. Run CALIBRATE_OFFSETS TOOL=0 2-3 more times to make sure the measured value is consistent.

The above procedure made a lot more sense today than it did in the past. Maybe I had to struggle for a while and then come back to this from a fresh perspective, kinda like letting go of that NYT Sunday Crossword at midnight, getting some sleep, and coming back to it the next day.

4.3.3. Other tool-head(s):

This is where I got lost before, as I just didn’t understand the strategy being pursued. The idea is to make sure the LUBE_BALLS calibration assembly (probe) is working by using it to calibrate the offsets for T0, and then use the T0 results as the reference for all other toolheads. The magic that makes this work is a macro called CALIBRATE_OFFSETS, which starts by running T0 against the LUBE_BALLS cal probe, and then automatically running each subsequent toolhead T1 through TN against the same probe, thereby establishing the X, Y & Z offsets of all the other toolheads relative to T0. These offsets are then stored in the gcode_x/y/z_offset variables in the [tool T(n)] section in the SAVE_CONFIG area of printer.cfg. If CALIBRATE_OFFSETS is called with a ‘TOOL=N’ argument, then only T0 and TN are calibrated. If CALIBRATE_OFFSETS TOOL=0 is used, only T0 is calibrated as is done in step 9 above.

After doing all this, I wound up with the following offsets for T1:

Amazingly enough, this setup resulted in a ‘perfect’ (or at least ‘damned good’) first layer, using my first-layer adjustment test print, shown below:

After this was successful, I replaced the PETG on T1 with my brand-new roll of SainSmart PVA, and tried my partial pill dispenser test print (shown above) again. This time the first PVA layer was as good as I have ever seen for a PVA layer, and the entire print continued without fail (The PVA supports inside the open cavity of the slide part did get loose about halfway through the print, but that wasn’t due to any calibration problem – just PVA not sticking completely to PVA. See the following gallery of print photos:

So at this point I believe I have essentially completed the journey to add a second toolhead to my Voron 2.4/300 3D printer – what a ride!

MissChanger Docking Woes – Solved!

Posted 25 October 2025

Earlier this month I was able to run a successful docking sequence with one toolhead, as shown below:

Unfortunately, I haven’t been able to replicate this successfully, and after several failures I started looking for the root cause. Eventually I figured out that at least part of the issue was that the middle ‘retainer’ foot that keeps the sliding ‘claw’ from falling off is rotated slightly by the claw when it comes out the ‘docked’ position during an undocking procedure, and this rotation keeps the claw from freely sliding down the ramp and subsequently connecting to the toolhead carrier. See the following two photos for an example of this issue:

At first, I thought I just hadn’t tightened the retainer foot down enough, but doing so actually made the problem worse; now when the toolhead is pulled out of the pins by the toolhead carrier, there is enough force to still rotate the foot, but now the additional screw tension makes it even harder for the claw to slide down to the release position – yikes!

As an experiment, I modified the foot by removing 1mm from the bottom to form a ledge to mate with the front of the base, figuring this would stop the foot from rotating. Unfortunately this did not work – there was still enough play in even a very tightly matched ledge to allow the foot to rotate. Next I decided to create a second point of alignment to the foot by way of a post on the underside of the foot that mates to a hole on the upper surface of the base, as shown in the following photos.

The combination of the post/hole and ledge features seemed to do the trick. Now the claw disengages cleanly from the ‘docked’ position and slides freely down to the ‘undocked’ position as shown in the following video:

In an interesting side note, I discovered that I could easily adjust the rubber band tension by making a loop around either (or both) screw/washer combinations. As it turned out though, even the weakest arrangement (no additional loops) with the new foot/claw configuration was plenty to pull the claw all the way down the slide. Hopefully this will result in much better dock/undock performance – we’ll see.

24 October 2025 Update:

I wound up going through a few minor iterations on the design of the dock body/base and the retainer piece. On the dock body, I opened up all four pin docking holes by 0.5mm, and slightly enlarged the holes for the 2mm self-tapping screws, as these were very difficult to get all the way in, especially the two on the bottom. On the retainer piece, I wound up removing 1mm from the side that the claw slides on, as this seemed to provide a better sliding action.

After getting all this done, I remounted the dock assembly on my printer, and again (for the upteenth time) went through section 4.1. ‘Park position calibration’. When I thought I had everything lined up, I ran TEST_DOCKING only to have it fail – again. The claw wasn’t sliding over to the docked position, so I must not have gotten the Y-position correct and the pins didn’t slide into their respective holes. Went through the whole process again, but this time when I got to the part where the claw was ‘all the way up the ramp’ I commanded an X-minus move of 5mm, and made sure the claw moved smoothly into the docked position. Because I was working with the left-most dock , I was able to actually look through the left side transparency of the printer and see whether the pins on that side were lined up with the holes. Turns out that the docking failure was caused by the Y position being off (1mm too positive). I was only 1mm, but that made a huge difference. Here’s a short video of a successful dock/undock sequence.

Stay tuned,

Frank

MissChanger Klipper Configuration

Posted 29 September 2025

I have decided to make the Klipper-related changes for my MissChanger adventure into its own post, so readers won’t have to wade through all my other non-klipper related blatherings.

The current project status is:

  • My single SB configuration with single-extruder config file 250830_OrigToolhead_printer.cfg & 250920_Original_stealthburner_leds.cfg working fine.
  • Currently using my new SB (due to original SB’s neopixel intermittency) with original SB’s NH BCB (due to new SB,s PCB failure). This combo works fine

Next step is to reload 250928_MC_T0_printer.cfg, 250922_T0-Nitehawk-Revo-LDO_Ex.cfg and 250922_T0_stealthburner_leds.cfg. this config file set loaded and started up fine.

Now it is time to go through Vim’s ‘Calibration’ (Section 4 in the TOC) instructions to see if I can get prints to work

02 October 2025 Update:

The first part of the ‘Calibration’ section is intended to shake the toolhead around on the Tap & Change mount to make sure it will slide onto and off the mount during tool changes.

Ran ‘G28’ (Home All) and confirmed the toolhead Z position of +10mm at the center of the bed.

Set the heated bed temp to 60C. According to Vin, this is to get the chamber temp up to 40C or so before starting the ‘shake & bake’ routine.

Tried to run ‘SHAPER_CALIBRATE’ but got a ‘Unknown Command’ error. Researched this a bit, and decided to skip this step for the moment.

So, I moved on to Section 4.1 – Park Position Calibrate.

First, I mounted the docking hardware I had previously constructed. This in itself required a bit of work to get everything assembled and mounted.

Then I ran the Home-All & QGL and STOP_TOOL_PROBE_CRASH_DETECTION.

I temporarily replaced the ‘100’ with ‘0.1’ in the toolhead movement options for X/Y movement. Then I used these movement options to optimize the ‘X’ position of the toolhead in front of the leftmost dock, as shown.

This process turned out to be a LOT more complicated than I thought, due to the irregular shape of the stealthburner toolhead. Not only did the X position have to be correct, but the dock module rotation around the 10mm rod mattered as well. Eventually I got what I think is a good lineup at X = 68.7.

After getting the X value down, and getting a good dock module orientation, I tried some dock/undock movements as shown in the following short video:

Tool 0 Dock/Undock testing

The above test was performed by moving the toolhead laterally to the optimum X position (68.7), and forward to just in front of the dock (Y ~ 110). Then I commanded a 50mm Y travel to fully engage the toolhead in the dock without forcing the docking collar up the locking ramp, followed by backing the toolhead out 50mm & repeating the process.

At this point I have one toolhead docking station calibrated with the leftmost docking station.

As a side note, my replacement NH USB PC and replacement RGB LED string came in today, so I have two working toolheads again. My original (Red) SB is now labelled as ‘T1’ and my second (Gray) SB is now labelled as ‘T0’. the USB serial ID’s are”

The next step is to create a second toolhead-specific config with its companion stealthburner_leds.cfg. Since the two stealthburners are identical save for their USB IDSs, this should be relatively easy.

I copied 250922_T0-Nitehawk-Revo-LDO_Ex.cfg to 251002_T1-Nitehawk-Revo-LDO_Ex.cfg, replaced the T0 USB ID with the new T1 USB ID, replaced include 250922_T0_stealthburner_leds.cfg with include 251002_T1_stealthburner_leds.cfg, and changed all 20 instances of ‘nhk0:’ with ‘nhk1:’.

I copied 250922_T0_stealthburner_leds.cfg to 251002_T1_stealthburner_leds.cfg and changed ‘nhk0:gpio7’ to ‘nhk1:gpio7’

Then I saved 250928_MC_T0_printer.cfg to 251002_MC_T1_printer.cfg and (on line 826) changed include ./250922_T0-Nitehawk-Revo-LDO_Ex.cfg to include ./251002_T1-Nitehawk-Revo-LDO_Ex.cfg.

Then using SCP in a Windows command window, I loaded all the above to the raspberry, changing the name of 251002_MC_T1_printer.cfg to just printer.cfg.

I disconnected the USB/Power connector onT0 and restarted restarted the printer. Got ‘mcu nhk0’ Unable to connect.

03 October 2025 Update:

I was a bit ahead of myself with getting the second toolhead up and running. For one thing, I discovered the problem I was having with not being able to successfully do a firmware restart instead having to cycle power was a known problem with the LDO USB adaptor board, and the fix was to physically remove two resistor chips from the PCB. I did this for both the USB adaptor boards.

Then I realized I hadn’t really completed the ‘park position calibrate’ step – I had just done the X position step, so I reverted the firmware to the T0 configuration and started over with this procedure. This time I wound up with X = 69.7 (probably due to some lateral movement of the entire docking bar).

05 October 2025 Update:

Finally got all the way through the dock park calibrate step for T0, and was able to run several successful TEST_DOCK cycles

08 October 2025 Update:

The last couple of days have been marked by one disaster after another. First, I have been unable to get the neopixel string on my new(er) Stealthburner to work, even though I would have sworn on a stack of bibles that it was working fine a few days ago. Second, I tried to ‘unload filament’, forgetting that that particular macro (and a few others I suspect) move the toolhead to the front of the printer, where it promptly collided with the docking assembly, and third, I tried a test print with my new(er) toolhead forgetting that I needed to recalibrate the z-axis offset, so my extruder tip was dragging along the print bed while I frantically banged on the fine-tuning Z+ button. I thought I was doing OK until I watched in horror as the entire conical tip of the extruder fell onto the print bed, along with a huge glop of molten filament! YIKES!!!

Neopixel LED Woes:

By swapping the front shell of my known-good original toolhead with the one from my new(er) toolhead, I was able to determine that the neopixel problem followed the front shell – so not a NH PCB, umbilical or USB adaptor problem. I removed the neopixel strings from both shells and swapped just the neopixel string – and the problem followed the suspect string. Visual inspection of the string was hampered by the fact that whoever assembled the string used all black wires for the intra-pixel connections, and then glopped what looks like black RTV on the connections.

While I did find and repair a broken connection, the string still didn’t work. At this point I decided to get a replacement string on order, so I jumped up on Amazon and ordered this:

When it arrived, I plugged it into my new(er) toolhead (thankfully without going to the trouble of installing all the LEDs) whereupon I discovered that it didn’t work either! I did the same thing with my original shell – no joy there either. Now I feel like I’m in an episode of “The Twilight Zone” (for those of you old enough to have watched them); I have three strings, one of which is brand-new, but only my original toolhead string actually works! After sleeping on this, I decided to set up a test jig to test all the strings independently of the printer. I grabbed an ancient Arduino UNO and a 3-pin 2.0mm male JST plug from my parts bin, downloaded Adafruit’s wonderful NeoPixel library and used their ‘strandtest.ino’ example program to drive the string under test. After getting through all the normal stupid programmer issues, I was able to validate the test jig against my known-good neopixel string – Yay! Then I tested the suspect string from my new(er) toolhead – yep still bad – and then the brand-new string from Amazon – bad. I was really shocked that the new string was bad, as it looked perfect physically, and since the pixels are wired in parallel, I would certainly have expected at least one to work. So, I went looking on Amazon for reviews and found one that said the blue (data) and black (ground) wires were reversed in the connector – yikes! I reversed the pins, and voila` the string lit up – YAY!!

Re-pinned Amazon Neopixel string

Now I have two working strings and one that’s still dead. Maybe it has the same mis-wiring issue? I grabbed my trusty Hanmatek DOS1102 digital O’Scope (a must-have for a well-equipped lab) and used it on my brand-new working string to verify that each pixel chip on the brand-new string had good, solid data (see trace-grab below).

However, when I looked at the ‘bad’ string, I can see the proper waveform on the ‘DO’ solder pad on the ‘input’ side of the first pixel, but not on the ‘output’ side (I didn’t realize until just now that there was an ‘input’ and ‘output’ side – I thought the data line was just like the +V and GND – straight passthrough). So, I bypassed the first pixel by physically connecting the ‘output’ wire to the ‘input’ pad and sure ’nuff, the remaining two pixels lit right up!

‘Bad’ neopixel string test with first pixel bypassed

I installed the new Neopixel string into my ‘T0’ toolhead (with the gray shell). Now that I have my nifty Arduino test program, I was able to test the string at each stage of the installation process to make sure all the required wire contortions didn’t fatally pinch a wire or break a solder connection. Here it is after the string was fully installed (and yes, I did check that the front-facing LED was working too).

Toolhead T0 shell with Neopixel string installed

If you happen to have an Arduino-compatible board (Ardiono, Sparkfun, Teensy, etc) you can easily build the same test jig. I have provided the Arduino code below:

Filament Load/Unload macros – and others?

When I tried to do a filament unload, the toolhead promptly drove itself right into the dock – oops! It was at this point that I realized I really didn’t know what I was doing, and had to get A LOT smarter. The filament unload macro (and surely many others) uses print bed size information from printer.cfg. gcode_macro UNLOAD_FILAMENT calls a macro called ‘FRONT’ to move the toolhead to the front center of the print bed, as shown below:

As can be seen in the above code, the line “G1 X{x_center} Y10 F7800” uses the variable ‘x_center’, but goes to Y = 10, which is why it drives into the dock. This macro should really use something like “Y{printer.position_max – 10}, where ‘printer.position_max’ changes depending on whether or not the dock is present (i.e. on the value of the ‘variable_dock’ variable in ‘gcode_macro _home’)

11 October 2025 Update:

The above issue ran me down a rabbit hole from which I have just emerged – dirty but victorious. Although this crash problem could have been fixed easily by just changing ‘Y10’ to ‘Y110’, I was worried about other places where ‘magic numbers’ might be lurking. And then this got me thinking about all those places in the code where ‘printer.toolhead.axis_maximum.y’ is used, as this value doesn’t currently get changed when CONFIG_TOGGLE is executed.

So, I posed this problem to Grok as follows:

I have the MissChanger toolchanger mod installed. This mod uses a macro called CONFIG_TOGGLE to modify some printer.cfg parameters to account for the approximately 130mm at the front of the build plate occluded by the toolhead docking assembly, The python function ‘klipper-toolchanger/klipper/extras/config_switch.py’ manages this by replacing a section of printer.cfg with either the contents of ‘printer_data/config/config/config_no_dock.cfg’ or ‘printer_data/config/config/config_wt_dock.cfg’ I have attached copies of ‘printer.cfg’, ‘config_wt_dock.cfg’ and ‘config_no_dock.cfg’. It looks like the switch code should modify the printer object’s minimum_y value (derived from the stepper_y section’s position_max) instead of ( or maybe in addition to) the ‘variable_xh’ value in printer.cfg, as the printer object’s values are used everywhere in the code. What do you think?

Amazingly, Grok not only agreed with the idea in principal, but went on to digest the files I had provided and then produce a complete step-by-step procedure for implementing the idea, including complete ‘config_switch files. Grok even analyzed ‘klipper-toolchanger/klipper/extras/config_switch.py’ and figured out that the [stepper_y] and [tmc5160 stepper_y] sections would have to be moved below the ‘;< # Section Variable marker’ line in printer.cfg so that ‘config_switch.py’ could modify the ‘position_min:’ value appropriately. And Grok did the whole thing in just a few minutes! To say that I was blown away by this would be to hugely understate the impact this had on me – wow!

Armed with Grok’s step-by-step plan, I was able (after more ‘running around in circles’ than I care to admit) come up with a complete working set of files to support ‘with_dock’ and ‘without_dock’ configuration switching.

At this point I can switch from the ‘dock module installed’ to the ‘dock module removed’ condition freely. It remains to be seen whether I can now build on that to get to a fully functional dual-toolhead system.

16 October 2025 Update:

I was away for a while, but I’m back now. I read through my notes above, and starting from there will try to make a bit more progress. After getting the ‘config_toggle’ to work, I’m going to try to get the current toolhead (gray shell) working to the point of doing a test print. DON’T FORGET TO MAKE SURE THE ‘CONFIG_TOGGLE’ state matches the actual physical state (docking assembly present or not)!

Note: If you get the error “failed to detect active tool” after a head-banging episode, it is probably because the power was cycled with the toolhead resting on the print bed with the z_axis sensor in the ‘triggered’ state – apparently this prevents the toolhead from being ‘active’. Manually raise the gantry sufficiently to UNtrigger the sensor (blue LED changes to RED). Don’t worry about keeping the gantry level as this will be done later.

In the ‘Dock Installed’ configuraion, I got the Home_all to work, but the gantry-level failed with an ‘out of bounds’ error. This was due to the config_wt_dock.cfg file having ‘110’ as the min Y, but ‘position_min’ in [stepper_y] was set to 130 – oops. I fixed this by setting both numbers to 120 and did ‘Save&Restart’. Then I did *two* ‘CONFIG_TOGGLES’ and re-checked. OOPS! no change to ‘printer.cfg’ – how can this be?

I went back into config_wt_dock.cfg and saw that the numbers had not changed – so what happenec? Checked config_no_dock.cfg and those numbers are OK (25 for min quad level move in Y, position_min = 0 in [stepper_y]).

Did ONE Config_Toggle, and I see the value changed to the ‘no_dock’ values. Did a second one, and now the values are ‘110’ and ‘130’ again, even though I changed them to 120 & 120 in config_wt_dock.cfg. No, they are still 110 & 130 in config_wt_dock.cfg. I edited them again, verified that they were still correct after a save, then did a Save & Restart and checked again. This time they are correct. Oooh, I have a headache! I did a CONFIG_TOGGLE and verified the ‘no_dock’ numbers were correct, but when I did another CONFIG_TOGGLE, not only were the ‘wt_dock’ numbers wrong in printer.cfg, they were also wrong in /config/config_wt_dock.cfg! Something is editing (or reverting?) the wt_dock file

OK, the problem was that CONFIG_TOGGLE calls CONFIG_SAVE before anything else, and CONFIG_SAVE, writes the dock-related contents of printer.cfg to ‘config_wt_dock’ or ‘config_no_dock’ depending on the value (True or False) of the ‘variable_dock:’ parameter. Now fixed.

So now HOME_ALL and QUAD_GANTRY_LEVEL both worked as expected in the ‘with dock’ configuration. So now doing the ‘Calibrate reference z-offset’ step. *should* use the value ‘130’ (min_y = 120 + 10 = 130). YES! It did – and I’m getting a successful print – YAY!

The first test print required a ‘fine-tune’ adjustment of +0.350 to get the right amount of ‘squish’. When the print completed, I accepted the change, and this modified the z-offset to -2.000 (was -1.650). The second test print was OK without any fine-tuning.

I would like to have the toolhead go to Z = 225 after the print has finished but, if possible, do this only for the ‘with_dock’ configuration. I modified printer.cfg to put the entire PRINT_END macro just below the ‘variables’ marker, and then changed the finish z-axis position to 225. Then I ran a test print and this worked – the toolhead climbed to 225, pulling the dock assembly with it so I could easily access the finished print. Then I did a ‘SAVE_CONFIG_MODE’ from the console to write the new printer.cfg contents to the ‘config_wt_dock.cfg’ file. I checked this file and verified that the PRINT_END macro had indeed been saved to it. Then I switched to the ‘no-dock’ configuration, again moved the PRINT_END macro below the variable marker, changed the ending z position to Z25, and ran SAVE_CONFIG_MODE to write it out to ‘config_no_dock’.

Then I did a ‘test print, to verify that the PRINT_END macro works as intended in this config.

18 October 2025 Update:

I couldn’t get the TEST_DOCK operation to work. I kept getting ‘move out of bounds’ errors even though I had executed the STOP_TOOL_PROBE_CRASH_DETECTION macro. This worked before, so I was more than a little bit confused. When I asked Grok about this, he maintained that the STOP_TOOL_PROBE_CRASH_DETECTION has only a ‘local’ (whatever that means) effect – the hardware bounds listed in the config file are still checked and honored. Just now it came to me that I caused this problem when I modified the configuration toggle mechanism to dynamically modify the ‘position_min’ variable in [stepper_y]

I thought I was being very clever, but apparently not clever enough for klipper!

19 October 2025 Update:

When I asked Grok about this issue, it gave me a pretty detailed explanation why the previous ‘clever idea’ didn’t (and won’t) work. Here is Grok’s response:

To address your issue with position_min blocking docking operations while still leveraging printer.toolhead.axis_minimum.y (and similar) for general macro consistency, the core challenge is that position_min enforces a hard, system-wide limit on all moves—it’s static after startup and can’t be dynamically toggled or selectively bypassed for specific macros without workarounds. Based on Klipper’s documentation and community discussions, there are no built-in ways to change it at runtime or ignore it per-macro safely. However, here’s a viable strategy that balances your goals, with options from safe (recommended) to more advanced/risky.Recommended Approach: Use Soft Limits with Full Hardware RangeRevert position_min to 0 in both toggle files (config_no_dock.cfg and config_wt_dock.cfg) to allow full Y-axis access at the hardware level—this ensures docking macros can always succeed without errors, even mid-print. Then, enforce an “effective” minimum Y (your occlusion value, e.g., 130) as a soft limit via macro variables and conditionals. This propagates dynamically without magic numbers by referencing a single variable, while still using the printer object’s actual axis_minimum.y (now always 0) as a base.

Step 1: Update Toggle Files for Full Range

  • In both config_no_dock.cfg and config_wt_dock.cfg, set [stepper_y] position_min: 0 (keep other values like position_max: 310).
  • This makes printer.toolhead.axis_minimum.y always 0 after restart, avoiding any hard bounds errors during docking.

Step 2: Define an Effective Min Y Variable. Add or update a global variable in your toggle files (e.g., in [gcode_macro _static_variable] or a new [gcode_macro _limits]). Use variable_dock to set an “effective_min_y”:

[gcode_macro _limits]
variable_effective_min_y: {% if printer["gcode_macro _home"].dock %} 130.0 {% else %} printer.toolhead.axis_minimum.y {% endif %}  # Your occlusion value; use 110 if that's exact
gcode:  # Empty, just for variables
  • Place this in the swappable section of both toggle files (after the marker).
  • Now, printer[“_limits”].effective_min_y acts as your dynamic, dock-aware min Y—it’s 130 when docked (soft-enforcing occlusion for print ops) and 0 otherwise.
  • After toggling/restarting, this propagates to all macros without hardcoding 130 everywhere.

Step 3: Update Macros to Use the Effective MinReplace direct references to printer.toolhead.axis_minimum.y or hard Y values with {printer[“_limits”].effective_min_y} (or add offsets as needed). Examples:

  • Prime Line (e.g., in PRINT_START or a prime macro):
  • {% set prime_y = printer["_limits"].effective_min_y + 5 %} # Safe offset from effective min
  • G1 X{printer.toolhead.axis_maximum.x / 2} Y{prime_y} F7800 # Prime at front if no dock, or just above occlusion if docked
  • Parking (e.g., in PAUSE or M600):G1 X{printer.toolhead.axis_maximum.x / 2} Y{printer["_limits"].effective_min_y + 5} F6000 # Parks safely above effective min
  • Other Macros: For any that position near front (e.g., nozzle clean, unload), use similar: Y{printer[“_limits”].effective_min_y + offset}.
  • Keep [bed_mesh] and [quad_gantry_level] toggling as-is—they already use high min Y (e.g., 110) when docked to avoid probing occluded areas.

Benefits and Trade-offs

  • Keeps Using Printer Object: You still reference printer.toolhead.axis_minimum.y as a base (it’s now reliably 0), but layer the effective value on top for dock awareness—no magic numbers scattered around.
  • Docking Succeeds: Full range allows low-Y moves without errors.
  • Safety: Soft limits prevent accidental print/probe in occluded areas via macros, but won’t block invalid custom G-code (e.g., manual G0 Y10 would still work—add warnings if needed).
  • No Restart Mid-Print: Toggle only when switching dock install state (e.g., hardware changes).
  • Update your slicer profiles to match effective build volume (Y min 130 when docked) to avoid sliced violations.

This is the safest, most maintainable way without risking hardware.

It occurred to me that rather than modifying the dock & no-dock toggle files per Step1, I could simply move the [stepper_y] & [tmc5160 stepper_y] sections back above the variable marker where they started and remove the sections from both the dock & no-dock config files. I checked this with Grok, and he was OK with that. So, Step 1 – complete.

Step2: Grok said the [gcode_macro _limits] section could go anywhere ABOVE the toggle marker, so I put it JUST above the marker, with a comment. I also changed ‘130’ to ‘120’ as I know it works.

Other macros that needed to be modified:

  • Prime line code in [gcode_macro PRINT_START]
  • Front position in [gcode_macro FRONT]: I discovered that past-Frank had shifted this macro into the ‘Session Variables’ section (presumably so the y-value could be changed to reflect the ‘dock/no-dock’ configurations), but the corresponding macros in ‘config_wt_dock’ and ‘config_no_dock’ weren’t any different than the original version – oops!. Moved the CHOME & FRONT macros back to their original positions above the ‘Session Variables’ marker and changed the y value in ‘FRONT’ from {% set y_center = printer.toolhead.axis_maximum.y|float / 2.0 %} to {% set y_front = printer[“_limits”].effective_min_y + 5 %} and ‘G1 X{x_center} Y{y_center} F7800’ to ‘G1 X{x_center} Y{y_front} F7800’. Also added a statement to send the FRONT x,y pos to the display.
  • Removed the CHOME & FRONT macros from ‘dock’ & ‘no-dock config files (and moved the ‘#include'[include 251003_T0-Nitehawk-Revo-LDO.cfg]’ to the top)

Now I will just have to play with the printer for a while and see what happens. Fortunately by this time I have a pretty good understanding of how all the bells and whistles work. As one more safety measure, I have included printer.cfg, config_wt_dock, and config_no_dock here:

config_wt_dock.cfg:

config_no_dock.cfg:

printer.cfg

20 October 2025 Update:

Back to testing after yesterday’s marathon sessions with Grok. Started a test print with the dock in place (“variable_dock: True” in printer.cfg). Hopefully the prime line will get laid down just in front of the dock exclusion area. Hurrah – it worked! The prime line was laid down at Y=125, as expected, and the print itself turned out as well as any in the past.

28 October 2025 Update:

I spent the entire day yesterday trying to get the ‘LOAD_FILAMENT’ macro to work with toolhead T1, with no success. Every time I tried the macro, it would heat the extruder to 230C and then hang forever ‘waiting for temperature’, even though I could plainly see that extruder 1 was at 230C. For a long time I thought maybe this was happening because I hadn’t yet calibrated the PID for the extruder heater, so the temp was varying too much. After I finally figured out how (with a lot of help from Grok) to calibrate the PID, I *still* couldn’t get LOAD_FILAMENT to work. Eventually, with more help from Grok, I figured out the problem. It turns out that the LOAD_FILAMENT macro definition in printer.cfg only works for a single extruder setup, and it was blocking the execution of the multiple-extruder version of LOAD_FILAMENT in the ‘macro_general.cfg’ file that came with the MissChanger installation – oops!

Once I figured this out, I deleted the LOAD_FILAMENT (and UNLOAD_FILAMENT) versions in printer.cfg, and voila! everything started working again!

So now I understand why the example printer.cfg that came with the MissChanger installation is so simple compared to the one I had developed over time since I first got my Voron 2.4 going; it’s because many of the standard operations in my printer.cfg assume a single extruder (named ‘extruder’). This still works OK with my dual extruder setup when extruder T0 is active, as it is also named ‘extruder’. However, when T1 is active, its extruder is named ‘extruder1’, which isn’t recognized at all by the single-extruder macro definitions. The corresponding macros in ‘macro_general.cfg’ have been generalized to deal with any number of extruders, named ‘extruder’ (for T0) or ‘extruder[x]’ (where ‘x’ ranges from 0-N).

After finally figuring this out, I went back through all the macros in printer.cfg to see what other single-toolhead limited code has to be removed to avoid overriding multiple-toolhead versions in macro_general.cfg, but didn’t find any more. Apparently, the LOAD/UNLOAD_FILAMENT were the only ones.

OK, now I’m trying to figure out why my SB LEDs aren’t working, and my assumption is it has something to do with the T0/T1 issue above. I instrumented 251002_T1_stealthburner_leds.cfg to display on the status screen in the ‘Dashboard’ display, and from that I can tell that when I run the ‘status_ready’ (and others), that the correct macro is called (in this case, the one in 251002_T1_stealthburner_leds.cfg). However, nothing happens on the toolhead itself.

251029 Update:

Well, I am truly down the rabbit-hole without a crumb trail on this one. After a full day of working on the issue with Grok, I’m more lost now than when I started. Grok seems completely convinced that the issue is a hardware problem caused by trying to run the nominally 5V neopixel string from the nominally 3.3V RP2040 MCU on the NH PCB. Grok’s cure was to install a WS2812B 3.3-5V Shifter Board. I’m more than a little suspicious of this result, as I remember having the LED strings on both toolheads working not long ago. Here’s a short movie of a dock/undock cycle from 24 October and the neopixel string was working just fine then.

So, my plan is to revert my Klipper config setup to that previous one and see if the LEDs work again. If so, then it obviously is a software, not hardware, problem.

Looking through my saved config files, I found this complete set of config files:

I replaced the contents of printer.cfg with the contents of 251025_wt_dock_printer.cfg (this file uses the 251003_T0-Nitehawk-Revo-LDO.cfg tool-specific config file, which is already available on the printer), and voila! the LEDs on the T0 (gray) toolhead are back, and all the ‘STATUS_xxx’ macros work as well! So, my old “Hardware never fails – it is ALWAYS a software issue” mantra wins again.

When I told this to Grok, he(it?) congratulated me on eliminating hardware as the problem, and then decided the problem was caused when I moved the T0/T1 include files to the top of printer.cfg. This caused the T0/T1 code to be inserted in the wrong place, thereby causing the LED problems I experienced. Grok then guided me through fixing the issues with the dual toolhead config files.

30 October 2025 Update:

Well, Grok and I have been back and forth a lot over the last few days, and I’m sure by now Grok (he/she/it?) is getting frustrated with the inability of this old human to ‘grok’ (and yes, I *am* old enough to have read “Stranger in a Strange Land” when it first came out) the finer points of Klipper configuration file construction.

The basic problem is that whenever I try to implement a dual-toolhead configuration, the stealthburner LEDs are disabled. Grok has explained this is due to ‘included’ files overwriting needed LED control information (like pin numbers?), and has provided several ideas for fixing the problem via different config file edits. Unfortunately my Klipper ignorance is showing (and Grok has some real blind spots as well), so I haven’t been able to get anything to work.

While researching why this LED thing is giving me so much trouble, I came to realize that the real problem is that I started with the single-toolhead config file developed over time since I first got the Voron going, and part of that was the use of the ‘stealthburner_leds.cfg’ add-on that contains all the cool ‘STATUSxxx’ macros. However, vin’s MISSChanger project starts with just a very plain-vanilla printer.cfg file without any of the bells/whistles and adds the multiple-toolhead stuff from there. This was a situation ripe for problems and boy did I have them. I’m going to give Grok’s ideas a good try, but if I can’t make them work, I’m going to go back to Vin’s basic printer.cfg and build things up from there.

31 October 2025:

Last night I was able to verify that ‘klippy.log’ contains the entire in-lined configuration, after all includes and before parsing at the top of each entry. This should go a long way toward effective troubleshooting of the ‘No LEDs’ problem. However, when I started the process of implementing the Grok-suggested changes, I discovered that my printer will no longer connect to nhk0 or nhk1. I get the dreaded “mcu ‘nhk1’: Unable to connect” and/or “mcu ‘nhk0’: Unable to connect” error(s). Since I haven’t made any hardware changes this is kinda hard to believe, and at least so far I’m convinced this is yet another software-induced issue.

So, I plan to go back to my 251025 configuration (251025_wt_dock_printer.cfg & 251003_T0-Nitehawk-Revo-LDO.cfg). Yep! this configuration setup worked perfectly – no errors, and the restart was very rapid (maybe 2-5 seconds).

I’m going to start a new post – “MissChanger Klipper Configuration – Part 2” – as this one is getting a bit cumbersome.

Stay tuned,

Frank

Adding a Second Toolhead to my Voron 2.4

Posted 12 September 2025

Last May I started the process of building a Voron 2.4 300x300mm 3D printer, with the ultimate goal of constructing a dual extruder system capable (hopefully) of complex prints requiring soluble supports. Now that I have the printer running with a single ‘Stealthburner’ toolhead, it is time to move on toward my ultimate goal of a dual extruder system.

After a LOT of research into the many available toolchanger mods, I chose the MISSChanger (the ‘MISS’ stands for ‘Make It Simple, Stupid!’) mod because unlike all the other mods, this one does not require a ‘top hat’ addition to make room for the top-rail-mounted docking system, room that I do not have in my office. Instead, it uses up about 130 mm of print surface (almost half of my available Y-dimension space on my 300×300 plate at the front of the printer for the docking system. If necessary, however, the docking system can be easily removed to recover the print space, but only at the cost of going back to a single-extruder configuration.

No room for a tophat

At this point, I have all the printed parts done, with a working dock module and two separately tested ‘Stealthburner’ toolheads

Now it is time to put all these parts together and see if I can get it all to work!

The MissChanger Github repo contains a ‘Klipper_Config’ folder that holds all the software and also provides a detailed description of the steps required to transition from a single to a multiple extruder firmware configuration. Step1 of this process is backing up the current config files by selecting them in the web interface and downloading them to your computer.

Step 2 (para 3.1.1 in the ReadMe) is the installation of the MissChanger-specific Klipper fork into the Raspbery Pi control computer on the Voron. This is accomplished by ssh’ing into the Pi and running the following command to install the ‘For normal use’ branch:

This operation went OK, but I got a minor error as shown:

When I posted this to Vin, he said – “this always happens the first time – just reboot”. I didn’t actually reboot, but the error seems to have disappeared, so…

On to the next step (Step 2: Set up printer.cfg in the ReadMe): Here is the sample printer.cfg:

14 September 2025 Update:

After a LOT of back-and-forth with Vin on Discord I finally got Klipper to get all the way through the bootup sequence to the point where I could actually try a print. Unfortunately, as soon as I tried, Klipper started throwing errors again, like the following:

This particular error was cleared by noting that there was a capitalization error in printer.cfg’s [temperature_sensor_chamber] section – the word ‘chamber’ should be capitalized, as follows:

Also, it took me forever to figure out how to handle the hardware pin assignment for this sensor. The sensor is connected to the NiteHawk PCB board on one of my two Stealthburner toolheads, but it is used regardless of which toolhead is actually in use. This meant (as I finally figured out) that the above ‘temperature_sensor Chamber’ section had to go into printer.cfg insteaf of one of the ‘Tx…’ toolhead config files, but the hardware pin has to be named ‘nhk0:gpio28’ because that’s actually where the signal shows up.

Then I hit another roadblock:

This got me to thinking about all the macros that were in my original, working-fine, printer.cfg that weren’t in my brand-new multiple-extruder ‘printer.cfg’. So, I took a deep breath and copied them all over to ‘printer.cfg’ and restarted everything. This time Klipper came all the way up – almost like normal!! – and I was able to print a test object – Yay!!

Strap retainer printed in PETG with ‘printer.cfg’ and ‘T0-StealthNhk-CW-Revo.cfg’ using Vin’s multiple-extruder Klipper configuration.

A couple of small flies in the ointment: First, the print started out *way* too close to the bed, just about dragging. I was able to use Klipper’s ‘fine tune’ facility (nice nice nice!) to raise the nozzle enough (1.5mm) to get a good first layer, and the print finished OK. Second, when I tried to save the new Z-offset I got an error about ‘BABY STEPS’ that I didn’t understand. Here are the relevant lines from Klippy.log:

Looking at ‘printer.cfg’ after the print, I see:

The ‘z_offset value of -1.680 *looks* correct, so maybe the fine-tuning offset got saved anyway. Another test print will tell the tale.

Nope – the second print had the same problem, so the offset was NOT saved – bummer!

15 September 2025 Update:

After fumbling around quite a bit with this single-extruder-but-multiple-extruder-configuration, I decided to try revert back to the original printer.cfg, which in this case is my ‘250830_SecondToolhead_printer.cfg’. To do this I ssh’d into the raspberry pi, replaced the existing ‘printer.cfg’, with my ‘250830_SecondToolhead_printer.cfg’ (renamed to ‘printer.cfg’ to the raspberry using SCP at a Windows Command Line prompt (the actual command syntax is shown below)

After doing this and restarting the printer, everything came back up peaches. The printer connected to the web browser page without issues, and now I could see all four temperature readouts as shown below:

The print job ran normally, and although I didn’t really need to, I used the ‘Fine Tune’ facility on the printer to slightly optimize the extruder z-offset to see if the new offset adjustment could be saved at the end of the print. As it turned out – the new offset save was successful, and the printer reset properly and reconnected to the browser properly (the MissChanger configuration did not allow this – I had to physically cycle the power each time to get the printer to come up and reconnect to the browser.

So, it is clear now that the problems I was having were due entirely to the differences in the printer.cfg and its interactions with the rest of the ‘Toolchanger’ software stack. Tomorrow I will try going back to the Toolchanger setup, with a much more basic config.

Stay Tuned!

Frank

16 September 2025 Update:

The plan for today is to start by breaking up my known-good ‘printer.cfg’ into two parts – ‘Printer_Specific_printer.cfg’ and ‘T0_Specific_printer.cfg’. The sum of these parts will exactly match the current ‘printer.cfg’, and therefore, should operate flawlessly – I hope. Here’s my current working ‘printer.cfg’:

Starting from the top:

  • the two includes and the ‘[mcu]’ sections stay in ‘250916_Printer_Specific_printer.cfg’, and the ‘[mcu nhk]’ section goes to ‘250916_T0_Specific_printer.cfg’:
  • The following stay in ‘Printer’:

The [extruder] and [tmc2209 extruder] sections go to ‘T0_Specific’

the [heater_bed] section stays.

The [probe], [fan] (print cooling fan) and [heater_fan hotend_fan] sections go.

The [output_pin caselight] and [output_pin pcb_led] sections stay

The ### Accelerometer ### and ### TH ### sections go

Everything else stays in ‘Printer_Specific’.

I inserted ‘[include 250916_T0_Specific_printer.cfg] just before ‘### Homing and Gantry Adjustment Routines ###’ and then saved the ‘Printer_Specific’ file to ‘MissChager/Config Files/printer.cfg’.

In ‘T0_Specific I changed all ‘nhk:’ entries to ‘nhk0:’ and then saved the file.

Then I ssh’d into the raspberry pi and deleted the existing ‘printer.cfg’

Then, using the following ‘SCP’ command, I copied ‘C:\Users\Frank\Documents\3D Projects\Voron Printer\MissChanger\Config Files\printer.cfg’ and ‘C:\Users\Frank\Documents\3D Projects\Voron Printer\MissChanger\Config Files\250916_T0_Specific_printer.cfg’ to the raspberry pi.

Then, in the MainSail view, I verified that ‘printer.cfg’ on the raspberry pi had been changed, and clicked on ‘Save and Restart’. This resulted in the following error:

Then I restarted the host (printer) and this rebooted the raspberry. This succeeded and I got back into the Mainsail window:

ASSIDE: I noticed when the Mainsail window came up that the ‘ToolChanger’ plugin (along with some others) had the ‘Update’ option activated, so maybe Vin did some more work on that overnight. I left it alone for the moment, not wanting to add yet another variable to the problem.

I attempted to print my simple strap tensioner. It started out OK with the printer homing and going on from there. Interestingly, the Mainsail ‘Dashboard’ window only showed two temperatures – extruder and heatbed.

This test succeeded. The ‘split config’ test worked great. The test print came out fine, with no need for ‘fine tuning’ and the Mainsail display looked OK too.

I think the next logical step would be to add in the raft of [include] statements that are in the MissChanger ‘printer.cfg’ but not in the one I just tested. Before doing that, however, I want to perform all the file updates advertised in the ‘machine’ view

This seemed to work fine, so I proceeded to the next step – adding all the [include xxxx] to the top of printer.cfg.

After making these changes and restarting the printer, I got an error message

Then I used ‘grep -r “safe_z_homing” to find all files with that string. This led me to klipper/klippy/extras/safe_z_home.py, where I found the following:

I looked for ‘homing_override’ in printer.cfg but could not find it. Then I looked for the same thing in the 250916_T0_Specific_printer.cfg file but couldn’t find it there either. Then I looked for safe_z_homing’ and found ‘[safe_z_home]’ (not the same, but close) in printer.cfg.

Then I looked into ‘/home/pi/klipper-toolchanger/macros/homing.cfg’ (one of the files included from MissChanger, where I found the following:

I don’t know if this is a ‘smoking gun’ or not. The error message (and the seems to indicate a conflict between ‘safe_z_homing’ and a [homing_override] section. So, I commented out the ‘[include misschanger_macros/homing.cfg] line and tried again.

This produced an error “option ‘pin’ not valid in section ‘probe’. Uncommenting the line

reproduced the ” ‘homing_override’ and ‘safe_z_homing’ cannot be used simultaneously” error

Got a note from ‘Vin’ saying that I needed to ‘disable’ the safe_z_homing section in printer.cfg. I finally figured out (with some help from Grok) that I needed to comment out the entire section.

When I did that, I got an error: “option ‘pin’ in section [probe] is invalid. So I commented out the ‘probe’ section in the ‘T0—.cfg’ file.

Now I get ‘unknown pin chip name nhk0’. There are 16 instances of ‘nhk0’ in the ‘T0—.cfg’ file and none in ‘printer.cfg’.

Thanks to some more help from Vin and others, I got through this one. It turns out the culprit was this line from ‘250916_T0_Specific_printer.cfg’:

This line ‘names’ the mcu inside the toolhead as ‘nhk’, but all the pin definitions later on used the name ‘nhk0’ – oops! All I had to do was add a ‘0’ to the name, and that error went away — only to be replaced by yet another one. This one is:

I found the symbol ‘speed’ in my toolhead config file:

I commented it out – reloaded the file to the raspberry, and did a ‘firmware restart on the printer. Then the same thing happened with the ‘samples’ symbol in the same secton. Commented that out too, and went on. Same with ‘sample_result’, ‘sample_retract_dist’, ‘samples_tolerance’. Then the error changed to “Option ‘activate_gcode’ is not valid in section ‘tmc2209 extruder’ “. I commented this out, by then realizing that I had actually commented out the entire ‘probe’ section.

At this point I didn’t get any immediate (parsing?) errors, but Klipper wouldn’t restart with just the ‘Firmware Restart’ button. Tried ‘cycling power, ‘Klipper Restart’, and this resulted in the error: “mcu ‘nhk0’: Unable to connect”. Tried power cycling, which resulted in the “Klipper is attempting to restart” error. I looked at Klippy.log, and found a lot of references to not finding ‘mcu nhk’. This led me on a merry chase for quite a while, until I finally did a search for all instances of ‘nhk’ in my toolhead config file, where I found this one little teensy line:

So, I changed ‘nhk’ above to ‘nhk0’, reloaded the file to the raspberry and restarted the printer. Took me a couple of tries, and I finally had to resort to a power cycle, but then it came *all the way* back and now shows the following in the browser window:

Note that all four temps are now shown, including the heat bed temperature – Yay!!

17 September 2025 Update:

Well, maybe I spoke too soon. I tried a test print and got an error saying the extruder temp was too low and a jinja ‘undetermined error’. See the following screenshot:

So now it appears that the PRINT_START macro in printer.cfg is not executing when the line ‘print_start EXTRUDER=240 BED=90’ is encountered in the gcode. I have no idea why this happened, so I’m now officially lost. I think I’m going to (once again) revert to my single working printer.cfg, and work my way back into the two-file configuration while watching closely to see where the system breaks.

I ssh’d into raspberry and used the Windows ‘SCP’ command to overwrite the current printer.cfg. Unfortunately, this time Klipper came back up complaining about “Unknown pin chip name ‘nhk0’ “. This was due to my changing ‘nhk’ to ‘nhk0’ in ‘stealthburner_leds.cfg’, so I changed it back and now everything looks good.

Tried a test print and it went well, *except* the ‘Heatsoak’ display message said ’45c’ instead of ‘100c’. I tracked this down to a bug in PRINT_START and fixed it – so moving on. I completed the test print and confirmed that I could save the ‘fine tune’ result.

Now back to our regularly scheduled program: Following the above procedure, I once again started dividing my known-good printer.cfg into two parts, but this time armed with a bit more knowledge about symbol & object naming.

  • Move ‘[include stealthburner_leds.cfg]’ include to T0
  • Move the [mcu nhk] section to T0
  • Move the [extruder] and [tmc2209 extruder] sections to T0
  • Move the [probe], [fan] (print cooling fan) and [heater_fan hotend_fan] sections to T0
  • Move the [output_pin pcb_led], Accelerometer and TH sections to T0

Change all instances of ‘nhk’ to ‘nhk0’ in T0 (20 instances)

Insert [include ./250917_T0-StealthNhk-CW-Revo.cfg] just before ‘### Homing and Gantry Adjustment Routines ###’

Save ‘printer.cfg’ and ‘250917_T0-StealthNhk-CW-Revo.cfg’ and then transfer them to the raspberry pi.

Reboot the printer

After clearing up a few typo issues, the printer came back up and I was able to print my test model with no issues, and the little ‘fine tune’ adjustment was saved with no fuss – YAY!!

Not so fast!! I discovered that I had the ‘include stealthburner_leds.cfg’ line in printer.cfg and 250917_T0-StealthNhk-CW-Revo.cfg, so I deleted it from printer.cfg, rebooted, and tried the print again. The print completed successfully. Tomorrow I’ll try adding the MissChanger specific includes – but not before saving this file pair several times in different places so I don’t have to start from scratch — again!

18 September 2022 Update:

Saved ‘printer.cfg’ to

C:\Users\Frank\Documents\3D Projects\Voron Printer\MissChanger\Config Files\250918_Working_Without_Misschanger_Includes_printer.cfg

Saved ‘250917_T0-StealthNhk-CW-Revo.cfg’ to:

C:\Users\Frank\Documents\3D Projects\Voron Printer\MissChanger\Config Files\250918_Working_250917_T0-StealthNhk-CW-Revo.cfg

Then I added the MissChanger-specific includes to the top of printer.cfg, rebooted, and got the ‘homing_override and safe_z_homing cannot be used simultaneously’ error. From previous work,

Unfortunately, I can’ seem to find a ‘safe_z_homing’ section in either file. Did a grep safe_z_homing on the raspberry, and got a bunch of hits, but the one that seems relevant is in ‘klipper/klippy/extras/safe_z_home.py’

Then I did a ‘grep -r homing_override’ and got lots and lots of hits, but nothing in user space. So I did a ‘grep -r safe_z_homing’ and got no hits in user space.

19 September Update:

In response to my ‘What am I missing (again!) plea for help, Vin replied:

So, back to the example printer.cfg, where I found that I had completely ignored the ‘Session Variables’ section that needs to be added just before the *** SAVE_CONFIG**** section. The instructions are:

I found my first attempt at this from 09/16 (only 3 days ago?!!!), and after careful comparison of this version with the MissChanger example printer.cft, I constructed another one, as shown below. This version places the [gcode_macro _home], [bed_mesh] and [quad_gantry_level] sections properly within the ‘Session Variables’ section, and replaces the [bed_mesh] and [quad_gantry_level] sections with the versions from my original single-extruder printer.cfg, and adds [include ./250918_Working_T0-StealthNhk-CW-Revo.cfg] the [include] for the current working version of the toolhead.cfg file

As usual, I had to clear up a number of typos and other errors, but I finally wound up with what I hope is the ‘one remaining error’ – Option ‘pin’ is not valid in section ‘probe’. After stumbling around on this one for a while, I finally resorted to asking X/Grok, who came up with this answer:

And that was the revelation: in multi-tool setups the ‘pin’ option is invalid in the (a?) [probe] section. Comparing the T3 sample configuration file to my ‘250918_Working_T0-StealthNhk-CW-Revo.cfg’, I see the following matching sections:

  • The MCU section
  • [adxl345] – c/o in the example file
  • [resonance_tester] – c/o in the example file
  • [temperature_sensor chamber] – remove this section and move the ATC Semitec 104NT-4-R025H42G info into the [extruder] section as shown in the example file.
  • [thermistor CMFB103F3950FANT] – Rename to [thermistor CMFB103F3950FANT0]
  • [temperature_sensor nh_temp] rename to [temperature_sensor T0] and change ‘CMFB103F3950FANT’ to ‘CMFB103F3950FANT0’ to match thermistor section name
  • [extruder3] – rename to just [extruder] for T0
  • [tmc2209 extruder] – name stays the same
  • [fan] rename to [fan_generic T0_partfan]
  • [heater_fan hotend_fan] rename to [heater_fan T0_hotend_fan]
  • [probe] – rename to [tool_probe T0], change number of retries from 5 to 10. Copy “tool:3” from ‘T3-Nitehawk-Revo-LDO.cfg’, and change ‘3’ to ‘0’.
  • [output_pin pcb_led] rename to [output_pin act_led0]

In addition to the above, I have to:

  • Copy the [verify_heater extruder3] section from ‘T3-Nitehawk-Revo-LDO.cfg’, and change ‘3’ to ‘0’.
  • Copy the [neopixel T3_hotend_rgb] section from ‘T3-Nitehawk-Revo-LDO.cfg’, and change ‘T3’ to ‘T0’. Also remove ‘[include stealthburner_leds.cfg]’
  • Copy [gcode_macro T3] from ‘T3-Nitehawk-Revo-LDO.cfg’, and change ‘T3’ to ‘T0’. Change ‘3’ ‘to ‘0’ within the body of the macro.
  • Copy [tool T3] from ‘T3-Nitehawk-Revo-LDO.cfg’. Change “tool_number: 3” to “tool_number: 0”, “extruder: extruder3” to “extruder: extruder”, “fan: T3_partfan” to “fan: T0_partfan”

20 September 2025 Update:

After making the above changes, I changed printer.cfg to include ‘250919_T0_Merged_With_T3-Nitehawk-Revo-LDO_Ex.cfg’, and transferred both it and 250919_T0_Merged_With_T3-Nitehawk-Revo-LDO_Ex.cfg to the raspberry, and rebooted.

After fixing a number of typos, I got the system to come up with no errors. However, when I tried to print my test model, I got an error message saying “Temperature too low to extrude”. This happened before, and I remember it being something that prevented (or skipped) PRINT_START from running. Then I noticed there was an error message “Cannot interact with probe – no active tool probe” underneath the image of the test print model, so I asked Grok about it, resulting in this:

The error “Cannot interact with probe – no active tool probe” in a Voron 2.4 setup with Tap and multiple toolheads typically indicates that Klipper cannot identify an active tool or its associated probe, often due to incomplete hardware setup or configuration issues in tool changer mods like TapChanger or StealthChanger.

These designs rely on OptoTap sensors (PCBs) installed on every toolhead for dual purposes: Z-axis probing (like standard Tap) and detecting which tool is currently active/mounted on the gantry.

Common Causes and Fixes: Missing or Incomplete OptoTap Sensors: Each toolhead must have its own OptoTap sensor wired correctly. Parked toolheads typically have their sensors in a “triggered” state (e.g., mechanically engaged in the dock), while the active tool’s sensor is “not triggered.” If any toolhead lacks a sensor, Klipper can’t reliably detect the active one, leading to the error. Solution: Install and wire OptoTap on all toolheads—shorting pins temporarily can act as a workaround for testing, but order proper sensors for a permanent fix.

This triggered (pun intended) an earlier memory; I had inadvertently left the printer on overnight and when I came into my office this morning, I noticed that the blue ‘triggered’ LED on the toolhead was illuminated. I thought nothing of it at the time, but Grok’s input led me to turn the printer off and manually move the gantry up a bit so the toolhead tap probe would not be triggered.

OK! This time the print actually started (or at least the head movement started). Then I got “Heater extruder not heating at expected rate
See the ‘verify_heater’ section in docs/Config_Reference.md
for the parameters that control this check.

I had previously commented out the [verify heater extruder] section to get past a different error, so I uncommented the block and restarted the test print. So far, so good!

Nope – same error message: Looked some more and found that I had not included the [heater_bed] section in printer.cfg. Edited C:\Users\Frank\Documents\3D Projects\Voron Printer\MissChanger\Config Files\250919_With_MissChanger_Includes_and_SessionVariables_Section_printer.cfg to add this section and restarted. Starting another test print, and this time the status line shows: “Bed: 90c”, and the bed is definitely warming. However, when I looked at the actual heat_bed temperature reading, it stayed at 45c, indicating that the thermistor values weren’t being read by the mcu.

Then I had a similar issue with the extruder temps, so I may simply have the extruder and heat bed thermistor pin assignments swapped.

This may turn out to be a misconfiguration issue with the extruder hotend thermistor. There are actually 3 different places in the config that cite the same ATC Semitec 104NT-4-R025H42G thermistor

  • sensor_type: ATC Semitec 104NT-4-R025H42G in the [extruder] section
  • sensor_type: ATC Semitec 104NT-4-R025H42G in the [heater_bed] section
  • sensor_type: ATC Semitec 104NT-4-R025H42G in the [temperature_sensor chamber]

To eliminate any hardware issues, I swapped the toolhead back to my original one and changed printer.cfg back to ‘250830_OrigToolhead_printer.cfg’ to try to get back to a baseline.

Unfortunately Klipper came up with “unknown pin chip ‘nhk0’. I finally figured out that this was caused by me editing ‘stealthburner_leds.cfg’ for the second toolhead by changing ‘nhk’ to ‘nhk0’. I fixed this and (once I moved the chamber thermistor back from my second toolhead) I now have a working baseline, with all four temps shown – yay!

OK, now that I know the pin assignments in ‘250830_OrigToolhead_printer.cfg’ are correct, I can start comparing them to the later configs.

Comparing ‘250830_OrigToolhead_printer.cfg’ to ‘250830_SecondToolhead_printer.cfg’ I verified that they are identical in every way *except* for the nozzle diameter (0.4 on orig & 0.6 on second) and the unique USB ID. So, I should be able to swap in the second toolhead and its config and get it to come right up.

Yep – came up no problem, and successfully printed the test model.

So at this point we know that all the hardware works, and – more importantly – the nhk pin numbers in either printer.cfg correctly match the actual hardware. In particular the pin assignments for the three different ATC Semitec 104NT-4-R025H42G thermistors are:

  • In the [heater_bed] section it maps to ‘sensor pin: PA2’. It stays the same with all toolheads and is placed in printer.cfg.
  • in the [extruder] section the thermistor maps to’sensor_pin: nhk:gpio29′.
  • In the [temperature_sensor chamber] it maps to ‘sensor_pin: nhk:gpio28’.

Now back to the multi-toolhead ‘printer.cfg’ and my ‘T0 toolhead.cfg

comparing my original printer.cfg and 250919_With_MissChanger_Includes_and_SessionVariables_Section_printer.cfg, I see that in the [heater_bed] section they both map the thermistor to ‘sensor pin: PA2’. Good

Comparing the original printer.cfg to ‘250919_T0_Merged_With_T3-Nitehawk-Revo-LDO_Ex.cfg’:

  • [mcu nhk] becomes [mcu nhk0]
  • [extruder] sections are identical with the exception of the nozzle size and ‘nhk0’ vs ‘nhk’. In particular, they both point to the same pin nhk:gpio29 vs nhk0:gpio29. oops! duplicate ‘sensor_type’/’sensor_pin’ declaration to nhk0:gpio28 in the ‘T0—‘ file [extruder] section. Removed.
  • [temperature_sensor chamber] section in the ‘T0—‘ file was commented out – uncommented and verified it is pointed to nhk0:gpio28

OK, loading ‘250919_T0_Merged_With_T3-Nitehawk-Revo-LDO_Ex.cfg’ and ‘250919_With_MissChanger_Includes_and_SessionVariables_Section_printer.cfg’. This should work with the ‘T0’ toolhead already mounted in the printer.

It looks like everything is working with the T0 (gray) toolhead, *except*:

  • None of the ‘STATUS_xxx’ commands work
  • Still can’t save baby steps after a print

23 September 2025 Update:

Well, today I got everything working, including all the STATUS_xxx RGB LED macros, and I can now print and save the z-offset (‘baby steps’) from the ‘fine tune’ facility. All the code corrections are in 250922_printer.cfg, 250922_T0-Nitehawk-Revo-LDO_Ex.cfg and 250922_T0_stealthburner_leds.cfg (the only change in 250922_T0_stealthburner_leds.cfg is this line: pin: nhk0:gpio7 – it has to match the ‘T-ness’ of the associated toolhead. So there will be a T1_stealthburner_leds.cfg and it will point to ‘nhk1:gpio7).

I was basking in the glow of completion when I when I noticed that the next step, which was to run SAVE_CONFIG_MODE to create the needed ‘config_no_dock.cfg’ and ‘config_wt_dock.cfg’ files (which are in the wrong directory, but this doesn’t seem to hurt anything, so…). With a *lot* of help from Vin I got this done, only to find out I couldn’t proceed because my printer refused to recover from a FIRMWARE_RESTART call (which I believe has to happen on every tool change). Fortunately, I was able to troubleshoot this problem by replacing the toolhead I was using (the one I built from a kit from KB3D) with the one I built with the original LDO kit. Eventually by changing things in and out I was able to determine that the NiteHawk PCB on the ‘new’ toolhead was defective and wouldn’t reliably connect to raspberry pi via USB.

After figuring that out I created a support ticket on KB3D and it is now working its way through the system (KB3D responded very quickly, but ultimately the decision for replacement has to come from LDO, which means China. Hopefully that will work out OK.

In the meantime, I should be able to continue by using the ‘old’ toolhead, which is working fine.

24 September 2025 Update:

To summarize where I am at the moment. I have a complete working set of hardware, consisting of:

  • My original Stealthburner with Nitehawk USB PCB
  • A working printer-specific configuration file (250922_printer.cfg)
  • A working toolhead-specific configuration (250922_T0-Nitehawk-Revo-LDO_Ex.cfg)
  • 250922_T0_stealthburner_leds.cfg – included in 250922_T0-Nitehawk-Revo-LDO_Ex.cfg to handle toolhead RGB LED ‘STATUS_xxx’ color combinations

I ran a test print with the original toolhead, and it worked fine except for the starting z-offset. I used ‘fine tune’ to adjust this during the print, then cancelled the print, saved the offset, and reprinted the part. I had wondered if Klipper would offer to save the offset for a cancelled print, and now I know the answer is ‘Yes’.

The next print went the other way a bit in terms of z-offset, so I know the adjustment ‘took’. I adjusted it down a bit, cancelled, saved the offset, and started another print.

The next one overshot the mark again, toward too small an offset. I began to wonder if the fact that my current toolhead uses a 0.4mm nozzle, but the config was for a 0.6mm nozzle. I changed that and started another print.

In the next print, I used fine tune to adjust the offset down (toward the bed) by 0.250. This time I was smart enough to check the current configuration file offset *before* applying the offset. I saved printer.cfg & T0xxx.cfg to ‘Downloads’, then I applied the offset and started another print.

Comparing printer.cfg files, I see:

was added to the bottom of the SAVE_CONFIG section. I guess I won’t really know about offset adjustments until after the upcoming print.

OK, this time the adjustment was +0.450 (away from the bed), and now the #*# z_offset is -1.614, a change of -0.200; no idea why this works this way.

Started yet another print. This time the adjustment was -0.550 (toward the bed), and now the #*# z_offset is -2.164, a change of -0.550; at least that makes sense mathematically.

Another run, this time the adjustment was +0.250 (away from bed), and now the #*# z_offset is -1.314, a change of +0.850 – over 3x the offset I *thought* I was applying. WTF? I posted this data to the Voron discord in the ‘Klipper help’ channel, but haven’t seen anything remotely helpful so far.

25 September 2025 Update:

So, today I started over – again. I replaced the printer.cfg file with my 250830_OrigToolhead_printer.cfg file and did a Z-calibrate to get reasonably close to a printing starting point. Before the calibrate, the z_offset was about -1.6. After the Z-calibrate, I see

The print didn’t start. I got a ‘too many retries’ error (on the QGL I think). Nothing in Klippy.log though. Tried again and this time the print started OK. Used fine-tune and raised the nozzle +0.700. Stopped the print, saved the offset, and now I see:

Which makes sense (-0.530 – 0.70 = -1.230).

Did another manual Z-probe calibration. After the calibration finished, I see:

Did another manual Z-probe and this time the ‘before’ and ‘after’ numbers were very close (0.02mm). After completion, I see

So the Z probe cal is working properly.

Tried another print. This one started out with *almost* perfect offset. I dropped it down just a bit. After the reboot, I see:

So, just 0.05mm toward the bed, resulting in a slightly smaller negative offset.

So, at this point it looks like the original toolhead with the original printer.cfg is working properly. Did another print, and this one looks great.

All this time, none of the ‘STATUS_xxx’ LED colors were visible, even though it looks like the proper stealthburner_led.cfg file has been included. Hmm, I screwed around a bit with stealthburner_led.cfg, and now all of a sudden the LEDs are working again! Magic!

Reseated the neopixel cable connector to the NiteHawk PCB and things seem to be working for the moment.

So the situation at the moment is: I have my original toolhead and original printer.cfg working, and the Z-prob cal & fine tuning process seems to work, and produces believable, consistent offset values. The next step is to replace printer.cfg with my MissChanger versions 250922_printer.cfg, 250922_T0-Nitehawk-Revo-LDO_Ex.cfg and 250922_T0_stealthburner_leds.cfg

OK, changed back to the ‘MissChanger’ set of config files, and ran the Z-probe calibrate routine. At the start of the procedure I see:

At the end of the calibration process I see a Z: 0.530, very close (assuming sign match) to the current value. After accepting the above value and restarting, I see:

Note that the above is quite a bit different than what I saw in the ‘original’ config setup. Now there are *two* values of interest – the [tool_probe T0] value of -0.5673, and the [tool_probe_endstop] value of -1.870, neither of which are the value I got from the calibration (although the too_probe T0 value is pretty close).

Tried a test print: (Side note: neopixel LEDs are all OFF and don’t respond to a STATUS_PRINT command

After the print started I did a live-adjust to +0.400. When the print finished, I saved the offset, and looked at printer.cfg to see:

Frank

Looking at the post-Z-cal values I see that [tool_probe T0] was -0.563750 and is now -2.270. [tool_probe_endstop] z_offset was -1.870 and is now -0.964. Neither of these values make any sense to me.

Did another print, and this one started out with too little squish. I adjusted down by 0.1 and that seemed to work. Saved the offset, and now [tool_probe T0] changed from -2.270 to -0.864.

Did another print, and this time I had to go up 0.400 again! After cancelling the print, I accepted the adjustment and looked at printer.cfg. This time [tool_probe T0] changed from -0.864 to -2.570.

26 September Update:

I got a note from Vin that he had found and fixed a bug that might (or might not) have caused the above offset-related problems. So, I’m back to running the same series of experiments as before the update.

First print: I forgot to do the probe calibration beforehand, so who knows where the nozzle will be :(. I would start over, except that the printer takes sooooo loooong to heat up. The nozzle was *way* off the bed, and it took a fine-tune adjustment of -1.050mm to get it back down to where it was printing at least somewhat normally. Cancelled the print and saved the offset adjustment. Before applying the adjustment, the offset in printer.cfg were:

From the before and after values, it looks like the tool_probe z_offset value went from -2.57 to -1.264, a change of +1.306 (closer to the bed). The tool_probe_endstop value changed from -1.264 to -1.520, a change of -0.256 (farther from the bed). So the net affect (if this story can be believed, is a change of +(1.306-0.256) = +1.05 (closer to the bed, I think). This value (1.050) is exactly what was entered during fine-tuning. This, of course, begs the question of why this amount was allocated between these two values in such a way.

Second print. This time I had to adjust 1.35mm away from the bed in order to get a good first layer. The ‘after’ probe values are shown below:

From the before and after values, it looks like the tool_probe z_offset value went from -0.214 to -2.87, a change of -2.56 (farther from the bed). The tool_probe_endstop value changed from -1.520 to -1.564, a change of -0.36 (farther from the bed). So the net affect is a change of -(2.56+0.36) = -2.92 (farther from the bed). This value (2.92) is more than twice the entered adjustment value of -1.35mm.

This time I set the extruder temp to 150 and then did a PROBE_CALIBRATE from the Voron front panel, using a piece of paper with a measured thickness of 0.9mm. With the paper dragging just a bit, the required offset was -1.13. Before accepting the result, the printer.cfg values were:

After accepting the offset value, the probe values are:

As a result of PROBE_CALIBRATE, the [too_probe T0] value was not changed, but the [tool_probe_endstop] value was changed from -1.564 to -1.840, i.e 0.236mm farther away from the bed.

I did another Z-CALIBRATE and this time the [tool_probe_endstop] value changed from -1.840 to -1.744, about 0.096 closer to the bed.

A third calibration resulting in -1.185, and the [tool_probe_endstop] value stayed constant at -1.744.

Did two test prints. For the first one I had to lower the nozzle over 1mm to get a decent print, and on the second on I had to raise the nozzle by over 1mm to get a good print. This is not acceptable. I think I’m going back to my single-toolhead configuration until this can get sorted out. A second factor in all this is it seems my neopixel LEDs aren’t dependable in the multi-tool configuration, and I don’t remember them being this way.

Went back to my single-toolhead configuration. Did a Z_CALIBRATE, and the new offset was very close to the ‘saved’ offset.

Started a test print. It printed perfectly the first time – no ‘fine-tuning’ required. However, the toolhead LEDs are still OFF – so this may well be a hardware issue on the toolhead.

I loosened the top two screws on the stealthburner, and now the LEDs are alive again. Maybe a pinched wire? I removed the front half of the stealthburner, and I could see where the ground (black) wire leading from the lower LEDs to the upper set could have been pinched by the front half when the screws where tightened. I moved this wire out of the line of fire, and now everything seems to be going OK.

28 September 2025 Update:

I’ve been fighting a couple of hardware problems with my stealthburners. The Nitehawk PCB on my second (“new”) toolhead has become intermittent, so I’m corresponding with LDO via the KB-3D discord, trying to get me to send me a new PCB. In addition, the neopixel LEDs on my original stealthburner have become intermittent, to the point where I ordered a new neopixel assembly from Amazon. I was able to replace the defective NH PCB on the ‘new’ toolhead with the one from the original one, thereby giving me one toolhead with both LEDs and PCB working.

I got info back from Vin that I’m ‘almost there’, but I apparently missed a vital step in setting up the z_offset, step 4.3 as shown below:

I changed back from my single toolhead configuration to the MissChanger T0 configuration (250922_T0-Nitehawk-Revo-LDO_Ex.cfg, 250922_T0_printer.cfg and 250922_T0_stealthburner_leds.cfg. Because I switched NH PCBs, these .cfg files probably reference the wrong USB serial port ID, so I’ll have to fix that before moving on.

25 October 2025 Update:

I now have a two-tool config set (printer.cfg, T0 & T1 toolhead configs) working – at least as far as the config files go. I can start up with both toolheads connected, but as soon as I try to do anything that requires a tool switch, I get a bunch of errors:

  • Gantry is not LEVELED…
  • Printer is not HOMED…
  • Calibration Probe is not in place…
  • No tool selected (“A” / “a” / “0” / “1” / etc.)
  • Cannot select tool, toolchanger status is uninitialized

I finally worked my way through all the errors, and got to the point where I had T1 mounted in its cradle, and found that the proper X value for it is 246 – with the Y value the same as for T0. I ran TEST_DOCKING and was stunned to see the printer try to dock and undock T0 instead of T1!

After clearing up some more errors, I was planning to try that trick again but discovered that Klipper now didn’t recognize *either* toolhead and refused to respond to any movement commands. Even power cycling the printer didn’t solve the problem. Eventually barring any other ideas, I decided to manually mount T0 onto the carriage, and “lo and behold!” everything started working again. This makes NO SENSE to me, as I can’t see how the printer (klipper) can tell if a toolhead is actually mounted on the carriage. It’s a mystery.

Hallelujah! I got the printer to do a toolchange from T0 to T1 and then from T1 back to T0! See the short video below:

Reading some more through Vin’s ReadMe, I came across this note in the “‘Tool-change Tuning” section:

The speed and path of the default tool-change routine in misschanger_settings.cfg is tuned for reliability. It is slower and has more steps than needed. For a smooth running MissChanger. The params_path_speed can be increased and some of the “Wiggle wiggle”, in the path, can be disabled.

So I looked into misschanger_settings.cfg and saw this:

So it looks like there is plenty of “wriggle room” (pun intended). I modified this by removing several lines of ‘wriggle’s and restarted the printer. Then I did a toolchange and noted that the tool un-dock motion was a bit less frantic. I’ll let this ride for a while now and see how it goes.

26 October 2025 Update:

After getting the toolchange operation working, I have been trying to work my way through the the MissChanger Klipper_Config ReadMe instructions. It’s a bit confusing, as “Step 2: Set up printer.cfg” also incorporates a number of ‘Steps’ whose numbering duplicates the step numbers in other sections. After getting T0 working with the dock assembly and making some test prints, I started working on “Step 6: Make the next tool-head and its config file”. I created a config file for T1 and [include]’ed it in the session variables section of printer.cfg. Then I copy/pasted the ‘[tool_probe T0]’ & ‘[extruder]’ sections to ‘[tool_probe T1]’ & ‘[extruder1]’ in the ‘SAVE_CONFIG’ section of printer.cfg.

27 October 2025 Update:

I was running around in circles yesterday, trying to use the MissChanger calibration probe to get both toolheads zeroed in, and failing miserably. So today I decided to go back to basics on Tool 0.

I temporarily removed the docking module, as I discovered yesterday that the active toolhead brushes the inactive toolhead during quad gantry levelling operations. This isn’t bad enough to do any damage, but it definitely needs fixing.

After HOME_ALL & QGL, I did a PROBE_CALIBRATE to find the zero offset for T0. This value came in at -1.830 – significantly different than the -2.000 I had been using up til now. Not sure what caused this. Note that the new offset value appeared in the original

section at the very bottom of the SAVE_CONFIG section. This section isn’t used by MissChanger, so per the ReadMe I copy/pasted that value to

Then I made a test print, and it came out perfectly, with no fine tuning required – Yay!

Now I have a working baseline again – so I can go forward. The first thing I want to do though is fix the problem with the active toolhead brushing the inactive toolhead when doing a QGL. I re-attached the docking module and remounted the inactive toolhead in the left-most dock. Then I used manual position control to move the active toolhead back and forth on the X axis past the inactive toolhead, for decreasing values of Y.

OK, this turned out to be a false alarm. The toolheads only brush if the inactive toolhead is in the ‘release’ position (still in the dock, but not in the parked position). When the inactive toolhead is in the parked position, there is plenty of room – yay!

Then I did a HOME_ALL & QGL with the red toolhead in the fully docked position to verify the clearance – worked great!

Then I manually (using the MainSail control panel) switched from T0 to T1, and redid the PROBE_CALIBRATE operation. This time though, I copied this value:

to ‘tool_probe T1’ instead of ‘tool_probe T0’.

After a brief side-trip down the LOAD/UNLOAD_FILAMENT rabbit-hole (see the 28 October Update in this post) Then I tried the same test print as before.