Monthly Archives: November 2025

GPS-enabled Dash Cam Power Switch

Posted 10 November 2025

A while ago I got a dash cam for my truck, thinking that would be a good thing to have if someone tries to cash in on my insurance by deliberately backing into me on the road. So, I got this dash cam, mounted it on the windshield of my truck, and life was good. Then my wife and I went out of town for a few days and when we came back (at 2am), the truck battery was dead and it took us a while (and a new car battery) to recover. This happened one more time, fortunately in my garage, and I decided I was going to have to come up with a way of killing the power to the dash cam when (or shortly thereafter) the truck stopped moving.

I researched the power outlets in my truck (a 2011 Ford F-150) and found that the power to the SYNC system was (at least theoretically) on only when the engine was running. Unfortunately, I had pulled the fuse for this circuit years before to keep SYNC from grabbing my phone’s Bluetooth signal even though I had long ago UNpartnered SYNC and my phone, so that was out.

My next idea was to construct a power switch around one of the recent GPS modules available cheaply, such as this one. I looked around a little bit, and found the nice ‘TinyGPS++’ library, and used a Sparkfun Pro Micro (the Arduino version) from my parts box to interface to the GPS module. Another search and I found an example sketch, and I was in business. After the usual number of errors I got the sketch working, with data displayed in the serial window of my Windows 11/Visual Studio/Visual Micro setup.

Unfortunately, all the data came back as ‘INVALID’, mostly because we live in an earth-sheltered house, and that pretty much snuffs out any GPS signals. The next day I took my laptop and the breadboard for a spin, and the GPS module started spitting out valid data about 30 seconds after I backed out of the garage. The data looks like this:

This isn’t particularly useful for my project, as I had planned to use speed < MPH_THRESHOLD for some time > ELAPSED_TIME_THRESHOLD, maybe something like 10-20 minutes. The above data has the time I need, but not the speed. Maybe the TinyGPS++ library has that capability?

Yes, the TinyGPS++ library does have the methods I want. Here’s the code I came up with:

Now to test the code. I found a free web-based app called NMEASimulator by panazzolo.com that allows me to set a course with heading and speed, and then output the corresponding NMEA sentences to a COM port. With a USB-to-Serial adapter I should be able to replace the data lines from the GPS module with the simulator output and test the code.

12 November 2025 Update:

My USB-to-Serial adapter arrived today, and I was able to connect it to my GPS switching board, bypassing the actual GPS. Then I was able to use the NMEA simulator to transmit NMEA messages to the Sparkfun Pro Micro and test the Dash Cam power switch algorithm.

This combination worked great! I started the action, NMEA sentences started flowing to the Pro Micro which output decoded speed values to the debug window. I could run the speed up and down and watch the program toggle power to the load (39-Ohm power resistor) in response to the speed changes. The only things left to do are to build an enclosure and change the time and speed threshold parameters. Here’s the ‘final’ code:

26 November 2025 Update:

Thinking about how to test my GPS-enabled power switch project, I decided to add a cheap LCD display so I could monitor GPS output and power switch status in real time. So, I reached into my parts box and what came out was a pair of ‘Cheap Yellow Display’ modules had been laying around for some time now. As I started working with the display, I realized it wasn’t just a display; the ESP32-2432S028R development board that runs the touch-sensitive display incorporates a ESP32-WROOM-32 module as its main microcontroller. This module features a dual-core Xtensa LX6 processor running at up to 240 MHz, 520 KB SRAM, 448 KB ROM, integrated Wi-Fi (802.11 b/g/n) and Bluetooth (v4.2 BR/EDR and BLE), and 4 MB flash memory. In addition, the board has a standard micro-USB port for power and programming, a USB-C port for power, three 4-pin micro-JST 1.25mm pitch connectors for UART and GPIO, and a 2-pin micro-JST connector for a speaker. Looking at the specs, I realized I could conceivably eliminate the Sparkfun Pro Micro module entirely, and have just the display/CYD connected to the GPS via CN1 (4-pin GPIO/power/GND) and a single GPIO output (plus GND) to run the power switch.

