Ein Problem mit dem HC-SR04 Ultraschallsensor und der korrekten Programmierung

Hallo zusammen,
Ich baue einen kleinen Roboter für einen Schul-Wettbewerb. Das Ziel des Wettbewerbes ist, dass man Ping-Pong-Bälle aufsammelt in einem Feld von 2.5 m auf 2.5 m. Das Aufsammeln ist kein Problem und wird auch nicht vom Roboter gesteuert. Das Problem ist das Richtige Ansteuern der Motoren.
Ich habe die folgenden Materialien benutzt:
Arduino Uno
Arduino Motor Shield 3r
HC-SR04 Ultraschallsensor
2 Brushless Motoren mit je einem esc und je einem Akku

Informationen zum Code:
Der Roboter initialisiert zuerst alles, und dann startet er mit einer Speed-Runde: Das bedeutet, dass er 4 mal eine Kurve machen sollte, und dann in die Mitte des Feldes fahren sollte.
Dann sollte er mit einem Slalom beginnen:
Er fährt zur gegenüberliegenden Wand und dreht sich und fährt auf der nächsten Linie wieder zurück.
Das alles sollte er mit einem unbeweglichem Ultraschallsensor vollbringen.

Ich habe jetzt jedoch 3 Probleme:

  1. Ich kann die Kurven nicht zählen, da er mehrmals in einer Kurve messen wird und die Motoren mehrmals gleich ansteuert, wodurch ich keine Variabel einsetzen kann.
  2. Der Ultraschallsensor reagiert nicht
  3. WIe kann ich die Kurven so gestalten, damit er nach einer Kurve wieder geradeaus fährt?

Hier ist mein Code.
Ich weiss, dass er total verwirrend ist, aber bitte schaut ihn euch mal an, wahrscheinlich ist es einfach ein Anfängerfehler.

#include <Servo.h>


// Definiere Servos
Servo rechts; 
Servo links;      

// Definiere Pins
const int pingPin = 10;
const int inPin = 7;

// Initialisiere Variabeln
long duration = 100;
long cm; //Sensor-Wert
int gfahr = 1350; //Geschwindigkeit nach vorn
int gdrehen = 500; // Geschwindigkeit für die Drehung, falls zu nah an der Wand
int gkurve = 900; // Geschwindigkeit für das 2. Rad bei der langsamen kurve
int gzurueck = 0;
int arm = 100;
int k = 0; // k ist die Variable, die für das Zahlen der Kurve genommen wird
int h = 0; // h wird benötigt, um in die Mitte zu fahren
int a = 0; // a wird ebenfalls für den übergang von der Mitte zum Slalom benötigt

// Definiere FUNKTIONEN:  
int fahr();            
int fahrrechts();      
int drehen();
int fahrzurmitte();  // Damit fährt er nach seiner schnellen Runde durch die mitte, und fährt dann in einem Slalom-Muster über das ganze Spielfeld
int slalom(); //Der Slalom wird zum Schluss initialisiert und läuft bis zum Ende des Matches

// Setup das wird nur einmal ausgeführt:
void setup()
{
  // Kombiniere Servos mit den zugehörenden PINS
  rechts.attach( 3 );    // hier werden die PINS den servos zugewiesen
  links.attach( 11 );

  
  // Definiere inpin und pingpin für den Sensor
  pinMode( inPin, INPUT );
  pinMode( pingPin, OUTPUT );
  digitalWrite( pingPin, LOW );

}

// Programm main
void loop()
{
  digitalWrite(pingPin, HIGH); // Hier misst der Sensor den Abstand zur vorderen Wand
  delayMicroseconds(10);
  digitalWrite(pingPin, LOW);
  duration = pulseIn(inPin, HIGH);
  cm = microsecondsToCentimeters(duration); //und gibt sie als die Variabel cm heraus
  
  if (cm >=150) // Hier wird der Abstand so definiert, damit sich der Roboter vollständig dreht und nicht nur immer an die Wand schaut
  {
    fahr();  
  }
  
  else if (cm < 60 && cm > 35)
  {
    fahrrechts();
    k ++;
  }
  
  else if (cm <= 35)
  {
    drehen();
  }
  
  if( k == 4 ) // wenn dieses k jetzt auf eine gewisse Zahl aufgezählt hat, dann hat der Roboter die speed-Runde abgeschlossen und macht die langsameren Runden
  {
    fahrzurmitte();
    if ( a > 0)
    {
      slalom();
    }
  }

}

int microsecondsToCentimeters(int microseconds)
{
  return microseconds / 60;
}


int fahr() 
{
  rechts.write( 50);  //hier wird der Motor für die Geradeaus-Phase gesetzt
  delayMicroseconds(gfahr);
  rechts.write(LOW);
  links.write(50);
  delayMicroseconds(gfahr);
  links.write(LOW);
  delay(20);
}

int fahrrechts()
{
  rechts.write(50);
  delayMicroseconds(gfahr);
  rechts.write(LOW);
  links.write(50);
  delayMicroseconds(gkurve);
  links.write(LOW);
  delay(20);
}

int drehen()
{
  rechts.write(50);
  delayMicroseconds(gdrehen);
  rechts.write(LOW);
  links.write(50);
  delayMicroseconds(gzurueck);
  links.write(LOW);
  delay(20);
}

