Arduino Uno als Besetzt-Ampel

Hallo, Leute.

Erstmal möcht' ich mich kurz vorstellen, Ich heiße Olaf, bin 27 Jahre alt und Kfz-Techniker-Meister.
Ich habe einen kleinen :wink: Hang zur Technik und bastel und probier gern unsinniges und manchmal auch sinniges aus.

Nun zu meinem Projekt und meinem Problem:

Mir ist vor einiger Zeit der Gedanke gekommen, meinen Schribtischstuhl mit einer kleinen Ampel als besetzt zu markieren,
auch, wenn ich mal kurz nicht am Platz bin. Die Suche, nach geeigneten Möglichkeiten ging los, sollte aber nicht zu teuer sein.
Durch meine Ausbildung und meine (möchte ich behaupten) doch recht gutes Verständnis für Elektrik, war auch schnell ein Schaltplan erstellt. Die Teilebeschaffung jedoch, war eine etwas größere Hürde. Da ich die Anlage nicht zu groß haben und auch nicht mit Spannungen >12V arbeiten wollte, wurden die Bauteile schnell recht teuer. Zeitrelais unter ~12V sind mir etwas zu groß.
schlussendlich bin ich auf das Arduino-System gestoßen, mit dem ich mich jetzt seit ca. 4 wochen beschäftige. :~

Mir fällt es nicht leicht, es zu sagen, aber ich hänge fest. Ich schaffe es einfach nicht, meinen Schaltplan, auf das Arduino vernünftig anzuwenden. Entweder es ist so, das ich die Halte- und Verzögerungsoption nicht sauber hinbekomm' und das Abtasten des sensor (sharp Distanzsensor) über längere zeit nicht funktioniert. Oder ich kann nicht zwischendurch neueinsteigen. =(

Funktion: Einschalten des Boards über einen Hauptschalter und an einer 9V-Blockbatterie.
Registriert der Distanzsensor ein Objekt auf dem Stuhl, welches sich ca 10s dort befindet, soll die LED-Rot geschaltet werden, sobald ich den Platz verlasse, soll die LED-Rot für eine bestimmte Zeit (sagen wir 10min.) geschaltet bleiben und dann für eine weitere zeit (sagen wir 5min.) auf Orange/Gelb wechseln. Danach soll Grün aktiviert werden. Grün wird solange gehalten, bis wieder Jemand, etwas, ICH, sich auf den Stuhl begibt für ca. 10s. :stuck_out_tongue:

Jetzt ist das Problem, welches ich habe:
Der Distanzssensor schaltet, LED-Grün geht aus, LED-Rot geht an und ab dann läuft die Zeit. wenn ich jetzt nach 8min. den Stuhl verlasse, bleibt die LED-Rot nur noch 2min. aktiv und schaltet dann weiter auf Orange/Gelb und dann grün. Genauso, wenn ich nach 2min. den Stuhl verlasse und nach 5min. (insgesamt 7min.) wiederkomme, bleibt die LED-Rot nur noch 3min. aktiv, schaltet dann auf Orange/Gelb und danach auf Grün und erfasst mich dann erst über den Sensor neu, Startet das Programm jetzt aber wieder von vorn. :disappointed_relieved:

Zur Hilfe.....

Mein Schaltplan im Anhang.

Und mein Grundgerüst vom Prozess:

int greenPin = 10;
int yellowPin = 11;
int redPin = 12;
int bridge_outPin = 5;
int bridge_inPin = 7;
int analogIn = A0;
int analogValue = 0.01;
const float referenceVolts = 5.0;
void setup()
{
  Serial.begin(9600);
  pinMode(greenPin, OUTPUT);
  pinMode(yellowPin, OUTPUT);
  pinMode(redPin, OUTPUT);
  pinMode(bridge_outPin, OUTPUT);
  pinMode(bridge_inPin, INPUT);
}
void loop()
{
    int val = analogRead(A0);  // Wert vom Sensor einlesen
    float volts = (val / 630.0) * referenceVolts;  // Verhältnis berechnen
    Serial.print(volts);
    
    //Hier kommt die Schaltung für Besetzt
    
    }
