Hilfe gesucht: Signalsteuerung eines Löschfahrzeugmodells

Hallo zusammen,

mein Name ist Kai und ich bin neu in der Welt von Arduino. Bevor die Frage aufkommt: technisches Verständnis ist vorhanden und i.d.R. ergoogel ich mir was ich brauche, verstehe es und setze es um. Wenn ich keine passenden Lösungen finde und selbst nicht weiterkomme suche ich mir ein Forum das mir kompetent vorkommt - und an diesem Punkt bin ich derzeit. Soviel zum Vorgeplänkel :slight_smile:

Die Ausgangssituation: ich habe mir vor einiger Zeit einen Bausatz eines Löschfahrzeuges geholt und wollte mir diesen nach eigenen Vorstellungen anpassen. Irgendwann kam mir der Gedanke "Mit Licht und Ton würde der bestimmt noch besser wirken...", also hab ich ne Schaltung mit mehreren NE555 entworfen. da diese aber zu groß wäre bin ich irgendwann auf den Arduino Nano gestoßen und dachte mir "versuchste es damit, dann reicht der Platz". Nun, 1,5 Monate nach dem Anfang des Projekts auf einem Arduino MEGA2560 R3 habe ich die Grundfunktionen (inkl. IR-Receiver) zwar fertig, allerdings (und da werden sich mit Sicherheit dem einen oder anderen die Nackenhaare streuben) basierend auf jeder Menge Delays.

Das Problem: Ich würde das Programm gerne schlanker, übersichtlicher und effizienter/realitätsnaher gestalten, aber dafür müssten die Delays raus und 4 Timer/Zähler die Arbeit übernehmen. Das Einfachste hierbei ist noch der Warnblinker. Die Blaulichtsequenzen (3 Ausgänge) müssten in sich und zueinander asynchron laufen (siehe Anhang). Zudem müssten alle per Timer gesteuerten Ausgänge beim Ausschalten ein LOW bekommen.

Was mir bislang nicht gelungen ist:

  • die Timer-gesteuerten Blaulichtsequenzen
  • das "erzwungene" LOW-Signal beim Ausschalten von Warnblinker oder Blaulicht

Das Ziel: Derzeit erlaubt das Programm nur das Starten bestimmter Abläufe nach Ablauf vorangegangener Delays, soll heißen: ist der Warnblinker an und Blaulicht soll gestartet werden, dann wartet Blaulicht bis der Warnblinker einmal durch ist. Das soll aber auch asynchron voneinander gestartet werden können. Genauso möchte ich die einzelnen Funktionen auch via Interrupt mitten in der (jetzigen) Schleife stoppen können.

Was derzeit noch unwichtig ist ist die Ton-Geschichte, dafür werde ich notgedrungen auf ein externes Soundmodul zurückgreifen (blöderweise bräuchte ich für den Ton nämlich 2 Ausgänge, die zeitgleich (!) 2 unterschiedliche Frequenzen wiedergeben und nach 750ms 2 weitere unterschiedliche Frequenzen ausgeben --> mehr Details: siehe Anhang)

Hier erstmal der bisherige Code:

#include <boarddefs.h>
#include <IRremote.h>
#include <IRremoteInt.h>
#include <ir_Lego_PF_BitStreamEncoder.h>


volatile int irPin = 2;

boolean b1On = false; //Initialize b1On Status "OFF"
boolean b2On = false; //Initialize b2On Status "OFF"
boolean b3On = false; //Initialize b3On Status "OFF"
boolean yeOn = false; //Initialize yeOn Status "OFF"
boolean ledOn = false; //Initialize ledOn Status "OFF"
boolean SPKOn = false; //Initialize SPKOn Status "OFF"

IRrecv irrecv(irPin);
decode_results results;

#define b1 6 //Blue Lights left
#define b2 7 //Blue Lights right
#define b3 8 //Blue Lights Front
#define ye 9 //Indicators Mode Warning
#define lights 10 //Traffic Lights
#define SPK 11 //ext. SoundModule
#define IR 2 //IR Input

