Go Down

Topic: kitt knight rider (Read 2180 times) previous topic - next topic

manolomao

Ciao a tutti, con un mio amico ci stiamo divertendo a creare il mitico effetto che aveva la macchina di supercar, il famoso kitt...
Ho trovato in rete molti esempi, ma tutti utilizzano delay come tempo di attesa.
Code: [Select]

void setup(){
for (byte pin=2;pin<14;pin++){
pinMode(pin,OUTPUT);}
}

void loop(){
 byte t=20;
//---------->>> for this side
for (byte i=2;i<14;i++{
     digitalWrite(i,HIGH);
     delay (t);
     digitalWrite(i+1,HIGH);
     delay (t);
     digitalWrite(i+2;HIGH);
     delay (t);
     digitalWrite(i,LOW);
     delay (t);
     digitalWrite(i+1,LOW);
}
//  <<<-------- for this side
for (byte i=13;i>1;i--){
     digitalWrite(i,HIGH);
     delay (t);
     digitalWrite(i-1,HIGH);
     delay (t);
     digitalWrite(i-2;HIGH);
     delay (t);
     digitalWrite(i,LOW);
     delay (t);
     digitalWrite(i-1,LOW);
}
}

Come ben sappiamo delay è bloccante ed io volevo provare a modificare questo scketch funzionante con i millis, in modo da non bloccare arduino, facendogli fare altri controlli
Avete qualche suggerimento da darmi??
Io avevo pensato ad una cose del genere:
Code: [Select]

unsigned long tempo_pausa;
byte volte=0;
void setup(){
for (byte pin=2;pin<14;pin++){
pinMode(pin,OUTPUT);}
tempo_pausa=millis();
}

void loop(){

//---------->>> for this side
for (byte i=2;i<14;i++{
     digitalWrite(i,HIGH);
     if(millis()-tempo_pausa>=20 && volte==0){digitalWrite(i+1,HIGH);tempo_pausa=millis();volte=1;}
     if(millis()-tempo_pausa>=20 && volte==1){digitalWrite(i+2;HIGH);tempo_pausa=millis();volte=2;}
     if(millis()-tempo_pausa>=20 && volte==2){digitalWrite(i,LOW);volte=3;}
     if(millis()-tempo_pausa>=20 && volte==3){digitalWrite(i+1,LOW);volte=0;}
}

Ma non funziona prorpio bene.
Aiutino??
Grazie

fabpolli

Stai sbagliando l'approccio, ovvero tu dici che vuoi lasciar libero Arduino di fare altri controlli, ma finché racchiudi l'effetto sui led all'interno di un cliclo for sarai legato a fare i controlli dento al for e ripeterli anche nell'altro for che gestirà l'effetto in ordine inverso.
Il consiglio che ti posso dare è di strutturare il programma in modo che ao ogni ciclo di loop se è trascorso il tempo tra uno step e il siccessivo venga eseguito quando necessario ovvero qualcosa del tipo:
Code: [Select]

void loop
{
  if(millis()-tempo_pausa>=20)
  {
     if(direzione==--->)
     {
        switch(i)
        {
           case 0:
              accendi il led N;
              break;
           case 1:
              accendi il led M;
           ecc.
        }
       i++;
       if(i>14)
       {
          i=0;
          direzione = <--;
       }
       
     }
     else
     {
        ..codice per direzione inversa
     }
     tempo_pausa = millis();
  }
  ...altri controlli...
}

doppiozero

Ho trovato in rete molti esempi, ma tutti utilizzano delay come tempo di attesa.

eeeh, non hai cercato bene  :P

Runtime Clock Manager -- https://github.com/duezero/RCM---Runtime-Clock-Manager
GPX datalogger -- https://github.com/duezero/GPX-datalogger
AVR HV Rescue Board -- https://www.youtube.com/watch?v=EErKo0aTEio

docdoc

eeeh, non hai cercato bene  :P
Interessante, grazie, utile anche per me, non conoscevo la "SoftPWM"! :)

L'effetto è ottimo, ma voglio provare a giocare un poco sull'implementazione perché il codice non l'avrei scritto proprio così... ;)
Alex "docdoc" - ** se ti sono stato d'aiuto, un punto karma sarà gradito, clicca su "add" qui a sinistra, vicino al mio nome ;) **

maubarzi

Interessante...
...perché il codice non l'avrei scritto proprio così... ;)
Concordo su entrambi i punti.
A naso direi che ci si potrebbe riuscire riducendo di un fattore 10 la complessità del codice, vediamo se mi confermi l'intuito nasale ;)
Io lo avrei impostato con un tipo dato (visto il numero di bit e il fatto che non scorre del tutto fuori schermo potrebbe bastare un byte solo) gestito bit a bit con lo shift a destra o a sinistra di un bit alla volta e una variabile per gestire la dissolvenza agli estremi una il contrario dell'altra, cioè considerando in percentuale se la variabile la facciamo crescente in percentuale, l'accensione sarebbe uguale alla variabile, lo spegnimento a 100-variabile. Un ciclo sarebbe composto da una intera dissolvenza e lo shift di 1 bit in un senso o nell'altro.
Al momento non ho molto tempo per giocarci e togliermi il dubbio, ma sono curioso di vedere la tua soluzione, se ci giocherai e vorrai condividere ;)
Magari abbiamo avuto un'idea simile :P
Nessuna buona azione resterà impunita!

Preistoria -> medioevo -> rinascimento -> risorgimento -> rincoglionimento!

doppiozero

L'effetto è ottimo, ma voglio provare a giocare un poco sull'implementazione perché il codice non l'avrei scritto proprio così... ;)

sicuramente può essere scritto meglio  :D  l'ho scritto da super nabbo, oggi lo scriverei solo da quasi nabbo  :P
Runtime Clock Manager -- https://github.com/duezero/RCM---Runtime-Clock-Manager
GPX datalogger -- https://github.com/duezero/GPX-datalogger
AVR HV Rescue Board -- https://www.youtube.com/watch?v=EErKo0aTEio

maubarzi

#6
Mar 15, 2019, 10:15 am Last Edit: Mar 15, 2019, 10:17 am by maubarzi
Sei tu l'autore? io non direi meglio o peggio ma diverso e magari più compatto, che non necessariamente significa meglio ;)
La potremmo far diventare una gara tra nabbi, perchè mi ci metto pure io su questa definizione :P
Nessuna buona azione resterà impunita!

Preistoria -> medioevo -> rinascimento -> risorgimento -> rincoglionimento!

Standardoil

Piatto ricco mi ci ficco
Se mi permettete. ...
Prima legge di Nelson (che sono io): A parità di risultato maggiore è il pensiero, minore il lavoro. Quindi prima di fare pensa!
Non si da retta a studenti: andate a copiare da un'altra parte...
Lo hai visto su Youtube? -> lo chiedi su Youtube

doppiozero

Sei tu l'autore?
si l'ho fatto qualche anno fa. Mi ricordo di aver provato anche con un codice più semplice e consendatori per il fading, non era male, peccato che non ci sia il video

Runtime Clock Manager -- https://github.com/duezero/RCM---Runtime-Clock-Manager
GPX datalogger -- https://github.com/duezero/GPX-datalogger
AVR HV Rescue Board -- https://www.youtube.com/watch?v=EErKo0aTEio

docdoc

#9
Mar 15, 2019, 01:05 pm Last Edit: Mar 15, 2019, 01:55 pm by docdoc
sicuramente può essere scritto meglio  :D
Beh una prima "sgrossata" la farei così (non l'ho provata, ovviamente, ma solo scritta di getto):

Code: [Select]
#include <SoftPWM.h>
#include <SoftPWM_timer.h>

// Numero totale di LED
#define TOTLEDS 9
// Primo pin corrispondente a led[0] (pin consecutivi)
#define MINLED 2

unsigned long int StartTime = 0;
unsigned long int[TOTLEDS] StartTimeOld;
unsigned long int[TOTLEDS] delay;

byte[9] FadeIn;

byte[9] reset = true;

byte forward = false;

int[9] a;

const int TimeFadeIn = 1; // millis
const int TimeFadeOut = 3; //millis
const byte brightness = 110; // pwm value and speed

void setup() {
  SoftPWMBegin();

  Serial.begin(9600);

  for( int i=0; i<=TOTLEDS; ++i )
  {
StartTimeOld[i] = 0;
delay[i] = 0;
FadeIn[i] = true;
reset[i] = false;
a[i] = 0;
pinMode(MINLED+i, OUTPUT);
  }
  reset[0] = true;
}

void loop() {
  StartTime = millis();

  for( int i=0; i<=TOTLEDS; ++i )
    delay[i] = StartTime - StartTimeOld[i];

  for( int i=0; i<=TOTLEDS; ++i )
  {
    if (FadeIn[i] && delay[i] > TimeFadeIn && reset[i])
{
    SoftPWMSet(i+MINLED, ++a[i]);
    StartTimeOld[i] = StartTime;
    }
    else if (!FadeIn[i] && delay[i] > TimeFadeOut)
    {
      SoftPWMSet(i+MINLED, --a[i]);
      StartTimeOld[i] = StartTime;
    }
    if (a[i] == brightness)
{
      FadeIn[i] = false;
      reset[i] = false;
      if (forward && i < TOTLEDS)
        reset[i+1] = true;
      if (!forward && i > 0)
        reset[i-1] = true;
    }
else if ( a[i] == 0 )
{
  FadeIn[i] = true;
}
  }
}


Non assicuro che funzioni, soprattutto perché ho cercato di "dedurre" il funzionamento dal codice iniziale e carpire le cose che si potevano "vettorializzare" e parametrizzare (ti prego, le variabili a, b, c, d eccetera "nun se ponno vede" ;) infatti non sapendo bene a cosa servano le ho convertite in un array a[]) .
Ma può essere un punto di partenza, e soprattutto come vedi è mooooolto più compatto ;)
Alex "docdoc" - ** se ti sono stato d'aiuto, un punto karma sarà gradito, clicca su "add" qui a sinistra, vicino al mio nome ;) **

