/
AutoFSRStandard.ino
240 lines (200 loc) · 8.96 KB
/
AutoFSRStandard.ino
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
/*
Auto Tuning FSR Trigger for ATtiny85 and AdaFruit Trinket
Author: Wing Tang Wong
GitHub: https://github.com/WingTangWong/AutoTuningFSRTrigger/ATTINY85_TRINKET_FSR
Description:
This Arduino Sketch is meant to be installed on an ATtiny85 or AdaFruit Trinket, which
uses an ATtiny85 as the MCU. This is the heavily pruned and reduced code.
The sketch makes use of all of the IO pins in the following manner:
========= ============= ==================================================================================
Chip PIN - Trinket Pin - Usage
========= ============= ==================================================================================
1 - RST - Short to reset the MCU. Wire to a switch that shorts to GND.
2 - PB3 / 3 / 3 - Digital pin 3, Analog pin 3. Used for FSR input.
3 - PB4 / 4 / 2 - Digital pin 4, Analog pin 2. Used for FSR input.
4 - GND - GND pin.
5 - PB0 / OUT - Digital Pin 0, Used for end stop output. HIGH by default, goes LOW when triggered.
6 - PB1 / LED - Digital Pin 1, used as LED indicator. On the Trinket, this is wired to an LED.
7 - PB2 / 2 / 1 - Digital pin 2, Analog Pin 1. Used for FSR input.
8 - VCC - VCC input. 5V or 3.3V depending on your Trinket.
========= ============= ==================================================================================
The design makes use of all three generally accessible ADC pins for three independent FSR inputs. ADC0 /PB5 is
on the RSET pin and will not be used as an IO pin.
Installing the code:
To install this code on your ATTINY85 MCU or onto the AdaFruit Trinket, you will want to download the Arduino 1.0.5(or later)
IDE along with AdaFruit's definitions/etc.
Alternatively, you can follow the Adafruit instructions on how to customize your existing Arduino IDE to work with the AdaFruit Trinket.
Note, the Trinket operates at 8Mhz or 16Mhz. Make sure you set the Board in Arduino IDE appropriately.
If you are programming to a bare ATTIN85 chip, you will want to edit the boards.txt definition to include an "1Mhz Trinket"
like so:
trinket1.name=Adafruit Trinket 1MHz
trinket1.bootloader.low_fuses=0xF1
trinket1.bootloader.high_fuses=0xD5
trinket1.bootloader.extended_fuses=0xFE
trinket1.upload.maximum_size=5310
trinket1.build.mcu=attiny85
trinket1.build.f_cpu=1000000L
trinket1.build.core=arduino:arduino
trinket1.build.variant=tiny8
This will allow an ATtiny85 to run off of the internal 1Mhz OSC and with timings operating properly. You can burn the code
onto a bare ATTINY85 using the 8Mhz definition, but the chip will run super slow. Using the 16Mhz definition on a bare ATTINY85
can potentially brick your MCU.
Chip Hookup:
Once you have flashed your chip, you will need to hookup the chip to your 3D printer's z-min-end-stop. To do that, you should
refer to the wiring diagram included as an image in this repo.
Basically:
* VCC should be hooked up to your printer board's VCC (Can use the VCC pin from the 3 pin endstop connection)
* GND should be hooked up to your printer board's GND (Can use the GND pin from the 3 pin endstop connection)
* OUT should be hooked up to the signal pin on your printer control board's z-min-end-stop. Be sure to not hook it up to the VCC/GND pins.
* LED can be left unconnected as the Trinket has an oboard LED. If using a bare ATTINY85, you can wire up an LED and low value resistor
from the pin to GND: (LED PIN)----|>|------/\/\/\/\-----(GND)
* LED can be any low voltage LED
* Resistor can be a typical 1k to 4.7k ohm resistor.
* RSET can be left unconnected on the Trinket. On the bare ATTINY85, it can also be left unconnected, or pulled up via a 10k-50k ohm resistor
hooked up to VCC.
* ADC1, ADC2, ADC3 should be hooked up as follows:
* Pin pulled down to GND via a 10K+ ohm resistor.
* Pin also connected to one leg of the FSR.
* Other leg of FSR connected to VCC.
* You can optionally place an LED in-line with the FSR and VCC so it illuminates when the FSR is pressed. Though this will not indicate
a trigger state.
Testing Circuit:
* Power on your printer board and your new module.
* Perform an M119 on your printer to get the endstop states. Presuming none of the endstops are triggered, you should see
that none of the enstops are triggered.
* Press down on an FSR sensor. The output LED should light up.
* Perform another M119. You should now see the z-min-end-stop triggered.
* If this works, you are good to give probing a try.
* Install the FSR under the bed plate if you have not already.
* Make sure everything is hooked up. If you had left the Trinket on, you will see the LED still lit. Hit the reset button on the Trinket.
The light will turn off.
* Press down on the print bed. The light should go on. Letting go will see the light go off again. You're good to attempt a test bed levelling.
Testing Probing:
* Assuming your FSR are installed
* Home your printer
* With one hand on the printer control board reset switch, initiate a G29 to auto-level probe the bed.
* When the tip of the hot end touches the bed, if it doesn't tink and back off immediately, ie. it is pushing against the bed, hit the reset.
Then, check to see what might be wrong.
* If the head tinks against the bed, but keeps raising up toward home, hit reset. Something made the sensor/module stuck in ON/triggered
mode.
* If the head just proceeds through the auto-level process, yay!
*/
// Pin assignments
int OUT = 0; // OUTPUT pin
int LED = 1; // LED pin
int A[3] = {1,2,3}; // Analog pin numbers
int AD[3] = {2,4,3}; // Digital pin numbers correlating to the physical analog pins
// Various variables used for state and tracking calculations
unsigned long PRECALIBRATION=0;
unsigned long SEED = 40;
float VALUE[3]={0,0,0};
float AVERAGE[3]={0,0,0};
float NOISE_LEVEL[3]={8,8,8};
float TRIGGER_LEVEL[3]={0,0,0};
float RECOVERY_LEVEL[3]={0,0,0};
unsigned long TALLY[3]={0,0,0};
float TOTAL[3]={0,0,0};
unsigned long STATE[3]={0,0,0};
unsigned long TRIGGER_ADJUST[3]={60,60,60};
unsigned long RECOVERY_ADJUST[3]={10,10,10};
long scratch;
// the setup routine runs once when you press reset:
void setup() {
pinMode( OUT , OUTPUT );
digitalWrite( OUT , HIGH );
pinMode( LED , OUTPUT );
digitalWrite( LED , LOW );
for(scratch=0; scratch<3 ; scratch++) {
pinMode( AD[scratch] , INPUT );
digitalWrite( AD[scratch], LOW );
};
do_calibration();
}
// the loop routine runs over and over again forever:
void loop() {
do_calibration();
do_read_sensors();
do_output();
};
// Take the read values and average them
// Also, get the noise level.
void do_read_average(int idx)
{
float noise_delta;
// Take a single reading
delay(25); // delay 25 milliseconds
VALUE[idx] = analogRead( A[idx] );
TOTAL[idx] = TOTAL[idx] + VALUE[idx];
TALLY[idx]++;
// Update the average
AVERAGE[idx] = ( TOTAL[idx] / TALLY[idx] );
if ( VALUE[idx] > AVERAGE[idx] ) {
noise_delta = ( VALUE[idx] - AVERAGE[idx] );
} else {
noise_delta = ( AVERAGE[idx] - VALUE[idx] );
};
// bump up the noise... only if it is greater than the default noise already set
if ( noise_delta > NOISE_LEVEL[idx] ) {
NOISE_LEVEL[idx] = ( NOISE_LEVEL[idx] + noise_delta ) / 2.0;
};
};
// If we determined we really need to calibrate, do it here.
// Read in values and set trigger levels.
void do_real_calibration()
{
int idx;
int run;
for(idx=0; idx<3 ; idx++ ) {
if ( TALLY[idx] < SEED ) {
for(run=0; run<SEED ; run++ ) {
do_read_average(idx);
};
} else {
do_read_average(idx);
};
TRIGGER_LEVEL[idx]=NOISE_LEVEL[idx] + TRIGGER_ADJUST[idx];
RECOVERY_LEVEL[idx]=NOISE_LEVEL[idx] + RECOVERY_ADJUST[idx];
};
PRECALIBRATION++;
};
// Function to determine if we need to perform a calibration.
void do_calibration()
{
if ( PRECALIBRATION < 1 ) {
do_real_calibration();
};
};
// Function to read values from the FSR sensors
void do_read_sensors()
{
int idx;
for( idx=0; idx<3 ; idx++ ) {
// single read. multiple reads were not really effective
VALUE[idx] = analogRead( A[idx] );
delay(25);
if ( VALUE[idx] > ( AVERAGE[idx] + TRIGGER_LEVEL[idx]) ) {
STATE[idx] = 1;
};
if ( VALUE[idx] < ( AVERAGE[idx] + RECOVERY_LEVEL[idx]) ) {
STATE[idx] = 0;
};
};
};
// Update the LED and OUTPUT pins.
void do_output()
{
int idx;
int TRIGGERED=0;
for(idx=0; idx<3; idx++ ){
TRIGGERED=TRIGGERED + STATE[idx];
};
// The HIGH/LOW corresponds to a Normally Connected signal output.
if ( TRIGGERED > 0 ) {
digitalWrite( OUT, LOW );
digitalWrite( LED, HIGH);
} else {
digitalWrite( OUT, HIGH
);
digitalWrite( LED, LOW );
};
};