int fahrzurmitte()
{
  if ( cm < 200)    // wenn der Roboter in der Mitte ist, dann dreht er sich bis er  (fast) zur Mitte schaut
{  
      rechts.write(50);
      delayMicroseconds(gdrehen);
      rechts.write(LOW);
      links.write(50);
      delayMicroseconds(gzurueck);
      links.write(LOW);
      delay(20);
  }
  
  else if ( cm > 200)    // sobald er soweit ist, fährt er durch die Mitte hindurch bis zur anderen Wand
  {
    fahr();
    h ++; // dann wird h heraufgezählt
  }
  
  if (h > 0 && cm >20)
  {
    fahr();
  }
  else if (cm <= 20 && a == 0)  // mit dieser Programmierung fährt der Roboter zur anderen Wand und kehrt dort ab
  {
    drehen();
    if (cm >= 50)
    {
      a ++; // a wir höher als 0 gesetzt
    }
  }
  
}


int slalom()
{
  if (cm >= 20)
  {
    fahr;
  }
  
  else if ( cm <=20)
  {
    drehen();
    delay(500);
  }
}

Wenn ich mal die Bilder anschaue: Bist Du sicher daß der Entfernungssensor nicht die Luftschraube sieht?

Du weißt schon daß
duration = pulseIn(inPin, HIGH);
den sketch blockiert so wie delay()?

Ohne messung der Drehungen der motore oder des Zurückgelegten weges kannst Du keine ordentlichen Kurven fahren eil Du nicht weißt welchen Winkel Du gefahren bist.

Grüße Uwe

uwefed:
Wenn ich mal die Bilder anschaue: Bist Du sicher daß der Entfernungssensor nicht die Luftschraube sieht?

Sehr gut möglich. Der Schall tritt kegelförming aus und die Dinger haben einen ziemlich großen Öffnungswinkel.

Hallo Uwe, danke für deine schnelle Antwort!
Ja, das mit dem Rotor ist kein Problem, das haben wir gerade getestet.
Dauert dieser duration = pulseIn(inPin, HIGH); nicht nur wenige mikrosekunden?
Das mit der Kurve habe ich mir überlegt, dass ich einfach einen delay() experimentell mache, bis sich der Roboter 90° gedreht hat... aber das mit dem Sensor funktioniert nicht wirklich...

Ich bin mir ziemlich sicher, dass die Luftschraube vom Sensor erfasst wird.
Spiele selber grad mit so nem Sensor bisschen rum nebenbei..die haben nen recht weiten Winkel, indem sie alles wahrnehmen.

Ist aber einfach rauszufinden: das Ding mal auf die serielle Konsole werfen, und (im Stand) nachgucken, was er macht.
Auch mal das Rotorblatt richtung Sensor drehen-ich bin mir ziemlich sicher, das wird erfasst. Spätestens, wenn die Sache noch vibriert dann im Betrieb...
Übrigens ist die Lösung, das Ding starr zu montieren, kaum zu gebrauchen: er kann damit nicht erkennen, wo sich ein Hindernis befindet- spätestens wenn du in nem Winkel <90 Grad auf ne Wand zufährst, ist das ein Problem.
Also entweder zweie einbauen (und die so 45 grad seitlich gucken lassen (und ganz wichtig: nie zugleich triggern bzw. abfragen!) oder einen-schwenkbar.

Hallo,

hier ist mal ein Beispiel-Sketch, der mit dem HC-SR04 einwandfrei funktioniert. Pass mal die Pins im Sketch an oder schließe den Sensor an die im Sketch verwendeten Pins an und schau das Ergebnis auf dem seriellen Monitor an.

/*
  Arduino <-> Ultraschallsensor HC SR04
  -------------------------------------
  
  Erzeugt einen Ultraschallimpuls und misst die Zeit,
  bis das Echo aufgefangen wird. Aus der Laufzeit des
  Schallimpulses wird die Entfernung zum reflektierenden
  Objekt berechnet.

  Entnommen aus: http://www.elektronik-bastelkeller.de/wordpress/?p=504
 
*/

// Trig ist an Digital-Pin 7 angeschlossen
const byte TRIGGER = 7;

// und Echo an Digital-Pin 8
const byte ECHO = 8;


/************************************************************
*
* void setup()
* ------------
*
* Wird einmal beim Programmstart durchlaufen
*
*************************************************************/
void setup() {                
  Serial.begin(9600);   
  
  pinMode(TRIGGER, OUTPUT);
  pinMode(ECHO, INPUT);
  
  // Damit später durch HIGH-setzen von TRIGGER ein Impuls
  // ausgelöst werden kann, wird TRIGGER hier LOW gesetzt.
  digitalWrite(TRIGGER, LOW);
  
  // TRIGGER muss mindestens 2µs LOW sein
  delayMicroseconds(2);

  // Für Leonardo
  while (!Serial)
    ;  
}


/************************************************************
*
* void loop()
* ------------
*
* Wird immer wieder durchlaufen
*
*************************************************************/
void loop() {
  long laufzeit;
  double entfernung;
  
  while(true) {
    // Einen Impuls auslösen
    digitalWrite(TRIGGER, HIGH);
    delayMicroseconds(5);
    digitalWrite(TRIGGER, LOW);
  
    // Messen, wann der reflektierte Impuls zurückkommt
    laufzeit = pulseIn(ECHO, HIGH);
  
    // Pro Meter benötigt der Schall in Luft ca. 2,9 ms
    // Weg geht hin und zurück, also mal 2
    entfernung = (double) laufzeit / (2.9 * 2.0);
  
    Serial.print("Entfernung zum Objekt: ");
    Serial.print(entfernung);
    Serial.println(" mm");
  
    delay(100);
  }
}

Wenn auf dem Monitor nichts sinnvolles angezeigt wird, kannst Du ziemlich sicher sein, dass der Sensor die Luftschraube erfasst und deshalb "spinnt".

Gruß,
Ralf