Einparksensor: LEDs ausschalten nach Zeitraum X

Hallo zusammen,

auf der folgenden Webseite bin ich auf ein cooles Projekt gestoßen, dass ich gut gebrauchen könnte. Hierbei geht es um eine Einparkhilfe für die Garage, im Zusammenspiel mit dem Arduino, dem VL53L0X und einem WS2812B LED-Ring:

Arduino Einparkhilfe mit VL53L0X IR Laser Entfernungssensor und WS2812B NeoPixels – Makerblog.at

Hier der dahinter liegende Sketch:

/* Parkhilfe mit VL53L0X
 * Weitere Infos und Tutorial auf https://www.makerblog.at
 *  
 * Einparkhilfe z.B. zur fixen Montage an der rückseitigen Garagenwand,
 * misst den Abstand zwischen Sensor und Objekt (Auto) und visualisiert die 
 * korrekte Einparkposition mit WS2812B RGB LEDs
 * 
 *  
 * Setup: 
 * 
 * - Arduino Uno
 * 
 * - VL53LX0 Laser Sensor
 *   - Arduino 5V an Sensor VIN
 *   - Arduino GND an Sensor GND
 *   - Arduino A4 an Sensor SDA (I2C Data)
 *   - Arduino A5 an Sensor SCL (I2C Clock)
 * 
 * - WS2812B RGB LED Stripe
 *   - Arduino D6 über 220Ohm Widerstand an LED Data In
 *   - Stromversorgung über Arduino bei wenigen LEDs oder
 *     mit eigener Stromquelle an +/- des LED Stripes
 *     Achtung: Kondensator zwischen 5V und GND
 *     Siehe Tutorials zu WS2812B Neopixel LEDs
 * 
*/
 
// Libraries für I2C, Sensor und RGB LEDs einbinden. Alle Bibliotheken
// können über den Library Manager der Arduino IDE installiert werden
#include "Wire.h"
#include "VL53L0X.h"
#include "Adafruit_NeoPixel.h"
 
// Sensorobjekt
VL53L0X distanceSensor;
 
// Datenpin für den WS2812B LED Streifen
#define LEDPIN 6
#define LEDCOUNT 16
 
#define RANGESTARTMM 200
#define RANGEENDMM 50
 
#define ORANGESTARTLED 12
#define REDSTARTLED 16
 
// LEDs initialisieren
// in diesem Fall 16 LEDs mit den Adressen 0 bis 15
Adafruit_NeoPixel strip = Adafruit_NeoPixel(LEDCOUNT, LEDPIN, NEO_GRB + NEO_KHZ800);
 
// Standardfarben für die LEDs definieren
uint32_t rgbRed = strip.Color(255,0,0);
uint32_t rgbOrange = strip.Color(255,90,0);
uint32_t rgbGreen = strip.Color(0,255,0);
uint32_t rgbBlack = strip.Color(0,0,0);
uint32_t activeColor = rgbBlack;
 
 
void setup()
{
  Serial.begin(9600);
  Wire.begin();
 
  // Distanzsensor initialisieren und konfigurieren
  distanceSensor.setTimeout(500);
  if (!distanceSensor.init())
  {
    Serial.println("VL53L0X Sensor nicht gefunden! Ablauf angehalten.");
    while (1) {}
  }
  // Sensor auf 10 Messungen pro Sekunde
  distanceSensor.setMeasurementTimingBudget(100000);
 
  // LED Streifen starten und Helligkeit setzen
  strip.begin();
  strip.setBrightness(100); // Helligkeit 0-255
  strip.show(); 
 
}
 
void loop()
{
  // Entfernung in mm lesen
  int dist = distanceSensor.readRangeSingleMillimeters();
  // Falls TIMEOUT dann Fehler seriell ausgeben und dist auf 0 setzen
  if (distanceSensor.timeoutOccurred()) { 
    Serial.println("TIMEOUT");
    dist = 0;
  }
 
  int lastPixel = 0;
 
  // Sensorbereich in mm in Anzahl der LEDs umwandeln, im Beispiel
  // den Bereich von 50mm bis 200mm auf die LEDs 16 bis 0 mappen
  // D.h. bei bei dist=200 ist lastPixel = 0, bei dist=50 ist
  // lastPixel = 16 und der Wertebereich dazwischen wird ebenfalls
  // richtig umgerechnet.
  // ACHTUNG: eine Range von 50-200mm ist zum Testen auf dem Schreibtisch,
  // in der Garage passen Werte zwischen 500 und 2000mm besser :)
  // Mit den Konstanten ersetzt heisst diese Zeile
  // lastPixel = map(dist, 50, 200, 15, 0);
 
  lastPixel = map(dist, RANGEENDMM, RANGESTARTMM, LEDCOUNT-1, 0);
 
  // Zur Kontrolle Ausgabe der Distanz und der ermittelten LED
  // am seriellen Monitor
  Serial.print("dist = ");
  Serial.print(dist);
  Serial.print(" => ");
  Serial.print("lastPixel = ");
  Serial.println(lastPixel);
 
  // Alle LEDs löschen (= auf schwarz setzen)
  for (int i=0; i< LEDCOUNT; i++) {
    strip.setPixelColor(i, rgbBlack);    
  }
 
  // Entsprechend der Anzahl der aktiven LEDs ändert
  // ändert sich auch die Farbe aller LEDs
  if (lastPixel >= REDSTARTLED) {
    activeColor = rgbRed;
  } else if (lastPixel >= ORANGESTARTLED) {
    activeColor = rgbOrange;
  } else if (lastPixel >= 0) {
    activeColor = rgbGreen;
  } else {
    activeColor = rgbBlack;
  }
 
  // Wenn lastPixel >= LEDCOUNT dann auf LEDCOUNT-1 setzen
  if (lastPixel >= LEDCOUNT) {
    lastPixel = LEDCOUNT-1;
  }
 
  // Nummerierung der LEDs beginnt bei 0!
  for (int i=0; i<= lastPixel; i++) {
      strip.setPixelColor(i, activeColor);    
  }
 
  // LEDs aktualisieren
  strip.show();
 
}

Ich möchte das gerne genau so umsetzen. Für mich stellt sich nur die Frage: Was passiert mit den LEDs, wenn das Auto eingeparkt wurde? Leuchten dann die LEDs die ganze Nacht durch?
Ich würde es gerne so machen, dass sich die LEDs nur dann einschalten / ändern, wenn eine Bewegung erkannt wird. Meine Idee daher:

  • Wenn sich das lastPixel für einen Zeitraum von 2 Minuten nicht geändert hat -> schalte LEDs auf schwarz.

  • Wenn sich das lastPixel im Zeitraum von 2 Minuten geändert hat -> aktualisiere die LEDs.

Macht das Sinn? Würdet ihr das anders lösen?
Ich bin nur zu doof das im Sketch entsprechend zu ändern. Vom Ersteller habe ich bisher leider keine Rückmeldung erhalten, daher frage ich hier nach.

Hallo,
du zählst nach dem Einschalten der Leds und "ohne weitere Bewegung" mit millis() die Zeit und schaltest nach Ablauf der gewünschten Zeit die Leds aus.

Du kannst es so machen:

#include <Wire.h>
#include <Adafruit_NeoPixel.h>

//#define TOF   // Comment out this line if the VL53L0X sensor is to be used.

#ifdef TOF
#include <VL53L0X.h>
#define LONG_RANGE
#endif

//
// Definitions, Constants, global variables
//
constexpr bool DEBUG {true};   // false to disable the debug output

class Timer {
public:
  void start() { timeStamp = millis(); }
  bool operator()(const unsigned long duration) const { return (millis() - timeStamp >= duration) ? true : false; }

private:
  unsigned long timeStamp {0};
};

struct ColorSegment {
  uint32_t check(uint16_t ledNum) const { return (ledNum < from || ledNum > to) ? 0 : color; }

  const uint8_t from;
  const uint8_t to;
  const uint32_t color;
};

#ifndef TOF
constexpr uint8_t R_ECHOPIN {9};
constexpr uint8_t R_TRIGPIN {8};
#endif

constexpr uint16_t MAX_DISTANCE_THESHOLD {170};   // Maximum specified measuring range (especially for the VL53L0X)
constexpr uint16_t DISTANCE_HYSTERESIS {5};

// Data pin for the WS2812B LED leds
constexpr uint8_t LEDPIN {6};
constexpr uint8_t MAX_LEDS {16};

constexpr uint16_t RANGESTARTMM {150};   // Range in cm
constexpr uint16_t RANGEENDMM {10};      // Range in cm

// initialize LEDs
// in this case 16 LEDs with addresses 0 to 15
Adafruit_NeoPixel ledStrip = Adafruit_NeoPixel(MAX_LEDS, LEDPIN, NEO_GRB + NEO_KHZ800);

// constexpr uint32_t MAX_LIGHT_DURATION {1000 * 60 * 2};  // 2 Minutes
constexpr uint32_t MAX_LIGHT_DURATION {10000};

// Sensorobject
#ifdef TOF
VL53L0X distanceSensor;
#endif

Timer timer;

 // 16 LEDs
ColorSegment colorSegments[] {
    {0,  7,        0xFF00  }, // Green
    {8,  11,       0xFFA500}, // Orange
    {12, MAX_LEDS, 0xFF0000}  // Red
};

 // 12 LEDs
// ColorSegment colorSegments[] {
//     {0, 5,        0xFF00  }, // Green
//     {6, 8,        0xFFA500}, // Orange
//     {9, MAX_LEDS, 0xFF0000}  // Red
// };

//
// Functions
//
void printDistPix(int16_t dist, int8_t pix) {
  Serial.print(F("distance = "));
  Serial.print(dist);
  Serial.print(" => ");
  Serial.print(F("lastPixel = "));
  Serial.println(pix);
}

#ifdef TOF
uint16_t checkDistance(VL53L0X &sensor) {
  // Read distance in mm
  uint16_t dist = sensor.readRangeSingleMillimeters();
  // If TIMEOUT then output error serially and set dist to 0
  if (distanceSensor.timeoutOccurred()) {
    Serial.println("TIMEOUT");
    dist = 0;
  }
  return dist / 10; // Return cm
}
#else
uint16_t checkDistance(uint8_t trig, uint8_t echo) {
  digitalWrite(trig, HIGH);
  delayMicroseconds(10);
  digitalWrite(trig, LOW);
  return static_cast<uint16_t>(pulseIn(echo, HIGH) / 58);
}
#endif

template <size_t ITEMS> void setLeds(Adafruit_NeoPixel &leds, ColorSegment (&cs)[ITEMS], int8_t ledNum) {
  leds.clear();   //  Fill the whole NeoPixel leds with 0 / black / off
  if (ledNum > MAX_LEDS - 1) { ledNum = MAX_LEDS - 1; }
  if (ledNum > -1) {
    for (auto &c : cs) {
      auto activeColor = c.check(ledNum);
      if (activeColor) {
        for (auto i = 0; i <= ledNum; ++i) { leds.setPixelColor(i, activeColor); }
        break;
      }
    }
  }
  leds.show();   // Update LEDs
}

//
// Main program
//
void setup() {
  if (DEBUG) { Serial.begin(74880); }
  Wire.begin();
#ifdef TOF
  // Initialize and configure distance sensor
  if (!distanceSensor.init()) {
    if(DEBUG) { Serial.println(F("VL53L0X Sensor nicht gefunden! Ablauf angehalten.")); }
    while (1) {}
  }
  distanceSensor.setTimeout(500);
  distanceSensor.setMeasurementTimingBudget(100000);
  distanceSensor.setSignalRateLimit(0.1);
  distanceSensor.setVcselPulsePeriod(VL53L0X::VcselPeriodPreRange, 18);
  distanceSensor.setVcselPulsePeriod(VL53L0X::VcselPeriodFinalRange, 14);
#else
  // Configure HC-SR04
  pinMode(R_TRIGPIN, OUTPUT);
  pinMode(R_ECHOPIN, INPUT);
#endif
  // Start LED ring and set brightness
  ledStrip.begin();
  ledStrip.setBrightness(100);   // Brightness 0-255
  ledStrip.show();
}

void loop() {
  static uint16_t prevDistance {0};
  static bool isTurnedOn {false};
#ifdef TOF
  uint16_t distance {checkDistance(distanceSensor)};
#else
  uint16_t distance {checkDistance(R_TRIGPIN, R_ECHOPIN)};
#endif
  // Limitation of the measuring range (distance), prevents unwanted led flickering
  if (distance < MAX_DISTANCE_THESHOLD && prevDistance != distance) {
    // Use a hysteresis to prevent a possible flickering of the LEDs
    if (abs(prevDistance - distance) > DISTANCE_HYSTERESIS) {
      prevDistance = distance;
      int8_t lastPixel = map(distance, RANGEENDMM, RANGESTARTMM, MAX_LEDS - 1, 0);
      if (DEBUG) { printDistPix(distance, lastPixel); }
      setLeds(ledStrip, colorSegments, lastPixel);
      timer.start();
      isTurnedOn = true;
    }
  }

  // Turn off LEDs when the timer has run out.
  if (timer(MAX_LIGHT_DURATION) && isTurnedOn) {
    if (DEBUG) { Serial.println(F("Switch Off")); }
    ledStrip.clear();
    ledStrip.show();
    isTurnedOn = false;
  }
}

Dieses Beispiel ist zwar mit einem HC-SR04 umgesetzt, wenn die Kommentarzeichen der Zeile 4 entfernt werden (//#define TOF) , verwendet das Programm den VL53L0X als Sensor.

Hier das Beispiel zum Ausprobieren:

Nach dem Start der Simulation kann durch einen Klick auf den Ultraschallsensor der gemessene Entfernungswert geändert werden. Ändert sich die Entfernung nicht innerhalb von 10 Sekunden, werden die LEDs schwarz geschaltet (aus).

Für eine Leuchtdauer von zwei Minuten müsste halt der Wert MAX_LIGHT_DURATION
von 10.000 auf 1000 * 60 * 2 = 120.000 Millisekunden geändert werden

kompiliert fehler und warnungsfrei.
Ohne Grantie

/* Parkhilfe mit VL53L0X
   Weitere Infos und Tutorial auf https://www.makerblog.at

   Einparkhilfe z.B. zur fixen Montage an der rückseitigen Garagenwand,
   misst den Abstand zwischen Sensor und Objekt (Auto) und visualisiert die
   korrekte Einparkposition mit WS2812B RGB LEDs


   Setup:

   - Arduino Uno

   - VL53LX0 Laser Sensor
     - Arduino 5V an Sensor VIN
     - Arduino GND an Sensor GND
     - Arduino A4 an Sensor SDA (I2C Data)
     - Arduino A5 an Sensor SCL (I2C Clock)

   - WS2812B RGB LED Stripe
     - Arduino D6 über 220Ohm Widerstand an LED Data In
     - Stromversorgung über Arduino bei wenigen LEDs oder
       mit eigener Stromquelle an +/- des LED Stripes
       Achtung: Kondensator zwischen 5V und GND
       Siehe Tutorials zu WS2812B Neopixel LEDs

*/

// Libraries für I2C, Sensor und RGB LEDs einbinden. Alle Bibliotheken
// können über den Library Manager der Arduino IDE installiert werden
#include "Wire.h"
#include "VL53L0X.h"
#include "Adafruit_NeoPixel.h"

// Sensorobjekt
VL53L0X distanceSensor;

// Datenpin für den WS2812B LED Streifen
#define LEDPIN 6
#define LEDCOUNT 16

#define RANGESTARTMM 200
#define RANGEENDMM 50

#define ORANGESTARTLED 12
#define REDSTARTLED 16

// LEDs initialisieren
// in diesem Fall 16 LEDs mit den Adressen 0 bis 15
Adafruit_NeoPixel strip = Adafruit_NeoPixel(LEDCOUNT, LEDPIN, NEO_GRB + NEO_KHZ800);

// Standardfarben für die LEDs definieren
uint32_t rgbRed = strip.Color(255, 0, 0);
uint32_t rgbOrange = strip.Color(255, 90, 0);
uint32_t rgbGreen = strip.Color(0, 255, 0);
uint32_t rgbBlack = strip.Color(0, 0, 0);
uint32_t activeColor = rgbBlack;


uint32_t savedTime;
int savedPixel;

void setup()
{
  Serial.begin(9600);
  Wire.begin();
  // Distanzsensor initialisieren und konfigurieren
  distanceSensor.setTimeout(500);
  if (!distanceSensor.init())
  {
    Serial.println("VL53L0X Sensor nicht gefunden! Ablauf angehalten.");
    while (1) {}
  }
  // Sensor auf 10 Messungen pro Sekunde
  distanceSensor.setMeasurementTimingBudget(100000);
  // LED Streifen starten und Helligkeit setzen
  strip.begin();
  strip.setBrightness(100); // Helligkeit 0-255
  strip.show();
}

void loop()
{
  // Entfernung in mm lesen
  int dist = distanceSensor.readRangeSingleMillimeters();
  // Falls TIMEOUT dann Fehler seriell ausgeben und dist auf 0 setzen
  if (distanceSensor.timeoutOccurred())
  {
    Serial.println("TIMEOUT");
    dist = 0;
  }
  int lastPixel = 0;
  // Sensorbereich in mm in Anzahl der LEDs umwandeln, im Beispiel
  // den Bereich von 50mm bis 200mm auf die LEDs 16 bis 0 mappen
  // D.h. bei bei dist=200 ist lastPixel = 0, bei dist=50 ist
  // lastPixel = 16 und der Wertebereich dazwischen wird ebenfalls
  // richtig umgerechnet.
  // ACHTUNG: eine Range von 50-200mm ist zum Testen auf dem Schreibtisch,
  // in der Garage passen Werte zwischen 500 und 2000mm besser :)
  // Mit den Konstanten ersetzt heisst diese Zeile
  // lastPixel = map(dist, 50, 200, 15, 0);
  lastPixel = map(dist, RANGEENDMM, RANGESTARTMM, LEDCOUNT - 1, 0);
  if (lastPixel != savedPixel)
  {
    savedTime = millis();
    savedPixel = lastPixel;
  }
  // Zur Kontrolle Ausgabe der Distanz und der ermittelten LED
  // am seriellen Monitor
  Serial.print("dist = ");
  Serial.print(dist);
  Serial.print(" => ");
  Serial.print("lastPixel = ");
  Serial.println(lastPixel);
  // Alle LEDs löschen (= auf schwarz setzen)
  for (int i = 0; i < LEDCOUNT; i++)
  {
    strip.setPixelColor(i, rgbBlack);
  }
  // Entsprechend der Anzahl der aktiven LEDs ändert
  // ändert sich auch die Farbe aller LEDs
  if (millis() - savedTime < 5000)
  {
    if (lastPixel >= REDSTARTLED)
    {
      activeColor = rgbRed;
    }
    else if (lastPixel >= ORANGESTARTLED)
    {
      activeColor = rgbOrange;
    }
    else if (lastPixel >= 0)
    {
      activeColor = rgbGreen;
    }
    else
    {
      activeColor = rgbBlack;
    }
  }
  else
  { activeColor = rgbBlack; }
  // Wenn lastPixel >= LEDCOUNT dann auf LEDCOUNT-1 setzen
  if (lastPixel >= LEDCOUNT)
  {
    lastPixel = LEDCOUNT - 1;
  }
  // Nummerierung der LEDs beginnt bei 0!
  for (int i = 0; i <= lastPixel; i++)
  {
    strip.setPixelColor(i, activeColor);
  }
  // LEDs aktualisieren
  strip.show();
}

Ich habe auch gerade eine Garageneinparkhilfe für meine Frau bauen wollen. Habe die Abstandsmessung gestern mit eine Ultraschall Sensor getestet, aber das war negativ. Also wieder raus mit dem Ding und einen VL53LOX rein. Das Programm hier eingespielt, ein paar Definitionen angepasst und läuft zu ersten Zufriedenheit. Jedenfalls am Scheibtisch. Der Test in der Garage kommt später, weil meine Chefin mit dem Auto unterwegs ist.

Das Beispiel auf wokwi ist nur deshalb mit einem Ultraschallsensor realisiert, um das Funktionsprinzip des Codes zu zeigen und wokwi keinen TOF Sensor anbietet.

Der dort verlinkte Beispielcode funktioniert aber mit mit beiden Sensoren. Man muss lediglich ein #define auskommentieren, dann ist er 1 zu 1 für VL530X verwendbar.

Ja, in dem Fall ist US unmöglich. Wenn das Messziel nicht sauber in 90 Grad zur Schallquelle ist, dann verdreifacht oder vervierfacht sich die Messung, weil der Schall dann wohl erst einen Weg über ein paar Banden nimmt, bevor er zufällig ankommt :grinning:

da ich noch einige VL53L0X da liegen hatte, habe ich heute gleich umgebaut. Die Messungen sind damit recht genau. Wie es sich bei Autolack mit der Reflektion verhält, teste ich morgen mal. Aber bin sehr zuversichlich, dass das gut geht.

Franz

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.