Verzögerung bei Befehlverarbeitung Bluetooth modul HC-06

Hallo und Gruß an alle in diesem Forum ,

Mein Problem stellt sich wie folgt dar:

An meinen Arduino Mega hängt ein HC-06 Bluetooth Modul
Ich kann problemlos darauf zugreifen und auch die Befehle senden. So weit so gut.

Da ich es aber mit Sensorik verbinden will sind hierzu 3 Ultraschalsensoren implementiert.
Und genau ab hier wenn ich jetzt über Bluetooth eine Befehl sende wird dieser mit ca. 5 sek. Verzögerung bearbeitet.
Also es ist ein Fahrzeug der nach vorne fahren soll die taste wird gedrückt und nach ca. 5 sek. fährt er los.
Somit ist das ganze nicht steuerbar.

Hier der Code :

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <MotorShieldR3.h>
MotorShieldR3 yellowCar;
#define pinfrontLights    7    
#define pinbackLights     4     
char command = 'S';
int velocity = 0;   
//#define CMPS10Addr  0x60 // Addresse des CMPS10 

LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address
const byte TRIGGER1 = 23;
const byte TRIGGER2 = 25;
const byte TRIGGER3 = 27;

const byte ECHO1 = 22;
const byte ECHO2 = 24;
const byte ECHO3 = 26;

void setup() 
{       
  
  Serial.begin(9600);   
  Serial1.begin(19200);  
  pinMode(pinfrontLights , OUTPUT);
  pinMode(pinbackLights , OUTPUT);
  lcd.begin(16,2);
  Wire.begin(); // Connect to I2C  

  pinMode(TRIGGER1, OUTPUT);
  pinMode(ECHO1, INPUT);
  digitalWrite(TRIGGER1, LOW);
  delayMicroseconds(2);
  pinMode(TRIGGER2, OUTPUT);
  pinMode(ECHO2, INPUT);
  digitalWrite(TRIGGER2, LOW);
  delayMicroseconds(2);
  pinMode(TRIGGER3, OUTPUT);
  pinMode(ECHO3, INPUT);
  digitalWrite(TRIGGER3, LOW);
  delayMicroseconds(2);// TRIGGER muss mindestens 2µs LOW sein


}