maubarzi

si l'ho fatto qualche anno fa.
Beh, che dire, l'effetto è notevole.
Da nabbo non avevo pensato al fading, ci sono arrivato solo dopo aver guardato il codice.
Anche la soluzione con i condensatori è interessante, vanno calcolate bene le resistenze per dare la giusta durata dell'effetto, il dubbio è che ad un certo punto c'è il gradino quando si scende sotto la tensione minima del led, forse con il pwm, a naso, è più graduale, meno spigoloso.
Nessuna buona azione resterà impunita!

Preistoria -> medioevo -> rinascimento -> risorgimento -> rincoglionimento!

manolomao

Stai sbagliando l'approccio, ovvero tu dici che vuoi lasciar libero Arduino di fare altri controlli, ma finché racchiudi l'effetto sui led all'interno di un cliclo for sarai legato a fare i controlli dento al for e ripeterli anche nell'altro for che gestirà l'effetto in ordine inverso.
Il consiglio che ti posso dare è di strutturare il programma in modo che ao ogni ciclo di loop se è trascorso il tempo tra uno step e il siccessivo venga eseguito quando necessario ovvero qualcosa del tipo:
Code: [Select]

void loop
{
  if(millis()-tempo_pausa>=20)
  {
     if(direzione==--->)
     {
        switch(i)
        {
           case 0:
              accendi il led N;
              break;
           case 1:
              accendi il led M;
           ecc.
        }
       i++;
       if(i>14)
       {
          i=0;
          direzione = <--;
       }
       
     }
     else
     {
        ..codice per direzione inversa
     }
     tempo_pausa = millis();
  }
  ...altri controlli...
}

Hai ragione, ragionandoci è davvero un errore madornale....

manolomao

Grazie a tutti per i consigli...
La libreria SoftPWM.h non la conoscevo....ci guarderò....
Ora il mio amico mi chiede se il "giochino" è fattibile farlo cno 16 led, utilizzando il MCP2301.
So che è un I/O expander in I2C...
Dite che è fattibile farlo???

Datman

#13
Mar 15, 2019, 03:50 pm Last Edit: Mar 15, 2019, 03:51 pm by Datman
Io farei diversamente: senza usare la libreria, farei un loop() velocissimo che accende i led in sequenza e, al tempo stesso, accende i due led precedenti (se ci sono, a sinistra all'andata e a destra al ritorno, se vogliamo fare una vera scia) con un duty cycle del 40% e del 10%. Il duty cycle si può realizzare semplicemente contando i "passaggi" con un contatore (ad es. byte A): per il 40% resta acceso per valori di A da 1 a 4 e resta spento per valori da 5 a 10; per il 10% resta acceso se A vale 1 e resta spento per valori da 2 a 10. Se vogliamo fare il 15%, basta contare da 1 a 20  e tenerlo acceso da 1 a 3.
Hi,I'm Gianluca from Roma.I play&work with electronics since I was16(1984).
After 25yrs of maintenance on cameras&video mixers,since 2013myJob is HDTVstudios design.
Since Jan2015 IPlayWith Arduino:bit.ly/2F3LPWP
Thanks 4 a Karma if U like my answer

maubarzi

Mi hai letto nel pensiero, stavo ragionando su una cosa analoga anche io senza librerie ma solo loop a manetta opportunamente temporizzato.
Per pilotare i led stavo pensando ad uno shift register a 8 bit.
La dissolvenza la stavo pensando a step del 20%.
Per lo scorrimento stavo pensando ad uno shift di un bit su un byte ogni 5 passi che identifica il bit centrale degli 8 della serie (ho controllato sul film quante luci c'erano :P ) che va da un estremo all'altro.
Il led subito a destra o subito a sinistra sarebbe in dissolvenza.

Ho provato a valutare anche l'opzione con dissolvenza fatta con condensatore ma mi sono venuti valori abbastanza grandi, dell'ordine del mF da 100uF a 2mF a seconda della durata della dissolvenza con corrente di picco sul led di 20mA. Un po' tantino, per cui ho accantonato l'idea.
Nessuna buona azione resterà impunita!

Preistoria -> medioevo -> rinascimento -> risorgimento -> rincoglionimento!

Go Up