void setup() {
  pinMode(2, INPUT);
  pinMode(6, OUTPUT);
  pinMode(7, OUTPUT);
  pinMode(8, OUTPUT);
  pinMode(9, OUTPUT);
  pinMode(10, OUTPUT);
  pinMode(11, OUTPUT);
  pinMode(12, OUTPUT);
  irrecv.enableIRIn();
  Serial.begin(9600);

  attachInterrupt(digitalPinToInterrupt(2), IR_Int, DEC);
}

void loop() {
  interrupts();
  if(ledOn == true){
    digitalWrite (lights, HIGH);
    } else {
    digitalWrite (lights, LOW);
    }
  if((ledOn == true) && (yeOn == true) && (b1On == false)){
    digitalWrite(ye, HIGH);
    delay(500);
    digitalWrite(ye, LOW);
    delay(500);
    } else {
    digitalWrite(ye, LOW);
    } 
  if((ledOn == true) && (yeOn == false) && (b1On == true)){
    digitalWrite(b1, HIGH);
    digitalWrite(b3, HIGH);
    delay(125);
    digitalWrite(b1, LOW);
    digitalWrite(b3, LOW);
    delay(125);
    digitalWrite(b1, HIGH);
    digitalWrite(b3, HIGH);
    delay(125);
    digitalWrite(b1, LOW);
    digitalWrite(b3, LOW);
    delay(125);
    digitalWrite(b2, HIGH);
    delay(125);
    digitalWrite(b2, LOW);
    delay(125);
    digitalWrite(b2, HIGH);
    digitalWrite(b3, HIGH);
    delay(125);
    digitalWrite(b2, LOW);
    digitalWrite(b3, LOW);
    delay(125);
    digitalWrite(b1, HIGH);
    digitalWrite(b3, HIGH);
    delay(125);
    digitalWrite(b1, LOW);
    digitalWrite(b3, LOW);
    delay(125);
    digitalWrite(b1, HIGH);
    delay(125);
    digitalWrite(b1, LOW);
    delay(125);
    digitalWrite(b2, HIGH);
    digitalWrite(b3, HIGH);
    delay(125);
    digitalWrite(b2, LOW);
    digitalWrite(b3, LOW);
    delay(125);
    digitalWrite(b2, HIGH);
    digitalWrite(b3, HIGH);
    delay(125);
    digitalWrite(b2, LOW);
    digitalWrite(b3, LOW);
    delay(125);
    digitalWrite(b1, HIGH);
    delay(125);
    digitalWrite(b1, LOW);
    delay(125);
    digitalWrite(b1, HIGH);
    digitalWrite(b3, HIGH);
    delay(125);
    digitalWrite(b1, LOW);
    digitalWrite(b3, LOW);
    delay(125);
    digitalWrite(b2, HIGH);
    digitalWrite(b3, HIGH);
    delay(125);
    digitalWrite(b2, LOW);
    digitalWrite(b3, LOW);
    delay(125);
    digitalWrite(b2, HIGH);
    delay(125);
    digitalWrite(b2, LOW);
    delay(125);
  } else if((ledOn == true) && (yeOn == true) && (b1On == true)){
    digitalWrite(b1, HIGH);
    digitalWrite(b3, HIGH);
    digitalWrite(ye, HIGH);
    delay(125);
    digitalWrite(b1, LOW);
    digitalWrite(b3, LOW);
    delay(125);
    digitalWrite(b1, HIGH);
    digitalWrite(b3, HIGH);
    delay(125);
    digitalWrite(b1, LOW);
    digitalWrite(b3, LOW);
    delay(125);
    digitalWrite(b2, HIGH);
    digitalWrite(ye, LOW);
    delay(125);
    digitalWrite(b2, LOW);
    delay(125);
    digitalWrite(b2, HIGH);
    digitalWrite(b3, HIGH);
    delay(125);
    digitalWrite(b2, LOW);
    digitalWrite(b3, LOW);
    delay(125);
    digitalWrite(b1, HIGH);
    digitalWrite(b3, HIGH);
    digitalWrite(ye, HIGH);
    delay(125);
    digitalWrite(b1, LOW);
    digitalWrite(b3, LOW);
    delay(125);
    digitalWrite(b1, HIGH);
    delay(125);
    digitalWrite(b1, LOW);
    delay(125);
    digitalWrite(b2, HIGH);
    digitalWrite(b3, HIGH);
    digitalWrite(ye, LOW);
    delay(125);
    digitalWrite(b2, LOW);
    digitalWrite(b3, LOW);
    delay(125);
    digitalWrite(b2, HIGH);
    digitalWrite(b3, HIGH);
    delay(125);
    digitalWrite(b2, LOW);
    digitalWrite(b3, LOW);
    delay(125);
    digitalWrite(b1, HIGH);
    digitalWrite(ye, HIGH);
    delay(125);
    digitalWrite(b1, LOW);
    delay(125);
    digitalWrite(b1, HIGH);
    digitalWrite(b3, HIGH);
    delay(125);
    digitalWrite(b1, LOW);
    digitalWrite(b3, LOW);
    delay(125);
    digitalWrite(b2, HIGH);
    digitalWrite(b3, HIGH);
    digitalWrite(ye, LOW);
    delay(125);
    digitalWrite(b2, LOW);
    digitalWrite(b3, LOW);
    delay(125);
    digitalWrite(b2, HIGH);
    delay(125);
    digitalWrite(b2, LOW);
    delay(125);
  } else {
    digitalWrite(b1, LOW);
    digitalWrite(b2, LOW);
    digitalWrite(b3, LOW);
  }
}

