Geschwindigkeitsmessung mit Ultraschall

Hallo,

ich habe ein Problem mit der Funktion millis().
Mit einem Ultraschallsensor möchte ich die Geschwindigkeit messen.

Die Überlegung ist folgende: Mit dem Ultraschallsensor erfasse ich den Abstandswert1 und erfasse gleichzeitig die aktuelle Zeit, 500ms später erfasse ich den Abstandswert2 und errechne dadurch die Geschwindigkeit.

Die Abstandwerte zu erfassen klappt einwandfrei, aber die dazugehörige Zeiten abzuspeichern ist noch ein Problem.

Wie in dem Sketch im Anhang zu lesen versuche ich die Zeit mit millis() zu erfassen. Da millis() aber
immer weiter läuft und den int immer aktualisiert kann ich später nicht mit im weiter rechnen.

Hat jemand von euch eine Idee wie man das Problem lösen könnte?

int trigger = 7;
int echo = 6;
long Entfernung1 = 0;
long Entfernung2 = 0;
long Differenz1 = 0;
int Anfang = 0;
int Ende = 0;
int Differenz2 = 0;
int Geschw = 0;
long currentmillis = 0;
long  lastmillis = 0;
long dauer = 0;



void setup()
{
  Serial.begin (9600);
  pinMode(trigger, OUTPUT);
  pinMode(echo, INPUT);



}

void loop()
{

  Abstand1();

  if (Entfernung1 <=  400) {
    Anfang = millis();
    Serial.print("\tAnfang=\t"); 
    Serial.print(Anfang);


    if (millis() - Anfang >= 500) {


      Abstand2 ();

      Differenz1 = Entfernung1 - Entfernung2 ;
      //Serial.print(Differenz1);
      Geschw = Differenz1 / 500;

           // Serial.println(" m/s");
      //Serial.print(Geschw);
    }
  }
}



void Abstand1 () {

  digitalWrite(trigger, LOW);

  delay(5);

  digitalWrite(trigger, HIGH);

  delay(10);

  digitalWrite(trigger, LOW);

  dauer = pulseIn(echo, HIGH);

  Entfernung1 = (dauer / 2) / 29.1;

  if (Entfernung1 >= 1800 || Entfernung1 <= 0)

  {

    Serial.print("Kein Messwert");

  }
  else
  { Serial.print("\tEntfernung1=");
    Serial.print(Entfernung1);

    Serial.println("cm");
  }
}





void Abstand2 () {

  digitalWrite(trigger, LOW);

  delay(5);

  digitalWrite(trigger, HIGH);

  delay(10);

  digitalWrite(trigger, LOW);

  dauer = pulseIn(echo, HIGH);

  Entfernung2 = (dauer / 2) / 29.1;

  if (Entfernung2 >= 1800 || Entfernung2 <= 0)

  {

    Serial.print("Kein Messwert");

  }
  else
  { Serial.print("\tEntfernung2=\t");
    Serial.print(Entfernung2);

    Serial.println("\t cm \t ");
     
  }

}

Gruß

Jan

geschwindigkeitsmessung_sep13b.ino (1.55 KB)

Poste den Sketch bitte direkt in Code-Tags. Im Tablet kann ich den nicht lesen.

Danke

Hallo, wenn Du die Messung startest, dann mußt Du Dir die "echten" millis()in einer Variable merken. Gruß und Spaß Andreas

Tablet-Version:

Hallo, wenn Du die Messung startest, dann mußt Du Dir die "echten" millis() in einer Variable merken. Gruß und Spaß Andreas :)

Hallo,

habt ihr keinen Editor auf dem Tablet?

SkobyMobil: Hallo, wenn Du die Messung startest, dann mußt Du Dir die "echten" millis()in einer Variable merken. Gruß und Spaß Andreas

Tablet-Version:

Hallo, wenn Du die Messung startest, dann mußt Du Dir die "echten" millis() in einer Variable merken. Gruß und Spaß Andreas :)

SUPER...DANKE

Ein Karma hattest du schon ;)

Doc_Arduino: Hallo,

