Skip to content

Instantly share code, notes, and snippets.

@tspspi
Created October 14, 2019 13:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tspspi/e64c86991136de1d8a37cd952bb8d3fe to your computer and use it in GitHub Desktop.
Save tspspi/e64c86991136de1d8a37cd952bb8d3fe to your computer and use it in GitHub Desktop.
3D printer piezo board leveling Arduino test sketch
/*
Simple test program for 3D printer piezo
bed leveling adapter board described at
https://www.tspi.at/2019/09/11/piezobedlevel.html
(using Arduino IDE and libraries).
This does not provide any I2C connectivity, etc.
and just periodically reads analog samples, dumps
them to the serial port and does some moving average
filtering (as well as using a inductive probe as
veto to suppress triggering while moving)
*/
#define ANALOGPIN_IN0 A0
#define ANALOGPIN_IN1 A1
#define ANALOGPIN_IN2 A2
#define ANALOGPIN_IN3 A3
#define DIGITAL_OUT 9
#define INDUC_IN 10
#define TRIGGERDEVIATION 15
static int movingAverageState[4];
static int measuredCenterlines[4];
static int initsamples;
void setup() {
Serial.begin(9600);
// Set output pin
pinMode(DIGITAL_OUT, OUTPUT);
pinMode(INDUC_IN, INPUT);
movingAverageState[0] = analogRead(ANALOGPIN_IN0);
movingAverageState[1] = analogRead(ANALOGPIN_IN1);
movingAverageState[2] = analogRead(ANALOGPIN_IN2);
movingAverageState[3] = analogRead(ANALOGPIN_IN3);
double avg[4];
avg[0] = 0.0;
avg[1] = 0.0;
avg[2] = 0.0;
avg[3] = 0.0;
for(initsamples = 0; initsamples < 1000; initsamples = initsamples + 1) {
avg[0] = avg[0] + ((double)analogRead(ANALOGPIN_IN0)) / ((double)1000);
avg[1] = avg[1] + ((double)analogRead(ANALOGPIN_IN1)) / ((double)1000);
avg[2] = avg[2] + ((double)analogRead(ANALOGPIN_IN2)) / ((double)1000);
avg[3] = avg[3] + ((double)analogRead(ANALOGPIN_IN3)) / ((double)1000);
}
Serial.print("Init samples (averages): ");
Serial.print((int)avg[0]);
Serial.print(" ");
Serial.print((int)avg[1]);
Serial.print(" ");
Serial.print((int)avg[2]);
Serial.print(" ");
Serial.println((int)avg[3]);
measuredCenterlines[0] = (int)avg[0];
measuredCenterlines[1] = (int)avg[1];
measuredCenterlines[2] = (int)avg[2];
measuredCenterlines[3] = (int)avg[3];
}
static int debounceCounter = 12;
#define movingAverageAlpha 0.4f
void loop() {
int aValue[4];
aValue[0] = analogRead(ANALOGPIN_IN0);
aValue[1] = analogRead(ANALOGPIN_IN1);
aValue[2] = analogRead(ANALOGPIN_IN2);
aValue[3] = analogRead(ANALOGPIN_IN3);
movingAverageState[0] = movingAverageAlpha*aValue[0] + (1.0f - movingAverageAlpha)*movingAverageState[0];
movingAverageState[1] = movingAverageAlpha*aValue[1] + (1.0f - movingAverageAlpha)*movingAverageState[1];
movingAverageState[2] = movingAverageAlpha*aValue[2] + (1.0f - movingAverageAlpha)*movingAverageState[2];
movingAverageState[3] = movingAverageAlpha*aValue[3] + (1.0f - movingAverageAlpha)*movingAverageState[3];
int trigCount = 0;
int measValues[4];
for(int i = 0; i < 4; i++) {
measValues[i] = movingAverageState[i] - measuredCenterlines[i];
}
Serial.print(measValues[0]);
Serial.print(" ");
Serial.print(measValues[1]);
Serial.print(" ");
Serial.print(measValues[2]);
Serial.print(" ");
Serial.println(measValues[3]);
for(int i = 0; i < 4; i++) {
if(measValues[i] < 0) { measValues[i] = measValues[i] * -1; }
}
for(int i = 0; i < 4; i++) {
if(measValues[i] > TRIGGERDEVIATION) { trigCount++; }
}
if((trigCount >= 1) && digitalRead(INDUC_IN)) {
debounceCounter = 12;
}
if(debounceCounter > 0) {
digitalWrite(DIGITAL_OUT, HIGH);
debounceCounter--;
} else {
digitalWrite(DIGITAL_OUT, LOW);
}
delay(5);
}
@sergiofagundes
Copy link

