Working Automatic Tool Changer

I found a thread on the Inventables forum discussing a working ATC for the X-Carve. It looked pretty straight forward to me (I have a CS / EE background) so I decided to give it a go.

Here’s a quick video demonstration of it working:

The original thread on the Inventables forum that explains all the mechanics is here.

I’m using a CNC CAT automatic tool changer (from here) with a Chinese 1.5kW water-cooled spindle.

My dust collection is triggered by the spindle activation, so it turns on and off with the spindle.


Very cool. What G code sender are you using for this? In the inventables thread it looks like the originator built their own sender.

I’m using bCNC, but the way I set it up, I could use any sender that doesn’t filter out M8 & M9 flood coolant commands, because those are what I re-purposed for changer open and changer close. (The Carbide Motion board has a solder pad for A3, which is what I tapped to send open/close commands to the changer.)

I wrote a python script that changes M6 T# commands in gcode to a set of standard commands that GRBL does interpret, then I just run the script on the gcode output from my CAM program before loading it in my sender.

For example:

; === Replacing tool 1 ===
M05 ; stop the spindle
G04P4.0 ; pause for 4 seconds to let the spindle stop
G53 G0 Z-1 ; go to top of Z
G53 G0 X-10.3Y-355.5 ; move to 50mm in front of tool #1
G53 G0 X-10.3Y-405.5 ; move to above tool #1
G53 G0 Z-78.0 ; lower to tool change height
M8 ; open ATC
G04P2.0 ; pause for 2 seconds to let the ATC open
G53 G0 Z-20.0 ; go to ATC safe Z
G49 ; cancel tool length offset
; === Picking up tool 2 ===
G53 G0 X-45.8Y-405.5 ; move to above tool #2
G53 G0 Z-78.0 ; lower to tool change height
G04P1.0 ; pause for 1 second
M9 ; close ATC
G04P2.0 ; pause for 2 seconds to let the ATC close
G43.1 Z42.45 ; Set tool length offset for tool 2
G53 G0 Z-1 ; go to top of Z
G53 G0 X-45.8Y-355.5 ; move away from the tool rack
M3 S21000

The biggest downside right now is I have not found any way to do a dynamic tool length offset with a probing cycle just in gcode. That requires the sender to know how far the tool moved down in a probing cycle and then send that number as the TLO. Instead what I do now is manually pre-measure my tool length offsets and put those numbers in my script so the TLOs are statically set in the gcode file when they are processed by my script. Of course, if I change out a bit (and hence the offset) I have to update my script and re-run it against my gcode. This means my gcode is not re-usable weeks or months later. In practice this doesn’t affect my usual practice at all; I normally delete my gcode right after using it, and re-process things in CAM if I want to re-cut it, because I can never keep track of what I was testing or what strange settings I baked in to a gcode file.


I am still working through one problem that is worth mentioning. The CNC CAT changer has not released the tool 100% of the time when it was supposed to, and I have read other forum posts complaining about the same thing. When monitoring the machine, this creates an annoying crash and I have to hit my hold switch (which I have wired to GRBL’s safety door feature). If the machine was not being monitored, this could be a disaster. (And what is the point of a tool changer if you have to constantly monitor it and wait for the tool change operation?)

I’m currently in the process of updating my tool rack to have a series of micro-switches in the tool holders that sense the presence of each tool. I will wire them in parallel, and connect things so that if the tool changer is open, AND any tool is missing from the rack, it will trigger a feed hold and wait for human intervention.

This will at least let me walk away from the machine while it’s running and not worry that I’m going to come back to broken bits and a ruined work-piece. Of course, I’ll still have to keep an ear out for if the machine stops too early, but since it has only failed to release the bit a couple of times out of dozens of runs, it’s not that big of a problem as long as the fault is detected and disaster is automatically averted.

That would be a great feature, especially if you added it to CM and made it easy.

The tool change macro in bCNC (for instance) works well, but it takes some thought to wrap your head around initially. I have no doubt you guys could make it easier in CM.

I haven’t yet decided to delve into customizing a sender program so I can dynamically check TLO, but I might someday once I get the rest of this working smoothly.

1 Like

Did I miss something, I couldn’t find where you are resetting the New Z Height for the new tool?

This is awesome!

So my first question, how do you fit the quick tool change collet things to an ER style spindle?

I wonder if maybe you couldn’t prepare all the tools to have the same length ahead of time (assuming similar tools)?

See the lines:

“G49 ; cancel tool length offset"
"G43.1 Z42.45 ; Set tool length offset for tool 2”