habt ihr keinen Editor auf dem Tablet?

Ist halt nicht so elegant. Ich lese es lieber direkt im Forum

Hallo,

du speicherst doch den Anfang. Anfang = millis();

Variable Ende ist schon definiert wird nur nicht genutzt. Warum nicht? Also speicherst bei der 2. Messung mit Ende = millis();

und subtrahierst diese irgendwann.

Ist der Sketch von dir? Weil da viele Variablen zwar definiert sind aber nicht genutzt werden.

In deinem Sketch ist leider die Idee des nicht blockierenden Codes nur unzureichend umgesetzt. Es fehlt eine Flag-Variable, die verhindert, dass bei jedem Durchlauf Entfernung1 neu bestimmt wird. Anfang wird ständig neu gesetzt. Das musst du einmal speichern und darf erst zurückgesetzt werden, wenn die 500ms vergangen sind.

Ablauf wäre:

Wenn Laufflag ungesetzt ist, Entfernung1 bestimmen, wenn Abstand stimmt, Laufflag setzen und millis speichern.

Wenn das Laufflag gesetzt ist, wird geschaut, ob 500ms seit der gespeicherten Zeit vergangen sind, Wenn ja: neue Entfernung messen, Laufflag zurücksetzen und Geschwindigkeit berechnen und ausgeben.

Programm fängt wieder vorne an.

Schon mal danke für die vielen Antworten.

@Doc_Arduino Danke für die Info, der Integer Ende wird ja gar nicht mehr gebraucht, da es ja klar definiert ist, dass wenn millis() 500ms größer als der Wert Anfang ist, soll er ja Abstand2 messen. Habe den Abstands Code etwas abgeschaut, aber der Rest ist von mir ;)

@Theseus so wie du es jetzt beschrieben hast, wollte ich es auch umsetzten, aber an der Ausführung mangelt es noch. Mit Flags meinst du eine Bedingung oder?

Falls es jemand interessiert für was genau ich das brauche:

Ich möchte für meinen Hexacopter eine Hinderniserkennung bauen. Dafür muss ich aber wissen wie schnell der Hexacopter auf das Hindernis zu fliegt und je nachdem muss er dann stark dagegen regeln.

Mit Flag meine ich eine Statusvariable.

In der Dekalartion setzt du z.B. Boolean Messaktiv=false (alternativ Byte Messaktiv=0)

Dann in der Loop:

if (Messaktiv==false) {Entfernung1();..... Messaktiv=true; Anfang=millis();.....}

if ((Messaktiv==true) && (Anfang-millis()>500)) {2. Messung usw.....

.... Messaktiv=false;}

Alles klar vielen Dank! Ich probiers gleich mal aus.

Ich würde auch nicht unbedingt drauf setzen das wenn du auf >500 abfragst das dann genau 501millisekunden vergangen sind. Das klappt nur, wenn dein Loop mehr als 1000x pro Sec durchlaufen wird. Ansonsten vergeht auch mal mehr Zeit und du hast zusätzliche Messfehler.

Momentan allerdings ist dein Code noch klein genug mehr als 1000x durchlaufen zu werden pro sec. Aber man gewöhnt sich da leider Dinge an, die einem später viel Zeit kosten bei der Fehlersuche.

Hallo,

du kannst nach erreichen deiner 500ms rechnen Differenz = millis()-Anfang; ist gehoppt wie gesprungen, nur eine Variable weniger. Das andere ist nur auf den ersten Blick besser lesbar. Ob die Genauigkeit der Loopdurchläufe reicht ist eine andere Sache. Wurde ja schon angesprochen. Vorallendingen bei Topspeed. Du müßtest erstmal durchrechnen wieviel Zentimeter oder Meter das ausmacht wenn du mit Topspeed fliegst und die Loop einmal 20ms und einmal 100ms benötigt. Das als Differenz zu den 500ms dazu. Aber das ist alles viel Spekulation. Kann man nur grob abschätzen. Oder am Ende mit fertigen Code ausmessen. Wobei 100ms für eine Loop schon ziemlich heftig wäre. Da würde ich Probleme im Code vermuten. Bsp. Wenn der vorherige Durchlauf bei 475ms lag, dann triffste beim nächsten 30ms Umlauf die 500ms ziemlich genau. Lag der vorherige Umlauf dagegen bei 499ms, dann liegst im nächsten zutreffenden um 29ms daneben. Die Frage lautet also. Stört das oder ist die Ungenauigkeit egal.

