rotazione sincronizzata di due differenti ring Neopixels

Ciao a tutti!

Ho un problema con due anelli Neopixel:
Gli anelli sono composti da 24 e 16 pixel e il mio obbiettivo è riuscire a fare, nell’anello grande, due gruppi simmetrici di 4 led accesi (4 accesi, 8 spenti, 4 accesi, 8 spenti)che ruotano in sincrono con la rotazione dell’anello più piccolo che però ha due gruppi da 3 led accesi (3 accesi, 5 spenti, 3 accesi, 5 spenti). Il problema sta che finora sono riuscito a farli andare entrambi alla stessa velocità con questo programma:

#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
 #include <avr/power.h>
#endif

#define PixelCount 24 //numero led anello grande
#define PixelCountp 16 //numero  led anello piccolo

Adafruit_NeoPixel destra = Adafruit_NeoPixel(PixelCount, 7, NEO_GRBW + NEO_KHZ800); //anello grande
Adafruit_NeoPixel destrap = Adafruit_NeoPixel(PixelCountp, 4, NEO_GRBW + NEO_KHZ800); //anello piccolo

uint8_t  offset = 0;
uint32_t color  = 0x800080; // Start viola
uint32_t prevTime;



void setup(){
  destra.begin();
  destra.setBrightness(55);
  destrap.begin();
  destrap.setBrightness(55);
}

void loop(){

  for(byte x = 0; x < 20; x++){
    rotatePixels(false);
   delay(70);
  }
}

void rotatePixels(bool pixColour){
  static byte currentPos = 0; //posizione anello grande
  
  uint32_t colour = 0x800080; // Default viola
  
  if(++currentPos >= PixelCount){
    currentPos = 0;
  }
  static byte currentPosp = 0; //posizione anello piccolo
  
  if(++currentPosp >= PixelCountp){
    currentPosp = 0;
  }
  
  destra.setPixelColor((currentPos + PixelCount - 1) % PixelCount, 0);
  destra.setPixelColor((currentPos + PixelCount + 0) % PixelCount, 0);
  destra.setPixelColor((currentPos + PixelCount + 1) % PixelCount, 0);
  destra.setPixelColor((currentPos + PixelCount + 2) % PixelCount, 0);
  destra.setPixelColor((currentPos + PixelCount + 3) % PixelCount, 0);
  destra.setPixelColor((currentPos + PixelCount + 4) % PixelCount, 0);
  destra.setPixelColor((currentPos + PixelCount + 5) % PixelCount, 0);
  destra.setPixelColor((currentPos + PixelCount + 6) % PixelCount, 0);
  destra.setPixelColor((currentPos + PixelCount + 7) % PixelCount, 0);
  destra.setPixelColor((currentPos + PixelCount + 8) % PixelCount, colour);
  destra.setPixelColor((currentPos + PixelCount + 9) % PixelCount, colour);
  destra.setPixelColor((currentPos + PixelCount + 10) % PixelCount, colour);
  destra.setPixelColor((currentPos + PixelCount + 11) % PixelCount, colour);
  destra.setPixelColor((currentPos + PixelCount + 12) % PixelCount, 0);
  destra.setPixelColor((currentPos + PixelCount + 13) % PixelCount, 0);
  destra.setPixelColor((currentPos + PixelCount + 14) % PixelCount, 0);
  destra.setPixelColor((currentPos + PixelCount + 15) % PixelCount, 0);
  destra.setPixelColor((currentPos + PixelCount + 16) % PixelCount, 0);
  destra.setPixelColor((currentPos + PixelCount + 17) % PixelCount, 0);
  destra.setPixelColor((currentPos + PixelCount + 18) % PixelCount, 0);
  destra.setPixelColor((currentPos + PixelCount + 19) % PixelCount, 0);
  destra.setPixelColor((currentPos + PixelCount + 20) % PixelCount, colour);
  destra.setPixelColor((currentPos + PixelCount + 21) % PixelCount, colour);
  destra.setPixelColor((currentPos + PixelCount + 22) % PixelCount, colour);
  destra.setPixelColor((currentPos + PixelCount + 23) % PixelCount, colour);

  
  destrap.setPixelColor((currentPosp + PixelCountp - 1) % PixelCountp, 0);
  destrap.setPixelColor((currentPosp + PixelCountp + 0) % PixelCountp, 0);
  destrap.setPixelColor((currentPosp + PixelCountp + 1) % PixelCountp, 0);
  destrap.setPixelColor((currentPosp + PixelCountp + 2) % PixelCountp, 0);
  destrap.setPixelColor((currentPosp + PixelCountp + 3) % PixelCountp, 0);
  destrap.setPixelColor((currentPosp + PixelCountp + 4) % PixelCountp, 0);
  destrap.setPixelColor((currentPosp + PixelCountp + 5) % PixelCountp, colour);
  destrap.setPixelColor((currentPosp + PixelCountp + 6) % PixelCountp, colour);
  destrap.setPixelColor((currentPosp + PixelCountp + 7) % PixelCountp, colour);
  destrap.setPixelColor((currentPosp + PixelCountp + 8) % PixelCountp, 0);
  destrap.setPixelColor((currentPosp + PixelCountp + 9) % PixelCountp, 0);
  destrap.setPixelColor((currentPosp + PixelCountp + 10) % PixelCountp, 0);
  destrap.setPixelColor((currentPosp + PixelCountp + 11) % PixelCountp, 0);
  destrap.setPixelColor((currentPosp + PixelCountp + 12) % PixelCountp, 0);
  destrap.setPixelColor((currentPosp + PixelCountp + 13) % PixelCountp, colour);
  destrap.setPixelColor((currentPosp + PixelCountp + 14) % PixelCountp, colour);
  destrap.setPixelColor((currentPosp + PixelCountp + 15) % PixelCountp, colour);

  
  destra.show();
  destrap.show();
}