Note that I’m working in mm, and setting my work piece Z0 without any tool in the changer, so Z42.45 indicates that T2 is 42.45 mm longer than the spindle itself.


The CNC Cat website seems to be down now (Greece, go figure) so I can’t link what I bought, but here’s the gist:

  • The tool changer is designed for a spindle with a 42mm body, it slips right on, threads in place, and then a collar tightens around body of the spindle. Because of the way it threads on to the shaft end of the spindle, you can’t run it in reverse - that would potentially loosen the fitting and create a dangerous condition.
  • CNC Cat also sells the tool changer adapters with collet nut, which are sized for an ER11 collet (I bought 4x of these). I then bought 2x 1/4" ER11 collets, and 3x 1/8" ER11 collets from Precise Bits to fit various bits into the adapters.
  • Then, you just put a bit in a collet, and tighten it into the tool changer adapter with the included collet nut.

That’s a possibility if all of your bits have a similar OAL.

I’m using a combination of bits with varying lengths: 2.5" OAL with 1" flute; 1.5" OAL with .75" flute, etc. in such a way that all having the same length isn’t possible. A 2.5" 1/4" bit choked all the way in to the tool adapter is still slightly longer than a 1.5" OAL bit set at it’s maximum safe length.

If you were using more similar bits, especially if they have a depth ring like many of the bits that Precise Bits sells, and if you were OK with a few thousandths variation between your tool lengths (I am, I’m just cutting soft wood) then setting everything the same would probably work fine, then you wouldn’t have to re-process your gcode, just make sure the tool you swap out is set to the same depth as the last one was.

Speaking from recent experience with HAAS machines, one thought about how to do the probing and height offsets would be to use one of your work offsets (G54-G59) for setting your tool length by setting one of the offsets to be the “home” location of your probe, so that you do a probing cycle in that offset space, which stays constant regardless of material position, and then you jump back to the work offset for your actual job (G54 by default).

Or, since you’re already using G53 absolute machine movement for your ATC, you could put the tool height sensor at the end of your ATC rack and have tools be a measured offset relative to absolute machine position, that then gets transformed when you go back to the work.

Dunno if you’d already thought of it, but if not, might be worth a mention for everyone else’s benefit also :slight_smile:

Would you mind sharing that python script?

1 Like


Many disclaimers and obvious precautionary warnings! This is not a step-by-step direction… I assume you can figure this out. :slight_smile:

This is all very specific to my machine, and requires non-trivial changes to the code to customize it to another machine, but if you are comfortable with Python, it’s not terribly complex, it just takes time to sort through and figure out.

It’s important to understand that my machine (like any semi-stock Shapeoko) is not smart by “big machine” standards. It doesn’t know where each tool is, it doesn’t know what an “M6” command is, it doesn’t know how to probe to get the TLO. I do this all manually with the following scripts. The scripts actually rip out the M6 commands and replace them with simple move commands to move where each tool is, etc. If /anything/ goes wrong, disaster strikes. There is very little margin for error and can result in extremely dangerous situations. (e.g., spinning up to 21,000 RPM with a broken tool improperly seated in the changer, and then continuing on as if nothing were wrong.)

I have over-ridden the M8 / M9 coolant commands for open/close tool changer.

I have a tool rack that has micro-switches integrated in each tool holder, wired with the logic to the changer, so if any tool is missing from the rack while the tool changer is open, it triggers the “hold” switch. If a tool gets stuck in the chuck of the changer, this prevents a really dangerous crash if I’m not actively monitoring the machine. If you want the Fusion 360 file, or STL file for the toolholder, let me know. It’s not perfect, and takes some patience to assemble, but it works. I can also provide a schematic for wiring the micro-switches and relay with the HOLD line and tool changer lines if you like. (Of course, you have to recompiled grbl to enable the HOLD line…)

So please be careful, don’t do anything to get yourself hurt. Precautions aside, here’s how I do it:

  • I first edit (TLO gcode) to give it the specific machine coordinate locations of each tool, then run it. This Python script generates a gcode file that picks up each tool, moves to my touch probe, probes, and then pauses. I run that gcode (I use bCNC), and write down each measurement of the TLOs, so I can give my tool change script a precise length of each tool.
  • Next, I copy those measurements into (along with the locations of my tools, of course). Then I use to process the gcode for the job I want to run, and it adds the tool changes to the gcode.
  • Then I just use the resulting gcode to run the job with tool changes! (5.5 KB)