Arduino: RailFX-Baustellen- und Industriemodul

Das RailFX-Baustellen- und Industriemodul des RailFX-Systems ist für den Einsatz in Baustellen oder Industrieanlagen konzipiert und hat folgende Funktionen: Kran (Links, Ablassen, Aufnehmen, Rechts, Ablassen, Aufnehmen) LKW mit Mulde (Vorwärtsfahren, Mulde kippen, Mulde zurückholen, rückwärts fahren) Zwei Paar blinkende Warnleuchten (z. B. für Rundumleuchten oder Absperrungen) Fahrzeugbeleuchtung 4x Arbeitslicht (schaltet unterschiedlich schnell ein) Schweißlicht (1x Schweißblitz, 1x Nachglühen) Da es nicht möglich ist, das Soundmodul DFPlayer gleichzeitig mit Servomotoren zu verwenden, gibt es auf diesem Modul kein leider keine Soundausgabe. Allerdings kann dafür das unabhängige RailFX-Soundmodul (gerade in Arbeit) nutzen. Schaltplan D10: Kran-Servo Drehung D11: Kran-Servo Winde D12: LKW-Servo Bewegung D13: LKW-Servo Mulde D4, D5, D16 (A2), D17 (A3): LEDs für Blinklichter D6: Schweißlicht Blitz D7: Schweißlicht Nachglühen D14 (A13), D15 (A1): Fahrzeugbeleuchtung D2, D3, D8, D9: Arbeitslicht (die analogen Inputs werden als digitale Outputs verwendet) Achtung: Am Pin A4 wird das Control-Signal des RailFX Control-Moduls angelegt. Es steuert die Tageszeit und ist zwingend erforderlich. Bauteile LED-Set Servo-Motoren (Es kann Sinn ergeben, bessere Servos zu kaufen, weil diese relativ häufig auslösen müssen.) Einstellungen im Code Auch dieses Modul bietet eine Reihe an Einstellmöglichkeiten. Zum einen sollten alle Zielzustände der Servos eingestellt werden. Es gibt für jeden der vier Servos jeweils zwei Zustände, z.B. windeOben und windeUnten. Dabei handelt es sich um die Gradzahl, auf die sich der Servo einstellen soll. Dabei ist zu beachten, dass der Bereich zwischen 0 und 180 liegen sollte, obwohl Servos oft nicht diese Extremwerte erreichen können. Deshalb müssen diese Grenzen ausprobiert werden. Ich schlage vor, sich vorsichtig an diese Grenzen heranzutasten, z.B. 30 – 150, 20 – 160 … Des Weiteren muss windeOben größer als windeUnten. Das gilt für alle Grenzwerte. Der Kran vollzieht eine Animation, die zeitgesteuert abläuft. Die Dauer der einzelnen Phasen lässt ich über das Array kranTimeouts bestimmen. Hier werden die Zeiten in Millisekunden angegeben (1000ms=1s). Die Animation hat folgende Phasen: Warten (Wahrscheinlichkeit) Aufnehmen Warten Drehen Warten Ablassen Warten (Wahrscheinlichkeit) Aufnehmen Warten Drehen Warten Ablassen Position 0 und 6 (Die erste Stelle im Array ist immer 0) legen eine Wahrscheinlichkeit fest, mit der der Kran weiter arbeitet: je höher, desto seltener wird die nächste Animationsphase ausgeführt. Dadurch entsteht ein zufälligeres Arbeitsbild. Die Drehgeschwindigkeit der beiden Kranservos (Winde und Drehung) lassen sich über die Variablen kranWindeSpeedund kranDrehungSpeed einstellen. Je größer der Wert, desto langsamer bewegen sich die Servos. Ähnlich zum Kran vollzieht auch der LKW eine Animation, die zeitgesteuert abläuft. Die Dauer der einzelnen Phasen lässt ich auch hier über das Array lkwTimeouts bestimmen. Die Animation hat folgende Phasen: Warten (Wahrscheinlichkeit) Vorwärts fahren Warten Mulde kippen Warten (Wahrscheinlichkeit) Mulde zurückkippen Warten Rückwärts fahren Position 0 und 4 (Die erste Stelle im Array ist immer 0) legen eine Wahrscheinlichkeit fest, mit der der LKW weiter arbeitet: je höher, desto seltener wird die nächste Animationsphase ausgeführt. Die Drehgeschwindigkeit der beiden LKW-Servos (Fahren und Mulde) lassen sich über die Variablen lkwBewegungSpeed und lkwMuldeSpeed einstellen. Je größer der Wert, desto langsamer bewegen sich die Servos. Es gibt zwei Warnlicht-Paare, die unterschiedlich schnell blinken. Die Frequenz kann man über das Array warnlichtTimer einstellen. Eine leichte Varianz in der Frequenz erzeugt ein realistischeres Blinkbild. Drüber hinaus wird auf der Baustelle geschweißt. Das Schweißlicht (Blitz) lässt sich in der Pulsgeschwindigkeit in der Bariable schweissGeschwindigkeit anpassen. Je größer der Wert, desto langsamer die Schweißpulse. In der Variable schweissPause lässt sich die Pause zwischen den Schweißvorgängen einstellen. Die schweissDauer bestimmt die Dauer der Schweißvorgänge und mit der Variable nachGluehen lässt sich einstellen, wie hell das Nachglühen sein soll (0 = sehr hell, 255 = sehr dunkel). /* ***** ***** Einstellungen ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** */ int kranTimeouts[] = {1000, 3000, 1000, 3000, 1000, 3000, 1000, 3000, 1000, 3000, 1000, 3000}; /* Legt die Wartezeiten der Kranabfolge fest: warten (Wahrscheinlichkeit), aufnehmen, warten, drehen, warten, ablassen, warten (Wahrscheinlichkeit), aufnehmen, warten, drehen, warten, ablassen -> Position 0 und 6 legen eine Wahrscheinlichkeit fest, mit der der Kran weiter arbeitet: je höher, desto seltener */ int lkwTimeouts[] = {1000, 3000, 1000, 3000, 1000, 3000, 1000, 3000}; /* Legt die Wartezeiten des LKWs fest: warten (Wahrscheinlichkeit), vorwärts, warten, ablassen, warten (Wahrscheinlichkeit), aufladen, warten, zurück fahren -> Position 0 und 6 legen eine Wahrscheinlichkeit fest, mit der der Kran weiter arbeitet: je höher, desto seltener */ int kranWindeSpeed = 10; // Geschwindigkeit der Kranwinde (größer = langsamer) int kranDrehungSpeed = 10; // Geschwindigkeit der Krandrehung (größer = langsamer) int windeOben = 120; // Servoposition der eingezogenen Kranwinde int windeUnten = 60; // Servoposition der herabgelassenen Kranwinde int kranRechts = 160; // Servoposition des Kranturms Rechts int kranLinks = 30; // Servoposition des Kranturms Links int lkwMuldeSpeed = 10; // Geschwindigkeit der LKWmulde (größer = langsamer) int lkwBewegungSpeed = 10; // Geschwindigkeit der LKWdrehung (größer = langsamer) int muldeOben = 120; // Servoposition der eingezogenen LKWmulde int muldeUnten = 60; // Servoposition der herabgelassenen LKWmulde int lkwRechts = 160; // Servoposition des LKWturms Rechts int lkwLinks = 30; // Servoposition des LKWturms Links int schweissGeschwindigkeit = 50; // je größer, desto langsamer int schweissPause = 100; // Pause zwischen Schweißvorgängen int schweissDauer = 30; // Dauer der Schweißvorgänge int nachGluehen = 100; // Helligkeit des Nachglühens von 0 = hell bis 255 = aus int warnlichtTimer[3] = {800, 700, 650}; // Warnlicht Blitzfrequenz Beim Upload muss man darauf achten, dass das richtige Board im Arduino-Menü ausgewählt ist. Dazu muss ebenfalls im Werkzeuge-Menü im Unterpunkt Prozessor »ATmega328P (Old Bootlaoder)« ausgewählt sein. Der folgende Programmcode kann mit den oben erwähnten Änderungen einfach kopiert und auf das Arduino-Nano geladen werden. Code für das Modul: RailFX-Baustellen- und Industriemodul /* Rail-FX Baustelle-und Industrie-Modul StartHardware.org Arduino: RailFX-Baustellen- und Industriemodul */ #include <Servo.h> /* ***** ***** Einstellungen ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** */ int kranTimeouts[] = {1000, 3000, 1000, 3000, 1000, 3000, 1000, 3000, 1000, 3000, 1000, 3000}; /* Legt die Wartezeiten der Kranabfolge fest: warten (Wahrscheinlichkeit), aufnehmen, warten, drehen, warten, ablassen, warten (Wahrscheinlichkeit), aufnehmen, warten, drehen, warten, ablassen -> Position 0 und 6 legen eine Wahrscheinlichkeit fest, mit der der Kran weiter arbeitet: je höher, desto seltener */ int lkwTimeouts[] = {1000, 3000, 1000, 3000, 1000, 3000, 1000, 3000}; /* Legt die Wartezeiten des LKWs fest: warten (Wahrscheinlichkeit), vorwärts, warten, ablassen, warten (Wahrscheinlichkeit), aufladen, warten, zurück fahren -> Position 0 und 6 legen eine Wahrscheinlichkeit fest, mit der der Kran weiter arbeitet: je höher, desto seltener */ int kranWindeSpeed = 10; // Geschwindigkeit der Kranwinde (größer = langsamer) int kranDrehungSpeed = 10; // Geschwindigkeit der Krandrehung (größer = langsamer) int windeOben = 120; // Servoposition der eingezogenen Kranwinde int windeUnten = 60; // Servoposition der herabgelassenen Kranwinde int kranRechts = 160; // Servoposition des Kranturms Rechts int kranLinks = 30; // Servoposition des Kranturms Links int lkwMuldeSpeed = 10; // Geschwindigkeit der LKWmulde (größer = langsamer) int lkwBewegungSpeed = 10; // Geschwindigkeit der LKWdrehung (größer = langsamer) int muldeOben = 120; // Servoposition der eingezogenen LKWmulde int muldeUnten = 60; // Servoposition der herabgelassenen LKWmulde int lkwRechts = 160; // Servoposition des LKWturms Rechts int lkwLinks = 30; // Servoposition des LKWturms Links int schweissGeschwindigkeit = 50; // je größer, desto langsamer int schweissPause = 100; // Pause zwischen Schweißvorgängen int schweissDauer = 30; // Dauer der Schweißvorgänge int nachGluehen = 100; // Helligkeit des Nachglühens von 0 = hell bis 255 = aus int warnlichtTimer[3] = {800, 700, 650}; // Warnlicht Blitzfrequenz /* ***** ***** Ab hier beginnt der Programmcode, der nicht angepasst werden muss ***** ***** ***** ***** */ int warnlichtPins[4] = {4, 5, 16, 17}; // Warnlicht Pins int fahrzeugbeleuchtungPins[2] = {14, 15}; // Pins der Fahrzeugbeleuchtung int beleuchtungsPins[4] = {2, 3, 8, 9}; // an diesem Pin ist die Einsatzstellen-Beleuchtung angebracht int schweissPins[2] = {7, 6}; // an diesen Pins ist das Schweißlicht angeschlossen int kranServoPin = 10; int windeServoPin = 11; int lkwServoPin = 12; int muldeServoPin = 13; /* State Variablen */ int kranStatus = 0; int lkwStatus = 0; int schweissenStatus = 0; /* Speicher-Variablen */ int windePosition; int kranPosition; int muldePosition; int lkwPosition; int schweissnaht; /* Timer Variablen */ long kranTimer; long kranDrehungTimer; long kranWindeTimer; long lkwTimer; long lkwBewegungTimer; long lkwMuldeTimer; //long muldeTimer; /* Objekte anlegen */ Servo kranServo; Servo windeServo; Servo muldeServo; Servo lkwServo; /* Variablen vom Controlmodul um die Uhrzeit festzustellen*/ boolean receive = false; boolean receiveStarted = false; int receiveTimeout = 10; long receiveTimer = 0; int receivedTime = 0; int receivePulse = 0; int lastReceivePulse = 0; int receivePin = 18; int myTime = 0; #define PAYLOAD_SIZE 2 // nötig für die Kommunikation zum Master int uhrzeit = 0; // speichert die uhrzeit vom Master-Modul (0 und 255) byte nodePayload[PAYLOAD_SIZE]; // speichert die Daten vom Master-Modul zwischen void setup() { Serial.begin(115200); // started die serielle Kommunikation for (int i = 0; i < 4; i++) { // Für die Anzahl der Beleuchtung-Pins pinMode(beleuchtungsPins[i], OUTPUT); // Deklariere den Pin als Output digitalWrite(beleuchtungsPins[i], HIGH); // Schalte die LED an diesem Pin ab } for (int i = 0; i < 2; i++) { // Für die Anzahl der Fahrzeugbeleuchtung-Pins pinMode(fahrzeugbeleuchtungPins[i], OUTPUT); // Deklariere den Pin als Output digitalWrite(fahrzeugbeleuchtungPins[i], HIGH); // Schalte die LED an diesem Pin ab } for (int i = 0; i < 4; i++) { // Für die Anzahl der Warnlicht-Pins pinMode(warnlichtPins[i], OUTPUT); // Deklariere den Pin als Output digitalWrite(warnlichtPins[i], HIGH); // Schalte die LED an diesem Pin ab } lkwServo.attach(lkwServoPin); muldeServo.attach(muldeServoPin); kranServo.attach(kranServoPin); windeServo.attach(windeServoPin); } void loop() { receiveFunction(); // Führe Anweisungen für Empfang aus if (receiveStarted == false) { // Falls gerade keine Daten empfangen werden: if (myTime > 22) { // ***** Später Abend ***** schweissenAn(); // Schweißen einschalten warnlichtAn(); // Warnlichter einschalten beleuchtungAn(); // Beleuchtung einschalten fahrzeugbeleuchtungAn(); // Fahrzeugbeleuchtung einschalten lkwAn(); // Fallenden Baum einschalten kranAn(); // Kranbewegungen einschalten } else if (myTime > 18) { // ***** Abend ***** schweissenAn(); // Schweißen einschalten warnlichtAn(); // Warnlichter einschalten beleuchtungAn(); // Beleuchtung einschalten fahrzeugbeleuchtungAn(); // Fahrzeugbeleuchtung einschalten lkwAn(); // Fallenden Baum einschalten kranAn(); // Kranbewegungen einschalten } else if (myTime > 12) { // ***** Nachmittag ***** schweissenAn(); // Schweißen einschalten warnlichtAn(); // Warnlichter einschalten beleuchtungAus(); // Beleuchtung ausschalten fahrzeugbeleuchtungAus(); // Fahrzeugbeleuchtung ausschalten lkwAn(); // Fallenden Baum einschalten kranAn(); // Kranbewegungen einschalten } else if (myTime > 9) { // ***** Vormittag ***** schweissenAn(); // Schweißen einschalten warnlichtAn(); // Warnlichter einschalten beleuchtungAus(); // Beleuchtung ausschalten fahrzeugbeleuchtungAus(); // Fahrzeugbeleuchtung ausschalten lkwAn(); // Fallenden Baum einschalten kranAn(); // Kranbewegungen einschalten } else if (myTime > 7) { // ***** Morgen ***** schweissenAn(); // Schweißen einschalten warnlichtAn(); // Warnlichter einschalten beleuchtungAus(); // Beleuchtung ausschalten fahrzeugbeleuchtungAus(); // Fahrzeugbeleuchtung ausschalten lkwAn(); // Fallenden Baum einschalten kranAn(); // Kranbewegungen einschalten } else { // ***** Nacht ***** schweissenAus(); // Schweißen ausschalten warnlichtAus(); // Warnlichter einschalten beleuchtungAus(); // Beleuchtung einschalten fahrzeugbeleuchtungAn(); // Fahrzeugbeleuchtung einschalten lkwAn(); // Fallenden Baum ausschalten } } } void fahrzeugbeleuchtungAn() { digitalWrite(fahrzeugbeleuchtungPins[0], LOW); digitalWrite(fahrzeugbeleuchtungPins[1], LOW); } void fahrzeugbeleuchtungAus() { digitalWrite(fahrzeugbeleuchtungPins[0], HIGH); digitalWrite(fahrzeugbeleuchtungPins[1], HIGH); } void beleuchtungAn() { if (random(2000) <= 1) digitalWrite(beleuchtungsPins[0], LOW); if (random(2000) <= 1) digitalWrite(beleuchtungsPins[1], LOW); if (random(2000) <= 1) digitalWrite(beleuchtungsPins[2], LOW); if (random(2000) <= 1) digitalWrite(beleuchtungsPins[3], LOW); } void beleuchtungAus() { for (int i = 0; i < 4; i++) { digitalWrite(beleuchtungsPins[i], HIGH); } } void warnlichtAn() { for (int i = 0; i < 2; i++) { if (millis() % warnlichtTimer[i] < warnlichtTimer[i] / 2) { digitalWrite(warnlichtPins[i * 2], HIGH); digitalWrite(warnlichtPins[i * 2 + 1], LOW); } else { digitalWrite(warnlichtPins[i * 2], LOW); digitalWrite(warnlichtPins[i * 2 + 1], HIGH); } } } void warnlichtAus() { for (int i = 0; i < 4; i++) { digitalWrite(warnlichtPins[i], HIGH); } } void kranAn() { if ((kranStatus != 0) || (kranStatus != 6)) { if (kranTimer + kranTimeouts[kranStatus] < millis()) { kranStatus++; if (kranStatus > 11) kranStatus = 0; kranTimer = millis(); Serial.print("Kranstatus="); Serial.println(kranStatus); } } switch (kranStatus) { case 0: // warten if (random(kranTimeouts[0]) < 1) kranStatus = 1; break; case 1: // aufnehmen if (kranWindeTimer + kranWindeSpeed < millis()) { if (windePosition < windeOben) { windePosition++; windeServo.write(windePosition); } kranWindeTimer = millis(); } break; case 2: // pause break; case 3: // drehen if (kranDrehungTimer + kranDrehungSpeed < millis()) { if (kranPosition < kranRechts) { kranPosition++; kranServo.write(kranPosition); } kranDrehungTimer = millis(); } break; case 4: // pause break; case 5: // ablassen if (kranWindeTimer + kranWindeSpeed < millis()) { if (windePosition > windeUnten) { windePosition--; windeServo.write(windePosition); } kranWindeTimer = millis(); } break; case 6: // warten if (random(kranTimeouts[6]) < 1) kranStatus = 7; break; case 7: // aufnehmsen if (kranWindeTimer + kranWindeSpeed < millis()) { if (windePosition < windeOben) { windePosition++; windeServo.write(windePosition); } kranWindeTimer = millis(); } break; case 8: // pause break; case 9: // drehen if (kranDrehungTimer + kranDrehungSpeed < millis()) { if (kranPosition > kranLinks) { kranPosition--; kranServo.write(kranPosition); } kranDrehungTimer = millis(); } break; case 10: // pause break; case 11: // ablassen if (kranWindeTimer + kranWindeSpeed < millis()) { if (windePosition > windeUnten) { windePosition--; windeServo.write(windePosition); } kranWindeTimer = millis(); } break; } } void lkwAn() { if ((lkwStatus != 0) || (lkwStatus != 4)) { if (lkwTimer + lkwTimeouts[lkwStatus] < millis()) { lkwStatus++; if (lkwStatus > 7) lkwStatus = 0; lkwTimer = millis(); Serial.print("LKWstatus="); Serial.println(lkwStatus); } } switch (lkwStatus) { case 0: // warten if (random(lkwTimeouts[0]) < 1) lkwStatus = 1; break; case 1: // vorwärts if (lkwBewegungTimer + lkwBewegungSpeed < millis()) { if (lkwPosition < lkwRechts) { lkwPosition++; lkwServo.write(lkwPosition); } lkwBewegungTimer = millis(); } break; case 2: // pause break; case 3: // ablassen if (lkwMuldeTimer + lkwMuldeSpeed < millis()) { if (muldePosition > muldeUnten) { muldePosition--; muldeServo.write(muldePosition); } lkwMuldeTimer = millis(); } break; case 4: // warten if (random(lkwTimeouts[6]) < 1) lkwStatus = 5; break; case 5: // aufnehmsen if (lkwMuldeTimer + lkwMuldeSpeed < millis()) { if (muldePosition < muldeOben) { muldePosition++; muldeServo.write(muldePosition); } lkwMuldeTimer = millis(); } break; case 6: // pause break; case 7: // rückwärts fahren if (lkwBewegungTimer + lkwBewegungSpeed < millis()) { if (lkwPosition > lkwLinks) { lkwPosition--; lkwServo.write(lkwPosition); } lkwBewegungTimer = millis(); } break; } } void schweissenAn() { analogWrite(schweissPins[1], schweissnaht); switch (schweissenStatus) { case 0: // Schweissen analogWrite(schweissPins[0], 0); if (millis() % schweissGeschwindigkeit < 10) schweissenStatus = 1; schweissnaht = nachGluehen; break; case 1: // Flackern analogWrite(schweissPins[0], 255); if (random(schweissDauer * 1000) < 10) schweissenStatus = 2; else if (millis() % schweissGeschwindigkeit < 1) schweissenStatus = 0; break; case 2: // Nachglühen if (random(30) < 1) schweissnaht++; if (schweissnaht >= 255) { schweissnaht = 255; schweissenStatus = 3; } break; case 3: // Pause if (random(schweissPause * 1000) < 1) schweissenStatus = 0; break; } } void schweissenAus() { analogWrite(schweissPins[0], 255); analogWrite(schweissPins[1], 255); } /* ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** */ void receiveFunction() { // Empfängt die Uhrzeit vom Control-Modul receivePulse = digitalRead(receivePin); // Lies den Empfangspin aus if ((receiveTimer + receiveTimeout < millis()) && (receiveStarted == true)) { // Bei Timeout und aktivem Empfang receiveStarted = false; // beende aktiven Empfang myTime = receivedTime - 1; // speichere die empfangene Zeit receivedTime = 0; // setze die Hilfsvariable zum Zeitempfang zurück Serial.println(myTime); // serielle Ausgabe } // falls ein Puls am Empfangspin erfasst wird, der vorher nicht da war if ((receivePulse == 0) && (lastReceivePulse == 1)) { receiveTimer = millis(); // starte Timer neu if (receiveStarted == false) receiveStarted = true; // starte aktiven Empfang, wenn noch nicht geschehen receivedTime++; // es gab einen Puls, also erhöhe die Hilfsvariable zum Zeitempfang } lastReceivePulse = receivePulse; // aktuellen Zustand am Pin für nächsten Durchlauf merken } Der Beitrag Arduino: RailFX-Baustellen- und Industriemodul erschien zuerst auf Arduino Tutorial.

zum Artikel gehen

Sende a message from arduino nano to raspberry pi via 433 mhz rf module

I want to make a data transfer circuit using Arduino nano and Raspberry Pi. It will be done using 433 mhz rf module. If the password sent by Arduino is correct, Raspberry Pi will respond with a message stating the correct password... (Budget: $10 - $11 US

zum Artikel gehen

Mit Arduino Bewegungs- und Orientierungssensoren in Systeme integrieren

Entwickler müssen ihre Systeme zunehmend mit Orientierungs- und Bewegungsfunktionen ausstatten, sind aber unsicher, wo sie anfangen sollen. Ein Arduino könnte dabei helfen.

zum Artikel gehen

heise+ | Spracherkennung mit Arduino nano connect realisieren

Spracherkennung mit einem Arduino, das war bislang mangels Rechenpower unvereinbar. Doch der Nano RP2040 connect soll das packen. Wir zeigen, wie es geht.

zum Artikel gehen

Wokwi: Web-Simulator, etwa für Raspberry Pi Pico, Arduino und ESP32

Mit dem Online-Simulator Wokwi lassen sich Mikrocontroller-Projekte mit Raspberry Pi Pico, Arduino, ESP32 und weiteren Boards sowie Sensoren im Web-Browser simulieren.

zum Artikel gehen

Bauteile für Arduino – Hier bekommst du Nachschub

Bauteile für Arduino zu beschaffen kann eine Herausforderung darstellen. Besonders, wenn man gerade damit anfängt, scheitert man oft an Kleinigkeiten, wie dem speziellen Widerstandswert, den man noch nicht vorrätig hat. Doch woher bekommt man Teile und wa

zum Artikel gehen