A not-so-insignificant hitch in the getalong for this project was the type of connector required to interface to the sockets on the CYD. It turns out these are ‘micro JST 1.25mm’ connectors, and it took me three tries with Amazon to get the right ones. These are the correct ones.

I was able to easily connect the GPS input to CN1 and use the NMEA simulator to test the code, ported over from the Pro Micro project. However, I hit a roadblock when I went looking for a GPIO port to use as a switch signal to the power switch board; it turns out the display occupies most of the GPIO lines, and the two ports needed for GPS Txd & Rxd took the only remaining output-capable lines (IO35 is available, but it is input-only). Some more research with the help of Grok led me to this project site that describes how to free up ports via hardware mods. There I found directions for freeing up IO21, the port that normally controls display backlight brightness by PWM-ing the backlight LED. This involved removing a surface-mount transistor and re-orienting a TINY! surface-mount 3.9 Ω current-limiting resistor, as shown in the screenshot below:

As you might guess, this took some doing, as these parts are TINY!

But after a couple of false starts, I got it done:

The photo below shows the CYD module with GPS data displayed, and with my newly-liberated IO21 line connected to the power switch board (the illuminated red LED shows that the power switch is ON)

So now we are pretty close to being done; all that is left is to mount the display/controller into its box, mount both the display & power switch boxes onto their custom-printed carrier, and test the whole thing in my truck. The ‘final’ (to the extent that anything I do is actually final) code is shown below:

Here is a short video of the CYD display and power switch during a driving test in my local development loop. At the start of the video, the GPS module has already detected 8 sats (hard to see), so as soon as the computed speed goes over 5mph, the power switch changes from OFF to ON (red LED on the power switch and ‘ON’ on the CYD.

Unfortunately it was at this point that I discovered that the BUZ76A MOSFET power switch had too high of an Rds (around 4Ω) to actually turn on the camera -bummer!

Some discussion with Grok netted me a low-Rds MOSFET – the AOD424G AOD424 TO252 with Rds in the milli-Ohms. This has a pretty low Vds(max) of around 20V, but this is fine for my needs as it will only be switching 5V. Here’s the new schematic:

01 December 2025 Update:

As things are coming together on the electronics side, I took some time to investigate mounting options in my truck. After fiddling around a bit, I came up with the following possibility:

This would actually work out great, as the PETG plastic boxes wouldn’t be directly exposed to sunlight, and, the display would still be very visible to the driver, and it wouldn’t block vision to my time and temperature display at the top of the radio stack. As a huge bonus, it turns out there is enough slack in the USB power cable to the dash camera that I could plug it directly into the switch box (green in the photo above, if I changed out one of the USB type-C chassis connectors for a USB2/3 type. $7 for 5 connectors from Amazon – delivery in less than a week – yay!

Of course this means I need to change the box design, but that won’t take long.

08 December 2025 Update:

I got my new USB2 connector, and redesigned the box & lid to accommodate it, creating a conundrum in the process.

See the problem?

When I started wiring everything in, I realized I had created a big problem. If I ever wanted to remove the proto-board from the enclosure, I would have to unsolder all the wires to the USB connectors first – UGH!! I thought I could solve this problem by adding connectors in the lines to the USB connectors, but I hated that idea as it just adds complexity (“a connector is a source of trouble between two other sources of trouble”), so I put the whole thing aside to await a better solution. This morning while exercising it came to me – redesign the enclosure so the parting line between box and lid is right at the top edge of the connector modules. Then the proto-board and connectors can be lifted right out after removing the two proto-board mounting screws – genius! Only one small ‘gotcha’ the USB-C connectors will have to be flipped 180𝆩 so the PCB slot is on top rather than on the bottom. Since USB-C connectors are orientation insensitive anyway, this shouldn’t be an issue. Here’s a screenshot of the ‘final’ (as final as anything gets in my world) enclosure, with the connector cutouts moved to the top so removing the lid will allow the PCB – with the connectors still attached – to be lifted out.

Here are some photos of the ‘finished’ product:

After installing it in my truck, I made a couple of test runs around my little development’s circle, and it seems to be working great. Here are some photos showing the installation in my truck:

Here is the ‘finished’ version of the firmware:

15 December 2025 Update:

Now that things seem to be working, I’m trying to clean up the installation a bit. Here are some photos showing some of the current temporary installation details:

I also took the opportunity to measure the current load with the display and switch box electronics powered, but with the dashcam OFF. This is important, as this load determines how long the battery will last in this configuration. I used my handy-dandy USB2 ‘Charger Doctor’ pass-through device that alternately displays output voltage and current. As shown in the following photo, the ‘OFF’ current draw is about 0.19A.

Showing current draw in the ‘dashcam OFF’ configuration. The meter shows 0.19A (190 mA).

The 12V car battery in this truck is a ‘DieHard’ AGM Technology battery as shown below:

So I asked Grok how long this battery would last with the dashcam OFF, but the display (and it’s imbedded MCU) still powered up with a 0.2A draw, and this is what I got back:

So almost a month – that sounds about right, and it means I wouldn’t have had a dead battery at 2 am when my wife and I got home from last summer after a week at the 2025 Senior Games in Des Moines, Iowa!

Just as a sidenote, I have a ‘premium’ subscription to X not because I think X posts are worthwhile, but because Grok *IS* worthwhile. As a long-time electrical engineer, I was familiar with the property of lead-acid batteries that extended the discharge time under very small loads compared to the normal A-Hr rating, but I had never heard of the ‘Peukert effect’, which allows for a much better estimate of discharge times for low loads. This took Grok about 30 seconds – what a *great* engineering assistant!

And, speaking of Grok, I also asked him (it?) for the name and purpose of the ‘cubbyhole’ I’m using as the mounting cavity for the dashcam switch project. Turns out this was probably originally intended for an ashtray, and then repurposed as the mounting cavity for a trailer brake module. And, he also came up with dimensions, which should allow me to design a cradle that will fit snugly in the hole and keep the dashcam electronics from sliding around. We’ll see!

17 December 2025 Update:

A couple of interesting things happened in the last two days. The first thing is I have been cursing at the maker of the SuperONE cigar-lighter automobile power adapter for providing a USB-C retractable cable that doesn’t deliver +5V to power my dashcam switch module.

Because of this, I gave the product a ‘1’ review and described my methodology in determining that the retractable USB-C cable just wasn’t providing +5V. This got the company’s attention, and they offered to send me a new one, free of charge. I said, ‘OK’ but if the new one doesn’t work either, then my review will be edited to say that. Well, the new one arrived, and the same thing happened – no +5V to my project box. However, this time I was smart enough to try plugging the cable into my BT headset, and voila – it started charging the headset! Hmm… After some back and forth with Grok I learned that a ‘Power Delivery’ (PD) device doesn’t deliver power to a connection until it is asked to do so. The BT headset did, my cheap USB-C chassis receptacle didn’t – oops! So, I wound up editing my review from a 1 to a 5 and explained why; I suspect that will make the SuperONE folks a lot happier ;). Also, I ordered a different USB-C receptacle – one that has the smarts to request power from the USB-C cable.

The second thing that happened is I’m trying to figure out how to mount my dashcam power switch project into the ashtray/trailer brake ‘cubbyhole’ (see the photos above). And because I have not only one – but two 3D printers it naturally involves 3D printed parts. I designed and printed a shape that fits nicely into the cavity, and then I’ll need to figure out exactly how the combined assembly can be fastened into the cavity in a way that can be removed easily, if necessary, but also won’t just fall out at the slightest provocation.

1;8 December 2025:

After getting the enclosure issues resolved, I turned my attention to the GPS module, which is kind of hanging around on the shelf above the central audio panel. I’d like to build a small enclosure just to hide it away, leaving only the small GPS antenna itself and the even smaller RF cable leading down to the GPS module visible.

22 December 2025 Update:

I received and installed the new PD-enabled USB-C module, and it went in OK, with the usual curse-words and adaptations:

I printed up a small right-angle adaptor to mate the holes on the USB-C module with the holes on the box, but I had to mount the module on the inside wall – I decided not to make a new box just for this issue. So now The PD-enabled retractable cable on the cigar-lighter adaptor delivers 5V to the module and life is good!

Here’s the ‘final’ installation (nothing is every really ‘final’ in the Paynter world)

23 January 2026 Update:

I’ve been using the DashCam power switch for about a month now, and it seems to be working great. A couple of weeks ago I modifed the ‘Too Slow’ and ‘No Data’ readouts to change the unit from ‘sec’ to ‘min’ and ‘hours’ as appropriate; trying to figure out what ‘83520 sec’ meant was too hard for my brain, so I changed the code so this number would read ‘23.2 hours’

I also noticed that when I drive into my earth-sheltered garage, I get some strange status display readings. The number of sats will go to zero, but the clock time will often stay running (and stay accurate). Also, since the clock is active, the speed value will actually start to climb (divide by-almost-zero?) and so the speed criteria for keeping the power ON will be met. I think the way to handle this is to have a separate block in the logic for sats < min_satellites to force everything but the ‘Too Slow’ and ‘No Data’ timers to show “n/a”

26 January 2026 Update:

The dashcam switch is working well, but I’m not happy with the physical installation. I thought I had a great idea by putting it into the space originally designed for an ashtray, but it turns out not to be such a hot idea. The gear selector lever blocks out a significant amount of the display in ‘D’, and looking down at the display (and peering around the gear shifter lever) isn’t great. So, I decided to ‘re-imagine’ the entire installation.

The original installation features separate boxes for the display and the switch, which wastes a LOT of space. Starting from a clean sheet, I laid out the the switch circuitry and GPS module on a plug board, as shown in the following photo.

Required hardware for complete GPS-to-CYD implementation.

As shown above, the power input (USB-C), power output (USB2), switch (AOD424 MOSFET) and GT-U7 GPS modules easily fit into the footprint of the CYD display. I should be able to put everything into one box with the footprint of the CYD and sufficient depth to accommodate the switch & GPS hardware

However, the display area where I want to install the new version of the dash cam features a deeply recessed display area, and a complex profile. So, I needed to somehow model the profile so the box design would work. As the following photos show I used a combination of ‘cut & try’ for the first rough estimate, and then a contour gauge to get an estimate of the rest of the profile.

Then I used my 3D printer magic to print out successive profile estimates until I got reasonably close to the actual profile. This then can be used for the actual box design. The following photo shows the progression from left to right.

After getting the profile reasonably close, I printed a prototype box by extruding out the profile a few tens of millimeters, and got this result:

After a few more iterations I printed a full-size box:

Here’s a photo showing the old and new installations:

The above photo shows the old and new installations. The new installation will actually move to the left a bit as shown below, as it will incorporate the GPS module internally.

This will still hide the truck’s clock display, but since the new unit will also display time, that’s not a loss of functionality.

The next step was to disassemble the old installation to reuse the parts:

As can be seen from the above photo, there is quite a bit of wasted space in the power switch box, and I also figured out that one of the two USB-C chassis-mount connectors can also be removed, as the power connection from the power-switch circuit to the display will be routed internally – no need for a separate USB-C cable. I breadboarded the power switch circuit again, this time with compactness in mind, and wound up with this:

and then transferred the parts to a small piece of DIY circuit board. Then the whole thing fits nicely into the new enclosure, as shown in the following photos:

After more than a few hours of frustration due to the lack of a reliable GPS signal in the house, I think I finally got everything running properly, and tested it on my subdivision loop:

Here’s the updated schematic, with a missing ground wire added and with signal/control GPIO numbers added:

Stay tuned,

Frank

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!