solo che andando alla stessa velocità ovviamente l’anello piccolo finisce prima il suo giro sfasando poi la formazione completa.

Ho già guardato diversi altri topic dove utilizzavano millis() ma quando pensavo di aver capito ho visto che questo programma è il più funzionale rispetto a quelli con millis che neanche facevano accendere i led.
Grazie mille in anticipo

Buona sera,
essendo il tuo primo post nella sezione Italiana del forum, nel rispetto del nostro regolamento, ti chiedo cortesemente di presentarti QUI (spiegando bene quali conoscenze hai di elettronica e di programmazione ... possibilmente evitando di scrivere solo una riga di saluto) e di leggere con MOLTA attenzione il su citato REGOLAMENTO ... Grazie. :slight_smile:

Fatto, scusate

Accendendo i led alla solita frequenza non c'è possibilità di ottenere il sincronismo di cui tu parli, hai un solo delay che comanda entrabe i cerchi, essendo dotati di un numero differente di pixel non puoi arrivare al tuo obiettivo se non differenziando il tempo di accensione dei due ring in modo indipendente.
Così su due piedi ti direi che devi calcolare il tempo necessario a completare il giro del ring più esterno, di quello più piccolo e suddividere i due tempi totali per il numero di accensioni, da questo conto dovresti avere il tempo in millisecondi che devono trascorrere per ciascun cerchio tra un accensione e l'altra.
A questo punto devi suddividere in due funzioni distinte quello che adesso è tutto dentro la funzione rotatePixel in modo da poterle richiamare in modo indipendente l'una dall'altra.
Nel loop principale richiamerai le due funzioni in base al tempo trascorso con calcolato con millis().
Magari esiste un alternativa usando il delay() ma a me non viene in mente nulla in tal senso.

Non so se è lo stesso calcolo che mi proponevi di fare te ma ne avevo fatto uno dove avevo pensato questo:

  • una rotazione doveva durare 70ms
  • avendo 4 led accesi il ring grande aveva questo tempograndeacceso = (70/24)*4
  • stessa cosa con il ring più piccolo con tempopiccoloacceso = (70/16)*3
  • in più ho fatto anche il conto per quanto devono stare spenti ossia tempograndespento = (70/24)*8 e tempopiccolospento = (70/16)*5)

Da tutto questo è venuto questo programma:

#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
 #include <avr/power.h>
#endif

#define PixelCount 24
#define PixelCountp 16

Adafruit_NeoPixel destra = Adafruit_NeoPixel(PixelCount, 7, NEO_GRBW + NEO_KHZ800);
Adafruit_NeoPixel destrap = Adafruit_NeoPixel(PixelCountp, 5, NEO_GRBW + NEO_KHZ800);

