-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathzapfmeister500.ino
298 lines (254 loc) · 8.39 KB
/
zapfmeister500.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
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
#include <Adafruit_NeoPixel.h>
#include <Stepper.h>
#define DEBUG_MODE
#define INFO_MODE
#ifdef DEBUG_MODE
#define DEBUG(x) Serial.print("DEBUG : "); Serial.println(x)
#else
#define DEBUG(x) // Tut nichts
#endif
#ifdef INFO_MODE
#define INFO(x) Serial.print("INFO : "); Serial.println(x)
#else
#define INFO(x) // Tut nichts
#endif
#define WARN(x) Serial.print("WARNING : "); Serial.println(x)
/////////////////////////////////////////////////////
// PINS - Step1: 8,9,10,11 - Step2: 4,5,6,7
const int button_pin = 13; // GPIO Taster
const int trig_pin = 3;
const int echo_pin = 2;
const int led_pin = 12; //Pin, an dem der NeoPixel angeschlossen ist
//LED RING
const int leds = 8; //Anzahl der LEDs
int rgb_red = 255; //Rot
int rgb_green = 255; //Grün
int rgb_blue = 255; //Blau
Adafruit_NeoPixel ring = Adafruit_NeoPixel(leds, led_pin, NEO_GRB + NEO_KHZ800);
//ULTRASCHALL
float duration, distance;
const int min_distance = 9;
// STEPPER
const int upper_open_time = 10000;
const int lower_open_time = 10000;
// Voll-Schritt:4096 Halb:2038 Viertel:1024
const int steps_per_revolution = 512;
const int stepper_speed = 50;
const int stepper_rotations = 7;
// Pins entered in sequence IN1-IN3-IN2-IN4 for proper step sequence
Stepper upper_stepper = Stepper(steps_per_revolution, 8, 10, 9, 11);
bool upper_stepper_open = true;
// Pins entered in sequence IN1-IN3-IN2-IN4 for proper step sequence
Stepper lower_stepper = Stepper(steps_per_revolution, 4, 6, 5, 7);
bool lower_stepper_open = true;
enum State {
STATE_IDLE,
STATE_FILLING,
STATE_DISPENSING
};
State current_state = STATE_IDLE;
unsigned long start_time = 0;
/////////////////////////////////////////////////////
void close_all_valves() {
close_upper_valve();
close_lower_valve();
INFO("alle Ventile geschlossen");
}
void setup() {
Serial.begin(9600);
pinMode(button_pin, INPUT_PULLUP); // Pullup um Störsignale (float) zu verhindern
pinMode(trig_pin, OUTPUT);
pinMode(echo_pin, INPUT);
pinMode (led_pin, OUTPUT);
ring.begin();
ring.setBrightness(10); //Helligkeit: 0 (aus) - 255
close_all_valves(); // Zu Beginn alles schließen
DEBUG("setup done");
}
/////////////////////////////////////////////////////
// METHODEN
void loading_animation(int red, int green, int blue) {
static unsigned long previousMillis = 0; // Speichert die letzte Zeitaktualisierung
static int currentLED = 0; // Aktuelle LED, die leuchtet
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= 200) { // Intervall von 200ms
previousMillis = currentMillis;
ring.clear();
ring.setPixelColor(currentLED, ring.Color(red, green, blue));
ring.show();
currentLED++;
if (currentLED >= ring.numPixels()) {
currentLED = 0;
}
}
}
void set_all_leds(int red, int green, int blue) {
for (int i = 0; i < ring.numPixels(); i++) {
ring.setPixelColor(i, ring.Color(red, green, blue));
}
ring.show();
}
void blink_leds(int red, int green, int blue, int blinkCount, int blinkDuration) {
for (int i = 0; i < blinkCount; i++) {
set_all_leds(red, green, blue);
delay(blinkDuration);
set_all_leds(0, 0, 0);
delay(blinkDuration);
}
}
float ultraschall_dist() {
static float lastDistance = -1; // Speichert den letzten gültigen Wert
// Triggersignal senden
digitalWrite(trig_pin, LOW);
delayMicroseconds(2);
digitalWrite(trig_pin, HIGH);
delayMicroseconds(10);
digitalWrite(trig_pin, LOW);
// Messung des Echos
long duration = pulseIn(echo_pin, HIGH);
// Berechnung der Distanz
float distance = (duration * 0.0343) / 2;
// Fehlerbehandlung
if (distance == 0 || distance > 250) {
if (lastDistance == -1) {
// Wenn auch die letzte Messung ungültig war, gib -1 zurück
return -1;
} else {
// Wenn die vorherige Messung gültig war, nutze sie weiter
return lastDistance;
}
}
// Gültigen Wert speichern und zurückgeben
lastDistance = distance;
return distance;
}
void open_upper_valve() {
if (upper_stepper_open) {
WARN("oberes Ventil ist bereits offen!!");
} else {
upper_stepper.setSpeed(stepper_speed);
upper_stepper.step(-stepper_rotations*steps_per_revolution);
upper_stepper_open = true;
DEBUG("oberes Ventil geöffnet");
}
}
void open_lower_valve() {
if (lower_stepper_open) {
WARN("unteres Ventil ist bereits offen!!");
} else {
lower_stepper.setSpeed(stepper_speed);
lower_stepper.step(-stepper_rotations*steps_per_revolution);
lower_stepper_open = true;
DEBUG("unteres Ventil geöffnet");
}
}
void close_upper_valve() {
if (upper_stepper_open) {
upper_stepper.setSpeed(stepper_speed);
upper_stepper.step(stepper_rotations*steps_per_revolution);
upper_stepper_open = false;
DEBUG("oberes Ventil geschlossen");
} else {
WARN("oberes Ventil ist bereits geschlossen!!");
}
}
void close_lower_valve() {
if (lower_stepper_open) {
lower_stepper.setSpeed(stepper_speed);
lower_stepper.step(stepper_rotations*steps_per_revolution);
lower_stepper_open = false;
DEBUG("unteres Ventil geschlossen");
} else {
WARN("unteres Ventil ist bereits geschlossen!!");
}
}
/////////////////////////////////////////////////////
void loop() {
static bool is_glass = false;
static int last_button_state = HIGH;
int button_state = digitalRead(button_pin); // Knopfstatus lesen (LOW = gedrückt, HIGH = nicht gedrückt)
bool button_pressed_event = (button_state == LOW && last_button_state == HIGH); // Flankenerkennung: Event nur, wenn HIGH -> LOW switcht
if (button_pressed_event) {
DEBUG("BUTTON PRESS EVENT REGISTERD");
}
distance = ultraschall_dist();
// DEBUG(distance);
if(distance <= min_distance && !is_glass) {
is_glass = true;
INFO("Glas erkannt");
} else if(distance > min_distance && is_glass){
is_glass = false;
}
switch (current_state) {
case STATE_IDLE:
if(is_glass) {
set_all_leds(0, 255, 0);
} else {
set_all_leds(0, 0, 255);
}
// Im Leerlauf warten wir auf einen Knopfdruck
if (button_pressed_event) {
INFO("Starte Füllvorgang..."); //INFO
open_upper_valve();
start_time = millis();
current_state = STATE_FILLING;
}
break;
case STATE_FILLING:
loading_animation(255, 100, 100); //orange
// Check if the glass is still there
if (!is_glass) {
WARN("Abbruch: Glas entfernt während des Füllens!");
close_all_valves();
blink_leds(255, 0, 0, 3, 200); // blink red LEDs as abort signal
current_state = STATE_IDLE;
break; // exit this state immediately
}
// oder ob der Knopf erneut gedrückt wurde für Abbruch
if (button_pressed_event) {
WARN("Abbruch während des Füllens!");
close_all_valves();
blink_leds(255, 0, 0, 3, 200); // blinkt 3x rot für 200ms
current_state = STATE_IDLE;
} else {
unsigned long elapsed = millis() - start_time;
if (elapsed >= upper_open_time) {
DEBUG("oberes soll jetzt geschlossen werden");
close_upper_valve();
INFO("Wechsle zum Entleeren...(in 5s)");
delay(5000);
open_lower_valve();
start_time = millis();
current_state = STATE_DISPENSING;
}
}
break;
case STATE_DISPENSING:
loading_animation(0, 255, 0); //green
// Check if the glass is still there
if (!is_glass) {
WARN("Abbruch: Glas entfernt während des Entleerens!");
close_all_valves();
blink_leds(255, 0, 0, 3, 200); // blink red LEDs as abort signal
current_state = STATE_IDLE;
break; // exit this state immediately
}
// Während des Entleerens prüfen wir ebenfalls auf Abbruch oder Ablauf der Zeit
if (button_pressed_event) {
WARN("Abbruch während des Entleerens!");
close_all_valves();
blink_leds(255, 0, 0, 3, 200); // blinkt 3x rot für 200ms
current_state = STATE_IDLE;
} else {
unsigned long elapsed = millis() - start_time;
if (elapsed >= lower_open_time) {
close_lower_valve();
INFO("Vorgang abgeschlossen, zurück zu IDLE");
blink_leds(0, 255, 0, 3, 200); // blinkt 3x grün für 200ms
current_state = STATE_IDLE;
}
}
break;
}
last_button_state = button_state;
}