Hallo,

das mit der Zeit zwischen Entfernung 1 und Entfernung 2 klappt jetzt super, schon mal danke dafür!

Jetzt habe ich erneut ein Problem:

Zwischen der 1. Entfernungsmessung unter 50cm und der 2. Entfernungsmessung wird der Wert der 1.Entf. immer aktualisiert und damit ist meistens die Differenz von der 1.Entf. zur 2.Entf. =0.
Das Problem könnt ihr auch im Anhang in dem Bild SeriellerMonitor_Loop sehen.
Ich habe auch mal ein Ablaufdiagramm gemacht und frage mich warum er immer noch nach Messdurch= false in die Abstand1 Schleife geht.

Hat jemand ne Idee warum er das immer noch macht?

int trigger = 7;
int echo = 6;
long Entfernung1 = 0;
long Entfernung2 = 0;
long Differenz1 = 0;
unsigned long  Anfang = 0;
int Geschw = 0;
long dauer = 0;
boolean Messaktiv = false;
int Durchlauf = 0;
boolean Messdurch = true;

void setup()
{
  Serial.begin (9600);
  pinMode(trigger, OUTPUT);
  pinMode(echo, INPUT);



}

void loop()
{



  if (Messdurch = true) {
    Abstand1();
  }





  if ((Messaktiv == false) && (Entfernung1 <=  50)) {
    Serial.print (Durchlauf);
    Serial.print (".Durchlauf");
    Durchlauf++;
    Anfang = millis();
    Messaktiv = true;
    Messdurch = false;
 
    Serial.print("\tAnfang=\t");
    Serial.print(Anfang);
  }


  if (Messaktiv == true) {
    if (millis() - Anfang >= 478) {
   
      Serial.print("\tmillis=\t");
      Serial.print(millis());

      Abstand2 ();
      Differenz1 = Entfernung1 - Entfernung2 ;
      Geschw = Differenz1 / 500;
      Serial.print("\tDifferenz=");
      Serial.print(Differenz1);
      Serial.print("\t\t");

      Serial.print(Geschw);
      Serial.println("m/s\t");
      Messaktiv = false;
      Messdurch = true;

    }

  }


}




void Abstand1 () {

  digitalWrite(trigger, LOW);

  delay(5);

  digitalWrite(trigger, HIGH);

  delay(10);

  digitalWrite(trigger, LOW);

  dauer = pulseIn(echo, HIGH);

  Entfernung1 = (dauer / 2) / 29.1;

  if (Entfernung1 >= 1800 || Entfernung1 <= 0)

  {

    Serial.print("Kein Messwert");

  }
  else
  {
    Serial.print("\tEntfernung1=");
    Serial.print(Entfernung1);

    Serial.println("cm");
  }
}





void Abstand2 () {

  digitalWrite(trigger, LOW);

  delay(5);

  digitalWrite(trigger, HIGH);

  delay(10);

  digitalWrite(trigger, LOW);

  dauer = pulseIn(echo, HIGH);

  Entfernung2 = (dauer / 2) / 29.1;

  if (Entfernung2 >= 1800 || Entfernung2 <= 0)

  {

    Serial.print("Kein Messwert");

  }
  else
  { Serial.print("\tEntfernung2=");
    Serial.print(Entfernung2);

    Serial.println("\t cm \t ");

  }

}

SeriellerMonitor_Loop.PNG

Hallo,

das ist ja mal einfach. :) Weil du vorher mit if (Messdurch = true) ...

[u]immer[/u] erneut Messdurch den Wert "true" zuweist.

= ...... zuweisen == ... vergleichen

mach dir nichts daraus, passiert jeden. ;)

Doc_Arduino: mach dir nichts daraus, passiert jedem. ;)

Zumindest denen, die die Warnungen unterdrücken (leider Defaulteinstellung) oder ignorieren. ;)

sketch_sep30a.ino:31:23: warning: suggest parentheses around assignment used as truth value [-Wparentheses]
D:\Program Files

Hallo,

Warnungen werden generell ignoriert. Erst wenn es nicht kompiliert guckt man hin. :)

Seit ca. einem Jahr habe ich "alles ein" gesetzt. Man muß dann schon genau lesen was gemeint ist oder ob man es nicht doch irgnorieren kann. Habe mir angewöhnt jede Meldung ernst zu nehmen so das der Compiler auch keine Warnungen ausgibt. Außer bei fremden Libraries mit unbenutzten Variablen und solchen Mist. Ersteres kann ich mittlerweile selbst korrigieren. Dank Forum und der dicken Katze. :)

janbaz497: Hat jemand ne Idee warum er das immer noch macht?

Die Frage wurde ja schon beantwortet. Allerdings auch mit der Änderung "=" nach "==" kommt noch kein richtiger Wert heraus. Das liegt an der Mischung von verschiedenen Variablentypen und beispielsweise der Division einer kleinen Zahl durch eine große mit Hilfe von Ganzzahlenarithmetik. Also 2 durch 5 ergibt 0. Aber 2.0 durch 5.0 ergibt 0.4 (Punkt als Komma, wie die Amis das so machen).

Basierend auf Deinem Programm habe ich ein paar kleine Veränderungen vorgenommen. So habe ich die beiden Funktionen Abstand1 und Abstand2 zu einer mit Rückgabewert zusammengefaßt. Bei pulseIn(pin, value, timeout) habe ich timeout ergänzt. Die Geschwindigkeit berechne ich als float. Ob am Ende wirklich m/s herauskommt, habe ich nicht überprüft!

const int trigger = 7;
const int echo = 6;
long Differenz = 0;
unsigned long  Anfang = 0;
float Geschw = 0;
unsigned long dauer1 = 0, dauer2 = 0;
boolean Messaktiv = false;
int Durchlauf = 0;

void setup()
{
  Serial.begin (9600);
  Serial.println("Programmanfang");
  pinMode(trigger, OUTPUT);
  pinMode(echo, INPUT);
}

void loop()
{
  if (!Messaktiv) {
    dauer1 = Abstand();
    if (dauer1 > 0) {
      Anfang = millis();
      Messaktiv = true;
    }
  } else {
    if (millis() - Anfang >= 478) {
      dauer2 = Abstand();
      Messaktiv = false;
      if ((dauer1 > 0) && (dauer2 > 0)) {
        Durchlauf++;
        Serial.print (Durchlauf);
        Serial.print (".Durchlauf");
        Serial.print("\tZeit=");
        Serial.print(millis() - Anfang);
        Serial.print("\tdauer1=");
        Serial.print(dauer1);
        Serial.print("\tdauer2=");
        Serial.print(dauer2);
        Differenz = dauer1 - dauer2 ;
        Geschw = Differenz / 29000.0;
        Serial.print("\tDifferenz=");
        Serial.print(Differenz);
        Serial.print("\t\t");
        Serial.print(Geschw, 6);
        Serial.println(" m/s\t");
      }
    }
  }
}

unsigned long Abstand () {
  digitalWrite(trigger, LOW);
  delay(5);
  digitalWrite(trigger, HIGH);
  delay(10);
  digitalWrite(trigger, LOW);
  return pulseIn(echo, HIGH, 2900); // 50*58
}

Doc_Arduino: Warnungen werden generell ignoriert. Erst wenn es nicht kompiliert guckt man hin. :)

Seit ca. einem Jahr habe ich "alles ein" gesetzt.

Du seist mir diesbezüglich Vorbild :grin:

Hallo,

da hat sich aber jetzt jemand richtig Mühe gegeben. :)

Das Freigeben der Warnungen war eigentlich ganz einfach ;)