Salve a tutti, ho una lavagna dietro cui vorrei mettere una striscia led sempre accesa con brightness bassa, ma all'avvicinarsi di qualcuno (rilevato con sensore ultrasuoni) dovrebbe aumentare con fading e quindi non semplicemente fare uno scatto!
Ho provato diversi sketch ma tutti vanno troppo a scatti, avete qualche esempio che faccia a caso mio?
Non ho ben capito perché dovrebbero "fare uno scatto", o la striscia led non supporta i livelli di luminosità che prevedi, o il sensore non funziona correttamente, o nel codice non viene fatta la giusta corrispondeza tra distanza e luminosità.
Potresti scrivere quale striscia LED esattamente usi, quale sensore ultrasonico (io sconsiglio sempre li SR04, ormai uso sempre solo SRF05), uno schema dei collegamenti e il codice di uno sketch di quelli che hai provato?
#define echoPin 2 // attach pin D2 Arduino to pin Echo of HC-SR04
#define trigPin 3 //attach pin D3 Arduino to pin Trig of HC-SR04
long duration; // variable for the duration of sound wave travel
int distance; // variable for the distance measurement
int brightness; //variable for the brightness measurement
int lastBrightness;
#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
#include <avr/power.h> // Required for 16 MHz Adafruit Trinket
#endif
#define PIN 6
#define NUMPIXELS 7
Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800); //Determines the number of LEDs and Arduino pins.
#define DELAYVAL 500 // Time (in milliseconds) to pause between pixels
//---------------------------------------------------------------------
void setup() {
pinMode(trigPin, OUTPUT); // Sets the trigPin as an OUTPUT
pinMode(echoPin, INPUT); // Sets the echoPin as an INPUT
Serial.begin(9600); // Serial Communication is starting with 9600 of baudrate speed
pixels.begin();//Does the initialisations.
}
//---------------------------------------------------------------------
void loop() {
digitalWrite(trigPin, LOW); // Clears the trigPin condition
delayMicroseconds(2);
digitalWrite(trigPin, HIGH); // Sets the trigPin HIGH (ACTIVE) for 10 microseconds
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
duration = pulseIn(echoPin, HIGH); // Reads the echoPin, returns the sound wave travel time in microseconds
// Calculating the distance
distance = duration * 0.034 / 2; // Speed of sound wave divided by 2 (go and back)
pixels.clear();
pixels.setPixelColor(0, pixels.Color(253, 244, 200)); //Defines the LEDs color with the RGB system, after specifying the LED number (from 0 to NUMPIXELS-1).
pixels.setPixelColor(1, pixels.Color(253, 244, 200));
pixels.setPixelColor(2, pixels.Color(253, 244, 200));
pixels.setPixelColor(3, pixels.Color(253, 244, 200));
pixels.setPixelColor(4, pixels.Color(253, 244, 200));
pixels.setPixelColor(5, pixels.Color(253, 244, 200));
pixels.setPixelColor(6, pixels.Color(253, 244, 200));
if (distance <= 20) {
brightness = map(distance, 0, 20, 255, 1);
brightness = (brightness + lastBrightness) / 2;
lastBrightness = brightness;
}
else {
brightness = (brightness - lastBrightness) / 2;
if (brightness < 0)
brightness = 0;
lastBrightness = brightness;
}
pixels.setBrightness(brightness);
pixels.show();
}
purtroppo a disposizione ho solo l'ultrasuoni che non ti piace!
Ti consiglierei intanto, come si fa quando qualcosa non funziona come atteso, di mandare su seriale sia "duration" sia "brightness". Poi tu questi calcoli li fai migliaia di volte al secondo cosa non necessaria a meno che tu non debba misurare il movimento di un proiettile, metti (almeno per ora) un delay ad ogni ciclo, diciamo che fai 2 letture al secondo. Inoltre il calcolo della distanza viene fatto su un int partendo da un long, moltiplicato per un float: non ti pare un poco "rischioso"?
La distanza in centimetri lasciala long, ed evita le virgole dividendo direttamente per 58:
...
long distance; // variable for the distance measurement
...
duration = pulseIn(echoPin, HIGH); // Reads the echoPin, returns the sound wave travel time in microseconds
// Calculating the distance
distance = duration / 58 ; // Speed of sound wave divided by 2 (go and back)
...
pixels.setBrightness(brightness);
pixels.show();
// PER DEBUG
Serial.print(duration); Serial.print(" "); Serial.println(brightness);
delay(500);
// FINE DEBUG
}
A quel punto fai qualche prova avvicinando ed allontanando una mano, e verifica i due valori (nel caso, postali qui e vediamo insieme).
Questi valori poi dovrebbero autarti a calibrare meglio le formule che hai messo, e ce ho per ora tralasciato (sembra che tu faccia cose diverse quando è più vicino di 20 centimetri, cosa che non hai descritto...).
Devi usare una formula che esprima brightness in funzione di distanza: per esempio, se distanza<=20, brightness=(20-distanza)*12. Per distanze maggiori di 20, brightness=15.
Si quest'ho capito, ma non cambia luminosità con effetto fading, capito
Non so se stavi rispondendo a me o a Datman, comunque io ti consiglio di fare le modifiche che ho indicato e quindi il relativo test, e pubblicare qui il risultato. Una volta chiarito cosa acquisisci e soprattutto come lo converti, allora possiamo affinare l'algoritmo.
Forse deve solo aumentare progressivamente la luminosità quando una persona è al di sotto di una certa distanza e poi sfumare quando una persona si è allontanata, quindi il rilevamento di distanza deve essere a scatto, innescando l'aumento o la diminuzione di luminosità.
Forse ho spiegato male quello che voglio:
Ho una vetrina che deve avere sempre la brightness tipo a 10;
Quando si avvicina qualcuno e finquando rimane entro una certa distanza imposta la brightness a 255 (che mi pare sia il valore massimo!). Quindi prima di tutto deve rimanere sempre accesa con bassa luminosità, ed aumentare quando qualcuno si avvicina!
Cmq modificando il codice il monitor mi stampa:
Distance: 70 cm Brightness: 0
ovviamente avvicinandomi diminuisce distanza ed aumenta il brightness, però se rimango fermo lampeggia, quindi si accende e si spegne!
Si può postare un video?
Si, lo avevo capito, ma prima di questo deve capire se ha letto e convertito correttamente le letture e poi in base a questo creare l'algoritmo desiderato.
Aspettiamo la risposta dell'OP per favore.
Bene, quindi la distanza ti torna ed anche il valore di brightness, esatto?
Eh, a me pare normale: se vedi che i valori di distanza e brightness sono giusti, è perché tu fai tutte le operazioni (da "pixels.clear();" in poi) sempre ad ogni loop. Invece dovresti farle solo se cambia la distanza (e quindi il valore del brightness). E' una delle cose alle quali volevo portarti. Prova a modificare il codice e vediamo.
Allora ho messo pixel.clear nel setup,
poi nel loop
if (distance <= 30 || distance < newDistance) {
newDistance = distance;
brightness = map(distance, 0, 20, 255, 1);
brightness = (brightness + lastBrightness) / 2;
lastBrightness = brightness;
}
else {
brightness = 5;
}
lampeggia sempre, ma lampeggia perchè effettivamente anche se rimango fermo davanti al sensore la lettura ma da:
Distance: 8 cm Brightness: 157
Distance: 7 cm Brightness: 162
Distance: 7 cm Brightness: 164
Distance: 138 cm Brightness: 5
Distance: 143 cm Brightness: 5
ed è per questo che lampeggia
Io farei così:
#define echoPin 2 // attach pin D2 Arduino to pin Echo of HC-SR04
#define trigPin 3 //attach pin D3 Arduino to pin Trig of HC-SR04
int brightness; //variable for the brightness measurement
int lastBrightness;
#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
#include <avr/power.h> // Required for 16 MHz Adafruit Trinket
#endif
#define PIN 6
#define NUMPIXELS 7
Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800); //Determines the number of LEDs and Arduino pins.
#define DELAYVAL 500 // Time (in milliseconds) to pause between pixels
uint16_t distanza;
uint8_t soglia_dist=20;
uint8_t isteresi=3;
uint8_t acceso=0;
void setup()
{
pinMode(trigPin, OUTPUT); // Sets the trigPin as an OUTPUT
pinMode(echoPin, INPUT); // Sets the echoPin as an INPUT
Serial.begin(9600); // Serial Communication is starting with 9600 of baudrate speed
pixels.begin(); //Does the initialisations.
distanza_prec = duration * 0.034 / 2;
// ...
}
void loop()
{
digitalWrite(trigPin, HIGH); // Sets the trigPin HIGH (ACTIVE) for 10 microseconds
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
distanza = pulseIn (echoPin, HIGH) * 0.034 / 2; // Distanza in cm.
if (abs(distanza-distanza_prec) < 40) // Se la variazione è maggiore, la lettura va scartata.
{
distanza_prec=distanza;
if (acceso)
{
if (distanza >= soglia_dist+isteresi) acceso=0;
}
else
{
if (distanza <= soglia_dist-isteresi) acceso=1;
}
}
// ...
}
Cioè mi stai dicendo che il sensore non funziona bene, passando da una lettura di 7 centimetri a 1 metro e 40? Ma che strano, da uno SR04 non me lo aspetterei mai...
Battute a parte, posta il codice che ha prodotto quell'output e vediamo.
void setup() {
pinMode(trigPin, OUTPUT); // Sets the trigPin as an OUTPUT
pinMode(echoPin, INPUT); // Sets the echoPin as an INPUT
Serial.begin(9600); // Serial Communication is starting with 9600 of baudrate speed
pixels.begin();//Does the initialisations.
pixels.clear();
}
//---------------------------------------------------------------------
void loop() {
uint32_t magenta = pixels.Color(255, 255, 255);
digitalWrite(trigPin, LOW); // Clears the trigPin condition
delayMicroseconds(2);
digitalWrite(trigPin, HIGH); // Sets the trigPin HIGH (ACTIVE) for 10 microseconds
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
duration = pulseIn(echoPin, HIGH); // Reads the echoPin, returns the sound wave travel time in microseconds
distance = duration / 58; // Speed of sound wave divided by 2 (go and back)
pixels.fill(magenta, 0);
if (distance <= 30) {
brightness = map(distance, 0, 30, 250, 1);
brightness = (brightness + lastBrightness) / 2;
lastBrightness = brightness;
}
else {
brightness = 1;
}
pixels.setBrightness(brightness);
pixels.show();
Serial.print("Distance: ");
Serial.print(distance);
Serial.print(" cm ");
Serial.print("Brightness: ");
Serial.println(brightness);
}
Mah, le letture di quel sensore possono essere così erratiche che anche la variabile 'acceso' potrebbe "lampeggiare" nonostante l'isteresi.
Ritengo invece assolutamente corretta l'idea di sganciare il valore della variabile 'brightness' dalla lettura del sensore: il sensore deve dirci solo se c'è qualcuno nelle vicinanze (informazione magari gestita con una temporizzazione), mentre il fader modifica lentamente la variabile 'brightness' in un senso o nell'altro a seconda se il sensore dice presente/non presente.
Sì, infatti l'isteresi serve solo per avere un funzionamento a scatto: con acceso==1 la luminosità viene incrementata progressivamente fino al massimo; con acceso==0 la luminosità viene diminuita progressivamente fino al valore minimo.
Mi sto perdendo per la mia inesperienza.... Pensavo fosse una cosa semplice! Ma dite che è dovuta dal sensore o dal codice?
Per me entrambi.
Intanto perché l'SR04 a me ha sempre dato problemi (non questi, comunque), ma anche perché devi considerare che un sensore ad ultrasuoni è influenzato anche dal materiale, forma, e disposizione dell'oggetto. Metti un foglio di cartoncino ruvido a 45 gradi e vedrai che le letture non saranno così precise.
Ma nel codice non hai fatto tutto quello che ti ho consigliato. Se tu leggi così velocemente dal sensore (ricorda che la loop() viene richiamata migliaia di volte al secondo) tu stai "sparando" ultrasuoni a raffica, e questo non fa che confondere il calcolo perché avrai continuamente suoni che tornano al sensore per vari percorsi, quindi con tempi diversi. Tu devi diradare le letture, come ti avevo scritto: aggiungi intanto un delay(500) alla fine del loop per fare due letture al secondo, e vedi se cambia qualcosa.
Come dico sempre, quando si usano in uno sketch diversi elementi/circuiti/sensori e sembra non funzionare, bisogna separare i problemi analizzandoli uno alla volta. Inizia dalla base, ossia pensa solo alla misurazione della distanza: quando questa è affidabile, allora si passa al resto. Inutile stare a pensare a cose complicate e fasciarsi la testa con algoritmi, isteresi, o quant'altro quando è la base che non va...
Allora l letture della distanza me le fa bene, ma proviamo a semplificare il tutto, io voglio che:
void loop() {
pixels.clear();
digitalWrite(trigPin, LOW); // Clears the trigPin condition
delayMicroseconds(2);
digitalWrite(trigPin, HIGH); // Sets the trigPin HIGH (ACTIVE) for 10 microseconds
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
duration = pulseIn(echoPin, HIGH); // Reads the echoPin, returns the sound wave travel time in microseconds
// Calculating the distance
distance = duration * 0.034 / 2; // Speed of sound wave divided by 2 (go and back)
if (distance <= 40) {
for(int i=0;i<NUMPIXELS;i++){
pixels.setPixelColor(i, pixels.Color(255,255,250));
pixels.setBrightness(i);
}
pixels.show();
}
else {
for(int i=0;i<NUMPIXELS;i++){
pixels.setPixelColor(i, pixels.Color(10,10,10));
}
pixels.show();
}
delay(5000);
//Displays the applied values.
Serial.print("Distance: "); // Displays the distance on the Serial Monitor
Serial.print(distance);
Serial.print(" cm ");
Serial.print("Brightness: ");
Serial.println(brightness);
}
solo che vorrei che il passaggio tra 10 e 255 avvenisse con fade, e non tutto di colpo!!