Autonomes Auto mit Servo Motoren

Hey, haben derzeit ein Projekt in der Schule, in welchem wir ein Auto bauen und programmieren sollen. Es soll vorwärts und rückwärts fahren können. Wenn ein Gegenstand vorne im Weg steht soll es rückwärts fahren und vice versa. Es wird mit einer 9V batterie betrieben und die Motoren sind an einer H- Brücke angeschlossen. Der Zeit ist das Problem, dass es "falsche" Messungen gibt und der Motor zu spät oder garnicht aufhört zu rotieren. Würde mich sehr über Verbessurungsvorschläge und Tipps freuen. Hier der Code:

//Ultraschallsensor 1
int trigger1=13; 
int echo1=12; 
long dauer1=0;
long entfernung1=0; 

//Ultraschallsensor 2 
int trigger2 = 11;
int echo2 = 4;
long dauer2=0;
long entfernung2=0;

//Ultraschallsensor 3
int trigger3 = 1;
int echo3 = 2;
long dauer3=0;
long entfernung3=0;

// Gleichstrommotor 1                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          

int GSM1 = 10;
int in1 = 9;
int in2 = 8;

// Gleichstrommotor 2

int GSM2 = 5;
int in3 = 7;
int in4 = 6;

void setup()
{
  Serial.begin(9600);
  pinMode(GSM1, OUTPUT);    
  pinMode(GSM2, OUTPUT);
  pinMode(in1, OUTPUT);
  pinMode(in2, OUTPUT);
  pinMode(in3, OUTPUT);
  pinMode(in4, OUTPUT);
  pinMode(trigger1, OUTPUT); 
  pinMode(echo1, INPUT);
  pinMode(trigger2, OUTPUT); 
  pinMode(echo2, INPUT);
  pinMode(trigger3, OUTPUT); 
  pinMode(echo3, INPUT); 
}
void loop()
{
  messung1();
  messung2();
  messung3();
  vfahren();
  ruefahren();
  }
void vfahren()
{
 if( entfernung1 > 70) { 
  digitalWrite(in1, LOW);  // Motor 1 beginnt zu rotieren
  digitalWrite(in2, HIGH);

  analogWrite(GSM1, 200);   // Motor 1 soll mit der Geschwindigkeit "200" (max. 255) rotieren 

  digitalWrite(in3, HIGH);  // Motor 2 beginnt zu rotieren
  digitalWrite(in4, LOW);

  analogWrite(GSM2, 210);   // Motor 2 soll ebenfalls mit der Geschwindigkeit "200"(max.255) rotieren 
  delay(1000);
 }
 else{
  digitalWrite(in1, HIGH);  // Motor 1 beginnt zu rotieren
  digitalWrite(in2, LOW);
  analogWrite(GSM1, 200);   // Motor 1 soll mit der Geschwindigkeit "200" (max. 255) rotieren 
  digitalWrite(in3, LOW);  // Motor 2 beginnt zu rotieren
  digitalWrite(in4, HIGH);
  analogWrite(GSM2, 210);   // Motor 2 soll ebenfalls mit der Geschwindigkeit "200" (max. 255) rotieren
    delay(1000);

}
}
void ruefahren()
{
  if (entfernung2 > 70) {
    digitalWrite(in1, HIGH);  // Motor 1 beginnt zu rotieren
    digitalWrite(in2, LOW);
    analogWrite(GSM1, 200);   // Motor 1 soll mit der Geschwindigkeit "200" (max. 255) rotieren 
    digitalWrite(in3, LOW);  // Motor 2 beginnt zu rotieren
    digitalWrite(in4, HIGH);
    analogWrite(GSM2, 210);   // Motor 2 soll ebenfalls mit der Geschwindigkeit "200" (max. 255) rotieren
    delay(1000);

  }
    else {
     digitalWrite(in1, LOW);  // Motor 1 beginnt zu rotieren
     digitalWrite(in2, HIGH);
     analogWrite(GSM1, 200);   // Motor 1 soll mit der Geschwindigkeit "200" (max. 255) rotieren 
     digitalWrite(in3, HIGH);  // Motor 2 beginnt zu rotieren
     digitalWrite(in4, LOW);
     analogWrite(GSM2, 210);   // Motor 2 soll ebenfalls mit der Geschwindigkeit "200" (max. 255) rotieren 
     delay(1000);
  
  }
}


void messung1()
{

    
  //Sender kurz ausschalten um Störungen des Signal zu vermeiden
  digitalWrite(trigger1, LOW);
  delay(5);

  // Signal für 10 Micrsekunden senden, danach wieder ausschalten
  digitalWrite(trigger1, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigger1, LOW);
  // pulseIn -> Zeit messen, bis das Signal zurückkommt
  dauer1 = pulseIn(echo1, HIGH);

  // Entfernung in cm berechnen
  // Zeit/2 -> nur eine Strecke
  entfernung1 = (dauer1 / 2) * 0.03432;
  delay(100);

  // nur Entfernungen < 1000 anzeigen
  if (entfernung1 < 1000) 
  {
    // Messdaten anzeigen
    Serial.print("Vorwärts in cm: ");
    Serial.println(entfernung1 );
  }
}
void messung2()
{
  
  //Sender kurz ausschalten um Störungen des Signal zu vermeiden
  digitalWrite(trigger2, LOW);
  delay(5);

  // Signal für 10 Micrsekunden senden, danach wieder ausschalten
  digitalWrite(trigger2, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigger2, LOW);

  // pulseIn -> Zeit messen, bis das Signal zurückkommt
  dauer2 = pulseIn(echo2, HIGH);

  // Entfernung in cm berechnen
  // Zeit/2 -> nur eine Strecke
  entfernung2 = (dauer2 / 2) * 0.03432;
  delay(100);

  // nur Entfernungen < 1000 anzeigen
  if (entfernung2 < 1000) 
  {
    // Messdaten anzeigen
    Serial.print("Hinten in cm: ");
    Serial.println(entfernung2);
  }
}

void messung3()
{

  //Sender kurz ausschalten um Störungen des Signal zu vermeiden
  digitalWrite(trigger3, LOW);
  delay(5);

  // Signal für 10 Micrsekunden senden, danach wieder ausschalten
  digitalWrite(trigger3, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigger3, LOW);

  // pulseIn -> Zeit messen, bis das Signal zurückkommt
  dauer3 = pulseIn(echo3, HIGH);

  // Entfernung in cm berechnen
  // Zeit/2 -> nur eine Strecke
  entfernung3 = (dauer3 / 2) * 0.03432;
  delay(10);

  // nur Entfernungen < 1000 anzeigen
  if (entfernung3 < 1000) 
  {
    // Messdaten anzeigen
    Serial.print("Seitlich in cm: ");
    Serial.println(entfernung3);
  }
}

Das Grundproblem sind deine delays. Während dieser Zeit kann der uC nichts machen. Du brauchst (mehrere) Statemaschienen und die Steuerung in den Statemaschienen mit millis(). Hier im Forum gibt es hunderte Beispiele.

Habe ich gerade ein Déjà-vu oder wie man schreibt.

Zu der Frage habe ich doch von einiger Zeit schon was geschrieben.

Gruß

Pucki

Richtig.
"Statemachine" , "Zustandsautomat" o.ä. mögen abschreckende Begriffe sein, ist aber im Prinzip einfach. Ein loop-Durchlauf ist nicht der Ablauf eines Programms, sondern die Beschreibung des aktuellen Zustands und was im Moment zu tun ist, wenn dieser sich ändert.

Falsche Kommentare sind für den Controller kein Problem, für das menschliche Verständnis allerdings schon. Ein guter Kommentar sagt nicht, was man macht (das steht schon in der Anweisung selbst), sondern warum.

Funktionen sind gut. Wenn man eine Funktion durch Parameter anpassbar und wiederverwertbar macht, ist sie noch besser. Und eine Funktion die messung heißt, liefert optimalerweise das Messergebnis zurück.

Dann solltest du uns auch den kompletten Sketch posten.

Wirklich? Motoren?

Siehe "Obstacle Avoiding".

mach uns mal ein schematische Darstellung wie deine Sensoren verbaut sind. Wohin zeigen Ultraschallsensor 1, 2 und 3?

Hat dir dein Lehrer ausdrücklich empfohlen Variablen zu nummerieren oder hat er darauf hingewiesen, dass Variablen sprechend benannt werden sollen?

Gibt es irgendwelche Einschränkungen von C++ die du nicht nutzen darfst? Arrays wären ganz wichtig, Strukturen sowieso und Klassen wären naheliegend!

Hallo,
also Du hast zwei Fälle vor und zurück und wenn auf beiden Seiten ein Hindernis ist soll er stehen bleiben.
ich denke Du sollest dich zunächst mal um die Messung kümmern. Eigentlich kannst Du doch auf die delay(1000) komplett verzichten. Es sollte ja so schnell wie möglich auf ein Hindernis reagiert werden.

Aber mach erst mal nur die Messung ohne die Antriebe , also mit einem stehenden Fahrzeug. Du kannst ja mit einem Stück Pappe die Entfernung simulieren. Lass Dir dazu die drei Messergebnisse auf dem Monitor Anzeigen. Als nächsten Schritt legst Du dann das Fahrzeug erst mal so hin das die Räder in der Luft sind. Dann kannst Du die Antriebe kontrollieren ohne das dir die Karre ständig abhaut. Wenn Du dann der Meinung bist das es wie gewünscht klappt dann lass das Ding erst mal langsam fahren, das sollte mit 50% auch möglich sein.

Hier ist einer:

(entfernung1 < 1000)

"magic numbers" wie die 1000 sind böse. Benannte Konstanten verwenden!

... und ich bin ganz bei @michael_x (#4):
Funktionen und Methoden dürfen Parameter und Rückgabewerte haben.

Statt

void messung1() ...
void messung2() ...
void messung3() ...

mit exakt dem gleichen Inhalt, wäre

long messung(const byte trigger, const byte echo) 
{
  ...
  return entfernung;
}

und davon dann drei Aufrufe

entfernung1 = messung(trigger1, echo1);
entfernung2 = messung(trigger2, echo2);
entfernung3 = messung(trigger3, echo3);

vielleicht eine Überlegung wert.

Dann solltest Du Dich mit @cultist zusammen tun.

Mindestens solltest Du aber die Funktionen der Pins der Controller kennen.

Das wird nichts:

....

also puzzle ich mal ein wenig den Sketch.
Ich nehme mal an, daß der Abstand nach vorne und nach hinten größer als 70 ist, also das das Fahrzeug mutterselenallein in der Mitte eines Zimmers steht.

void loop()
{
  ...
  vfahren();
  ruefahren();
  }
void vfahren()
{
 if( entfernung1 > 70) { 
  digitalWrite(in1, LOW);  // Motor 1 beginnt zu rotieren
  digitalWrite(in2, HIGH);
oid ruefahren()
{
  if (entfernung2 > 70) {
    digitalWrite(in1, HIGH);  // Motor 1 beginnt zu rotieren
    digitalWrite(in2, LOW);

Die Programmstruktur.
Abstände messen
dann fährt es nach vorne
um dann nach hinten zu fahren.

Da sin einige blockierende Delays() Nebensache.
Grüeß Uwe

Warum?

Meinst die int trigger3 = 1;

//Ultraschallsensor 3
int trigger3 = 1;
int echo3 = 2;
long dauer3=0;
long entfernung3=0;

Am

 Serial.begin(9600);

ist doch nix zu bemängeln.

Pin 0 und 1 gehören der Seriellen Schnittstelle....

Servus,
erstmal vielen Dank für die Antwort. Habe jetzt mal versucht eine State Machine enzubauen. Bitte verzeih mir wenn diese nicht "perfekt" ist, bin ja nur Schüler. Hier ist der neue Code:

// Pins für Motoren
const int ENA = 10; 
const int IN1 = 9; 
const int IN2 = 8;
const int IN4 = 7;
const int IN3 = 6; 
const int ENB = 5;

// Pins für die Ultraschallsensoren 
const int trigPin1 = 13;
const int echoPin1 = 12;
const int trigPin2 = 11;
const int echoPin2 = 4;
const int trigPin3 = 3;
const int echoPin3 = 2;

// Zustände
enum State { VORWAERTS, RUECKWAERTS };
State zustand = VORWAERTS;

void setup() {
  // Motor-Pins als Ausgang
  pinMode(ENA, OUTPUT);
  pinMode(IN1, OUTPUT);
  pinMode(IN2, OUTPUT);
  pinMode(ENB, OUTPUT);
  pinMode(IN3, OUTPUT);
  pinMode(IN4, OUTPUT);

  // Ultraschallsensor
  pinMode(trigPin1, OUTPUT);
  pinMode(echoPin1, INPUT);
  pinMode(trigPin2, OUTPUT);
  pinMode(echoPin2, INPUT);
  pinMode(trigPin3, OUTPUT);
  pinMode(echoPin3, INPUT);
  

  Serial.begin(9600);
}

void loop() {
  long entfernung1 = messeAbstand(trigPin1, echoPin1);
  long entfernung2 = messeAbstand(trigPin2, echoPin2);
  long entfernung3 = messeAbstand(trigPin3, echoPin3);
  Serial.print("Vorne: "); Serial.print(entfernung1);
  Serial.print(" cm | Hinten: "); Serial.println(entfernung2);
  Serial.print(" cm | Seite: "); Serial.println(entfernung3);


  switch (zustand) {
    case VORWAERTS:
      if (entfernung1 < 20) {
        zustand = RUECKWAERTS;
        stopp();
        delay(300);
      } else {
        vorwaerts();
      }
      break;

    case RUECKWAERTS:
      if (entfernung2 < 20) {
        zustand = VORWAERTS;
        stopp();
        delay(300);
      } else {
        rueckwaerts();
      }
      break;
  }

  delay(100); 
}


//Ultraschall-Messung
long messeAbstand(int trigPin, int echoPin) {
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  long duration = pulseIn(echoPin, HIGH, 20000); // max. 20ms warten
  if (duration == 0) return 300; // falls kein Signal empfangen
  return duration * 0.034 / 2;
}


void vorwaerts() {
  digitalWrite(IN1, HIGH);
  digitalWrite(IN2, LOW);
  analogWrite(ENA, 200); // Geschwindigkeit A

  digitalWrite(IN3, HIGH);
  digitalWrite(IN4, LOW);
  analogWrite(ENB, 210); // Geschwindigkeit B
}

void rueckwaerts() {
  digitalWrite(IN1, LOW);
  digitalWrite(IN2, HIGH);
  analogWrite(ENA, 200);

  digitalWrite(IN3, LOW);
  digitalWrite(IN4, HIGH);
  analogWrite(ENB, 210);
}


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

Warum heißt entfernung1 nicht Entfernung vorne? Was macht entfernung3? Der Ansatz ist gut. Aber alle delays in den Status raus und durch weitere Staates ersetzten. In den Status dann die Weiterschaltung mit millis.

Die Abstandsmessung kostet relativ viel Zeit. Daher nur in den States die benötigt Messung machen.

Prinzipiell richtig. Allerdings wird die Entfernungsmessung gerade dann benötigt, wenn die Reaktion zeitkritisch ist, weil das Ding sich bewegt.
messeAbstand hat einen TimeOut von nur 20 ms. Das sollte auf jeden Fall schnell genug sein. Eher sollte man über das delay(100); in jedem loop Durchlauf nachdenken.

Was ist bei Fehlern in der Messung ? (Timeout heißt hier: mindestens 3m alles frei)

Im richtigen Leben sollte so ein Ding bei "Messfehler" stoppen, aber wenn das nicht von "alles frei" unterschieden werden kann?

Wenn ich dann aber auch noch 2 Sinnlose Messungen mache, ist es noch blöder