void setLights(int green, int yellow, int red)
{
  digitalWrite(greenPin, green);
  digitalWrite(yellowPin, yellow);
  digitalWrite(redPin, red);
}

Das ist hoffentlich nur ein Prinzipschaltbild und nicht was real existiert. Deine LEDs brauchen Vorwiderstände! Und zwar jede einen.

Da Relais zu verwenden ist nicht so schön. Das kann man mit Transistoren erschlagen.

ok ... da brauchen wir ein paar unsigned long Variable dafür:

  • Besetzt
  • Rot
  • Gelb

und nun zum Ablauf:

  1. wenn sich jemand frisch hinsetzt, wird in Besetzt die aktuelle "Systemzeit" mit mills() gespeichert. Wenn er wieder aufsteht, wird sie auf 0 gesetzt. Wie erkennst Du, ob er sich "frisch" hinsetzt? ganz einfach: der Sensor erkennt jemanden und der Wert von Besetzt == 0.

  2. dann überlegen wir mal, wann wir die Rote LED Einschalten müssen:

  • Besetzt > 0
  • Besetzt + 10 Sekunden < mills()
    Wenn diese Bedingung erfüllt ist, dann in Rot den Wert von mills() speichern und die rote LED einschalten. Das machst Du so lange, wie jemand vom Sensor erkannt wird. Wenn Du dann aufstehst, wird Besetzt ja gleich 0 und damit trifft diese Bedingung oben nicht mehr zu. Damit weißt Du, wann jemand aufgestanden ist.
  1. das kannst Du nun nutzen um zu prüfen, ob es Zeit für die Gelbe LED ist:
  • Besetzt == 0
  • Rot > 0
  • Rot + 10 min < mills()
    Wenn diese Bedingungen erfüllt sind, dann sitzt seit 10 Minuten keiner mehr auf dem Stuhl und Du kannst die rote LED aus und die gelbe einschalten. Zusätzlich wird der Wert von Rot auf 0 gesetzt und der Wert von mills() in Gelb gespeichert.

Das gleiche Spielchen machst Du dann nochmal mit der Grünen LED.

@ Serenifly:
Der Schaltplan ist nur als Prinzip, ja. Vorwiderstände sind 220 Ohm verbaut.
Zur Zeit sind keine Relais etc. verbaut, da ich ja alles uber das Arduino Uno laufen lassen will, muss ja auch gehen.

@ mgcss:
Über die Antwort muss ich erstmal grübeln und probier das dann aus, danke.

ei, ei ei...
Irgedwie ist das noch ein bischen zu schwer für mich. Hab mich jetzt 'ne ganze weile mit "Unsigned long" auseinandergesetzt, aber irgendwie will mir das nicht so richtig gelingen. Hab' den Sensor ja gut drin und mit einer Variablen kann ich soweit gut arbeiten, aber hat jemand vllt. ein Beispiel für mich, mit mehreren "unsigned long" Variablen?

Die Einbindung wäre ganz hilfreich, denn irgendwie find ich auch nichts gescheites auf deutsch im Netz.

unsigned long bzw uint32_t bedeutet nichts anderes, dass Variable mit Zahlen von 0 - 4.294.967.295 arbeiten kann. Somit nichts anderes als ein normales int, nur dass der Zahlen raumgrößer ist. Bei millis muss der Zahlenraum möglichst groß sein, da, wie der Name bereits sagt, sich der Wert jede Millisekunde um 1 erhört. Das wären +1000 in der Sekunde.

Der unterschied zwischen signed und unsigned gibt an, ob der Werte Bereich negativ und positiv oder nur positiv ist. Ein normales int ist immer signed, wenn es nicht extra als unsigned deklariert wird.

Suche mal nach HC-05 bei ebay. Das ist ein Ultraschallsensor zur Messung der Distanz. Der ist einfach in die IDE zu integrieren.

sschultewolter:
Suche mal nach HC-05 bei ebay. Das ist ein Ultraschallsensor zur Messung der Distanz.