void loop(){
    
  long laufzeit1i, laufzeitre, laufzeitmitt;
  unsigned int entfernungli, entfernungre, entfernungmitt;
  
  while(true) {
    //Impuls Sensor 1
    digitalWrite(TRIGGER1, HIGH);
    delayMicroseconds(50);
    digitalWrite(TRIGGER1, LOW);

    // Messen
    laufzeit1i = pulseIn(ECHO1, HIGH);

    delay (10);
    entfernungli = (double) laufzeit1i / (2.9 * 2.0);
    Serial.print("Entfernung zum Objekt links: ");
    Serial.print(entfernungli);
    Serial.println(" mm");    
    
    // Impuls auslösen Sensor 2
    digitalWrite(TRIGGER2, HIGH);
    delayMicroseconds(50);
    digitalWrite(TRIGGER2, LOW);

    // Messen 2
    laufzeitre = pulseIn(ECHO2, HIGH);

    delay (10);
    entfernungre = (double) laufzeitre / (2.9 * 2.0);
    Serial.print("Entfernung zum Objekt rechts: ");
    Serial.print(entfernungre);
    Serial.println(" mm");
    
    //Impuls auslösen Sensor 3
    digitalWrite(TRIGGER3, HIGH);
    delayMicroseconds(50);
    digitalWrite(TRIGGER3, LOW);

    // Messen 3
    laufzeitmitt = pulseIn(ECHO3, HIGH);
    delay (10);
    entfernungmitt = (double) laufzeitmitt / (2.9 * 2.0);
   
    lcd.setCursor(0,0);
    lcd.print(" Objekt Mitte ");
    lcd.setCursor(0,1);
    lcd.print(entfernungmitt);
    lcd.print("mm");
  
  if(Serial1.available()){ 
    command = Serial1.read(); 
    
    switch(command){
    case 'F':  
      yellowCar.Forward_2W(velocity, velocity);
      break;
    case 'B':  
      yellowCar.Back_2W(velocity, velocity);
      break;
    case 'L':  
      yellowCar.RotateLeft_2W(velocity, velocity );
      break;
    case 'R':
      yellowCar.RotateRight_2W(velocity, velocity);  
      break;
    case 'S':  
      yellowCar.Stopped_2W();
      break; 
    case 'W':  //Font ON 
      digitalWrite(pinfrontLights, HIGH);
      break;
    case 'w':  //Font OFF
      digitalWrite(pinfrontLights, LOW);
      break;
    case 'U':  //Back ON 
      digitalWrite(pinbackLights, HIGH);
      break;
    case 'u':  //Back OFF 
      digitalWrite(pinbackLights, LOW);
      break; 
    case 'D':  //Everything OFF 
      digitalWrite(pinfrontLights, LOW);
      digitalWrite(pinbackLights, LOW);
      yellowCar.Stopped_2W();
      break;         
    default:  //Get velocity
      if(command=='q'){
        velocity = 255;  //Full velocity
        yellowCar.SetSpeedLeft_2W(velocity);
        yellowCar.SetSpeedRight_2W(velocity);
      }
      else{ 
        //Chars '0' - '9' have an integer equivalence of 48 - 57, accordingly.
        if((command >= 48) && (command <= 57)){ 
          //Subtracting 48 changes the range from 48-57 to 0-9.
          //Multiplying by 25 changes the range from 0-9 to 0-225.
          velocity = (command - 48)*25;       
          yellowCar.SetSpeedLeft_2W(velocity);
          yellowCar.SetSpeedRight_2W(velocity);
        }
      }
    }
  } 
}
}

Die Programme arbeiten einzeln dh. nur die Sensoren bzw. nur die Bluetooth Steuerung Perfekt.
Nur wenn / sobald die Sensoren im Loop eingetragen werden kommt es zu der Verzögerung.

Was mache ich Falsch ?

Hoffe Ihr könnt mir hierbei Helfen

Gruß
Chris

Zerebrator: Also es ist ein Fahrzeug der nach vorne fahren soll die taste wird gedrückt und nach ca. 5 sek. fährt er los. Somit ist das ganze nicht steuerbar.

Du verwendest den Schrott-Befehl "pulseIn(ECHO1, HIGH);".

Das pulseIn-Kommando BLOCKIERT die Programmausführung während des Einlesens für bis zu 1 Sekunde. Die 1 Sekunde würde dann fällig werden, wenn kein Echo kommt. Man kann zwar das Timeout in so einer Anwendung heruntersetzen, z.B. auf die Laufzeit, die der Schall für 6 Meter benötigt, wenn eine maximale Entfernung von 3 Metern gemessen werden soll. Aber Programmblockierung bleibt Programmblockierung.

Der pulseIn-Befehl ist für Programme mit "Multitasking", die zu jedem Zeitpunkt und unter allen Betriebsbedingungen schnell reagieren sollen, ein VÖLLIG UNGEEIGNETER Befehl beim Programmieren.

Wenn Du dennoch solche blockierenden Befehle wie pulseIn verwenden möchtest, dann ist es nur sinnvoll möglich, für die Entfernungsmessung einen eigenen Controller vorzusehen, der dann nichts anderes macht als die Entfernungsmessung, und seine Daten dann weiter an einen anderen Controller sendet.

Hallo ,

danke für die Antwort.

Welche Alternativen habe ich denn ? Wie soll der Code aussehen wie spreche bzw. auswerte ich die Sensoren ohne pulsein ?

Gibt es dafür Bsp. ? Habe gerade ne Std. im netz gesucht und festgestellt dass jeder die pulsein befehle benutzt.

Vllt. als Anmerkung die delay Funktionen habe ich gänzlich auskommentiert auch ohne Verbesserung. Der pulsein Befehl dauert ja wenige Mikro Sekunden wie setzt sich das ganze zu 5 Sek. Verzögerung ?

Gruß Chris

Zerebrator: Welche Alternativen habe ich denn ? Wie soll der Code aussehen wie spreche bzw. auswerte ich die Sensoren ohne pulsein ?

Wie der Code am besten aussehen sollte, kommt darauf an, was Dir am Programm am wichtigsten ist: - eine jederzeitige schnelle Reaktionsfähigkeit - möglichst genaue Entfernungsmesswerte vom Ultraschallsensor - was an Ressourcen des Controllers noch frei ist (z.B. Timer) - welchen Programmieraufwand Du betreiben möchtest

Zerebrator: Gibt es dafür Bsp. ? Habe gerade ne Std. im netz gesucht und festgestellt dass jeder die pulsein befehle benutzt.

Der pulseIn-Befehl kann eigentlich nur von Arduino-Programmierern verwendet werden, da es es sich um einen Befehl aus der Arduino Core-Library handelt. Sehr einfach zu verwenden, selbst von Programmieranfängern mit geringsten Programmierkenntnissen, aber ggf. mit extrem problematischen Auswirkungen auf reale Programme. Ähnlich wie der "delay"-Befehl, dessen Problematik ebenso in der Blockierung der Programmausführung liegt.

Zerebrator: Der pulsein Befehl dauert ja wenige Mikro Sekunden wie setzt sich das ganze zu 5 Sek. Verzögerung ?

Der pulseIn-Befehl so wie Du ihn verwendest, dauert: - bis zum Eintreffen des Echos ODER - eine Sekunde Je nachdem, was kürzer dauert.

Wenn kein Echo kommt, dauert der Befehl in Deinem Programm eine Sekunde bis zum Timeout.

Da Du drei Sensoren nacheinander ansteuerst, würde 3x pulseIn soviel wie 3 Sekunden delay bedeuten, falls keiner der Sensoren ein Echo zurück bekommt.

Als erstes mal könntest Du testen, ob Dein Problem in der Hauptsache durch die Verwendung von pulseIn bei ausbleibendem Echo bedingt ist oder nicht. Es gibt zwei Möglichkeiten, den Befehl zu verwenden:

pulseIn(pin, value) pulseIn(pin, value, timeout)

Da Dein Ultraschall-Entfernungsmesser nur eine Reichweite von ca. 3 Metern hat, kannst Du das Timeout eigentlich auf die Laufzeit des Schalls von 6 Metern (hin und zurück zum Objekt) begrenzen. Mit einer Schallgeschwindigkeit von 340 m/s gerechnet, braucht der Schall für 6 m eine Zeit von t= 6/340s = 0,017647 s = 17647 µs Länger brauchst Du auf ein Echo eigentlich nicht zu warten.

Also änderst Du Deine pulseIn-Aufrufe zum Testen am besten mal ab auf:

laufzeit1i = pulseIn(ECHO1, HIGH, 17647);

(und sinngemäß gleich für die anderen pulseIn-Aufrufe)

Dann dauert pulseIn maximal 0,017647 s und Du bekommst in dem Fall eine Entfernung von ca. 3m heraus, die Du dann im Programm als "Out of Range" betrachten kannst.

Verändert sich dann etwas an der lahmen Reaktion des Programms oder bleibt alles gleich?

Hi

also eigentlich will ich damit "nur" Abstand messen, klar es geht dabei auch um die Geschwindigkeit sonst fährt mir das ding ständig gegen die Wand ;-) .

Ich habe deinen Code eingesetzt doch leider hat das keine Auswirkung ich muss trotzdem ewig ( ca. 5 sek) auf die Reaktion warten....

Was kann es noch sein ?

Gruß

Chris

Zerebrator: Was kann es noch sein ?

Ein weiterer Fallstrick kann Deine Art der Serial-Befehlsverarbeitung sein.

Du verarbeitest pro Durchlauf der loop-Funktion nur ein einziges Zeichen aus dem seriellen Eingangspuffer:

if(Serial1.available()){ 
  command = Serial1.read(); 
   ...

Falls Du also serielle Befehle "in Dauerschleife sendest" bis der Eingangspuffer voll ist, können sich bei langsamen Durchläufen der loop-Funktion bis zu 63 Zeichen im Eingangspuffer ansammeln, die dann erst in 63 Durchläufen der loop-Funktion abgearbeitet werden, bevor neue Befehle verarbeitet werden.

Eine schnellere Reaktion auf Befehle, die von der seriellen Schnittstelle eintreffen, bekommst Du dann, wenn Du pro Durchlauf der loop ALLE Zeichen im Eingangspuffer abarbeitest. Zum Beispiel mit einer while-Schleife statt einer if-Bedingung:

while(Serial1.available()){ 
  command = Serial1.read(); 
   ...

Eine while-Schleife wird ausgeführt, solange die Bedingung erfüllt ist, d.h. es würden in der Schleife so lange Zeichen ausgelesen wie welche im Eingangspuffer enthalten sind.

Das kann dann vorteilhaft sein, wenn Du "den Eingangspuffer voll zuballerst", etwa wenn Dein Steuerprogramm ständig Steuerbefehle in einer schnelleren Abfolge sendet als Du die Befehle auf dem Arduino verarbeitest, weil Du dort die Ausführung ständig mit delay() und pulseIn() Funktionsaufrufen für kürzere oder längere Zeit blockierst.

PERFEKT !!

Das war es !

Läuft so wie ich es mir vorgestellt habe. Keine Verzögerung

1000 Dank von selber wäre ich nie draufgekommen.

Gruß

Chris

Zerebrator:
Habe gerade ne Std. im netz gesucht und festgestellt dass jeder die pulsein befehle benutzt.

Es gibt in der Arduino einige Sachen die von vielen Leuten verwendet werden, aber nicht immer gut sind. Es gibt Anwendung bei denen diese Einschränkungen vertretbar sind und vor allem in den einfachen Beispiel-Sketchen wo sonst nichts gemacht wird, fällt das nicht auf. Aber man kann auch schnell auf die Schautze fallen, weil die negativen Punkte nicht dokumentiert sind.

jurs: Ein weiterer Fallstrick kann Deine Art der Serial-Befehlsverarbeitung sein.

Du verarbeitest pro Durchlauf der loop-Funktion nur ein einziges Zeichen aus dem seriellen Eingangspuffer:

if(Serial1.available()){ 
  command = Serial1.read(); 
   ...

Falls Du also serielle Befehle "in Dauerschleife sendest" bis der Eingangspuffer voll ist, können sich bei langsamen Durchläufen der loop-Funktion bis zu 63 Zeichen im Eingangspuffer ansammeln, die dann erst in 63 Durchläufen der loop-Funktion abgearbeitet werden, bevor neue Befehle verarbeitet werden.

Eine schnellere Reaktion auf Befehle, die von der seriellen Schnittstelle eintreffen, bekommst Du dann, wenn Du pro Durchlauf der loop ALLE Zeichen im Eingangspuffer abarbeitest. Zum Beispiel mit einer while-Schleife statt einer if-Bedingung:

while(Serial1.available()){ 
  command = Serial1.read(); 
   ...

Eine while-Schleife wird ausgeführt, solange die Bedingung erfüllt ist, d.h. es würden in der Schleife so lange Zeichen ausgelesen wie welche im Eingangspuffer enthalten sind.

Das kann dann vorteilhaft sein, wenn Du "den Eingangspuffer voll zuballerst", etwa wenn Dein Steuerprogramm ständig Steuerbefehle in einer schnelleren Abfolge sendet als Du die Befehle auf dem Arduino verarbeitest, weil Du dort die Ausführung ständig mit delay() und pulseIn() Funktionsaufrufen für kürzere oder längere Zeit blockierst.

hatte das gleiche Problem, und dank euch gleich über google gefunden.