uint32_t color  = 0x800080;
unsigned long startmillis; //variabili disponibili in tutto il programma
unsigned long accesograndemillis;
unsigned long accesopiccolomillis;
unsigned long spentograndemillis;
unsigned long spentopiccolomillis;
unsigned long currentmillis;
const unsigned long tempograndeacceso = 11.67;
const unsigned long tempograndespento = 23.33;
const unsigned long tempopiccolospento = 21.875;
const unsigned long tempopiccoloacceso = 13.125;

void setup(){
  startmillis = millis();  //tempo iniziale
  destra.begin();
  destra.show();
  destra.setBrightness(55);
  destrap.begin();
  destrap.show();
  destrap.setBrightness(55);
  accesograndemillis = millis(); //partenza del tempo di accensione ring grande
  spentograndemillis = millis(); //partenza del tempo di spegnimento ring grande
  accesopiccolomillis = millis();
  spentopiccolomillis = millis();
}

void loop(){
  currentmillis = millis(); //prende il tempo attuale  
  
}

void Tempograndeacceso(){
 static byte currentpos = 0;
  if(++currentpos >= PixelCount){
    currentpos = 0;
  }
  
  if(currentmillis - accesograndemillis >= tempograndeacceso)//controlla se il tempo è passato
 {
  destra.setPixelColor((currentpos + PixelCount) % PixelCount, color);
  }
destra.show();
destrap.show();
}

void Tempograndespento(){
  static byte currentpos = 0;
  if(++currentpos >= PixelCount){
    currentpos = 0;
  }
  
  if(currentmillis - spentograndemillis >= tempograndespento)//controlla se il tempo è passato
 {
  destra.setPixelColor((currentpos + PixelCount) % PixelCount, 0);
  }
destra.show();
destrap.show();
}

void Tempopiccoloacceso(){
  static byte currentposp = 0;
  if(++currentposp >= PixelCountp){
    currentposp = 0;
  }
  
  if(currentmillis - accesopiccolomillis >= tempopiccoloacceso)//controlla se il tempo è passato
 {
  destrap.setPixelColor((currentposp + PixelCountp) % PixelCountp, color);
  }
destra.show();
destrap.show();
}

void Tempopiccolospento(){
  static byte currentposp = 0;
  if(++currentposp >= PixelCountp){
    currentposp = 0;
  }
  
  if(currentmillis - spentopiccolomillis >= tempopiccolospento)//controlla se il tempo è passato
 {
  destrap.setPixelColor((currentposp + PixelCountp) % PixelCountp, 0);
  }
destra.show();
destrap.show();
}

Non riesco a capire l’errore visto che non mi si accende neanche un led e con millis ho poca dimestichezza

Sei sicuro che un giro dovrebbe durare 70 millisecondi?
Secondo me non si vede perché troppo corto.

Ciao Uwe

EliaFratta:
Non riesco a capire l’errore visto che non mi si accende neanche un led e con millis ho poca dimestichezza

Non è poca dimestichezza con millis() non ti si accende un tubo semplicemente perché dentro il loop non fai nulla se non riassegnare il valore restituito da millis() alla variabile currentmillis, che per inciso non ti serve a nulla al suo posto puoi usare direttamente millis().
In questi casi il consiglio che fornisco è sempre il solito, fai un passo indietro. So che è difficile mentalmente da fare perché “Sono al 99% non posso buttare tutto devo farcela” solitamente si trasforma in un immensa pedita di tempo per risolvere quell’1% se va bene, non si arriva mai al 100% se va male.
Parcheggia il tuo programma e riparti con uno nuovo dove ti concentrerai a far funzionare un solo anello usando millis() in modo tale che rispetti le tue specifiche (ovvero tipo di gioco di luce e tempo in cui deve essere eseguito) il tutto dal loop principale. Quando funzionerà al 100% sposta tutto il contenuto del loop che si occupa del gioco di luce in una funzione e richiamala nel loop e verifica che ancora tutto funzioni.
Quando sei a quel punto parcheggia anche questo e rifai la solita cosa per l’anello più piccolo.
Quando anche il secondo programma sarà funzionante al 100% ti basterà copiare la funzione dell’anelo più piccolo nel programma dell’anello più grande e dopo aver richiamato la funzione per l’anello più grande nel loop dovrai semplicemente richiamare anche la funzione dell’anello più piccolo.
E consordo con 70mS sono veramente pochi a scopo di debug di consiglio di ampliare questo tempo e anche ti molto ovvero mi prefisserei di far fare il giro alle luci in uno o due secondi, finito il debug cambiando semplicemente i valori confrontati con millis() potrai velocizzare il tutto in modo molto semplice
Inolte ti consigio di controllare il reference del tipo unsigned long perché opuoi usare solo numeri interi, non pensare di trasformare in float quelle variabili perché tanto millis() restituirà comunque un intero e saresti punto e accapo. A occhio nudo a meno che tu non stia realizzando il tutto per un robot è impossibile accorgersi di differenze nell’ordine della frazione di un millisecondo