Du meintest "HC-SR04", oder? Mit "HC-05" kommen Bluetooth-Module...

ulli.

Also, wen ich mich recht belesen habe, bedeutet es ja nichts anderes, als das ich mit dem "Unsigned long" einen bestimmten Speicherbereich fest für einen Programmschritt belege.
Jetzt habe ich aktuell das Problem, das ich (arbeite mit dem IR-Sensor von sharp 2Y0A02) diesen zwar eigebunden hab, aber es nur schaffe einen Interval zu programmieren.
Das heist, bisher ist es mir nur gelungen einen Rot-Grün wechsel zu erreichen und das mit unterschiedlichen Intervallen.

if(sensorValue > 80 && previousMillis > interval)
{
digitalWrite(greenPin, LOW);
digitalWrite(redPin, HIGH);
}
else
{
digitalWrite(greenPin, HIGH);
digitalWrite(redPin, LOW);
}

Habe aktuell zum Probieren einen 5sec. Intervall (5000). Jetzt stellt sich aber heraus, das wenn ich in das Sensorfeld eintrete, nach 5 Sekunden umgeschaltet wird, aber wenn ich mich durch das Sensorfeld bewege auch, nach zusammengerechnet 5 Sekunden. Will sagen, wenn ich mich 5x 1 Sekunde im Sensorfeld aufhalte, schaltet mein System auch um.

Ich habe leider nicht die meiste Zeit um mich damit zu beschäftigen, ca. 1-1,5Std. pro Tag, wobei ich die besten Einfälle, das Programm zu bearbeiten meist bei Autofahren habe, weil ich da die Ruhe hab' drüber nachzudenken. Problem bei der Sache... bis ich zu Hause bin hab ichs vergessen =(

Nochmal ein paar kurze Hintergrundfragen:

Mit "if" und "else" zu Arbeiten ist richtig, oder?
&& in der If-Verbindung bedeutet nichts anderes als "wenn ........ und ......." {dann.......} ?
Was passiert wenn ich nur & mache ?
Gibt es eine "oder" Programmierung ?
ist == das gleiche wie = ?

und < bedeutet auch nur "gößer und kleiner" ?
millis() liest immer meine aktuelle Systemzeit aus ? oder speichert es diese ?

Hoffe ich seh das jetzt alles richtig.
Und mus jetzt trotzig feststellen, das ich von Elektrik Ahnung habe, aber bei Elektronik und Programmierung noch viel lernen muss.

&& in der If-Verbindung bedeutet nichts anderes als "wenn ........ und ......." {dann.......} ?

ja

Was passiert wenn ich nur & mache ?

bitweise AND ( 6 & 3 ) == 2

Gibt es eine "oder" Programmierung ?

klar : || bzw. |

ist == das gleiche wie = ?

NEIN ! = (assignment operator) == (equal to)

und < bedeutet auch nur "gößer und kleiner" ?

meistens ja

millis() liest immer meine aktuelle Systemzeit aus ? oder speichert es diese ?

millis() liefert einen unsigned long Wert und macht sonst nichts. Wo soll die Funktion bitteschön etwas speichern ? Das machst du mit einer Anweisung wie

unsigned long meineZeit = millis();

Und mus jetzt trotzig feststellen, das ich von Elektrik Ahnung habe, aber bei Elektronik und Programmierung noch viel lernen muss.

Warum "trotzig" ? :wink: Es handelt sich hier um die Programmiersprache C ( genaugenommen C++ ) Dafür gibt es mehr Informationen als hier in der Arduino Referenz . Aber auch da sind deine Fragen oben bereits beantwortet. Du brauchst "nur" zu lesen, das Lernen kommt dann schon von allein, wenn du es verwendest :stuck_out_tongue:

Also, wen ich mich recht belesen habe, bedeutet es ja nichts anderes, als das ich mit dem "Unsigned long" einen bestimmten Speicherbereich fest für einen Programmschritt belege.

Was eine Variable in einer Programmiersprache ist, scheint dir etwas unklar zu sein.
Was du mit einem "Programmschritt" meinst, ist mir unklar. Du hast hier keine SPS - Ablaufsteuerung mit Schritten und Datenbereichen, sondern eine Programmiersprache.