void IR_Int() {
  if (irrecv.decode(&results)) {
    int value = results.value;
    switch (value){
      case 16724175 : //Feedback Key "1"
          ledOn = !ledOn;
          break;
      case 16718055 : // Feedback Key "2"
          yeOn = !yeOn;
          break;
      case 16743045 : //Feedback Key "3"
          b1On = !b1On;
          break;
      case 16716015 : //Feedback Key "4"
          SPKOn = !SPKOn;
          if((SPKOn == true) && (b1On == true)){
          digitalWrite(SPK, HIGH);
          }else{
            digitalWrite(SPK, LOW);
          }
          break;
          }
          Serial.println(value, DEC);
          delay(500);
          irrecv.resume();
  }
}

Nun meine Frage: könnt ihr mir helfen zumindest die Beleuchtungssteuerung Delay-frei hinzubekommen?

Um den ersten Timer-Versuch hier mit einzufügen hat der Platz leider nicht gereicht, kann ich aber bei Bedarf noch hinterherschicken.

Bei offenen Fragen einfach raus damit.

Grüße,
Kai

Zeitablaufdiagramm.pdf (8.89 KB)

Hallo

Wie du möglicherweise schon vermutest heißt das Zauberwort millis

Schau dir das Beispiel blink without delay an und verstehe es. Es ist nicht so schwer.
Dazu suche nach Nachtwächter Erklärung hier im Forum.

Wenn dir das zu viel Arbeit ist suche nach Bibliotheken die Timer können.

wenn du diesem Thread mal folgst: RC Einsatzfahrzeugbeleuchtung - Deutsch - Arduino Forum erhältst du einen Ansatz, wie du verschiedenes Geblinke quasi-parallel betreiben kannst.

Am Ende des Threads habe ich eine Version reingestellt, die verschiedene Blinkmuster gem. ECE unterstützt bzw so wie es im HELLA Datenblatt stand.

rabiahirviente:
... Arduino Nano ...

Auch möglich wäre der ProMini, dem nur die USB-Schnittstelle fehlt. Oder die starke Serie mit schönen Befestigungslöchern. Oder den Mega2560 pro.

