Ultraschallsensor Ausgabe verbessern

Hallo zusammen,

ich habe eine kurze Frage. Über diesen Sketch steuere ich meinen HC-SR04 Ultraschallsensor an.

#define trigPin 8
#define echoPin 9

void setup() {
  Serial.begin (9600);
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
}

void loop() {
  long distance;
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2); 
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10); 
  digitalWrite(trigPin, LOW);
  distance = pulseIn(echoPin, HIGH);

  if (distance <= 200){
    Serial.print("1");
  }
  else {
    Serial.print("0");
  }
  delay(500);
}

Ich nutze diesen Code für einen Processing-Sketch, der ein Video abspielt, sofern der Wert “1” ausgegeben wird (also wenn ein Gegenstand nahe am Ultraschallsensor ist).
Nun hat diese Messung ab und zu gewissen Ungenauigkeiten, soll heißen das Video wird manchmal kurz unterbrochen, weil zwischen den Messungen ein oder zwei Mal “0” statt “1” ausgegeben wird.
Meine Überlegung war, das ich lediglich wenn “0” oder “1” drei Mal hintereinander ausgegeben wird einen Wert schicke. Aber ich komme nicht dahinter, wie ich den Code in der Hinsicht anpassen könnte. Habt ihr eine Idee wie ich den Code fixen könnte, damit es zu weniger Unterbrechungen kommt?

Vielen Dank schon für eure Hilfe!

Viele Grüße

Du hast doch den Code für deinen Vorschlag schon fast. Eine Variable hochzählen und erst wenn sie größer-gleich drei ist die Ausgabe machen (und dann wieder auf 0 setzen).

Ob das insgesamt besser ist muss man sehen. Diese Sensoren sind allgemein nicht besonders genau.

Ja, aber ich weiß nicht genau wie ich das in den Code einbauen kann. Kannst du mir vielleicht auf die Sprünge helfen, ich steh grade ziemlich auf dem Schlauch.

So wie ich Serenifly verstehe musst du folgendes tun. Eine Integer Variable (counter) anlegen und in der Setup-Funktion mit 0 initialisieren. Nun inkrementierst du sie in deinem loop immer um den Wert 1.
Dein If, welches die Distanz abfragt, musst du erweitern. Dort noch nach deinem "counter" fragen. Ist er gleich 3 ist die Bedingung erfüllt und du schreibst deinen Wert. Nicht vergessen den counter wieder zurückzusetzen. Vorsicht beim else-Zweig.

Eigentlich sind diese Sensoren schon recht genau. Abweichungen von mehr als 10mm sollten nicht vorkommen, wenn es denn “echte” HC-SR04 sind.
Problem bei den Dingern ist, dass das Timing stimmen muss, sonst klappt gar nix.
Ausserdem bremst pulseIn gewaltig, in der Grundeinstellung!
Dann nämlich wird ne volle Sekunde gewartet, ob sich am Eingang was tut.
Bei den angegebenen 4m Reichweite der Sensoren ist das um Welten zu viel, wenn das Programm auch noch halbwegs flüssig laufen soll.
In Innenräumen würd ich hier maximal auf 100ms gehen, dann dürften auch wilde Echos problemlos abgeklungen sein. Allerdings, wenn du mit 2m arbeitest (das funktioniert allerdings nur mit den guten Ausführungen der HC-SR04, meine “Billignachbauten” schaffen die nicht), kannst du dir leicht ausrechnen, wie weit runter du mit dem Timeout gehen solltest- so lange, wie der Schall für 4m (2 hin, 2 zurück) braucht- so erreichst du das maximale Tempo.
Sollten dann wilde Echos auftreten (der Sensor misst irgendwelchen Nonsens) musst du entweder seltener messen oder aber das Timeout höher stellen.

Ausserdem kannst du die Ergebnisse etwas filtern, indem du z.b. dreimal nacheinander misst (in kurzen Abständen), und dann nen Mittelwert bildest oder aber das Ergebnis etwas rundest mit :
if(Abstand <(200+10) && Abstand>(200-10) oder ähnlich.
Scharfe Grenzen machen zu oft Probleme, inzwischen versuche ich, die immer zu meiden, wenn es denn geht.
Grad in der Robotik macht man vieles damit unnötig nervös.

Um zu erkennen ob ein Gegenstand in oder außerhalb des Grenzwertes liegt bau eine Hysterese ein.
zB:
if (meßwert < 100) Gegenstand = 1;
if (meßwert > 120) Gegenstand = 0;

Grüße Uwe

Hallo,

also ich habe jetzt ein paar Änderungen vorgenommen bin mir aber nicht sicher ob sich dadurch das Ergebnis schon gebessert hat. Zum einen habe ich die Libary NewPing eingefügt, die das Ergebnis angeblich verbessern soll. Und zum anderen habe ich versucht einen Mittelwert durch die Addition von den distance Werten und dann die Teilung durch 3.

Ich bin mir nicht sicher ob der gewünschte Effekt bislang eingetreten ist. Könntet ihr mal sehen ob ich noch Fehler in meinem Code habe und sie eventuell korrigieren?

#include <NewPing.h>
#define trigPin 8
#define echoPin 9
int sensor;
void setup() {
 Serial.begin (9600);
 pinMode(trigPin, OUTPUT);
 pinMode(echoPin, INPUT);
}

void loop() {
 long distance;
 digitalWrite(trigPin, LOW);
 delayMicroseconds(2); 
 digitalWrite(trigPin, HIGH);
 delayMicroseconds(10); 
 digitalWrite(trigPin, LOW);
 distance = pulseIn(echoPin, HIGH);
 if (distance > 0) sensor = (distance + distance + distance)/3; 
 if (sensor <= 200){
   Serial.print("1");
 }
 else {
   Serial.print("0");
 }
 delay(500);
}

newping ist gut, mittelwert ist schlecht, der macht die Ausreißer nicht weg. Mach z. B. 15 Messungen und nimm den Median. Damit bekomme ivh mit billigen China Teilen besser als 1 mm Wiederholgenauigkeit.

Soo beeindruckt bin ich von der NewPing nun auch wieder nicht, aber sie tuts auch.
Interessant wird die eigentlich erst, wenn man viele der Dinger zugleich einsetzen will.

@ElEspanol Interessenhalber: auf welche Entfernung?? Milimetergenau kenne ich nicht mal von den wirklich guten der Dinger (rein rechnerisch mit Einzelmessung auch gar nicht möglich, aber durch vermitteln evtl...)-aber ich weiss recht sicher, dass die Billigdinger (nich nur bei mir, sondern bei anderen ebefalls) nur selten 2m weit kommen. Komischerweise erscheinen bei freiem Feld dennoch irgendwelche Entfernungswerte...

im bereich von ca 20-30 cm

größere Entfernungen hatte ich noch nicht im Einsatz

kann aber sein, das ich auch 3 oder 5 Werte um den Median gemittelt habe. müsste ich nachschauen

Also auch mit fünf Werten schaffst du keine Genauigkeit von nem Millimeter.
Da brauchst schon nen paar Werte mehr, und wahrscheinlich nen Komplementärfilter.

Aber egal-mich würd mal interessieren (weil ich vier davon einsetzen wollte (eigentlich immer noch will wenn sie nich zicken würden)), wie weit deine wirklich kommen und, was die machen bei out-of-range.
Normal sollte dann ja gar nix kommen, meine aber produzieren bei Entfernungen oberhalb anderthalb Meter wirklich noch Entfernungsangaben-auch wenn ich sie senkrecht gen Himmel halte. :cry:
So bis etwa 1.20m arbeiten sie tadellos...*grmbl
Die Genauigkeit ist mir dagegen ziemlich Wurst in dem Fall, aber die Reichweite brauch ich.

Rabenauge:
Auch wenn ich sie senkrecht gen Himmel halte.

Das ist komisch, aber ein Grund weshalb die mit zunehmender Entfernung schlechter werden ist dass der Schall kegelförmig ausgesendet wird. So erhält bei zunehmenden Abstand auch Reflexionen von Objekten die recht weit außen liegen.

Ja. Gibt da so nette Scherereien wie mehrfache Echos, usw. Kenn ich alles, damit komme ich klar (zumal bei mir der Einsatz im Freien vorgesehn ist), dass ist mit gut bemessenen Timeouts in Griff zu kriegen.
Dennoch: egal wo, egal wieviel vor den Dingern frei ist, es gibt ne "Hinderniserkennung"- meist so um 1.20m herum.
Technisch eigentlich unmöglich, bei nen paar km freier Luft vor dem Sensor kann der eigentlich keinen Ping haben. Das Ganze ist aber reproduzierbar und-funktioniert mit vier verschiedenen.

Hier nun mal der code, den ich so oder ähnlich verwende. Auf serial wird sowohl der median als auch der Mittelwer um den Median rum ausgegeben. Die Variable Korrektur=7 nimmt von den 19 Array-werten am Anfang und am Ende je 7 (somit alle Ausreisser) weg, so dass über 5 der Durchschnitt gebildet werden kann. Mit array und korrektur kann man noch rumspielen, ob man es evtl. schneller oder genauer hinbekommt. Bei out of range (MAX_DISTANCE) kommt 0.00

Ich hoffe, es ist für den einen oder anderen von Nutzen, auf meinem Mist sind die Einzelnen Programmteile nicht gewachsen, ich habe es nur zusammengestrickt. Also Dank an die jeweiligen Autoren

// SR04 Routine
#include <NewPing.h>
#define TRIGGER_PIN  10  // Arduino pin tied to trigger pin on the ultrasonic sensor.
#define ECHO_PIN     11  // Arduino pin tied to echo pin on the ultrasonic sensor.
#define MAX_DISTANCE 300 // Maximum distance we want to ping for (in centimeters). Maximum sensor distance is rated at 400-500cm.
NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE); // NewPing setup of pins and maximum distance.

#include <Streaming.h>
#include <PString.h>

//Set the pin to recieve the signal.
const int pwPin = 7;
//variables needed to store values
const int arraysize = 19;  //quantity of values to find the median (sample size). Needs to be an odd number
 
//declare an array to store the samples. not necessary to zero the array values here, it just makes the code clearer
int rangevalue[arraysize];
long pulse;
int modE;
float cm;
int korrektur=7;
void setup()
{
 
  //Open up a serial connection
  Serial.begin(9600);
  //Wait for the serial connection
  delay(100);
 
}
//Main loop where the action takes place
void loop()
{
for(int i = 0; i < arraysize; i++)
  {
 
    pulse = sonar.ping();
    rangevalue[i] = pulse;
    delay(30);
  }
  
 
//  Serial.print("Unsorted: ");
//  printArray(rangevalue,arraysize);
  isort(rangevalue,arraysize);
//  Serial.print("Sorted: ");
//  printArray(rangevalue,arraysize);
  modE = mode(rangevalue,arraysize);
  Serial << "The mode/median is: " << modE << "   " << modE/58.0 << "   ";
for (int i=korrektur; i<arraysize-korrektur; i++)
 cm+=rangevalue[i];
Serial << "Mittelwert =" << cm/58.0/(arraysize-korrektur-korrektur) << " cm"<<endl;
  cm=0;
  delay(300);

}
 
/*-----------Functions------------*/
//Function to print the arrays.
void printArray(int *a, int n)
{
 
  for (int i = 0; i < n; i++)
  {
    Serial.print(a[i], DEC);
    Serial.print(' ');
  }
 
  Serial.println();
}
 
//Sorting function
// sort function (Author: Bill Gentles, Nov. 12, 2010)
void isort(int *a, int n)
//  *a is an array pointer function
{
  for (int i = 1; i < n; ++i)   
  {     
    int j = a[i];     
    int k;     
    for (k = i - 1; (k >= 0) && (j < a[k]); k--)
    {
      a[k + 1] = a[k];
    }
    a[k + 1] = j;
  }
}
 
//Mode function, returning the mode or median.
int mode(int *x,int n){
  int i = 0;
  int count = 0;
  int maxCount = 0;
  int mode = 0;
  int bimodal;
  int prevCount = 0;
 
  while(prevCount & count > maxCount)
  {
      mode=x[i];
      maxCount=count;
      bimodal=0;
    }
    if(count==0){
      i++;
    }
    if(count==maxCount)
    {//If the dataset has 2 or more modes.
      bimodal=1;
    }
    if(mode==0||bimodal==1)
    {//Return the median if there is no mode.
      mode=x[(n/2)];
    }
    return mode;
  //}
}