Elegoo Smart Carv V3 - IR Steuerung

Halli hallo,

bei uns wurde ein Projekt für den Tag der offenen Tür gestartet mit dem oben genannten Smart Car V3.
An sich läuft das was wir vorführen möchten auch.

Allerdings wäre es schön alle 3 Programme über die Infrarotfernbedienung aufrufen bzw Steuern zu können.

Die Programme wären Einmal das einfache Fahren + Erkennung und Vermeidung von Hindernissen, Steuern über die Richtungstasten der Fernbedienung und Linetracking mit Hinderniserkennung.


#include <IRremote.h> //Bibliothek für IR Befehle und Codes
#include <Servo.h>    //Biblothek für das Steuern des Sensorservomotors

//Definieren der Pins für die Motoren
#define ENA 5         // Linke Räder
#define ENB 6         // Rechte Räder
#define IN1 7         // Links vorwärts drehen
#define IN2 8         // Links rückwärts drehen
#define IN3 9         // Rechts rückwärts drehen
#define IN4 11        // Rechts vorwärts drehen 
#define carSpeed 225  // Umlaufgeschwindigkeit der Motoren Wert v. 0 bis 255

//Definieren der Infrarotfernbedienung ´
#define RECV_PIN  12      // Den Pin für den Infrarotempfänger festlegen
IRrecv irrecv(RECV_PIN);  // Den Pin in der Bibliothek definieren
decode_results results;   // Den empfangenen Code dekodieren
unsigned long val;        // Benötigt für Wertübergabe  
unsigned long preMillis;  // 

// Definieren der Richtungstasten auf der Fernbedinung 
#define F 16736925  // Vorwärts
#define B 16754775  // Rückwärts
#define L 16720605  // Links
#define R 16761405  // Rechts
#define S 16712445  // OK-Taste
#define Eins 16738455  // Eins 
#define Zwei 16750695  
#define Drei   16756815
#define Vier   16724175
#define Sechs  167430450
#define Sieben 16716015
#define Acht   16726215

#define UNKNOWN_F 5316027     // Vorwärts
#define UNKNOWN_B 2747854299  // Rückwärts
#define UNKNOWN_L 1386468383  // Links
#define UNKNOWN_R 553536955   // Rechts
#define UNKNOWN_S 3622325019  // OK-Taste


// Ultraschall Sensor 
int Echo = A4;    // Pin für den Ultraschallempfänger
int Trig = A5;    // Pin für den Ultraschallsender
int pos = 90;     // Startposition des Servosmotors auf dem der Sensor sitzt
int distance = 0; // Ausgangsdistanzwert
Servo myservo;    // definieren des Servomotors 

//Lintracking 
#define LT_R !digitalRead(10) //Rechter Sensor
#define LT_M !digitalRead(4)  //Mittlerer Sensor
#define LT_L !digitalRead(2)  //Linker Sensor 

// LED
#define LED 13      //Pin an dem die LED angeschlossen ist 
bool state = LOW ;  //Ausgangszustand der LED LOW=aus - HIGH=an


//Im Setup wird festgelegt ob ein Pin als In- oder Output arbeitet 
void setup() {
  pinMode(Echo, INPUT);    //Empfangen Ultraschall
  pinMode(Trig, OUTPUT);   //Senden Ultraschall
  pinMode(LED,OUTPUT);     //LED
  Serial.begin(9600);
  pinMode(IN1,OUTPUT);     //Motoren 
  pinMode(IN2,OUTPUT);     
  pinMode(IN3,OUTPUT);     
  pinMode(IN4,OUTPUT);     
  pinMode(ENA,OUTPUT);     
  pinMode(ENB,OUTPUT);     
  pinMode(LT_R,INPUT);     //Lintrack
  pinMode(LT_M,INPUT);     
  pinMode(LT_L,INPUT);     
  myservo.attach(3);       //Servormotor
  irrecv.enableIRIn();     //Infrarotempfänger 
}

