Zwei ToF Sensoren sollen zwei Abschnitte eines RGBW LED Strips ansteuern

Hallo zusammen,

ich bin ein Arduino- und Programmieranfänger. Ich habe mir folgende Idee in den Kopf gesetzt und benötige nun eure Hilfe:

Ich baue einen LED Streifen auf eine Fußsockelleiste und möchte nun, dass an der Stelle an der ich stehe der LED-Strip an geht.

Bisher habe ich hierfür zwei VL53L0X ToF Sensoren (SDA an PIN A4 und SCL an PIN A5) hintereinander geschaltet. Und meinen RGBW LED Strip an PIN 3 eingesteckt.

Mein bisheriger Code kann nun eine anfängliche Initialmessung durchführen und diese Maximaldistanzen (je eine pro ToF Sensor) in einem Array abspeichern. Nun wird kontinuierlich weiterhin die aktuelle Distanz gemessen.

Und nun komme ich an meine Grenzen: Ich möchte, dass wenn die Maximaldistanz von Sensor 1 durch die aktuell gemessene Distanz von Sensor 1 unterschritten wird, dass die LEDs 0 bis 31 warm weiß leuchten. Parallel und unabhängig von dem gerade beschrieben Vorgang sollen die LEDs 32 bis 72 warm weiß leuchten, wenn die Maximaldistanz von Sensor 2 durch die aktuell gemessene Distanz von Sensor 2 unterschritten wird.

Anbei mein bisheriger Code:

#include <Wire.h>
#include <Adafruit_VL53L0X.h>

#define FIRST_SENSOR_ADDRESS 0x31
#define SECOND_SENSOR_ADDRESS 0x32
#define MEASUREMENT_INTERVAL 300000 // Messintervall in Millisekunden (5 Minuten)

Adafruit_VL53L0X sensor1, sensor2;
uint16_t maxDistances[2]; // Array zur Speicherung der Maximaldistanzen

void setup() {
  Serial.begin(9600);
  Wire.begin();

  if (!sensor1.begin(FIRST_SENSOR_ADDRESS)) {
    Serial.println("Unable to find VL53L0X sensor 1");
    while (1);
  }

  if (!sensor2.begin(SECOND_SENSOR_ADDRESS)) {
    Serial.println("Unable to find VL53L0X sensor 2");
    while (1);
  }

  // Erhöhe die Messdauer für jedes Messintervall
  sensor1.setMeasurementTimingBudgetMicroSeconds(50000); // Beispielwert, experimentiere mit unterschiedlichen Werten
  sensor2.setMeasurementTimingBudgetMicroSeconds(50000); // Beispielwert, experimentiere mit unterschiedlichen Werten

  // Führe die Initialmessung durch
  performInitialMeasurement();

  delay(500);
}

void loop() {
  // Führe Messung durch
  VL53L0X_RangingMeasurementData_t measure1, measure2;
  sensor1.rangingTest(&measure1, false);
  sensor2.rangingTest(&measure2, false);

  // Gib die aktuellen Messwerte und abgespeicherten Maximaldistanzen aus
  printMeasurements(measure1, measure2);

  delay(1000);
}

void performInitialMeasurement() {
  // Führe die Initialmessung durch und speichere die Maximaldistanzen
  VL53L0X_RangingMeasurementData_t measure1, measure2;
  sensor1.rangingTest(&measure1, false);
  sensor2.rangingTest(&measure2, false);

  maxDistances[0] = measure1.RangeMilliMeter;
  maxDistances[1] = measure2.RangeMilliMeter;
}

void printMeasurements(VL53L0X_RangingMeasurementData_t measure1, VL53L0X_RangingMeasurementData_t measure2) {
  // Überprüfe und aktualisiere Maximaldistanzen alle 5 Minuten
  static uint32_t lastUpdateTime = 0;
  if (millis() - lastUpdateTime >= MEASUREMENT_INTERVAL) {
    lastUpdateTime = millis();
    performInitialMeasurement();
  }

  // Gib die aktuellen Messwerte und abgespeicherten Maximaldistanzen aus
  Serial.print("Sensor 1: ");
  if (measure1.RangeStatus != 4) {
    Serial.print(measure1.RangeMilliMeter);
    Serial.print(" mm");
  } else {
    Serial.print("Out of range");
  }

  Serial.print("\tMaximaldistanz 1: ");
  Serial.print(maxDistances[0]);
  Serial.print(" mm");

  Serial.print("\tSensor 2: ");
  if (measure2.RangeStatus != 4) {
    Serial.print(measure2.RangeMilliMeter);
    Serial.print(" mm");
  } else {
    Serial.print("Out of range");
  }

  Serial.print("\tMaximaldistanz 2: ");
  Serial.print(maxDistances[1]);
  Serial.println(" mm");
}

Ich hoffe ihr könnt mir weiterhelfen und bedanke mich vorab schonmal!

Viele Grüße iDalux

zeige was für einen

BTF-LIGHTING RGBW RGBWW Warmweiß SK6812 5m 60LEDs/Pixels/m 300LEDs Individuell adressierbar Flexibel RGB+Warm White 4 farbe in 1 LED Traumfarbe LED Streifen Nicht wasserdicht IP30 DC5V [Energieklasse F]

dann sollst du eine Bibliothek nutzen, wie FastLED oder NeoPixel

Das ist mir auch klar. Ich habe es auch schon geschafft, dass Sensor 1 auf die LEDs 0 - 31 zugreift. Aber als ich dann mit Sensor zwei die LEDs 32- 72 ansteuern wollte ging garnichts mehr.

zeige

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

#define FIRST_SENSOR_ADDRESS 0x31
#define SECOND_SENSOR_ADDRESS 0x32
#define MEASUREMENT_INTERVAL 300000 // Messintervall in Millisekunden (5 Minuten)
#define NUM_LEDS 72
#define LED_PIN 3

Adafruit_VL53L0X sensor1, sensor2;
uint16_t maxDistances[2]; // Array zur Speicherung der Maximaldistanzen
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LEDS, LED_PIN, NEO_GRBW + NEO_KHZ800);

void setup() {
  Serial.begin(9600);
  Wire.begin();

  if (!sensor1.begin(FIRST_SENSOR_ADDRESS)) {
    Serial.println("Unable to find VL53L0X sensor 1");
    while (1);
  }

  if (!sensor2.begin(SECOND_SENSOR_ADDRESS)) {
    Serial.println("Unable to find VL53L0X sensor 2");
    while (1);
  }

  // Erhöhe die Messdauer für jedes Messintervall
  sensor1.setMeasurementTimingBudgetMicroSeconds(50000); // Beispielwert, experimentiere mit unterschiedlichen Werten
  sensor2.setMeasurementTimingBudgetMicroSeconds(50000); // Beispielwert, experimentiere mit unterschiedlichen Werten

  // Führe die Initialmessung durch
  performInitialMeasurement();

  // NeoPixel-Strip initialisieren
  strip.begin();
  strip.show(); // Initialize all pixels to 'off'
  delay(500);
}

void loop() {
  // Führe Messung durch
  VL53L0X_RangingMeasurementData_t measure1, measure2;
  sensor1.rangingTest(&measure1, false);
  sensor2.rangingTest(&measure2, false);

  // Überprüfe und aktualisiere Maximaldistanzen
  updateMaxDistances(measure1.RangeMilliMeter, measure2.RangeMilliMeter);

  // Überprüfe, ob die aktuelle Distanz von Sensor 1 die abgespeicherte Maximaldistanz unterschreitet
  if (measure1.RangeMilliMeter < maxDistances[0]) {
    // Schalte die LEDs 1 bis 31 in PIN 3 warm weiß ein
    activateLEDsWarmWhite(0, 31);
  } else {
    // Schalte die LEDs 1 bis 31 in PIN 3 aus
    deactivateLEDs(0, 31);
  }

  // Überprüfe, ob die aktuelle Distanz von Sensor 2 die abgespeicherte Maximaldistanz unterschreitet
  if (measure2.RangeMilliMeter < maxDistances[1]) {
    // Schalte die LEDs 32 bis 72 in PIN 3 warm weiß ein
    activateLEDsWarmWhite(31, 71);
  } else {
    // Schalte die LEDs 32 bis 72 in PIN 3 aus
    deactivateLEDs(31, 71);
  }

  // Gib die aktuellen Messwerte aus
  printMeasurements(measure1, measure2);

  delay(1000);
}

void performInitialMeasurement() {
  // Führe die Initialmessung durch und speichere die Maximaldistanzen
  VL53L0X_RangingMeasurementData_t measure1, measure2;
  sensor1.rangingTest(&measure1, false);
  sensor2.rangingTest(&measure2, false);

  maxDistances[0] = measure1.RangeMilliMeter;
  maxDistances[1] = measure2.RangeMilliMeter;
}

void updateMaxDistances(uint16_t distance1, uint16_t distance2) {
  // Aktualisiere die Maximaldistanzen, falls eine größere Distanz gemessen wurde
  if (distance1 > maxDistances[0]) {
    maxDistances[0] = distance1;
  }

  if (distance2 > maxDistances[1]) {
    maxDistances[1] = distance2;
  }

  // Aktualisiere die Maximaldistanzen alle 5 Minuten
  static uint32_t lastUpdateTime = 0;
  if (millis() - lastUpdateTime >= MEASUREMENT_INTERVAL) {
    lastUpdateTime = millis();
    performInitialMeasurement();
  }
}

void printMeasurements(VL53L0X_RangingMeasurementData_t measure1, VL53L0X_RangingMeasurementData_t measure2) {
  // Gib die aktuellen Messwerte aus
  Serial.print("Sensor 1: ");
  if (measure1.RangeStatus != 4) {
    Serial.print(measure1.RangeMilliMeter);
    Serial.print(" mm");
  } else {
    Serial.print("Out of range");
  }

  Serial.print("\tSensor 2: ");
  if (measure2.RangeStatus != 4) {
    Serial.print(measure2.RangeMilliMeter);
    Serial.print(" mm");
  } else {
    Serial.print("Out of range");
  }

  Serial.println();
}

void activateLEDsWarmWhite(int start, int end) {
  // Schalte die LEDs in PIN 3 warm weiß ein
  for (int i = start; i <= end; i++) {
    strip.setPixelColor(i, strip.Color(255, 190, 125)); // Warmes Weiß
  }
  strip.show();
}

void deactivateLEDs(int start, int end) {
  // Schalte die LEDs in PIN 3 aus
  for (int i = start; i <= end; i++) {
    strip.setPixelColor(i, strip.Color(0, 0, 0, 0)); // Aus
  }
  strip.show();
}

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

#define FIRST_SENSOR_ADDRESS 0x31
#define SECOND_SENSOR_ADDRESS 0x32
#define MEASUREMENT_INTERVAL 300000 // Messintervall in Millisekunden (5 Minuten)
#define NUM_LEDS 72
#define LED_PIN 3

Adafruit_VL53L0X sensor1, sensor2;
uint16_t maxDistances[2]; // Array zur Speicherung der Maximaldistanzen
Adafruit_NeoPixel strip(NUM_LEDS, LED_PIN, NEO_GRBW + NEO_KHZ800);

void setup() {
  Serial.begin(9600);
  Wire.begin();

  if (!sensor1.begin(FIRST_SENSOR_ADDRESS)) {
    Serial.println("Unable to find VL53L0X sensor 1");
    while (1);
  }

  if (!sensor2.begin(SECOND_SENSOR_ADDRESS)) {
    Serial.println("Unable to find VL53L0X sensor 2");
    while (1);
  }

  // Erhöhe die Messdauer für jedes Messintervall
  sensor1.setMeasurementTimingBudgetMicroSeconds(50000); // Beispielwert, experimentiere mit unterschiedlichen Werten
  sensor2.setMeasurementTimingBudgetMicroSeconds(50000); // Beispielwert, experimentiere mit unterschiedlichen Werten

  // Führe die Initialmessung durch
  performInitialMeasurement();

  // NeoPixel-Strip initialisieren
  strip.begin();
  strip.show(); // Initialize all pixels to 'off'
  delay(500);
}

void loop() {
  // Führe Messung durch
  VL53L0X_RangingMeasurementData_t measure1, measure2;
  sensor1.rangingTest(&measure1, false);
  sensor2.rangingTest(&measure2, false);

  // Überprüfe und aktualisiere Maximaldistanzen
  updateMaxDistances(measure1.RangeMilliMeter, measure2.RangeMilliMeter);

  // Überprüfe, ob die aktuelle Distanz von Sensor 1 die abgespeicherte Maximaldistanz unterschreitet
  if (measure1.RangeMilliMeter < maxDistances[0])activateLEDsWarmWhite(0);   // Schalte die LEDs 1 bis 36  warm weiß ein
  else deactivateLEDs(0);    // Schalte die LEDs 1 bis 36  aus

  // Überprüfe, ob die aktuelle Distanz von Sensor 2 die abgespeicherte Maximaldistanz unterschreitet
  if (measure2.RangeMilliMeter < maxDistances[1])activateLEDsWarmWhite(36);   // Schalte die LEDs 37 bis 72  warm weiß ein
  else deactivateLEDs(36);   // Schalte die LEDs 37 bis 72  aus


  // Gib die aktuellen Messwerte aus
  printMeasurements(measure1, measure2);

  delay(1000);
}

void performInitialMeasurement() {
  // Führe die Initialmessung durch und speichere die Maximaldistanzen
  VL53L0X_RangingMeasurementData_t measure1, measure2;
  sensor1.rangingTest(&measure1, false);
  sensor2.rangingTest(&measure2, false);

  maxDistances[0] = measure1.RangeMilliMeter;
  maxDistances[1] = measure2.RangeMilliMeter;
}

void updateMaxDistances(uint16_t distance1, uint16_t distance2) {
  // Aktualisiere die Maximaldistanzen, falls eine größere Distanz gemessen wurde
  if (distance1 > maxDistances[0]) {
    maxDistances[0] = distance1;
  }

  if (distance2 > maxDistances[1]) {
    maxDistances[1] = distance2;
  }

  // Aktualisiere die Maximaldistanzen alle 5 Minuten
  static uint32_t lastUpdateTime = 0;
  if (millis() - lastUpdateTime >= MEASUREMENT_INTERVAL) {
    lastUpdateTime = millis();
    performInitialMeasurement();
  }
}

void printMeasurements(VL53L0X_RangingMeasurementData_t measure1, VL53L0X_RangingMeasurementData_t measure2) {
  // Gib die aktuellen Messwerte aus
  Serial.print("Sensor 1: ");
  if (measure1.RangeStatus != 4) {
    Serial.print(measure1.RangeMilliMeter);
    Serial.print(" mm");
  }
  else Serial.print("Out of range");

  Serial.print("\tSensor 2: ");
  if (measure2.RangeStatus != 4) {
    Serial.print(measure2.RangeMilliMeter);
    Serial.println(" mm");
  }
  else Serial.println("Out of range");
}

void activateLEDsWarmWhite(int start) {
  const uint32_t On = strip.Color(0, 0, 0, 255);
  // Schalte die LEDs in PIN 3 warm weiß ein
  for (int i = start; i < start + 36; i++) {
    strip.setPixelColor(i, On); // Warmes Weiß
  }
  strip.show();
}

void deactivateLEDs(int start) {
  const uint32_t Off = strip.Color(0, 0, 0, 0);
  // Schalte die LEDs in PIN 3 aus
  for (int i = start; i  < start + 36; i++) {
    strip.setPixelColor(i, Off); // Aus
  }
  strip.show();
}

repariert

Es kommt folgender Fehlercode aufgrund Zeile 124:

exit status 1

Compilation error: 'Off' was not declared in this scope

repariert

Vielen Dank, nun kommt keine Fehlermeldund mehr. Aber ich kann den Code gerade nicht testen, da meine ToF Sensoren beide die I2C Adresse "0x31" haben. Ich habe schonmal mit folgendem Code gescannt

#include <Wire.h>
 
 
void setup()
{
  Wire.begin();
 
  Serial.begin(9600);
  while (!Serial);             // Leonardo: wait for serial monitor
  Serial.println("I2C Scanner");
}
 
 
void loop()
{
  byte error, address;
  int nDevices;
 
  Serial.println("Scanning...");
 
  nDevices = 0;
  for(address = 1; address < 127; address++ )
  {
    // The i2c_scanner uses the return value of
    // the Write.endTransmisstion to see if
    // a device did acknowledge to the address.
    Wire.beginTransmission(address);
    error = Wire.endTransmission();
 
    if (error == 0)
    {
      Serial.print("I2C device found at address 0x");
      if (address<16)
        Serial.print("0");
      Serial.print(address,HEX);
      Serial.println("  !");
 
      nDevices++;
    }
    else if (error==4)
    {
      Serial.print("Unknown error at address 0x");
      if (address<16)
        Serial.print("0");
      Serial.println(address,HEX);
    }    
  }
  if (nDevices == 0)
    Serial.println("No I2C devices found");
  else
    Serial.println("done");
 
  delay(5000);           // wait 5 seconds for next scan
} 

Aber wenn ich mit diesem Code die Adresse ändern möchte, dann änder sich die Adresse aber nicht. Ich habe es zwar schon ein paar mal geschafft aber nicht immer. Und wenn ich den Stromstecker ziehe dann setzen die sich wieder zurück.

#include "Adafruit_VL53L0X.h"

Adafruit_VL53L0X lox = Adafruit_VL53L0X();


void setup() {
  // Robojax.com I2C address update 20181206
  lox.begin(0x32);// put any address between 0x29 to 0x7F 
}

void loop(){
  
}

Connecting Multiple Sensors

I2C only allows one address-per-device so you have to make sure each I2C device has a unique address. The default address for the VL53L0X is 0x29 but you can change this in software.

To set the new address you can do it one of two ways. During initialization, instead of calling lox.begin(), call lox.begin(0x30) to set the address to 0x30. Or you can, later, call lox.setAddress(0x30) at any time.

The good news is its easy to change, the annoying part is each other sensor has to be in shutdown. You can shutdown each sensor by wiring up to the XSHUT pin to a microcontroller pin. Then perform something like this pseudo-code:

  1. Reset all sensors by setting all of their XSHUT pins low for delay(10), then set all XSHUT high to bring out of reset
  2. Keep sensor #1 awake by keeping XSHUT pin high
  3. Put all other sensors into shutdown by pulling XSHUT pins low
  4. Initialize sensor #1 with lox.begin(new_i2c_address) Pick any number but 0x29 and it must be under 0x7F. Going with 0x30 to 0x3F is probably OK.
  5. Keep sensor #1 awake, and now bring sensor #2 out of reset by setting its XSHUT pin high.
  6. Initialize sensor #2 with lox.begin(new_i2c_address) Pick any number but 0x29 and whatever you set the first sensor to
  7. Repeat for each sensor, turning each one on, setting a unique address.

Note you must do this every time you turn on the power, the addresses are not permanent!

1 Like

Das ist Absicht.
Der Sensor hat keinen permananten Speicher; vergisst also alle seine Einstellungen, wenn er vom Strom genommen wird.

Ich sehe 2 Sensoren am selben Bus nur mit entsprechendem Aufwand als machbar.

Ja, wenn man eben pro Sensor einen Controllerpin für die Steuerung des XSHUT einganges des VL53L0X opfert dann geht das und funktioniert auch problemlos. Hab das beim Futterportionierer für meine Katze gemacht. Da nutze ich die 2 ToF Sensoren zuer Ermittlung der Futerstände im Vorratsbehälter und in der Ausgabeschale (während der Ausgabe um ein überfüllen der Schale zu vermeiden.) Steuer da nen Schrittmotor mit Stall Erkennungssensorv, 2 ToF, Notstrom Batterie überwachung , Animiertes 128x64 i2c Oled , RTC 3231 , I2C FRAM , ein 2 Tasten joypad und nen Buzzer alles mit 1 ATTiny 167.

Jo.

Theoretisch könnte man via XSHUT einen ausschalten und den anderen mit einer neuen Adresse versehen, so ich das richtig verstanden habe.

Ansonsten bei jedem Umlauf einen Sensorwechsel ist ja nun auch kein Ding :wink:

über den XShot kannst Du die beiden Sensoren mit jeweils ner eigenen Adresse initialisieren um sie gleichzeitig nutzen zu können. Die Initialisierung Funktioniert jedoch NUR , wenn gerage nur derjenig, der im Moment initialisiert wird aktiv ist, da ja beide vorerst auf dieselbe Adresse hören. Deshalb wissen ja dann , wen beide beim Initialisieren Ariv wären, die Sensoren nicht, welcher nun Gemeint ist, respektive, sie reagieren BEIDE auf die Adressänderung. Somit hätte man dann wiederum 2 Sensoren, die auf die Gleiche (jetzt halt neue) Adresse hören- Meistens lgeht dann jedoch die initialisierung eh schief und löst eine Fehlermeldung aus. Deshalb muss mann über den XSHUT Eingang erst die sensoren resetten, und dann nur den gerede zu Initialisirenden aktivieren um Ihm die Adresse zu verpassen und das BasisInit durchzuführen. Danach sind beide Sensoren aktiv und können ederzeit über ihre eigene Adresse (ohder das für den Sensor erstellte Objekt angesprochen werden. In meinem Futterprotionierer habich das so umgesetzt, dass ich die XShut Eingänge , die ja NUR im Setup benötigrt werden, am Attiny an zwei pins gehängt habe, die ich NACH dem Setup für andere Aufgaben (als Eingänge nutze. über externe Flipflops und ein paar GMos Gatter hab ich nen Sschalter aufgebaut, der die XShut nach erfolgtem Setup vom ATTiny trennt, da ich sonst nicht genügend Pins gehabt hätte um alle Sensoren und Aktoren zu bedienen. So komme ich mit den 16 I/O Pins des ATTiny 167 aus.

1 Like

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