Lichtschranke zur Motorsteuerung

Hallo liebe Gemeinde,
ich möchte ein kleines Projekt umsetzen das mehrere Lichtschranke zur Steuerung von 4 Motoren nutzen soll.

Dazu habe ich 4 JGY370 12 Volt Motoren die mit 2 L298n Modulen angesteuert werden sollen.

Mit dem Kippschalters soll der Sketch gestartet und gestoppt werden.
Die Geschwindigkeit der Motoren 1-3 soll mit einem Poti eingestellt werden können.

Im Anschluss werden die Fotowiderstände abgefragt.
Motor 1 und 2 sollen so lange laufen bis die Lichtschranke unterbrochen ist.
Die Lcihtschranken von Motor 3 und 4 werden immer nur kurz beim durchlaufen unterbrochen.
Sobald die Lichtschranke unterbrochen wird soll der Motor für 2 Sekunden laufen.
Wenn die Lichtschranke innerhalb dieser 2 Sekunden erneut unterbrochen wird soll der Motor erneut für 2 Sekunden laufen usw., bis die Lichtschranke nicht mehr unterbrochen wird.

Wichtig ist das in dieser Zeit die Lichtschranke 1 und 2 aber weiterhin abgefragt werden und der Sketch deshalb nicht mit delay()unterbrochen werden kann.

Bei der Nutzung von millis() bin ich bisher nur auf Beispiele gestoßen bei denen ein Ereignis alle paar Sekunden 1 mal ausgeführt wird aber nicht für eine definierte Zeit.

Für jeden Verbesserungsvorschlag bin ich sehr dankbar.

Anbei noch der Code:

// Motor 1 
int enA = 3; // PWM zur Geschwidigkeitsregelung
int in1 = 2;
int in2 = 1;
 
// Motor 2
int enB = 6; // PWM zur Geschwidigkeitsregelung
int in3 = 5;
int in4 = 4;

// Motor 3
int enC = 9;  // PWM zur Geschwidigkeitsregelung
int in5 = 8;
int in6 = 7;

// Vibrationsmotoren
int enD = 10;
int in7 = 11;
int in8 = 12;

// Geschwindigkeit Potentiometer
int SpeedControl1 = A0;  
int SpeedControl2 = A1;
int SpeedControl3 = A2; 
 
// Motor Start Wert 
int MotorSpeed1 = 0;
int MotorSpeed2 = 0;
int MotorSpeed3 = 0;
int MotorSpeedVibration = 0;

// Lichtschranke 1-4
int LR1 = A3;
int LR2 = A4;
int LR3 = A5;
int LR4 = A6;

// Kippschalter für starten und stoppen der Funktion
int Sw = 13;

// Schalterzustand 
int SwWert = 0;

 
void setup()
 
{
 
  // Motorpins als Output setzen  
  pinMode(enA, OUTPUT);
  pinMode(enB, OUTPUT);
  pinMode(enC, OUTPUT);
  pinMode(enD, OUTPUT);
  pinMode(in1, OUTPUT);
  pinMode(in2, OUTPUT);
  pinMode(in3, OUTPUT);
  pinMode(in4, OUTPUT);
  pinMode(in5, OUTPUT);
  pinMode(in6, OUTPUT);
  pinMode(in7, OUTPUT);
  pinMode(in8, OUTPUT);
  pinMode(Sw, INPUT);
  
   
}
 
