| |
| | #1 (permalink) Top |
| User |
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.
__________________ Peace & Love Fate le cose nel modo più semplice possibile, ma senza semplificare. (A. Einstein) |
| | |
| | #2 (permalink) Top | |
| User Data registr.: 13-09-2012
Messaggi: 4.690
| Citazione:
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 | |
| | |
| | #3 (permalink) Top |
| User Data registr.: 13-09-2012
Messaggi: 4.690
|
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. |
| | |
| | #4 (permalink) Top | |
| User | Citazione:
__________________ Peace & Love Fate le cose nel modo più semplice possibile, ma senza semplificare. (A. Einstein) | |
| | |
| | #6 (permalink) Top |
| User |
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;
}
/*-----------------------------------------------------------------------------*/
__________________ Peace & Love Fate le cose nel modo più semplice possibile, ma senza semplificare. (A. Einstein) Ultima modifica di ElNonino : 29 novembre 18 alle ore 22:06 |
| | |
| | #7 (permalink) Top |
| User |
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.
__________________ Peace & Love Fate le cose nel modo più semplice possibile, ma senza semplificare. (A. Einstein) |
| | |
![]() |
| Bookmarks |
| |
Discussioni simili | ||||
| Discussione | Autore discussione | Forum | Commenti | Ultimo Messaggio |
| Radiocomando 3 motori DC e 2 sensori di T con Arduino su trenino | spraity | Radiocomandi | 3 | 09 febbraio 17 15:07 |