Avevate ragione, 70ms sono pochi, infatti il giro dura in tutto un secondo e mezzo. Avevo detto 70 perchè negli altri programmi con il delay era quello il valore che mi dava una rotazione a me gradita.

Ho seguito il tuo consiglio di fare un nuovo programma tutto da capo dove poter fare ogni singola prova. A questo punto almeno sono riuscito ad accendere i led ma l'unico risultato che ho ottenuto è stato di ritardare l'accensione dei led i quali però vanno ad una velocità esagerata.

void loop(){
  static byte currentPos = 0;
  if(++currentPos >= PixelCount){
    currentPos = 0;
  }
  currentmillis = millis(); //prende il tempo attuale
  
if(currentmillis - accesograndemillis >= tempograndeacceso){
  startmillis = currentmillis;
  destra.setPixelColor((currentPos + PixelCount - 1) % PixelCount, 0);
  destra.setPixelColor((currentPos + PixelCount + 0) % PixelCount, 0);
  destra.setPixelColor((currentPos + PixelCount + 1) % PixelCount, 0);
  destra.setPixelColor((currentPos + PixelCount + 2) % PixelCount, 0);
  destra.setPixelColor((currentPos + PixelCount + 3) % PixelCount, 0);
  destra.setPixelColor((currentPos + PixelCount + 4) % PixelCount, 0);
  destra.setPixelColor((currentPos + PixelCount + 5) % PixelCount, 0);
  destra.setPixelColor((currentPos + PixelCount + 6) % PixelCount, 0);
  destra.setPixelColor((currentPos + PixelCount + 7) % PixelCount, 0);
  destra.setPixelColor((currentPos + PixelCount + 8) % PixelCount, colour);
  destra.setPixelColor((currentPos + PixelCount + 9) % PixelCount, colour);
  destra.setPixelColor((currentPos + PixelCount + 10) % PixelCount, colour);
  destra.setPixelColor((currentPos + PixelCount + 11) % PixelCount, colour);
  destra.setPixelColor((currentPos + PixelCount + 12) % PixelCount, 0);
  destra.setPixelColor((currentPos + PixelCount + 13) % PixelCount, 0);
  destra.setPixelColor((currentPos + PixelCount + 14) % PixelCount, 0);
  destra.setPixelColor((currentPos + PixelCount + 15) % PixelCount, 0);
  destra.setPixelColor((currentPos + PixelCount + 16) % PixelCount, 0);
  destra.setPixelColor((currentPos + PixelCount + 17) % PixelCount, 0);
  destra.setPixelColor((currentPos + PixelCount + 18) % PixelCount, 0);
  destra.setPixelColor((currentPos + PixelCount + 19) % PixelCount, 0);
  destra.setPixelColor((currentPos + PixelCount + 20) % PixelCount, colour);
  destra.setPixelColor((currentPos + PixelCount + 21) % PixelCount, colour);
  destra.setPixelColor((currentPos + PixelCount + 22) % PixelCount, colour);
  destra.setPixelColor((currentPos + PixelCount + 23) % PixelCount, colour);
  
  destra.show();
}
  }

Qui appunto l'utilizzo di millis mi porta a ritardare soltanto l'accensione. Quale potrebbe essere un modo corretto per scrivere in modo tale da far durare la parte destra.setPixelColor ecc. 1,5 secondi?

Mi potresti dire a parole cosa fa il loop quando viene eseguito, passo passo intendo Es.

diritalWrite(13,HIGH);
if(Serial.available())
{
....
}
ecc.

diventa
Mette il pin 13 allo stato HIGH
verifica se ci sono dati nella seriale, se si allora
...
ecc.

void loop(){
  static byte currentPos = 0;
  if(++currentPos >= PixelCount){
    currentPos = 0;
  }
  currentmillis = millis(); //prende il tempo attuale
  
if(currentmillis - accesograndemillis >= tempograndeacceso){
  startmillis = currentmillis;
  destra.setPixelColor((currentPos + PixelCount - 1) % PixelCount, 0);
  destra.setPixelColor((currentPos + PixelCount + 0) % PixelCount, 0);//8 led spenti
  destra.setPixelColor((currentPos + PixelCount + 1) % PixelCount, 0);
  destra.setPixelColor((currentPos + PixelCount + 2) % PixelCount, 0);
  destra.setPixelColor((currentPos + PixelCount + 3) % PixelCount, 0);
  destra.setPixelColor((currentPos + PixelCount + 4) % PixelCount, 0);
  destra.setPixelColor((currentPos + PixelCount + 5) % PixelCount, 0);
  destra.setPixelColor((currentPos + PixelCount + 6) % PixelCount, 0);
  destra.setPixelColor((currentPos + PixelCount + 7) % PixelCount, 0);
  destra.setPixelColor((currentPos + PixelCount + 8) % PixelCount, colour);//4 led accesi
  destra.setPixelColor((currentPos + PixelCount + 9) % PixelCount, colour);
  destra.setPixelColor((currentPos + PixelCount + 10) % PixelCount, colour);
  destra.setPixelColor((currentPos + PixelCount + 11) % PixelCount, colour);
  destra.setPixelColor((currentPos + PixelCount + 12) % PixelCount, 0);//8 led accesi
  destra.setPixelColor((currentPos + PixelCount + 13) % PixelCount, 0);
  destra.setPixelColor((currentPos + PixelCount + 14) % PixelCount, 0);
  destra.setPixelColor((currentPos + PixelCount + 15) % PixelCount, 0);
  destra.setPixelColor((currentPos + PixelCount + 16) % PixelCount, 0);
  destra.setPixelColor((currentPos + PixelCount + 17) % PixelCount, 0);
  destra.setPixelColor((currentPos + PixelCount + 18) % PixelCount, 0);
  destra.setPixelColor((currentPos + PixelCount + 19) % PixelCount, 0);
  destra.setPixelColor((currentPos + PixelCount + 20) % PixelCount, colour);//4 led spenti
  destra.setPixelColor((currentPos + PixelCount + 21) % PixelCount, colour);
  destra.setPixelColor((currentPos + PixelCount + 22) % PixelCount, colour);
  destra.setPixelColor((currentPos + PixelCount + 23) % PixelCount, colour);
  
  destra.show();
}
  }

Allora il loop di prima praticamente fa questo: assegna il valore 0 alla posizione corrente alla partenza del programma. Questa posizione aumenta progressivamente per poter permettere il movimento dei led illuminati. E’ inserito if(currentmillis - accesograndemillis >= tempograndeacceso) perchè è l’unico modo che ho trovato sulla temporizzazione con millis. Tutta la parte di destra.set l’ho inserita per poter gestire la distribuzione dei led accesi e spenti, sinceramente non so a cosa serva % PixelCount in aggiunta alla parentesi perchè è una parte di programma che ho trovato qui sul forum modificato per adattarlo alla mia situazione.
Il mio problema sorge nel fatto che prima la velocità di rotazione dei led la gestivo con un delay di 70ms subito dopo destra.show ma con l’aggiunta di un altro anello, con un numero minore di led, o avevo un rallentamento totale del programma che perdeva la fluidità che vorrei oppure ottenevo uno sfasamento del sincronismo del primo e del secondo anello.

La mia necessità sta nel trovare un metodo per gestire la velocità di rotazione degli anelli senza avere rallentamenti come li avrei utilizzando delay.
In teoria un giro completo dovrebbe durare 1.5 secondi

Nella tua idea dovrebbe fare quello, in realtà no ;D

  • Entri nel loop inizializzi la variabiel a zero (tralascio il fatto che definire una variabile static quando non strettamente necessario è farsi del male soprattutto perché il codice così ad una rapida lettura è ingannevole e porta a pensare che ad ogni ciclo la variabile si azzeri, definiscila globale e inizializza a zero nel setup)
  • Incrementi la variabile e verifichi se hai superato il numero di pixel se si la azzeri
  • Verifichi se è trascorso il tempo per accendere il led successivo, Non è passato, non fai nulla
  • Incrementi la variabile e verifichi se hai superato il numero di pixel se si la azzeri
  • Verifichi se è trascorso il tempo per accendere il led successivo, Non è passato, non fai nulla
  • Incrementi la variabile e verifichi se hai superato il numero di pixel se si la azzeri
  • Verifichi se è trascorso il tempo per accendere il led successivo, Non è passato, non fai nulla
  • Incrementi la variabile e verifichi se hai superato il numero di pixel se si la azzeri
  • Verifichi se è trascorso il tempo per accendere il led successivo, Non è passato, non fai nulla
  • Incrementi la variabile e verifichi se hai superato il numero di pixel se si la azzeri
  • Verifichi se è trascorso il tempo per accendere il led successivo, Non è passato, non fai nulla
  • Incrementi la variabile e verifichi se hai superato il numero di pixel se si la azzeri
  • Verifichi se è trascorso il tempo per accendere il led successivo, Non è passato, non fai nulla
  • Incrementi la variabile e hai superato il numero di pixel la azzeri
  • Verifichi se è trascorso il tempo per accendere il led successivo, Non è passato, non fai nulla
  • Incrementi la variabile e verifichi se hai superato il numero di pixel se si la azzeri
  • Verifichi se è trascorso il tempo per accendere il led successivo, Non è passato, non fai nulla
  • Incrementi la variabile e verifichi se hai superato il numero di pixel se si la azzeri
  • Verifichi se è trascorso il tempo per accendere il led successivo, Non è passato, non fai nulla
  • Incrementi la variabile e verifichi se hai superato il numero di pixel se si la azzeri
  • Verifichi se è trascorso il tempo per accendere il led successivo, è passato, accendi il led attuale
  • Incrementi la variabile e verifichi se hai superato il numero di pixel se si la azzeri
  • Verifichi se è trascorso il tempo per accendere il led successivo, Non è passato, non fai nulla
  • Incrementi la variabile e verifichi se hai superato il numero di pixel se si la azzeri
  • Verifichi se è trascorso il tempo per accendere il led successivo, Non è passato, non fai nulla

Siccome il loop viene eseguito in pochissimi microsecondi e tu accendi ogni tot millisecondi è normale che non hai l'effetto desiderato, come faresti a incrementare e accendere i led ogni tot millisecondi? Prova...

Incrementi la variabile e verifichi se hai superato il numero di pixel se si la azzeri

Dopo l’ultimo post mi è venuto in mente che potrei semplicemente temporizzare l’aumento della variabile currentPos. Quindi mi è venuto questo programma, dopo aver snellito anche l’impostazione dei led e aver impostato un tempomovimento che serve per aumentare progressivamente la variabile.

#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
 #include <avr/power.h>
#endif
 
#define PixelCount 24

Adafruit_NeoPixel destra = Adafruit_NeoPixel(PixelCount, 7, NEO_GRBW + NEO_KHZ800);

uint32_t colour  = 0x800080;
unsigned long startmillis; //variabili disponibili in tutto il programma
unsigned long accesograndemillis;
unsigned long spentograndemillis;
unsigned long movimentomillis;
unsigned long currentmillis;
const unsigned long tempomovimento = 10000;//lasso  di tempo in cui currentpos aumenta di valore
const unsigned long tempograndeacceso = 750;
const unsigned long tempograndespento = 500;
uint8_t currentPos = 0;

void setup(){
  startmillis = millis();  //tempo iniziale
  destra.begin();
  destra.show();
  destra.setBrightness(55);
  movimentomillis = millis(); //
  accesograndemillis = millis(); //partenza del tempo di accensione ring grande
  spentograndemillis = millis(); //partenza del tempo di spegnimento ring grande
}

void loop(){
  if(currentmillis - movimentomillis >= tempomovimento){
  if(++currentPos >= PixelCount){
    currentPos = 0;
  }
  startmillis = currentmillis;
  }
  destra.setPixelColor((currentPos + PixelCount - 4) % PixelCount, 0);
  destra.setPixelColor((currentPos) % PixelCount, colour);
  destra.setPixelColor((currentPos + PixelCount + 8) % PixelCount, 0);
  destra.setPixelColor((currentPos + PixelCount + 12) % PixelCount, colour);
  
  
  destra.show();
}

}

Questo programma è sicuramente sbagliato in quanto comunque la rotazione è ancora veloce a prescindere da quanto tempo io imposti. Sapete come posso correggerlo? E’ un idea valida temporizzare l’aumento della variabile invece di temporizzare il settaggio dei led?

Posso dire la mia fregnaccia?