/*Im Anschluss die Funktionen für das Fahren

Vorwärts : Motoren AN - Links und Rechts vorwärts
Rückwärts : Motoren AN - Links und Rechts rückwärts 
Links : Motoren AN - Links rückwärts - Rechts vorwärts
Rechts : Motoren AN - Links vorwärts - Rechts rückwärts
Stop : Motoren AUS*/
void forward(){ 
    digitalWrite(ENA,carSpeed);
    digitalWrite(ENB,carSpeed);
    digitalWrite(IN1,HIGH);
    digitalWrite(IN2,LOW);
    digitalWrite(IN3,LOW);
    digitalWrite(IN4,HIGH);
}

void back(){
    digitalWrite(ENA,carSpeed);
    digitalWrite(ENB,carSpeed);
    digitalWrite(IN1,LOW);
    digitalWrite(IN2,HIGH);
    digitalWrite(IN3,HIGH);
    digitalWrite(IN4,LOW);
}

void left(){
    analogWrite(ENA,carSpeed);
    analogWrite(ENB,carSpeed);
    digitalWrite(IN1,LOW);
    digitalWrite(IN2,HIGH);
    digitalWrite(IN3,LOW);
    digitalWrite(IN4,HIGH); 
}

void right(){
  analogWrite(ENA,carSpeed);
  analogWrite(ENB,carSpeed);
  digitalWrite(IN1,HIGH);
  digitalWrite(IN2,LOW);
  digitalWrite(IN3,HIGH);
  digitalWrite(IN4,LOW);
}

void stop(){
  digitalWrite(ENA, LOW);
  digitalWrite(ENB, LOW);  
}

//LED 
void led_switch(){
    state = !state;          
    digitalWrite(LED, state);
 }
 
//Distanztest
int distance_test(){
  digitalWrite(Trig,LOW);   //Sender aus
  delayMicroseconds(2);     // 2µs Pause
  digitalWrite(Trig,HIGH);  //Sender an
  delayMicroseconds(20);    // 20µs senden
  digitalWrite(Trig,LOW);   //Sender aus
  float Fdistance = pulseIn(Echo, HIGH);  //Wert für die Distanz 
  Fdistance = Fdistance/58; //Wert in cm
  return (int)Fdistance;    //Rückgabe des Wertes für andere Funktionen
}

/* Linetracking
Wenn der Mittlere Sensor ein Signal sendet UND die gemessene Distanz 
kleiner ist als 15[cm] soll geradeaus gefahren werden.
Wenn der rechte oder linke Sensor ein Signalsendet wird nach Rechts/Links gedreht 
bis kein Signal mehr gesendet wird
Wenn die Diestanz kleiner wird als 15 [cm] wird angehalten und
nach Rechts gedreht für 100ms */ 
void linetrack(){
  myservo.write(90);    // Servo inkl. Ultraschallsensor nach vorn ausrichten
  distance=distance_test();
  if(val!=UNKNOWN_S){
      if(LT_M&&(distance>15)){  
        forward();
      }
      else if(LT_R&&(distance>15)) { 
        right();
        while(LT_R&&(distance>15));                             
      }   
      else if(LT_L&&(distance>15)) {
        left();
        while(LT_L&&(distance>15));  
      }
      else if(distance<15){
        led_switch();
        stop();
        delay(50);
        right();
        delay(100);
        led_switch();
      }
  }
  else{
     return;
  }
}

void drive(){

  do{
    led_switch();
    delay(500);
      if(val==S){
    distance=1;
  }
  }while(distance==1);
}


void loop() {
  distance=distance_test();                   //Den Wert für die Distzan aus der Funktion holen 
  if (irrecv.decode(&results)){               //Wenn der Sensor ein Signal empfängt das den definierten Werten entspricht
    preMillis = millis();                     
    val = results.value;                      //Der Wert für die gedrückte Taste 
    irrecv.resume();
    switch(val){                              //
        case F: 
        case UNKNOWN_F: forward(); break;
        case B: 
        case UNKNOWN_B: back(); break;
        case L: 
        case UNKNOWN_L: left(); break;
        case R: 
        case UNKNOWN_R: right();break;
        case Eins : linetrack(); break;
        case Zwei : drive(); break; 
        default: break;
        }
  }
   else if(distance<=20){
         stop();
         delay(100);
         right();
         delay(720);
         stop();
         
   }
   else if(millis() - preMillis > 500){
      stop();
      preMillis = millis();     
   }
}

Nicht der schönste Code ich weiß :sweat_smile:

Was ich gerne erreichen möchte ist folgendes : Über die Tasten 1,2 und 3 werden die Programme aufgerufen und laufen so lang bis sie mit der OK-Taste beendet werden.

Zum Beispiel ich Fahre das Auto mit der IR-Fernbedienung bis zum bereich für das Linetracking und dann wird das Programm gestartet über Taste 2.

Und schon einmal Danke :slight_smile:

Gibt es dazu auch eine Frage oder war es das ?
Und was ist ein Elegoo Smart Car V3 ?

Ein Hyperlink zum Teil (keine URL) wäre sehr nützlich.

Hi

Das:while(LT_R&&(distance>15)); wird erfolgreich verhindern, daß Deine Sub-Funktionen schnellst möglich verlassen werden.
Du musst jede Deiner möglichen Funktionalitäten blockadefrei schreiben!
Jetzt, Du wählst fest eine der Funktionen aus, kommst Du in diese eine Funktion rein und bleibst dort drin, bis Jemand Reset drückt.
Bzw. akut scheint mir, daß Du den Fernsteuer-Modus mit aktiver Gegenfahr-Vermeidung aktiv hast.

Du brauchst Das so, daß in der loop() in einem switch die gewünschte Funktionalität aufgerufen wird.
Da hast Du dann die Kontrolle, diese Auswahl - z.B. mittels IR-Fernbedienung, anzupassen.
Dazu musst Du aber aus ALLEN Funktionalitäten direkt wieder raus springen.
die loop() wird eine State-Maschine - der Status ist hier 'Programm' - genau genommen, das Programm, Das Du ablaufen lassen willst.

Die Fernsteuerungs-Funktion wird ebenfalls zu einer State-Maschine.
Hier musst Du 'schauen', was der Fahrer wünscht und Dir diesen Wunsch 'merken'.
Wenn Er VORWÄRTS will, startest Du das Vorwärtsfahren.
Gleiches für die anderen Fahrer-Wünsche :wink:
Hier schaust Du aber auch, ob 'irgend was' im Weg ist und stoppst ggf. das Fahrzeug - also ignorierst den Willen des Fahrer, wenn's das Leben des Fahrzeug kosten würde.

Du ahnst Es - Linienfolger und andere Funktionalitäten müssen ebenfalls eigenständige State-Maschinen werden.

Jede der Funktionen muß schnellst möglich durchlaufen werden - also nicht stundenlang via while drauf warten, daß Da irgendwo ein Hindernis auftaucht.

While und delay sind Gift für einen schnellen Durchlauf.

Dein jetziger Code 'tut' - ich würde mir an Deiner Stelle eine Art FailSafe erstellen - Funktionsauswahl per DIP-Schalter - dann reicht ein Umstellen des DIP-Schalter und ein Reset, damit Du zumindest fest in das richtige Programm kommst, wie Es jetzt bereits vorhanden ist.

Das 'auf Schön trimmen' - also programmtechnisch - kannst Du dazu parallel angehen - immer mit dem Wissen, daß 'der Kram bereits so funktioniert' - wenn Du Es aber besser hinbekommst, daß Es 'noch besser' funktionieren wird.

MfG