[RISOLTO] millis su fade led rgb

LeoTer01:
Però mettendo valori che vanno da 200 a 500 non cambia nulla: sempre acceso su rosso

Nel loop ci sono tre if eseguiti uno dopo l'altro che alla fine lasciano i valori invariati... in un if vengono incrementati e in un if successivo decrementati, risultato finale valore uguale all'inizio.

Eh, probabilmente è per quello che non funziona ma non so proprio come risolvere il problema....ho provato di tutto ma non sono ancora riuscito a farlo funzionare. :sob:
Qualcuno mi potrebbe dare qualche linea guida, qualche aiuto su come fare?

P.S. Spero abbiate capito cosa voglio fare, in caso contrario cercherò di spiegarmi meglio!

Grazie
Leo

Prova facendo diversamente:
prendi un valore che varia ciclicamente, ad esempio il resto di millis() diviso 2000, e ne ricavi i valori per R, G e B sfasandoli tra loro: G=R+667; B=G+667. Naturalmente devi mettere degli if che azzerino al superamento del massimo: if(G>2000) G-=2000.

Tempo fa feci qualcosa del genere con un led RGB, ma usai dei delay perché non c'era altro nel programma. Mi resi conto, però, che per fare sfumi uniformi era necessaria una tabella con valori trovati sperimentalmente e, comunque, i 255 valori del pwm producevano visibili salti ai livelli di luminosità più bassi.

LeoTer01, il tuo codice iniziale con i cicli for() aveva il problema che usava i delay(), che tu non vuoi usare!

La tua alternativa con millis() non è una naturale evoluzione del codice con for().

Nel codice con for(), eseguo prima il primo for, poi il secondo for, poi il terzo for.

Per farlo con millis() a mio avviso dovresti usare una macchina a stati finiti, una variabile che assume tre valori, e tre if(), se stato=1 eseguo il primo decremento, poi stato passa a 2 ed eseguo il secondo decremento.

Esempio:

int R = 5;
int G = 6;
int B = 3;
int fadeR = 255;
int fadeG = 0;
int fadeB = 0;
unsigned long zero = 0;
unsigned long tempo=200;
byte stato=0; // A seconda del valore di stato esegue una cosa o un altra


void setup(){
pinMode(R, OUTPUT);
  pinMode(G, OUTPUT);
  pinMode(B, OUTPUT);
}
void loop(){
    analogRead(A5);
    pR = map(analogRead(A5), 0, 1023, 1, 20);
    tempo = pR;
    if(millis() - zero > tempo){

      if(stato==0){
     
        fadeR--;
        fadeG++;
        analogWrite(R, fadeR);
        analogWrite(G, fadeG);
        if(fadeR==0)
            stato=1; // Quando il colore rosso è zero passa allo stato successivo
        
      }else if(stato==1){
   
      
        fadeG--;
        fadeB++;
        analogWrite(G, fadeG);
        analogWrite(B, fadeB);
        if(fadeG==0)
            stato=2; // Quando il colore verde è zero passo allo stato successivo 2
        
      }else if(stato==2){
      
        fadeB--;
        fadeR++;
        analogWrite(B, fadeB);
        analogWrite(R, fadeR);
        if(fadeB==0)
             stato=0; // Quando l'ultimo stato è stato eseguito rincomincia tornando allo stato zero
         
      }
      zero = millis(); // Questo deve avvenire ogni step di tempo
    }
delay(10);
}

PER capire meglio leggi cosa sia una macchina a stati finiti in maniera da capire meglio, di imparare cose che ti possono tornare utili in altre occasioni :slight_smile:

Grazie mille torn24! A vederlo così sembra la soluzione migliore. Mi studierò la macchina a stati finiti che non ho mai usato poi proverò il programma e vi farò sapere.
Il consiglio di Datman mi sembra un po' macchinoso ma lo terrò comunque in considerazione.

Leo

Ho letto ora il post e mi sono venuti un paio di dubbi ... tu esattamente "come" vuoi fare il fading ? ... colori separati (cioe', prima uno da zero al massimo e poi di nuovo a zero, poi il secondo, poi il terzo), o mix dei 3 in proporzione di un terzo ? (cioe' come, ad esempio, l'incrocio delle sinusoidi in una trifase ?)

Anche perche' 256 non puo essere diviso esattamente per 3, nel secondo caso (la scala va da 0 a 255, quindi sono 256 valori), per cui per poter fare tre rampe regolari da mixare, o vai da 0 a 254, o da 1 a 255 (dato che 255, invece, puoi dividerlo per 3 senza decimali di resto)

Poi, se e' il secondo caso, non ti basta partire con i valori iniziali di un terzo, due terzi e full ... cioe', ad esempio, 80, 165 e 250 per R, G e B, o nell'ordine che vuoi, (basta che nessun valore iniziale sia 1 o 255, per non "falsare" il primo controllo negli if) e fare una semplice sequenza di 3 if/else consecutivi e 3 flag per sapere se devono sommare o sottrarre (alle flag cambi valore quando <=255 e quando <=1, dentro gli stessi if) ?

Cioe', una cosa tipo

int R = 5;
int G = 6;
int B = 3;
byte fadeR = 80;
byte fadeG = 165;
byte fadeB = 250;
byte flag1 = 1;
byte flag2 = 1;
byte flag3 = 1;
unsigned long ZERO;
unsigned long tempo;

void setup(){
  pinMode(R, OUTPUT);
  pinMode(G, OUTPUT);
  pinMode(B, OUTPUT);
  zero = millis();
}

void loop(){

  analogRead(A5);
  tempo = map(analogRead(A5), 0, 1023, 10, 210);
  if(millis() - zero > tempo){
    if(flag1 == 1){
      fadeR++;
      if(fadeR >= 255) flag1=0;
      analogWrite(R, fadeR);
    }
    else if(flag1 == 0){
      fadeR--;
      if(fadeR <= 1) flag1=0;
      analogWrite(R, fadeR);
    }

    if(flag2 == 1){
      fadeG++;
      if(fadeG >= 255) flag2=0;
      analogWrite(G, fadeG);
    }
    else if(flag2 == 0){
      fadeG--;
      if(fadeG <= 1) flag2=0;
      analogWrite(G, fadeG);
    }

    if(flag3 == 1){
      fadeB++;
      if(fadeB >= 255) flag3=0;
      analogWrite(B, fadeB);
    }
    else if(flag3 == 0){
      fadeB--;
      if(fadeB <= 1) flag3=0;
      analogWrite(B, fadeB);
    }
  zero = millis();
  }
}

EDIT: completato, ma l'ho buttato giu al volo col notepad partendo dal tuo, devi controllarlo ...

Il mio intento è creare una dissolvenza che fa così:
R che va da acceso a spento e contemporaneamente G va da spento a acceso.
G che va da acceso a spento e contemporaneamente B va da spento a acceso.
B che va da acceso a spento e contemporaneamente R va da spento a acceso.
Poi riparte.

Leo

Quindi hai tre fasi ben distinte, chiamiamole 0, 1, 2 che possono essere identificate dal valore di una variabile (il famoso stato delle macchine a stati).

Basta un if/else if/else per determinare la fase attiva ed eseguire solo le istruzioni corrispondenti.

Tra queste istruzioni ci va anche un if per riconoscere la fine della fase impostando quella nuova. Ad esempio per la fase 0 la condizione di termine è R completamente spento e G acceso al massimo.

Basta un solo ciclo che, sequenzialmente, sfuma tra R e G, poi tra G e B e poi tra B e R. Basta porre

A[1]=pinR; A[2]=pinG; A[3]=pinB; e poi sfumare tra A[x] e A[y], dove x va da 1 a 3 e y=x+1; if(y>3)y-=3;

Dopo essermi studiato il funzionamento della macchina a stati finiti (che mi è stata fondamentale per un altro gioco di luce :wink: ) ho provato con il programma consigliato da torn24 e FUNZIONA!!! :slight_smile:
Però accade una cosa molto strana: nonostante la variabile tempo cambi (controllato da seriale) il tempo della dissolvenza rimane sempre lo stesso :-\
Non riesco proprio a capire il motivo....vi lascio il programma:

analogRead(A5);
  pR = map(analogRead(A5), 0, 1023, 1, 20);
  tempo = pR;
  if(millis() - zero > tempo){
    if(stato == 0){
      fadeR--;
      fadeG++;
      analogWrite(R, fadeR);
      analogWrite(G, fadeG);
      if(fadeR == 0){
        stato = 1;
      }
     }
     else if(stato == 1){
      fadeG--;
      fadeB++;
      analogWrite(G, fadeG);
      analogWrite(B, fadeB);
      if(fadeG == 0){
        stato = 2;
      }
     }
     else if(stato == 2){
      fadeB--;
      fadeR++;
      analogWrite(B, fadeB);
      analogWrite(R, fadeR);
      if(fadeB == 0){
        stato = 0;
      }
     }
     zero = millis();
  }
}

Leo

pR = map(analogRead(A5), 0, 1023, 1, 20);

Non so se usi proprio questa riga, ma in questo caso hai un intervallo di tempo da 1 millisecondi a 20 millisecondi. Un uomo non è in grado di percepire queste differenze. Potresti percepire la differenza tra
100 e 300 millisecondi, comunque maggiore è l'intervallo più percepisci la differenza.

torn24:
Un uomo non è in grado di percepire queste differenze

Però il fading avviene in 256 cicli da 1..20ms, quindi in un tempo compreso tra 0.256 e 5.12 secondi (in realtà anche un po' più lento perché tra l'aggiornamento zero=millis() e la condizione >tempo si ritarda di minimo un altro millisecondo a giro), quindi dovrebbe essere perfettamente visibile... a meno che non ci siano altri ritardi nell'esecuzione del loop che noi non vediamo.

Se ho letto bene i vari post (ma ovviamente potrei sbagliare), in quello che state facendo, se volte un buon fade, state dimenticando una cosa fondamentale che, chi fa illuminazione con led RGB, conosce bene ...

... l'occhio umano NON è affatto lineare e quindi, fare un fade lineare variando semplicemente il PWM dei vari colori, da sempre un pessimo risultato (crescita rapida della luminosità all'inizio, fino circa al 50%, e poi sembra quasi che non cresca più o cresca molto lentamente). I fade fatti bene tengono conto del GAMMA e del HUE per i calcoli e, se ben ricordo, ci sono anche librerie apposta per Arduino che effettuano tali calcoli e permettono di ottenere fade come si deve.

Provate a fare una ricerca ... :slight_smile:

Guglielmo

*Edit: Credo che la libreria FastLED abbia tutta una serie di funzioni per operazione HSV *

Per quanto riguarda la semplice luminosità di un LED monocromatico ho trovato ottima l'applicazione di un esponenziale cubico. Si eleva il valore PWM al cubo e si divide per 65025 ottenendo di nuovo un valore compreso trra 0 e 255, ma con andamento esponenziale, che per l'occhio è una bella variazione progressiva della luminosità.

Nel caso dei LED RGB non ho mai provato (provvederemo :slight_smile: ), ma le non linearità dovrebbero essere ancora peggiori perché i singoli colori base non si comportano tutti allo stesso modo (immagino servirebbe una diversa curva di attivazione per ciascuno).

Claudio_FF:
Per quanto riguarda la semplice luminosità di un LED monocromatico ho trovato ottima l'applicazione di un esponenziale cubico ...

Considera che, mediamente, la risposta dell'occhio alla variazione di luminosità è la seguente:


riepilogabile in : B = L 1/γ (B=brightness, L=luminance, γ=gamma) quindi, se tu hai fatto una crescita esponenziale, sicuramente hai un ottimo risultato. La cosa, come hai ben detto, si complica quando ci sono di mezzo i colori dato che l'occhio ha, oltretutto, una differente risposta per differenti colori ... :o

Guglielmo

Un pochino offtopic

L'autore del thread ha 16 anni, non so da quanto si cimenti con arduino e la programmazione!
Ma penso che oltre il risultato ottenuto sia da considerare l'apprendimento, forse fare uso di librerie non è il modo migliore di imparare, esempio facendo le cose alla meno peggio ha scoperto la macchina a stati finiti, mi sembra una cosa positiva :slight_smile:

... non direi ... è giusto che impari ad usare anche le "librerie" ed inoltre, se vuole ottenere dei validi effetti, vedrai che non potrà farne a meno (... salvo non reinventare l'acqua calda).

Guglielmo

per quanto riguarda la sensibilità dell'occhio ai diversi colori suggerisco di dare un'occhiata qui
...nella mia professione me ne hanno fatto un mazzo tanto!! :smiley:

Un paio d'anni fa feci uno sfumo incrociato per un LED RGB. Per ottenere variazioni di luminosità piacevoli adottai una tabella:

int Z[69]={1,3,5,8,10,16,20,23,27,30,40,50,63,80,90,105,120,135,148,158,170,180,200,220,240,255,240,220,200,180,170,158,148,135,120,105,90,80,63,50,40,30,27,23,20,16,10,8,5,3,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
byte nR;
byte nG;
byte nB;

// I/O9:LED R; I/O10:LED G; I/O11:LED B; 

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

void loop()
{
  for(nR=0;nR<69;nR++)
  {
  analogWrite(9,Z[nR]);

  nG=nR+23; if(nG>68) nG-=69;
  analogWrite(10,Z[nG]);

  nB=nR+46; if(nB>68) nB-=69;
  analogWrite(11,Z[nB]);

  /*
  Serial.print(nR);
  Serial.print("  ");
  Serial.print(nG);
  Serial.print("  ");
  Serial.println(nB);

  X=int((Z[n]%100)/10);
  Calc();
  Serial.print(X);
  Serial.print("  ");
  analogWrite(10,X);

  X=int(Z[n]%10);
  Calc();
  Serial.println(X);
  analogWrite(11,X);
  */

  delay(10);
  }
 
}

Ringrazio a tutti per l'interessamento, il fatto di tener conto della sensibilità dell'occhio, pur essendo interessante come argomento, credo che potrei anche tralasciarlo in quanto è già tanto se sono riuscito a fare quello che ho fatto :smiley:
Appena torno a casa darò un occhiata alla libreria consigliata.
Per quanto riguarda invece il mio problema (quello relativo al fatto che non riesco a variare il tempo) mi sembra che nessuno sia riuscito a capire dove sta l'inghippo (apparte torn24, che però non credo possa risolvere, ma proverò lo stesso) giusto? O mi sono perso qualcosa?

Leo