Io farei così:
Un giro dura 1,5s cioè 1500 ms
L’anello più grande ha 24 led quindi dovrebbe fare un passo ogni 1500/24 = 62,5ms
L’anello più piccolo ha 16 led quindi dovrebbe fare un passo ogni 1500/16 = 93,75ms
Decimali brutti, come li eliminiamo?
Troviamo il minimo comune multiplo tra il numero di led dei due anelli: 48 giusto?
Ora 1500/48 = 31,25
Eliminiamo i decimali arrotondando per difetto: 31
31ms è la misura di un nostro passo standard.
Ora, l’anello grande ruota una volta ogni 2 passi: 48/24 = 2
L’anello piccolo ruota una volta ogni 3 passi: 48/16 = 3
Giusto?
In questo modo i due anelli sono sincronizzati.

L’anello grande lo possiamo rappresentare da 24 bit nel seguente modo:
111100000000111100000000
1=led acceso, 0=led spento
L’anello piccolo con 16 bit nel seguente modo:
1110000011100000
Nel primo caso sono 3 byte, nel secondo 2 byte.
11110000 00001111 00000000
11100000 11100000

ora possiamo scrivere una logica dove ogni due passi fa uno shift di 1 bit a sinistra della striscia grande, facendo rientrare a destra il bit che esce a sinistra
mentre ogni tre passi fa uno shift a destra della striscia piccola facendo rientrare a sinistra il bit che esce a destra.

dopo 3 cicli avrei
11100000 00011110 00000001
01110000 01110000
Ora posso accendere o spegnere i relativi led leggendo il valore dei singili bit.
Ovviamente ogni led sarà associato ad un bit della relativa struttura.

Tadaaaaan

Si fa prima a scriverlo che a spiegarlo mi sa.

Ad es. l’anello grande potrei gestirlo con 3 byte:
byte G2 = B11110000;
byte G1 = B00001111;
byte G0 = B00000000;
che saranno considerati uniti in questo modo G2G1G0
l’anello piccolo con 2 byte:
byte P1 = B11100000;
byte P0 = B11100000;
che consideriamo uniti come P1P0
G sta per grande e P per piccolo.

Con un for i da 0 a 7 posso settare tutti i led con 5 istruzioni, una per ogni byte definito leggendo il bit di posizione i

con bitRead() leggo il bit che uscirà dopo lo shift per poterlo far rientrare dal lato opposto.
con G2<<1 faccio scorrere i bit a sinistra di 1
con P1>>1 faccio scorrere i bit a destra di 1
se il bit che esce è 1 lo faccio rientrare dal lato opposto con bitWrite()
leggo valorePrecedentementeLetto
shifto G2
bitWrite(G2, 0, bitRead(G1, 0));
shifto G1
bitWrite(G1, 0, bitRead(G0, 0));
shifto G0
bitWrite(G0, 0, valorePrecedentementeLetto);

leggo valorePrecedentementeLetto
shifto P1
bitWrite(P1, 7, bitRead(P0, 7));
shifto P0
bitWrite(P0, 7, valorePrecedentementeLetto);

posso salvarmi 2 variabili di temporizzazione e fare i due shift una ogni 312=62 milliseconti e una ogni 313=93 millisecondi temporizzando con millis.

Tutto molto incasinato?

EliaFratta:
Questo programma è sicuramente sbagliato in quanto comunque la rotazione è ancora veloce a prescindere da quanto tempo io imposti. Sapete come posso correggerlo? E' un idea valida temporizzare l'aumento della variabile invece di temporizzare il settaggio dei led?

Parto dal consiglio, innutile ridefinire e rifare la show ad ogni ciclo di loop se non cambiano i pixel.
Detto ciò, perdonami ma, programmi senza attenzione e soprattutto non hai chiaro l'uso di millis() secondo me dovresti proprio ripartire a studiare millis anche con un programma che non fa nulla che me si limita a stampare su seriel ogni secondo un messaggio perché così andrai poco lontano.
Detto che funzionerebbe comunque male il programma segui la variabile currentmillis, startmillis e vedrai che di ambedue ne fai un uso assolutamente innutile in assoluto e nello specifico alla soluzione del problema

maubarzi:
Tutto molto incasinato?

Non entro nel merito della tua idea (che è sicuramente valida) sulla quale non mi sono soffermato ad analizzare la struttura ma a mio modesto parere fornire un idea con bitshift e quant'altro seuppur efficente e bella all'OP che ha difficoltà con la programmazione di base lo potrebbe portare in un caos assoluto, magari risolverebbe il problema attuale con il copia/incolla ma non imparerebbe nulla e in futuro sarebbe punto e accapo, sempre IMHO