rabiahirviente:
Nun meine Frage: könnt ihr mir helfen zumindest die Beleuchtungssteuerung Delay-frei hinzubekommen?

Ja.

Beginne mit einer einfachen Aufgabenstellung: Lasse zwei LEDs unabhängig nit unterschiedlicher Frequenz blinken.

Lesestoff:
Blaulicht für Modell, aber wie?
Lichtsteuerung Modellflugzeug (Standmodell)

So, vielen Dank erstmal für die Antworten :slight_smile:

Die Nachtwächtererklärung habe ich vorher schonmal gesehen, aber zugegeben lediglich grob überflogen. Zumindest die Funktion "Warnblinker" habe ich auch nach dem Beispiel umgesetzt (das war noch vor Threaderöffnung), aber für den Rest haben mir halt Ideen bzw. Denkanstöße gefehlt.

Ich habe mir eure Vorschläge mal genau angesehen (den Nachtwächter nun auch genauer) und habe am Ende (für´s Erste) eine Kombination aus Timern und Logikelementen erstellt (keine Ahnung ob es so einen Code schon gab):

#include <boarddefs.h>
#include <IRremote.h>
#include <IRremoteInt.h>
#include <ir_Lego_PF_BitStreamEncoder.h>

boolean b1On = false; //Initialize b1On Status "OFF"
boolean b2On = false; //Initialize b2On Status "OFF"
boolean b3On = false; //Initialize b3On Status "OFF"
boolean b1t = false; //Initialize Timer-Status Blue 1 "OFF"
boolean b2t = false; //Initialize Timer-Status Blue 2 "OFF"
boolean b3t = false; //Initialize Timer-Status Blue 3 "OFF"
boolean yeOn = false; //Initialize yeOn Status "OFF"
boolean ledOn = false; //Initialize ledOn Status "OFF"
boolean SPKOn = false; //Initialize SPKOn Status "OFF"

unsigned long TS1; //Timer 1 Start
unsigned long TS2; //Timer 2 Start
unsigned long TS3; //Timer 3 Start
unsigned long TS4; //Timer 4 Start

#define TE1 125 //Timer 1 End
#define TE2 375 //Timer 2 End
#define TE3 500 //Timer 3 End
#define TE4 500 //Timer 4 End

int b1Stat = LOW; //Initialize b1 Status "OFF"; used for possible expansions
int b2Stat = LOW; //Initialize b2 Status "OFF"; used for possible expansions
int b3Stat = LOW; //Initialize b3 Status "OFF"; used for possible expansions

int IR = 2; //Infrared-Input
int b1 = 6; //Blue Lights front right (FR) and rear left (RL)
int b2 = 7; //Blue Lights front left (FL) and rear right (RR)
int b3 = 8; //Blue Lights Front
int ye = 9; //Indicators Mode Warning Output
int lights = 10; //Headlamp and Backlight Output
int SPK = 11; //Trigger MP3-Module "Play/Stop" (act.: spaceholder!)

volatile int irPin = 2;

decode_results results;
IRrecv irrecv(irPin);


void setup() {
  pinMode(2, INPUT);
  pinMode(6, OUTPUT);
  pinMode(7, OUTPUT);
  pinMode(8, OUTPUT);
  pinMode(9, OUTPUT);
  pinMode(10, OUTPUT);
  pinMode(11, OUTPUT);
  irrecv.enableIRIn();
  Serial.begin(9600);

  attachInterrupt(digitalPinToInterrupt(2), IR_Int, DEC);
}

