Nähesensitives Licht ist zu langsam und nicht gleichzeitig :-(

Liebe Arduino-Gemeinde, ich brauche eure Hilfe:

Ich beschäftige mich mit der Interaktion zwischen Mensch und Maschine und möchte eine Installation für Tänzer bauen. Es ist im Grunde "nur" ein Licht, welches heller wird, wenn sich jemand auf das Licht zubewegt; bei einem Klatschen ändert sich die Farbe des Lichtes. Mein Aufbau funktioniert, nur leider ist alles zu langsam und läuft nicht gleichzeitig ab.

  • Ich nutze ein Arduino Uno**.**
    - Ultrasonic Sensor HC-SR04 um die Distanz zu messen.
    Da dieser Sensor arg ungenau ist, muss ich die Werte mit der Bibliothek "MyUltrasoundSensor" mehrfach messen und mit dem Codeschnipsel "runningAverage" den neuen Wert mit dem vorherigen gegenrechnen.

  • LM35 misst die Temperatur für den HC-SR04. Wird aber im aktuellen Aufbau ignoriert.
    - KY-038 Microphone Sound Sensor soll das Klatschen ermitteln.

  • LED RGB Stripe mit 3 N-Channel MOSFET

1. Problem
Mit diesem Tutorial Link funktioniert der Sensor recht gut; mit meinem Aufbau aber nur wenn man permanent am Mikrofon reibt.

Ist es, weil zwei Loops parallel ablaufende müssten? Schafft das ein ArduionDuo? Oder ist mein Code nicht "smart" genug?

2. Problem
Der ganze Prozess läuft sehr stockend.

Zuerst dachte ich es liegt daran, weil der Arduino zu langsam für die LED´s ist.
Ich nutzte zuerst ein "LED VCC"-Stripe, was mithilfe der "FastLight"-Library jedes einzelne LED anspricht Link. Und nahm stattdessen einem LED RGB Stripe mit 3 N-Channel MOSFET Link = Richtig schneller ist es aber dadurch auch nicht geworden.

Jetzt glaube ich, dass Ultraschall nicht die beste Lösung ist, weil es ab 1m zu ungenau und zu langsam wird. Könnt ihr mir eine bessere und schnellere Methode empfehlen? Infrarot? Laser?

Ich habe dazu das hier gefunden: Aber das scheint auch nicht schnell genug zu sein: Link

lg
fm

#include <MyUltrasoundSensor.h> // MyUltrasoundSensor - Version: Latest 

#define TrigPin 7 // HC-SR04  
#define EchoPin 6 // HC-SR04 
float Distance; // HC-SR04: to narrow the Distance
int tempRohWert; //Rohwert von LM35
float tempWert; //air temperature

MyUltrasoundSensor MyUsS(TrigPin, EchoPin); // HC-SR04: to prevent erroneous measurements

#define RedPin 5 // LED RGB Stripe 
#define GreenPin 4 // LED RGB Stripe 
#define BluePin 3 // LED RGB Stripe 

#define SoundPin 2 // KY-038 Microphone Sound Sensor
int counter = 0;

void setup() {

  Serial.begin(9600);
  
  analogReference(INTERNAL); //Referenzspannung für LM35 auf 1,1 V stellen
  MyUsS.medianNumber = 5; //Anzahl der Messungen für Median-Wert (Standardeinstellung = 5)

  //Mindestzeit in ms zwischen 2 Messungen (Standardeinstellung = 50)
  //Die kürzeste Zeit darf 20 ms sein (max. 50 Messungen/s) beim HC-SR04

  //bzw. 50 ms (max. 20 Messungen/s) beim HY-SRF05
  //Wird ein kleinerer Wert als 20 angegeben, wird der Wert in der
  //Library auf 20 ms begrenzt.
  MyUsS.measureDelay = 50;

  pinMode(RedPin, OUTPUT); // LED RGB Stripe 
  pinMode(GreenPin, OUTPUT); // LED RGB Stripe 
  pinMode(BluePin, OUTPUT); // LED RGB Stripe 

  pinMode(SoundPin, INPUT); // KY-038 Microphone Sound Sensor

}

void loop() {

  // ++++++++++++++++++++++++++++++++++++++++++++ Distance measurement 
  Distance = MyUsS.distanceTempCompMedian(tempWert); // HC-SR04: The correct distance
  int DistanceArea = constrain(Distance, 0, 100); // HC-SR04: The DistanceArea here 1m
  DistanceArea = runningAverage(DistanceArea); // HC-SR04: the mix between the last and the current value to prevent big light difference
  int Brightness = map(DistanceArea, 100, 0, 0, 255); // HC-SR04: the correlation between distance and light
  
  // ++++++++++++++++++++++++++++++++++++++++++++ Clap measurement 
  
  int Sound = !digitalRead(SoundPin); // KY-038: if a clap ->
  if (Sound == 1) { 

    counter = counter + 1;
  } // KY-038: count 1

  if (counter == 4) {

    counter = 0;
  } 

  // ++++++++++++++++++++++++++++++++++++++++++++ LED brightness 

  switch (counter) {

    case 1:
      analogWrite(RedPin, Brightness);
      Serial.print("Case"); Serial.println(1);
      break;

    case 2:
      analogWrite(GreenPin, Brightness);
      Serial.print("Case"); Serial.println(2);
      break;

    case 3:
      analogWrite(BluePin, Brightness);
      Serial.print("Case"); Serial.println(3);
      break;

    default:
      analogWrite(BluePin, Brightness);
      analogWrite(GreenPin, Brightness);
      analogWrite(RedPin, Brightness);
      Serial.print("Case"); Serial.println(4);
      break;

  }

}

// ++++++++++++++++++++++++++++++++++++++++++++ runningAverage

long runningAverage(int M) {
#define LM_SIZE 3
  static int LM[LM_SIZE];      // LastMeasurements
  static byte index = 0;
  static long sum = 0;
  static byte count = 0;

  // keep sum updated to improve speed.
  sum -= LM[index];
  LM[index] = M;
  sum += LM[index];
  index++;
  index = index % LM_SIZE;
  if (count < LM_SIZE) count++;

  return sum / count;
}

Hi

Wenn ich Das recht überflogen habe, blockiert hier der Entfernungsmesser den Programmablauf?!?
Wenn DEM so ist (eine einfache Blink-LED sollte Das anzeigen können - 1x mit, 1x ohne den Echo-Kram), könntest Du versuchen, den Abstandmesser 'von Hand' und via Interrupt anzugehen.
Dafür brauchst Du eine Zeit-Variable, Die von der ISR gesetzt werden kann - Diese wird global und volatile sein müssen.
Das Auslösen der Schall-Impuls ist ein kurzer High-Low Wechsel am Trigger-Pin.
Zum Auslösen:
Aktuelle Zeit merken (Startzeit), Impuls auslösen.

Nun in der loop() auf das Ergebnis warten - ob die loop() eine ms mehr oder weniger braucht, spielt hier keine größere Rolle.

In der ISR wird unterdessen das Echo erkannt und die aktuelle Uhrzeit gespeichert.
Nun ist Es in der loop() möglich, die Differenz beider Zeiten zu bestimmen - wenn die Stop-Zeit nach der Start-Zeit kam, haben wir ein Echo empfangen.
Das kannst Du wieder Deinem runningMedian (würde ich nehmen, ist in einer Philips-Lib ... suche Das gleich Mal raus - siehe PS unten) übergeben und erhältst den aktuellen Median, Den Du zur Auswertung heranziehst.

Als Uhr wird hier wohl mikros() sinniger als millis sein.

MfG

PS: Knapp daneben ... ist SharpDistSensor, GitHub, wo dann die MedianFilter enthalten ist.

Evtl. könnte auch die NewPing-Lib für Dich interessant sein.

Gruß Tommy

efemde:
Ist es, weil zwei Loops parallel ablaufende müssten? Schafft das ein ArduionDuo? Oder ist mein Code nicht "smart" genug?

Ich habe Dein Posting nur sehr schnell quergelesen.

Das Problem, das Du zu haben scheinst, kannst Du mit einer passenden Programmierstrategie vermeiden. Es gibt dazu einen sehr guten Text hier im Forum (die sog. Nachtwächter-Erklärung) und ein Getexte von mir.

Ansonsten fällt mir nur ein, dass auch ich schon ähnliches wie Du angestellt habe. Allerdings mit einem IR-Taster. Das hat sehr gut geklappt, nachdem ich die Sendediode „verpackt“ hatte - Streulicht war ein riesen-Problem, was mir erst nach dem Verpacken aufging. Ultraschall kam wegen Katze nicht infrage.

Gruß

Gregor

Hi

gregorss:
Ultraschall kam wegen Katze nicht infrage.

:o Meine Samtpfoten sind bisher von meinen Spielereien mit dem HC-SR04 völlig unbeeindruckt - bei dem Viehzeug, daß Die mir so anschlüren (als ob's hier nix zum Fressen gäbe), sollten Sie auch noch nicht sonderlich taub sein.

Hast Du andere Erfahrungen gemacht?

MfG

postmaster-ino:
Hast Du andere Erfahrungen gemacht?

Nein. Ich habe keine Katze, mag die Viecher aber. Und die Katzen, die ich bislang kennen gelernt habe, haben einfach alles gehört. Und da in meiner vorletzten Wohnung oft Katzenbesuch kam, wollte ich einfach alles ausschließen, was problematisch sein könnte.

Gruß

Gregor

Vielen Vielen Dank für die vielen Tips und Schlüsselwörter! Und vor allem für die schnelle Antwort.

Ich musste meinerseits noch vieles nachlesen, und alles habe ich noch nicht verstanden :frowning:

  1. Problem

Habe es jetzt mit attachInterrupt() hinbekommen. Nur spielt er das mehrfach ab. Sollte man deswegen nach dem Prinzip des "Endlichen Automaten" programieren?

  1. Problem
    Der HC-SR04 misst auf 50 cm richtig gut, aber ab 100 cm wird er fehlerhaft. Durch das häufigeren Messen wird alles zwar genauer aber langsamer.

Nach dieser Rechnung…
0,00292 s (Schall in der Luft auf 1m bei 20c) x 2 (hin und zurück) x 2 (2m entfernung) x 5 (fehlerauslese) = 0,0584 s … sollte es aber schnell genug sein.

Die Library "New Ping" klingt recht gut, nur habe ich keine Ahnung wie ich sie mit meinem Code integriere. Wird der Sensor dadurch genauer, oder schneller?

#include <MyUltrasoundSensor.h> // MyUltrasoundSensor - Version: Latest 

#define TrigPin 7 // HC-SR04  
#define EchoPin 6 // HC-SR04 
float Distance; // HC-SR04: to narrow the Distance
int tempRohWert; //Rohwert von LM35
float tempWert; //air temperature

MyUltrasoundSensor MyUsS(TrigPin, EchoPin); // HC-SR04: to prevent erroneous measurements

#define RedPin 5 // LED RGB Stripe 
#define GreenPin 4 // LED RGB Stripe 
#define BluePin 3 // LED RGB Stripe 

#define SoundPin 2 // KY-038 Microphone Sound Sensor

volatile int Sound = 0; // KY-038 Microphone Sound Sensor
volatile int counter = 0;

void setup() {

  Serial.begin(115200);

  analogReference(INTERNAL); //Referenzspannung für LM35 auf 1,1 V stellen
  MyUsS.medianNumber = 2; //Anzahl der Messungen für Median-Wert (Standardeinstellung = 5)

  //Mindestzeit in ms zwischen 2 Messungen (Standardeinstellung = 50)
  //Die kürzeste Zeit darf 20 ms sein (max. 50 Messungen/s) beim HC-SR04

  //bzw. 50 ms (max. 20 Messungen/s) beim HY-SRF05
  //Wird ein kleinerer Wert als 20 angegeben, wird der Wert in der
  //Library auf 20 ms begrenzt.
  MyUsS.measureDelay = 50;

  pinMode(RedPin, OUTPUT); // LED RGB Stripe
  pinMode(GreenPin, OUTPUT); // LED RGB Stripe
  pinMode(BluePin, OUTPUT); // LED RGB Stripe

  pinMode(SoundPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(SoundPin), ColorChange, HIGH);

}

void loop() {

  // ++++++++++++++++++++++++++++++++++++++++++++ Distance measurement
  Distance = MyUsS.distanceTempCompMedian(tempWert); // HC-SR04: The correct distance
  int DistanceArea = constrain(Distance, 0, 50); // HC-SR04: The DistanceArea here 1m
  DistanceArea = runningAverage(DistanceArea); // HC-SR04: the mix between the last and the current value to prevent big light difference
  int Brightness = map(DistanceArea, 50, 0, 0, 255); // HC-SR04: the correlation between distance and light

  // ++++++++++++++++++++++++++++++++++++++++++++ Clap measurement

  // ++++++++++++++++++++++++++++++++++++++++++++ LED brightness

  switch (counter) {

    case 1:
      analogWrite(BluePin, Brightness);
      analogWrite(GreenPin, 0);
      analogWrite(RedPin, 0);
      Serial.print("Case"); Serial.println(1);
      break;

    case 2:
      analogWrite(BluePin, 0);
      analogWrite(GreenPin, Brightness);
      analogWrite(RedPin, 0);      
      
      Serial.print("Case"); Serial.println(2);
      break;

    case 3:
      analogWrite(BluePin, 0);
      analogWrite(GreenPin, 0);
      analogWrite(RedPin, Brightness);
      Serial.print("Case"); Serial.println(3);
      break;

    default:
      analogWrite(BluePin, Brightness);
      analogWrite(GreenPin, Brightness);
      analogWrite(RedPin, Brightness);
      Serial.print("Case"); Serial.println(4);
      break;

  }

}

void ColorChange() {
  Serial.print("hallo");
  if (counter < 4) {

    counter = counter + 1;
     delay(100); 
  } // KY-038: count 1

  if (counter == 4) {

    counter = 0;
    delay(100); 
  }
}

// ++++++++++++++++++++++++++++++++++++++++++++ runningAverage

long runningAverage(int M) {
#define LM_SIZE 3
  static int LM[LM_SIZE];      // LastMeasurements
  static byte index = 0;
  static long sum = 0;
  static byte count = 0;

  // keep sum updated to improve speed.
  sum -= LM[index];
  LM[index] = M;
  sum += LM[index];
  index++;
  index = index % LM_SIZE;
  if (count < LM_SIZE) count++;

  return sum / count;
}

Hi

Schau Dir Mal den Median-Filter an, den ich in #1 genannt habe.
Dabei wird die Mitte der Messungen als Messwert zurück gegeben.
Dadurch stören vereinzelte Ausreißer nicht.
Anders als bei einem Mittelwert verfälscht ein Ausreißer hier auch nicht das Ergebnis, es 'dauert halt', bis der aktuelle Messwert 'in die Mitte' gewandert ist.

Schneller wird der Schall durch eine andere Lib nicht wirklich und Fehlmessungen wirst Du immer haben, ob Median oder Mittelwert hier besser sind, muß sich zeigen.
Beim Schall, wo ich teilweise stark schwankende Werte habe, hat sich der Median ganz gut gemacht.
Für eine Differenzdruck-Messung wollte ich schon lange einen Sketch auf Mittelwert umgestrickt haben ...
Mit Median sieht Das bisher so aus:


Gestrichelte Linie -> Null-Linie
Oben Links Min und Max-Wert, rechts davon der zuletzt eingetragene Wert, daneben angezeigte Dauer (hier 3 Stunden)
(und: ja, bin mit dem Sensor nicht sonderlich zufrieden)

MfG

GELÖST

1.Problem
Ich glaube ich habe es jetzt verstanden, wie man durch die Systemzeit Zeitversetzt ohne Delay aktionen ausführt. Danke nochmal für die Hilfe! Nochmal für die Akten der Code:

const int pwPin1 = 8; // HC-MaxSonar: 
float Distance; // HC-MaxSonar: to narrow the Distance

#define RedPin 5 // LED RGB Stripe 
#define GreenPin 6 // LED RGB Stripe 
#define BluePin 3 // LED RGB Stripe 

#define SoundPin 2 // KY-038 Microphone Sound Sensor

volatile int Sound = 0; // KY-038 Microphone Sound Sensor
volatile int counter = 0;

volatile long int TimeStamp; // Merker fuer millis()

void setup() {

  Serial.begin(115200);

  pinMode(pwPin1, INPUT);

  pinMode(RedPin, OUTPUT); // LED RGB Stripe
  pinMode(GreenPin, OUTPUT); // LED RGB Stripe
  pinMode(BluePin, OUTPUT); // LED RGB Stripe

  pinMode(SoundPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(SoundPin), ColorChange, HIGH);

  TimeStamp = millis();

}

void loop() {
// ++++++++++++++++++++++++++++++++++++++++++++ Distance measurement
  Distance = pulseIn(pwPin1, HIGH); // MaxSonar: The DistanceArea here 1m
  int DistanceArea = constrain(Distance, 0, 10000); // MaxSonar: The DistanceArea here 1m
  DistanceArea = runningAverage(DistanceArea); // MaxSonar: the mix between the last and the current value to prevent big light difference
  int Brightness = map(DistanceArea, 10000, 0, 0, 255); // MaxSonar: the correlation between distance and light

  // ++++++++++++++++++++++++++++++++++++++++++++ Clap measurement

  // ++++++++++++++++++++++++++++++++++++++++++++ LED brightness

  switch (counter) {

    case 1:
      analogWrite(BluePin, Brightness);
      analogWrite(GreenPin, 0);
      analogWrite(RedPin, 0);
      Serial.print("ColorBlue"); Serial.println();
      Serial.print("Distance"); Serial.println(Brightness);
      break;

    case 2:
      analogWrite(BluePin, 0);
      analogWrite(GreenPin, Brightness);
      analogWrite(RedPin, 0);

      Serial.print("ColorGreen"); Serial.println();
      Serial.print("Distance"); Serial.println(Brightness);
      break;

    case 3:
      analogWrite(BluePin, 0);
      analogWrite(GreenPin, 0);
      analogWrite(RedPin, Brightness);
      Serial.print("ColorRed"); Serial.println();
      Serial.print("Distance"); Serial.println(Brightness);
      break;

    default:
      analogWrite(BluePin, Brightness);
      analogWrite(GreenPin, Brightness);
      analogWrite(RedPin, Brightness);
      Serial.print("ColorWhite"); Serial.println();
      Serial.print("Distance"); Serial.println(Distance);
      break;

  }

}

void ColorChange() {
  while (millis() - TimeStamp > 300) {

    Serial.println("ColorChange");
    if (counter < 4) {

      counter = counter + 1;
    } // KY-038: count 1

    if (counter == 4) {

      counter = 0;
    }
  TimeStamp = millis();
  }
}

// ++++++++++++++++++++++++++++++++++++++++++++ runningAverage

long runningAverage(int M) {
#define LM_SIZE 3
  static int LM[LM_SIZE];      // LastMeasurements
  static byte index = 0;
  static long sum = 0;
  static byte count = 0;

  // keep sum updated to improve speed.
  sum -= LM[index];
  LM[index] = M;
  sum += LM[index];
  index++;
  index = index % LM_SIZE;
  if (count < LM_SIZE) count++;

  return sum / count;
}
  1. Problem:
    Wichte Erkenntnis: Der Preis macht es!

Habe mir jetzt bei MaxBotix ein Sensor für ca. 50 Euro gekauft und es klappt recht gut, der ist Super schnell, ich brauche nicht irgendwelche Medians, Mittelwerte oder andere verzögernde Mehrfachmessungen verwenden.

Natürlich wenn jemand einen Tip hat, wo man einen ähnlichen für Günstiger bekommt, würde ich den Rat gerne annehmen.

Der hat ja einen Mindestabstand von 20 cm. Wenn Dir 25 cm auch genügen Amazon oder direkt aus China.
Ich habe aber keine Untersuchungen damit angestellt.

Gruß Tommy