BaroneRosso.it - Forum Modellismo

BaroneRosso.it - Forum Modellismo (https://www.baronerosso.it/forum/)
-   Circuiti Elettronici (https://www.baronerosso.it/forum/circuiti-elettronici/)
-   -   Arduino e sensori accelerometri (https://www.baronerosso.it/forum/circuiti-elettronici/377835-arduino-e-sensori-accelerometri.html)

Minestrone 30 ottobre 18 12:24

Arduino e sensori accelerometri
 
Premesso che sono molto, ma molto, nubbio in elettronica, vorrei realizzare un circuito con degli accelerometri. Ho trovato in rete un progettino liberamente scaricabile e molto simile al mio che utilizza due Adafruit MMA8451 facendo largo uso di librerie preconfezionate. Gli MMA8451 però li ho trovati abbastanza costosi.
Siccome ho trovato sensori GY 520 con MPU-6050 molto più economici, vorrei chiedervi che differenze ci sono tra gli uni e gli altri e se l'utilizzo, dal punto di vista del codice, cambia molto oppure no.

Grazie tante a tutti.

gawain 30 ottobre 18 12:52

Citazione:

Originalmente inviato da Minestrone (Messaggio 5120808)
Premesso che sono molto, ma molto, nubbio in elettronica, vorrei realizzare un circuito con degli accelerometri. Ho trovato in rete un progettino liberamente scaricabile e molto simile al mio che utilizza due Adafruit MMA8451 facendo largo uso di librerie preconfezionate. Gli MMA8451 però li ho trovati abbastanza costosi.
Siccome ho trovato sensori GY 520 con MPU-6050 molto più economici, vorrei chiedervi che differenze ci sono tra gli uni e gli altri e se l'utilizzo, dal punto di vista del codice, cambia molto oppure no.

Grazie tante a tutti.

devi usare le librerie per mpu6050

Minestrone 30 ottobre 18 14:53

Citazione:

Originalmente inviato da gawain (Messaggio 5120817)
devi usare le librerie per mpu6050

Trovate, grazie. Però immagino che dovrò creare una funzione di filtro per filtrare i valori in ingresso vero?

ps.
sono queste?
https://github.com/jarzebski/Arduino-MPU6050

gawain 30 ottobre 18 17:03

Citazione:

Originalmente inviato da Minestrone (Messaggio 5120845)
Trovate, grazie. Però immagino che dovrò creare una funzione di filtro per filtrare i valori in ingresso vero?

ps.
sono queste?
https://github.com/jarzebski/Arduino-MPU6050

ce ne sono tante, probabilmente vanno bene anche queste. per i filtri ci sono gia dentro mpu6050 da parametrizzare credo che la banda passante piu bassa sia 5hz.
comunque se devi fare un inclinometro di alta performance ti conviene fare la sensor fusion tra accelerometri e gyro. oppure piu semplice puoi sfruttare il sw interno di mpu6050 che fa gia la sensor fusion... certo ti togli il gusto di capirci qualcosa...

importante procurarsi la mappa dei registri... la trovi facilmente su internet digitando su google register map mu6050 pdf

Minestrone 30 ottobre 18 17:19

Citazione:

Originalmente inviato da gawain (Messaggio 5120870)
ce ne sono tante, probabilmente vanno bene anche queste. per i filtri ci sono gia dentro mpu6050 da parametrizzare credo che la banda passante piu bassa sia 5hz.
comunque se devi fare un inclinometro di alta performance ti conviene fare la sensor fusion tra accelerometri e gyro. oppure piu semplice puoi sfruttare il sw interno di mpu6050 che fa gia la sensor fusion... certo ti togli il gusto di capirci qualcosa...

importante procurarsi la mappa dei registri... la trovi facilmente su internet digitando su google register map mu6050 pdf

Ecco lo sapevo. Sono passato da un progetto quasi pronto da modificare nelle sue parti più banali ad un progetto da rifare quasi in toto. Vabbè, così sia.
A questo punto metterò in pausa perché questo mese non ho molto tempo ma tra un paio di settimane lo farò....
Intanto comincio a studiare perché non ne so nulla.
Se avessi qualche link da cui partire te ne sarei grato. Intanto grazie delle info.

Inviato dal mio Mi A1 utilizzando Tapatalk

gawain 03 novembre 18 07:51

Citazione:

Originalmente inviato da Minestrone (Messaggio 5120873)
Ecco lo sapevo. Sono passato da un progetto quasi pronto da modificare nelle sue parti più banali ad un progetto da rifare quasi in toto. Vabbè, così sia.
A questo punto metterò in pausa perché questo mese non ho molto tempo ma tra un paio di settimane lo farò....
Intanto comincio a studiare perché non ne so nulla.
Se avessi qualche link da cui partire te ne sarei grato. Intanto grazie delle info.

Inviato dal mio Mi A1 utilizzando Tapatalk

https://github.com/musse/tricot-malin/wiki/IMU
da questo link raggiungi una grande quantità di altri link... c'è di tutto e di più ..

Minestrone 03 novembre 18 07:58

Grazie molte

Inviato dal mio Mi A1 utilizzando Tapatalk

Minestrone 13 novembre 18 10:08

una piccola imbeccata
 
Ormai è quasi una settimana che smanetto con i sensori e l'arduino. Ho letto molto in merito ed ho trovato una infinità di librerie. Purtroppo sono al punto in cui mi sono sturato di informazioni e ho confusione.

La lettura dei dati raw e la loro elaborazione non è un problema (ci sono riuscito senza librerie) però mi sembra che i valori siano molto sporchi e molto variabili. Quello che voglio realizzare è un incidenziometro e, calcolando l'angolo rispetto alla verticale sfruttando solo gli accelerometri, trovo che il dato mi varia di parecchi decimi di grado.
So che i dati provenienti dagli accelerometri sono rumorosi di natura e pertanto ho capito che devo filtrare i dati e combinarli con l'angolo ottenuto integrando i valori dei giroscopi. Qui mi sto trovando in difficoltà.

Qualcuno sa darmi un'imbeccata su come applicare un filtro Kalman o, ancora meglio, complementare e come combinare i dati dei giroscopi con quelli degli accelerometri per ottenere dei dati che mi permettano di arrivare a capire l'angolo rispetto alla verticale?

Ho capito che questi calcoli li potrebbe fare il DMP integrato nella scheda ma non ho trovato alcuna informazione su come usarlo.

gawain 14 novembre 18 14:41

Citazione:

Originalmente inviato da Minestrone (Messaggio 5122519)
Ormai è quasi una settimana che smanetto con i sensori e l'arduino. Ho letto molto in merito ed ho trovato una infinità di librerie. Purtroppo sono al punto in cui mi sono sturato di informazioni e ho confusione.

La lettura dei dati raw e la loro elaborazione non è un problema (ci sono riuscito senza librerie) però mi sembra che i valori siano molto sporchi e molto variabili. Quello che voglio realizzare è un incidenziometro e, calcolando l'angolo rispetto alla verticale sfruttando solo gli accelerometri, trovo che il dato mi varia di parecchi decimi di grado.
So che i dati provenienti dagli accelerometri sono rumorosi di natura e pertanto ho capito che devo filtrare i dati e combinarli con l'angolo ottenuto integrando i valori dei giroscopi. Qui mi sto trovando in difficoltà.

Qualcuno sa darmi un'imbeccata su come applicare un filtro Kalman o, ancora meglio, complementare e come combinare i dati dei giroscopi con quelli degli accelerometri per ottenere dei dati che mi permettano di arrivare a capire l'angolo rispetto alla verticale?

Ho capito che questi calcoli li potrebbe fare il DMP integrato nella scheda ma non ho trovato alcuna informazione su come usarlo.



qui trovi comi utilizzare dmp
https://maker.pro/arduino/tutorial/h...pu-6050-sensor

ElNonino 15 novembre 18 14:18

Non conosco direttamente la MPU in oggetto però per lavoro ho utilizzato accelerometri per leggere un'inclinazione sul piano, alcuni analogici altri con uscita digitale e DSP interni.

Per misurare un'inclinazione in regime statico come è la lettura dell'incidenza di ali, piani di coda o pale di elicottero basta un accelerometro, il giroscopio è inutile, il problema degli accelerometri analogici è che l'uscita non era lineare rispetto all'angolo d'inclinazione ma bensì ha un andamento sinusoidale che va compensato tramite algoritmi di fusione dei dati di almeno due assi e poi ulteriormente linearizzato con una tabella appositamente creata.

Uso un solo accelerometro analogico da oltre 10 anni per leggere l'inclinazione verticale dei pannelli FV installati in baita sul mio sistema di inseguimento solare senza alcun problema, utilizzo solo gli assi X ed Y in quanto l'asse Z è sempre parallelo al suolo e la velocità di rotazione è estremamente bassa quindi non ho necessità di effettuare ulteriori compensazioni.

Indipendentemente dal tipo di sensore usato è comunque necessario filtrare molto bene il segnale, sia attraverso reti RC passa basso + algoritmi digitali nel caso di analogico che filtri digitali + DSP in quelli puramente digitali, mi ricordo di aver disquisito di ciò sul Barone in un'altra discussione (forse in elicotteri o multirotori)

Comunque una soluzione semplicissima (ma non di soddisfazione) per realizzare un incidenziometro è quella di acquistare un inclinometro digitale e fissarlo su opportuni supporti, cosa che ho fatto io per le pale dei miei elicootteri RC.

Se servono info a disposizione.

:yeah:

Minestrone 15 novembre 18 16:37

Grazie a tutti delle preziose informazioni. Sto sbattendo la testa per la prima volta con questi sensori e sto cercando a fatica di capire. Oramai ho capito come lavorare sul registro dell'integrato e mi sento già un passo avanti. Purtroppo non riesco più a stare alzato fino a tardi come qualche anno fa e la mia attività modellistica ne sta risentendo.

Ora sto rifinendo il mio sketch che, al momento, fa uso di due soli assi dell'accelerometro. Devo inserire la calibrazione e registrare il valore nel registro dell'integrato. Per adesso non sto usando né DMP né librerie.

Per quanto riguarda il giroscopio, da quello che ho capito e da quello che sto osservando nelle mie prove, il problema è che l'accelerometro è molto rumoroso e il filtro complementare (o altri) mixano i valori del gyro e dell'accelerometro per ottenere un dato pulito. Devo ancora implementare la lettura e la determinazione dell'angolo con il gyro, fatto quello potrò scoprire se il filtro funziona.

Per adesso ho detto valori molto sporchi e variabili. Ho provato ad applicare un filtro passa basso con la libreria filter senza ottenerne nulla, probabilmente la frequenza di campionamento dell'integrato è troppo bassa. Sto facendo la media delle letture con calcolo della media ogni mezzo secondo ma i risultati sono ancora sporchissimi.

Inviato dal mio Mi A1 utilizzando Tapatalk

gawain 15 novembre 18 16:53

Citazione:

Originalmente inviato da ElNonino (Messaggio 5122840)
Non conosco direttamente la MPU in oggetto però per lavoro ho utilizzato accelerometri per leggere un'inclinazione sul piano, alcuni analogici altri con uscita digitale e DSP interni.

Per misurare un'inclinazione in regime statico come è la lettura dell'incidenza di ali, piani di coda o pale di elicottero basta un accelerometro, il giroscopio è inutile, il problema degli accelerometri analogici è che l'uscita non era lineare rispetto all'angolo d'inclinazione ma bensì ha un andamento sinusoidale che va compensato tramite algoritmi di fusione dei dati di almeno due assi e poi ulteriormente linearizzato con una tabella appositamente creata.

Uso un solo accelerometro analogico da oltre 10 anni per leggere l'inclinazione verticale dei pannelli FV installati in baita sul mio sistema di inseguimento solare senza alcun problema, utilizzo solo gli assi X ed Y in quanto l'asse Z è sempre parallelo al suolo e la velocità di rotazione è estremamente bassa quindi non ho necessità di effettuare ulteriori compensazioni.

Indipendentemente dal tipo di sensore usato è comunque necessario filtrare molto bene il segnale, sia attraverso reti RC passa basso + algoritmi digitali nel caso di analogico che filtri digitali + DSP in quelli puramente digitali, mi ricordo di aver disquisito di ciò sul Barone in un'altra discussione (forse in elicotteri o multirotori)

Comunque una soluzione semplicissima (ma non di soddisfazione) per realizzare un incidenziometro è quella di acquistare un inclinometro digitale e fissarlo su opportuni supporti, cosa che ho fatto io per le pale dei miei elicootteri RC.

Se servono info a disposizione.

:yeah:


la sensor fusion con il gyro serve per migliorare la risposta in frequenza... se la misura è lenta allora la soluzione diventa banale e basta filtrare potentemente con filtro IIR le componeti del vettore accelerazione

ElNonino 15 novembre 18 22:55

Citazione:

Originalmente inviato da gawain (Messaggio 5122850)
la sensor fusion con il gyro serve per migliorare la risposta in frequenza... se la misura è lenta allora la soluzione diventa banale e basta filtrare potentemente con filtro IIR le componeti del vettore accelerazione

Esatto, il gyro visto che la misura è statica non serve, non credo che misuri l'incidenza con il modello in volo :D, per filtrare decentemente potresti iniziare ad usare una media mobile a 16 o 32 campioni, darò un occhiata al datasheet della MPU.

:yeah:

Minestrone 16 novembre 18 01:01

Citazione:

Originalmente inviato da ElNonino (Messaggio 5122884)
Esatto, il gyro visto che la misura è statica non serve, non credo che misuri l'incidenza con il modello in volo :D, per filtrare decentemente potresti iniziare ad usare una media mobile a 16 o 32 campioni, darò un occhiata al datasheet della MPU.

:yeah:

Si ma infatti pensavo di implementare il filtro solo per pulire il segnale.
Comunque stasera ho fatto diverse prove. Il filtro passabasso non mi ha portato a nessun miglioramento significativo, ho provato diverse frequenze ma il risultato non cambiava molto; forse ho sbagliato qualcosa.
Facendo la media aritmetica dei campionamenti raccolti in un mezzo secondo il risultato si stabilizza molto anche se ci sono ancora oscillazioni alla seconda cifra decimale (se riuscissi ad avere una buona pulizia alla prima cifra decimale sarei parecchio contento).
Avevo scelto di fare una media del genere perchè ho pensato di fare il refresh del display ogni mezzo secondo.
Facendo una media in virgola mobile naturalmente il risultato migliora perchè perde gli scalini e gli sbalzi di una media aggiornata ogni 500millisecondi, però per poter ottenere un risultato decente ho usato degli array con 64 valori.
Dovendo calcolare la media mobile su 3 array con 64 valori credo proprio che non potrò usare un algoritmo grezzo, altrimenti occupo il processore con il solo calcolo della media.

Minestrone 16 novembre 18 07:31

Citazione:

Originalmente inviato da Minestrone (Messaggio 5122899)
Si ma infatti pensavo di implementare il filtro solo per pulire il segnale.
Comunque stasera ho fatto diverse prove. Il filtro passabasso non mi ha portato a nessun miglioramento significativo, ho provato diverse frequenze ma il risultato non cambiava molto; forse ho sbagliato qualcosa.
Facendo la media aritmetica dei campionamenti raccolti in un mezzo secondo il risultato si stabilizza molto anche se ci sono ancora oscillazioni alla seconda cifra decimale (se riuscissi ad avere una buona pulizia alla prima cifra decimale sarei parecchio contento).
Avevo scelto di fare una media del genere perchè ho pensato di fare il refresh del display ogni mezzo secondo.
Facendo una media in virgola mobile naturalmente il risultato migliora perchè perde gli scalini e gli sbalzi di una media aggiornata ogni 500millisecondi, però per poter ottenere un risultato decente ho usato degli array con 64 valori.
Dovendo calcolare la media mobile su 3 array con 64 valori credo proprio che non potrò usare un algoritmo grezzo, altrimenti occupo il processore con il solo calcolo della media.

In realtà però posso calcolare la media solo sul risultato finale, non sui dati iniziali. Meno calcoli.
Bah... Alla notte dovrei dormire, non calcolare le medie..

Inviato dal mio Mi A1 utilizzando Tapatalk

ElNonino 16 novembre 18 12:42

Ho dato un'occhiata al datasheet della MCU e mi pare che non abbia un filtro passa basso sull'accelerometro ma solo sul giroscopio, quindi necessita sicuramente filtrare il segnale nel microprocessore anche perchè questa MCU è indicata per giocattoli od applicazioni in cui non è richiesta molta precisione.

Quando fai le prove controlla che la MCU non abbia vibrazioni, sia ben fissata ed usa i canali X ed Y non lo Z; poi controlla con un break point quali sono i valori nei due array per vedere se ci sono picchi od anomalie.

La media mobile comporta solo pochissimi calcoli, in pratica una sottrazione, una somma ed un right shift quindi può essere chiamata spesso senza appesantire la CPU, un buon filtraggio lo puoi anche ottenere usando due medie mobili in cascata, comunque scordati di ottenere l'accuratezza di 1/100 di grado e sopratutto che con quella MCU sia affidabile nel tempo.

Verifica anche che non ci siano perdite di dati nella comunicazione I2C o SPI.

:yeah:

Minestrone 16 novembre 18 13:35

Citazione:

Originalmente inviato da ElNonino (Messaggio 5122936)
Ho dato un'occhiata al datasheet della MCU e mi pare che non abbia un filtro passa basso sull'accelerometro ma solo sul giroscopio, quindi necessita sicuramente filtrare il segnale nel microprocessore anche perchè questa MCU è indicata per giocattoli od applicazioni in cui non è richiesta molta precisione.

Quando fai le prove controlla che la MCU non abbia vibrazioni, sia ben fissata ed usa i canali X ed Y non lo Z; poi controlla con un break point quali sono i valori nei due array per vedere se ci sono picchi od anomalie.

La media mobile comporta solo pochissimi calcoli, in pratica una sottrazione, una somma ed un right shift quindi può essere chiamata spesso senza appesantire la CPU, un buon filtraggio lo puoi anche ottenere usando due medie mobili in cascata, comunque scordati di ottenere l'accuratezza di 1/100 di grado e sopratutto che con quella MCU sia affidabile nel tempo.

Verifica anche che non ci siano perdite di dati nella comunicazione I2C o SPI.

:yeah:

Mah , proverò a fare delle altre prove avvitando il sensore al tavolo ed alzando la frequenza di campionamento dell'integrato (mi sembra di ricordare che ci sia un valore di registro per impostare la frequenza).
Nelle prove che ho fatto non c'era NESSUNA differenza tra i valori filtrati e quelli non filtrati. Che frequenza di filtro mi consigli?

Per la precisione credo che un decimo di grado sia più che sufficiente, per l'affidabilità metterò un algoritmo di calibrazione da richiamare ogni tanto. Se poi funziona bene posso anche pensare di trasformare il tutto per un sensore più preciso.
Stasera devo mettere mano al minikosmo, che è più importante, domani vedo di andare avanti.

Intanto grazie dell'interessamento.

Inviato dal mio Mi A1 utilizzando Tapatalk

Minestrone 29 novembre 18 11:17

Sto andando avanti con il mio progettino ma ho un problemino con la gestione della media in virgola mobile. In pratica il risultato della media impiega parecchi secondi a stabilizzarsi ad ogni movimento del sensore. Non capisco perchè, sarà sicuramente una stupidata ma io non la vedo.
Se posso approfitto della vostra competenza e vi allego il codice del loop per cercare di capire cosa non va.
Considerate che la maggior parte del codice risiede nel void setup, compresa la parte della calibrazione che comprende la maggioranza delle righe di codice, ma non credo che quella interessi.
Vi posto il codice

note: tempodiciclo è impostato a 500millisecondi ( const int tempodiciclo=500; )
k è la dimensione dell'array per il calcolo della virgola mobile e vale 64 ( const int k=64; )


void loop(){
letturaMPU_0(); //funzione che riceve dati dal sensore MPU_0 e li memorizza nelle variabili
// MPU_0_AcX, MPU_0_AcY e MPU_0_GyZ (i primi due sono accelerazioni,
//l'ultimo e un dato di gyroscopio.)

sommadegMPU_0-=degMPU_0[i];
degMPU_0[i] = ((atan2(MPU_0_AcY, MPU_0_AcX )) * 180.0) / PI; //calcolo tramite accelerometro
sommadegMPU_0+=degMPU_0[i];
i++;
if (i==k) {i=0;}
tempodiciclo = millis()-startMillis;
startMillis = millis(); //reset timer
ciclorefresh+=tempodiciclo;
deggyroMPU_0=deggyroMPU_0+(((MPU_0_GyZ/131)*tempodiciclo)/1000);//calcolo tramite gyro
if(ciclorefresh >= lcdRefreshRate){
mediadegMPU_0 = sommadegMPU_0 / k ;
ciclorefresh=0;

} //fine if

#ifdef debug {stampadebug(); #endif} //se il debug è acceso chiama la funzione per la stampa
seriale dei valori

}




Ovviamente il valore dell'angolo calcolato tramite accelerometro cambia ogni 500 millisecondi sullo schermo del pc perchè così è impostato, però ad ogni movimento il valore impiega 4 o 5 secondi a raggiungere il valore reale.

il tempo di ciclo lo stampo a video per vedere quanto vale ed è attorno agli 83 millisecondi. Ho scoperto che il tempo di ciclo varia in funzione di come modifico la funzione stampadebug() , evidentemente la stampa a video di valori e stringhe tramite Serial.print() richiede molto tempo. Stampando un pochino di valori per avere un'idea di come varino le variabili sono arrivato ad avere tempi di ciclo sui 250ms.

ElNonino 29 novembre 18 17:46

Citazione:

Originalmente inviato da Minestrone (Messaggio 5124514)
Sto andando avanti con il mio progettino ma ho un problemino con la gestione della media in virgola mobile. In pratica il risultato della media impiega parecchi secondi a stabilizzarsi ad ogni movimento del sensore. Non capisco perchè, sarà sicuramente una stupidata ma io non la vedo.
Se posso approfitto della vostra competenza e vi allego il codice del loop per cercare di capire cosa non va.
Considerate che la maggior parte del codice risiede nel void setup, compresa la parte della calibrazione che comprende la maggioranza delle righe di codice, ma non credo che quella interessi.
Vi posto il codice

note: tempodiciclo è impostato a 500millisecondi ( const int tempodiciclo=500; )
k è la dimensione dell'array per il calcolo della virgola mobile e vale 64 ( const int k=64; )


void loop(){
letturaMPU_0(); //funzione che riceve dati dal sensore MPU_0 e li memorizza nelle variabili
// MPU_0_AcX, MPU_0_AcY e MPU_0_GyZ (i primi due sono accelerazioni,
//l'ultimo e un dato di gyroscopio.)

sommadegMPU_0-=degMPU_0[i];
degMPU_0[i] = ((atan2(MPU_0_AcY, MPU_0_AcX )) * 180.0) / PI; //calcolo tramite accelerometro
sommadegMPU_0+=degMPU_0[i];
i++;
if (i==k) {i=0;}
tempodiciclo = millis()-startMillis;
startMillis = millis(); //reset timer
ciclorefresh+=tempodiciclo;
deggyroMPU_0=deggyroMPU_0+(((MPU_0_GyZ/131)*tempodiciclo)/1000);//calcolo tramite gyro
if(ciclorefresh >= lcdRefreshRate){
mediadegMPU_0 = sommadegMPU_0 / k ;
ciclorefresh=0;

} //fine if

#ifdef debug {stampadebug(); #endif} //se il debug è acceso chiama la funzione per la stampa
seriale dei valori

}




Ovviamente il valore dell'angolo calcolato tramite accelerometro cambia ogni 500 millisecondi sullo schermo del pc perchè così è impostato, però ad ogni movimento il valore impiega 4 o 5 secondi a raggiungere il valore reale.

il tempo di ciclo lo stampo a video per vedere quanto vale ed è attorno agli 83 millisecondi. Ho scoperto che il tempo di ciclo varia in funzione di come modifico la funzione stampadebug() , evidentemente la stampa a video di valori e stringhe tramite Serial.print() richiede molto tempo. Stampando un pochino di valori per avere un'idea di come varino le variabili sono arrivato ad avere tempi di ciclo sui 250ms.

Stasera ti metto un pezzo di codice di come realizzo io i campionamenti e la media mobile.

:yeah:

Minestrone 29 novembre 18 17:55

Citazione:

Originalmente inviato da ElNonino (Messaggio 5124556)
Stasera ti metto un pezzo di codice di come realizzo io i campionamenti e la media mobile.

:yeah:

Molto gentile. Grazie.

Inviato dal mio Mi A1 utilizzando Tapatalk

ElNonino 29 novembre 18 22:01

Prima del listato devo anticiparti che io da tempo uso un semplicissimo RTOS che a dire il vero è uno schedulatore a bassissima latenza, cioè ogni funzione viene eseguita ad intervalli regolari di x tempo, questo perchè in genere ho bisogno di precisione nel timing di misure od altro, anche eventuali routine di interrupt non creano problemi perchè vengono eseguite sempre in tempi ridottissimi.

Il codice è in ANSI C e molto portatile, purtroppo uso pochissimo Arduino quindi quello che segue è per ARM o PIC.

Codice:

// Loop RTOS 12,5ms task, 100ms loop
  while (1)
  {
          switch(u8Tic & 7)
          {
                  case 0:        //TASK 0
                                                  break;

                  case 1: //TASK 1
                                                  break;

                  case 2:        //TASK 2
                                                  break;

                  case 3:        //TASK 3
                                                  break;

                  case 4: //TASK 4
                                                  break;

                  case 5:        //TASK 5
                                                  break;

                  case 6: //TASK 6
                                                  break;

                  case 7: //TASK 7
                                                  break;
          }
          ++u8Tic;
          WaitMain();
        }

/*******************************************************************************|
| Function Name  : WaitMain                                                    |
| Description    : Routine di ritardo 12,5ms per RTOS.                          |
| Input          : None                                                        |
| Output        : None                                                        |
| Return        : None                                                        |
|*******************************************************************************/
void WaitMain(void)
{
  while(__HAL_TIM_GET_FLAG(&htim6,TIM_FLAG_UPDATE) == RESET);
  __HAL_TIM_CLEAR_FLAG(&htim6, TIM_FLAG_UPDATE);
}
/*-----------------------------------------------------------------------------*/

/******************************************************************************|
| Function Name  : Read_Voltage                                                      |
| Description    : Routine lettura tensioni alimentazione e temperatura PIC.  |
| Input          : None                                                        |
| Output        : None                                                        |
| Return        : None                                                        |
|******************************************************************************/     
void(Read_Voltage)(void)
{
  u8PunMMV = (++u8PunMMV & 15);
 
  u16App_ADC = ADCC_GetSingleConversion(channel_Temp);  // Temperatura PIC
  u32Acc_P_T = u32Acc_P_T - u16Tab_P_T[u8PunMMV] + u16App_ADC;
  u16Tab_P_T[u8PunMMV] = u16App_ADC;
  u16P_T = u32Acc_P_T >> 4;
  __delay_ms(10);
 
  u16App_ADC  = ADCC_GetSingleConversion(P_12V);          // Tensione 12V
  u32Acc_12V = u32Acc_12V - u16Tab_12V[u8PunMMV] + u16App_ADC;
  u16Tab_12V[u8PunMMV] = u16App_ADC;
  u16P_12V = u32Acc_12V >> 4;
  __delay_ms(10);
 
  u16App_ADC =  ADCC_GetSingleConversion(P_5V);          // Tensione 5V
  u32Acc_5V = u32Acc_5V - u16Tab_5V[u8PunMMV] + u16App_ADC;
  u16Tab_5V[u8PunMMV] = u16App_ADC;
  u16P_5V = u32Acc_5V >> 4;
  __delay_ms(10);
 
  u16App_ADC =  ADCC_GetSingleConversion(P_3V);          // Tensione 3V
  u32Acc_3V = u32Acc_3V - u16Tab_3V[u8PunMMV] + u16App_ADC;
  u16Tab_3V[u8PunMMV] = u16App_ADC;
  u16P_3V = u32Acc_3V >> 4;
}
/*-----------------------------------------------------------------------------*/

Se hai dubbi chiedi pure.

:yeah:

ElNonino 29 novembre 18 22:12

Dimenticavo, la media mobile che ho lincato include un ritardo di 10ms fra i vari canali perchè era per un applicazione assai lenta, togliendo i ritardi viene eseguita tutta in pochi ms (5ms per tutti i canali) con un PICF18..... con clock a 48MHz.

Con un STM32F030... sempre a 48MHZ una media mobile su 8 campionamenti di un Array a 16 biti di dimensioni 2x8 impiega 2ms.

:yeah:

Minestrone 30 novembre 18 14:47

Ciao ElNonino. Effettivamente ho diversi dubbi, ci sono delle parti del tuo codice che non so decifrare. Però mi sembra di capire che la porzione del codice che mi interessa, ovvero quella della virgola mobile, sia questa (per un canale):

u8PunMMV = (++u8PunMMV & 15);

u16App_ADC = ADCC_GetSingleConversion(channel_Temp); // Temperatura PIC
u32Acc_P_T = u32Acc_P_T - u16Tab_P_T[u8PunMMV] + u16App_ADC;
u16Tab_P_T[u8PunMMV] = u16App_ADC;
u16P_T = u32Acc_P_T >> 4;

Mi sembra uguale alla mia:

sommadegMPU_0-=degMPU_0[i];
degMPU_0[i] = ((atan2(MPU_0_AcY, MPU_0_AcX )) * 180.0) / PI;
sommadegMPU_0+=degMPU_0[i];
i++;
if (i==k) {i=0;}

poi, ogni 500 millisecondi eseguo:

mediadegMPU_0 = sommadegMPU_0 / k

dove k è la dimensione del vettore contenente l'angolo ricavato

in pratica la variabile sommadegMPU_0 contiene la somma di tutti i valori delle letture che concorrono al calcolo della virgola mobile, tali valori sono contenuti nell'array degMPU_0[] e i è l'incremento che mi dice quale elemento del vettore degMPU_0[] devo sostituire. mediadegMPU_0 è la media.

ElNonino 30 novembre 18 22:44

Citazione:

Originalmente inviato da Minestrone (Messaggio 5124665)
Ciao ElNonino. Effettivamente ho diversi dubbi, ci sono delle parti del tuo codice che non so decifrare. Però mi sembra di capire che la porzione del codice che mi interessa, ovvero quella della virgola mobile, sia questa (per un canale):

u8PunMMV = (++u8PunMMV & 15);

u16App_ADC = ADCC_GetSingleConversion(channel_Temp); // Temperatura PIC
u32Acc_P_T = u32Acc_P_T - u16Tab_P_T[u8PunMMV] + u16App_ADC;
u16Tab_P_T[u8PunMMV] = u16App_ADC;
u16P_T = u32Acc_P_T >> 4;

Mi sembra uguale alla mia:

sommadegMPU_0-=degMPU_0[i];
degMPU_0[i] = ((atan2(MPU_0_AcY, MPU_0_AcX )) * 180.0) / PI;
sommadegMPU_0+=degMPU_0[i];
i++;
if (i==k) {i=0;}

poi, ogni 500 millisecondi eseguo:

mediadegMPU_0 = sommadegMPU_0 / k

dove k è la dimensione del vettore contenente l'angolo ricavato

in pratica la variabile sommadegMPU_0 contiene la somma di tutti i valori delle letture che concorrono al calcolo della virgola mobile, tali valori sono contenuti nell'array degMPU_0[] e i è l'incremento che mi dice quale elemento del vettore degMPU_0[] devo sostituire. mediadegMPU_0 è la media.

ci sono alcune differenze fra i due sistemi, la principale è che io uso una variabile u32Acc_P_T che è un accumulatore, cioè contiene ad ogni loop la somma attuale degli n valori compionati ed inseriti nell' array, e quando viene divisa per 16 in u16P_T mi trovo aggiornata ad ogni loop la media reale.

Poi ti spiego alcuni trucchi:

- usare una variabile di appoggio (u16App_ADC) dove memorizzare la lettura del sensore aiuta molto nel debug e velocizza il loop,

- usare "u8PunMMV = (++u8PunMMV & 15)" anzichè "i++; if (i==k) {i=0;}" è più veloce, un & richiede in genere un solo ciclo di clock un if ne usa di più. quando un contatore incrementale ad 8 bit super 255 ritorna a 0 quindi con un & adatto ottieni automaticamente i valori da 0 a n. Chiaramente funziona se la dimensione dell'array è potenza di 2, cosa peraltro assai consigliabile.

- il motivo per cui la tua routine è lenta e sicuramente occupa anche tanta memoria è che usi tutto in floating point e se il micro non ha una FPU ci mette un secolo a fare quei calcoli, inoltre per la velocità sarebbe meglio usare un #def 180 180.0 perchè il compilatore ne è felice...

Se tu lavorassi con interi poi potresti usare un >> per la divisione (sempre se con esponenti di 2) che è enormemente più veloce di un / fra floating.

In ultimo se usi una printf per stampare (o mettere in una stringa) un valore floating un micro ad 8 bit ci passa la notte....

Vedo di riesumare la mia routine per leggere l'elevazione dei pannelli FV completa di tabella di linearizzazione e poi la pubblico, girava su un PIC16F877 .

Nei sistemi embedded è una regola d'oro usare sempre interi e convertirli in floating una sola volta, se possibile.

:yeah:

Minestrone 01 dicembre 18 00:42

Citazione:

Originalmente inviato da ElNonino (Messaggio 5124707)
ci sono alcune differenze fra i due sistemi, la principale è che io uso una variabile u32Acc_P_T che è un accumulatore, cioè contiene ad ogni loop la somma attuale degli n valori compionati ed inseriti nell' array, e quando viene divisa per 16 in u16P_T mi trovo aggiornata ad ogni loop la media reale.

Esattamente come faccio io, se sto capendo bene (e non ne sono sicuro). La mia variabile sommadegMPU_0 è l'accumulatore.

Poi ti spiego alcuni trucchi:

- usare una variabile di appoggio (u16App_ADC) dove memorizzare la lettura del sensore aiuta molto nel debug e velocizza il loop,
Ok, questa l'ho capita

- usare "u8PunMMV = (++u8PunMMV & 15)" anzichè "i++; if (i==k) {i=0;}" è più veloce, un & richiede in genere un solo ciclo di clock un if ne usa di più. quando un contatore incrementale ad 8 bit super 255 ritorna a 0 quindi con un & adatto ottieni automaticamente i valori da 0 a n. Chiaramente funziona se la dimensione dell'array è potenza di 2, cosa peraltro assai consigliabile.
Questa invece non l'ho capita, sto cercando di documentarmi ma non ho ancora ben capito cosa cercare.

- il motivo per cui la tua routine è lenta e sicuramente occupa anche tanta memoria è che usi tutto in floating point e se il micro non ha una FPU ci mette un secolo a fare quei calcoli, inoltre per la velocità sarebbe meglio usare un #def 180 180.0 perchè il compilatore ne è felice...
Sul discorso della lentezza dei calcoli convariabili reali ci sono. Sul #def 180 180.0 no

Se tu lavorassi con interi poi potresti usare un >> per la divisione (sempre se con esponenti di 2) che è enormemente più veloce di un / fra floating.
Queste sono operazioni con i bit. Ho sempre evitato di approfondire per semplificarmi la vita

In ultimo se usi una printf per stampare (o mettere in una stringa) un valore floating un micro ad 8 bit ci passa la notte....
Ok, anche qui ci sono. Però la cosa non mi preoccupa perchè una volta messo a punto il codice tutto il debug, ovvero tutte le printf verranno eliminate, infatti ho notato anche io che aggiungendo o diminuendo due o 3 valori con virgola al debug il tempo di ciclo saliva o scendeva enormemente.

Vedo di riesumare la mia routine per leggere l'elevazione dei pannelli FV completa di tabella di linearizzazione e poi la pubblico, girava su un PIC16F877 .

Nei sistemi embedded è una regola d'oro usare sempre interi e convertirli in floating una sola volta, se possibile.

:yeah:

Grazie mille ElNonino, come noterai sono al livello dell' ABC e non voglio tediarti più del dovuto con lezioni di base di programmazione. Vedrò di approfondire. Però mi rimane il problema che il programma, così come è, stabilizza il risultato della media in 4 o 5 secondi quando il tempo di ciclo è attorno agli 80ms, il motivo è certamente il numero di valori contenuti nell'array. La soluzione è, come suggerisci tu, diminuire enormemente il tempo di ciclo oppure diminuire di molto il numero di valori nell'array della media. Proverò con entrambi.

Minestrone 01 dicembre 18 08:00

Ok, penso di aver capito anche l'uso che fai di &. Veramente interessante

Inviato dal mio Mi A1 utilizzando Tapatalk

ElNonino 01 dicembre 18 22:32

Allora per il punto #def k 180.0 è perchè in genere una costante (k) il compilatore la alloca in memoria statica e quando viene utilizzata viene richiamata in un solo ciclo, invece usare 180.0 obbliga il compilatore ad usare più cicli.

Per le operazioni binarie devi sapere che un x >>1 equivale a dividere per 2 il valore di x ed un x <<2 equivale a moltiplicare per due, ora nella maggior parte dei compilatori questa operazione comporta un solo ciclo di clock, una / molti di più.

Il tuo tempo di stabilizzazione può essere corretto, nel senso che se hai un ciclo di 80ms ed un array di 64 valori 0,08s x 64 = 5,12s contando che per avere un valore stabile all'accensione servono almeno due serie di campionamenti completi siamo sui 10,24s, decisamente lento.

Io direi che se usi un array di 2 x 16 valori in cui inserisci le letture di X ed Y dell'accelerometro e calcoli l'angolo una sola volta a ciclo usando la media dei due canali velocizzi di molto il tempo di ciclo.

Poi per il printf di float ci sono trucchetti semplici che lo velocizzano molto.

Se hai un oscilloscopio, anche economicissimo, ti consiglierei di utilizzarlo per misurare con precisione il tempo impiegato da operazioni, funzioni, routine o loop: imposti un pin digitale come output e ti crei due macro in define che settino o resettino il pin e le chiami TEST_ON e TEST_OFF poi

TEST_ON
......
.....
.....
TEST_OFF

e sull'oscilloscopio vedrai esattamente la durata delle operazioni comprese far ON ed OFF, è un sistema che ho sempre usato in fase di scrittura e test di programmi time critical per microprocessori embedded.

:yeah:

Minestrone 01 dicembre 18 22:41

Farò tesoro dei consigli. Per quanto riguarda la misura del tempo di ciclo un oscilloscopio rudimentale ce l'ho, però ho sempre fatto misurare il tempo di ciclo tramite la funzione millis() e facendo stampare a video il risultato; certamente il tempo di ciclo è sovrastimato, però credo che con buona approssimazione possa andare, o no?

Inviato dal mio Mi A1 utilizzando Tapatalk

ElNonino 02 dicembre 18 10:59

Io non fido troppo delle misure sui tempi d'esecuzione ottenute dallo stesso micro su cui gira il programma, preferisco andare alla vecchia con l'oscilloscopio, l'unico errore introdotto dallo strumento è quello del tempo di salita e discesa dei fronti dell'impulso che in genere è di pochissimi ns.

:yeah:

Minestrone 02 dicembre 18 11:06

Citazione:

Originalmente inviato da ElNonino (Messaggio 5124811)
Io non fido troppo delle misure sui tempi d'esecuzione ottenute dallo stesso micro su cui gira il programma, preferisco andare alla vecchia con l'oscilloscopio, l'unico errore introdotto dallo strumento è quello del tempo di salita e discesa dei fronti dell'impulso che in genere è di pochissimi ns.

:yeah:

Capisco. L'errore di salita e discesa però dovrebbe compensarsi, almeno in parte. O no?

Inviato dal mio Mi A1 utilizzando Tapatalk


Tutti gli orari sono GMT +2. Adesso sono le 09:21.

Basato su: vBulletin versione 3.8.11
Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
E' vietata la riproduzione, anche solo in parte, di contenuti e grafica. Copyright 1998/2019 - K-Bits P.I. 09395831002