P_coupe:
Das heist, bisher ist es mir nur gelungen einen Rot-Grün wechsel zu erreichen und das mit unterschiedlichen Intervallen.

Im Prinzip mußt Du Dir für ein Programm immer zwei Dinge überlegen:

  1. geeignete Datenstrukturen für Deine Variablen, die das Problem abbilden und
  2. geeignete Algorithmen, die mit diesen Datenstrukturen hantieren

Das ganze dann in ein strukturiertes Programm nach dem EVA-Prinzip verpacken:
E - Eingabewerte ermitteln
V - Verarbeitung der Eingabewerte zu Ausgangswerten
A - Ausgangswerte ausgeben

Ich würde für Dein Programm zwei Zeitzähler vorschlagen:

  • Anwesenheitszähler - zählt immer die Zeit hoch, wenn Abstand unterschritten
  • Abwesenheitszähler - zählt immer die Zeit hoch, wenn Abstand überschritten
    Beim Wechsel des Abstands unterschritten/überschritten werden beide Zähler auf null zurückgesetzt
    Und der Zähler, der seinen Grenzwert überschreitet, bestimmt dann, welche LEDs geschaltet werden

Danke Jungs. :slight_smile:

Ich habs jetzt soweit. Das einzige, was mir noch fehlt, ist das einschalten von Rot, erst nach einer zeit von (irgendeine Zeit) im Sensorbereich. Aber das bekommen wir schon hin, nicht wahr 8).

Ich grübel jetzt den Abend nochmal darüber und schau morgen mal, was geht.

Mahlzeit!
Also, um ohne Umwege auf den Punkt zu kommen:

Die 10 Sekunden Verzögerung und auch das Zurückspringen während der Zeit läuft, nur die "Verzögerung" in meinem Sinne nicht.
Ich möchte ja, das sich die rote LED (also besetzt) erst einschaltet, wenn jemand ca. 10s im Sensorbereich ist.
Aktuell ist es so, das wenn jemand im Sensorbereich aufhält sind alle LED'S LOW (ist so gewollt), sobald der Sensorbeireich frei ist (egal nach welcher Zeit) läuft Rot, Gelb, Grün. Setze ich jetzt die Zeit so, das nach 10s im Sensorbereich erst umgeschaltet wird, ist es so, das nicht unbedingt dauerhafte 10s im sensorbereich von nöten sind sondern es funktioniert auch bei 10x 1s mit unterbrechungen.

Funktioniert eine, wie von mir gewollte, Verzögerung überhaupt. Oder bracuhe ich dafür ein extra Relais?
Also genau, wie in meiner Schaltplan-Skizze. ein zurücksentzen also auch erst wenn etwas sich 10s im Sensorbereich aufhält.

//Schaltung für Besetzt von OJ

const int greenPin = 10;
const int yellowPin = 11;
const int redPin = 12;
int sensorPin = A0;
int sensorValue = 0;
int greenState = HIGH;             // LED-Status
int yellowState = LOW;
int redState = LOW;
const float referenceVolts = 5.0;
unsigned long previousMillis = 0; // speichert wie viele Sekunden seit derletzten Änderung vergangen sind
unsigned long interval = 20000;    // Interval zwischen zwei Änderungen led

void setup()
{
  Serial.begin(9600);
  pinMode(greenPin, OUTPUT);
  pinMode(yellowPin, OUTPUT);
  pinMode(redPin, OUTPUT);
  pinMode(sensorPin, INPUT);
}
void loop()
{
    
    unsigned long currentMillis = millis();
    sensorValue = analogRead(A0);
    if(sensorValue > 100)
    {
      previousMillis = currentMillis;
    digitalWrite(greenPin, LOW);
    digitalWrite(yellowPin, LOW);
    digitalWrite(redPin, LOW);
    }
    if(currentMillis - previousMillis > 500 
        && currentMillis - previousMillis < 10000)
    {
    digitalWrite(greenPin, LOW);
    digitalWrite(yellowPin, LOW);
    digitalWrite(redPin, HIGH);
    }
    if(sensorValue < 80 && currentMillis - previousMillis > 10000
        && currentMillis - previousMillis < 18000)
    {
      digitalWrite(greenPin, LOW);
      digitalWrite(yellowPin, HIGH);
      digitalWrite(redPin, LOW);
    }
    if(sensorValue < 80 && currentMillis - previousMillis > 18000)
    {
      digitalWrite(greenPin, HIGH);
      digitalWrite(yellowPin, LOW);
      digitalWrite(redPin, LOW);
    }
  }