Hi. How is your project going ? It's working good ? Can it be used on a delta using only 3 piezo sensors ? Thank you

@tspspi
Copy link
Author

tspspi commented Oct 25, 2020

Yes, I'm using this (pretty simple) method on my printer and it seems relieable to me. I've had to do some minor modifications though (I've added a new mount for my heatbed that allows me to adjust the weight distribution on the four piezo sensors - it's simply an aluminium frame that rests on four M3 screws that I can extend out of the bottom of the frame that rest directly on top of the piezos and some sliding bearings that fix the frame in the X and Y dimension, previously misalignment above the piezos sometimes lead to problems)

Of course the same idea should also work out using 3 piezo sensors. The main drawbacks using this simple method I've seen is that I have to really use the inductive sensor as a additional signal to enable the piezos since my system vibrates too heavy during long travel distances along the Z distance after larger builds so piezos triggered at arbitrary heights when not using the inductive probe. The other problem I've discovered with this simple method is about the environment - I'm personally using the printer in a not too vibrating environment (no other machines in vicinity) and it's additionally decoupled using neoprene feet and some other vibrational damping material, the piezos would most probably produce some noise and might trigger in such cases when one's using such a simple scheme - I've seen some approaches of doing fourier transforms and detecting frequency changes or applying simple digital filters for frequency changes during the touch event. The other thing I've discovered is that my simple method does not work with too slow traveling - i.e. requires some force between the nozzle and the surface - which seems to be ok since my bed is rested on springs anyways but I can imagine that depending on used materials this can be a problem too.

That potential problems aside I'm pretty satisfied with this tramming method but I'm not using it in an industrial or commercial setting (way more satisfied than with the capacitive probe alone since this lead to problem with head tilt when getting out of sync on my Z axis steppers). The only method that I'd liked somewhat more was checking for electrical conductivity between the nozzle and the bed but since one usually prints on an insulator that is not really an option - I've also played with the idea of measuring capacitance between the nozzle and the bed itself but haven't tried that until now.

@tspspi
Copy link
Author

tspspi commented Oct 25, 2020

Just to add that: Even that code should work unmodified if one pulls the input for the unconnected piezo to GND or VCC so no random noise is measured - I've actually done that during testing a few times.

@sergiofagundes
Copy link

sergiofagundes commented Oct 26, 2020

Thanks for replying. I have remixed your board for using the Attiny85 instead. When I have it done I'll post my testings here.
I'm planning to disable the Attiny85 reset pin, and get 2 extra pins to create a threshold setup pins to easily tune the board without reprogramming the attiny85. Of course, I need to change the code to matches the t85 pinout. I have done this for the JohnSL
/ FSR_Endstop too, but the FSR sensors it's not cheap here where I live (it's about US$16 each, where the Piezo costs only $1.6 each).

tiny85_piezo_sensor

@tspspi
Copy link
Author

tspspi commented Oct 26, 2020

Yeah having a reset method is pretty useful - I've added this (but not uploaded here up until now, maybe I should do this) to my own implementation too using I2C (since most components of my custom machine communicate via I2C anyways). I'd be really interested in how well that approach works for your machine too - since the only "experience" I made with this is unfortunately my own custom designed machine.

Yep, the price and also the constraints by having an capacitive sensor mounted onto the printhead also was a reason I tried to operate without one - I think it should be possible with more fancy signal processing (for example if I hear correctly I have an fan mounted onto my printhead that seems to change frequency in case of a touch event - it should be possible to detect that) - and of course also to discriminate for noise so one doesn't need any other additional sensor - I didn't follow that route though since the capacitive sensor already had been in place so there was no need for that though it would be really interesting if this works well (and after print has started one could of course disable or ignore endstop triggering as usual; Maybe it would also be possible to simply do some statistics to remove noisy triggering by the piezos to by modifying the tramming process ...)

@tspspi
Copy link
Author

tspspi commented Oct 26, 2020

Maybe just another comment about "biasing" the piezos that way - depending on the piezos this works pretty well but when one drives the input of the AVR directly with them one relies on the protection diodes to catch voltage spikes that might arise when larger forces are acting on the piezos - also one cannot use typical industrial sensors that way, it works pretty well with piezo disks that are thought as guitar pickups or speakers though usually but of course there is no guarantee that a specific type doesn't deliver voltages too large for an AVR to handle. It's never been a problem for my setups (even when dropping tools on the print surface, etc.) with different disks but I think it's worth to mention

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment