11 Sep 2019 - tsp
Updated: How to wire correctly (at the end of the blog entry)
What is bed leveling? The idea behind bed leveling is to give a machine (for example a 3D printer as in the following case, a CNC mill or any other machine) a way to sense the layout of the machine bed or building plate. When not using bed leveling one normally assumes a given bed layout - for example on a 3D printer one assumes that the bed is leveled and perfectly parallel to the 3D printer axis, the same on a mill. It is also assumed to be at a given z offset relative to the z axis endstops. Zero along the X and Y axis is normally determined via any other mean (for example using mechanical endstop switches or inductive, capacitive, ultrasonic or optical sensors). This raises the requirement for the build plate to be as parallel to the build axis as possible - which is of course always a good idea if you’re not using one of the infinite size beds built around tilted conveyor belts. On the other hand there are many machines where one manipulates the bed - for example on 3D printers one might change the coating on which on prints, at CNC mills one might add additional clamping mechanisms although it’s normally assumed there that these are precise and that the workpiece is resting on the buildplate itself.
To gain more precision than having a calibrated system one can perform a measurement of the build surface (and for CNC machines of the workpiece and it’s orientation if one does multiple manufacturing steps on different machines) before each build or on a periodic shedule. This allows the control software to adjust itself to changes in machine geometry. Of course this doesn’t mean one should ignore mechanical precision, a machine should as usual be as precise as possible - but it allows to compensate for different errors or gain more precision than would be possible with a mechanical solution.
At 3D printers bed leveling is typically performed by a variety of methods:
Note: This section describes the first try that seemed to work somewhat at first but had to be modified later on (as described below).
The following article describes some experiments and solutions to do bed leveling via a touch probe. The basic idea is to sense the contact between the 3D printer nozzle or a milling tool and the printer bed or machine table. On a 3D printer one cannot use a simple conductive probe (i.e. sense the contact between the nozzle and a conducting bed) since one normally uses a non conductive coating as described above. To overcome that problem one can use pressure sensors. Since they are readily available I’ve tried to use piezo disks as sensors. They are cheaply available in huge quantities and are salvageable from electronic waste like watches, cheap microphones, classical guitar and violin pickups, etc. The are basically manufactured by attaching a layer of piezoelectric material onto a metal plate and connected on the top of the sandwitch as well as on the metal plate.
The effect being used is the piezoelectric effect. This effect can occur in materials that change polarization with mechanical stresses (i.e. average charge carriers are moved inside the material in case of stress changes). The model normally used to describe the piezoelectric effect assumes that one can calculate the balance point for positive and negative charges - and as soon as one applies stress to the material it deforms which leads to the formation or change of the dipole moment inside the material. Polarization changes then lead to a change in electrical potential and thus in voltage - which again leads to a small current. The piezoelectric effect can be used to measure (i.e. mechanical stress leads to induced voltage) or inversely to induce deformation by applying voltage. The latter method is used in some high precision machines like scanning tunneling microscopes or high precission mills. It’s also used in cheap watches to generate the buzzing noises. The direct effect that is used for bedleveling sensors on the other hand is also used in microphones, accelerometers and other stuff seen on a day to day basis.
There are two possible placements for the piezo disks. Since the printer I’ve built already had an finished and not easily changeable printing head I’ve decided to add the piezo disks below the build surface. This is possible since the build plate is not too huge - the idea was to put one piezo disk into every corner and rest the whole weight of the mounting frame for the heatbed onto these disks. Since the disks have welded and soldered cables on top I’ve added a small spacer (using some cents) above the piezoelectric layer and put the table on top of them. After that I’ve connected all four piezo disks in parallel for the easiest and cheapest solution. That might not be a good idea in every case since - under some circumstances and geometries - it’s entirely possible of occuring voltages to cancel out.
The next problem when connecting piezos to microcontrollers was that they produce positive and negative voltage depending on the direction of deformation. Since the idea was to use an single rail ADC for measuring (i.e. the ADC functionality of the AVR itself) a voltage divider consisting of two $1 M\Omega$ resistors is added. This provides biasing of the piezo discs such that one can measure positive and negative voltage spikes. One can of course use different voltage dividers. Lower resistor values lead to higher leakage current and less sensitivity, higher resistor values to higher sensitivity of the system. One shouldn’t use that aproach when using other piezo sensors - because their voltage spikes can be way to high for the AVR and it’s internal protective circuits to handle - but using the piezo disks directly with the biasing resistors attached works pretty well.
This way one can simply run normal bed leveling
One just has to tune the threasholds to prevent triggering because of external noise and vibrations - and to stay sensitive enough for the slow touch during the probing moves. In case simple threasholding does not work:
If this is still not enough one could in theory perform event fitting (i.e. try to fit an function that models charging and discharging of the circuit during a touch event) to discriminate touch events a piezo sensor might not be the right choice.
And additional upgrade would be to sample all piezo disks separately. This would also allow absolute position determination of the touch event.
As turned out the system as described above was not nearly as sensitive as it could be and has a dead section in about 20 percent of the plate. This turned out to be caused by manufaturing and wiring differences with the piezo disks. To solve that problem each piezo disk has been attached to it’s own analog digital converter. This has first been tried with an ATMega328P. The system can now also report the signal shape for all four disks. As one can see the centerline of one of the pizeos is shifted towards lower voltage. This caused the system to oscillate sometimes and caused the lower voltage disk to be way less sensitive then the other disks.
Running the same system with 4 channels and the same frequency allows more relieable detection of touch events and being less sensitive to external vibrations like passing cars or trains.
As one can see the design also has been modified to allow I2C communication for configuration and calibration as well as reading measurement data and flashing with an suited I2C bootloader as well as ICSP programming. The board also has an option to add an local 5V DC-DC regulator as well as an additional input for a traditional bed leveling sensor. This allows to run detection in coincidence mode to provide increased noise immunity for larger Z travel distances (i.e. trigger only whenever the standard z level sensor and the piezo sensors trigger). One can also support switching between piezo and classical mode.
All KiCad design files are available on GitHub.
A really good manufacturer for PCBs for hobbyist quantities is PCBWay.
Note: All links are Amazon affilate links. This pages author profits from all qualified purchases
Some test code for the board presented above using the ArduinoIDE (for easy deployment) has been uploaded as a GIST. This code does not supply connectivity via I2C.