//Schaltung für Besetzt von OJ

Funktioniert eine, wie von mir gewollte, Verzögerung überhaupt. Oder bracuhe ich dafür ein extra Relais?

Nur wegen der Programmlogik braucht man kein Relais.

Eher umgekehrt: Erstaunlich, was Steuerungsfuzzis mit Relais hinkriegen, wo "normale Menschen" einen Controller bräuchten.

Wenn dein Programm nicht das macht was du willst, helfen dir meist Testausschriebe um deine eigene Logik zu verstehen.

Oder einfaches Draufschauen:

    if(sensorValue > 100)
    {
      previousMillis = currentMillis;
      digitalWrite(greenPin, LOW);
      digitalWrite(yellowPin, LOW);
      digitalWrite(redPin, LOW);
    }

Das ist nicht das was du wünschst, sondern schaltet auf jeden Fall alle LED, wenn sensorValue > 100.

Du musst erstmal erkennen, wenn sensorValue sich signifikant ändert ( von besetzt nach frei oder umgekehrt )
wann welche Zeit neu gestartet werden muss, bzw. abgelaufen ist. Erst daraus ergibt sich, welche LED leuchten soll.
( So hab ich deine Beschreibung jedenfalls verstanden. )

Wenn du dafür in "Relais" denkst, meinst du vermutlich eigentlich eine globale Variable zur Zustandsführung.

#define ANWESEND true
#define ABWESEND false

boolean platzZustand;

void loop() {
   boolean aktuellerZustand;
   if (analogRead(A0) > 40 )
      aktuellerZustand = ANWESEND;
   else
      aktuellerZustand = ABWESEND; 

   if ( aktuellerZustand != platzZustand)
   {  // etwas ändert sich : 
       // passende Zeit starten  ...
       platzZustand = aktuellerZustand;  // Änderung merken
   }
  // ...
}

