I came up with a fairly simple but very accurate way of measuring how perpendicular your Z axis is.
You can find some more details and code at my Github project for this: pvdbrand/cnc-z-perpendicularity. The code is not that polished, so it may be hard to get everything working if you’ve never done anything in Python.
The basic idea is that you string a very thin piece of wire along the X and/or Y axis. Using a Z probe, the end mill touches off on both sides of the wire at various depths. You repeat the process with the end mill rotated 180 degrees, to compensate for a possible non-zero angle between the Z axis and the end mill itself (for example if your end mill is bent).
Those measurements can be used to compute what the angle of the Z axis is, and what the angle between the Z axis and the end mill is. If you know the Z axis angle, you can calculate exactly how much to shim the mount in which place. No more trial and error, no need to make test cuts! (This is left as an exercise for the reader for now.)
The most important caveat is that your “end mill” should have the same diameter along the part that is used to probe the wire. A spiral flute will not work well for example. I used a small aluminum tube instead. If you have a very short cutting edge you may be able to insert it upside down.
I have never shimmed my tool mount, and my Z axis was only 0.2 degrees or so off perpendicular. Not bad! To test the approach further, I printed a special mount for my aluminum “end mill tube” at 5 degrees off in one axis and 10 degrees off in another axis. I also printed a small piece to simulate an angle of 2.5 degrees between the Z axis itself and the end mill. I ran the script, and all angles were measured correctly
I also implemented measurements of backlash in the same script. The idea is that the probe moves towards the wire and stops on contact. Then the probe is moved away until contact is broken again. The distance moved until contact is broken is the backlash. I measured the backlash several times when I was testing various things, and I typically got a histogram that looked like this:
The X axis is the backlash in millimeters, the Y axis is how often I measured that specific backlash. Very good numbers I think!