void loop() {

  //Kippschalter auslesen
  SwWert = digitalRead(Sw);

  //Starten der wenn Schalter auf "ein"
  if(SwWert == HIGH){
    
     //Lichtschranken einlesen 
     LR1 = analogRead(3);
     LR2 = analogRead(4);
     LR3 = analogRead(5);
     LR4 = analogRead(6);
  
     // Motor 1 
      if(LR1 < 100){
    
        // Motor 1 vorwärts
        digitalWrite(in1, HIGH);
        digitalWrite(in2, LOW);

        // Poti auslesen
        MotorSpeed1 = analogRead(SpeedControl1);

        // Umwandeln für PWM
        MotorSpeed1 = map(MotorSpeed1, 0, 1023, 0, 255);

        // Minimalgeschwindigkeit um Motorsurren zu vermeiden
        if (MotorSpeed1 < 20)MotorSpeed1 = 0;
    
        // Geschwindigkeit einstellen
        analogWrite(enA, MotorSpeed1);

      }

      else{

        // Motor ausschalten wenn LR1 unterbrochen ist
        MotorSpeed1 = 0;
        analogWrite(enA, MotorSpeed1);
    
      }


        // Motor 2 
      if(LR2 < 100){
    
        // Motor 2 vorwärts
        digitalWrite(in3, HIGH);
        digitalWrite(in4, LOW);

        // Poti auslesen
        MotorSpeed2 = analogRead(SpeedControl2);

        // Umwandeln für PWM
        MotorSpeed2 = map(MotorSpeed2, 0, 1023, 0, 255);

        // Minimalgeschwindigkeit um Motorsurren zu vermeiden
        if (MotorSpeed2 < 20)MotorSpeed2 = 0;
    
        // Geschwindigkeit einstellen
        analogWrite(enB, MotorSpeed2);

      }

      else{

        // Motor ausschalten wenn LR2 unterbrochen ist
        MotorSpeed2 = 0;
        analogWrite(enB, MotorSpeed2);
    
      }


        // Motor 3 
        if(LR3 < 100){
    
        // Motor 3 vorwärts
        digitalWrite(in5, HIGH);
        digitalWrite(in6, LOW);

        // Poti auslesen
        MotorSpeed3 = analogRead(SpeedControl3);

        // Umwandeln für PWM
        MotorSpeed3 = map(MotorSpeed3, 0, 1023, 0, 255);

        // Minimalgeschwindigkeit um Motorsurren zu vermeiden
        if (MotorSpeed3 < 20)MotorSpeed3 = 0;
    
        // Geschwindigkeit einstellen
        analogWrite(enC, MotorSpeed3);

      }

      else{

        // Motor ausschalten wenn LR3 unterbrochen ist
        MotorSpeed3 = 0;
        analogWrite(enC, MotorSpeed3);
    
      }


        // Vibrationsmotor 
        if(LR4 > 400){
    
        // Vibrationsmotor an
        digitalWrite(in7, HIGH);
        digitalWrite(in8, LOW);

        MotorSpeedVibration = 255;
    
        // Geschwindigkeit einstellen
        analogWrite(enD,MotorSpeedVibration);

      }

      else{

        MotorSpeedVibration = 0;
        analogWrite(enD,MotorSpeedVibration);
    
      }
  }


  //Anhalten wenn Schalter auf "aus"
  else{
    analogWrite(enA,0);
    analogWrite(enB,0);
    analogWrite(enC,0);
    analogWrite(enD,0);
       
  }
}

Hi

Verbesserungspotential erkannt

  • Pins als const byte (nicht int) zuweisen.
    Das erlaubt den Kompiler diese Zahlen direkt im Code einzupflegen.
    Ohne das const (also auch bei byte) wird die Variable aus dem Speicher ausgelesen und dann erst benutzt - unnötige Zwischenschritte, Die neben Zeit auch Platz kosten.

SwWert brauchst Du nicht global, wird nur in loop() benutzt.
if (digitalRead(Sw){ …
reicht vollkommen und braucht gar keine Variable.

Motor 1 bis Motor 4 machen exakt das Gleiche - doppelten Code lagert man in eine Funktion aus - so braucht’s nur 1x den Code, spart Platz.
(Zugegeben: Motor 4 macht’s bei unterbrochener Lichtschranke - Das sollte aber die Funktion nicht großartig verkomplizieren)

//Original:
//Der Sketch verwendet 1900 Bytes (5%) des Programmspeicherplatzes. Das Maximum sind 32256 Bytes.
//Globale Variablen verwenden 23 Bytes (1%) des dynamischen Speichers, 2025 Bytes für lokale Variablen verbleiben. Das Maximum sind 2048 Bytes.

//Umbau:
//Der Sketch verwendet 1836 Bytes (5%) des Programmspeicherplatzes. Das Maximum sind 32256 Bytes.
//Globale Variablen verwenden 20 Bytes (0%) des dynamischen Speichers, 2028 Bytes für lokale Variablen verbleiben. Das Maximum sind 2048 Bytes.

//Es ließe sich noch Einiges reduzieren - bis jetzt machen alle 4 Motoren genau das Gleiche, nur 1x bei unterbrochener Lichtschranke, statt bei offener.

// Motor 1
const byte enA = 3; // PWM zur Geschwidigkeitsregelung
const byte in1 = 2;
const byte in2 = 1; //solltest Du bei UNO und NANO noch Mal überlegen - hier sitzt der USB-Anschluß dran
 
// Motor 2
const byte enB = 6; // PWM zur Geschwidigkeitsregelung
const byte in3 = 5;
const byte in4 = 4;

// Motor 3
const byte enC = 9;  // PWM zur Geschwidigkeitsregelung
const byte in5 = 8;
const byte in6 = 7;

// Vibrationsmotoren
const byte enD = 10;
const byte in7 = 11;
const byte in8 = 12;

// Geschwindigkeit Potentiometer
const byte pinSpeed1=A0;
const byte pinSpeed2=A1;
const byte pinSpeed3=A2;
int SpeedControl1;     //uint bringt keine Vorteile, 2 Byte brauchen wir eh
int SpeedControl2;     //analogRead liefert 0...1023
int SpeedControl3;
 
// Motor Start Wert
byte MotorSpeed1 = 0;       //analogWrite hingegen kann nur 0...255 - hier reicht Byte (oder uint8_t)
byte MotorSpeed2 = 0;
byte MotorSpeed3 = 0;
byte MotorSpeedVibration = 0;

// Lichtschranke 1-4
const byte pinLR1=A3;
const byte pinLR2=A4;
const byte pinLR3=A5;
const byte pinLR4=A6;//wenn Du hier digital abfragen KANNST - A6 und A7 (also ein NANO, beim UNO nicht rausgeführt)
                     //könntest Du diese Lichtschranke und ein Poti tauschen - A6 und A7 sind reine analog-IN
int LR1;
int LR2;
int LR3;
int LR4;

// Kippschalter für starten und stoppen der Funktion
const byte Sw = 13;

void setup(){
   // Motorpins als Output setzen 
  pinMode(enA, OUTPUT);
  pinMode(enB, OUTPUT);
  pinMode(enC, OUTPUT);
  pinMode(enD, OUTPUT);
  pinMode(in1, OUTPUT);
  pinMode(in2, OUTPUT);
  pinMode(in3, OUTPUT);
  pinMode(in4, OUTPUT);
  pinMode(in5, OUTPUT);
  pinMode(in6, OUTPUT);
  pinMode(in7, OUTPUT);
  pinMode(in8, OUTPUT);
  pinMode(Sw,INPUT);
}
 
void loop() {
  if(digitalRead(Sw)){
    //Schalter ist auf HIGH   

     LR1 = analogRead(pinLR1);
     LR2 = analogRead(pinLR2);
     LR3 = analogRead(pinLR3);
     LR4 = analogRead(pinLR4);
 
     // Motor 1
      if(LR1 < 100){      //Lichtschranke 1 nicht unterbrochen
        // Motor 1 vorwärts
        digitalWrite(in1, HIGH);
        digitalWrite(in2, LOW);
        // Poti auslesen
        MotorSpeed1 = analogRead(SpeedControl1);
        // Umwandeln für PWM
        MotorSpeed1 = map(MotorSpeed1, 0, 1023, 0, 255);
        // Minimalgeschwindigkeit um Motorsurren zu vermeiden
        if (MotorSpeed1 < 20)MotorSpeed1 = 0;
        // Geschwindigkeit einstellen
        analogWrite(enA, MotorSpeed1);
      }else{
        // Motor ausschalten wenn LR1 unterbrochen ist
        MotorSpeed1 = 0;
        analogWrite(enA, MotorSpeed1);
      }

        // Motor 2
      if(LR2 < 100){
        // Motor 2 vorwärts
        digitalWrite(in3, HIGH);
        digitalWrite(in4, LOW);
        // Poti auslesen
        MotorSpeed2 = analogRead(SpeedControl2);
        // Umwandeln für PWM
        MotorSpeed2 = map(MotorSpeed2, 0, 1023, 0, 255);
        // Minimalgeschwindigkeit um Motorsurren zu vermeiden
        if (MotorSpeed2 < 20)MotorSpeed2 = 0;
        // Geschwindigkeit einstellen
        analogWrite(enB, MotorSpeed2);
      }else{
        // Motor ausschalten wenn LR2 unterbrochen ist
        MotorSpeed2 = 0;
        analogWrite(enB, MotorSpeed2);
      }

        // Motor 3
        if(LR3 < 100){
        // Motor 3 vorwärts
        digitalWrite(in5, HIGH);
        digitalWrite(in6, LOW);
        // Poti auslesen
        MotorSpeed3 = analogRead(SpeedControl3);
        // Umwandeln für PWM
        MotorSpeed3 = map(MotorSpeed3, 0, 1023, 0, 255);
        // Minimalgeschwindigkeit um Motorsurren zu vermeiden
        if (MotorSpeed3 < 20)MotorSpeed3 = 0;
        // Geschwindigkeit einstellen
        analogWrite(enC, MotorSpeed3);
      }else{
        // Motor ausschalten wenn LR3 unterbrochen ist
        MotorSpeed3 = 0;
        analogWrite(enC, MotorSpeed3);
      }

        // Vibrationsmotor
        if(LR4 > 400){
        //Wenn Lichtschranke 4 unterbrochen   
        // Vibrationsmotor an
        digitalWrite(in7, HIGH);
        digitalWrite(in8, LOW);
        MotorSpeedVibration = 255;
        // Geschwindigkeit einstellen
        analogWrite(enD,MotorSpeedVibration); //analogWrite 255 entspricht digitalWrite HIGH
      }else{
        MotorSpeedVibration = 0;
        analogWrite(enD,MotorSpeedVibration);
      }
  }else{
    //Wenn Schalter auf LOW, dann Anlage aus
    analogWrite(enA,0);
    analogWrite(enB,0);
    analogWrite(enC,0);
    analogWrite(enD,0);
  }
}

Was mir auffällt: Du kommst aus dem Motor4-Lauf nicht mehr raus.
Wenn die Lichtschranke unterbrochen ist, rüttelt der Motor los, oder von Wem hängt die Zuführung ab?

Unnötige Leerzeilen entfernen und in der IDE STRG+T drücken, helfen die Lesbarkeit zu erhöhen.
Habe auch die Klammern bei IF/ELSE umgesetzt - wenn die Klammer erst die Zeile drunter steht, wird der Code auseinander gerissen - gefällt mir zumindest nicht - die Funktion ist identisch, da der Kompiler hier keine Unterschiede sieht.

Am Sketch selber hat sich Nichts geändert, wenn’s vorher funktioniert hat, funktioniert’s jetzt noch genau so.

MfG

xanderv:
Bei der Nutzung von millis() bin ich bisher nur auf Beispiele gestoßen bei denen ein Ereignis alle paar Sekunden 1 mal ausgeführt wird aber nicht für eine definierte Zeit.

Hallo,

du hast Bsp. gefunden, dass ist gut. Hast du diese auch gelesen und versucht zu verstehen? millis ist nichts weiter wie deine ewig laufende Armbanduhr. Mit dieser ermittelst du tagtäglich eher unbewusst Differenzzeiten. Genau das machste jetzt mit millis. Bsp. aus der Praxis bezogen auf millis.
Theseus erklärt millis()

Die übliche Logik

if (ms - last_ms >= interval)
{
    last_ms = ms;
    // mach hier sinnvolles
}

für aller X ms musste nur anpassen. Wenn gewünschte Differenzzeit noch nicht vorbei mache ...

xanderv:
Für jeden Verbesserungsvorschlag bin ich sehr dankbar.

Wenn du dann Sattelfester bist, kannste dich über struct informieren. Damit kannst du die Eigenschaften deiner Motoren zusammenfassen und damit den Code übersichtlicher gestalten was am Ende Vorteile bringt. Machste wenn du mit millis alles im Griff hast. :wink:

Danke für die Hinweise,
das entfernen der Leerzeichen etc. macht es wirklich wesentlich übersichtlicher.

Mit Code auslagern meinst du über #include?
Das schaue ich mir heute Mittag oder Abend nochmal an.

Ich nutze einen Arduino Nano, verstehe aber nicht genau was du mit A6 und A7 meinst.
Der Vibrationsmotoren die über Lichtschranke 4 gestartet werden nicht über ein Poti gesteuert sondern sollen auf 100% laufen.

Das mit den millis() an sich habe ich schon verstanden, nur an der Umsetzung hängt es manchmal.
In Programmiersprache Denken liegt mir noch nicht so sehr.

Den Code habe ich jetzt abgeändert, Lichtschranke 3 und 4 werden immer nur kurz unterbrochen und sollen bei Unterbrechung dafür sorgen das der Motor für 2 bzw. 5 Sekunden laufen.

Ich habe es jetzt versucht das nach dem Durchlaufen der Lichtschranke die Zeit genommen wird
und im Anschluss mit der aktuellen verglichen wird.
Solange die Differenz unter 2000 bzw 5000ms liegt wird der Code ausgeführt.

Jedenfalls ist so der Gedankengang.

Würde der Code das was ich denke auch umsetzen?
Hier noch einmal der Code nur von der Steuerung von Motor 3 und dem Vibrationsmotor.
initialisiert habe ich die beiden lastMillis über unsigned long.

Und vielen Dank für die Hilfe.

 // Motor 3
   if (LR3 > 400) {
     lastMillisMotor3 = millis();
   }
   if (millis() - lastMillisMotor3 <= 5000) {
     // Motor 3 vorwärts
     digitalWrite(in5, HIGH);
     digitalWrite(in6, LOW);
     // Poti auslesen
     MotorSpeed3 = analogRead(SpeedControl3);
     // Umwandeln für PWM
     MotorSpeed3 = map(MotorSpeed3, 0, 1023, 0, 255);
     // Minimalgeschwindigkeit um Motorsurren zu vermeiden
     if (MotorSpeed3 < 20)MotorSpeed3 = 0;
     // Geschwindigkeit einstellen
     analogWrite(enC, MotorSpeed3);
   } else {
     // Motor ausschalten wenn LR3 unterbrochen ist
     MotorSpeed3 = 0;
     analogWrite(enC, MotorSpeed3);
   }

   // Vibrationsmotor
   if (LR4 > 400) {
     lastMillisVibration = millis();
     }
  if (millis() - lastMillisVibration <= 2000) {
     // Vibrationsmotor an
     digitalWrite(in7, HIGH);
     digitalWrite(in8, LOW);
     MotorSpeedVibration = 255;
     // Geschwindigkeit einstellen
     analogWrite(enD, MotorSpeedVibration);
   } else {
     MotorSpeedVibration = 0;
     analogWrite(enD, MotorSpeedVibration);
   }

Hallo,

A6 und A7 sind beim Arduino Nano reine analoge Eingänge. Die kannst du für Potis einlesen etc. verwenden und hast damit andere digitale Pins frei für andere Zwecke. Ich denke so meinte das postmaster.

Vielleicht kannst du deine vielen Leds auch nur neu gruppieren (am Arduino zuweisen) und damit einfacher kleine Funktionen schreiben die gezielt diese Led Gruppen, also eine Lampe ansprechen bzw. manipulieren. Wenn du soweit bist kannste dich auch über struct informieren. Alles Schritt für Schritt.

Hi

Er meinte auch, daß die Pins beim UNO gar nicht zur Verfügung stehen.
Da Es der gleiche Chip ist, wird's die Hardware wohl intern geben - nur hast Du Nichts davon (... vll. als Seed fur den Zufallsgenerator?? ... Zumindest schlickert der Wert für ADC6 am Uno mit Beispielsketch (irgendwas mit 6x ADC auf OLED) zwischen 650 und 750 ...)

Der Nano bietet diese zwei Pins.
Könnte mir vorstellen, daß der Uno anfangs aus einem DIP entwickelt wurde - Der hat die zwei Pins auch nicht rausgeführt - einfach kein Pin mehr frei gewesen.
Die SMD-Variante hat Das wohl, aber der Uno war halt 'schon fertig'.

... hätte noch einen Uno mit DIP-Chip ... was Der zu dem ADC-Sketch schwätzt?