if ( aktuellerZustand != platzZustand)
{ // etwas ändert sich :
// passende Zeit starten ...
platzZustand = aktuellerZustand; // Änderung merken

Was meinst du mit passende Zeit starten? Sollte das meine Unsigned long sein? Mit delay() halte ich ja wieder das ganze Programm auf.

Problem ist halt, das die Verzögerung auch eintritt wenn ich nur kurz im Sensorbereich bin. Mit einem Relais bin ich jedesmal gezwungen (so wie ich das gern möchte) 10s im Sensorbereich zu verweilen, sonst schaltet dies ja nicht.
Ich habe irgendwie immer das Bedürfnis, den Sensor zu Fragen: Jetzt > 40 ..... 10s später ...... immer noch >40? wenn ja dann jetzt Schalten und Zeit ablaufen lassen. Und wenn Sensorwert währenddessen wieder > 40 und 10s später immernoch >40, dann zurück zum Anfang von Schalten und Zeitablauf.
Funktioniert halt soweit, bis auf die Verzögerung....Hab auch schon daran gedacht, den Sensor durch einen Sitzkontakt zu ersetzen, weil es Vllt. an dem analogen Sensorbereich liegt, aber ich glaub, ich hätte das gleiche Problem.

Das mit alle LED'S LOW ist mir zwischendurch eingefallen und find das eigentlich soweit ganz gut, dachte mir, das behalt ich so.

Aber erstmal zur obersten Frage zurück und dann probier ich das mal so aus.

Mit delay() halte ich ja wieder das ganze Programm auf.

Wer redet von delay() ?

Was meinst du mit passende Zeit starten? Sollte das meine unsigned long sein?

Ja, tschuldigung: ich meinte Start-Zeitpunkt merken. Zeit messen geht immer durch (millis() - StartZeit)

Kannst übrigens auch mehrere Start-Zeiten merken, in verschiedenen Variablen, wenn das hilft.
Aber so wie ich das verstehe, läuft immer nur eine Zeit: entweder für die 10 sek bis besetzt erkannt wird , oder die 10 Minuten bis die nächste LED dran kommt. ?

Also ist mein Starzeitpunkt "currentMillis=previousMillis"
Genau. Ich bekomm's halt nicht recht hin, das ich wirklich 10s im Sensorbereich sein muss. Der Rest funktioniert ja, nach meinem Willen.

Wie merke ich mir Zeiten? Mehrere "unsigned long" ? Hast 'n Bsp.?

Ich bekomm's halt nicht recht hin, das ich wirklich 10s im Sensorbereich sein muss

    if(sensorValue > 100)
    {
      previousMillis = currentMillis;
      // alle LED aus
    }

Das speichert indirekt (indem previousMillis nicht mehr verändert wird) den Zeitpunkt, wenn sensorValue <= 100 wird

    if(currentMillis - previousMillis > 500 
        && currentMillis - previousMillis < 10000)
    {
    digitalWrite(greenPin, LOW);
    digitalWrite(yellowPin, LOW);
    digitalWrite(redPin, HIGH);
    }

0.5s bis 10s später wird Rot HIGH gesetzt.
Ich glaube nicht, dass du diese 0.5 sec sauber sehen kannst, woher deine Vermutung kommt, 10 kleine Intervalle könnten zusammenaddiert werden, sehe ich nicht.

    if(sensorValue < 80 && currentMillis - previousMillis > 10000
        && currentMillis - previousMillis < 18000)
    {
      digitalWrite(greenPin, LOW);
      digitalWrite(yellowPin, HIGH);
      digitalWrite(redPin, LOW);
    }

10 .. 18s nachdem sensorValue < 100 und wenn ausserdem sensorValue < 80 ist, wirds Gelb
nach insgesamt 18s Grün.

Sobald alle Led aus gehen, hat jemand sensorValue > 100 gesetzt. Im Bereich sensorValue = 80 .. 100 läuft die Zeit weiter, aber die Leds ändern sich nicht, damit du es ein bisschen schwerer hast.

Mach mal die erste Wartezeit (500) größer und lass die zweite Grenze (sensorValue <80) weg.
Und gib der Variable previousMillis einen besseren Namen ... :wink:

Ich hab Spass, das muss ich ja sagen, aber ich muss meine kleinen grauen Zellen auch oderntlich fordern. :cold_sweat:

Bin grad' auf dem weg logisch zu Verknüpfen, das wenn ich die Zeit (ganz oben im Ablauf) starte und jetzt mit anderen Bezeichnungen arbeite, den Sensorbereich betreten kann und mein Ablauf im Hintergrund weiterläuft.... ich bekommst noch raus..... :stuck_out_tongue:

den Sensorbereich betreten kann und mein Ablauf im Hintergrund weiterläuft.

Ich fürchte, du denkst immer noch "Ablaufsteuerung"

Ein loop-Durchlauf beschreibt den Zustand im Bruchteil einer millisekunde.
In den allermeisten Durchläufen ändert sich gar nichts:
Du stellst zwar deine 3 LED ein, aber in der Regel genauso wie sie schon waren.

Die 4[b] if() { } [/b]Teile könnten in beliebiger Reihenfolge dastehen, es würde praktisch genauso funktionieren.

Noch ein Tip:
ein Arduino hat auf Pin 13 schon eine kleine Led angeschlossen. Die könntest du zu Testzwecken zusätzlich schalten: z.B. während der ersten "10 sek" ( die in deinem sketch nur 500 ms sind) um den Unterschied zwischen sensor > 100 und "Zeit läuft" ab sensor < 100 zu erkennen ....

Meint ich doch...falsch ausgedrückt :stuck_out_tongue:

Der ist gut, das Probier ich aus....