void loop() {
  if(ledOn == true){  //white and red leds engaged
    digitalWrite (lights, HIGH);
    } else {
    digitalWrite (lights, false);
    }

  //yellow leds blink
  if((yeOn == true) && (ledOn == true) && (millis() - TS3 >= TE3)){
    TS3 = millis();
    digitalWrite(ye, digitalRead(ye) ^ 1);
  } else if(yeOn == false){
    digitalWrite(ye, LOW);
  }

  //blue leds Interval 125ms
  if((ledOn == true) && (b1On == true) && (millis() - TS1 >= TE1)){
    TS1 = millis();
    b1t = !b1t;
  } else if((ledOn == true) && (b1On == false) && (millis() - TS1 <= TE1)){
    TS1 = millis();
    b1t = false;
  }

  //blue leds Interval 375ms
  if((ledOn == true) && (b1On == true) && (millis() - TS2 >= TE2)){
    TS2 = millis();
    b2t = !b2t;
  }else if((ledOn == true) && (b1On == false) && (millis() - TS2 <= TE2)){
    TS2 = millis();
    b2t = false;
  }

  //blue leds Interval 500ms
  if((ledOn == true) && (b1On == true) && (millis() - TS4 >= TE4)){
    TS4 = millis();
    b3t = !b3t;
  }else if((ledOn == true) && (b1On == false) && (millis() - TS4 <= TE4)){
    TS4 = millis();
    b3t = false;
  }

  //blue leds FR and RL blink
  if((b1t == true) && (b3t == true)){ //command: start at theoretical 0ms, run 500ms, pause 500ms etc.
    digitalWrite(b1, HIGH);
    b1Stat = HIGH;
  } else {
    digitalWrite(b1, LOW);
    b1Stat = LOW;
  }

  //blue leds FL and RR blink
  if((b1t == true) && (b3t != true)){ //command: start at theoretical 500ms, run 500ms, pause 500ms etc.
    digitalWrite(b2, HIGH);
    b2Stat = HIGH;
  } else{
    digitalWrite(b2, LOW);
    b2Stat = LOW;
  }

  //blue leds Front blink
  if((b1t == true) && (b2t == true)){ //command: start at theoretical 0ms, run 375ms, pause 375ms etc.
    digitalWrite(b3, HIGH);
    b3Stat = HIGH;
  } else{
    digitalWrite(b3, LOW);
    b3Stat = LOW;
  }
}

void IR_Int() {
  if (irrecv.decode(&results)) {
    int value = results.value;
    switch (value){
      case 16724175 : //Feedback Key "1"
          ledOn = !ledOn;
          break;
      case 16718055 : // Feedback Key "2"
          yeOn = !yeOn;
          break;
      case 16743045 : //Feedback Key "3"
          b1On = !b1On;
          break;
      case 16716015 : //Feedback Key "4"
          SPKOn = !SPKOn;
          if((b1On == true) && (SPKOn == true)){ //Trigger Signal to MP3-Module
            digitalWrite(SPK, HIGH);
          } else {
            digitalWrite(SPK, LOW);
          }
          break;
          }
          Serial.println(value, DEC);
          delay(500);
          irrecv.resume();
  }
}

Resultat: 72 Zeilen gespart und funktioniert zu 90% so wie ich es mir vorgestellt habe. Die restlichen 10% resultieren zur Hälfte aus einer Asynchronität der einzelnen Timer, wodurch es zeitweise zu einer geringfügigen Überschneidung von b1 und b2 kommt - und zur anderen Hälfte aus der noch fehlerhaften Ausschaltbedingung für SPK. Derzeit ist der nur deaktivierbar wenn ledOn und b1On beide wahr sind. Sobald eine dieser Bedingungen wegfällt und SPK noch aktiv ist bleibt SPK aktiv bis die Einschaltbedingungen wieder gegeben sind - und kann erst dann wieder abgeschaltet werden. Ziel ist jedoch, dass SPK automatisch aus geht wenn B1On ausgeschaltet wird.

Was die Vorschläge "Blaulicht für Modell, aber wie?" und "RC Einsatzfahrzeugbeleuchtung" angeht: sobald ich die dort beschriebenen Funktionen richtig verstanden habe versuche ich es auch mal damit. Wer weiß, vielleicht kann man das Skript dadurch ja noch schlanker machen :smiley: