Aiuto.... Possibile problema con gli interrupt di un encoder

Buongiorno, vado subito a descrivere il problema:
ho composto uno sketch in cui una scheda relè viene pilotata in relazione al numero di rotazioni di un motore a cui é collegato un encoder rotativo per il rilevamento di quest'ultimi.
Il codice funziona bene sull'apparato "prototipo" ma non su quello definitivo il quale si differenzia dal prototipo solo per per il modello di encoder utilizzato, se sul prototipo é montato un piccolo encoder rotativo mosso manualmente giusto per testare lo sketch, sull'apparato definitivo é montato un encoder rotativo industriale che gira assieme al motore a cui è meccanicamente collegato .
Fatta questa premessa vado ad esporre dove si presenta la problematica :
nell' insieme di tutto il circuito è presente un pulsante che deve mettere in "pausa" un ciclo di funzionamento ben definito e che sulla scheda prototipo funziona correttamente con l'unica differenza che l'encoder è mosso manualmente, testando il tutto sul circuito definitivo invece quando si prova la funzione di pausa metre l'encoder gira assieme al motore essa non solo non risponde ma causa malfunzionamento in tutta la logica del programma da me scritto .
Ho già provato a sostituire la scheda arduino pensando ad un difetto hardware ma niente, si comporta allo stesso modo , quindi sono giunto alla conclusione che la problematica risieda nella continua richiesta di interrupt generata dall'encoder in movimento che in qualche modo non lascia spazio al resto della logica di funzionamento.
La mia è una congettura ma lascio spazio ai più esperti per cercare di venirne a capo e risolvere il problema .
Grazie

parafrasando un detto: "vedere programma dare suggerimento".

sarebbe interessante vedere anche lo schema di collegamento...ed i due tipi di encoder.

nel frattempo ho voluto testare la funzione "pausa" per vedere la risposta della scheda relè scollegando il carico assegnato e quindi ad encoder fermo, infatti il problema non si presenta se l'encoder non gira .
Morale della favola ... a quanto pare gestire l'encoder con gli interrupt non va daccordo col resto di tutto il funzionamento, ho letto che è possibile gestire l'encoder con il metodo polling, ma non avendo mai usato questo sistema non so se effettivamente puo' risolvere la cosa , che ne pensate ?

ciao...per cortesia modifica il tuo ultimo post mettendo il codice all'interno dei tag "< code >" e non nel testo...poi sarebbe meglio se lo formattassi...giusto per rendere più leggibile il tutto.

#include <Nextion.h>
#include <Encoder.h>
#include <EasyNextionLibrary.h>
EasyNex myNex(Serial);
NexDSButton b_ss = NexDSButton (0, 32, "bt0");
NexButton b_ret = NexButton (0, 13, "b1");
NexButton b_loa = NexButton (0, 19, "b2");
NexNumber thread_n = NexNumber (0,30,"va0");
NexNumber depth_n = NexNumber (0,32,"va1");
//NexNumber ret_st = NexNumber (0,34,"n3");
NexProgressBar bar = NexProgressBar (0,21,"j0");
NexTouch *nex_listen_list[] ={
  &b_ss, &b_ret, &b_loa, &thread_n, &depth_n,  NULL
};

Encoder enc(2,3);
int rele_a = 4;  // pin rele A
int rele_b = 5; //pin rele B
volatile float pos=0; // posizione corrente encoder 
volatile float old_pos=0; // vecchia posizione encoder 
int pos_2=0;// 
uint32_t thread=0; // passo selezionato in mm 
uint32_t depth=0; // valore profondità da raggiungere in mm  
uint32_t b_ss_st=0;//stato pulsante start stop
uint32_t b_ret_st=0;//stato bottone ritorno
float Step=0;  // numero rotazioni
bool milling=false; //filetttura
bool pause=false;  //intervallo
bool escape=false; //fine ciclo
bool zero_enc=false; //azzeramento encoder
int ret_st=0; //stato di RETURN
int max_step=600; //NUMERO PASSI TOTALI ENCODER
int step_2=0; //conversione mm profondità in step ( step da raggiungere)
float depth_2=0; // profondità
float thread_2=0; //conversione passo in step
int comp_cic = 0; //cicli completati
int bar_value = 0; // variabile per progress bar 


void setup() {
Serial.begin(9600);
pinMode (rele_a,OUTPUT);
pinMode (rele_b,OUTPUT);
digitalWrite (rele_a,LOW);
digitalWrite (rele_b,LOW);
myNex.begin(9600);
b_ss_st=0;
b_ret_st=0;
b_ss.attachPop(start_stop,&b_ss);
b_loa.attachPop(loading,&b_loa);
b_ret.attachPush(INDIETRO_ON,&b_ret);
b_ret.attachPop(INDIETRO_OFF,&b_ret);
nexInit();
delay (1000);
}

void loop() {
  ENCODER ();
  myNex.NextionListen();
  nexLoop(nex_listen_list);
  if (b_ss_st==1) {
    RUN(); 
  }else{
    PAUSE();
  }
}
  

void ENCODER (){
     pos = (enc.read()/4);
     pos_2 = (thread_2/60000)*pos;
     if (pos != old_pos) {
      PROG_BAR ();
     old_pos = pos;
     myNex.writeNum ("page0.n1.val",pos);
     myNex.writeNum ("page0.n1.val",pos);
     if (thread!=0) {
     myNex.writeNum ("page0.x5.val",pos_2);
     }
    }
   }
void loading (void *ptr){
  Soft_reset ();
  thread_n.getValue (&thread);
  depth_n.getValue (&depth);
  thread_2=thread*100;
  depth_2=depth*100;
  Step=(depth_2/thread_2);
  step_2=Step*max_step;
  myNex.writeNum ("page0.x4.val",thread);
  myNex.writeNum ("page0.x4.val",thread);
  myNex.writeNum ("page0.x1.val",depth);
  myNex.writeNum ("page0.x1.val",depth);
  myNex.writeNum ("page0.n2.val",step_2);
  myNex.writeNum ("page0.n2.val",step_2);
  delay (100);
}

void start_stop (void *ptr){
b_ss.getValue (&b_ss_st);
}

void Soft_reset () {
   enc.write (0);
   pos = 0;
   pos_2 = 0;
   b_ss_st = 0;
   milling = false;
   pause = false;
   escape = false;
   zero_enc = false;
   myNex.writeNum ("page0.bt0.val",0); 
}

void PAUSE (){
  digitalWrite (rele_a,LOW);
}


void PROG_BAR (){
  if (b_ss_st==1){
    bar_value = map (pos,0,step_2,0,100);
    bar.setValue (bar_value);
  }
}


void INDIETRO_ON (void *ptr) {  
  digitalWrite (rele_b,HIGH);
}

void INDIETRO_OFF (void *ptr) {
  digitalWrite (rele_b,LOW);
}


void RUN (){
    
if  (zero_enc==false){
     enc.write (0);
     zero_enc=true;  
}
if ((milling==false)&&(pause==false)&&(pos<=step_2)&&(escape==false)){
    digitalWrite (rele_a,HIGH);
    digitalWrite (rele_b,LOW);   
     }
    if ((milling==false)&&(pause==false)&&(pos>=step_2)&&(escape==false)){
    digitalWrite (rele_a,LOW);  
    digitalWrite (rele_b,LOW);
    milling = true;
    pause = true;
    delay (2000);
  }
if ((milling==true)&&(escape==false)&&(pause==true)&&(pos>-max_step)) {
    digitalWrite (rele_a,LOW);
    digitalWrite (rele_b,HIGH);
    }
    if ((milling==true)&&(escape==false)&&(pause==true)&&(pos<=-max_step)) {
    digitalWrite (rele_a,LOW);  
    digitalWrite (rele_b,LOW);
    escape = true;
    comp_cic = comp_cic+1;
    myNex.writeNum ("page0.n0.val",comp_cic);
    myNex.writeNum ("page0.n0.val",comp_cic);
    myNex.writeNum ("page0.t3.aph",127);
    myNex.writeNum ("page0.t3.aph",127);
    myNex.writeNum ("page0.t3.aph",0);
    myNex.writeNum ("page0.t3.aph",0);
    Soft_reset ();
    delay (1500);
    }
   }

La ISR deve essere veloce! Non puoi pretendere di scrivere sul display dalla ISR!
Il display aggiornalo ogni 500 o 1000ms usando millis().

Inoltre, la lettura dell'encoder usa l'interrupt ma viene chiamata continuamente nel loop?. .

Dai anche un'occhiata qui:

Ok ! Evidentemente stò sbagliando alcuni concetti di base, la funzione "Encoder" funzionerebbe anche senza richiamarla nel loop? Ho anche appreso oggi cosa si intende per ISR , puoi indicarmi meglio quale parte identifichi come ISR nel mio codice ?

Tu hai parlato di interrupt e, in effetti, la libreria li usa, ma dal telefonino non avevo capito bene...
Io parlavo della continua chiamata di ENCODER(), che a ogni giro di loop scrive sul display.
Il display devi aggiornarlo periodicamente:

uint32_t t_display;
if(millis()-t_display>=1000) // o 500ms.
  {
  t_display+=1000; // o 500ms.
  myNex.writeNum ("page0.n1.val",pos);
  myNex.writeNum ("page0.n1.val",pos);
  if (thread!=0) 
    {
    myNex.writeNum ("page0.x5.val",pos_2);
    }
  }

Il display che uso ha un suo micro interno e si aggiorna da solo senza uno specifico comando, ad ogni modo parlando anche con un altro esperto sembra proprio che il problema risieda nella frequenza degli interrupt generata dall'encoder in movimento, tornando alla funzione ENCODER , essa scrive sul display la posizione dell'encoder in tempo reale , quindi non posso aggiornare il display con un periodo di latenza

Saranno un mix di cose che impediscono di funzionare come funziona a banco.
Il motore gira rapidamente ed ogni giro l'encode emette dei segnali, quanti? dipende da encoder e da quanto gira veloce il motore. Nota che la Serial hardware che software usa gli interrup e quando si entra in una ISR tutti gli altri interrupt risultano disabilitati. Provabile che ti perda alcuni impulsi dell'encode.
In pooling le cose possono solo andare peggio, il problema e la velocità di rotazione del motore che si traduce in 10000 impulsi al secondi.

Ciao.

Ciao.

Buongiorno e buona domenica ! ... Anche io pensavo alla stessa cosa, ma ieri sera ho provato di nuovo tutto a banco inserendo diverse modifiche allo sketch e facendo girare l'encoder a mano ( quindi ben lontano dalla velocità del motore ) e la problematica non cambia ...
Spulciando la libreria encoder ho trovato un comando ( ENCODER_OPTIMIZE_INTERRUPTS) da inserire ad inizio pagina per snellire il lavoro sul Pic ma non cambia nulla, ho addirittura cercato aiuto interpellando ChatGPT3 che effettivamente ha individuato il problema e proposto diversi miglioramenti alla sketch ma il problema è sempre lí! Comincio a pensare che forse l'unica soluzione sia passare ad una scheda piú veloce .

La soluzione, come ho già detto, è non scrivere inutilmente sulla seriale a ogni giro di loop.
Inoltre, non può andare a più di 9600?

Se non mando un segnale di posizione ad ogni singolo passo dell'encoder come faccio a vedere su schermo la posizione in tempo reale ? ...per quanto riguarda il baud rate i classici 9600 non dovrebbero essere il massimo per una Arduino Uno ??
In ogni caso proverò a rallentare il feedback su seriale e vediamo che succede :slight_smile:

ho ricontrollato tutto il codice ma non vedo nessun segnale inviato in loop sulla seriale, il segnale viene inviato ad ogni cambio di posizione dell'encoder, come infatti dovrebbe essere ....

Sei cosciente che non è che si aggiorna da solo? Cioè si aggiorna perché la libreria usa la seriale hardware come da codice:

Ad ogni modo io non vedo come possa cambiare il valore di:

volatile float pos=0; // posizione corrente encoder

Forse se indentassi il codice lo leggerei meglio ma mi sfugge qualcosa.

Girando l'encoder manualmente cosa accade che non dovrebbe accadere, cioè riesponi il problema con l'encoder girato manualmente.

Ciao.

Comunque, se pos cambia 1000 volte al secondo vengono mandati 2000 o 3000 myNex.writeNum in un secondo. Quanto tempo impiega un myNex.writeNum per essere eseguito? Quanto è veloce l'occhio umano? Con che velocità l'occhio riesce a vedere e il cervello a interpretare due valori diversi?

Perdonate la mia ignoranza merito ma scrivo raramente sul forum e non capisco cosa si intende per intestazione del codice.
Per piacere fatemi un esempio e riposto il codice intestato.

Intestazione???... InDeNtazione!
https://www.google.com/search?q=indentazione+del+codice

:stuck_out_tongue::stuck_out_tongue: questa mi mancava , vado a studiare e riposto il codice "indentato"...

Ottimo, ma in ardujino IDE c'è l'auto indentazione con la combinazione di tasti CTRL+T.

Dove incrementi il valore di pos?

Ciao.