#include <Servo.h>
#include <Wire.h>
#include <Adafruit_NeoPixel.h> // 1000uF Kondensator zwischen + und -, 300-500 OHM Widerstand in der Datenleitung!
// Servos und Kontakte
Servo ServoDrehkranz; // Servo-Objekte anlegen
Servo ServoLeiter;
const int PinKontaktGlas[] = {2, 3, 4, 5, 6, 7, -1}; // Pins der IR-Kontakte
const int PinServoDrehkranz = 8; // Servo Pin Drehkranz
const int PinServoLeiter = 9; // Servo Pin Leiter
int ServoWinkelDrehkranzIst = 0; // Startwinkel Drehkranz
int ServoWinkelLeiterIst = 0; // Starteinkel Leiter
int ServoGeschwingigkeit = 30; // Höhere Werte verlangsamen die Servos
unsigned long LeiterTimer = millis(); // Merker - Zuständig für die Geschwindigkeit der Servos
unsigned long DrehkranzTimer = millis(); // Merker - Zuständig für die Geschwindigkeit der Servos
int Schritt = 1; // Diese Variable steuert die Bewegungsabläufe der Servos (Leiter hoch(1), Drehen(2), Leiter runter(3))
int InArbeit = 0; // Diese Variable sorgt dafür dass erst ein Glas befüllt wird, dann das Nächste
int Winkel = 22; // Winkelvariable für den Drehkranz (Soll)
//Neopixel
const int PinLed = 10; // LED Pin (Neopixel)
const int AnzahlLeds = 6; // Anzahl LEDs
const int LedHelligkeit = 50; // Helligkeit 0-255
// Blaulicht
const int Blaulicht[] = {1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, -1}; // Blitzabfolge
const unsigned long BlaulichtTempo = 36; // Höhere Werte verlangsamen den Blitz
int Zaehler = 0; // Wird in der Funktion Blitzer benötigt. Dias Array Blaulicht wird damit Stück für Stück abgearbeitet
unsigned long Merker = 0; // Merker für die Verzögerung beim Blaulicht (Tempo) - Dieser Variable wird der Wert von millis() übergeben.
int BlaulichtAnforderung = 0; // 0 = Kein Blaulicht, 1 = Angefordert, 2 = Baulicht durchläuft die Schleife
int Ein = 0; // Merker fürs Blaulicht
int ON = 0; // Merker fürs Blaulicht
unsigned long Leerlauftimer = 0;
// Declare our NeoPixel strip object:
Adafruit_NeoPixel LedStreifen(AnzahlLeds, PinLed, NEO_GRB + NEO_KHZ800);
// Argument 1 = Number of pixels in NeoPixel strip
// Argument 2 = Arduino pin number (most are valid)
// Argument 3 = Pixel type flags, add together as needed:
// NEO_KHZ800 800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
// NEO_KHZ400 400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
// NEO_GRB Pixels are wired for GRB bitstream (most NeoPixel products)
// NEO_RGB Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)
// NEO_RGBW Pixels are wired for RGBW bitstream (NeoPixel RGBW products)
unsigned long Timer = 0; // Dieser Variable wird der Wert von millis() übergeben - für die Wartezeit bevor das Glas befüllt wird
unsigned long StandzeitNeuesGlas = 1000; // Wie lange muss das Glas dort stehen, bevor es befüllt wird? Angabe in Millisekunden.
int GlasDefinitionen[] = { 0, 0, 0, 0, 0, 0 }; // 6 Werte für 6 Gläser - 7. Wert ist Ruhestellung!
void setup() {
ServoDrehkranz.attach(PinServoDrehkranz); // ServoDrehkranz mit Pin verbinden
ServoLeiter.attach(PinServoLeiter); // ServoLeiter mit Pin Verbinden
pinMode(PinKontaktGlas[0], INPUT_PULLUP);
pinMode(PinKontaktGlas[1], INPUT_PULLUP);
pinMode(PinKontaktGlas[2], INPUT_PULLUP);
pinMode(PinKontaktGlas[3], INPUT_PULLUP);
pinMode(PinKontaktGlas[4], INPUT_PULLUP);
pinMode(PinKontaktGlas[5], INPUT_PULLUP);
Serial.begin(9600);
LedStreifen.begin();
LedStreifen.show();
LedStreifen.setBrightness(LedHelligkeit);
Serial.println("FireFiller 2.0 - 08.12.23");
ServoDrehkranz.write(ServoWinkelDrehkranzIst);
ServoLeiter.write(ServoWinkelLeiterIst);
}
void loop() {
Check();
Tanken();
Leerlaufcheck();
}
void Leerlaufcheck() {
if (Leerlauftimer + 100 < millis() && (ServoWinkelDrehkranzIst > 0 || ServoWinkelLeiterIst > 0)) {
switch (Schritt) {
case 1:
LeiterBewegen(50, ServoGeschwingigkeit);
break;
case 2:
DrehkranzBewegen(0, ServoGeschwingigkeit);
break;
case 3:
LeiterBewegen(0, ServoGeschwingigkeit);
break;
}
}
}
void Check(){ // Livezustände checken und mit gemerkten Zuständen vergleichen. Stati und LEDs nach Situation verändern.
for (int i = 0; PinKontaktGlas[i] > 0 ; i++) { // Kontaktnummer zum Auslesen festlegen
int LiveZustand = digitalRead(PinKontaktGlas[i]); // Kontakt auslesen und Wert in Variable schreiben
if (LiveZustand == 0) { // 0 = Glas erkannt, 1 = Kein Glas
switch (GlasDefinitionen[i]) {
case 0: // 0 = Vormals wurde kein Glas erkannt, nun steht hier eins! --> Licht rot, Timer starten, Status auf 1 setzen.
LedStreifen.setPixelColor(i, LedStreifen.Color(255, 0, 0));
LedStreifen.show();
Timer = millis();
GlasDefinitionen[i] = 1;
break;
case 1: // 1 = Glas steht noch. Timer abwarten -->dann Status auf 2 setzen
Leerlauftimer = millis();
if (Timer + StandzeitNeuesGlas < millis()) {
GlasDefinitionen[i] = 2;
}
break;
case 2: // 2 = (Status 2 = Blaulicht ist an!!!) Servos werden angesteuert und dann Status auf 3
Leerlauftimer = millis();
if (BlaulichtAnforderung == 0) {
BlaulichtAnforderung = 1;
}
break;
case 3: // 3 = Glas ist voll! Blaulicht abschalten und Licht grün. Status auf 4 setzen.
BlaulichtAnforderung = 0;
LedStreifen.setPixelColor(i, LedStreifen.Color(0, 255, 0));
LedStreifen.show();
GlasDefinitionen[i] = 4;
break;
case 4: // 4 = Glas ist voll, licht ist bereits grün... Nichts machen!
break;
}
} else if (LiveZustand == 1 && GlasDefinitionen[i] > 0) { // Kein Glas erkannt, vorher stand hier jedoch eins. --> Status ändern!
GlasDefinitionen[i] = 0; // Status auf 0 setzen
LedStreifen.setPixelColor(i, LedStreifen.Color(0, 0, 0)); // LEDs definieren
LedStreifen.show();
BlaulichtAnforderung = 0;
Schritt = 1;
}
Blitzer(i);
}
}
int Blitzer(int LedNummer) {
if (BlaulichtAnforderung == 1){ // Wenn Blaulichtanforderung = 1 ist, soll der Blitzer laufen und die Servos angesteuert werden.
Merker = millis(); // Merker setzen
Zaehler = 0; // Variable zum Auslesen der Blitzabfolge
BlaulichtAnforderung = 2; // Blaulichtanforderung auf 2 setzen, sonst startet der Timer bei jedem durchgang wieder von vorne.
}
if(BlaulichtAnforderung == 2 && millis() >= (Merker + BlaulichtTempo)) { // Erst ausführen wenn Der Timer abgelaufen ist
for (int h = 0; PinKontaktGlas[h] > 0 ; h++) {
if (GlasDefinitionen[h] == 2 && Blaulicht[Zaehler] == 1 && Ein == 0) {
LedStreifen.setPixelColor(h, LedStreifen.Color(0, 0, 255));
ON = 1;
}
if (GlasDefinitionen[h] == 2 && Blaulicht[Zaehler] == 0 && Ein == 1) { // Wenn Blaulicht[i] = 0 dann Licht ausschalten und Merken dass es aus ist
LedStreifen.setPixelColor(h, LedStreifen.Color(0, 0, 0));
ON = 0;
}
}
Ein = ON;
Zaehler++;
Merker = millis();
LedStreifen.show();
if (Zaehler > 17) {
Zaehler = 0;
}
}
}
void Tanken() {
int x = (Winkel / 22) - 1; // x hat Werte von 0 - 5 (Für 6 Gläser)
if (PinKontaktGlas[x] >-1) { // -1 ist das Abbruchkriterium, der letzte Wert in dem Array.
int LiveZustand = digitalRead(PinKontaktGlas[x]); // Kontakt auslesen und Wert in Variable schreiben
if (LiveZustand == 0 && GlasDefinitionen[x] == 2 && (InArbeit == 0 || InArbeit == x)) { // Wenn Ein Glas erkannt wird UND das Glas befüllt werden soll (Status 2) UND die Variable InArbeit 0 ODER die Nummer des Felldes hat DANN weiter
if (InArbeit == 0) { // Die Servos sollen sich bewegen. Wenn InArbeit = 0 dann
InArbeit = x; // muss InArbeit die nummer des Glases erhalten um die Bewegungen für dieses Glas komplett abzuarbeiten
}
switch (Schritt) { //Schritt 1 = Leiter hoch, 2 = Drehen, 3 = Leiter runter
case 1:
LeiterBewegen(50, ServoGeschwingigkeit);
break;
case 2:
DrehkranzBewegen(Winkel, ServoGeschwingigkeit);
break;
case 3:
LeiterBewegen(0, ServoGeschwingigkeit);
break;
}
}
Winkel += 22;
if (Winkel > (6 * 22)){
Winkel = 22;
}
}
}
int LeiterBewegen (int Soll, unsigned long Verzoegerung) { // Funktion zum bewegen der Leiter
if (ServoWinkelLeiterIst < Soll && LeiterTimer + Verzoegerung < millis()) { // Wenn der SollWinkel nicht erreicht ist und die Wartezeit abgelaufen ist, dann weiterdrehen
ServoWinkelLeiterIst++; // IstWinkel um 1 erhöhen
ServoLeiter.write(ServoWinkelLeiterIst); // auf Wert drehen
LeiterTimer = millis(); // Timer für Wartezeit neu starten
}
if (ServoWinkelLeiterIst > Soll && LeiterTimer + Verzoegerung < millis()) { // Wenn der SollWinkel nicht erreicht ist und die Wartezeit abgelaufen ist, dann weiterdrehen
ServoWinkelLeiterIst--; // IstWinkel um 1 verringern
ServoLeiter.write(ServoWinkelLeiterIst); // auf Wert drehen
LeiterTimer = millis(); // Timer für WarteZeit neu starten
}
if (ServoWinkelLeiterIst == Soll) { // Wenn Sollwinkel erreicht ist dann
Schritt++; // zum nächsten Schritt gehen
if (Schritt == 4) { // Wenn Schritt 4 oder größer (Es gibt nur 3 Schritte)
InArbeit = 0;
Schritt = 1;
if (Winkel != 0) {
GlasDefinitionen[(Winkel/22) - 1] = 3; // Da der ablauf für dieses Glas abgeschlossen ist, wird der Status neu gesetzt
}
}
}
}
int DrehkranzBewegen (int Soll, int Verzoegerung) { // Funktion zum bewegen des Drehkranzes
if (ServoWinkelDrehkranzIst < Soll && DrehkranzTimer + Verzoegerung < millis()) { // Wenn der SollWinkel nicht erreicht ist und die Wartezeit abgelaufen ist, dann weiterdrehen
ServoWinkelDrehkranzIst++; // IstWinkel um 1 erhöhen
ServoDrehkranz.write(ServoWinkelDrehkranzIst); // auf Wert drehen
DrehkranzTimer = millis(); // Timer für Wartezeit neu Starten
}
if (ServoWinkelDrehkranzIst > Soll && DrehkranzTimer + Verzoegerung < millis()) { // Wenn der SollWinkel nicht erreicht ist und die Wartezeit abgelaufen ist, dann weiterdrehen
ServoWinkelDrehkranzIst--; // IstWinkel um 1 verringern
ServoDrehkranz.write(ServoWinkelDrehkranzIst); // auf Wert drehen
DrehkranzTimer = millis(); // Timer für Wartezeit neu Starten
}
if (ServoWinkelDrehkranzIst == Soll) { // Wenn der Winkel erreicht ist,
Schritt++; // zum nächsten Schritt gehen
}
}