Monday 25 April 2011

Auto bed leveling

One thing I find tedious is leveling the bed of my machines, so I decided to make use of the Z-probe on HydraRaptor to measure the incline of the bed and compensate for it in software.

First I had to increase the resolution of my Z axis. When I first built the machine I did not realise that I would need fine resolution on Z, so I used an old 24V unipolar motor that I had in my junk collection. With half stepping it gave me 0.05mm resolution. I thought that it was a 200 step motor and that the lead screw had a pitch of 20mm. It turns out it must have been a 250 step motor because the pitch is actually 25mm. I replaced it with a Keling KL23H251-24-8B NEMA23 left over from my Darwin and I now drive it with a x10 microstepping controller the same as I use on X and Y. That gives me a resolution of 0.0125mm and also makes it the fastest axis on my machine. It can easily do 150 mm/s but seeing the nozzle approaching the bed at that speed and then stopping within 0.3mm is very unnerving, so I limit the speed to 50mm/s!

I no longer need the heat sink and fan because the new motor is more efficient and is directly mounted on the axis, which takes the heat away.


I use 6mm aluminium tooling plate so I make the assumption that the bed is a flat plane (rotated slightly around the X and Y axes and offset a little in Z). That means I only need to measure the height at three arbitrary points in order to characterise that plane. I then use the method here to calculate the equation of the plane in the form ax + by +cz +d = 0. The method puts two vectors through the three points and takes the cross product to get a vector at right angles to both of them. That is the normal to the plane and its components are the coefficients a, b and c. Substituting the first point into the equation gives d.

It is important that the three points are ordered anti-clockwise, otherwise the normal vector would point downwards and the machine would try to build the object upside down under the surface of the bed!

Given the bed's plane I then have to make the model coordinates relative to that inclined plane and transform them to the coordinate system of the machine. To do that I calculate two orthonormal basis vectors on the plane using it's equation and use the normalised normal vector for the third. I then multiply the model coordinates by those vectors and add the origin to find where they are in the machine's coordinates. Here is the Python code I used: -

class Plane:
    "A plane in 3D."

    def __init__(self, p0, p1, p2):
        "Construct from three anti-clockwise points"
        #
        # Calcluate the normal vector
        #
        v1 = p1.minus(p0)
        v2 = p2.minus(p0)
        normal = v1.cross(v2)
        if normal.z < 0:
            raise Exception, "Probe points must be anti-clockwise"
        #
        # Coefficients of the plane equation ax + by + cz + d = 0
        #
        a = normal.x
        b = normal.y
        c = normal.z
        d = -a * p0.x -b * p0.y -c * p0.z
        #
        # Generate three basis vectors aligned with the plane
        #
        self.origin = vector( 0, 0, -d / c)

        self.k = normal                      # k axis is simply the normalised normal
        self.k.normalize()

        px = vector( 1.0, 0.0, -(a + d) / c) # an arbitrary point on the x axis: x = 1, y = 0
        self.i = px.minus(self.origin)       # find direction to it from origin
        self.i.normalize()                   # make a unit vector

        self.j = self.k.cross(self.i)        # make a third vector mutually at right angles to the other two
        self.j.normalize()                   # make a unit vector, probably is already

    def transform(self, p):
        "Transform a point to be relative to the plane"
        return self.origin.plus(self.i.times(p.x)).plus(self.j.times(p.y)).plus(self.k.times(p.z))

To test the principal I put a 1mm thick washer under one corner support of the bed to give it an extreme slant compared to normal misalignment. I then built a 100 x 100 x 5mm cube with 0.35mm layers. This would normally be impossible without the bed being level to a small proportion of the layer height. The result was that it came out fine.


As the nozzle traverses the object in XY the Z axis moves a few microsteps. It is barely visible but I can hear it and feel it if I hold the stepper motor shaft. The object is built perpendicular to the plane of the bed, so the sides are very slightly slanted with respect to the machine axis and the nozzle. I am not sure how well it would work on Mendel as the z-axis is geared down so much. It would probably still work as the movement required is so small when the bed is reasonably level. I can't test it as there isn't room for a z-probe on my carriage due to the large heat sink.

Monday 4 April 2011

Auto z-probe

A niggling problem I have with Hydraraptor is that the z-axis calibration varies with the weather and how much it is used. This is because the frame is made from wood, which absorbs atmospheric moisture and expands. When the machine is running constantly the heat from the bed dries it out and it plateaus at a low z-value. If I don't use it for a while the z-axis gets higher by as much as 0.5mm in wet weather and the first few builds need large adjustments. When printing raft-less the initial layer height needs to be accurate to about 0.05mm for 0.3mm layers.

When it was configured as a milling machine I made a tool height sensor to solve the problem. It doesn't work for FFF though because the nozzle usually has hot plastic dribbling from it and it also wastes some of the build area.

To solve the problem I designed a z-probe that hangs below the nozzle at the start of the build but then retracts itself after the measurement. It consists of a weighted metal rod that slides through a couple of plastic guides. It has a plastic flange on the top that depresses the plunger of a light action micro switch. In measurement mode the rod protrudes about 10mm below the nozzle. When the measurement is completed the axis descends to place the nozzle close to the bed. The rod lifts until the attractive force of two Neodymium magnets causes it to be pulled about 5mm above the nozzle and held there until the start of the next build.




Here it is installed on the axis.


I used a Meccano worm gear as an improvised weight to ensure the micro switch is activated, much cheaper options exist! The actual weight is surprisingly not very critical. It must be enough to activate the switch reliably but not too heavy for the magnets to lift.


The operating procedure is as follows: The machine warms up the bed and the extruder and waits for a couple of minutes for the nylon pillars that support the bed to expand fully. It then extrudes a length of filament with the z-axis at the top and gives an audio prompt on my computer. I grab the filament and snap it off and then lower the z-probe, which closes the switch and instructs the machine to start.

The axis descends rapidly to place the rod 1mm above the centre of the bed. It then descends in 0.1mm steps until the switch opens. Then it ascends in 0.01mm steps until the switch closes again and that gives the Z calibration point, which is a known distance (about 10mm) above the bed. The nozzle then descends to 1mm above the bed to retract the probe before it moves to the start point.

Here is a video of the sequence.



It could also lower the probe automatically simply by having a bracket near the top of the z-axis to catch the flange as the axis rises past it. The reason I don't do that at the moment is because I use the act of manually lowering the probe as a cue to the machine that I have removed the start extrusion.

The design is on Thingiverse.