fabpolli:
... fornire un idea con bitshift e quant'altro seuppur efficente e bella all'OP che ha difficoltà con la programmazione di base lo potrebbe portare in un caos assoluto, magari risolverebbe il problema attuale con il copia/incolla ma non imparerebbe nulla e in futuro sarebbe punto e accapo, sempre IMHO

Concordo al 100% ... adeguare sempre le soluzioni alla preparazione di chi si ha davanti, magari consigliadogli, per il futuro, di esaminare altre possibili soluzioni.

Guglielmo

capisco, imparo e mi adeguo :wink:

Avendo necessità che funzioni tutto il prima possibile sono anche aperto a proposte alternative, meglio se più valide. Quindi sarei molto interessato anche alla proposta di maubarzi anche perché l'unico modo per studiarmi millis è solo in via teorica perché non ho i materiali come motori o display che trovo nella maggior parte di tutorial. L'unica cosa è, riferendomi a maubarzi, mi servirebbero proprio parti di codice così da non scrivere errato e poter capire al meglio il procedimento nuovo

Non hai bisogno di nulla se non una scheda Arduino i link che ti fornito per capire millis e un po' di fantasia, ad esempio prima ti ho suggerito di stampare su monitor seriale ogni secondo una frase a tua scelta, quando riesci a fare quello puoi provare a modificare il tempo e/o introdurre due controlli sifferenti, il primo stampa ogni secondo il secondo ogni tre secondi, se riesci a fare quello capendo come impostare controllare millis() hai risolto e a quel punto potrai costruire il tuo vero programma

Seguendo il mio post ho buttato giù lo scheletro di temporizzazione.
Questo è valido a prescindere dal fatto di usare la mia logica con lo shift dei bit o un'altra logica più alla portata.
Lo puoi prendere per capire come funziona millis.
Da questo, dovresti capire come fare quello che ti chiede fabpolli.
Se capisci il mio codice e fai l'esercizio proposto da fabpolli, dovresti arrivare alla comprensione di come funziona millis e si può passare allo step successivo.

Come vedi non serve nulla se non arduino e la seriale per vedere il risultato.

#define MILLIS_PASSO 31 * 10 // Ho moltiplicato per 10 per rallentare e vedere i singoli passi a velocità umana.
#define PASSI_STEP_GRANDE 2
#define PASSI_STEP_PICCOLO 3

unsigned long lastMillisCerchioGrande = 0;
unsigned long lastMillisCerchioPiccolo = 0;

void setup() {
  Serial.begin(9600);
  unsigned long currMillis = millis(); // Solo per avere lo stesso valore su tutte le assegnazioni. Pignoleria mia.
  lastMillisCerchioGrande = currMillis;
  lastMillisCerchioPiccolo = currMillis;
}

void loop() {
  unsigned long currMillis = millis(); // Solo per avere lo stesso valore su tutte le operazioni. Pignoleria mia.
  avanzaCerchioGrande(currMillis);
  avanzaCerchioPiccolo(currMillis);
}

void avanzaCerchioGrande(unsigned long curr) {
  if (curr - lastMillisCerchioGrande >= MILLIS_PASSO * PASSI_STEP_GRANDE) {
    // Logica di avanzamento di un passo del cerchio grande.
    /*
     * 
     */
    Serial.print("G");
    lastMillisCerchioGrande += MILLIS_PASSO * PASSI_STEP_GRANDE;
  }
}

void avanzaCerchioPiccolo(unsigned long curr) {
  if (curr - lastMillisCerchioPiccolo >= MILLIS_PASSO * PASSI_STEP_PICCOLO) {
    // Logica di avanzamento di un passo del cerchio grande.
    /*
     * 
     */
    Serial.print("P");
    lastMillisCerchioPiccolo += MILLIS_PASSO * PASSI_STEP_PICCOLO;
  }
}

Il risultato è la stampa su seriale di una sequenza continua di caratteri che si alternano tra G e P.
Es. GPGGPGPGGPGPGGPGPGGPGPGGPGPGGPGPGGPGPGGP
come vedi ogni tanto tra le P c'è G e ogni tanto GG
Perchè? perchè il cerchio grande deve ruotare più velocemente e quindi fa più passi.
G sta per Grande e P sta per Piccolo e si riferiscono ai cerchi di led :wink: